SystemInfo命令

这个命令能够显示计算机及其操作系统的详细配置信息,包括操作系统配置、安全信息、产品 ID 和硬件属性,如 RAM、磁盘空间和网卡和补丁信息等。比如,有人希望你确认操作系统版本信息,除了使用 WinVer, 还可以试试这个命令。例如,运行结果如下:

此外,还可以直接显示需要的结果,比如直接获得系统型号,可以和 findstr 配合使用

特别注意:很多资料说可以使用 find,但是根据我的实验,这条指令在中文操作系统下无法正常工作,推荐使用 findstr。

通过这样的工具,如果下次有人需要你提供当前版本信息,可以直接生成全部信息提供给他了。

参考:

  1. https://www.cnblogs.com/sfccl/p/12344416.html win10系统systeminfo命令的过滤用法
  2. https://baike.baidu.com/item/systeminfo systeminfo

制作一个 WinPE 启动盘

FAT32 分区存在着单个文件无法大于4G的限制,NTFS分区存在着无法启动的限制。将U盘制作成具有分别是FAT32和NTFS格式的分区可以结合二者优点避免上述限制。下面介绍一下具体制作方法。因为 Windows不支持对U盘分区,所以需要使用第三方工具,这里推荐 DiskGenius。官方网站 http://www.diskgenius.cn/

  1. 准备一个U盘,越大越好。
  2. 使用DiskGenius打开U盘,首先删除之前U盘上的分区,下面是一个14G的U盘

3, 选择新建分区,出现下面的画面,选择取消

4. 接下来新建第一个分区,注意需要设置为 NTFS 分区,我这边分配给他 13G

操作之后U盘分配如下

5.接下来继续在空闲的空间建立分区

这次选择 FAT32 格式,大小为1GB

之后,U盘空间分配如下

6.保存更改,工具会提示是否格式化,选择是自动格式化。

7. 经过这样的处理后U盘上有两个分区,分别是 NTFS 和 FAT32。对于 Win7 Win8 和 Win10 早期版本,只能看到 NTFS 分区,后面的FAT32分区是不可见的。

8. 继续使用 DiskGenuis, 选中U盘第二个分区,使用“浏览文件”

9.解压之前的 WinPELABZ.ISO, 将解压后的文件拖到第二个分区中。这个ISO是450MB大小,因此理论上只要分区大于这个值都可以放进去。同样的,如果你有其他的工具,比如DISM++,可以使用同样的方法放在这个分区上。

10.拷贝完成后即制作完成。

11.在启动时,调出 Boot Menu 选择从这个U盘启动即可。

在使用的时候,可以将硬盘镜像存放在 NTFS 格式的分区上,这样用一个U盘就能完成系统的恢复或者备份,非常方便。

ModernStandby调试的准备

《人月神话》是一本软件工程的著名书籍。其中“人月”的是一种表示劳动时间的计量单位。比如,一个软件需要3个人5个月来完成,这个软件的工作量就可以描述为 3*5=15人月。当然,因为软件设计是复杂的思维劳动,用上面的衡量办法很可能出现下面这样的推理:一头猪五个月下五个仔,换算下来一个猪仔相当于一个猪月,那么如果需要十个猪仔只需要十头猪一个月即可…….

其中的一章名称是“没有银弹”。“银弹”这个词来源于欧洲中世纪的传说。说的是狼人这样的怪物,一般的子弹是打不死它的。必须使用银子做的子弹才能杀死它。(说道这里我忽然发觉这个词听起来充满了贵族气息,比如月光下帅气的男主角从容的掏出手枪,装上散发出银色光芒的子弹然后射死怪物;相比之下国产的盗墓小说提到的对付“大粽子”的墨线糯米还有黑驴蹄子则充满了乡土气息……)后来“银弹”这个词就被用来形容,那些特别有效果、一用就很灵的方法。这章节 “没有银弹”的意思是,软件工程是一个超级复杂系统,没有任何特效的方法,可以一直提高效率。在Debug Modern Standby 的时候同样 “没有银弹” 。需要有足够的心理预期,因为整个过程可能会拉的很长有很多试验需要进行,必须保持足够的耐心。最常见的问题是在Debug 过程中因为灵光一闪而进行跳跃试验,漏掉一些因素最终导致数据和结论相互矛盾。因此,建议在上手的时候保持足够的耐心和勇气,尽量不厌其烦的将试验和条件逐一记录下来。

在动手之前,请保证如下事宜:

  1. 有一台能够进行参考的系统,最好是Intel RVP。在出现进入 MS死机或者重启时,可以非常有效的比对出当前是HW还是FW 问题。如果出现HW工程师开始研究FW设定,然后FW工程师反复研究电路图,通常意味着问题已经进入了死胡同;
  2. 在干净的系统上进行试验。这里的干净系统指的是只包括Windows和BKC驱动的系统。比如,XX电脑管家可能会导致系统无法进入MS,爱奇艺的存在也会影响进入 MS;
  3. 使用已经验证过的,确定支持 MS 的外围设备,特别是硬盘。作为工程师我们只能解决自己设计上的问题,无法解决部件的问题。特别是硬盘这种外观型号能够完全一致但是内部 FW版本不同的部件。另外,用具体试验来作为认定一些部件有问题是非常有说服力同时容易让人接受的。比如,硬盘是进入 MS 的关键部件,Intel SoC 无法兼容UMIS的 NVME 和FORESEE的SSD会让系统Block在 PC2;
  4. 进行测试时请拔掉USB设备,包括键盘鼠标和 Hub,理论上这些都不会影响MS,唯一的问题是你不知道你手上的是不是不影响MS的;
  5. 显示器可能会影响进入 MS。我听说过这样的事情,但是并没有亲见,如果有条件建议多用几个显示器试验;
  6. 检查所有的 GPIO 设定。最好让 HW 提供GPIO 设定的表格,虽然他们通常并不情愿,但是这个确实应该他们做,只有他们才能深刻的理解每一根GPIO的功能。设定之后在 Windows下用 GPIO 工具导出最终结果然后检查是否和HW设定匹配。我不认为有“高级错误” 和“低级错误”的差别。但是你可以想象当你和老板解释为什么某个问题花费了3周才能解决时,“GPIO设定错误”和“Intel 给出来的 PMC 有Bug,结果他们用了二十多天在我们不停的催促下才给出了更新的版本”哪种解释更容易让他接受;
  7. 如果设计有 ThunderBolt/TCSS ,务必请 HW保证设计同 RVP 相同,理论上用任何GPIO都是可行的,但是因为涉及到诸多的 FW 你无法保证其中能够配合你的设计。之前我碰到过一个 Camera 模块一直无法点亮,HW 测量表明对应的 MIPI Clock 频率不正确,在我研究三天无果焦头烂额甚至找不到能够配置频率的寄存器后,驱动工程师承认他在驱动中Hard Code成固定的频率;
  8. 尽量关闭BIOS中的安全相关的设定,比如:Secure Boot。因为这些项目可能会影响测试软件以及测试结果。当然如果试验发现确实会这样,后面找 Intel 来解决就好了(这也意味着其他家会有同样的问题,不用担心);
  9. 不要连接互联网。这句话的意思是:从安装系统开始,可以连接局域网,但是必须保证没有连接到互联网上。 Windows 后台有升级操作,但是你不知道的动作和进度。我碰到过多次工作正常的系统在连接一次互联网之后就变得不稳定,明确的结果能够给我们明确的方向,不稳定的结果非常有可能误导我们。
  10. 建议在开始之前关闭 RTD3 功能,这个功能对省电有帮助,但是 MS 没有帮助。在项目开始的时候,Codebase 中的 RTD3 设定的 GPIO 和你项目硬件设定不符有可能导致奇怪的问题;
  11. 可以多用用全盘镜像的工具,比如:Macrium Reflect 【参考1】,这样可以及时发现因为驱动更新导致的问题;

当上述工作完成后,就可以开始进行 Debug 了, 具体的方法就是运行 Power House Mountain 然后查看结果。具体有如下操作:

  1. 如果Sleep MS 的时候有异常重启,可以通过BIOS设定 CPU C-Status Limitation的方式来判断是否和MS相关。比如,Limit 到 C8 之后不会发生重启,就能确定问题是SLPS0 信号发出时导致的问题;通常这种问题是和硬件设计相关还需要请 HW 帮忙测试找到原因;
  2. 如果PHM提示某个设备有问题没有 Power Gated, 最简单的方法是关闭之然后继续试验。特别注意的是:Audio设备不要轻易关闭,一些能够正常工作的系统关闭 Audio 之后反倒变得无法进入CS,据说这个问题是同 GFX Driver 有关;
  3. 如果发现某个外部 PCIE 设备有问题,需要确认对应的 Clock Request Pin 是否正确。在 PHM 的 Log中有这个的读取结果,结合电路图进行确认。当然,这里我非常建议用示波器之类的确认这个Pin是否工作正常。
  4. 如果PHM 提示 CSME 工作异常,首先需要确认 BIOS中的ME 版本和系统驱动是否匹配,其次还要检查没有使用的SMB Pin之类是否正确关闭;

从上面的描述也可以看到,几乎所有的方面都会对 MS 产生影响,这也是为什么“在Debug Modern Standby 的时候同样 ‘没有银弹’ 。” 的原因。如果考试之前老师表示这本书全部都是重点,那么也就相当于没有重点……..

Good Luck, BIOS Engineer!

参考:

1. http://www.lab-z.com/newghost/   Ghost 替代者,新的全盘备份工具

QEMU的重新编译(下)

前面介绍了完整的重新编译QEMU 的方法,下面介绍一个另外的方法,稍微简便一点。

简单的说,我使用前面提到的方法升级了所有的Package,然后把msys64目录进行了打包。有需要的朋友可以下载下面的内容:

[1] Env.7z  里面有两个目录,一个是 msys64 这是上面提到的所有工具,解压后将这个目录放在c:根目录下;另外一个 MSYS2 64Bit 里面有指向MinGW 的快捷方式,解压后放在桌面即可,后面的打开msys2 终端都是从 MSYS2 MinGW 64-Bit 运行的。

[2] Qemu-4.2.0.tar 源代码。不需要事先解压,直接放置到 c:\msys64\home目录下。

编译方法:

[1] 使用 “MSYS MinGW 64-bit”快捷方式打开 msys2 终端,然后进入 home 目录

[2] 解压 Qemu 源代码,命令是 tar xvf qemu-4.2.0.tar

[3] 在解压后的目录中创建build 目录

[4] 设置编译目标,我们只玩 X86 X64 所以目标设定为x86_64-softmmu即可。

../configure –prefix=/qemu –target-list=x86_64-softmmu  –enable-sdl –enable-tools

[5] 之后,运行 Make即可编译,相比 VirtualBox 这个快多了。

[6] 再运行  make install

[7] 可以在  c:\msys64 下面找到qemu目录,进入之后运行

[8] 可以看到虚拟机正常运行起来了

目前看起来这样的方法美中不足是编译出来的 exe 只能在 msys64 环境下运行,无法在Windows下面直接运行。

下载链接  https://pan.baidu.com/s/1Zgkl4uORtMDEkHrT2LP2Sw 密码:98yu

Leonardo改装为USB读卡器

前面介绍了如何用 Leonardo 实现SD卡的读写,这次介绍如何实现将其改装为 USB SD 卡读卡器。

经过搜索在 http://elasticsheep.com/2010/04/teensy2-usb-mass-storage-with-an-sd-card/  给出了一个代码。结合上面提到的硬件可以完成功能(CS Pin 直接接地,此外其他连接相同)。

使用 C:\WinAVR-20100110\进行编译:

C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC>cd\
C:\>cd C:\WinAVR-20100110\SDCardReader
C:\WinAVR-20100110\SDCardReader>setenv.bat
C:\WinAVR-20100110\SDCardReader>PATH=C:\WinAVR-20100110\bin;C:\WinAVR-20100110\utils\bin;C:\Windows\System32\wbem
C:\WinAVR-20100110\SDCardReader>cd "LowLevelMassStorage+SD"
C:\WinAVR-20100110\SDCardReader\LowLevelMassStorage+SD>make
-------- begin --------
avr-gcc (WinAVR 20100110) 4.3.3
Copyright (C) 2008 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.


Size before:
AVR Memory Usage
----------------
Device: atmega32u4
Program:    9094 bytes (27.8% Full)
(.text + .data + .bootloader)
Data:        712 bytes (27.8% Full)
(.data + .bss + .noinit)
Checking for invalid events...
---- Compile Time Library Options ----
USB_DEVICE_ONLY
FIXED_CONTROL_ENDPOINT_SIZE=8
FIXED_NUM_CONFIGURATIONS=1
USE_FLASH_DESCRIPTORS
USE_STATIC_OPTIONS=(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)
INTERRUPT_CONTROL_ENDPOINT
--------------------------------------
--------- Target Information ---------
AVR Model: atmega32u4
Board: USER
Clock: 16000000Hz CPU, 16000000Hz Master
--------------------------------------
Size after:
AVR Memory Usage
----------------
Device: atmega32u4

Program:    9094 bytes (27.8% Full)
(.text + .data + .bootloader)
Data:        712 bytes (27.8% Full)
(.data + .bss + .noinit)
-------- end --------

编译之后生成 MassStorage.hex 文件,我使用Arduino的上传方式进行烧写,烧写之前按下 reset  button 然后马上运行,特别注意根据你自己的实际情况选择COM,我这里是 COM7 (意思是按下 Reset 之后出现的 Bootloader 的COM号):

D:\arduino-1.8.4\hardware\tools\avr\bin\avrdude -v -Cd:\arduino-1.8.4\hardware\tools\avr\etc\avrdude.conf -patmega32u4 -cavr109 -PCOM7 -b57600 -D -V -Uflash:w:./MassStorage.hex:i

烧写之后就可以正常工作了。

写入速度

读取速度能快一点

完整的代码和Lufa 下载(根据我的测试只有特定的 Lufa版本LUFA_091223才能通过编译,所以放在一起了,另外,为了减小体积我删除了 Lufa 里面的 Demo)。

TinkerNode NB-IoT 制作看股票的工具

人类社会的进步始终伴随着通讯技术的发展。当我们谈谈及通讯相关历史时,一定会提起中国古代用于示警外族入侵的烽火。但是这种方式信息容量非常小,只能传递“入侵发生”这个信号。类似的,17世纪的法国创建了基于视觉的全国性信号传递系统,具体是通过称作“信号塔” (semaphore towers)的建筑来实现。信号的表示方法接近旗语,每个高塔通过操控机械展示出不同的形状,然后使用接力的方法将消息传递出去。

                                    

              

随着时代发展和科技进步,人类的通讯不再局限于消息的传递,而是更加注重设备之间的互联。这就是“万物互联”的概念。TinkerNode NB-IoT 是 DFRobot 最新出品的物联网开发板。物联网(The Internet of things,IoT)顾名思义,就是物与物相连的互联网。这有两层意思:第一,物联网的核心和基础仍然是互联网,是在互联网基础上的延伸和扩展的网络;第二,其用户端延伸和扩展到了任何物品与物品之间,进行信息交换和通信。窄带物联网(Narrow Band Internet of Things,NB-IoT)是物联网领域一个新兴的技术,主要用于低移动性、小数据量、对时延不敏感的连接服务,其支持低功耗设备在网络中的数据传输,因此也是一种低功耗广域网(Low Power Wide Area Network,LPWAN)通信技术。相对于被逐渐淘汰的2G通信,NB-IoT具有三大优势:

大连接:海量链接的能力,在同一基站的情况下, NB-IoT 可以比现有无线技术提供 50~100 倍的接入数。一个扇区能够支持,10 万个连接,设备成本与功耗有效降低,网络架构得到优化。

广覆盖:在同样的频段下, NB-IoT比现有的网络增益提升了 20 dB,相当于提升了 100 倍的覆盖面积。

低功耗:NB-IoT借助 PSM(Power Saving Mode,节电模式)和 eDRX(Extended Discontinuous Reception,超长非连续接收)可实现更长待机。

TinkerNode NB-IoT开发板主控芯片是 ESP32,主频:240MHz,内存达到:520KB。

因此,使用它可以方便的完成很多工作。抽烟嚼槟榔吃中药和炒股票是重要的爱国标志,这次我就要用这个板子制作一个能够随时随地显示A股大盘走势的设备。

TinkerNode NB-IoT有着强大的通讯功能,这次用到的是它的WIFI通讯功能。从原理上说:TinkerNode NB-IoT访问一个网址,取得实时的大盘数据,然后将数据显示在液晶屏幕上。

硬件方面,除了TinkerNode NB-IoT还需要一个液晶屏。最终选择的是7寸液晶屏触摸串口屏。这个屏幕的特点首先是尺寸大,分辨率更是800×480。使用串口传输内容让显示非常方便。

多介绍两句这种串口屏。传统的屏幕需要在主机端生成好内容,然后不停的将内容数据发送到屏幕上,因此对于主机和接口有较高的要求。主机需要有足够的内存存放下要显示的内容,同时接口必须足够快并且不断发送数据刷新。而串口屏没有这样的限制,只要有串口就可以实现显示操作。实现的原理是:首先通过屏幕配套的图形化界面设计软件设计界面,比如,在屏幕中央会有一个20字节的字符串需要显示。然后将生成的配置文件烧写到屏幕上。在使用的时候单片机发出“在特定的位置显示字符串”即可。比如,在这次的作品上使用界面设计软件绘制如下:

具体就在800×400 的界面上放上2个显示文本变量外加实时曲线:

其中的文本变量都有对应的地址,比如上图中的“文本变量1”属性如下:

当屏幕串口收到 A5 5A 0E 82 04 86 30 33 31 36 20 34 33 32 32 FF FF 它可以知道一共有 0x0E 个数据,命令是 0x82,访问的地址是 0x0486,后面就是要显示的ASCII。于是就将就将ASCII 显示在文本变量1的位置上。接下来将生成配置文件Copy到U盘上,插入到屏幕的USB 口上电,屏幕自动完成读取。之后就可以使用串口操作了。当然目前串口屏没有统一标准,具体操作需要查看不同厂家手册。

TinkerNode NB-IoT板子上有一组串口,这次就使用它来完成和液晶屏的通讯(实际上只用TXD 即可,因为不需要屏幕反馈数据)

整体供电使用充电宝充电,一路直接提供给液晶屏(屏幕耗电在500MA,因此无法从板子提供),另外一路提供给TinkerNode NB-IoT,直接接入到板子5V位置(实验表明当没有充电电池的时候,太阳能电池板充电输入也无法正常工作)。

代码通过HTTP访问 http://hq.sinajs.cn/list=sh000001 这个网址获得实时信息。取得结果是类似“var hq_str_sh000001="上证指数,2727.0186,2702.1296,2745.6182,2751.8964,2702.4933,0,0,252019507,281583369664,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2020-03-20,15:01:59,00,";”这样的信息。细心的朋友也可以猜到sh000001是股票信息,可以通过更换这个代码获得特定股票的实时信息。
/**
 * BasicHTTPClient.ino
 *
 *  Created on: 24.05.2015
 *
 */

#include <Arduino.h>

#include <WiFi.h>
#include <WiFiMulti.h>

#include <HTTPClient.h>

#define USE_SERIAL Serial

WiFiMulti wifiMulti;

void setup() {

    USE_SERIAL.begin(115200);
    Serial2.begin(115200);
/*
    for(uint8_t t = 4; t > 0; t--) {
        USE_SERIAL.printf("[SETUP] WAIT %d...\n", t);
        USE_SERIAL.flush();
        delay(1000);
    }
*/
    wifiMulti.addAP("YOUID", "YouPassword");

}

//"var hq_str_sh000001=\"上证指数,3001.7616,2996.7618,2968.5174,3010.0286,2968.5174,0,0,352470970,378766618968,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2020-03-11,15:12:07,00,\";";
String payload;

//
// String Parser function
// Input: Str Source String
//        Arg1 - Output start position
//        Arg2 - Output end position
void GetNoData(int number, int *start, int *stop) {
  
  int Index=0;
  *start=0;
  *stop=0;
  // Find first '"'
  while ((Index<payload.length())&&(payload[Index]!='"'))
    {Index++;}
  // if current position is not '"', this means didn't find '"'
  if (payload[Index]!='"')  {return ;}
  // Look for the number string
  while (number>0) {
    *start=Index; *stop=Index;
    while ((Index<payload.length())&&(payload[Index]!=',')) {Index++;}
    *stop=Index;  
    Index++;
    number--;
  }     
}

void loop() {
  //USE_SERIAL.print("[HTTP] begin...\n");


    // wait for WiFi connection
    if((wifiMulti.run() == WL_CONNECTED)) {

        HTTPClient http;

        USE_SERIAL.print("[HTTP] begin...\n");
        // configure traged server and url
        //http.begin("https://www.howsmyssl.com/a/check", ca); //HTTPS
        http.begin("http://hq.sinajs.cn/list=sh000001"); //HTTP

        USE_SERIAL.print("[HTTP] GET...\n");
        // start connection and send HTTP header
        int httpCode = http.GET();

        // httpCode will be negative on error
        if(httpCode > 0) {
            // HTTP header has been send and Server response header has been handled
            USE_SERIAL.printf("[HTTP] GET... code: %d\n", httpCode);

            // file found at server
            if(httpCode == HTTP_CODE_OK) {
                payload = http.getString();
                USE_SERIAL.println(payload);
                int a,b,i;
                String CurrentHi,CurrentLow;
                long v;
                
                //时间
                GetNoData(32,&a,&b);
                for (int i=a;i<b;i++) { USE_SERIAL.print(payload[i]); } USE_SERIAL.print("\n");
               
                //A5 5A 12 82 04 0b 30 33 31 36 20 32 32 3A 32 39 3A 31 32 FF FF 
                Serial2.write(0xA5);
                Serial2.write(0x5A);
                Serial2.write(3+b-a+2);
                Serial2.write(0x82);
                Serial2.write(0x04);
                Serial2.write(0x0B);  
                for (int i=a;i<b;i++) { Serial2.write(payload[i]); } 
                Serial2.write(0xFF);
                Serial2.write(0xFF);
                
                //大盘
                GetNoData(4,&a,&b);
                for ( i=a;i<b;i++) { USE_SERIAL.print(payload[i]); } USE_SERIAL.print("\n");
                //A5 5A 0E 82 04 86 30 33 31 36 20 34 33 32 32 FF FF
                Serial2.write(0xA5);
                Serial2.write(0x5A);
                Serial2.write(3+b-a+2);
                Serial2.write(0x82);
                Serial2.write(0x04);
                Serial2.write(0x86);  
                for (int i=a;i<b;i++) { Serial2.write(payload[i]); } 
                Serial2.write(0xFF);
                Serial2.write(0xFF);
                
                //大盘整数
                for ( i=a;payload[i]!='.';i++) {CurrentHi=CurrentHi+payload[i];}
                //Serial.print(CurrentHi);Serial.print("\n");
                USE_SERIAL.print(CurrentHi.toInt());USE_SERIAL.print("\n");    
                //大盘小数
                for (i=i+1;i!=b;i++) {CurrentLow=CurrentLow+payload[i];}
                //Serial.print(CurrentHi);Serial.print("\n");
                USE_SERIAL.print(CurrentLow.toInt());USE_SERIAL.print("\n");  
                v= CurrentHi.toInt()*10000+CurrentLow.toInt();
                v=(v-27500000)/1000+200;
                USE_SERIAL.print(v);  USE_SERIAL.print("\n");  
                //A5 5A 04 84 01 00 00 
                Serial2.write(0xA5);
                Serial2.write(0x5A);
                Serial2.write(4);
                Serial2.write(0x84);
                Serial2.write(0x01);
                //Serial2.write(((CurrentHi.toInt()-2600)&0xFF00)>>8);  
                //Serial2.write((CurrentHi.toInt()-2600)&0xFF);
                Serial2.write((v>>8)&0xFF);  
                Serial2.write(v&0xFF);

            }
        } else {
            USE_SERIAL.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
        }

        http.end();
    }

    delay(5000);
}

找一个纸盒,将屏幕固定在外面,因为除了供电没有其他线路,所以内部使用面包板插接即可:

工作的视频(因为这个屏幕支持触摸,所以看起来外面还有一层膜):

PowerHouse Mountain 的安装

PowerHouse Mountain 简称 PHM,是 Intel 提供的用于Debug 功耗的软件。因为这个软件会向系统中安装一些常驻软件同时调整系统设置,可能会导致账号无法登陆的问题, 因此个人不建议在工作机上安装。建议安装到一台专用机器上,或者安装在虚拟机中用于查看的Log。

  1. 运行安装文件

   2.建议使用默认路径

3.特别注意,建议勾选在桌面上创建快捷方式,默认不创建快捷方式(如果测试PSR 屏幕,桌面图标要尽量少)

4.中间会出现 Node.js 安装提示,选择 Next 继续

5.提示是否安装其他工具,我一般不会勾选(默认不勾选),因为没有必要

5.等待,很快即可完成安装

6.运行之后最上方有 Home (主界面)/ Collector (测试收集Log)/ Open Trace (查看抓取的日志)

注意:如果你打开之后无法看到下面红色方框中的选项那么说明安装有问题。原因不明,解决方法是重新安装 PHM 甚至重新安装系统。

7.现在就可以进行手工测试了,但是我并不推荐手工测试(Manual),因为比较麻烦需要手工唤醒等等,其他人复制现象的时候也会非常麻烦。因此,还请安装 WDTF。在没有安装之前  ModernStandby 是无法勾选的。

7.1 WDTF 的安装:找到和你 Windows 版本对应的 WDK (不同版本 WDK 之间会有差别)

7.2 打开之后进入 Shell,运行如下命令

8.至此,PHM 的安装已经完成,可以通过勾选上方的ModernStandby进行测试,其他参数不需要修改,保持默认即可。第一次运行会出现要求重启的提示,根据要求重新启动系统再次运行 PHM 即可。在测试期间,建议拔掉全部USB设备避免干扰。测试是自动的,屏幕会自动黑掉,5分钟后自动唤醒。比如,下图就是正常取得Log 后的提示:

9.之后,可以通过Open Trace 选择打开Log 文件,比如,我们需要看的就是上面路径下 Contents.phms 这文件。

10.打开后,在 Report 中,勾选 “Select Report”中的 PCH_SLP_S0B即可可以看到结果:

Windows 10 无法 Win+L锁屏

最近我的一台电脑出现 Win+ L 无法锁屏的问题。一番搜索下来有很多文章介绍在注册表中有一个控制的位置。但是我根据文章无法找到对应的位置,后来使用搜索功能在 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon 找到。

DisableLockWorkstation = 1 表示禁止锁屏功能,0 表示可以锁屏。

所以,出现同样问题时,不妨先查看上面的那个注册表位置。

一个奇怪的 Python CSV 处理问题

我需要Python处理一个类似下面的 CSV文件:

于是编写代码先尝试读取之:

import csv
with open('Datax.CSV', encoding='utf-8') as csvfile:
	reader = csv.DictReader(csvfile)
	for row in reader:
		print(row['Process Name'])

奇怪的事情发生了:我可以读取除了第一个”Time of Day”之外的所有 row 的值。当我写出来 print(row[‘Time of Day’]) 的时候会出现下面的错误:

C:\Users\Administrator\AppData\Local\Programs\Python\Python38>go2.py
Traceback (most recent call last):
  File "C:\Users\Administrator\AppData\Local\Programs\Python\Python38\go2.py", l
ine 5, in <module>
    print(row['Time of Day'])
KeyError: 'Time of Day'

测试数据文件在这里,代码在这里。有兴趣的朋友在看解释之前可以尝试自己解决一下。

接下来我各种猜测,默认是因为空格等等,都不是Root Cause。后来用代码将取得的 Key 打印一下:

惊奇的发现第一个是 ‘\ufeff”Time of Day”‘。用十六进制软件打开数据文件查看:

在文件头上有 EF BB BF ,这是CSV 文件的 Unicode 头。就是它引起了我们奇怪的问题。

知道了原因之后,可以通过尝试构造出一个相同的Key 来解决:

import csv
with open('Datax.CSV', encoding='utf-8') as csvfile:
	reader = csv.DictReader(csvfile)
	for row in reader:
		print(row["\ufeff\"Time of Day\""])

运行正常:

结论:这是因为数据文件的 Unicode 头导致的……. 话说 Python 处理数据还真是方便,虽然调试和编写耗时不短,但是代码长度大大出乎我的意料。