ASCII 一览表

工作需要经常查看 ASCII 数值,索性弄了一个列表和在线查询的功能:

这是在线查询的功能,使用 JavaScript 实现,有兴趣的朋友也可以直接保存到本地使用:

ASCII control characters (character code 0-31)

The first 32 characters in the ASCII-table are unprintable control codes and are used to control peripherals such as printers.

DECOCTHEXBINSymbolHTML NumberHTML NameDescription
00000000000000NUL� Null character
10010100000001SOH Start of Heading
20020200000010STX Start of Text
30030300000011ETX End of Text
40040400000100EOT End of Transmission
50050500000101ENQ Enquiry
60060600000110ACK Acknowledge
70070700000111BEL Bell, Alert
80100800001000BS Backspace
90110900001001HT	 Horizontal Tab
100120A00001010LF
 Line Feed
110130B00001011VT Vertical Tabulation
120140C00001100FF Form Feed
130150D00001101CR
 Carriage Return
140160E00001110SO Shift Out
150170F00001111SI Shift In
160201000010000DLE Data Link Escape
170211100010001DC1 Device Control One (XON)
180221200010010DC2 Device Control Two
190231300010011DC3 Device Control Three (XOFF)
200241400010100DC4 Device Control Four
210251500010101NAK Negative Acknowledge
220261600010110SYN Synchronous Idle
230271700010111ETB End of Transmission Block
240301800011000CAN Cancel
250311900011001EM End of medium
260321A00011010SUB Substitute
270331B00011011ESC Escape
280341C00011100FS File Separator
290351D00011101GS Group Separator
300361E00011110RS Record Separator
310371F00011111US Unit Separator

ASCII printable characters (character code 32-127)

Codes 32-127 are common for all the different variations of the ASCII table, they are called printable characters, represent letters, digits, punctuation marks, and a few miscellaneous symbols. You will find almost every character on your keyboard. Character 127 represents the command DEL.

DECOCTHEXBINSymbolHTML NumberHTML NameDescription
320402000100000SP  Space
330412100100001!!!Exclamation mark
340422200100010""Double quotes (or speech marks)
350432300100011###Number sign
360442400100100$$$Dollar
370452500100101%%%Per cent sign
380462600100110&&&Ampersand
390472700100111''Single quote
400502800101000((&lparen;Open parenthesis (or open bracket)
410512900101001))&rparen;Close parenthesis (or close bracket)
420522A00101010***Asterisk
430532B00101011+++Plus
440542C00101100,,,Comma
450552D00101101- Hyphen-minus
460562E00101110...Period, dot or full stop
470572F00101111///Slash or divide
48060300011000000 Zero
49061310011000111 One
50062320011001022 Two
51063330011001133 Three
52064340011010044 Four
53065350011010155 Five
54066360011011066 Six
55067370011011177 Seven
56070380011100088 Eight
57071390011100199 Nine
580723A00111010:::Colon
590733B00111011;&#59;;Semicolon
600743C00111100<&#60;&lt;Less than (or open angled bracket)
610753D00111101=&#61;&equals;Equals
620763E00111110>&#62;&gt;Greater than (or close angled bracket)
630773F00111111?&#63;&quest;Question mark
641004001000000@&#64;&commat;At sign
651014101000001A&#65; Uppercase A
661024201000010B&#66; Uppercase B
671034301000011C&#67; Uppercase C
681044401000100D&#68; Uppercase D
691054501000101E&#69; Uppercase E
701064601000110F&#70; Uppercase F
711074701000111G&#71; Uppercase G
721104801001000H&#72; Uppercase H
731114901001001I&#73; Uppercase I
741124A01001010J&#74; Uppercase J
751134B01001011K&#75; Uppercase K
761144C01001100L&#76; Uppercase L
771154D01001101M&#77; Uppercase M
781164E01001110N&#78; Uppercase N
791174F01001111O&#79; Uppercase O
801205001010000P&#80; Uppercase P
811215101010001Q&#81; Uppercase Q
821225201010010R&#82; Uppercase R
831235301010011S&#83; Uppercase S
841245401010100T&#84; Uppercase T
851255501010101U&#85; Uppercase U
861265601010110V&#86; Uppercase V
871275701010111W&#87; Uppercase W
881305801011000X&#88; Uppercase X
891315901011001Y&#89; Uppercase Y
901325A01011010Z&#90; Uppercase Z
911335B01011011[&#91;&lsqb;Opening bracket
921345C01011100\&#92;&bsol;Backslash
931355D01011101]&#93;&rsqb;Closing bracket
941365E01011110^&#94;&Hat;Caret – circumflex
951375F01011111_&#95;&lowbar;Underscore
961406001100000`&#96;&grave;Grave accent
971416101100001a&#97; Lowercase a
981426201100010b&#98; Lowercase b
991436301100011c&#99; Lowercase c
1001446401100100d&#100; Lowercase d
1011456501100101e&#101; Lowercase e
1021466601100110f&#102; Lowercase f
1031476701100111g&#103; Lowercase g
1041506801101000h&#104; Lowercase h
1051516901101001i&#105; Lowercase i
1061526A01101010j&#106; Lowercase j
1071536B01101011k&#107; Lowercase k
1081546C01101100l&#108; Lowercase l
1091556D01101101m&#109; Lowercase m
1101566E01101110n&#110; Lowercase n
1111576F01101111o&#111; Lowercase o
1121607001110000p&#112; Lowercase p
1131617101110001q&#113; Lowercase q
1141627201110010r&#114; Lowercase r
1151637301110011s&#115; Lowercase s
1161647401110100t&#116; Lowercase t
1171657501110101u&#117; Lowercase u
1181667601110110v&#118; Lowercase v
1191677701110111w&#119; Lowercase w
1201707801111000x&#120; Lowercase x
1211717901111001y&#121; Lowercase y
1221727A01111010z&#122; Lowercase z
1231737B01111011{&#123;&lcub;Opening brace
1241747C01111100|&#124;&verbar;Vertical bar
1251757D01111101}&#125;&rcub;Closing brace
1261767E01111110~&#126;&tilde;Equivalency sign – tilde
1271777F01111111DEL&#127; Delete

The extended ASCII codes (character code 128-255)

There are several different variations of the 8-bit ASCII table. The table below is according to Windows-1252 (CP-1252) which is a superset of ISO 8859-1, also called ISO Latin-1, in terms of printable characters, but differs from the IANA’s ISO-8859-1 by using displayable characters rather than control characters in the 128 to 159 range. Characters that differ from ISO-8859-1 is marked by light blue color.

DECOCTHEXBINSymbolHTML NumberHTML NameDescription
1282008010000000&#8364;&euro;Euro sign
1292018110000001 Unused
1302028210000010&#130;&sbquo;Single low-9 quotation mark
1312038310000011ƒ&#131;&fnof;Latin small letter f with hook
1322048410000100&#132;&bdquo;Double low-9 quotation mark
1332058510000101&#133;&hellip;Horizontal ellipsis
1342068610000110&#134;&dagger;Dagger
1352078710000111&#135;&Dagger;Double dagger
1362108810001000ˆ&#136;&circ;Modifier letter circumflex accent
1372118910001001&#137;&permil;Per mille sign
1382128A10001010Š&#138;&Scaron;Latin capital letter S with caron
1392138B10001011&#139;&lsaquo;Single left-pointing angle quotation
1402148C10001100Œ&#140;&OElig;Latin capital ligature OE
1412158D10001101 Unused
1422168E10001110Ž&#142;&Zcaron;Latin capital letter Z with caron
1432178F10001111 Unused
1442209010010000 Unused
1452219110010001&#145;&lsquo;Left single quotation mark
1462229210010010&#146;&rsquo;Right single quotation mark
1472239310010011&#147;&ldquo;Left double quotation mark
1482249410010100&#148;&rdquo;Right double quotation mark
1492259510010101&#149;&bull;Bullet
1502269610010110&#150;&ndash;En dash
1512279710010111&#151;&mdash;Em dash
1522309810011000˜&#152;&tilde;Small tilde
1532319910011001&#153;&trade;Trade mark sign
1542329A10011010š&#154;&scaron;Latin small letter S with caron
1552339B10011011&#155;&rsaquo;Single right-pointing angle quotation mark
1562349C10011100œ&#156;&oelig;Latin small ligature oe
1572359D10011101 Unused
1582369E10011110ž&#158;&zcaron;Latin small letter z with caron
1592379F10011111Ÿ&#159;&Yuml;Latin capital letter Y with diaeresis
160240A010100000NBSP&#160;&nbsp;Non-breaking space
161241A110100001¡&#161;&iexcl;Inverted exclamation mark
162242A210100010¢&#162;&cent;Cent sign
163243A310100011£&#163;&pound;Pound sign
164244A410100100¤&#164;&curren;Currency sign
165245A510100101¥&#165;&yen;Yen sign
166246A610100110¦&#166;&brvbar;Pipe, broken vertical bar
167247A710100111§&#167;&sect;Section sign
168250A810101000¨&#168;&uml;Spacing diaeresis – umlaut
169251A910101001©&#169;&copy;Copyright sign
170252AA10101010ª&#170;&ordf;Feminine ordinal indicator
171253AB10101011«&#171;&laquo;Left double angle quotes
172254AC10101100¬&#172;&not;Negation
173255AD10101101­SHY&#173;&shy;Soft hyphen
174256AE10101110®&#174;&reg;Registered trade mark sign
175257AF10101111¯&#175;&macr;Spacing macron – overline
176260B010110000°&#176;&deg;Degree sign
177261B110110001±&#177;&plusmn;Plus-or-minus sign
178262B210110010²&#178;&sup2;Superscript two – squared
179263B310110011³&#179;&sup3;Superscript three – cubed
180264B410110100´&#180;&acute;Acute accent – spacing acute
181265B510110101µ&#181;&micro;Micro sign
182266B610110110&#182;&para;Pilcrow sign – paragraph sign
183267B710110111·&#183;&middot;Middle dot – Georgian comma
184270B810111000¸&#184;&cedil;Spacing cedilla
185271B910111001¹&#185;&sup1;Superscript one
186272BA10111010º&#186;&ordm;Masculine ordinal indicator
187273BB10111011»&#187;&raquo;Right double angle quotes
188274BC10111100¼&#188;&frac14;Fraction one quarter
189275BD10111101½&#189;&frac12;Fraction one half
190276BE10111110¾&#190;&frac34;Fraction three quarters
191277BF10111111¿&#191;&iquest;Inverted question mark
192300C011000000À&#192;&Agrave;Latin capital letter A with grave
193301C111000001Á&#193;&Aacute;Latin capital letter A with acute
194302C211000010Â&#194;&Acirc;Latin capital letter A with circumflex
195303C311000011Ã&#195;&Atilde;Latin capital letter A with tilde
196304C411000100Ä&#196;&Auml;Latin capital letter A with diaeresis
197305C511000101Å&#197;&Aring;Latin capital letter A with ring above
198306C611000110Æ&#198;&AElig;Latin capital letter AE
199307C711000111Ç&#199;&Ccedil;Latin capital letter C with cedilla
200310C811001000È&#200;&Egrave;Latin capital letter E with grave
201311C911001001É&#201;&Eacute;Latin capital letter E with acute
202312CA11001010Ê&#202;&Ecirc;Latin capital letter E with circumflex
203313CB11001011Ë&#203;&Euml;Latin capital letter E with diaeresis
204314CC11001100Ì&#204;&Igrave;Latin capital letter I with grave
205315CD11001101Í&#205;&Iacute;Latin capital letter I with acute
206316CE11001110Î&#206;&Icirc;Latin capital letter I with circumflex
207317CF11001111Ï&#207;&Iuml;Latin capital letter I with diaeresis
208320D011010000Ð&#208;&ETH;Latin capital letter ETH
209321D111010001Ñ&#209;&Ntilde;Latin capital letter N with tilde
210322D211010010Ò&#210;&Ograve;Latin capital letter O with grave
211323D311010011Ó&#211;&Oacute;Latin capital letter O with acute
212324D411010100Ô&#212;&Ocirc;Latin capital letter O with circumflex
213325D511010101Õ&#213;&Otilde;Latin capital letter O with tilde
214326D611010110Ö&#214;&Ouml;Latin capital letter O with diaeresis
215327D711010111×&#215;&times;Multiplication sign
216330D811011000Ø&#216;&Oslash;Latin capital letter O with slash
217331D911011001Ù&#217;&Ugrave;Latin capital letter U with grave
218332DA11011010Ú&#218;&Uacute;Latin capital letter U with acute
219333DB11011011Û&#219;&Ucirc;Latin capital letter U with circumflex
220334DC11011100Ü&#220;&Uuml;Latin capital letter U with diaeresis
221335DD11011101Ý&#221;&Yacute;Latin capital letter Y with acute
222336DE11011110Þ&#222;&THORN;Latin capital letter THORN
223337DF11011111ß&#223;&szlig;Latin small letter sharp s – ess-zed
224340E011100000à&#224;&agrave;Latin small letter a with grave
225341E111100001á&#225;&aacute;Latin small letter a with acute
226342E211100010â&#226;&acirc;Latin small letter a with circumflex
227343E311100011ã&#227;&atilde;Latin small letter a with tilde
228344E411100100ä&#228;&auml;Latin small letter a with diaeresis
229345E511100101å&#229;&aring;Latin small letter a with ring above
230346E611100110æ&#230;&aelig;Latin small letter ae
231347E711100111ç&#231;&ccedil;Latin small letter c with cedilla
232350E811101000è&#232;&egrave;Latin small letter e with grave
233351E911101001é&#233;&eacute;Latin small letter e with acute
234352EA11101010ê&#234;&ecirc;Latin small letter e with circumflex
235353EB11101011ë&#235;&euml;Latin small letter e with diaeresis
236354EC11101100ì&#236;&igrave;Latin small letter i with grave
237355ED11101101í&#237;&iacute;Latin small letter i with acute
238356EE11101110î&#238;&icirc;Latin small letter i with circumflex
239357EF11101111ï&#239;&iuml;Latin small letter i with diaeresis
240360F011110000ð&#240;&eth;Latin small letter eth
241361F111110001ñ&#241;&ntilde;Latin small letter n with tilde
242362F211110010ò&#242;&ograve;Latin small letter o with grave
243363F311110011ó&#243;&oacute;Latin small letter o with acute
244364F411110100ô&#244;&ocirc;Latin small letter o with circumflex
245365F511110101õ&#245;&otilde;Latin small letter o with tilde
246366F611110110ö&#246;&ouml;Latin small letter o with diaeresis
247367F711110111÷&#247;&divide;Division sign
248370F811111000ø&#248;&oslash;Latin small letter o with slash
249371F911111001ù&#249;&ugrave;Latin small letter u with grave
250372FA11111010ú&#250;&uacute;Latin small letter u with acute
251373FB11111011û&#251;&ucirc;Latin small letter u with circumflex
252374FC11111100ü&#252;&uuml;Latin small letter u with diaeresis
253375FD11111101ý&#253;&yacute;Latin small letter y with acute
254376FE11111110þ&#254;&thorn;Latin small letter thorn
255377FF11111111ÿ&#255;&yuml;Latin small letter y with diaeresis

上述来自: https://www.ascii-code.com/

一个简单的计数批处理文件

@echo off
setlocal enabledelayedexpansion

:: 定义计数文件
set counter_file=counter.txt

:: 检查计数文件是否存在
if not exist %counter_file% (
    echo 0 > %counter_file%
)

:: 从文件中读取当前计数值
set /p counter=&lt;%counter_file%

:: 显示当前计数值
echo Current counter value: %counter%

:: 将计数值加1
set /a counter+=1

:: 将新的计数值写入文件
echo %counter% > %counter_file%

:: 显示新的计数值
echo New counter value: %counter%

::为了看的清楚,这里加入一个 Pause
pause

endlocal

MAX98357 I2S功放模块测试

之前购买了一个MAX98357 I2S功放模块,这次编写简单的代码进行测试。

硬件连接如下:

MAX98357ESP32S3用途
SPK+/- 连接喇叭 连接喇叭正负极,喇叭输出
DIN  48从 ESP32S3 发送的 I2S数据
BCLK45从 ESP32S3 发送的 I2S Clock
LRC 35从 ESP32S3 发送的 I2S 左右声道选择信号
GNDGND
VCC5V供电

按照上述方案连接好后,烧录如下代码:

#include <I2S.h>
const int frequency = 440; // frequency of square wave in Hz
const int amplitude = 32000; // amplitude of square wave
const int sampleRate = 8000; // sample rate in Hz
const int bps = 16;

const int halfWavelength = (sampleRate / frequency); // half wavelength of square wave

short sample = amplitude; // current sample value
int count = 0;

i2s_mode_t mode = I2S_PHILIPS_MODE; // I2S decoder is needed
// i2s_mode_t mode = ADC_DAC_MODE; // Audio amplifier is needed

// Mono channel input
// This is ESP specific implementation -
//   samples will be automatically copied to both channels inside I2S driver
//   If you want to have true mono output use I2S_PHILIPS_MODE and interlay
//   second channel with 0-value samples.
//   The order of channels is RIGH followed by LEFT
//i2s_mode_t mode = I2S_RIGHT_JUSTIFIED_MODE; // I2S decoder is needed

void setup() {
  Serial.begin(115200);
  Serial.println("I2S simple tone");
  delay(5000);

    //setAllPins(int sckPin, int fsPin, int sdPin, int outSdPin, int inSdPin);
  I2S.setAllPins(45        , 35       , 48       , 48          , -1);

  // start I2S at the sample rate with 16-bits per sample
  if (!I2S.begin(mode, sampleRate, bps)) {
    
    Serial.println("Failed to initialize I2S!");
    while (1); // do nothing
  }
}

void loop() {

   while (Serial.available()) {
    char c = Serial.read();
    if (c == '3') {
      ESP.restart();
    }
    // 主机端发送 l, 回复 z 用于识别串口
    if (c == '1') {
      Serial.print('z');
    }
    // 主机端发送 l, 回复 z 用于识别串口
    if (c == '2') {
      Serial.printf("getSckPin:%d getFsPin:%d getDataPin:%d",
                      I2S.getSckPin(),
                      I2S.getFsPin(),
                      I2S.getDataPin());
    }    
  }

  
    if (count % halfWavelength == 0 ) {
      // invert the sample every half wavelength count multiple to generate square wave
      sample = -1 * sample;
    }

    if(mode == I2S_PHILIPS_MODE || mode == ADC_DAC_MODE){ // write the same sample twice, once for Right and once for Left channel
      I2S.write(sample); // Right channel
      I2S.write(sample); // Left channel
    }else if(mode == I2S_RIGHT_JUSTIFIED_MODE || mode == I2S_LEFT_JUSTIFIED_MODE){
      // write the same only once - it will be automatically copied to the other channel
      I2S.write(sample);
    }

    // increment the counter for the next sample
    count++;
}

测试的视频在下面可以看到:

WinPE下面制造一个蓝屏

正常的 Windows下面蓝屏很常见,实际上 WinPE 下面也是可以出现蓝屏的。这次介绍通过修改 WinPE 的注册表,实现USB键盘上按下右 Ctrl+快速按下Scroll键即可触发蓝屏 【参考1】。

最关键的步骤是修改 WinPE的注册表,打开这个触发蓝屏的功能。

1.将 Windows安装盘中的 Boot 解压,放在 c:\labz 目录下,然后运行如下命令解包之:

dism /mount-wim /wimfile:c:\labz\boot.wim /index:1 /mountdir:c:\m1

2.打开本机的注册表工具,先选中 HKEY_USERS,然后在菜单上选择 Load Hive

3.在对话框上选择 c:\m1\windows\system32\config\system 文件

4.设置一个加载点

这样操作之后可以看到挂载到如下位置了

5.我们在LABZ\ControlSet001\Services\kbhid\Parameters 下面创建 CrashOnCtrlScroll 并且赋值为1

6.选中注册表上的 “LABZ”,然后菜单选择 Unload Hive,这样就从注册表中卸载了WinPE的注册表

7.之后 关闭注册表编辑器,然后使用如下命令写入 WIM(特别注意,实践中发现有时候无法正常写入,错误信息是 Windows有占用目录下的文件,这种情况下重启操作系统再运行一次即可)

dism /unmount-wim /MountDir:c:\m1 /Commit

8.接下来再次解包 Boot.WIM (原因和之前” 制作全自动安装的 Windows 11 ISO”文章提到的一样,BOOT.WIM 中有2个WindowPE环境)

dism /mount-wim /wimfile:c:\labz\boot.wim /index:2  /mountdir:c:\m1

之后同样执行2-7步骤,最终我们就得到了一个修改后的 BOOT.WIM

使用,ISO 编辑工具将BOOT.WIM 写入 ISO 之后,我们就得到了一个测试 Windows安装镜像文件。在安装过程中使用 USB 键盘,按下右侧Ctrl然后快速按下2测 Scoll 键就能够触发蓝屏了。

可以看到蓝屏发生后,显示一段之后会自动重启。

最后讲个有意思的事情。很多年前,我碰到过一个奇怪的问题:工厂那边反映我们 Release 的BIOS有问题,会导致生产过程中重启。负责这个事情的BIOS工程师是一个妹子,被这个问题折磨很久。问题发生之后,她不修改任何代码,只是重新编译一次BIOS,发给产线使用问题就会消失。但是后面不知道什么时候问题又会出来。出于好奇后来我接手这个问题进行研究。所有的整机无论是笔记本还是台式机,在生产的过程中都会有灌装系统运行产测软件的步骤。在这个过程中,会检查一些基本的功能,比如:是否会有声音,屏幕键盘鼠标能否工作正常等等。这个测试通常需要一气呵成完成的,每个测试都会收集测试结果,然后上报到服务器中的,因此如果发生意外重启会打断整个流程。测试结束后,会重新安装一个新的操作系统然后再交给客户。作为BIOS工程师,我是不太相信BIOS会导致这样的问题。因此,我和工厂要了一下他们的产测软件在实验室进行研究。产线使用 WinPE环境,我手上没有,只能在普通 Windows上试验。试验几次之后,我发现其中的测试软件会出现Windows的报错对话框。于是,将关注点放在了这个软件上。咨询产线得知这个软件的作用是在0xF0000 中搜索一个字符串。听到这里我心里就有了大概,Windows下访问物理内存,出现错误是很重要的。之后和产线要到的源代码,简单读了了一下很快就定位了问题。这个软件需要在物理内存中搜索,于是作者调用了一个 Window API 做了一下映射,将 0xF0000开始的64K物理内存映射到应用程序的内存上,然后用 memcmp 进行查找。发生问题的原因是,要查找的字符串刚好卡在结尾处,比如我们需要在内存中查找“LAB-Z.COM”这个字符串,但是刚好碰到这个字符串在内存中分布如下:

0xFFFFA0xFFFFB0xFFFFC0xFFFFD0xFFFFE0xFFFFF0x10 00000x10 00010x10 00020x10 0003
LABZ.COM0

当直接使用 memcpy 查找的时候,它会先找到 “LAB-Z”,但是继续比较字符串剩余部分的时候就碰到“指针出界”的问题。如果在正常的Windows下是可以抛出这个问题继续运行的,但是在WinPE环境下就直接变为重启。最终,经过努力这次的问题没有让BIOS工程师来背锅。

另外多说一句:即便相同的产线,相同的物料,白班和夜班的质量也会有差别。原因是白天人全,技术和后端都在,出了问题会有人处理;夜班的话,人不全,出了问题通常的处理方法是“小车不倒只管推”了。

参考:

1. https://www.lab-z.com/wdbg/  WinDBG 分析键盘生成的 Dump 文件

ASCII数字

因为 UEFI Shell 是 CUI 界面,很多测试需要用 ASCII 显示结果。所以有些时候我们需要足够大的字来展示。

最近偶然发现了这个 ASCII 字体的网站,可以用来取得一些 ASCII 拼凑出来的字形。例如:

░▒▓█▓▒░       ░▒▓██████▓▒░░▒▓███████▓▒░░▒▓████████▓▒░ 
░▒▓█▓▒░      ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░      ░▒▓█▓▒░ 
░▒▓█▓▒░      ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░    ░▒▓██▓▒░  
░▒▓█▓▒░      ░▒▓████████▓▒░▒▓███████▓▒░   ░▒▓██▓▒░    
░▒▓█▓▒░      ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░░▒▓██▓▒░      
░▒▓█▓▒░      ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░        
░▒▓████████▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓███████▓▒░░▒▓████████▓▒░ 
                                                      

 __      __    ____      ____ 
(  )    /__\  (  _ \ ___(_   )
 )(__  /(__)\  ) _ &lt;(___)/ /_ 
(____)(__)(__)(____/    (____)

     ___       ___           ___           ___     
     /\__\     /\  \         /\  \         /\  \    
    /:/  /    /::\  \       /::\  \        \:\  \   
   /:/  /    /:/\:\  \     /:/\:\  \        \:\  \  
  /:/  /    /::\~\:\  \   /::\~\:\__\        \:\  \ 
 /:/__/    /:/\:\ \:\__\ /:/\:\ \:|__| _______\:\__\
 \:\  \    \/__\:\/:/  / \:\~\:\/:/  / \::::::::/__/
  \:\  \        \::/  /   \:\ \::/  /   \:\~~\~~    
   \:\  \       /:/  /     \:\/:/  /     \:\  \     
    \:\__\     /:/  /       \::/__/       \:\__\    
     \/__/     \/__/         ~~            \/__/    

有兴趣的朋友可以在这里看到:

http://www.patorjk.com/software/taag/#p=testall&f=Alpha&t=LAB-Z

UEFI TIPS:Print=UnicodeSPrint+ ConOut

最近有在屏幕输出数据的需求,但是无法直接使用 Print 。经过对于 PrintLib 的一番研究,得出了结论:

UEFI Shell 下的Print 的实现可以看作两个动作,一个根据输入格式化得到字符串,另外一个是使用 gST 进行输出。简单的说就是:

Print=UnicodeSPrint+ gST->ConOut->OutputString

编写测试代码:

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

#include  <Library/PrintLib.h>
extern EFI_SYSTEM_TABLE			 *gST;
INTN
EFIAPI
ShellAppMain (
  IN UINTN Argc,
  IN CHAR16 **Argv
  )
{
  CHAR16					Buffer[32];
  
  UnicodeSPrint((CHAR16 *)Buffer,sizeof(Buffer),L"%x\n",2024);
  gST->ConOut->OutputString(gST->ConOut,Buffer);
 
  return(0);
}

运行结果:

如果你在调试 Application 或者Driver遇到无法直接使用 Print 的情况,不妨考虑本文提到的方法。当然,如果你有从串口或者其他设备输出调试数据的时候,也可以考虑UnicodeSPrint()来实现数据格式化方便阅读调试。

一些Unicode 数字符号定义

1.圈中带有数字

⓪ ① ② ③ ④ ⑤ ⑥ ⑦ ⑧ ⑨ ⑩ ⑪ ⑫ ⑬ ⑭ ⑮ ⑯ ⑰ ⑱ ⑲ ⑳
㉑ ㉒ ㉓ ㉔ ㉕ ㉖ ㉗ ㉘ ㉙ ㉚ ㉛ ㉜ ㉝ ㉞ ㉟ ㊱ ㊲ ㊳ ㊴ ㊵
㊶ ㊷ ㊸ ㊹ ㊺ ㊻ ㊼ ㊽ ㊾ ㊿

2.实心方块中空圆形数字

         
         

3.实心方块数字

         

4.中文

         

来源:http://xahlee.info/comp/unicode_circled_numbers.html

此外,在 https://altcodeunicode.com/alt-codes-circled-number-letter-symbols-enclosed-alphanumerics/ 还有一些圆圈的英文序号

制作全自动安装的 Windows 11 ISO

前面提 到通过应答文件来实现自动安装【参考1】,使用这个方法在虚拟机上测试正常,但是实体机上在分区拷贝完成之后会进入OOBE的界面要求手工选择,因此并非全自动安装。

针对这个问题进行了更深入的研究,原来除了在安装盘下面放置autounattend.xml 之外,在对应的 WinPE 盘,Windows\Panther 目录下还需要放置一个 unattend.xml 应答文件。更具体的操作是,安装 ADK

1。解压Windows 11 安装 ISO

2.取出其中的 boot.wim 文件

3.在 “Deployment and Imaging Tools Environment”中使用如下命令解压 Boot.WIM 到 m1 目录下

dism /mount-wim /wimfile:c:\LABZ\boot.wim /index:1 /mountdir:c:\m1

4.将unattend.xml拷贝到 m1\Windows\Panther目录下

5.将修改回写到 boot.wim 中

dism /unmount-wim /MountDir:c:\m1 /Commit

6.同样在 “Deployment and Imaging Tools Environment”中再次解压 Boot.WIM 到 m1 目录下(Boot 中有个 Index,上一次用的是 1,这次用的是 2)

dism /mount-wim /wimfile:c:\LABZ\boot.wim /index:2 /mountdir:c:\m1

7.将unattend.xml拷贝到 m1\Windows\Panther目录下

8.将修改回写到 boot.wim 中

dism /unmount-wim /MountDir:c:\m1 /Commit

这样就有了一个更换过 unattend.xml的Boot.WIM 其中是一个完整的 WinPE 环境,接下来使用工具将Boot.WIM替换回原始的安装 ISO。最终我们就有了一个全自动的Window安装盘。

这样的ISO通过 Refuse或者Ventoy 制作出来的启动U盘上都可以正常启动,并且能够做到完全自动的安装。

本文提到的制作好的 Windows 11 可以在这里下载(文件超过4G, 分割为2个ZIP 压缩文件)

文件1

文件2

对应的2个 xml 文件可以在这里下载:

参考:

1. https://www.lab-z.com/winut/

测试的视频,在 LattePanda MU 上进行的测试:

基于Ch554 实现 USB 转 USB

最近设计了一个 USB 转USB 设备,它带有一个USB公头和一个USB母头,可以读取一个USB 设备发出来的数据,然后转换为另外的数据。

首先是硬件设计,使用了2个 CH554e芯片,这个芯片能够实现 USB Host和Device,二者通过串口进行通讯。这款芯片是南京WCH出品的,最高支持 24Mhz主频内置,16K程序存储器ROM和256字节内部iRAM以及1K 字节片内xRAM。Ch554e 是最小的封装形式,MOP10方便焊接。

硬件设计比较简单,2个5V供电的Ch554的最小系统,中间通过串口连接。

PCB 设计如下:

这样的设计刚好能够放入淘宝购买的透明外壳中。

两个 Ch554分别写入不同的固件。其中USB母头连接Ch554的需要写入 Keil编译的代码,用于实现 USB Host 功能。解析后的HID 数据会按照 Ch9350 格式通过串口输出,有兴趣的朋友可以在【参考1】看到实现。

USB 公头连接的Ch554代码使用 Arduino 进行编译。实现的功能是检测通过串口获得数据是否包含 wasd 这几个按键,如果有的话就转为对应的鼠标移动操作:

#ifndef USER_USB_RAM
//#error "This example needs to be compiled with a USER USB setting"
#endif

#include "src/userUsbHidKeyboardMouse/USBHIDKeyboardMouse.h"

#define DEBUGMODE 0

void setup() {
  // 串口通讯
  Serial1_begin(500000);
  USBInit();
  pinMode(14, OUTPUT);
  digitalWrite(14, LOW);
}

boolean FindKey(byte s, byte *p, byte len) {
  for (byte i = 0; i < len; i++) {
    if (p[i] == s) {
      return true;
    }
  }
  return false;
}
void loop() {
  //根据 CH9350 Spec 每次最多输出 72Bytes
  byte Data[72];
  byte CounterLast = Serial1_available();
  byte CounterCurrent = 0;

  // 如果当前串口有数据
  if (CounterLast != 0) {
    // 进行简单测试,如果当前还在传输数据那么持续接收
    while (CounterCurrent != CounterLast) {
      CounterLast = Serial1_available();
      delayMicroseconds(500);
      CounterCurrent = Serial1_available();
    }
  }

  if (CounterCurrent > 0) {
    // 一次性将数据收取下来
    //Serial1_readBytes(Data, CounterCurrent);
    for (byte i = 0; i < CounterCurrent; i++) {
      Data[i] = Serial1_read();
      //  USBSerial_print_ub(Data[i], 16);
    }

    unsigned int i = 0;
    unsigned int Length;
    while (i < CounterCurrent) {
      // 识别帧头
      if ((Data[i] == 0x57) && (Data[i + 1] == 0xAB)) {
        // 有效键值帧
        if (Data[i + 2] == 0x88) {
          // 获得数据长度
          Length = Data[i + 3];
          //如果是键盘
          if (Data[i + 4] == 0x10) {
            digitalWrite(14, HIGH);
            if (DEBUGMODE) {
              for (int j = 3; j < Length - 2; j++) {
                USBSerial_print_ub(Data[i + 3  + j], 16);
              }
              USBSerial_println_only();
            }
            if (FindKey(0x1A, Data, Length) == true) { // 'w'
              Mouse_move(0, -100);
            }
            if (FindKey(0x16, Data, Length) == true) { // 's'
              Mouse_move(0, 100);
            }
            if (FindKey(0x04, Data, Length) == true) { // 'a'
              Mouse_move(-100,0);
            }
            if (FindKey(0x07, Data, Length) == true) { // 'd'
              Mouse_move(100,0);
            }
            digitalWrite(14, LOW);
          } //if (Data[i + 4] == 0x10) {
        }
        i = i + 3 + Length;
      }
      i++;
    } // while (i < Counter)
  }
}

通过串口烧录,短接 DL1 或者  DL2 接口,插入 Windows主机后,设备管理器中会出现新的设备,然后使用 wchispstudio 即可烧写。对于USB Host 对应的Ch554需要一个 USB 公头转公头来实现转为USB公头然后进行烧写。

参考:

  1. https://mc.dfrobot.com.cn/thread-319462-1-1.html

本文提到的完整代码下载:

1.模拟键盘的代码(Arduino)

2. USB Host 代码

Step to UEFI (296)虚拟机下的假电池

电池作为现在笔记本必不可少的部件,通过 ACPI 和 Windows 进行交互。

对此,ACPI Spec 定义了几个 Table。换一句话说,Windows 只要能够正确读取出 Table,那么就可以根据上面的信息展示给客户一个电池。

第一个是 _BIX (Battery Information Extended) (特别注意ACPI 4.0定义的 _BIF (Battery Information)已经废止 ),其中给出了电池的信息。

偏移名称大小解释
RevisionDWORD目前版本号为 1
Power UnitDWORD电池容量单位: 0 – [mWh], 同时充放电速度将会以[mW]为单位 1 – [mAh], 同时充放电速度将会以[mA]为单位
Design CapacityDWORD设计容量,单位由上面的 Power Unit 给出 取值范围: 0x00000000-0x7FFF FFFF 0xFFFFFFFF 未知容量
Last Full Charge CapacityDWORD充满后的预期容量 取值范围: 0x00000000-0x7FFF FFFF 0xFFFFFFFF 未知容量
Battery TechnologyDWORD电池位置 0x0000 0000 主电池 0x0000 0001 第二块电池
Design VoltageDWORD设计电压, 取值范围 0x000000000 – 0x7FFFFFFF in [mV] 0xFFFFFFFF – 未知电压
Design Capacity of WarningDWORDOEM 设置的告警容量值 取值范围 0x000000000 – 0x7FFFFFFF in [mWh] or [mAh]
Design Capacity of LowDWORDOEM 设置的低容量值 取值范围 0x000000000 – 0x7FFFFFFF in [mWh] or [mAh]
Cycle CountDWORD充电循环次数 取值范围 0x000000000 – 0xFFFFFFFF
Measurement AccuracyDWORD电池容量测量准确度,以1/1000为单位,比如:80000表示80%
Max Sampling TimeDWORD_BST 中两次测量的最大间隔时间,比如,当前电池容量,放电速度或者剩余容量。以为毫秒单位。0xFFFFFFFF表示该位置无效。
Min Sampling TimeDWORD_BST 中两次测量的最小间隔时间。以为毫秒单位。0xFFFFFFFF表示该位置无效。
Max Averaging IntervalDWORD_BST 中两次测量的平均最大间隔时间。
Min Averaging IntervalDWORDBST 中两次测量的平均最小间隔时间。
Battery Capacity Granularity 1DWORD电池在告警容量值和低容量值之间的颗粒度
Battery Capacity Granularity 2DWORD电池在告警容量值和充满容量值之间的颗粒度
Model Number零结尾ASCII字符串OEM 定义的电池型号
Serial Number零结尾ASCII字符串OEM 定义的电池序列号
Battery Type零结尾ASCII字符串OEM 定义的电池类型
OEM Information零结尾ASCII字符串OEM 定义的在UI上展示的电池OEM信息
Battery Swapping CapabilityDWORD0x0 不可更换电池,例如,内部密封电池,用户无法接触到 0x1关机之后可更换电池 0x10 热插拔电池
上述根据ACPI Spec翻译,如果有错误欢迎指出,会进行订正

第二个是 _BST (Battery Status), 这个用于报告当前电池的状态信息。

偏移名称大小解释
Battery StateDWORDBit0 为1表示正在放电 Bit1  为1表示正在充电 Bit2  为1表示电池预警  
Battery Present RateDWORD电池充放电速度 取值范围 0x000000000 – 0x7FFFFFFF以[mW]或者[mA]为单位 0xFFFFFFFF – 未知速度    
Battery Remaining CapacityDWORD电池剩余容量 取值范围 0x000000000 – 0x7FFFFFFF以[mWh]或者[mAh]为单位 0xFFFFFFFF – 未知容量  
Battery Present VoltageDWORD电池电压 取值范围 0x000000000 – 0x7FFFFFFF以[mV]为单位 0xFFFFFFFF – 未知电压  

以本人的电脑(HP 840 G6)为例,设备管理器中可以看到电池:

使用 HE 直接读取 ACPI Table:

根据上面的整理出两个对应的Table, 放在 BAT0 设备中

Device (BAT0)
        {
            Name (_HID, EisaId ("PNP0C0A") /* Control Method Battery */)  // _HID: Hardware ID
            Name (_UID, One)  // _UID: Unique ID
            Method (_DSM, 4, Serialized)  // _DSM: Device-Specific Method
            {
                If (LEqual (Arg0, ToUUID ("4c2067e3-887d-475c-9720-4af1d3ed602e") /* Battery Thermal Limit */))
                {
                    Switch (ToInteger (Arg2))
                    {
                        Case (0x03)
                        {
                            Return (Package (0x01)
                            {
                                0x1E
                            })
                        }

                    }
                }
                Else
                {
                    Return (Package (0x01)
                    {
                        Zero
                    })
                }
            }

            Method (_STA, 0, NotSerialized)  // _STA: Status
            {
                Return (0x1F)
            }

            Method (_BIX, 0, NotSerialized)  // _BIX: Battery Information Extended
            {
                Return ( Package (0x15)
						{
							1, 
							1, 
							20000, 
							20000, 
							0, 
							4300, 
							2000, 
							1000, 
							10, 
							80000, 
							1000, 
							500, 
							750, 
							500, 
							0x64, 
							0x64, 
							"LABZBAT0", 
							"202410", 
							"MODOL1", 
							"LABZBAT0", 
							One
						})
            }

            Method (_BST, 0, NotSerialized)  // _BST: Battery Status
            {
                Return ( Package (0x04)	{
               			 1, 
               			 100, 
                		 10000, 
                		 4200
           			   })
            }

        }

     }

接下来选择使用 VirtualBox 虚拟机,根据【参考1】,替换内部的 ACPI Table, 最终效果如下:

就是说,我们成功的在这个虚拟机中安装了一块电量为 50% 的电池。

本文提到的修改后的 ACPI 源代码可以在这里下载:

参考:

1.https://www.lab-z.com/arcpi/