比如,我在一个目录下有大量的 zip 文件,我想解压之,就可以使用下面的批处理
for %%i in (*.zip) do 7z x %%i -o%%~ni
其中:
for %%i in (*.zip) 是枚举目录下的全部 zip 文件名
7z x %%i 是按照完整路径解压的意思
-o%%~ni 是解压到文件名相同的目录的意思
比如,我有一个zip文件名称是 labz.zip 那么运行之后,会生成一个 labz 的目录,然后将文件内容解压进去
比如,我在一个目录下有大量的 zip 文件,我想解压之,就可以使用下面的批处理
for %%i in (*.zip) do 7z x %%i -o%%~ni
其中:
for %%i in (*.zip) 是枚举目录下的全部 zip 文件名
7z x %%i 是按照完整路径解压的意思
-o%%~ni 是解压到文件名相同的目录的意思
比如,我有一个zip文件名称是 labz.zip 那么运行之后,会生成一个 labz 的目录,然后将文件内容解压进去
网上有朋友提了一个问题“arduino怎么把13号引脚的亮度减小一半”。自然而然的想法是用PWM做,查一下资料,非常不幸 Uno的Pin13不是PWM。
我们只能采用模拟PWM的方式来做。首先想到的是直接在 Timer0 的ISR (在\hardware\arduino\avr\cores\arduino\wiring.c)上加入内容。但是实验结果非常糟糕,肉眼能够看到LED在闪烁。于是,需要自己设置一个快速的中断,然后在里面写拉高低的代码。
最终找到tsaiwn 编写的代码【参考1】。直接在上面修改:
设定的亮度有十级别,0是最亮,9是最暗。
// 控制 LED 亮滅, 每秒閃爍 5000 次: 亮 0.0001 秒滅 0.0001 秒 …
// Prescaler 用 64
volatile int ggyy = 1; // 使用這當 Flag 給 ISR 使用 !
int ledPin =13;
unsigned char myPWM=0;
unsigned char myPCounter=0;
/// For Prescaler == 64
/// 1 秒 / (16 000 000 / 64) = 1/250000 = 0.000004 sec / per cycle
/// 0.1 sec / 0.000004 sec -1 = 25000 -1 = 24999
/// 0.0001 sec / 0.000004 sec -1 = 25 -1 = 24
const int myTOP = 24; // 0.0001 sec when Prescaler == 64
///// Interrupt Service Routine for TIMER1 CTC on OCR1A as TOP
/// 注意以下名稱是有意義的, 不可亂改 !
ISR(TIMER1_COMPA_vect)
{
//digitalWrite(ledPin, ggyy); // ggyy 是 0 或 1
//ggyy = 1 – ggyy; // 給下次進入 ISR 用
myPCounter++;
if ((myPCounter % 10) >= myPWM)
{
digitalWrite(ledPin, HIGH);
}
else
{
digitalWrite(ledPin, LOW);
}
}
void setup( ) {
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, LOW); // turn Off the LED
cli(); // 禁止中斷
TCCR1A = 0;
TCCR1B = (1<
每一个Arduino 的玩家都应该准备一个 ISP 下载器,有了它能让你的 Uno 玩出很多花样。这里就介绍一下如何使用 USBTinyISP。本文将介绍使用这款工具的三种刷写方式:
首先,你要有一个USBTinyISP烧录器。下面的是购买自淘宝的 OCROBOT 出品,价格是 45元,属于较贵的。

这款需要安装驱动才能工作,淘宝很多出售的号称不需要驱动程序,我也曾经入手过一个,一直无法使用。因此,建议购买之前要和卖家沟通好,索要驱动,特别的如果卖家要求关闭数字签名才能安装驱动也请不要购买。这样做会让你的系统暴露在风险之中,另外,64位Windows由于本身的特性无法关闭数字签名功能。
插入之后安装驱动,驱动来自【参考1】。安装之后是下面这样(特别提醒,如果插入之后出现无法获得USB Descriptor 的提示,那么请更换一个USB端口,产生这个问题的原因可能是某些USB3.0端口和这个卡上的控制芯片有兼容问题)
Arduino UNO 上有2个烧录口,一个是给 USB 转串口芯片使用的,一个是给 328P 使用的。通常我们需要烧录的是328P 【参考】。也就是下图中的橘色标记口。

直接将USBTinyISP的头插入这个位置即可。需要注意的是:
至此,硬件部分准备完毕,下面就是如何使用软件进行烧写了。
运行 Avrdudess,先选择 USBTinyISP

然后使用右侧Detect 按钮进行芯片识别。正常情况下,主芯片应该是328P,USB转串口芯片应该是16U2或者8U2如果没有识别,应该是插线反了导致的,请调换方向重新插入

最后,选择要烧写的文件,再使用GO 按钮即可进行烧录

特别提醒:不要调整右侧 Fuses 选项。
二. Arduino IDE 刷写 328P BootLoader的方法
3.Tools->BurnBootloader 直接烧写 328P 的Bootloader
烧写成功的话,会有下面的提示信息
某些情况下,我们需要直接烧写328P上面的程序,方法如下:

运行成功后有下面类似提示
本文首发 http://www.arduino.cn/thread-21619-1-1.html
文章中提到的工具和驱动也可以在上面的网址找到
参考:
直接进行 Source Level的 Debug 对于学习过是非常有用,本文就介绍一下如何在 NT32Pkg的模拟环境下进行 Source Level Debug 的方法。使用的环境是 Windows7 + UDK2015+VS2013。调试的目标是 UDK2015 AppPkg 自带的 Hello。
在 Hello.INF 中加入下面的编译参数:
[BuildOptions] MSFT:DEBUG_*_IA32_DLINK_FLAGS = /EXPORT:InitializeDriver=$(IMAGE_ENTRY_POINT) /ALIGN:4096 /FILEALIGN:4096 /SUBSYSTEM:CONSOLE
此外,在代码中加入_asm int 3 ,当编译器遇到这个命令时,会自动停止准备调试
INTN
EFIAPI
ShellAppMain (
IN UINTN Argc,
IN CHAR16 **Argv
)
{
_asm int 3
Print(L"Hello there fellow Programmer.\n");
Print(L"Welcome to the world of EDK II.\n");
return(0);
}
上述修改完成后,正常编译
Build –a IA32 –p AppPkg\AppPkg.dsc
编译完成之后,在NT32 模拟环境中运行 hello.efi, 会出现下面的错误信息,选择使用 VS2013 调试

我试验了一下,感觉还不错。
一般情况下BIOS工程师不会进行源码级别的调试,最直接的原因是:这样的调试过于复杂,必须额外的硬件支持,要么需要 AMI Debugger ,要么需要 XDP 之类的高级工具,单纯的准备就需要花费很多时间。
自从有了UEFI 的架构,串口 Debug 信息是 BIOS 工程师最忠实的伙伴。
【注释】:本文根据《UEFI 原理与编程》一书 P59 3.4 调试 UEFI 写成。只是这本书上给出来的方法我试验并不好用,疑惑之间搜索到了该书作者在他的Blog上提到这个问题,试验之后完全没有问题:
http://www.cppblog.com/djxzh/archive/2015/02/08/209766.html
“书中讲到了如何利用_asm int 3 调试代码。
_asm int 3需要配合Nt32Pkg使用。也就是说通过Nt32Pkg编译出的.efi文件才能够调试。
如果你带_asm int 3语句的工程是通过非Nt32Pkg编译出来的(例如AppPkg),在SecMain模拟器中调试会导致断点停在Image.c文件如下代码中
Image->Status = Image->EntryPoint (ImageHandle, Image->Info.SystemTable);
在模拟器控制台会输出
WARNING: No source level debug
表明SecMain在加载你的模块时没有成功加载调试符号。
解决方案
在.inf文件中添加如下代码
[BuildOptions]
MSFT:DEBUG_*_IA32_DLINK_FLAGS = /EXPORT:InitializeDriver=$(IMAGE_ENTRY_POINT) /ALIGN:4096 /FILEALIGN:4096 /SUBSYSTEM:CONSOLE
“
最近安装了一个 VS2013进行 UEFI 的编译,碰到了其怪的错误:
“C:\Program Files\Microsoft Visual Studio 12.0\Vc\bin\link.exe” /out:”c:\udk2015\Build\NT32IA32\DEBUG_VS2013\IA32\SecMain.exe” /base:0x10000000 /pdb:”c:\udk2015\Build\NT32IA32\DEBUG_VS2013\IA32\SecMain.pdb” /LIBPATH:”C:\Program Files\Microsoft Visual Studio 12.0\VC\\Lib” /LIBPATH:”C:\Program Files\Windows Kits\8.1\Lib\winv6.3\um\x86″ /NOLOGO /SUBSYSTEM:CONSOLE /NODEFAULTLIB /IGNORE:4086 /MAP /OPT:REF /DEBUG /MACHINE:I386 /LTCG Kernel32.lib MSVCRTD.lib Gdi32.lib User32.lib Winmm.lib Advapi32.lib /EXPORT:InitializeDriver=_ModuleEntryPoint /BASE:0x10000 /ALIGN:4096 /FILEALIGN:4096 /SUBSYSTEM:CONSOLE @c:\udk2015\Build\NT32IA32\DEBUG_VS2013\IA32\Nt32Pkg\Sec\SecMain\OUTPUT\static_library_files.lst
SecMain.lib(WinNtThunk.obj) : error LNK2001: unresolved external symbol _SetCons
oleCursorInfo@8
c:\udk2015\Build\NT32IA32\DEBUG_VS2013\IA32\SecMain.exe : fatal error LNK1120: 1
51 unresolved externals
build…
: error 7000: Failed to execute command
C:\Program Files\Microsoft Visual Studio 12.0\Vc\bin\nmake.exe /nologo t
build [c:\udk2\015\Build\NT32IA32\DEBUG_VS2013\IA32\Nt32Pkg\Sec\SecMain]
仔细研究发现是虚拟机无法找到一些 Windows SDK 的内容。后来经过研究发现错误的原因是因为我使用了错误 VS2013 的控制台。我想编译 X64的UEFI 代码,但是进入了 x86(IA32)的控制台。
正确的做法是:
如果你要编译x64 的代码,那么需要进入上面红色框中的命令行模式。然后,Conf\Target.txt 中的TOOL_CHAIN_TAG 必须是VS2013;
如果你要编译IA32的代码,那么需要进入上面绿色框中的命令行模式。然后,Conf\Target.txt 中的TOOL_CHAIN_TAG 必须是VS2013x86;
否则编译器无法找到对应的SDK 文件。
如果你使用的是Intel 集成显卡的话,安装好驱动之后可以使用键盘上的 Ctrl + Alt+方向键旋转屏幕。根据这个功能,我们可以尝试制作一个整蛊的硬件。原理上来说就是使用 Leonardo模拟按下这个组合键,发送给系统来实现转动。当然为了防止你的朋友们变成下面这个样子,代码使用随机转动:

代码非常简单
#define KEY_LEFT_CTRL 0x80
#define KEY_LEFT_ALT 0x82
#define KEY_UP_ARROW 0xDA
#define KEY_DOWN_ARROW 0xD9
#define KEY_LEFT_ARROW 0xD8
#define KEY_RIGHT_ARROW 0xD7
void setup() {
// put your setup code here, to run once:
Keyboard.begin();
}
void loop() {
delay(5000);
// CTRL-ALT-LEFT
Keyboard.press(KEY_LEFT_CTRL);
Keyboard.press(KEY_LEFT_ALT);
switch(random(3)){
case 0:
Keyboard.press(KEY_LEFT_ARROW);
break;
case 1:
Keyboard.press(KEY_RIGHT_ARROW);
break;
case 2:
Keyboard.press(KEY_UP_ARROW);
break;
case 3:
Keyboard.press(KEY_DOWN_ARROW);
break;
}
Keyboard.releaseAll();
}
运行之后的效果:
关于按键信息在下面这个文件中可以看到:
\hardware\arduino\sam\cores\arduino\USB\USBAPI.h
弄明白上面的原理,你还可以做一个能够遥控旋转的设备,如果你不想让别人动你的电脑就让他转起来,很快对方就会知难而退的。
FDTI232系列芯片是最好的USB转串口芯片,驱动全,芯片本身很稳定,兼容性也很好。这次介绍一个FTDI USB串口芯片的项目,地址是
https://github.com/tianocore/tianocore.github.io/wiki/Tasks-USB-Serial-Adapter-driver#Real_UEFI_system
项目的简介如下:
“Today there are many inexpensive USB Serial adapters available, and most systems are built with USB ports available. But at the same time, the dedicated Serial port is becoming less common to find available in a system.
A serial port can still be useful for software debugging purposes. (debug trace messages)
It can also be useful in providing a secondary terminal to the UEFI system.
This task would involve writing a USB driver which interfaces with a USB Serial Adapter.
Ideally, this project should enable a driver that will attach to the USB Serial Adapter and produce the SerialIo protocol to enable the UEFI terminal to become available through the USB Serial adapter.”。
简单的说如果你的系统当前有 FTDI的USB串口,那么驱动会帮你生成一个 SerialIO 供你使用。这样你就可以在UEFI 环境中使用 FTDI 的USB 串口进行通讯。
在使用之前,请确定你的USB串口设备ID,例如:我现在使用的USB串口在 Windows下面看到的信息是这样的:

本文并不打算做原理上的分析,只是介绍如何编译和实验。
实验环境是 UDK2015
1.在 C:\EDK\Nt32Pkg\Nt32Pkg.dsc 文件的 [Components] 段中添加下面的内容
Nt32Pkg/WinNtBlockIoDxe/WinNtBlockIoDxe.inf Nt32Pkg/WinNtSerialIoDxe/WinNtSerialIoDxe.inf Nt32Pkg/WinNtGopDxe/WinNtGopDxe.inf Nt32Pkg/WinNtSimpleFileSystemDxe/WinNtSimpleFileSystemDxe.inf MdeModulePkg/Application/HelloWorld/HelloWorld.inf #LabZ_Start FtdiUsbSerialDxe/FtdiUsbSerialDxe.inf #LabZ_End # # Network stack drivers # To test network drivers, need network Io driver(SnpNt32Io.dll), please refer to NETWORK-IO Subproject. #
特别说明:如果有可能,最好在你当前的项目上重新这样编译一次。比如,你打算在BayTrail上用这个驱动,那么最好再Baytrail的BIOS中重新编译一次,这样最为稳妥。
2.将FtdiUsbSerialDxe目录拷贝到你UDK 的根目录下 例如: C:\EDK\
3.使用 Build 命令编译 NT32,这次是编译为 X64 的驱动。 命令式 Build –a X64
至此,驱动程序已经编译完成。可以在Build目录下找到我们需要的驱动,名称是 FtdiUsbSerialDxe.efi。 接下来我们就可以进行实验。
实验是在实体机上进行的,让一款“酷比魔方”的平板电脑和台式机进行通讯。实验中我使用了2个USB串口设备,还有一段双母头线(因为USB转串口都是公头)。
1. 首先检查一下,当前系统中没有 SerialIo Protocol

3. 再次检查会发现系统中多了一个 SerialIO protocol

直接 dh 进行检查会发现多了2个handle 一个是驱动,一个是新增的挂protocol

4. 之后使用我们前面介绍过的串口工具【参考1】

看起来在启动的时候串口上会有一些乱码
完整的代码下载
FtdiUsbSerialDxe
编译好的X64 驱动下载
FtdiUsbEFI
特别注意:本文提到的代码是在 Windows7 VS2013 UDK2015环境下编译生成。
参考:
1. http://www.lab-z.com/stu91/ Step to UEFI (91) Shell下的串口测试软件
Arduino Uno 上16U2 芯片的作用是烧写328P Firmware。具体来说,它负责把PC上的USB转为328P能够识别的串口,然后每次刷写的时候它会先用一个Pin将328P拉到 Reset状态下,然后从串口“喂”给328P 需要的Firmware.
本文介绍的就是:如何重新编译 16U2 上面的Firmware.
1. Download WinAVR 我使用的是 20100110 的安装版
2. Download LUFA-100807 特别注意,一定要这个版本,我试验过最新的版本,居然自己的测试编译项目都无法通过
2.1 Lufa 随便解压到一个目录,我是解压到C:\WinAVR-20100110\LUFA-100807
2.2 打开 cmd 命令行模式,进入目录中,使用 make 命令编译 Lufa 的工程,这是为了测试 Lufa 是否正常

3. 正式的编译
3.1 16U2 Firmware source code 在\hardware\arduino\avr\firmwares\atmegaxxu2\arduino-usbserial 中,你要把整个目录copy到 Lufa 的Project目录下。例如:

3.2 命令行进入这个目录,输入 make 即可编译出新的 HEX

最后,把这个生成的HEX文件刷写到16U2上即可。
Note:编译时你可能遇到一些奇怪的错误信息,例如 “incompatible with avr”产生的原因是 2.2 步骤测试时生成了一些非 AVR8 格式的中间文件。你重新到 Lufa 根目录下,运行 make clean 清除测试生成的中间文件即可。
上面是重新编译 16U2的方法,下面说点关于USB的事情。
我们先插入一个 Arduino Uno,在设备管理器中查看他的一些信息。
其中最重要的就是 USB 的 PID 和 VID.众所周知 USB 是一种 PNP (即插即用设备),当然,实际上这个名称和实际的效果差别很远,插上之后还需要安装驱动等等动作之后才能保证你的设备能够正常使用。所谓PnP的真正含义是:连接硬件之后能够自动识别。比如插上一块PCI卡,PC能够知道它用的资源是多少,基本功能是什么。X86电脑上的设备有 Non-Pnp 和 Pnp两种:
1. Non–PnP 方式。具体实现方法有两种,一种是直接“吸收”特定内存或者IO 端口数据。以ISA串口卡为例,当这个卡看到ISA总线上出现发往 0x3F8 IO端口的数据就知道这是在和串口通讯,它会要吸收这个信号并且转发到外面的实体上;另外一种方法是直接“写死”。比方说,内置驱动程序,强行加载。大多数 x86 上的安卓系统就是这样玩的。还有可以通过 ACPI 的 ASL 来通知系统,比如:平板电脑上挂接在 I2C总线上的设备需要用这样的方式通知Windows,当前这个设备的地址传输速度等等。
2. Pnp 方式。 PCI和USB 设备就是典型的 Pnp设备。协议本身就规定了设备如何报告ID给系统,系统用这个ID来识别需要的资源和驱动等等。
从发展上来看,Pnp 是后面才出现的,他的出现也避免了很多用户设置上的麻烦。比如,很早之前,如果系统中有很多使用某个io端口的ISA卡,用户只能一次次跳线来避免冲突反复尝试。时至今日,大多数电脑从生产出来开始,用户几乎没有打开机箱的必要(由于硬件接口的不断变化,电脑升级通常只意味着更换一台)。
继续说 USB ,每个USB设备在插入之后,都会向上报告自己的 VID (Vendor ID),PID (Product ID)。通过这两个ID, 系统就能够知道这是 X 厂商生产的 Y 设备。顺便说一句,如果你系统中出现了无法识别的USB设备,你可以直接在网上搜索 USB PID VID通常能够顺利找到对应的驱动。
上面的各种USB相关数据都能搜索到,下面讲点书本之外的: PID 和 VID 怎么来的。
在世界上有一个USB组织【参考1】,他们负责制定USB标准(在电脑界,越是开放的协议越容易流行,相反那些不愿意透露一点信息而大肆吹嘘厉害的协议很少有人支持或者说更多只是骗局而已)。这个组织会负责分配 VID。当然加入这个组织是要缴纳会费的,如果没有记错的话差不多是$2000一年(几年之前比较便宜,后来涨价了。对于个人来说看着比较多,但对于公司来说只是九牛一毛)。加入这个组织可以给自己申请一个 VID 。有了 VID 之后,可以自己随心编造 PID了。PID 范围是从 0到0xFFFF 。如果你想把你的设备加入到 Windows的 Update中(就是那个有时候找不到驱动,Windows提示网上搜索的功能),正规的 VID和PID是必不可少的。
说道这里,再说一个事情:我目前用到的最好用的USB转串口芯片是 FT232系列的,稳定,支持的驱动也很全。前几年很多人发现他们原来用的好好的基于FT232 芯片的产品忽然变得不正常。最终发现,FT232的生产厂家更新了驱动,新的驱动会“毁坏”产品上的FT232芯片(PID变成0000).新的驱动是通过Windows Update分发的。而厂商这样做的原因是“市场上充斥着山寨货和假货,通过包装很难区分真正的和假冒的FT232,但芯片的硅组成上有着巨大的差异,新的FT232驱动利用这些差异,对其重组,导致这些假冒产品无法兼容现有的驱动程序。这是一个大胆的策略来减少市场上的假冒FTDI。”
下面讲不正规的做法:
1. 你选用的USB IC,比如:你的产品用了CYPRESS公司出品的EZ-USBFX的某款IC,那么你可以直接找CYPRESS,让他们给你一个 PID;
2. 网上有一家公司【参考2】出售自己的PID。他是很多年前加入USB组织的,拿到了一个 VID。然后他就在网上出售自己的PID(6万多个足够卖一阵了)。后来他们收到 USB组织的律师函,意思是说你这样做是不对的,根据协议巴拉巴拉。然后他们的回复是,我们当年加入组织的时候,你们的协议没有这样的巴拉巴拉。然后USB组织说亲我可以给你退钱,不要这样玩。他们回复,根据我们国家的消费者相关法律,购买生效之后是不接受这样的事情的……然后他们继续卖
3. 在设计的时候,可以使用兼容Windows自带驱动的协议。比如:HID 或者 mass-Storage。这样的情况下,也不用考虑 PID和VID的问题,插上就可以用。
参考:
1.http://www.usb.org/about/
2.http://www.mcselec.com/index.php?page=shop.product_details&flypage=shop.flypage&product_id=92&option=com_phpshop&Itemid=1
UEFI System Table 中的 ConOut-> OutputString 能够让我们直接在屏幕上输出字符串。这里介绍一种方法,能够让我们截获并且修改这个函数输出的字符串。
首先看一下 System Table 的定义在 \MdePkg\Include\Uefi\UefiSpec.h
///
/// EFI System Table
///
typedef struct {
///
/// The table header for the EFI System Table.
///
EFI_TABLE_HEADER Hdr;
///
/// A pointer to a null terminated string that identifies the vendor
/// that produces the system firmware for the platform.
///
CHAR16 *FirmwareVendor;
///
/// A firmware vendor specific value that identifies the revision
/// of the system firmware for the platform.
///
UINT32 FirmwareRevision;
///
/// The handle for the active console input device. This handle must support
/// EFI_SIMPLE_TEXT_INPUT_PROTOCOL and EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
///
EFI_HANDLE ConsoleInHandle;
///
/// A pointer to the EFI_SIMPLE_TEXT_INPUT_PROTOCOL interface that is
/// associated with ConsoleInHandle.
///
EFI_SIMPLE_TEXT_INPUT_PROTOCOL *ConIn;
///
/// The handle for the active console output device.
///
EFI_HANDLE ConsoleOutHandle;
///
/// A pointer to the EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL interface
/// that is associated with ConsoleOutHandle.
///
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut;
///
/// The handle for the active standard error console device.
/// This handle must support the EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.
///
EFI_HANDLE StandardErrorHandle;
///
/// A pointer to the EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL interface
/// that is associated with StandardErrorHandle.
///
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *StdErr;
///
/// A pointer to the EFI Runtime Services Table.
///
EFI_RUNTIME_SERVICES *RuntimeServices;
///
/// A pointer to the EFI Boot Services Table.
///
EFI_BOOT_SERVICES *BootServices;
///
/// The number of system configuration tables in the buffer ConfigurationTable.
///
UINTN NumberOfTableEntries;
///
/// A pointer to the system configuration tables.
/// The number of entries in the table is NumberOfTableEntries.
///
EFI_CONFIGURATION_TABLE *ConfigurationTable;
} EFI_SYSTEM_TABLE;
其中的ConOut 是指向 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL 的指针
具体定义可以在 \MdePkg\Include\Protocol\SimpleTextOut.h 查到
///
/// The SIMPLE_TEXT_OUTPUT protocol is used to control text-based output devices.
/// It is the minimum required protocol for any handle supplied as the ConsoleOut
/// or StandardError device. In addition, the minimum supported text mode of such
/// devices is at least 80 x 25 characters.
///
struct _EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL {
EFI_TEXT_RESET Reset;
EFI_TEXT_STRING OutputString;
EFI_TEXT_TEST_STRING TestString;
EFI_TEXT_QUERY_MODE QueryMode;
EFI_TEXT_SET_MODE SetMode;
EFI_TEXT_SET_ATTRIBUTE SetAttribute;
EFI_TEXT_CLEAR_SCREEN ClearScreen;
EFI_TEXT_SET_CURSOR_POSITION SetCursorPosition;
EFI_TEXT_ENABLE_CURSOR EnableCursor;
///
/// Pointer to SIMPLE_TEXT_OUTPUT_MODE data.
///
EFI_SIMPLE_TEXT_OUTPUT_MODE *Mode;
};
我们需要的是将 EFI_TEXT_STRING OutputString; 替换为我们自己的函数。
最终的代码如下
#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Library/ShellCEntryLib.h>
extern EFI_BOOT_SERVICES *gBS;
extern EFI_SYSTEM_TABLE *gST;
extern EFI_RUNTIME_SERVICES *gRT;
EFI_SYSTEM_TABLE myST;
EFI_SYSTEM_TABLE *pmyST=&myST;
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL myConOut;
EFI_STATUS
myOut (
IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
IN CHAR16 *String
)
{
//Just a experiment, add a String to the output
CHAR16 R[40]=L"LAB-Z:";
StrCat(R,String);
gST->ConOut->OutputString(This,R);
return EFI_SUCCESS;
}
int
EFIAPI
main (
IN int Argc,
IN CHAR16 **Argv
)
{
//Create a fake EFI_SYSTEM_TABLE named myST
memcpy(&myST,gST,sizeof(EFI_SYSTEM_TABLE));
//Test this EFI_SYSTEM_TABLE
gST->ConOut->OutputString( gST->ConOut,L"Test of gSt 1\n\r");
pmyST->ConOut->OutputString(pmyST->ConOut,L"Test of pmyST 2\n\r");
//Create a fake EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
memcpy(&myConOut,gST->ConOut,sizeof(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL));
//Test the fake ConOut
pmyST->ConOut=&myConOut;
//If we use pmyST->ConOut it will be an error
pmyST->ConOut->OutputString(gST->ConOut,L"Test of myConOut 3\n\r");
//Replace OutputString function with our function
pmyST->ConOut->OutputString=&myOut;
pmyST->ConOut->OutputString(gST->ConOut,L"Test of myConOut 4\n\r");
return EFI_SUCCESS;
}
运行结果
特别需要注意的地方,如果我们写成
pmyST->ConOut->OutputString(pmyST ->ConOut,L”Test of myConOut 3\n\r”);
那么会碰到下面这个错误
产生问题的代码在 \ShellPkg\Application\Shell\ConsoleLogger.c 中,看起来是向 Handle 安装另外一个 Protocol的时候出现报错信息。
Status = gBS->InstallProtocolInterface(&gImageHandle, &gEfiSimpleTextOutProtocolGuid, EFI_NATIVE_INTERFACE, (VOID*)&((*ConsoleInfo)->OurConOut));
if (EFI_ERROR(Status)) {
SHELL_FREE_NON_NULL((*ConsoleInfo)->Buffer);
SHELL_FREE_NON_NULL((*ConsoleInfo)->Attributes);
SHELL_FREE_NON_NULL((*ConsoleInfo));
*ConsoleInfo = NULL;
return (Status);
}
gST->ConsoleOutHandle = gImageHandle;
gST->ConOut = &(*ConsoleInfo)->OurConOut;
return (Status);
完整的代码下载:
MySt
今天在刷写Arduino Uno的时候意外损坏了一个 328P 芯片(很大可能是烧写次数太多)。具体的现象是:用 AvrDudu 这样的第三方芯片都无法识别芯片型号。刚好手上有其他的 Uno板子,于是随手换了一块。新的板子可以正常识别328P和烧写,但是我发现竟然无法烧写16u2这个芯片。正常情况下将烧录器插在 16U2 的ICSP接口之后,会对板子进行供电,板子上的灯会亮,但是这块板子插上之后板子上的灯不亮,烧写器上的灯也会灭掉。
首先打开PCB电路图进行查看。
ICSP1顺序如下:
和16U2对应关系如下
1– Pin17 MISO
2–Pin4 VCC
3– Pin15 SCLK
4– Pin16 MOSI
5–Pin24 Reset
6—GND
然后经过测试发现排针上 GND 竟然和 VCC 是连通的,这也是为什么每次插上烧录器灯就会灭掉,这样根本就让烧录器短路了…….
这是能够正常烧写 16U2 的板子,因为使用时间很长,右上角的插座已经掉了。
这是无法刷新 16U2的板子
仔细查看PCB 还是能发现有些不同的,比如:这个位置,通常这样的设计是为了让走线长度相同,而另一块板子没有这样的设计。
再次查看 Arduino PCB设计可以发现正常是应该有这样的走线的。
所以提醒购买Uno板子的朋友,如果你发现走线上和上图有差别,请用万用表测量16U2的刷写脚,如果有短路问题,请马上联系卖家。