实验 MPU-6050模块

在使用之前,需要特别注意的是:MPU-6050 本身只支持到 3.3V,如果你需要供电5V那么要特别确认一下你的板子是否有转换。我使用的下面这个模块上面带降压的,所以可以直接接5V.

T1OIRvXBXfXXXXXXXX_!!0-item_pic

另外,连接GND和VCC时一定要注意不能搞反了,否则转换芯片会急剧发热(推荐你第一次上电的时候留心这个芯片)。

首推极客工坊的文章【参考1】。但是可能是版本太老的缘故,在编译时(1.5.0)会出现core.a的错误。

随后查了一下,Arduino官方网站上有介绍和示例代码【参考2】:

// MPU-6050 Short Example Sketch
// By Arduino User JohnChi
// August 17, 2014
// Public Domain
#include<Wire.h>
const int MPU=0x68;  // I2C address of the MPU-6050
int16_t AcX,AcY,AcZ,Tmp,GyX,GyY,GyZ;
void setup(){
  Wire.begin();
  Wire.beginTransmission(MPU);
  Wire.write(0x6B);  // PWR_MGMT_1 register
  Wire.write(0);     // set to zero (wakes up the MPU-6050)
  Wire.endTransmission(true);
  Serial.begin(9600);
}
void loop(){
  Wire.beginTransmission(MPU);
  Wire.write(0x3B);  // starting with register 0x3B (ACCEL_XOUT_H)
  Wire.endTransmission(false);
  Wire.requestFrom(MPU,14,true);  // request a total of 14 registers
  AcX=Wire.read()<<8|Wire.read();  // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L)     
  AcY=Wire.read()<<8|Wire.read();  // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L)
  AcZ=Wire.read()<<8|Wire.read();  // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L)
  Tmp=Wire.read()<<8|Wire.read();  // 0x41 (TEMP_OUT_H) & 0x42 (TEMP_OUT_L)
  GyX=Wire.read()<<8|Wire.read();  // 0x43 (GYRO_XOUT_H) & 0x44 (GYRO_XOUT_L)
  GyY=Wire.read()<<8|Wire.read();  // 0x45 (GYRO_YOUT_H) & 0x46 (GYRO_YOUT_L)
  GyZ=Wire.read()<<8|Wire.read();  // 0x47 (GYRO_ZOUT_H) & 0x48 (GYRO_ZOUT_L)
  Serial.print("AcX = "); Serial.print(AcX);
  Serial.print(" | AcY = "); Serial.print(AcY);
  Serial.print(" | AcZ = "); Serial.print(AcZ);
  Serial.print(" | Tmp = "); Serial.print(Tmp/340.00+36.53);  //equation for temperature in degrees C from datasheet
  Serial.print(" | GyX = "); Serial.print(GyX);
  Serial.print(" | GyY = "); Serial.print(GyY);
  Serial.print(" | GyZ = "); Serial.println(GyZ);
  delay(333);
}

 

我使用的是 Arduino Pro Micro (这并非Arduino官方出品,是一种类似 Arduino Leonardo 的兼容产品) , 电路非常简单,使用面包板即可

6050

运行结果

6050r

取得值本身很简单,但是如果想解出正确的姿态还是蛮复杂的。

参考:

1.http://www.geek-workshop.com/thread-1017-1-1.html arduino学习笔记37 – Arduino Uno + MPU6050首例整合性6轴演示实验

2.http://playground.arduino.cc/Main/MPU-6050 MPU-6050 Accelerometer + Gyro

Step to UEFI (35) —– How to build Shell.efi

【特别提醒:下面的全部操作都是在UDK2014中完成,具体代码会与2010有差别】

第一个问题:我们运行的模拟环境(NT32)中的Shell是来自哪里?

回答:在 \Nt32Pkg\Nt32Pkg.fdf 中你可以看到下面的定义

################################################################################
#
# FILE statements are provided so that a platform integrator can include
# complete EFI FFS files, as well as a method for constructing FFS files
# using curly "{}" brace scoping. The following three FILEs are
# for binary shell, binary fat and logo module.
#
################################################################################
INF EdkShellBinPkg/FullShell/FullShell.inf

INF FatBinPkg/EnhancedFatDxe/Fat.inf

FILE FREEFORM = PCD(gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdLogoFile) {
    SECTION RAW = MdeModulePkg/Logo/Logo.bmp

如果你把上面的 FullShell.inf 替换成 EdkShellBinPkg\MinimumShell 下面的MinimumShell.inf 再次编译之后会发现使用的是Mini版本的Shell. 例如: Hexedit 这个命令只在Full版本中才有,Mini版本下不支持。(实验时候特别注意,如果你 Build了 MinimumShell.inf, 在 fsnt1: 下面有一个 Hexedit.efi)

2.如何重新Build Shell.efi?

根据 ShellBinPkg 目录下的 Readme.txt (没错,我也不知道为什么是在这个目录而不是ShellPkg下面的 ReadMe.txt) ,可以使用下面的命令进行Build:

build -a IA32 -p ShellPkg\ShellPkg.dsc -b RELEASE

3.实际操作。这是我们最常见到的Shell的模样,我下面要尝试给他添加一段String.

full

在 \ShellPkg\Application\Shell\Shell.c 可以看到输出版本信息的语句

    //
    // Display the version
    //
    if (!ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoVersion) {
      ShellPrintHiiEx (
        0,
        gST->ConOut->Mode->CursorRow,
        NULL,
        STRING_TOKEN (STR_VER_OUTPUT_MAIN_SHELL),
        ShellInfoObject.HiiHandle,
        SupportLevel[PcdGet8(PcdShellSupportLevel)],
        gEfiShellProtocol->MajorVersion,
        gEfiShellProtocol->MinorVersion
       );

      ShellPrintHiiEx (
        -1,
        -1,
        NULL,
        STRING_TOKEN (STR_VER_OUTPUT_MAIN_SUPPLIER),
        ShellInfoObject.HiiHandle,
        (CHAR16 *) PcdGetPtr (PcdShellSupplier)
       );

      ShellPrintHiiEx (
        -1,
        -1,
        NULL,
        STRING_TOKEN (STR_VER_OUTPUT_MAIN_UEFI),
        ShellInfoObject.HiiHandle,
        (gST->Hdr.Revision&0xffff0000)>>16,
        (gST->Hdr.Revision&0x0000ffff),
        gST->FirmwareVendor,
        gST->FirmwareRevision
       );
    }

    //
    // Display the version
    //
    if (!ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoVersion) {
      ShellPrintHiiEx (
        0,
        gST->ConOut->Mode->CursorRow,
        NULL,
        STRING_TOKEN (STR_VER_OUTPUT_MAIN_SHELL),
        ShellInfoObject.HiiHandle,
        SupportLevel[PcdGet8(PcdShellSupportLevel)],
        gEfiShellProtocol->MajorVersion,
        gEfiShellProtocol->MinorVersion
       );

      ShellPrintHiiEx (
        -1,
        -1,
        NULL,
        STRING_TOKEN (STR_VER_OUTPUT_MAIN_SUPPLIER),
        ShellInfoObject.HiiHandle,
        (CHAR16 *) PcdGetPtr (PcdShellSupplier)
       );

      ShellPrintHiiEx (
        -1,
        -1,
        NULL,
        STRING_TOKEN (STR_VER_OUTPUT_MAIN_UEFI),
        ShellInfoObject.HiiHandle,
        (gST->Hdr.Revision&0xffff0000)>>16,
        (gST->Hdr.Revision&0x0000ffff),
        gST->FirmwareVendor,
        gST->FirmwareRevision
       );
    }

	//LabZDebug_Start 加入我们定义的String
	ShellPrintHiiEx (
        -1,
        -1,
        NULL,
        STRING_TOKEN (STR_LABZ_UEFI),
        ShellInfoObject.HiiHandle
       );
	//LabZDebug_End

    //
    // Display the mapping
    //

    if (PcdGet8(PcdShellSupportLevel) >= 2 && !ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoMap) {
      Status = RunCommand(L"map", NULL);
      ASSERT_EFI_ERROR(Status);
    }

同时在 \ShellPkg\Application\Shell\Shell.uni 加入我们自定义的字符串

#string STR_LABZ_UEFI		          #language en-US "www.lab-z.com 2014/12/12 build.....\r\n"

最后的结果如下,可以看到多出来一行我们自己定义的字符串:

modify

特别提醒:请注意文章中两张图片,实际上盘符是有差别的,一个是 FSNTx: 一个是 FSx。就是说在虚拟环境下模拟出来的盘符还是有差别的。目前我不清楚这个差别是如何导致的。

========================================================================
2015年3月31日补充

1.build shell.efi 之后生成的文件在 Build\Shell\RELEASE_MYTOOLS\IA32下面。同样他的子目录中也能找到Shell.efi (总共三个),他们内容相同

2.有一种情况是你替换了 Shell_Full.efi 之后,模拟器无法进入 shell,始终停留在Setup中。这种情况请检查输出的Log信息,我遇到的情况是因为改动有问题,导致 Shell.efi 是损坏的,无法正常Load起来。

Arduino Uno 的 Vin Pin

偶然注意到 Arduino Uno 上有个Vin Pin,但是AVR上没有对应的管脚,感觉比较奇怪,研究了一下。

ArduinoVin

原始图片来自【参考1】

这样的问题自然是要到电路图中查找答案。电路图和印刷版文件来自【参考2】

vin2

美中不足:虽然有PDF的电路图,但是不支持搜索,找了半天才在右上角找到

vin3

就是说Vin可以看作是DC输入的电压经过了一个二极管。因此,有两种情况:一是如果你插入了DC,那么Vin上会出现比DC稍微小一点的电压(因为经过了一个二极管);第二种情况,可以直接从这里灌进去一个电压。猜测这样的设计可能是为了某些有供电能力的Shield考虑吧。

关于这部分,有一些介绍【参考2】

External (non-USB) power can come either from an AC-to-DC adapter (wall-wart) or battery. The adapter can be connected by plugging a 2.1mm center-positive plug into the board’s power jack. Leads from a battery can be inserted in the Gnd and Vin pin headers of the POWER connector.

再查看 PCB 文件

vin31

对照 Vin 可以看到,它是接U1的 3 Pin的。

vin41

U1是 NCP1117ST50T3,简单翻翻手册【参考3】,这是一个降压的IC,Pin 3是输入

vin6

因此,Vin是一个可以直接对板子供电,电器特性功能和板子上DC插孔类似的输入脚。

参考:

1.http://arduino.cc/en/uploads/Main/ArduinoUno_R3_Front.jpg

2.http://arduino.cc/en/Main/ArduinoBoardUno

3.http://wenku.baidu.com/view/f66976af284ac850ad0242b9.html NCP1117

4.http://solderpad.com/solderpad/arduino-uno/ Bom List特别注意上面的一些名称和原本电路图有差别。

二维码对联

前一段看张鸣老师的书,上面提到对联是一种很重要的传统文化表现形式,尤其是春节时要四处张贴的春联。据说很多地区的大学生春节回家之后还要承担起为乡亲们题写春联的重任。母亲说当年他们插队时,逢年也会给老乡写春联。内容上通常是毛语录,比如:“金猴奋起千钧棒,玉宇澄清万里埃”或者“四海翻腾云水怒 五洲震荡风雷激”,一类的。

每年春节上街我都会觉得这是越来越重要的传统——至少从春联的价格上来看是这样。让我编点春联是没问题的,至于写的话因为现在提笔忘字以及本人的字都会被老婆笑话,还是免谈了。

作为一个专业的工程技术人员,灵机一动,想到了既然我只能编不能写可以用眼下最时髦的二维码技术来生成。有好奇心的人就会去扫一扫,然后就能看到了。具体做法如下:

首先,找个二维码生成软件。选择最高的误码率,简单的理解这个就是你能够覆盖生成二维码的比率。比如:25%的误码率意味着你可以覆盖画面上25%的区域仍然能够正常扫出。

错误修正容量

L水平 7%的字码可被修正

M水平 15%的字码可被修正

Q水平 25%的字码可被修正

H水平 30%的字码可被修正

【参考 1】

image001

【参考1】

我随便选了一个软件,二维码大师,最高误码率30%,然后选择最高分辨率。文本内容中输入上联“壹零做法神通广大不服来扫我”,输入过程中就自动生成二维码了,具体在下面三个地方设置和输入。

image002

选择保存为一个BMP文件。比如上面“壹零做法神通广大不服来扫我”,生成的结果就是下面的图片。

image003

然后修改这个图片即可,我最喜欢用的就是Windows的画笔工具。

image004

修改之后结果

image005

特别的,修改之后一定要用刚才的软件校验一下,避免做完了根本无法识别的状况。

image006

同样做法,再做一下下联“纵横成形网挂众多若信任联”。

image007
上面这个对联是我父亲拟的,横批就是“二维码”。

最后多说两句,大多数情况下人们只是注意上下问对仗是否工整而不大在意内容本身,好比,有女生给班主任写条子,”老师,我怀了男朋友得孩子”。老师看到之后大吃一惊“唉,现在的学生啊,真是的!都上初中了,怎么还分不清楚‘的地得’的用法?”。我随口拟了一个联儿,念给父亲听,他听了片刻说“对的比较工整,这是一个传统的联吧?”

image008

image009

参考:

1. http://zh.wikipedia.org/wiki/QR%E7%A2%BC QR码

Windows 7 64位下arduino驱动安装失败解决办法

最近入手一块 Arduino Micro Pro ,插在台式机上之后要求安装驱动,指定了 Arduino 目录下的 Drivers之后还出现了 Inf 段落无效的字样。忽然想起来我的 Win7 是Ghost版本,于是上网搜索解决办法。

在 http://blog.csdn.net/u013926582/article/details/24442583 和 http://www.arduino.cn/thread-2485-1-1.html 都有提到。

最后使用的方法是 查看 C:\Windows\inf\setupapi.dev.log (要从下向上搜索,最近安装的错误在文件尾)

发现下面的字样

dvi: {DIF_INSTALLDEVICEFILES} 17:08:34.464
dvi: Class installer: Enter 17:08:34.465
dvi: Class installer: Exit
dvi: Default installer: Enter 17:08:34.465
dvi: {Install FILES}mdmcpq.inf
inf: Opened PNF: ‘c:\windows\system32\driverstore\filerepository\arduino.inf_amd64_neutral_844213a156728dfe\arduino.inf’ ([strings])
inf: Opened PNF: ‘C:\Windows\INF\mdmcpq.inf’ ([strings])
inf: Opened PNF: ‘C:\Windows\INF\usb.inf’ ([strings.0804])
inf: {Install Inf Section [DriverInstall]}
inf: CopyFiles=FakeModemCopyFileSection (arduino.inf line 128)
cpy: Open PnpLockdownPolicy: Err=2. This is OK. Use LockDownPolicyDefault
flq: QueueSingleCopy…
flq: Inf : ‘c:\windows\system32\driverstore\filerepository\arduino.inf_amd64_neutral_844213a156728dfe\arduino.inf’
! flq: Missing SourceDisksFiles/SourceDisksNames information from INF.
! flq: Default INBOX source locations pulled from pre-built DrvIndex
flq: SourceRootPath: ‘C:\Windows\System32\DriverStore\FileRepository\mdmcpq.inf_amd64_neutral_b53453733bd795bc’
flq: {FILE_QUEUE_COPY}
flq: CopyStyle – 0x00002000
flq: {FILE_QUEUE_COPY}
flq: CopyStyle – 0x00002000
flq: SourceRootPath – ‘C:\Windows\System32\DriverStore\FileRepository\mdmcpq.inf_amd64_neutral_b53453733bd795bc’
flq: SourcePath – ‘\’
flq: SourceFilename – ‘usbser.sys’
flq: TargetDirectory- ‘C:\Windows\system32\DRIVERS’
flq: TargetFilename – ‘usbser.sys’
flq: {FILE_QUEUE_COPY exit(0x00000000)}
flq: {FILE_QUEUE_COPY exit(0x00000000)}
inf: {Install Inf Section [DriverInstall] exit (0x00000000)}
dvi: Processing co-installer registration section [DriverInstall.CoInstallers].
inf: {Install Inf Section [DriverInstall.CoInstallers]}
inf: {Install Inf Section [DriverInstall.CoInstallers] exit (0x00000000)}
dvi: Co-installers registered.
dvi: {Install INTERFACES}
dvi: Installing section [DriverInstall.Interfaces]
dvi: {Install INTERFACES exit 00000000}
dvi: {Install FILES exit (0x00000000)}
dvi: Default installer: Exit
dvi: {DIF_INSTALLDEVICEFILES – exit(0x00000000)} 17:08:34.479
ndv: Pruning file queue…
dvi: {_SCAN_FILE_QUEUE}
flq: ScanQ flags=620
flq: SPQ_SCAN_PRUNE_COPY_QUEUE
flq: SPQ_SCAN_FILE_COMPARISON
flq: SPQ_SCAN_ACTIVATE_DRP
flq: ScanQ number of copy nodes=1
! sig: GetNameSDInfo
! sig: Error 0: The operation completed successfully.
flq: ScanQ action=200 DoPruning=32
flq: ScanQ end Validity flags=620 CopyNodes=1
dvi: {_SCAN_FILE_QUEUE exit(0, 0x00000000)}
ndv: Committing file queue…
flq: {_commit_file_queue}
flq: CommitQ DelNodes=0 RenNodes=0 CopyNodes=1
flq: {SPFILENOTIFY_STARTQUEUE}
flq: {SPFILENOTIFY_STARTQUEUE – exit(0x00000001)}
flq: {_commit_copy_subqueue}
flq: subqueue count=1
flq: {SPFILENOTIFY_STARTSUBQUEUE}
flq: {SPFILENOTIFY_STARTSUBQUEUE – exit(0x00000001)}
flq: source media:
flq: SourcePath – [C:\Windows\System32\DriverStore\FileRepository\mdmcpq.inf_amd64_neutral_b53453733bd795bc]
flq: SourceFile – [usbser.sys]
flq: Flags – 0x00000000
flq: {SPFQNOTIFY_NEEDMEDIA}
flq: {SPFILENOTIFY_NEEDMEDIA}
flq: {SPFILENOTIFY_NEEDMEDIA – exit(0x00000000)}
flq: {SPFQNOTIFY_NEEDMEDIA – returned 0x00000000}
!!! flq: source media: SPFQOPERATION_ABORT.
!!! flq: Error 2: The system cannot find the file specified.
flq: {_commit_copy_subqueue exit(0x00000002)}
!!! flq: FileQueueCommit aborting!
!!! flq: Error 2: The system cannot find the file specified.
flq: {SPFILENOTIFY_ENDQUEUE}
flq: {SPFILENOTIFY_ENDQUEUE – exit(0x00000001)}
flq: {_commit_file_queue exit(0x00000002)}
ndv: Device install status=0x00000002
ndv: Performing device install final cleanup…
! ndv: Queueing up error report since device installation failed…
ndv: {Core Device Install – exit(0x00000002)} 17:08:34.493
dvi: {DIF_DESTROYPRIVATEDATA} 17:08:34.494
dvi: Class installer: Enter 17:08:34.494
dvi: Class installer: Exit

错误是说找不到 C:\Windows\System32\DriverStore\FileRepository\mdmcpq.inf_amd64_neutral_b53453733bd795bc(特别注意,不同系统,这个名字会不同,需要根据你当前系统中的错误来确定) 我进去 C:\Windows\System32\DriverStore\FileRepository\ 一看确实没有。

又在网上搜索了一下,在 http://www.arduino.cn/thread-2350-1-1.html 这里给出来两个64位的。

下载之后,首先将 UsbSer.sys 放到 Windows\System32\Drivers 下面,然后在 C:\Windows\System32\DriverStore\FileRepository\ 下面创建一个 mdmcpq.inf_amd64_neutral_b53453733bd795bc 目录把mdmcpq.zip中的全部内容放进去。

卸载之前安装的驱动,然后重新安装一次即可。

usbser

mdmcpq.inf

如果有遇到同样问题的朋友可以试试。

===========================================================================
2月16日 如果始终无法完成安装,建议检查一下你是否将设备插在 USB 3.0 的Port上。某些USB 3.0的 Controller 对于一些低速设备存在兼容性问题。如果是的话,请更换到 USB 2.0 的端口上再进行上述实验。

4月4日 在FileRepository 目录下创建目录的过程中,可能遇到“需要权限来执行此操作”的问题。解决方法是:

1.确保你的杀毒软件关闭了(比如,瑞星之类的你可以考虑直接卸载)
2.在FileRepository 目录上点鼠标右键,弹出的菜单上切换到安全页面。然后在上面的组或用户名栏目上检查是否有你当前账户。比如:开机登录的用户名是 player ,而这里没有。那么按下编辑键,在新弹出页面上用添加按钮,然后输入 player ,按下检查名称按钮就添加进去了。特别注意:其中的 SYSTEM 用户名,并非 Administrator,如果你是 Administrator 登录进来,那么需要手工添加一下。

Arduino 显示奶瓶温度

有个网友提出一个需求“做一个能够显示温度的奶瓶。奶瓶泡好奶后放在底座上,可直接给婴儿喝的绿灯亮,过烫红灯亮,过凉蓝灯亮。”这是他的一个作业,然后我就帮着做了一下。整体思路就是直接使用上一次做的那个红外温度计的方案,我想这样的方案恐怕在网上都是独一无二的吧。

使用到的基本元件有:Arduino Uno + LED + 红外温度传感器(上面有一个激光头用于瞄准)

使用红外温度传感器能够获得下列优点:

1.无需接触,不必考虑卫生的问题
2.准确度在可以接受的范围内
3.速度快,对准之后马上显示
4.兼容性好,各种型号的奶瓶都可以

缺点:

1.贵
2.有人说无法精确得知瓶中奶的温度,测量的是奶瓶温度而已

milkb2

milkb1

#include <Arduino.h>
#include <Wire.h>
#include "TN901.h"  
TN901 tn;          
int RedLed=10;  //Red Led Pin10
int GreenLed=7;  //Green Led Pin10
int BigRedLed=4;  //Big Led Pin4
void setup()
{
    Serial.begin(9600);
    tn.Init(13,12,11);  //初 始 化 data clk ack
    pinMode(RedLed,OUTPUT);
    digitalWrite(RedLed,LOW);
    pinMode(GreenLed,OUTPUT);
    digitalWrite(GreenLed,LOW);    
    pinMode(BigRedLed,OUTPUT);
    digitalWrite(BigRedLed,LOW);      
}
void loop()
{
   tn.Read();
   SerialValue();
   delay(2000);
}

void SerialValue()
{
   String s;
   s=">O"+String(tn.OT, DEC)+"E"+String(tn.ET,DEC)+"<";
   Serial.println(s);
   if (tn.OT>5000) { // Temp too high
         digitalWrite(RedLed,HIGH);
         digitalWrite(GreenLed,LOW);
         digitalWrite(BigRedLed,HIGH);        
   }
   else {
     if (tn.OT>2100) {// Temp is OK
         digitalWrite(RedLed,LOW);
         digitalWrite(GreenLed,HIGH);
         digitalWrite(BigRedLed,HIGH);        
         }
    else { //Temp is too Low      
         digitalWrite(RedLed,HIGH);
         digitalWrite(GreenLed,HIGH);
         digitalWrite(BigRedLed,LOW);
     
    }
   }  
}

 

设计上我们使用了2个LED,一个是小LED双色红色和绿色,一个是单独的大个红色的(手边只有这两种LED,更好的设计应该换个颜色的LED便于区分)。温度传感器是红外温度传感器。

温度区间:

>50 小LED的红色亮起 表示温度过高

50-20 小LED的绿色亮起 表示温度适合

<20 大红色LED亮起 表示温度过低 工作时的视频 首先展示一下电路,然后我们有一瓶大瓶冷水;放在上面的时候温度过低,大红色 LED亮起;然后我们换成奶瓶,其中是热水,温度过高,小红色LED亮起;然后我们将大瓶子的水兑到小瓶子中,温度会变得适中,于是小LED绿色会亮起。

这个方案对于作业来说应该是足够了。就是这样。

Step to UEFI (34) —– FindFile2 查找特定文件

前面介绍了如何枚举全部文件,这里介绍一下如何枚举特定的问题。比如,用 “M*.*” 匹配全部 M开头的文件。

参考 touch 命令的Source Code 很快有了方案,使用:ShellOpenFileMetaArg

对应的头文件在 \ShellPkg\Include\Library\ShellLib.h

/**
  Opens a group of files based on a path.

  This function uses the Arg to open all the matching files. Each matched
  file has a SHELL_FILE_ARG structure to record the file information. These
  structures are placed on the list ListHead. Users can get the SHELL_FILE_ARG
  structures from ListHead to access each file. This function supports wildcards
  and will process '?' and '*' as such.  The list must be freed with a call to
  ShellCloseFileMetaArg().

  If you are NOT appending to an existing list *ListHead must be NULL.  If
  *ListHead is NULL then it must be callee freed.

  @param[in] Arg                 The pointer to path string.
  @param[in] OpenMode            Mode to open files with.
  @param[in, out] ListHead       Head of linked list of results.

  @retval EFI_SUCCESS           The operation was sucessful and the list head
                                contains the list of opened files.
  @retval != EFI_SUCCESS        The operation failed.

  @sa InternalShellConvertFileListType
**/
EFI_STATUS
EFIAPI
ShellOpenFileMetaArg (
  IN CHAR16                     *Arg,
  IN UINT64                     OpenMode,
  IN OUT EFI_SHELL_FILE_INFO    **ListHead
  );

 

从介绍上来看,最主要的参数有2个:Arg输入要查找的路径,可以使用通配符。ListHead 返回结果。结果实际上是两部分一部分是 SHELL_FILE_ARG 结构体,另外一部分是 EFI_SHELL_FILE_INFO 结构体。前者只有一个,后者有一个或者很多个。他们使用链表结构联系在一起。上面这样的结构体感觉上很奇怪,不过确实是这样的。可以在Touch的 Source Code中看到。他使用 GetFirstNode 来跳过第一个不需要的结构体。这个函数可以在 \MdePkg\Library\BaseLib\LinkedList.c 里面看到

/**
  Retrieves the first node of a doubly-linked list.

  Returns the first node of a doubly-linked list.  List must have been 
  initialized with INTIALIZE_LIST_HEAD_VARIABLE() or InitializeListHead().
  If List is empty, then List is returned.

  If List is NULL, then ASSERT().
  If List was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or 
  InitializeListHead(), then ASSERT().
  If PcdMaximumLinkedListLenth is not zero, and the number of nodes
  in List, including the List node, is greater than or equal to
  PcdMaximumLinkedListLength, then ASSERT().

  @param  List  A pointer to the head node of a doubly-linked list.

  @return The first node of a doubly-linked list.
  @retval NULL  The list is empty.

**/
LIST_ENTRY *
EFIAPI
GetFirstNode (
  IN      CONST LIST_ENTRY          *List
  )
{
  //
  // ASSERT List not too long
  //
  ASSERT (InternalBaseLibIsNodeInList (List, List, FALSE));

  return List->ForwardLink;
}

 

最终编写程序如下

#include  <Uefi.h>
#include  <Library/UefiLib.h>
#include  <Library/ShellCEntryLib.h>

#include  <stdio.h>
#include  <stdlib.h>
#include  <wchar.h>

#include <Protocol/EfiShell.h>
#include <Library/ShellLib.h>

extern EFI_BOOT_SERVICES         *gBS;
extern EFI_SYSTEM_TABLE			 *gST;
extern EFI_RUNTIME_SERVICES 	 *gRT;

extern EFI_SHELL_PROTOCOL        *gEfiShellProtocol;

void PrintShellFileInfo(EFI_SHELL_FILE_INFO     *ShellFileInfo)
{
  //Print(L"Status [%d]\n",ShellFileInfo-> Status);
  Print(L"FullName [%s]\n",ShellFileInfo-> FullName);
  //Print(L"FileName [%s]\n",ShellFileInfo-> FileName);
  //Print(L"Handle [%d]\n",ShellFileInfo->Handle);  
}

int
EFIAPI
main (                                         
  IN int Argc,
  IN char **Argv
  )
{
  //EFI_FILE_HANDLE   DirHandle;
  RETURN_STATUS     Status;
  EFI_SHELL_FILE_INFO *FileList=NULL;
  EFI_SHELL_FILE_INFO *Node;
  
  Status = ShellOpenFileMetaArg(L"fsnt0:\\a*.*", EFI_FILE_MODE_READ, &FileList);
  if(Status != RETURN_SUCCESS) {
        Print(L"OpenFile failed!\n");
		return EFI_SUCCESS;
  }							   
  
  //Print(L"Signature [%X]\n",((SHELL_FILE_ARG *)&FileList)->Signature);  
  //Print(L"Status []\n",((SHELL_FILE_ARG *)&FileList)->Status);  
  //Print(L"ParentName [%s]\n",((SHELL_FILE_ARG *)&FileList)->ParentName);  
  //Print(L"FullName [%s]\n",((SHELL_FILE_ARG *)&FileList)->FullName);  
  //Print(L"FileName [%s]\n",((SHELL_FILE_ARG *)&FileList)->FileName);  

  
  // check that we have at least 1 file
  //
  if (FileList == NULL || IsListEmpty(&FileList->Link)) {
                Print(L"No Files Found!\n");
  } else {
		//
		// loop through the list and make sure we are not aborting...
		//
		for ( Node = (EFI_SHELL_FILE_INFO*)GetFirstNode(&FileList->Link)
			; !IsNull(&FileList->Link, &Node->Link) && !ShellGetExecutionBreakFlag()
			; Node = (EFI_SHELL_FILE_INFO*)GetNextNode(&FileList->Link, &Node->Link)){
					PrintShellFileInfo(Node);			   
				//
				// make sure the file opened ok
				//
				if (EFI_ERROR(Node->Status)){
					Print(L"OpenFile Error!\n");
				}

        }
    }
		  
   //
   // Free the fileList
   //
   if (FileList != NULL && !IsListEmpty(&FileList->Link)) {
       Status = ShellCloseFileMetaArg(&FileList);
   }
   FileList = NULL;
		
  return EFI_SUCCESS;
}

 

运行结果

FindFIle2

可以看出能够正常查找到我们需要的 fsnt0:x下面a开头的文件。

代码下载

FindFile2

===============================================================================
最后有一个问题:
前面说过,ShellOpenFileMetaArg 输出的结果是2部分组成的,我的程序只是输出了后面的那个结构体,那么前面的那个结构体呢?

  Status = ShellOpenFileMetaArg(L"fsnt0:\\a*.*", EFI_FILE_MODE_READ, &FileList);
  if(Status != RETURN_SUCCESS) {
        Print(L"OpenFile failed!\n");
		return EFI_SUCCESS;
  }							   
  
  Print(L"Signature [%X]\n",((SHELL_FILE_ARG *)&FileList)->Signature);  
  Print(L"Status []\n",((SHELL_FILE_ARG *)&FileList)->Status);  
  Print(L"ParentName [%s]\n",((SHELL_FILE_ARG *)&FileList)->ParentName);  
  Print(L"FullName [%s]\n",((SHELL_FILE_ARG *)&FileList)->FullName);  
  Print(L"FileName [%s]\n",((SHELL_FILE_ARG *)&FileList)->FileName); 

 

结果出来之后非常奇怪的是 Signature 的输出并非固定的数值,而根据 EfiShellEnvironment2.h 来看,这个似乎应该是一个固定的值。

不知道是我理解有偏差还是输出方法不对。有懂的朋友请指教一下。谢谢!

窗花

前几天看《小说月报》,一篇讲述的是研究生毕业的漂亮女硕士,为了完成女导师的愿望,毅然决然选择从政的故事。只不过这是主旋律小说,必须有光明的尾巴:一直期望她能成为自己“李万姬”的老领导患了癌症,向革命老前辈们报到前说出了所有的事情,于是全部矛盾迎刃而解。最后女主角镀金完成,换了岗位,抱得男朋友满载而归。比较有意思的是故事中有一个情节,讲的是他们那里支柱企业是无纺布生产厂,受到经济危机影响,贷款出了问题,然后女主角想办法筹集资金,拖欠了一下当地干部和教师的工资,又下达集资的命令。看到资金的来源,我觉得这篇小说还真是写实。确实,对于教师这个职业,没有好处的很多时候不会想起来你是公务员,但是要是有需要体现精神的时候又会被推到前面。

又想起来很久之前的一个科幻小说,讲述人类发送太阳能电池到太空作为新能源,但是太空中有尘埃,每隔一段就需要清理。发送博士之类风险太大薪水又不能太低,最后作为特产,农民工就被送到太空,从事这份高工资的工作,也算是人上人了。小说还真是传承社会精神面貌的镜子。回头我找本书好好研究下宋朝的生活,顺便批判一下封建社会的腐朽的生活方式。

我这里说的窗花并非那种传统手工图样,而是凝结在窗户上的水汽形成的美丽图样。

0f53c8d303a1add716cbc1cbef375ee8

我的一位同学,是小学老师,前一段她每天早晨都会在朋友圈中晒出办公室窗花的照片。听起来很浪漫,现实中意味着寒冷—-办公室没有暖气和空调。听起来难以置信,不过据她所说就是这样。此外,因为种种安全上的考量严禁各种非生物能源转换,意思是除了蹦跳多穿衣服多吃东西之外严禁使用电器。于是她便只能望着美丽的窗花偶发感慨聊以自慰了。

以前我在的公司也有过这样的事情:大冬天为了省电不开空调,HW工程师冻的手都没有办法握稳电烙铁。具体是这样的,冬季是我国江南地区传统的用电高峰,企业在用电上会有一些限制,于是老板就在空调上打起来主意。最大的问题是老板的房间是在整栋楼的中间,好比上下各有一层脂肪,大约是感受不到多少寒冷,而我们研发非常不幸的处在顶楼,不开空调很冷啊。我们找了一楼的总务很多次,总务总是指着墙上的一直温度计辩解还没有降低到18度,由拒绝开,我甚至一直在怀疑,他那只温度计是特殊定制的,显示值会比正常的温度高那么两三度。再后来终于开放中央空调,但是还想了一个非常奇特的规则:整点的时候供电10分钟。意思是,比如九点到九点十分,中央空调是有电的,但是需要手工用遥控器打开之。于是,每逢快到整点,研发人员就像神经病一样相互提醒马上准备开空调,能暖和一段。偶然忘记了大家更是垂足顿胸。

时间一长,大家都受不鸟了。就开始研究解决方法了。做HW的工程师夏天的时候可以做几只风扇并联起来,但是冬天的时候没有太合适的工具取暖,热风枪吹起来只有外焦里生的效果。电烙铁的加热区域也太小,没办法满足四肢的需要…….通常 HW 搞不定的就要靠SW了。于是,我旁边的妹子提出:太TMD冷了,自己买个暖风机,然后我也附议了一下,一起买吧。忽然想起来那次似乎是我第一次在京东上购物。根据自己的体积,我挑选了一个2KW的暖风机,旁边的妹子挑选了一个2.5KW的。头天下午的订单,第二天就送货上门签收交易完成,那也是我第一次被京东的配送速度震撼到。用起来感觉不错,是风暖型的,中午熄灯之后吹上去暖洋洋的,我恨不得搬着一张床钻到桌子下面去。等我们用了一段,看看没啥动静,办公室的人也都一窝蜂的去买,到了最后几乎是人手一只。连研发的老大也悄悄买了一个低调的塞在座位下面:高调的理念通常只适用在别人身上,真正到了自己这边舒服一些比什么都强。大约也是到了这个岁数所谓天降大人于私人也不那么重要。没有大志终究比大痔或者冻疮强。

再后来,总务想管来着,羞羞答答的提出了除了费电之外的全部理由,比如:不安全,不环保等等。只是研发没人鸟。想必总务也是有所顾忌的,一方面大冬天不给开空调本来就不占理;另一方面也许是实在讲不过研发的人吧。再后来也就不了了之,我们吹着暖风迎来了春天………..

事后,我曾经认真的总结,这个事情之所以能成,很大程度上是总务对我们有所顾忌,也就睁一只眼闭一只眼了;更高一点层次来说,研发人员算是稀缺,上面也不愿意太过分。再后面发生太过分的事情,研发3个月走了一半的。

从另外一个角度来说,我同学那样的小学老师,生活是很稳定的,一辈子不用担心你会被开除或者因为某些变故失去工作,而这种稳定付出的代价就是自由。

Step to UEFI (33) —– FindFile 枚举目录下所有文件

研究一下如何枚举目录下的全部文件,查到了2个函数 ShellFindFirstFile 和 ShellFindNextFile。下面就研究如何使用这两个函数。

这两个函数在 \ShellPkg\Include\Library\ShellLib.h 中有定义

/** Retrieve first entry from a directory.

  This function takes an open directory handle and gets information from the
  first entry in the directory.  A buffer is allocated to contain
  the information and a pointer to the buffer is returned in *Buffer.  The
  caller can use ShellFindNextFile() to get subsequent directory entries.

  The buffer will be freed by ShellFindNextFile() when the last directory
  entry is read.  Otherwise, the caller must free the buffer, using FreePool,
  when finished with it.

  @param[in]  DirHandle         The file handle of the directory to search.
  @param[out] Buffer            The pointer to the buffer for the file's information.

  @retval EFI_SUCCESS           Found the first file.
  @retval EFI_NOT_FOUND         Cannot find the directory.
  @retval EFI_NO_MEDIA          The device has no media.
  @retval EFI_DEVICE_ERROR      The device reported an error.
  @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted.
  @return Others                Status of ShellGetFileInfo, ShellSetFilePosition,
                                or ShellReadFile.

  @sa ShellReadFile
**/
EFI_STATUS
EFIAPI
ShellFindFirstFile (
  IN      SHELL_FILE_HANDLE       DirHandle,
     OUT  EFI_FILE_INFO         **Buffer
  );


/** Retrieve next entries from a directory.

  To use this function, the caller must first call the ShellFindFirstFile()
  function to get the first directory entry.  Subsequent directory entries are
  retrieved by using the ShellFindNextFile() function.  This function can
  be called several times to get each entry from the directory.  If the call of
  ShellFindNextFile() retrieved the last directory entry, the next call of
  this function will set *NoFile to TRUE and free the buffer.

  @param[in]  DirHandle         The file handle of the directory.
  @param[out] Buffer            The pointer to buffer for file's information.
  @param[out] NoFile            The pointer to boolean when last file is found.

  @retval EFI_SUCCESS           Found the next file, or reached last file
  @retval EFI_NO_MEDIA          The device has no media.
  @retval EFI_DEVICE_ERROR      The device reported an error.
  @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted.
**/
EFI_STATUS
EFIAPI
ShellFindNextFile(
  IN SHELL_FILE_HANDLE                      DirHandle,
  OUT EFI_FILE_INFO              *Buffer,
  OUT BOOLEAN                    *NoFile
  )
{
  //
  // pass to file handle lib
  //
  return (FileHandleFindNextFile(DirHandle, Buffer, NoFile));
}

 

阅读说明可以发现,调用之后会分配一个Buffer,然后由调用者来负责释放。

开始写程序之后很快问题就来了,下面这样很简单的程序会让我的模拟器一次次崩溃。

int
EFIAPI
main (
  IN int Argc,
  IN char **Argv
  )
{
  EFI_FILE_HANDLE   DirHandle;
  RETURN_STATUS     Status;
  EFI_FILE_INFO     *FileInfo = NULL;
  BOOLEAN			NoFile=FALSE;
  
  Status = ShellOpenFileByName(L"fsnt0:\\testz", (SHELL_FILE_HANDLE *)&DirHandle,
                               EFI_FILE_MODE_READ , 0);

  if(Status != RETURN_SUCCESS) {
        Print(L"OpenFile failed!\n");
		return EFI_SUCCESS;
      }							   

  ShellFindFirstFile(DirHandle,&FileInfo);
  PrintFileInfo(FileInfo);
  free(FileInfo);
  while (FALSE==NoFile) 
    {
		Status=ShellFindNextFile(DirHandle,FileInfo,&NoFile);
		if (EFI_SUCCESS == Status)
			{
			}
		Print(L"No File[%d]\n",NoFile);	
	}
 
  return EFI_SUCCESS;
}

 

百思不得其解,在程序中加入输出函数,跟踪一下。出错的部分在ShellFindNextFile(DirHandle,FileInfo,&NoFile); 中。追踪进入 \ShellPkg\Library\UefiFileHandleLib\UefiFileHandleLib.c 的 FileHandleFindNextFile。

/** Retrieve next entries from a directory.

  To use this function, the caller must first call the FileHandleFindFirstFile()
  function to get the first directory entry.  Subsequent directory entries are
  retrieved by using the FileHandleFindNextFile() function.  This function can
  be called several times to get each entry from the directory.  If the call of
  FileHandleFindNextFile() retrieved the last directory entry, the next call of
  this function will set *NoFile to TRUE and free the buffer.

  @param[in]  DirHandle         The file handle of the directory.
  @param[out] Buffer            The pointer to buffer for file's information.
  @param[out] NoFile            The pointer to boolean when last file is found.

  @retval EFI_SUCCESS           Found the next file, or reached last file
  @retval EFI_NO_MEDIA          The device has no media.
  @retval EFI_DEVICE_ERROR      The device reported an error.
  @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted.
**/
EFI_STATUS
EFIAPI
FileHandleFindNextFile(
  IN EFI_FILE_HANDLE          DirHandle,
  OUT EFI_FILE_INFO          *Buffer,
  OUT BOOLEAN                *NoFile
  )
{
  EFI_STATUS    Status;
  UINTN         BufferSize;

  //
  // ASSERTs for DirHandle or Buffer or NoFile poitners being NULL
  //
  ASSERT (DirHandle != NULL);
  ASSERT (Buffer    != NULL);
  ASSERT (NoFile    != NULL);

  //
  // This BufferSize MUST stay equal to the originally allocated one in GetFirstFile
  //
  BufferSize = FIND_XXXXX_FILE_BUFFER_SIZE;

  //
  // read in the info about the next file
  //
  Status = FileHandleRead (DirHandle, &BufferSize, Buffer);
  ASSERT(Status != EFI_BUFFER_TOO_SMALL);
  if (EFI_ERROR(Status)) {
    return (Status);
  }

  //
  // If we read 0 bytes (but did not have erros) we already read in the last file.
  //
  if (BufferSize == 0) {
    FreePool(Buffer);
    *NoFile = TRUE;
  }

  return (EFI_SUCCESS);
}

 

确定是 FreePool(Buffer); 导致的。看到这个代码感觉很奇怪,明明是让 caller 负责释放,为什么他在里面要干这事情?再阅读函数说明“ If the call of
FileHandleFindNextFile() retrieved the last directory entry, the next call of
this function will set *NoFile to TRUE and free the buffer.” 原来这个函数设计的意思是:调用FileHandleFindNextFile 不断取得文件时,如果你中间停止了,那么请自行释放Buffer;但是如果你一直调用到了最后一个文件,那么函数本身会帮你释放掉而不需要你来做。

最终的程序不复杂

#include  <Uefi.h>
#include  <Library/UefiLib.h>
#include  <Library/ShellCEntryLib.h>

#include  <stdio.h>
#include  <stdlib.h>
#include  <wchar.h>

#include <Protocol/EfiShell.h>
#include <Library/ShellLib.h>

extern EFI_BOOT_SERVICES         *gBS;
extern EFI_SYSTEM_TABLE			 *gST;
extern EFI_RUNTIME_SERVICES 	 *gRT;

extern EFI_SHELL_PROTOCOL        *gEfiShellProtocol;

void PrintFileInfo(EFI_FILE_INFO     *FileInfo)
{
  Print(L"Filesize [%ld] bytes\n",FileInfo-> FileSize);
  Print(L"PhysicalSize [%ld] bytes\n",FileInfo-> PhysicalSize);  

  Print(L"File Create date [%d-%d-%d %d-%d-%d]\n",
		FileInfo-> CreateTime.Year,
		FileInfo-> CreateTime.Month,
		FileInfo-> CreateTime.Day,
		FileInfo-> CreateTime.Hour,
		FileInfo-> CreateTime.Minute,
		FileInfo-> CreateTime.Second);    
		
  Print(L"File last accessed date [%d-%d-%d %d-%d-%d]\n",
		FileInfo-> LastAccessTime.Year,
		FileInfo-> LastAccessTime.Month,
		FileInfo-> LastAccessTime.Day,
		FileInfo-> LastAccessTime.Hour,
		FileInfo-> LastAccessTime.Minute,
		FileInfo-> LastAccessTime.Second);   		
		
  Print(L"File last modification date [%d-%d-%d %d-%d-%d]\n",
		FileInfo-> ModificationTime.Year,
		FileInfo-> ModificationTime.Month,
		FileInfo-> ModificationTime.Day,
		FileInfo-> ModificationTime.Hour,
		FileInfo-> ModificationTime.Minute,
		FileInfo-> ModificationTime.Second);   		

  Print(L"File Name [%s]\n",&FileInfo->FileName[0]);  
}

int
EFIAPI
main (
  IN int Argc,
  IN char **Argv
  )
{
  EFI_FILE_HANDLE   DirHandle;
  RETURN_STATUS     Status;
  EFI_FILE_INFO     *FileInfo = NULL;
  BOOLEAN			NoFile=FALSE;
  
  Status = ShellOpenFileByName(L"fsnt0:", (SHELL_FILE_HANDLE *)&DirHandle,
                               EFI_FILE_MODE_READ , 0);

  if(Status != RETURN_SUCCESS) {
        Print(L"OpenFile failed!\n");
		return EFI_SUCCESS;
      }							   

  ShellFindFirstFile(DirHandle,&FileInfo);
  while (TRUE!=NoFile) 
    {
	    PrintFileInfo(FileInfo);
		Status=ShellFindNextFile(DirHandle,FileInfo,&NoFile);
	}
  return EFI_SUCCESS;
}

 

运行结果

findfile

完整代码下载

FindFile

Step to UEFI (32) —– GetFileInfo

这里介绍一个能够获得文件基本信息的函数: GetFileInfo

可以在 \ShellPkg\Include\Library\ShellLib.h 看到定义

/**
  This function will retrieve the information about the file for the handle
  specified and store it in allocated pool memory.

  This function allocates a buffer to store the file's information. It is the
  caller's responsibility to free the buffer.

  @param[in] FileHandle         The file handle of the file for which information is
                                being requested.

  @retval NULL                  Information could not be retrieved.

  @return                       The information about the file.
**/
EFI_FILE_INFO*
EFIAPI
ShellGetFileInfo (
  IN SHELL_FILE_HANDLE          FileHandle
  );

 

需要FileHandle作为输入函数,输出结果是 EFI_FILE_INFO 结构体。 这个结构体可以在
\MdePkg\Include\Guid\FileInfo.h 这个文件中看到(同时在 \EdkCompatibilityPkg\Foundation\Efi\Protocol\FileInfo\FileInfo.h 里面也有一个定义,只是这个定义未参加编译)。需要注意,调用的函数负责给结果分配一块内存,你自己的程序要负责释放这块内存的。

typedef struct {
  ///
  /// The size of the EFI_FILE_INFO structure, including the Null-terminated FileName string.
  ///
  UINT64    Size;
  ///
  /// The size of the file in bytes.
  ///
  UINT64    FileSize;
  ///
  /// PhysicalSize The amount of physical space the file consumes on the file system volume.
  ///
  UINT64    PhysicalSize;
  ///
  /// The time the file was created.
  ///
  EFI_TIME  CreateTime;
  ///
  /// The time when the file was last accessed.
  ///
  EFI_TIME  LastAccessTime;
  ///
  /// The time when the file's contents were last modified.
  ///
  EFI_TIME  ModificationTime;
  ///
  /// The attribute bits for the file.
  ///
  UINT64    Attribute;
  ///
  /// The Null-terminated name of the file.
  ///
  CHAR16    FileName[1];
} EFI_FILE_INFO;

 

看这个结构体可以得知,我们能够获得文件的大小,创建时间,修改时间属性文件名等等。

对于时间的定义 EFI_TIME 可以在 \BaseTools\Source\C\Include\Common\UefiBaseTypes.h 看到。相比之前我们看过的 time_t ,这个结构体是很单纯的定义,不需要换算:

// EFI Time Abstraction:
//  Year:       2000 - 20XX
//  Month:      1 - 12
//  Day:        1 - 31
//  Hour:       0 - 23
//  Minute:     0 - 59
//  Second:     0 - 59
//  Nanosecond: 0 - 999,999,999
//  TimeZone:   -1440 to 1440 or 2047
//
typedef struct {
  UINT16  Year;
  UINT8   Month;
  UINT8   Day;
  UINT8   Hour;
  UINT8   Minute;
  UINT8   Second;
  UINT8   Pad1;
  UINT32  Nanosecond;
  INT16   TimeZone;
  UINT8   Daylight;
  UINT8   Pad2;
} EFI_TIME;

 

对于 Attribute 的定义,在 \MdePkg\Include\Protocol\SimpleFileSystem.h

//
// File attributes
//
#define EFI_FILE_READ_ONLY  0x0000000000000001ULL
#define EFI_FILE_HIDDEN     0x0000000000000002ULL
#define EFI_FILE_SYSTEM     0x0000000000000004ULL
#define EFI_FILE_RESERVED   0x0000000000000008ULL
#define EFI_FILE_DIRECTORY  0x0000000000000010ULL
#define EFI_FILE_ARCHIVE    0x0000000000000020ULL
#define EFI_FILE_VALID_ATTR 0x0000000000000037ULL

 

最后,写一个程序验证一下

#include  <Uefi.h>
#include  <Library/UefiLib.h>
#include  <Library/ShellCEntryLib.h>

#include  <stdio.h>
#include  <stdlib.h>
#include  <wchar.h>

#include <Protocol/EfiShell.h>
#include <Library/ShellLib.h>

extern EFI_BOOT_SERVICES         *gBS;
extern EFI_SYSTEM_TABLE			 *gST;
extern EFI_RUNTIME_SERVICES 	 *gRT;

extern EFI_SHELL_PROTOCOL        *gEfiShellProtocol;

int
EFIAPI
main (
  IN int Argc,
  IN char **Argv
  )
{
  EFI_FILE_HANDLE   FileHandle;
  RETURN_STATUS     Status;
  EFI_FILE_INFO     *FileInfo = NULL;
  
  Status = ShellOpenFileByName(L"fsnt0:", (SHELL_FILE_HANDLE *)&FileHandle,
                               EFI_FILE_MODE_READ , 0);

  if(Status != RETURN_SUCCESS) {
        Print(L"OpenFile failed!\n");
		return EFI_SUCCESS;
      }							   

  FileInfo = ShellGetFileInfo( (SHELL_FILE_HANDLE)FileHandle);	

  Print(L"Filesize [%ld] bytes\n",FileInfo-> FileSize);
  Print(L"PhysicalSize [%ld] bytes\n",FileInfo-> PhysicalSize);  

  Print(L"File Create date [%d-%d-%d %d-%d-%d]\n",
		FileInfo-> CreateTime.Year,
		FileInfo-> CreateTime.Month,
		FileInfo-> CreateTime.Day,
		FileInfo-> CreateTime.Hour,
		FileInfo-> CreateTime.Minute,
		FileInfo-> CreateTime.Second);    
		
  Print(L"File last accessed date [%d-%d-%d %d-%d-%d]\n",
		FileInfo-> LastAccessTime.Year,
		FileInfo-> LastAccessTime.Month,
		FileInfo-> LastAccessTime.Day,
		FileInfo-> LastAccessTime.Hour,
		FileInfo-> LastAccessTime.Minute,
		FileInfo-> LastAccessTime.Second);   		
		
  Print(L"File last modification date [%d-%d-%d %d-%d-%d]\n",
		FileInfo-> ModificationTime.Year,
		FileInfo-> ModificationTime.Month,
		FileInfo-> ModificationTime.Day,
		FileInfo-> ModificationTime.Hour,
		FileInfo-> ModificationTime.Minute,
		FileInfo-> ModificationTime.Second);   		

  Print(L"File Name [%s]\n",&FileInfo->FileName[0]);  
		
  free(FileInfo);  // Free up the buffer from ShellGetFileInfo()  
  
  return EFI_SUCCESS;
}

 

getfileinfo

代码下载:
GetFileInfo

参考:

1.本文的例子参考 \ShellPkg\Library\UefiShellLevel3CommandsLib\Touch.c