重新编译EDK2工具的方法(Python部分)

之前在《重新编译EDK2工具的方法(C语言部分)》【参考1】中介绍了重新编译C语言编写的编译工具的方法。本文介绍重新编译Python工具的方法。

我们知道,每次编译时,先运行 edksetup.bat 然后使用 build 命令即可进行编译。下面先说build命令的来龙去脉。

我们运行的Build实际上是 BaseTools\bin\Win32 下面的 Build.exe 。运行 edksetup.bat 之后,会自动把这个目录加入到 Path 中。它的源代码可以在BaseTools\Source\Python下面找到。

根据BaseTools\Source\Python\MakeFile中的建议,编译需要使用 cx_Freeze 4.2.3 和 Python 2.7.2。Python是解释型语言,需要解释器才能正常执行程序,Cx_Freeze是将Python源程序转换为EXE的工具,转换之后即可脱离Python解析器单独运行(相当于把解释器打包到EXE中)。特别提醒,一定要使用上面说的这个版本, cx_Freeze版本之间差别很大,选择其他版本会有莫名的问题。这里【参考2】提供上述版本的下载,有需要的朋友可以直接抓取。

接下来是Python的安装,安装完之后,在命令行下手工输入 Python查看能否运行,如果无法运行,请在环境变量中加入Python的路径。如下图所示。

image001

加入Path后,可以在任意位置调用到Python。

image002

之后安装cx_Freeze。安装完成之后在Python27\Scripts下面会有cxfreeze.bat文件,可以运行这个批处理检查是否能正常工作。

image003

还可以编写一个简单的Python文件然后使用下面的命令生成EXE进行测试
cxfreeze hello.py –target-dir dist

最后,可以开始重新编译工具了。在toolsetup.bat 中加入下面语句指定 cxFreeze 和Python的路径。
Set PYTHON_HOME=c:\python27
Set PYTHON_FREEZE_PATH=c:\python27\Scripts

image004

编译的方法是:首先运行 edksetup.bat ,然后进入BaseTools目录,运行
toolsetup.bat ForceRebuild

image005

运行结果如下

image006

编译后生成的EXE 会直接放置到 BaseTools\Bin\Win32下面。

为了验证这个方法,我在 Build.py上加入输出字符串的语句,重新编译工具后再编译整个BIOS。可以看到执行了我加入的语句。

image007

如果你对 buid 的过程感兴趣,下面就可以慢慢分析了。

就是这样。

参考:

1. http://www.lab-z.com/%E9%87%8D%E6%96%B0%E7%BC%96%E8%AF%91edk2%E5%B7%A5%E5%85%B7%E7%9A%84%E6%96%B9%E6%B3%95%EF%BC%88c%E8%AF%AD%E8%A8%80%E9%83%A8%E5%88%86%EF%BC%89/ 重新编译EDK2工具的方法(C语言部分)》
2. Baidu 网盘链接: http://pan.baidu.com/s/1kTjDDf5 密码: 4wsf

Arduino 控制USB设备(4)解析描述符

前面一篇介绍了如何获得USB Descriptor,更麻烦的是这个数据的解读。在【参考1】给出了一个直接解析 Descriptor的例子。美中不足的是,这个例子只能在老版本的Arduino上工作(我估计是 0.22),在新版本 1.6.x 的IDE上会出现很多报错。

经过努力修改,终于可以编译通过(需要选择 Arduno Uno),程序如下:

/* MAX3421E USB Host controller configuration descriptor parser */
//#include "Spi.h"
#include "Max3421e.h"
#include "Usb.h"
#include "descriptor_parser.h"
 
#define LOBYTE(x) ((char*)(&(x)))[0]
#define HIBYTE(x) ((char*)(&(x)))[1]
#define BUFSIZE 256    //buffer size
#define DEVADDR 1

#define getReportDescr( addr, ep, nbytes, parse_func, nak_limit ) ctrlXfer( addr, ep, bmREQ_HIDREPORT, USB_REQUEST_GET_DESCRIPTOR, 0x00, HID_DESCRIPTOR_REPORT, 0x0000, nbytes, parse_func, nak_limit )
#define getReport( addr, ep, nbytes, interface, report_type, report_id, parse_func, nak_limit ) ctrlXfer( addr, ep, bmREQ_HIDIN, HID_REQUEST_GET_REPORT, report_id, report_type, interface, nbytes, parse_func, nak_limit )

/* Foeward declarations */ 
void setup();
void loop();
byte ctrlXfer( byte addr, byte ep, byte bmReqType, byte bRequest, byte wValLo, byte wValHi, unsigned int wInd, uint16_t nbytes, PARSE parse_func, uint16_t nak_limit );
void HIDreport_parse( uint8_t* buf, uint8_t* head, uint8_t* tail);

typedef struct {
  uint8_t bDescriptorType;
  uint16_t wDescriptorLength;
} HID_CLASS_DESCRIPTOR;


//typedef void (*PARSE)( int8_t*, int8_t*, int8_t );

MAX3421E Max;
USB Usb;
 
void setup()
{
  Serial.begin( 115200 );
  printProgStr(PSTR("\r\nStart"));
  Max.powerOn();
  delay( 200 );
}
 
void loop()
{
  uint8_t rcode;
  uint8_t tmpbyte = 0;

  //PARSE pf = &HIDreport_parse;
  /**/
  Max.Task();
  Usb.Task();
  if( Usb.getUsbTaskState() >= USB_STATE_CONFIGURING ) {  //state configuring or higher
  /* printing device descriptor */
    printProgStr(PSTR("\r\nDevice addressed... "));
    printProgStr(PSTR("Requesting device descriptor."));
    tmpbyte = getdevdescr( DEVADDR );                           //number of configurations, 0 if error   
    if( tmpbyte == 0 ) {
      printProgStr(PSTR("\r\nDevice descriptor cannot be retrieved. Program Halted\r\n"));
      while( 1 );           //stop
     }//if( tmpbyte
     /* print configuration descriptors for all configurations */
     for( uint8_t i = 0; i < tmpbyte; i++ ) {
       getconfdescr( DEVADDR, i );
     }   
  /* Stop */
      while( 1 );                          //stop
  }    
}

/* Prints device descriptor. Returns number of configurations or zero if request error occured */
byte getdevdescr( byte addr )
{
  USB_DEVICE_DESCRIPTOR buf;
  byte rcode;
  //Max.toggle( BPNT_0 );
  rcode = Usb.getDevDescr( addr, 0, 0x12, ( char *)&buf );
  if( rcode ) {
    printProgStr( rcode_error_msg );
    print_hex( rcode, 8 );
    return( 0 );
  }
  printProgStr(PSTR("\r\nDevice descriptor: \r\n"));
  //Descriptor length
  printProgStr( descr_len );
  print_hex( buf.bLength, 8 );
  //Descriptor type
//  printProgStr( descr_type );
//  print_hex( buf.bDescriptorType, 8 );
//  printProgStr( descrtype_parse( buf.bDescriptorType ));
  //USB Version
  printProgStr(PSTR("\r\nUSB version:\t\t"));
  Serial.print(( HIBYTE( buf.bcdUSB )), HEX );
  Serial.print(".");
  Serial.print(( LOBYTE( buf.bcdUSB )), HEX );
  //Device class
  printProgStr( class_str );
  print_hex( buf.bDeviceClass, 8 );
  printProgStr( classname_parse( buf.bDeviceClass ));
  //Device Subclass 
  printProgStr( subclass_str );
  print_hex( buf.bDeviceSubClass, 8 );
  //Device Protocol
  printProgStr( protocol_str );
  print_hex( buf.bDeviceProtocol, 8 );
  //Max.packet size
  printProgStr( maxpktsize_str );
  print_hex( buf.bMaxPacketSize0, 8 );
  //VID
  printProgStr(PSTR("\r\nVendor  ID:\t\t"));
  print_hex( buf.idVendor, 16 );
  //PID
  printProgStr(PSTR("\r\nProduct ID:\t\t"));
  print_hex( buf.idProduct, 16 );
  //Revision
  printProgStr(PSTR("\r\nRevision ID:\t\t"));
  print_hex( buf.bcdDevice, 16 );
  //Mfg.string
  printProgStr (PSTR("\r\nMfg.string index:\t"));
  print_hex( buf.iManufacturer, 8 );
  getstrdescr( addr, buf.iManufacturer );
  //Prod.string
  printProgStr(PSTR("\r\nProd.string index:\t"));
  print_hex( buf.iProduct, 8 );
  //printProgStr( str_cont );
  getstrdescr( addr, buf.iProduct );
  //Serial number string
  printProgStr(PSTR("\r\nSerial number index:\t"));
  print_hex( buf.iSerialNumber, 8 );
  //printProgStr( str_cont );
  getstrdescr( addr, buf.iSerialNumber );
  //Number of configurations
  printProgStr(PSTR("\r\nNumber of conf.:\t"));
  print_hex( buf.bNumConfigurations, 8 );
  return( buf.bNumConfigurations );
}
/* Get string descriptor. Takes device address and string index */
byte getstrdescr( byte addr, byte idx )
{
  char buf[ BUFSIZE ];
  byte rcode;
  byte length;
  byte i;
  unsigned int langid;
  if( idx == 0 ) {  //don't try to get index zero
    return( 0 );
  }
  rcode = Usb.getStrDescr( addr, 0, 1, 0, 0, buf );  //get language table length
  if( rcode ) {
    printProgStr(PSTR("\r\nError retrieving LangID table length"));
    return( rcode );
  }
  length = buf[ 0 ];      //length is the first byte
  rcode = Usb.getStrDescr( addr, 0, length, 0, 0, buf );  //get language table
  if( rcode ) {
    printProgStr(PSTR("\r\nError retrieving LangID table"));
    return( rcode );
  }
  HIBYTE( langid ) = buf[ 3 ];                            //get first langid  
  LOBYTE( langid ) = buf[ 2 ];                            //bytes are swapped to account for endiannes
  //printProgStr(PSTR("\r\nLanguage ID: "));
  //print_hex( langid, 16 );
  rcode = Usb.getStrDescr( addr, 0, 1, idx, langid, buf );
  if( rcode ) {
    printProgStr(PSTR("\r\nError retrieving string length"));
    return( rcode );
  }
  length = ( buf[ 0 ] < 254 ? buf[ 0 ] : 254 );
  printProgStr(PSTR(" Length: "));
  Serial.print( length, DEC ); 
  rcode = Usb.getStrDescr( addr, 0, length, idx, langid, buf );
  if( rcode ) {
    printProgStr(PSTR("\r\nError retrieveing string"));
    return( rcode );
  }
  printProgStr(PSTR(" Contents: "));
  for( i = 2; i < length; i+=2 ) {
    Serial.print( buf[ i ] );
  }
  return( idx );
}
/* Returns string to class name */
const char* classname_parse( byte class_number )
{
  switch( class_number ) {
    case 0x00:
      return PSTR(" Use class information in the Interface Descriptor");
    case 0x01:
      return PSTR(" Audio");
    case 0x02:
      return PSTR(" Communications and CDC Control");
    case 0x03:
      return PSTR(" HID (Human Interface Device)");
    case 0x05:
      return PSTR(" Physical");
    case 0x06:
      return PSTR(" Image");
    case 0x07:
      return PSTR(" Printer");
    case 0x08:
      return PSTR(" Mass Storage");
    case 0x09:
      return PSTR(" Hub");
    case 0x0a:
      return PSTR(" CDC-Data");
    case 0x0b:
      return PSTR(" Smart Card");
    case 0x0d:
      return PSTR(" Content Security");
    case 0x0e:
      return PSTR(" Video");
    case 0x0f:
      return PSTR(" Personal Healthcare");
    case 0xdc:
      return PSTR("Diagnostic Device");
    case 0xe0:
      return PSTR(" Wireless Controller");
    case 0xef:
      return PSTR(" Miscellaneous");
    case 0xfe:
      return PSTR(" Application Specific");
    case 0xff:
      return PSTR(" Vendor Specific");
    default:
      return unk_msg;
  }//switch( class_number
}            
/* Getting configuration descriptor */
byte getconfdescr( byte addr, byte conf )
{
  char buf[ BUFSIZE ];
  char* buf_ptr = buf;
  byte rcode;
  byte descr_length;
  byte descr_type;
  unsigned int total_length;
  printProgStr(PSTR("\r\n\nConfiguration number "));
  Serial.print( conf, HEX );
  rcode = Usb.getConfDescr( addr, 0, 4, conf, buf );  //get total length
  if( rcode ) {
    printProgStr(PSTR("Error retrieving configuration length. Error code "));
    Serial.println( rcode, HEX );
    return( 0 );
  }//if( rcode
  LOBYTE( total_length ) = buf[ 2 ];
  HIBYTE( total_length ) = buf[ 3 ];
  printProgStr(PSTR("\r\nTotal configuration length: "));
  Serial.print( total_length, DEC );
  printProgStr(PSTR(" bytes"));
  if( total_length > BUFSIZE ) {    //check if total length is larger than buffer
    printProgStr(PSTR("Total length truncated to "));
    Serial.print( BUFSIZE, DEC);
    printProgStr(PSTR("bytes"));
    total_length = BUFSIZE;
  }
  rcode = Usb.getConfDescr( addr, 0, total_length, conf, buf ); //get the whole descriptor
  while( buf_ptr < buf + total_length ) {  //parsing descriptors
    descr_length = *( buf_ptr );
    descr_type = *( buf_ptr + 1 );
    switch( descr_type ) {
      case( USB_DESCRIPTOR_CONFIGURATION ):
        printconfdescr( buf_ptr );
        break;
      case( USB_DESCRIPTOR_INTERFACE ):
        printintfdescr( buf_ptr );
        break;
      case( USB_DESCRIPTOR_ENDPOINT ):
        printepdescr( buf_ptr );
        break;
      case( HID_DESCRIPTOR_HID ):
        printhid_descr( buf_ptr );
        break;
      default:
        printunkdescr( buf_ptr );
        break;
        }//switch( descr_type
    Serial.println("");    
    buf_ptr = ( buf_ptr + descr_length );    //advance buffer pointer
  }//while( buf_ptr <=...
  return( 0 );
}
/* function to print configuration descriptor */
void printconfdescr( char* descr_ptr )
{
 USB_CONFIGURATION_DESCRIPTOR* conf_ptr = ( USB_CONFIGURATION_DESCRIPTOR* )descr_ptr;
 uint8_t tmpbyte;
  printProgStr(PSTR("\r\n\nConfiguration descriptor:"));
  printProgStr(PSTR("\r\nTotal length:\t\t"));
  print_hex( conf_ptr->wTotalLength, 16 );
  printProgStr(PSTR("\r\nNumber of interfaces:\t"));
  print_hex( conf_ptr->bNumInterfaces, 8 );
  printProgStr(PSTR("\r\nConfiguration value:\t"));
  print_hex( conf_ptr->bConfigurationValue, 8 );
  printProgStr(PSTR("\r\nConfiguration string:\t"));
  tmpbyte = conf_ptr->iConfiguration;
  print_hex( tmpbyte, 8 );
  getstrdescr( DEVADDR, tmpbyte );
  printProgStr(PSTR("\r\nAttributes:\t\t"));
  tmpbyte = conf_ptr->bmAttributes;
  print_hex( tmpbyte, 8 );
  if( tmpbyte & 0x40 ) {  //D6
    printProgStr(PSTR(" Self-powered"));
  }
  if( tmpbyte & 0x20 ) { //D5
    printProgStr(PSTR(" Remote Wakeup"));
  }
  printProgStr(PSTR("\r\nMax.power:\t\t"));
  tmpbyte = conf_ptr->bMaxPower;
  print_hex( tmpbyte, 8 );
  printProgStr(PSTR(" "));
  Serial.print(( tmpbyte * 2 ), DEC);
  printProgStr(PSTR("ma"));
  return;
}
/* function to print interface descriptor */
void printintfdescr( char* descr_ptr )
{
 USB_INTERFACE_DESCRIPTOR* intf_ptr = ( USB_INTERFACE_DESCRIPTOR* )descr_ptr;
 uint8_t tmpbyte;
  printProgStr(PSTR("\r\nInterface descriptor:"));
  printProgStr(PSTR("\r\nInterface number:\t"));
  print_hex( intf_ptr->bInterfaceNumber, 8 );
  printProgStr(PSTR("\r\nAlternate setting:\t"));
  print_hex( intf_ptr->bAlternateSetting, 8 );
  printProgStr(PSTR("\r\nEndpoints:\t\t"));
  print_hex( intf_ptr->bNumEndpoints, 8 );
  printProgStr( class_str );
  tmpbyte = intf_ptr->bInterfaceClass;
  print_hex( tmpbyte, 8 );
  printProgStr(classname_parse( tmpbyte ));
  printProgStr( subclass_str );
  print_hex( intf_ptr->bInterfaceSubClass, 8 );
  printProgStr( protocol_str );
  print_hex( intf_ptr->bInterfaceProtocol, 8 );
  printProgStr(PSTR("\r\nInterface string:\t"));
  tmpbyte = intf_ptr->iInterface;
  print_hex( tmpbyte, 8 );
  getstrdescr( DEVADDR, tmpbyte );
  return;
}
/* function to print endpoint descriptor */
void printepdescr( char* descr_ptr )
{
 USB_ENDPOINT_DESCRIPTOR* ep_ptr = ( USB_ENDPOINT_DESCRIPTOR* )descr_ptr;
 uint8_t tmpbyte;
  printProgStr(PSTR("\r\nEndpoint descriptor:"));
  printProgStr(PSTR("\r\nEndpoint address:\t"));
  tmpbyte = ep_ptr->bEndpointAddress;
  print_hex( tmpbyte & 0x0f, 8 );
  printProgStr(PSTR(" Direction: "));
  ( tmpbyte & 0x80 ) ? printProgStr(PSTR("IN")) : printProgStr(PSTR("OUT"));
  printProgStr(PSTR("\r\nAttributes:\t\t"));
  tmpbyte = ep_ptr->bmAttributes;
  print_hex( tmpbyte, 8 );
  printProgStr(PSTR(" Transfer type: "));
  printProgStr((char*)pgm_read_word(&transfer_types[(tmpbyte & 0x03)]));
  if(( tmpbyte & 0x03 ) == 1 ) {  //Isochronous Transfer
    printProgStr(PSTR(", Sync Type: "));
    printProgStr((char*)pgm_read_word(&sync_types[(tmpbyte & 0x0c)]));
    printProgStr(PSTR(", Usage Type: "));
    printProgStr((char*)pgm_read_word(&usage_types[(tmpbyte & 0x30)]));
  }//if( tmpbyte & 0x01
  printProgStr( maxpktsize_str );
  print_hex( ep_ptr->wMaxPacketSize, 16 );
  printProgStr(PSTR("\r\nPolling interval:\t"));
  tmpbyte = ep_ptr->bInterval;
  print_hex( tmpbyte, 8 );
  printProgStr(PSTR(" "));
  Serial.print( tmpbyte, DEC );
  printProgStr(PSTR(" ms"));
  return;
}
/* function to print HID descriptor */
void printhid_descr( char* descr_ptr )
{
 PARSE pf = &HIDreport_parse;
 USB_HID_DESCRIPTOR* hid_ptr = ( USB_HID_DESCRIPTOR* )descr_ptr;
 uint8_t tmpbyte;
  /**/
  printProgStr(PSTR("\r\nHID descriptor:"));
  printProgStr(PSTR("\r\nDescriptor length:\t"));
  tmpbyte = hid_ptr->bLength;
  print_hex( tmpbyte, 8 );
  printProgStr(PSTR(" "));
  Serial.print( tmpbyte, DEC );
  printProgStr(PSTR(" bytes"));
  printProgStr(PSTR("\r\nHID version:\t\t"));
  Serial.print(( HIBYTE( hid_ptr->bcdHID )), HEX );
  Serial.print(".");
  Serial.print(( LOBYTE( hid_ptr->bcdHID )), HEX );
  tmpbyte = hid_ptr->bCountryCode;
  printProgStr(PSTR("\r\nCountry Code:\t\t"));
  Serial.print( tmpbyte, DEC );
  printProgStr(PSTR(" "));
  ( tmpbyte > 35 ) ? printProgStr(PSTR("Reserved")) : printProgStr((char*)pgm_read_word(&HID_Country_Codes[ tmpbyte ]));
  tmpbyte = hid_ptr->bNumDescriptors;
  printProgStr(PSTR("\r\nClass Descriptors:\t"));
  Serial.print( tmpbyte, DEC );
  //Printing class descriptors
  descr_ptr += 6; //advance buffer pointer
  for( uint8_t i = 0; i < tmpbyte; i++ ) {
    uint8_t tmpdata;
    HID_CLASS_DESCRIPTOR* hidclass_ptr = ( HID_CLASS_DESCRIPTOR* )descr_ptr;
    tmpdata = hidclass_ptr->bDescriptorType;
    printProgStr(PSTR("\r\nClass Descriptor Type:\t"));
    Serial.print( tmpdata, HEX );
    if(( tmpdata < 0x21 ) || ( tmpdata > 0x2f )) {
     printProgStr(PSTR(" Invalid"));
    }
    switch( tmpdata ) {
      case 0x21:
        printProgStr(PSTR(" HID"));
        break;
      case 0x22:
        printProgStr(PSTR(" Report"));
        break;
      case 0x23:
        printProgStr(PSTR(" Physical"));
        break;
      default:
        printProgStr(PSTR(" Reserved"));
        break;
    }//switch( tmpdata
    printProgStr(PSTR("\r\nClass Descriptor Length:"));
    Serial.print( hidclass_ptr->wDescriptorLength );
    printProgStr(PSTR(" bytes"));
    printProgStr(PSTR("\r\n\nHID report descriptor:\r\n"));
    getReportDescr( DEVADDR, 0 , hidclass_ptr->wDescriptorLength, pf, USB_NAK_LIMIT );
    descr_ptr += 3; //advance to the next record
  }//for( uint8_t i=...
  return;
}
/*function to print unknown descriptor */
void printunkdescr( char* descr_ptr )
{
  byte length = *descr_ptr;
  byte i;
  printProgStr(PSTR("\r\nUnknown descriptor:"));
  printProgStr(PSTR("Length:\t\t"));
  print_hex( *descr_ptr, 8 );
  printProgStr(PSTR("\r\nType:\t\t"));
  print_hex( *(descr_ptr + 1 ), 8 );
  printProgStr(PSTR("\r\nContents:\t"));
  descr_ptr += 2;
  for( i = 0; i < length; i++ ) {
    print_hex( *descr_ptr, 8 );
    descr_ptr++;
  }
}
/* Control-IN transfer with callback. Sets address, endpoint, fills control packet with necessary data, dispatches control packet, and initiates bulk IN transfer   */
/* Control, data, and setup stages combined from standard USB library to be able to read large data blocks. Restricted to control-IN transfers with data stage   */
/* data read and MAX3421E RECV FIFO buffer release shall be performed by parse_func callback */
/* return codes:                */
/* 00       =   success         */
/* 01-0f    =   non-zero HRSLT  */
byte ctrlXfer( byte addr, byte ep, byte bmReqType, byte bRequest, byte wValLo, byte wValHi, unsigned int wInd, uint16_t nbytes, PARSE parse_func, uint16_t nak_limit = USB_NAK_LIMIT )
{
 byte rcode;   
 SETUP_PKT sp;
 EP_RECORD* ep_rec = Usb.getDevTableEntry( addr, ep );
 byte pktsize;
 byte maxpktsize = ep_rec->MaxPktSize;
 unsigned int xfrlen = 0;
  /**/
  Max.regWr( rPERADDR, addr );                    //set peripheral address
  /* fill in setup packet */
  sp.ReqType_u.bmRequestType = bmReqType;
  sp.bRequest = bRequest;
  sp.wVal_u.wValueLo = wValLo;
  sp.wVal_u.wValueHi = wValHi;
  sp.wIndex = wInd;
  sp.wLength = nbytes;
  Max.bytesWr( rSUDFIFO, 8, ( char *)&sp );    //transfer to setup packet FIFO
  rcode = Usb.dispatchPkt( tokSETUP, ep, nak_limit );            //dispatch packet
  //Serial.println("Setup packet");   //DEBUG
  if( rcode ) {                                   //return HRSLT if not zero
      printProgStr(PSTR("\r\nSetup packet error: "));
      Serial.print( rcode, HEX );                                          
      return( rcode );
  }
  /* Data stage */
  //ep_rec->rcvToggle = bmRCVTOG1;
  Max.regWr( rHCTL, bmRCVTOG1 );  //set toggle
  while( 1 ) {                    //exited by break
    /* request data */
    rcode = Usb.dispatchPkt( tokIN, ep, nak_limit );
    if( rcode ) {
      printProgStr(PSTR("\r\nData Stage Error: "));
      Serial.print( rcode, HEX );
      return( rcode );
    }
    /* check for RCVDAVIRQ and generate error if not present */ 
    /* the only case when absense of RCVDAVIRQ makes sense is when toggle error occured. Need to add handling for that */
    if(( Max.regRd( rHIRQ ) & bmRCVDAVIRQ ) == 0 ) {
      printProgStr(PSTR("\r\nData Toggle error."));
      return ( 0xf0 );                            
    }    
    pktsize = Max.regRd( rRCVBC );  //get received bytes count
    parse_func( pktsize );          //call parse function. Parse is expected to read the FIFO completely
    Max.regWr( rHIRQ, bmRCVDAVIRQ );                    // Clear the IRQ & free the buffer
    xfrlen += pktsize;                              // add this packet's byte count to total transfer length
    /* The transfer is complete under two conditions:           */
    /* 1. The device sent a short packet (L.T. maxPacketSize)   */
    /* 2. 'nbytes' have been transferred.                       */
    if (( pktsize < maxpktsize ) || (xfrlen >= nbytes )) {      // have we transferred 'nbytes' bytes?
      break;
    }
  }//while( 1 )
  rcode = Usb.dispatchPkt( tokOUTHS, ep, nak_limit );
  if( rcode ) {   //return error
    printProgStr(PSTR("Status packet error: "));
    Serial.print( rcode, HEX );                                          
  }
  return( rcode );
}
/* Parses bitfields in main items */
void print_mainbitfield( uint8_t byte_toparse )
{
  ( byte_toparse & 0x01 ) ? printProgStr(PSTR("Constant,")) : printProgStr(PSTR("Data,"));  //bit 0
  ( byte_toparse & 0x02 ) ? printProgStr(PSTR("Variable,")) : printProgStr(PSTR("Array,"));  //bit 1
  ( byte_toparse & 0x04 ) ? printProgStr(PSTR("Relative,")) : printProgStr(PSTR("Absolute,"));  //...
  ( byte_toparse & 0x08 ) ? printProgStr(PSTR("Wrap,")) : printProgStr(PSTR("No Wrap,"));
  ( byte_toparse & 0x10 ) ? printProgStr(PSTR("Non Linear,")) : printProgStr(PSTR("Linear,"));
  ( byte_toparse & 0x20 ) ? printProgStr(PSTR("No preferred,")) : printProgStr(PSTR("Preferred State,"));
  ( byte_toparse & 0x40 ) ? printProgStr(PSTR("Null State,")) : printProgStr(PSTR("No Null Position,"));  //bit 6
  ( byte_toparse & 0x40 ) ? printProgStr(PSTR("Volatile( ignore for Input),")) : printProgStr(PSTR("Non-volatile(Ignore for Input),"));  //bit 7
}
/* HID Report Desriptor Parser Callback             */
/* called repeatedly from Control transfer function */
void HIDreport_parse( uint8_t pkt_size )
{
#define B_SIZE 0x03        //bSize bitmask
#define B_TYPE 0x0c        //bType bitmask
#define B_TAG  0xf0        //bTag bitmask
 /* parser states */
 enum STATE { ITEM_START, DATA_PARSE };
 static STATE state = ITEM_START;
 static uint8_t databytes_left = 0;
 static uint8_t prefix;              //item prefix - type and tag
 uint8_t byte_toparse;
 uint8_t bType;
 uint8_t tmpbyte;
 /**/
  while( 1 ) {
     if( pkt_size ) {
       byte_toparse = Max.regRd( rRCVFIFO );  //read a byte from FIFO
       pkt_size--;
     }
     else {
       return;                                //all bytes read
     }
     switch( state ) {
      case ITEM_START:  //start of the record
        prefix = byte_toparse >>2;        //store prefix for databyte parsing
        tmpbyte = byte_toparse & B_SIZE; 
        /* get item length */
        ( tmpbyte == 0x03 ) ? databytes_left = 4 : databytes_left = tmpbyte;
         if( databytes_left ) {
           state = DATA_PARSE;    //read bytes after prefix
         }
         printProgStr(PSTR("\r\nLength: "));
         Serial.print( databytes_left, DEC );
         /* get item type */
         bType = ( byte_toparse & B_TYPE ) >>2;
         printProgStr(PSTR("  Type: "));
         printProgStr((char*)pgm_read_word(&btypes[ bType ]));
         /* get item tag */
         printProgStr(PSTR("\t\tTag: "));
         tmpbyte = ( byte_toparse & B_TAG ) >>4 ;
         switch( bType ) {
           case 0:  //Main
             if( tmpbyte < 0x08 ) {
               printProgStr(PSTR("Invalid Tag"));
             }
             else if( tmpbyte > 0x0c ) {
               printProgStr( reserved_msg ); 
             }
             else {
               printProgStr((char*)pgm_read_word(&maintags[ tmpbyte - 8 /* & 0x03 */]));
               //Serial.print("Byte: ");
               //Serial.println( tmpbyte, HEX );
             }
             break;//case 0 Main
           case 1:  //Global
             ( tmpbyte > 0x0b ) ? printProgStr( reserved_msg ) : printProgStr((char*)pgm_read_word(&globaltags[ tmpbyte ]));
             break;//case 1 Global
           case 2:  //Local
             ( tmpbyte > 0x0a ) ? printProgStr( reserved_msg ) : printProgStr((char*)pgm_read_word(&localtags[ tmpbyte ]));
             break;//case 2 Local
           default:
             break;  
         }//switch( bType...        
         break;//case ITEM_START
       case DATA_PARSE:
         switch( prefix ) {
           case 0x20:  //Main Input
           case 0x24:  //Main Output
           case 0x2c:  //Main Feature
             /* todo: add parsing 8th bit */
             print_mainbitfield( byte_toparse );
             break;
           case 0x28:    //Main Collection
             if(( byte_toparse > 0x06 ) && ( byte_toparse < 0x80 )) {
               printProgStr( reserved_msg );
             }
             else if(( byte_toparse > 0x7f ) && ( byte_toparse <= 0xff )) {
               printProgStr(PSTR("Vendor-defined"));
             }
             else {
               printProgStr((char*)pgm_read_word(&collections[ byte_toparse ]));
             }
             break;//case 0x28 Main Collection           
           //case 0x30: //Main End Collection
           case 0x01:    //Global Usage Page
             switch( byte_toparse ) {  //see HID Usage Tables doc v.1.12 page 14
               case 0x00:              
               case 0x01:
               case 0x02:
               case 0x03:
               case 0x04:
               case 0x05:
               case 0x06:
               case 0x07:
               case 0x08:
               case 0x09:
               case 0x0a:
               case 0x0b:
               case 0x0c:
               case 0x0d:
               case 0x0e:
               case 0x0f:
               case 0x10:
                 printProgStr((char*)pgm_read_word(&usage_pages[ byte_toparse ]));
                 break;
               case 0x14:
                 printProgStr(PSTR("Alphanumeric Display"));
                 break;
               case 0x40:
                 printProgStr(PSTR("Medical Instruments"));
                 break;
               case 0x80:
               case 0x81:
               case 0x82:
               case 0x83:
                 printProgStr(PSTR("Monitor page"));
                 break;
               case 0x84:
               case 0x85:
               case 0x86:
               case 0x87:
                 printProgStr(PSTR("Power page"));
                 break;
               case 0x8c:
                 printProgStr(PSTR("Bar Code Scanner page"));
                 break;
               case 0x8d:
                 printProgStr(PSTR("Scale page"));
                 break;
               case 0x8e:
                 printProgStr(PSTR("Magnetic Stripe Reading (MSR) Devices"));
                 break;
               case 0x8f:
                 printProgStr(PSTR("Reserved Point of Sale pages"));
                 break;
               case 0x90:
                 printProgStr(PSTR("Camera Control Page"));
                 break;
               case 0x91: 
                 printProgStr(PSTR("Arcade Page"));
                 break;                
             default:
//               printProgStr(PSTR("Data: "));
//               print_hex( byte_toparse, 8 );
               //databytes_left--;
               break;           
             }//switch case 0x01:    //Global Usage Page
         }//switch( prefix ...         
         printProgStr(PSTR("  Data: "));
         print_hex( byte_toparse, 8 );
         databytes_left--;
         if( !databytes_left ) {
           state = ITEM_START;
         }
         break;
     }//switch( state...
   }//while( 1 ...
}
/* prints hex numbers with leading zeroes */
// copyright, Peter H Anderson, Baltimore, MD, Nov, '07
// source: http://www.phanderson.com/arduino/arduino_display.html
void print_hex(int v, int num_places)
{
  int mask=0, n, num_nibbles, digit;
 
  for (n=1; n<=num_places; n++) {
    mask = (mask << 1) | 0x0001;
  }
  v = v & mask; // truncate v to specified number of places
 
  num_nibbles = num_places / 4;
  if ((num_places % 4) != 0) {
    ++num_nibbles;
  }
  do {
    digit = ((v >> (num_nibbles-1) * 4)) & 0x0f;
    Serial.print(digit, HEX);
  } 
  while(--num_nibbles);
}

/* given a PROGMEM string, use Serial.print() to send it out       */
/* Some non-intuitive casting necessary:                           */
/* printProgStr(PSTR("Func.Mode:\t0x"));                           */
/* printProgStr((char*)pgm_read_word(&mtpopNames[(op & 0xFF)]));   */
void printProgStr(const char* str)
{
  if(!str) { 
    return;
  }
  char c;
  while((c = pgm_read_byte(str++))) {
    Serial.write(c);
  }
  return;
}

 

工作的照片:

usbkbs

我用USB Shield挂接了一个USB小键盘,获得的结果如下:

Start
Device addressed… Requesting device descriptor.
Device descriptor:

Descriptor Length: 12
USB version: 1.10
Class: 00 Use class information in the Interface Descriptor
Subclass: 00
Protocol: 00
Max.packet size: 08
Vendor ID: 13BA
Product ID: 0001
Revision ID: 0100
Mfg.string index: 00
Prod.string index: 00
Serial number index: 00
Number of conf.: 01

Configuration number 0
Total configuration length: 34 bytes

Configuration descriptor:
Total length: 0022
Number of interfaces: 01
Configuration value: 01
Configuration string: 00
Attributes: A0 Remote Wakeup
Max.power: 32 100ma

Interface descriptor:
Interface number: 00
Alternate setting: 00
Endpoints: 01
Class: 03 HID (Human Interface Device)
Subclass: 01
Protocol: 01
Interface string: 00

HID descriptor:
Descriptor length: 09 9 bytes
HID version: 1.10
Country Code: 0 Not Supported
Class Descriptors: 1
Class Descriptor Type: 22 Report
Class Descriptor Length:54 bytes

HID report descriptor:

Length: 1 Type: Global Tag: Usage Page Generic Desktop Controls Data: 01
Length: 1 Type: Local Tag: Usage Data: 06
Length: 1 Type: Main Tag: Collection Application (mouse, keyboard) Data: 01
Length: 1 Type: Global Tag: Usage Page LEDs Data: 08
Length: 1 Type: Local Tag: Usage Minimum Data: 01
Length: 1 Type: Local Tag: Usage Maximum Data: 03
Length: 1 Type: Global Tag: Logical Minimum Data: 00
Length: 1 Type: Global Tag: Logical Maximum Data: 01
Length: 1 Type: Global Tag: Report Size Data: 01
Length: 1 Type: Global Tag: Report Count Data: 03
Length: 1 Type: Main Tag: Output Data,Variable,Absolute,No Wrap,Linear,Preferred State,No Null Position,Non-volatile(Ignore for Input), Data: 02
Length: 1 Type: Global Tag: Report Count Data: 05
Length: 1 Type: Main Tag: Output Constant,Array,Absolute,No Wrap,Linear,Preferred State,No Null Position,Non-volatile(Ignore for Input), Data: 01
Length: 1 Type: Global Tag: Usage Page Keyboard/Keypad Data: 07
Length: 1 Type: Local Tag: Usage Minimum Data: E0
Length: 1 Type: Local Tag: Usage Maximum Data: E7
Length: 1 Type: Global Tag: Report Count Data: 08
Length: 1 Type: Main Tag: Input Data,Variable,Absolute,No Wrap,Linear,Preferred State,No Null Position,Non-volatile(Ignore for Input), Data: 02
Length: 1 Type: Global Tag: Report Size Data: 08
Length: 1 Type: Global Tag: Report Count Data: 01
Length: 1 Type: Main Tag: Input Constant,Array,Absolute,No Wrap,Linear,Preferred State,No Null Position,Non-volatile(Ignore for Input), Data: 01
Length: 1 Type: Local Tag: Usage Minimum Data: 00
Length: 1 Type: Local Tag: Usage Maximum Data: 91
Length: 2 Type: Global Tag: Logical Maximum Data: FF Data: 00
Length: 1 Type: Global Tag: Report Count Data: 06
Length: 1 Type: Main Tag: Input Data,Array,Absolute,No Wrap,Linear,Preferred State,No Null Position,Non-volatile(Ignore for Input), Data: 00
Length: 0 Type: Main Tag: End Collection

Endpoint descriptor:
Endpoint address: 01 Direction: IN
Attributes: 03 Transfer type: Interrupt
Max.packet size: 0008
Polling interval: 0A 10 ms

修改后的可以正常编译的代码下载

descriptor_parser

参考:

1. https://github.com/felis/USB_Host_Shield/tree/master/examples/descriptor_parser USB_Host_Shield/examples/descriptor_parser/

Step to UEFI (57) —– 只在一个有显示?

之前的很多实验都有一个奇怪的显现,开出了2个模拟窗口,只有一个上面有显示。琢磨了一下,猜测是因为只打开了一个设备上面的Protocol,于是用命令查看了一下有Graphics 的 Protocol,发现有三个(模拟环境下)

handle

之前我们的代码都是用 gBS->LocateProtocol 打开的,这个函数的意思是“是从内核中找出指定Protocol的第一个实例。”【参考1】

gBS->LocateProtocol(&GraphicsOutputProtocolGuid, NULL, (VOID **) &GraphicsOutput);

 

我们遇到问题就是【参考1】中提到的:“UEFI内核中某个Protocol的实例可能不止一个,例如每个硬盘及每个分区都有一个EFI_DISK_IO_PROTOCOL实例。LocateProtocol顺序搜索HANDLE链表,返回找到的第一个该Protocol的实例。我们可以用BootServices提供的其它函数处理HANDLE和Protocol。”

编写代码如下,枚举系统中的所有实例,然后逐个打开并且调用:

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

#include  <stdio.h>
#include  <stdlib.h>
#include  <wchar.h>
#include  <time.h>
#include <Protocol/EfiShell.h>
#include <Library/ShellLib.h>

#include <Protocol/SimpleFileSystem.h>
#include <Protocol/BlockIo.h>
#include <Library/DevicePathLib.h>
#include <Library/HandleParsingLib.h>
#include <Library/SortLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/BaseMemoryLib.h>

#include <Protocol/LoadedImage.h>



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

extern EFI_SHELL_ENVIRONMENT2    *mEfiShellEnvironment2;
extern EFI_HANDLE				 gImageHandle;

static EFI_GUID GraphicsOutputProtocolGuid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
static EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput = NULL;

//Copied from  C\MdePkg\Include\Protocol\UgaDraw.h
typedef struct {
  UINT8 Blue;
  UINT8 Green;
  UINT8 Red;
  UINT8 Reserved;
} EFI_UGA_PIXEL;


int
EFIAPI
main (                                         
  IN int Argc,
  IN char **Argv
  )
{
    EFI_STATUS    Status;
    UINTN i;
    UINTN HandleIndex;	
	EFI_GRAPHICS_OUTPUT_BLT_PIXEL FillColor;
    UINTN HandleCount;
	EFI_HANDLE   *HandleBuffer;
    //
    // Search for the shell protocol
    //
    Status = gBS->LocateHandleBuffer(
	 ByProtocol,
      &GraphicsOutputProtocolGuid,
      NULL,
	  &HandleCount,
      &HandleBuffer
     );

    Print(L"[%d] \r\n",HandleCount);
	 
	for (HandleIndex=0; HandleIndex<HandleCount;HandleIndex++)
	{
		Status = gBS -> HandleProtocol (
							HandleBuffer[HandleIndex],
							&gEfiGraphicsOutputProtocolGuid,
							(void **)&GraphicsOutput);
		if (!(EFI_ERROR(Status))) {
			for (i=0;i<100;i++) {
				FillColor.Blue=rand() % 256;
				FillColor.Red=rand() % 256;
				FillColor.Green=rand() % 256;
	
				GraphicsOutput->Blt(GraphicsOutput, &FillColor, EfiBltVideoFill,
					0, 
					0 , 
					rand() % (GraphicsOutput->Mode->Info->HorizontalResolution-100), 
					rand() % (GraphicsOutput->Mode->Info->VerticalResolution-100), 
					100, 100, 0); 
				gBS->Stall(50000);
			} // For i
		}
		else {
		    Print(L"Error @[%d] \r\n",HandleCount);
		}
	} // For HandleIndex		

  return EFI_SUCCESS;
  
}

 

运行结果:

gfxtest6

可以看到现在两个窗口都会有显示。

完整代码下载:

GFXTest6

参考:

1.http://www.cppblog.com/djxzh/archive/2012/03/06/167106.html UEFI 实战(4) protocol

Step to UEFI (56) —– 在屏幕上显示一幅BMP

前面介绍了如何截图,如果把这个过程反过来,先是读取BMP文件到内存,然后重新排列RGB,再用Blt输出到Video上就是显示BMP的过程。

根据这个原理编写程序如下:

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

#include  <stdio.h>
#include  <stdlib.h>
#include  <wchar.h>
#include  <time.h>
#include <Protocol/EfiShell.h>
#include <Library/ShellLib.h>

#include <Protocol/SimpleFileSystem.h>
#include <Protocol/BlockIo.h>
#include <Library/DevicePathLib.h>
#include <Library/HandleParsingLib.h>
#include <Library/SortLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/BaseMemoryLib.h>

#include <Protocol/LoadedImage.h>

#define MAX_FILE_SIZE (1024*1024*1024)

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

extern EFI_SHELL_ENVIRONMENT2    *mEfiShellEnvironment2;
extern EFI_HANDLE				 gImageHandle;

static EFI_GUID GraphicsOutputProtocolGuid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
static EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput = NULL;

#pragma pack(1)

//Copied from  C\MdePkg\Include\Protocol\UgaDraw.h
typedef struct {
  UINT8 Blue;
  UINT8 Green;
  UINT8 Red;
  UINT8 Reserved;
} EFI_UGA_PIXEL;

/* This should be compatible with EFI_UGA_PIXEL */
typedef struct {
    UINT8 b, g, r, a;
} EG_PIXEL;

typedef struct {
    CHAR8         CharB;
    CHAR8         CharM;
    UINT32        Size;
    UINT16        Reserved[2];
    UINT32        ImageOffset;
    UINT32        HeaderSize;
    UINT32        PixelWidth;
    UINT32        PixelHeight;
    UINT16        Planes;       // Must be 1
    UINT16        BitPerPixel;  // 1, 4, 8, or 24
    UINT32        CompressionType;
    UINT32        ImageSize;    // Compressed image size in bytes
    UINT32        XPixelsPerMeter;
    UINT32        YPixelsPerMeter;
    UINT32        NumberOfColors;
    UINT32        ImportantColors;
} BMP_IMAGE_HEADER;

typedef struct {
    UINTN       Width;
    UINTN       Height;
    BOOLEAN     HasAlpha;
    EG_PIXEL    *PixelData;
} EG_IMAGE;
#pragma pack()



VOID egFreeImage(IN EG_IMAGE *Image)
{
    if (Image != NULL) {
        if (Image->PixelData != NULL)
            FreePool(Image->PixelData);
        FreePool(Image);
    }
}




static EFI_GUID ESPGuid = { 0xc12a7328, 0xf81f, 0x11d2, 
				{ 0xba, 0x4b, 0x00, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b } };

static EFI_STATUS egFindESP(OUT EFI_FILE_PROTOCOL *RootDir)
{
    EFI_STATUS          Status;

   

    return Status;
}

//
// Basic image handling
//

EG_IMAGE * egCreateImage(IN UINTN Width, IN UINTN Height, IN BOOLEAN HasAlpha)
{
    EG_IMAGE        *NewImage;
    
    NewImage = (EG_IMAGE *) AllocatePool(sizeof(EG_IMAGE));
    if (NewImage == NULL)
        return NULL;
    NewImage->PixelData = (EG_PIXEL *) AllocatePool(
								Width * Height * sizeof(EG_PIXEL));
    if (NewImage->PixelData == NULL) {
        FreePool(NewImage);
        return NULL;
    }

    NewImage->Width = Width;
    NewImage->Height = Height;
    NewImage->HasAlpha = HasAlpha;
    return NewImage;
}

EFI_STATUS LoadFile(  IN CHAR16 *FileName,
                      IN UINT8 **FileData, 
					  IN UINTN *FileDataLength)
{
    EFI_STATUS          Status;
    EFI_FILE_HANDLE     FileHandle;
    EFI_FILE_PROTOCOL   *Root;
	EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFileSystem;
	EFI_FILE_INFO     *FileInfo = NULL;
	
    Status = gBS->LocateProtocol(
						&gEfiSimpleFileSystemProtocolGuid, 
						NULL,
						(VOID **)&SimpleFileSystem);
    if (EFI_ERROR(Status)) {
		    Print(L"Cannot find EFI_SIMPLE_FILE_SYSTEM_PROTOCOL \r\n");
            return Status;	
	}

	Status = SimpleFileSystem->OpenVolume(SimpleFileSystem, &Root);
    if (EFI_ERROR(Status)) {
		    Print(L"OpenVolume error \r\n");
            return Status;	
	}

    Status = Root->Open(
							Root, 
							&FileHandle, 
							FileName,
							EFI_FILE_MODE_READ , 
							0);
    if (EFI_ERROR(Status))
	  {
        Print(L"Error Open NULL\n");
        return Status;
	  }	

	FileInfo = ShellGetFileInfo( (SHELL_FILE_HANDLE)FileHandle);	
    Print(L"Filesize [%ld] bytes\n",FileInfo-> FileSize);
	*FileDataLength=(UINTN) FileInfo->FileSize;
	
	*FileData  = AllocatePool((UINTN) FileInfo->FileSize);
    Status = FileHandle->Read(FileHandle, FileDataLength, *FileData );
    if (EFI_ERROR(Status)) {
		Print(L"Loading file error! \n");
	}
	Print(L"Get file size [%d]!\n",*FileDataLength);
    

    FileHandle->Close(FileHandle);
    
    return Status;
}


//
// Load BMP image
//

EG_IMAGE * egDecodeBMP
	(
		IN UINT8 *FileData, 
		IN UINTN FileDataLength, 
		IN BOOLEAN WantAlpha)
{
    EG_IMAGE            *NewImage;
    BMP_IMAGE_HEADER    *BmpHeader;
    EFI_UGA_PIXEL       *BmpColorMap;
    UINTN               x, y;
    UINT8               *ImagePtr;
    UINT8               *ImagePtrBase;
    UINTN               ImageLineOffset;
    UINT8               ImageValue=0, AlphaValue;
    EG_PIXEL            *PixelPtr;
    UINTN               Index, BitIndex;

    // read and check header
    if (FileDataLength < sizeof(BMP_IMAGE_HEADER) || FileData == NULL)
        return NULL;

    BmpHeader = (BMP_IMAGE_HEADER *) FileData;
    if (BmpHeader->CharB != 'B' || BmpHeader->CharM != 'M')
        return NULL;

    if (BmpHeader->CompressionType != 0)
        return NULL;

    if (BmpHeader->BitPerPixel != 1 && BmpHeader->BitPerPixel != 4 &&
        BmpHeader->BitPerPixel != 8 && BmpHeader->BitPerPixel != 24)
        return NULL;

    // calculate parameters
    ImageLineOffset = BmpHeader->PixelWidth;
    if (BmpHeader->BitPerPixel == 24)
        ImageLineOffset *= 3;
    else if (BmpHeader->BitPerPixel == 1)
        ImageLineOffset = (ImageLineOffset + 7) >> 3;
    else if (BmpHeader->BitPerPixel == 4)
        ImageLineOffset = (ImageLineOffset + 1) >> 1;
    if ((ImageLineOffset % 4) != 0)
        ImageLineOffset = ImageLineOffset + (4 - (ImageLineOffset % 4));
    // check bounds
    if (BmpHeader->ImageOffset + 
			ImageLineOffset * BmpHeader->PixelHeight > FileDataLength)
        return NULL;
    
    // allocate image structure and buffer
    NewImage = egCreateImage(BmpHeader->PixelWidth, 
								BmpHeader->PixelHeight, WantAlpha);
    if (NewImage == NULL)
        return NULL;
    AlphaValue = WantAlpha ? 255 : 0;
    
    // convert image
    BmpColorMap = (EFI_UGA_PIXEL *)(FileData + sizeof(BMP_IMAGE_HEADER));
    ImagePtrBase = FileData + BmpHeader->ImageOffset;
    for (y = 0; y < BmpHeader->PixelHeight; y++) {
        ImagePtr = ImagePtrBase;
        ImagePtrBase += ImageLineOffset;
        PixelPtr = NewImage->PixelData + 
				(BmpHeader->PixelHeight - 1 - y) * BmpHeader->PixelWidth;
        
        switch (BmpHeader->BitPerPixel) {
            
            case 1:
                for (x = 0; x < BmpHeader->PixelWidth; x++) {
                    BitIndex = x & 0x07;
                    if (BitIndex == 0)
                        ImageValue = *ImagePtr++;
                    
                    Index = (ImageValue >> (7 - BitIndex)) & 0x01;
                    PixelPtr->b = BmpColorMap[Index].Blue;
                    PixelPtr->g = BmpColorMap[Index].Green;
                    PixelPtr->r = BmpColorMap[Index].Red;
                    PixelPtr->a = AlphaValue;
                    PixelPtr++;
                }
                break;
            
            case 4:
                for (x = 0; x <= BmpHeader->PixelWidth - 2; x += 2) {
                    ImageValue = *ImagePtr++;
                    
                    Index = ImageValue >> 4;
                    PixelPtr->b = BmpColorMap[Index].Blue;
                    PixelPtr->g = BmpColorMap[Index].Green;
                    PixelPtr->r = BmpColorMap[Index].Red;
                    PixelPtr->a = AlphaValue;
                    PixelPtr++;
                    
                    Index = ImageValue & 0x0f;
                    PixelPtr->b = BmpColorMap[Index].Blue;
                    PixelPtr->g = BmpColorMap[Index].Green;
                    PixelPtr->r = BmpColorMap[Index].Red;
                    PixelPtr->a = AlphaValue;
                    PixelPtr++;
                }
                if (x < BmpHeader->PixelWidth) {
                    ImageValue = *ImagePtr++;
                    
                    Index = ImageValue >> 4;
                    PixelPtr->b = BmpColorMap[Index].Blue;
                    PixelPtr->g = BmpColorMap[Index].Green;
                    PixelPtr->r = BmpColorMap[Index].Red;
                    PixelPtr->a = AlphaValue;
                    PixelPtr++;
                }
                break;
            
            case 8:
                for (x = 0; x < BmpHeader->PixelWidth; x++) {
                    Index = *ImagePtr++;
                    PixelPtr->b = BmpColorMap[Index].Blue;
                    PixelPtr->g = BmpColorMap[Index].Green;
                    PixelPtr->r = BmpColorMap[Index].Red;
                    PixelPtr->a = AlphaValue;
                    PixelPtr++;
                }
                break;
            
            case 24:
                for (x = 0; x < BmpHeader->PixelWidth; x++) {
                    PixelPtr->b = *ImagePtr++;
                    PixelPtr->g = *ImagePtr++;
                    PixelPtr->r = *ImagePtr++;
                    PixelPtr->a = AlphaValue;
                    PixelPtr++;
                }
                break;
            
        }
    }
    
    return NewImage;
}


int
EFIAPI
main (                                         
  IN int Argc,
  IN char **Argv
  )
{
    EFI_STATUS    Status;
    EG_IMAGE        *Image;	
    UINT8           *FileData=NULL;
    UINTN           FileDataLength;

	
    Status = gBS->LocateProtocol(&GraphicsOutputProtocolGuid, 
						NULL, (VOID **) &GraphicsOutput);
    if (EFI_ERROR(Status)) {
        GraphicsOutput = NULL;
		Print(L"Loading Graphics_Output_Protocol error!\n");
		return EFI_SUCCESS;
	}	
    
	Status=LoadFile(L"test.bmp",&FileData,&FileDataLength);
    Print(L"Get file size [%d]!\n",FileDataLength);	
	
    Image=egDecodeBMP(FileData, FileDataLength, FALSE);

    Print(L"Image height [%d]:width[%d]",
					Image->Height,
					Image->Width);

	GraphicsOutput->Blt(
				GraphicsOutput, 
				(EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) Image->PixelData,
				EfiBltBufferToVideo,
                0, 
				0 , 
				0x20, 
				0x0, 
				Image->Width, 
				Image->Height, 0); 					
	
  return EFI_SUCCESS;
  
}

 

运行结果:

showbmp

完整代码例子:

ShowBMP

本文同样参考了之前提到的 https://github.com/chengs/UEFI 的代码,再次感谢!

E2010 Incompatible types: ‘Cardinal’ and ‘TSearchRec’

在编写一个非常简单的Delphi程序时,遇到一个奇怪的问题

[DCC Error] Project2.dpr(25): E2010 Incompatible types: ‘Cardinal’ and ‘TSearchRec’

var
  searchResult : TSearchRec;

begin
  // Try to find regular files matching Unit1.d* in the current dir
  if FindFirst('Unit1.d*', faAnyFile, searchResult) = 0 then
  begin
    repeat
      ShowMessage('File name = '+searchResult.Name);
      ShowMessage('File size = '+IntToStr(searchResult.Size));
    until FindNext(searchResult) <> 0;

    // Must free up resources used by these successful finds
    FindClose(searchResult);
  end;
end;

 

上述代码来自【参考1】

错误始终指向 FindClose(searchResult); 这一句,百思不得其解,后来搜索到了一个解释【参考2】,调换 uses 中的 windows和 sysutils 位置即解决……

参考:

1.http://www.delphibasics.co.uk/RTL.asp?Name=FindFirst FindFirst Function

2.http://www.delphipages.com/forum/showthread.php?t=145983

悲剧了,浪费18元

之前给别人做东西,用了DFRobot的障碍、遮蔽传感器,感觉非常好用,只是价格比较高,要28.后来在taobao 的“树莓派一号店”买东西,正好看到他家也有,只要18,顺手就带了一个试试。结果发现不好用…….根本没有电平信号出来。找售后,他坚持说每一件出厂前都测试过,

TB1sswwHFXXXXaeXFXXXXXXXXXX_!!0-item_pic

所以,如果你希望你的作品稳定一些最好还是选用DFRobot的产品,相比他们的服务,他们的产品还是很靠谱的。

另外,淘宝买回来的东西一定尽快实验确定是否好用。

Step to UEFI (55) —– 截屏的代码

前面介绍了 EFI_GRAPHICS_OUTPUT_PROTOCOL 的各种用法,这里介绍一下如何使用这个 Protocol 进行截屏,将屏幕信息保存为 BMP 文件。

原理是:用 GraphicsOutput->Blt 将屏幕信息保存在指定的内存位置,然后加一个 BMP 的文件头,再重新排列一下颜色(BMP是直接颜色BGR排列下来),最后将这块内存保存下来就得到需要的BMP文件了。

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

#include  <stdio.h>
#include  <stdlib.h>
#include  <wchar.h>
#include  <time.h>
#include <Protocol/EfiShell.h>
#include <Library/ShellLib.h>

#include <Protocol/SimpleFileSystem.h>
#include <Protocol/BlockIo.h>
#include <Library/DevicePathLib.h>
#include <Library/HandleParsingLib.h>
#include <Library/SortLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/BaseMemoryLib.h>

#include <Protocol/LoadedImage.h>



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

extern EFI_SHELL_ENVIRONMENT2    *mEfiShellEnvironment2;
extern EFI_HANDLE				 gImageHandle;

static EFI_GUID GraphicsOutputProtocolGuid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
static EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput = NULL;

#pragma pack(1)

//Copied from  C\MdePkg\Include\Protocol\UgaDraw.h
typedef struct {
  UINT8 Blue;
  UINT8 Green;
  UINT8 Red;
  UINT8 Reserved;
} EFI_UGA_PIXEL;

/* This should be compatible with EFI_UGA_PIXEL */
typedef struct {
    UINT8 b, g, r, a;
} EG_PIXEL;

typedef struct {
    CHAR8         CharB;
    CHAR8         CharM;
    UINT32        Size;
    UINT16        Reserved[2];
    UINT32        ImageOffset;
    UINT32        HeaderSize;
    UINT32        PixelWidth;
    UINT32        PixelHeight;
    UINT16        Planes;       // Must be 1
    UINT16        BitPerPixel;  // 1, 4, 8, or 24
    UINT32        CompressionType;
    UINT32        ImageSize;    // Compressed image size in bytes
    UINT32        XPixelsPerMeter;
    UINT32        YPixelsPerMeter;
    UINT32        NumberOfColors;
    UINT32        ImportantColors;
} BMP_IMAGE_HEADER;

typedef struct {
    UINTN       Width;
    UINTN       Height;
    BOOLEAN     HasAlpha;
    EG_PIXEL    *PixelData;
} EG_IMAGE;
#pragma pack()

//
// Basic image handling
//

EG_IMAGE * egCreateImage(IN UINTN Width, IN UINTN Height, IN BOOLEAN HasAlpha)
{
    EG_IMAGE        *NewImage;
    
    NewImage = (EG_IMAGE *) AllocatePool(sizeof(EG_IMAGE));
    if (NewImage == NULL)
        return NULL;
    NewImage->PixelData = (EG_PIXEL *) AllocatePool(
								Width * Height * sizeof(EG_PIXEL));
    if (NewImage->PixelData == NULL) {
        FreePool(NewImage);
        return NULL;
    }

    NewImage->Width = Width;
    NewImage->Height = Height;
    NewImage->HasAlpha = HasAlpha;
    return NewImage;
}

//
// Save BMP image
//

VOID egEncodeBMP(IN EG_IMAGE *Image, OUT UINT8 **FileDataReturn, 
											OUT UINTN *FileDataLengthReturn)
{
    BMP_IMAGE_HEADER    *BmpHeader;
    UINT8               *FileData;
    UINTN               FileDataLength;
    UINT8               *ImagePtr;
    UINT8               *ImagePtrBase;
    UINTN               ImageLineOffset;
    EG_PIXEL            *PixelPtr;
    UINTN               x, y;
    
    ImageLineOffset = Image->Width * 3;
    if ((ImageLineOffset % 4) != 0)
        ImageLineOffset = ImageLineOffset + (4 - (ImageLineOffset % 4));
    
    // allocate buffer for file data
    FileDataLength = sizeof(BMP_IMAGE_HEADER) + 
										Image->Height * ImageLineOffset;
    FileData = AllocateZeroPool(FileDataLength);
    if (FileData == NULL) {
        Print(L"Error allocate %d bytes\n", FileDataLength);
        *FileDataReturn = NULL;
        *FileDataLengthReturn = 0;
        return;
    }
	
    // fill header
    BmpHeader = (BMP_IMAGE_HEADER *)FileData;
    BmpHeader->CharB = 'B';
    BmpHeader->CharM = 'M';
    BmpHeader->Size = FileDataLength;
    BmpHeader->ImageOffset = sizeof(BMP_IMAGE_HEADER);
    BmpHeader->HeaderSize = 40;
    BmpHeader->PixelWidth = Image->Width;
    BmpHeader->PixelHeight = Image->Height;
    BmpHeader->Planes = 1;
    BmpHeader->BitPerPixel = 24;
    BmpHeader->CompressionType = 0;
    BmpHeader->XPixelsPerMeter = 0xb13;
    BmpHeader->YPixelsPerMeter = 0xb13;
 
    // fill pixel buffer
    ImagePtrBase = FileData + BmpHeader->ImageOffset;
    for (y = 0; y < Image->Height; y++) {
        ImagePtr = ImagePtrBase;
        ImagePtrBase += ImageLineOffset;
        PixelPtr = Image->PixelData + 
					(Image->Height - 1 - y) * Image->Width;
        
        for (x = 0; x < Image->Width; x++) {
            *ImagePtr++ = PixelPtr->b;
            *ImagePtr++ = PixelPtr->g;
            *ImagePtr++ = PixelPtr->r;
            PixelPtr++;
        }
    }
    
    *FileDataReturn = FileData;
    *FileDataLengthReturn = FileDataLength;
}

VOID egFreeImage(IN EG_IMAGE *Image)
{
    if (Image != NULL) {
        if (Image->PixelData != NULL)
            FreePool(Image->PixelData);
        FreePool(Image);
    }
}

/**

  Function opens and returns a file handle to the root directory of a volume.

  @param DeviceHandle    A handle for a device

  @return A valid file handle or NULL is returned

**/
EFI_FILE_HANDLE
EfiLibOpenRoot (
  IN EFI_HANDLE                   DeviceHandle
  )
{
  EFI_STATUS                      Status;
  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume;
  EFI_FILE_HANDLE                 File;

  File = NULL;

  //
  // File the file system interface to the device
  //
  Status = gBS->HandleProtocol (
                  DeviceHandle,
                  &gEfiSimpleFileSystemProtocolGuid,
                  (VOID *) &Volume
                  );

  //
  // Open the root directory of the volume
  //
  if (!EFI_ERROR (Status)) {
    Status = Volume->OpenVolume (
                      Volume,
                      &File
                      );
  }
  //
  // Done
  //
  return EFI_ERROR (Status) ? NULL : File;
}


static EFI_GUID ESPGuid = { 0xc12a7328, 0xf81f, 0x11d2, 
				{ 0xba, 0x4b, 0x00, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b } };

static EFI_STATUS egFindESP(OUT EFI_FILE_PROTOCOL *RootDir)
{
    EFI_STATUS          Status;

   

    return Status;
}



EFI_STATUS egSaveFile(IN CHAR16 *FileName,
                      IN UINT8 *FileData, IN UINTN FileDataLength)
{
    EFI_STATUS          Status;
    EFI_FILE_HANDLE     FileHandle;
    UINTN               BufferSize;
    EFI_FILE_PROTOCOL   *Root;
	EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFileSystem;
	
    Status = gBS->LocateProtocol(
						&gEfiSimpleFileSystemProtocolGuid, 
						NULL,
						(VOID **)&SimpleFileSystem);
    if (EFI_ERROR(Status)) {
		    Print(L"Cannot find EFI_SIMPLE_FILE_SYSTEM_PROTOCOL \r\n");
            return Status;	
	}

	Status = SimpleFileSystem->OpenVolume(SimpleFileSystem, &Root);
    if (EFI_ERROR(Status)) {
		    Print(L"OpenVolume error \r\n");
            return Status;	
	}

    Status = Root->Open(
							Root, 
							&FileHandle, 
							FileName,
							EFI_FILE_MODE_READ |
							EFI_FILE_MODE_WRITE | 
							EFI_FILE_MODE_CREATE, 
							0);
    if (EFI_ERROR(Status))
	  {
        Print(L"Error Open NULL\n");
        return Status;
	  }	
    
    BufferSize = FileDataLength;
    Status = FileHandle->Write(FileHandle, &BufferSize, FileData);
    FileHandle->Close(FileHandle);
    
    return Status;
}


int
EFIAPI
main (                                         
  IN int Argc,
  IN char **Argv
  )
{
    EFI_STATUS    Status;
    EG_IMAGE        *Image;	
    UINT8           *FileData;
    UINTN           FileDataLength;
	
    Status = gBS->LocateProtocol(&GraphicsOutputProtocolGuid, 
								NULL, (VOID **) &GraphicsOutput);
    if (EFI_ERROR(Status)) {
        GraphicsOutput = NULL;
		Print(L"Loading Graphics_Output_Protocol error!\n");
		return EFI_SUCCESS;
	}	
    
	// allocate a buffer for the whole screen
    Image = egCreateImage(GraphicsOutput->Mode->Info->HorizontalResolution, 
					      GraphicsOutput->Mode->Info->VerticalResolution, 
						  FALSE);
    if (Image == NULL) {
        Print(L"Error egCreateImage returned NULL\n");
        return EFI_SUCCESS;
    }		

	// get full screen image
    if (GraphicsOutput != NULL) {
        GraphicsOutput->Blt(GraphicsOutput, 
			(EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) Image->PixelData, 
			EfiBltVideoToBltBuffer,
			0, 0, 0, 0, Image->Width, Image->Height, 0); }
  
    // encode as BMP
    egEncodeBMP(Image, &FileData, &FileDataLength);
    egFreeImage(Image);
	
    if (FileData == NULL) {
        Print(L"Error egEncodeBMP returned NULL\n");
        return EFI_SUCCESS;
    }	

    // save to file on the ESP
    Status = egSaveFile(L"screenshot.bmp", FileData, FileDataLength);
    FreePool(FileData);
    if (EFI_ERROR(Status)) { 
        Print(L"Error egSaveFile: %x\n", Status);
		return EFI_SUCCESS;
    }
    
	
  return EFI_SUCCESS;
  
}

 

运行结果:

scrcap

完整代码下载:

SCRCap

特别注意,本文使用的代码来自 https://github.com/chengs/UEFI 再次表示感谢。

参考:

1.http://biosengineer.blogspot.com/2011/09/uefi-screenshot-capture-screen.html UEFI Screenshot (Capture screen)
2.http://kurtqiao.blogspot.com/2013/03/how-to-take-screen-shot-under-uefi-shell.htmlHow to take screen shot under UEFI shell

DIY蓝牙水平仪倾角器

做了一个很简单的小东西,用的是taobao上君悦智控【参考1】的 “JY901串口9轴加速度计\陀螺仪 MPU6050 姿态角度测量模块 卡尔曼”。用MPU6050可以很容易的获得角速度,但是如果没有算法的支撑,得到的RAW数据根本没法用。我之前试图用Arduino直接做一个能够测量摆动的装置,发现得到的数据非常糟糕。

jy9

这个模块上有加速度和陀螺仪加上地磁仪器,还有一个单片机,内部有他们自己设计的算法,处理之后从串口送出结果,就是各种姿态速度信息了。

我用这个模块,直接做了一个原型,通过usb接口供电(上面是电池,下面黑色的是一个usb取电装置,用这个装置只是因为上面有USB母头,可以方便的取电而已)。

a1

大概介绍一下是三部分

b1

演示是在Windows平板电脑上,只要有蓝牙接口的Windows都可以运行

c1

上位机使用Delphi编写,源程序下载

comptest

工作的视频

http://www.tudou.com/programs/view/t_cxuhLU2hw/?resourceId=414535982_06_02_99

http://www.tudou.com/programs/view/z2Rq0ND_ARM/?resourceId=414535982_06_02_99

补充一下电路连接,直接把串口用蓝牙送出去,非常简单

jy901

参考:

1.http://robotcontrol.taobao.com/

Step to UEFI (54) —– EFI_SIMPLE_FILE_SYSTEM_PROTOCOL 写文件

通常,每个UEFI系统至少有一个 ESP (EFI System Partition)分区,在这个分区上存放启动文件。EFI内置了EFI_SIMPLE_FILE_SYSTEM_PROTOCOL(简称 FileSystemIo)可以用来操作FAT文件系统【参考1】。

相关的介绍:

\MdePkg\Include\Protocol\SimpleFileSystem.h

///
/// The EFI_FILE_PROTOCOL provides file IO access to supported file systems.
/// An EFI_FILE_PROTOCOL provides access to a file's or directory's contents, 
/// and is also a reference to a location in the directory tree of the file system 
/// in which the file resides. With any given file handle, other files may be opened 
/// relative to this file's location, yielding new file handles.
///
struct _EFI_FILE_PROTOCOL {
  ///
  /// The version of the EFI_FILE_PROTOCOL interface. The version specified 
  /// by this specification is EFI_FILE_PROTOCOL_LATEST_REVISION.
  /// Future versions are required to be backward compatible to version 1.0.
  ///
  UINT64                Revision;
  EFI_FILE_OPEN         Open;
  EFI_FILE_CLOSE        Close;
  EFI_FILE_DELETE       Delete;
  EFI_FILE_READ         Read;
  EFI_FILE_WRITE        Write;
  EFI_FILE_GET_POSITION GetPosition;
  EFI_FILE_SET_POSITION SetPosition;
  EFI_FILE_GET_INFO     GetInfo;
  EFI_FILE_SET_INFO     SetInfo;
  EFI_FILE_FLUSH        Flush;
  EFI_FILE_OPEN_EX      OpenEx;
  EFI_FILE_READ_EX      ReadEx;
  EFI_FILE_WRITE_EX     WriteEx;
  EFI_FILE_FLUSH_EX     FlushEx;
};

 

\MdePkg\Include\Protocol\SimpleFileSystem.h

#define EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID \
  { \
    0x964e5b22, 0x6459, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \
  }

 

\EdkCompatibilityPkg\Foundation\Efi\Protocol\SimpleFileSystem\SimpleFileSystem.c

EFI_GUID  gEfiSimpleFileSystemProtocolGuid = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID;

 

从原理上来说,先通过这个Protocol OpenVolume,即可获得FAT文件系统上的根目录句柄。目录句柄(EFI_FILE_PROTOCOL)包含了操作该目录里文件的文件操作接口。之后我们再用 Open打开这个目录,选定需要操作的文件即可写入。

\MdePkg\Include\Protocol\SimpleFileSystem.h

/**
  Writes data to a file.

  @param  This       A pointer to the EFI_FILE_PROTOCOL instance that is the file
                     handle to write data to.
  @param  BufferSize On input, the size of the Buffer. On output, the amount of data
                     actually written. In both cases, the size is measured in bytes.
  @param  Buffer     The buffer of data to write.

  @retval EFI_SUCCESS          Data was written.
  @retval EFI_UNSUPPORTED      Writes to open directory files are not supported.
  @retval EFI_NO_MEDIA         The device has no medium.
  @retval EFI_DEVICE_ERROR     The device reported an error.
  @retval EFI_DEVICE_ERROR     An attempt was made to write to a deleted file.
  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
  @retval EFI_WRITE_PROTECTED  The file or medium is write-protected.
  @retval EFI_ACCESS_DENIED    The file was opened read only.
  @retval EFI_VOLUME_FULL      The volume is full.

**/
typedef
EFI_STATUS
(EFIAPI *EFI_FILE_WRITE)(
  IN EFI_FILE_PROTOCOL        *This,
  IN OUT UINTN                *BufferSize,
  IN VOID                     *Buffer
  );

 

完整代码:

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

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

#include <Protocol/SimpleFileSystem.h>

extern EFI_BOOT_SERVICES         *gBS;
extern EFI_SYSTEM_TABLE			 *gST;


int
EFIAPI
main (                                         
  IN int Argc,
  IN char **Argv
  )
{
    EFI_STATUS          			Status;
	EFI_FILE_PROTOCOL    			*Root;
	EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFileSystem;
	UINTN	BufSize;
	CHAR16 *Textbuf = (CHAR16*) L"www.lab-z.com";
	EFI_FILE_PROTOCOL *FileHandle=0;
	
    Status = gBS->LocateProtocol(
						&gEfiSimpleFileSystemProtocolGuid, 
						NULL,
						(VOID **)&SimpleFileSystem);
						
	
    if (EFI_ERROR(Status)) {
		    Print(L"Cannot find EFI_SIMPLE_FILE_SYSTEM_PROTOCOL \r\n");
            return Status;	
	}

	Status = SimpleFileSystem->OpenVolume(SimpleFileSystem,&Root);
    if (EFI_ERROR(Status)) {
		    Print(L"OpenVolume error \r\n");
            return Status;	
	}
   
    Status = Root -> Open(Root,
			&FileHandle,
			(CHAR16 *) L"atest.txt",
			EFI_FILE_MODE_CREATE | EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE,
			0);
			
    if (EFI_ERROR(Status) || (FileHandle==0)) {
		    Print(L"Open error \r\n");
            return Status;	
	}	
	
	BufSize = StrLen (Textbuf) * 2;
	Print(L"[%d]\r\n",BufSize);		
	Print(L"[%s]\r\n",Textbuf);			
	Status = FileHandle -> Write(FileHandle, &BufSize, Textbuf);
	
	Print(L"Write Done \r\n");	
	
	Status  = FileHandle -> Close (FileHandle);
	
    return EFI_SUCCESS;
}

 

运行结果:

esptest

比较有意思的是,我们按照上面的程序写入之后,使用 type 文件名 来显示文件内容和我们的预期有差别,原因是Type命令默认使用 ASCII 来显内容,而我们的文件中写入的是 Unicode。使用 type -u 强制使用 Unicode即可看到我们期望的内容。

根据【参考2】的提示,我们还可以通过给TXT文件加一个头来通知当前内容格式的方法克服这个问题。

关键代码:

	UINT16  TextHeader =0xFEFF;

 

	BufSize = 2;
	Status = FileHandle -> Write(FileHandle, &BufSize, &TextHeader);
	
	BufSize = StrLen (Textbuf) * 2;
	Print(L"[%d]\r\n",BufSize);		
	Print(L"[%s]\r\n",Textbuf);			
	Status = FileHandle -> Write(FileHandle, &BufSize, Textbuf);

 

运行结果:

esptest2

可以看到经过这样的处理,都可以正常显示内容了。

完整代码下载
ESPTest

参考:

1.UEFI 原理与编程 戴正华 著 P152页

2.http://www.biosren.com/thread-6541-2-1.html UEFI下使用EFI_FILE_PROTOCOL 檔案操作能多次讀寫嗎?

 

=============================================================

2024年9月20日

下面这个代码段能够实现将指定内存内容保存为文件,方便调试,有需要的朋友可以试试。

#include &lt;Library/BaseMemoryLib.h>
#include &lt;Library/MemoryAllocationLib.h>
#include &lt;Protocol/SimpleFileSystem.h>

extern EFI_HANDLE        			  gImageHandle;

EFI_STATUS
WriteMemoryToFile(
    IN EFI_HANDLE ImageHandle,
    IN CHAR16 *FileName,
    IN VOID *Buffer,
    IN UINTN BufferSize
)
{
    EFI_STATUS Status;
    EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFileSystem;
    EFI_FILE_PROTOCOL *Root;
    EFI_FILE_PROTOCOL *File;
    EFI_HANDLE *Handles = NULL;
    UINTN HandleCount = 0;

    // Locate all handles that support the Simple File System Protocol
    Status = gBS->LocateHandleBuffer(ByProtocol, &amp;gEfiSimpleFileSystemProtocolGuid, NULL, &amp;HandleCount, &amp;Handles);
    if (EFI_ERROR(Status)) {
        Print(L"Failed to locate handles for Simple File System Protocol: %r\n", Status);
        return Status;
    }

    // Open the first Simple File System Protocol
    Status = gBS->HandleProtocol(Handles[0], &amp;gEfiSimpleFileSystemProtocolGuid, (VOID **)&amp;SimpleFileSystem);
    if (EFI_ERROR(Status)) {
        Print(L"Failed to open Simple File System Protocol: %r\n", Status);
        return Status;
    }

    // Open the root directory
    Status = SimpleFileSystem->OpenVolume(SimpleFileSystem, &amp;Root);
    if (EFI_ERROR(Status)) {
        Print(L"Failed to open root directory: %r\n", Status);
        return Status;
    }

    // Create or open the file
    Status = Root->Open(Root, &amp;File, FileName, EFI_FILE_MODE_CREATE | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ, 0);
    if (EFI_ERROR(Status)) {
        Print(L"Failed to open or create file: %r\n", Status);
        return Status;
    }

    // Write the buffer to the file
    Status = File->Write(File, &amp;BufferSize, Buffer);
    if (EFI_ERROR(Status)) {
        Print(L"Failed to write to file: %r\n", Status);
        File->Close(File);
        return Status;
    }

    // Close the file
    Status = File->Close(File);
    if (EFI_ERROR(Status)) {
        Print(L"Failed to close file: %r\n", Status);
        return Status;
    }

    Print(L"Memory successfully written to file: %s\n", FileName);
    return EFI_SUCCESS;
}

 

 

Step to UEFI (53) —– EFI_Graphics_Output_Protocol 屏幕拷贝的测试

前面实验了颜色填充,这里实验一下屏幕的拷贝。测试很简单,就是屏幕上一个区域的内容copy到另外的位置.

v2v

代码如下:

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

#include  <stdio.h>
#include  <stdlib.h>
#include  <wchar.h>
#include  <time.h>
#include <Protocol/EfiShell.h>
#include <Library/ShellLib.h>

#include <Protocol/SimpleFileSystem.h>
#include <Protocol/BlockIo.h>
#include <Library/DevicePathLib.h>
#include <Library/HandleParsingLib.h>
#include <Library/SortLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/BaseMemoryLib.h>

#include <Protocol/LoadedImage.h>



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

extern EFI_SHELL_ENVIRONMENT2    *mEfiShellEnvironment2;
extern EFI_HANDLE				 gImageHandle;

static EFI_GUID GraphicsOutputProtocolGuid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
static EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput = NULL;

//Copied from  C\MdePkg\Include\Protocol\UgaDraw.h
typedef struct {
  UINT8 Blue;
  UINT8 Green;
  UINT8 Red;
  UINT8 Reserved;
} EFI_UGA_PIXEL;


int
EFIAPI
main (                                         
  IN int Argc,
  IN char **Argv
  )
{
    EFI_STATUS    Status;
    UINTN i;
	
    Status = gBS->LocateProtocol(&GraphicsOutputProtocolGuid, NULL, (VOID **) &GraphicsOutput);
    if (EFI_ERROR(Status)) {
        GraphicsOutput = NULL;
		Print(L"Loading Graphics_Output_Protocol error!\n");
		return EFI_SUCCESS;
	}	

  for (i=0;i<100;i++) {
	GraphicsOutput->Blt(GraphicsOutput, NULL, EfiBltVideoToVideo,
                        rand() % (GraphicsOutput->Mode->Info->HorizontalResolution-100), 
						rand() % (GraphicsOutput->Mode->Info->VerticalResolution-100) , 
						rand() % (GraphicsOutput->Mode->Info->HorizontalResolution-100), 
						rand() % (GraphicsOutput->Mode->Info->VerticalResolution-100), 
						100, 100, 0); 
	gBS->Stall(50000);
  }				

  
  return EFI_SUCCESS;
  
}

 

运行结果

gfx3

工作视频:

http://www.tudou.com/programs/view/7gRxW6SqBKg/?resourceId=414535982_06_02_99

完整代码下载

GFXTest3

当然,这个实验有些让人看不清楚,修改上面的程序,直接在屏幕上画色块

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

#include  <stdio.h>
#include  <stdlib.h>
#include  <wchar.h>
#include  <time.h>
#include <Protocol/EfiShell.h>
#include <Library/ShellLib.h>

#include <Protocol/SimpleFileSystem.h>
#include <Protocol/BlockIo.h>
#include <Library/DevicePathLib.h>
#include <Library/HandleParsingLib.h>
#include <Library/SortLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/BaseMemoryLib.h>

#include <Protocol/LoadedImage.h>



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

extern EFI_SHELL_ENVIRONMENT2    *mEfiShellEnvironment2;
extern EFI_HANDLE				 gImageHandle;

static EFI_GUID GraphicsOutputProtocolGuid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
static EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput = NULL;

//Copied from  C\MdePkg\Include\Protocol\UgaDraw.h
typedef struct {
  UINT8 Blue;
  UINT8 Green;
  UINT8 Red;
  UINT8 Reserved;
} EFI_UGA_PIXEL;


int
EFIAPI
main (                                         
  IN int Argc,
  IN char **Argv
  )
{
    EFI_STATUS    Status;
    UINTN i;
	EFI_GRAPHICS_OUTPUT_BLT_PIXEL FillColor;
	
    Status = gBS->LocateProtocol(&GraphicsOutputProtocolGuid, NULL, (VOID **) &GraphicsOutput);
    if (EFI_ERROR(Status)) {
        GraphicsOutput = NULL;
		Print(L"Loading Graphics_Output_Protocol error!\n");
		return EFI_SUCCESS;
	}	

  for (i=0;i<100;i++) {
    FillColor.Blue=rand() % 256;
	FillColor.Red=rand() % 256;
	FillColor.Green=rand() % 256;
	
	GraphicsOutput->Blt(GraphicsOutput, &FillColor, EfiBltVideoFill,
                0, 
				0 , 
				rand() % (GraphicsOutput->Mode->Info->HorizontalResolution-100), 
				rand() % (GraphicsOutput->Mode->Info->VerticalResolution-100), 
				100, 100, 0); 
	gBS->Stall(50000);
  }				

  
  return EFI_SUCCESS;
  
}

 

运行结果

gfxtest5

工作视频:

http://www.tudou.com/programs/view/VSbFaN1XBZc/?resourceId=414535982_06_02_99

完整代码下载

GFXTest5

参考:

1. UEFI SPEC 2.4 P498

2. 本文参考 https://github.com/chengs 的代码