Step to UEFI (292)Cpp UEFI 008 This 是啥

这一系列文章的目标是让人看懂C++ 代码,因此很多地方知道意思即可。这次介绍的是 “this” 这个关键字。这是一个指向当前对象的 const 指针,通过它可以访问当前对象的所有成员。更简单的描述如下【参考1】:

一.this是什么

this 是 C++ 中的一个关键字

this是一个 const 指针

this 指针是所有成员函数的隐含参数

二、this可以用在哪

this 只能用在类的内部

this可用于调用类的成员函数和成员变量

三、this可以用来做什么

它指向当前对象,通过它可以访问当前对象的所有成员(包括 private、protected、public 属性的成员)

友元函数没有 this 指针,因为友元不是类的成员。只有成员函数才有 this 指针。

参考:

1. https://blog.csdn.net/LiuXF93/article/details/121466530

C# 判断字符串是否为空或者空格的函数

在C#中,判断一个字符串是否仅由一个或多个空格组成可以通过String.IsNullOrWhiteSpace方法来实现。这个方法在检查字符串时会考虑空格、制表符、换行符等空白字符,如果字符串为null、空字符串(“”),或者仅包含空白字符,则返回true

using System;

class Program
{
    static void Main()
    {
        // 示例字符串
        string singleSpace = " ";
        string multipleSpaces = "   ";
        string emptyString = "";
        string nullString = null;

        // 判断字符串是否为空或仅包含空白字符
        bool isSingleSpaceEmpty = String.IsNullOrWhiteSpace(singleSpace);
        bool isMultipleSpacesEmpty = String.IsNullOrWhiteSpace(multipleSpaces);
        bool isEmptyStringEmpty = String.IsNullOrWhiteSpace(emptyString);
        bool isNullStringEmpty = String.IsNullOrWhiteSpace(nullString);

        // 输出结果
        Console.WriteLine($"单个空格字符串是否为空或仅包含空白字符: {isSingleSpaceEmpty}");
        Console.WriteLine($"多个空格字符串是否为空或仅包含空白字符: {isMultipleSpacesEmpty}");
        Console.WriteLine($"空字符串是否为空或仅包含空白字符: {isEmptyStringEmpty}");
        Console.WriteLine($"null字符串是否为空或仅包含空白字符: {isNullStringEmpty}");
    }
}

测试0x3F8 串口输出的 UEFI Application

之前的文章【参考1】介绍过,初始化 Legacy COM Port 为 115200 的方法。这次编写一个 UEFI Shell Application,初始化这个 COM port 之后输出 www.lab-z.com字符。

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

void init_serial(UINTN Port) {
	IoWrite8(Port + 1, 0x00); // Disable all interrupts
	IoWrite8(Port + 3, 0x80); // Enable DLAB (set baud rate divisor)
	IoWrite8(Port + 0, 0x01); // Set divisor to 1 (lo byte) 115200 baud
	IoWrite8(Port + 1, 0x00); // (hi byte)
	IoWrite8(Port + 3, 0x03); // 8 bits, no parity, one stop bit
	IoWrite8(Port + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold
	IoWrite8(Port + 4, 0x0B); // IRQs enabled, RTS/DSR set
}

INTN
EFIAPI
ShellAppMain (
  IN UINTN Argc,
  IN CHAR16 **Argv
  )
{
	CHAR8 TestString[]="www.lab-z.com";
	init_serial(0x3F8);
	for (UINTN i=0;i<sizeof(TestString);i++) {
		IoWrite8(0x3F8,TestString[i]);
	}
	return(0);
}

虽然有很多BIOS 的调试方法,但是BIOS 工程师最常见的方法仍然是串口输出 Log,唯一的原因是:足够简单和直接。用户无需为了调试BIOS而去调试工具。

源代码和编译后的 EFI Application:

参考:

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

推荐一个开源的HTTP Server

有些时候我们需要进行一些带有JavaScript的网页测试,为了保证能够可靠的运行,推荐架设一个的 HTTP Server 然后通过浏览器进行测试。这推荐一个开源简单的命令行 HTTP Server:simple-http-server,项目地址是https://github.com/TheWaWaR/simple-http-server/

项目支持多种 OS:

对于我们来说,最简单的是 Windows 版本的。

具体的命令行参数如下:

Simple HTTP(s) Server 0.6.8

USAGE:
    x86_64-pc-windows-msvc-simple-http-server.exe [FLAGS] [OPTIONS] [--] [root]

FLAGS:
        --coep       Add "Cross-Origin-Embedder-Policy" HTTP header and set it to "require-corp"
        --coop       Add "Cross-Origin-Opener-Policy" HTTP header and set it to "same-origin"
        --cors       Enable CORS via the "Access-Control-Allow-Origin" header
    -h, --help       Prints help information
    -i, --index      Enable automatic render index page [index.html, index.htm]
        --nocache    Disable http cache
        --norange    Disable header::Range support (partial request)
        --nosort     Disable directory entries sort (by: name, modified, size)
    -o, --open       Open the page in the default browser
    -s, --silent     Disable all outputs
    -u, --upload     Enable upload files. (multiple select) (CSRF token required)
    -V, --version    Prints version information

OPTIONS:
    -a, --auth &lt;auth>                HTTP Basic Auth (username:password)
        --cert &lt;cert>                TLS/SSL certificate (pkcs#12 format)
        --certpass &lt;certpass>        TLS/SSL certificate password
    -c, --compress &lt;compress>...     Enable file compression: gzip/deflate
                                         Example: -c=js,d.ts
                                         Note: disabled on partial request!
        --ip &lt;ip>                    IP address to bind [default: 0.0.0.0]
    -p, --port &lt;port>                Port number [default: 8000]
        --redirect &lt;redirect>        takes a URL to redirect to using HTTP 301 Moved Permanently
    -t, --threads &lt;threads>          How many worker threads [default: 3]
        --try-file &lt;PATH>            serve this file (server root relative) in place of missing files (useful for single
                                     page apps) [aliases: try-file-404]
    -l, --upload-size-limit &lt;NUM>    Upload file size limit [bytes] [default: 8000000]

ARGS:
&lt;root>    Root directory

比较常用的参数有如下几个:

–ip :指定绑定的IP 地址

-p : 指定绑定的端口号

例如:首先使用 ipconfig 查看你当前的 ip,接下来指定绑定信息

然后通过浏览器直接访问这个IP 即可(80 Port是 HTTP 默认端口,如果指定其他端口,访问时还需要写成  IP:端口 的形式)

如果你需要打开后直接访问 index.html文件还可以使用 -i 参数打开 index。推荐有需要的朋友直接去项目地址下载。如果无法访问可以直接使用下面这个版本:

修改 Win11 鼠标右键菜单的方法

Windows 11 中修改了鼠标右键菜单,我们经常需要选择“Show more options”才能找到我们需要的功能。本文介绍如何修改为之前的菜单。

管理员权限使用如下命令即可修改为老式右键菜单风格:

reg.exe add "HKCU\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}\InprocServer32" /f /ve

之后还可以使用如下命令恢复:

reg.exe delete "HKCU\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}" /f

修改之后需要重启才能生效,或者使用如下命令重启Explorer:

taskkill /f /im explorer.exe &amp; start explorer.exe

编写两个批处理方便使用(密码 labz):

参考:

1.https://answers.microsoft.com/en-us/windows/forum/all/restore-old-right-click-context-menu-in-windows-11/a62e797c-eaf3-411b-aeec-e460e6e5a82a

2.有没有什么办法可以让win11右键默认显示更多选项? – 知乎 (zhihu.com)

一种 WinDBG 无法使用的解决方法

之前偶然发现很多机器无法使用 WinDBG + USB 3.0 Cable 进行调试。最近花了一点时间仔细研究这个问题。

我遇到的现象是:USB 3.0 调试线连接之后设备管理器中有时候没有新设备出现,有时候出现Yellow Bang ,提示 Port Reset 失败。

经过研究这个问题是我的被调试系统(DUT)中存在多个 XHCI,解决方法是需要指定一个 XHCI 作为被调试目标。在 DUT 中管理员权限打开一个 CMD 窗口,然后输入如下命令:

bcdedit /set “{dbgsettings}” busparams 0.20.0

其中 0.20.0 是Bus:0 Device:20 Func:0 的意思,Intel 芯片组上对应着 XHCI 控制器。解析来工作机上的设备管理器中就会出现 “USB Debug Connection Device”,接下来就可以使用 WinDBG 进行工作了。

参考:

1.https://zhuanlan.zhihu.com/p/405683773 用USB 3.0 + WinDbg开始你的调试之旅

2.https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/bcdedit–dbgsettings BCDEdit /dbgsettings

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

2025年3月 有兴趣的朋友可以查看这篇文章《Windows Hypervisor&内核调试的几种常见/不常见方法》 https://research.qianxin.com/archives/1876

3分钟看懂“打羽毛球因流浪猫绊倒致伤残,投喂者被判赔24万元”

(写这篇文章是因为看新闻看的恼火,那么多人包括律师就没有人直接引用原始文档看看判决究竟讲的是什么。都在强调“爱心”或者“道德退步”等等)。忍不住自己去查了一下。

这个事情是因为裁判文书网的公开所以被众人所知的,因此如果想知道发生了什么,需要去看原始的文档。

https://wenshu.court.gov.cn/website/wenshu/181107ANFZ0BXSK4/index.html?docId=nsblavzcFEjwf6iUEPJ3BF5Orla4JPs5WzfeZDnfDu6BbLO4nWpCUZO3qNaLMqsJlcEe6S1vNd6naPGooBXPL2d+lrXF7ZQmiXrSLaaivhjZLPMDuMaeltLqLP8VI69c

大概内容如下:

原告是吴某,被告一个是提供羽毛球场地的公司,还有肖某。第一次庭审两个被告都来了,第二次开庭只有被告的公司来了,肖某没来(传唤无正当理由不到庭)。

事情简单的说是2023年4月20日,原告吴某和同事一起被告公司经营羽毛球馆打羽毛球。原告吴某在后场准备跳起接球扣杀,落地时右脚踩到了猫肚子上,致摔倒受伤。后至医院治疗,诊断为右双踝骨折和右腓骨干骨折。经鉴定,原告构成十级伤残。然后要求承担提供场地的公司和被告肖某承担责任负责赔偿。

要求承担提供场地的公司承担责任可以理解,他们有必要承担安全责任。但是被告肖某的责任让人有争议。

被告肖某自己说事发当日自己不在场,原告证据不能证明受伤和猫有关系,所述的猫也不能证明是被告肖某饲养的。

接下来就是法院的认定了。确定原告吴某打球受伤了,产生费用。确认被告肖某是当时被告公司的员工。然后聊天记录显示“这个猫是球馆一个工作人员看着可怜,收养的流浪猫,不是球馆的”。然后聊天记录还有一些证明是因为猫导致的受伤。

接下来和被告肖某电话通话录音中,肖某表示“这个猫是我养的,球馆不理我这个事情……”

再接下来公司有人证明被告肖某收养流浪猫。肖某会喂猫,还为猫起了个名字叫“土豆”,猫的喂养等都由肖某料理,他还带猫去宠物医院洗澡、看病。

最后判决:

一、被告肖某于本判决生效之日起十日内赔偿原告吴某1医疗费46,550.20元、住院伙食补助费430元、营养费4,200元、护理费6,300元、残疾赔偿金168,068元、精神抚慰金5,000元、交通费800元、鉴定费2,850元、律师费6,000元,共计240,198.20元;

二、被告某某公司于本判决生效之日起十日内对上述第一项被告肖某不能赔偿的部分,承担补充赔偿责任。被告某某公司承担补充责任后,可以向被告肖某追偿。

简单的说就是羽毛球馆有人收留了流浪猫,喂养、起名、带洗澡看病,然后这个猫闯祸了。这个人不出庭不承认自己收留了猫。很明显有人受伤和收留流浪猫有直接关系,因此这样的判决就不难理解了。

当然最后最重要的是附上原始文档:

C# 实现计算函数耗时的方法

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
using System.Threading;

namespace ConsoleApp9
{
    class Program
    {
        
        static void Main(string[] args)
        {
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();
            // 让线程暂停5秒(5000毫秒)
            Thread.Sleep(5000);
            stopwatch.Stop();
            // 获取运行时间
            TimeSpan ts = stopwatch.Elapsed;
            // 格式化并显示时间
            string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
                ts.Hours, ts.Minutes, ts.Seconds,
                ts.Milliseconds / 10);
            Console.WriteLine("Time: " + elapsedTime);
            Console.ReadLine();
        }
    }
}

Step to UEFI (291)Cpp UEFI 007 类

C++ 的类可以看作是一种特别的数据类型。基本的结构如下:

Class 类名 {
Private:
   XXXX //公有成员
Public:
  YYYY://私有成员
Protected:
 ZZZZ://保护成员
}

Public 成员相当于 Struct 结构体定义的,可以用 a.x 这种形式访问(public访问权限是全局的);

Private 成员不能直接被类的实体访问,也不能被子类的实体访问,但是可以被类的成员函数访问(private访问权限就是对内不设防,对外设防的);

Protected 成员不能被类的实体访问,但是可以被子类访问,也可以被类的成员函数访问(protected访问权限就是对内不受保护,对外受保护的)

这样设计的目的是:

1、访问权限作用,保护内部资源

(1)private的成员是class内部使用,外部没必要直接访问(读取或赋值),所以干脆在语法上让你看不见

(2)访问权限的保护是一种语法层面的保护,而非硬件上限制访问,硬件做不了这么细致

(3)最终目的也是为了整个程序更安全

2、访问权限作用, 隐藏外部无需关心的细节

(1)将class内部使用而外部绝不会用到的成员变量隐藏起来,以免干扰外部或者不小心被外部修改了

(2)隐藏细节可以降低使用类库的人的难度,调用时只看到对我有用的东西

(3)这个隐藏其实是把class的作者和使用者专业分工,是很有必要的

3、这就是面向对象的封装特性

(1)封装特性的体现之一就是抽象,抽象的一层意思就是隐藏掉不必要的细节

(2)封装特性的体现之一就是组织和保护,便于整个整体和外部更合理的交流

参考:

  1. https://c.biancheng.net/view/2217.html C++类成员的访问权限以及类的封装
  2. https://blog.csdn.net/weixin_39270987/article/details/108669956 C++类详解(public、private、protected)
  3. https://blog.csdn.net/qq_45544223/article/details/107043760 【C++的面向对象】——- 类成员的访问权限

Rapoo V820 VS2019 控制 LED 的代码

Rapoo(雷柏) V820是一款游戏机械键盘,采用雷柏自主机械轴,双色注塑键帽,5个独立游戏G键,全尺寸一体式掌托,USB口109键无冲突,109键可编程,12种背光模式,加厚金属上盖。

它自带了一个颜色控制的程序,经过研究总结出了它的控制方法。使用 USBLyzer 抓取它设置的动作发现应用程序会对设备发送几个 Package。

经过多次实验,确定了2个 Pacakge 是必须的,发送之后键盘会改变LED颜色。第一个是下面代码中的cmdBuffer定义的,第二个是LedBuffer中定义的,所有颜色信息都是通过这个提供给键盘的。LedBuffer[8] 开始是按键的Blue;LedBuffer[140]开始是按键的 Red取值;LedBuffer[272] 开始为 Green 取值。

按键偏移总结如下:

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

#include "hidapi.h"


int Asc2KeyLEDOffset(char asc) {
	int KeyOffset;
	switch (asc) {
	case '~':
	case '`':
		KeyOffset = 30;
		break;
	case '!':
	case '1':
		KeyOffset = 31;
		break;
	case '@':
	case '2':
		KeyOffset = 32;
		break;
	case '#':
	case '3':
		KeyOffset = 33;
		break;
	case '$':
	case '4':
		KeyOffset = 34;
		break;
	case '%':
	case '5':
		KeyOffset = 35;
		break;
	case '^':
	case '6':
		KeyOffset = 36;
		break;
	case '&':
	case '7':
		KeyOffset = 37;
		break;
	case '*':
	case '8':
		KeyOffset = 38;
		break;
	case '(':
	case '9':
		KeyOffset = 39;
		break;
	case ')':
	case '0':
		KeyOffset = 40;
		break;
	case '_':
	case '-':
		KeyOffset = 41;
		break;
	case '+':
	case '=':
		KeyOffset = 42;
		break;
	case 'Q':
	case 'q':
		KeyOffset = 53;
		break;
	case 'W':
	case 'w':
		KeyOffset = 54;
		break;
	case 'E':
	case 'e':
		KeyOffset = 55;
		break;
	case 'R':
	case 'r':
		KeyOffset = 56;
		break;
	case 'T':
	case 't':
		KeyOffset = 57;
		break;
	case 'Y':
	case 'y':
		KeyOffset = 58;
		break;
	case 'U':
	case 'u':
		KeyOffset = 59;
		break;
	case 'I':
	case 'i':
		KeyOffset = 60;
		break;
	case 'O':
	case 'o':
		KeyOffset = 61;
		break;
	case 'P':
	case 'p':
		KeyOffset = 62;
		break;
	case '{':
	case '[':
		KeyOffset = 63;
		break;
	case '}':
	case ']':
		KeyOffset = 64;
		break;
	case '|':
	case '\\':
		KeyOffset = 65;
		break;
	case 'A':
	case 'a':
		KeyOffset = 75;
		break;
	case 'S':
	case 's':
		KeyOffset = 76;
		break;
	case 'D':
	case 'd':
		KeyOffset = 77;
		break;
	case 'F':
	case 'f':
		KeyOffset = 78;
		break;
	case 'G':
	case 'g':
		KeyOffset = 79;
		break;
	case 'H':
	case 'h':
		KeyOffset = 80;
		break;
	case 'J':
	case 'j':
		KeyOffset = 81;
		break;
	case 'K':
	case 'k':
		KeyOffset = 82;
		break;
	case 'L':
	case 'l':
		KeyOffset = 83;
		break;
	case ':':
	case ';':
		KeyOffset = 84;
		break;
	case '"':
	case '\'':
		KeyOffset = 85;
		break;
	case 'Z':
	case 'z':
		KeyOffset = 98;
		break;
	case 'X':
	case 'x':
		KeyOffset = 99;
		break;
	case 'C':
	case 'c':
		KeyOffset = 100;
		break;
	case 'V':
	case 'v':
		KeyOffset = 101;
		break;
	case 'B':
	case 'b':
		KeyOffset = 102;
		break;
	case 'N':
	case 'n':
		KeyOffset = 103;
		break;
	case 'M':
	case 'm':
		KeyOffset = 104;
		break;
	case '<':
	case ',':
		KeyOffset = 105;
		break;
	case '>':
	case '.':
		KeyOffset = 106;
		break;
	case '?':
	case '/':
		KeyOffset = 107;
		break;
	case ' ':
		KeyOffset = 123;
		break;

	default:
		KeyOffset = 0;
		break;
	}
	return KeyOffset;
}

//#pragma comment (lib,"setupapi.lib")//hidapi所需的lib环境,没有此文件会导致链接错误

// Headers needed for sleeping.
#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h>
#endif

// Fallback/example
#ifndef HID_API_MAKE_VERSION
#define HID_API_MAKE_VERSION(mj, mn, p) (((mj) << 24) | ((mn) << 8) | (p))
#endif
#ifndef HID_API_VERSION
#define HID_API_VERSION HID_API_MAKE_VERSION(HID_API_VERSION_MAJOR, HID_API_VERSION_MINOR, HID_API_VERSION_PATCH)
#endif

//
// Sample using platform-specific headers
#if defined(__APPLE__) && HID_API_VERSION >= HID_API_MAKE_VERSION(0, 12, 0)
#include <hidapi_darwin.h>
#endif

#if defined(_WIN32) && HID_API_VERSION >= HID_API_MAKE_VERSION(0, 12, 0)
#include "hidapi_winapi.h"
#endif

#if defined(USING_HIDAPI_LIBUSB) && HID_API_VERSION >= HID_API_MAKE_VERSION(0, 12, 0)
#include <hidapi_libusb.h>
#endif
//

int res;

unsigned char cmdBuffer[5] = { 0x05, 0x83, 0x00,  0x00, 0x00 };

unsigned char LedBuffer[1032] = {
0x06, 0x09, 0xac, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

const char* hid_bus_name(hid_bus_type bus_type) {
	static const char* const HidBusTypeName[] = {
		"Unknown",
		"USB",
		"Bluetooth",
		"I2C",
		"SPI",
	};

	if ((int)bus_type < 0)
		bus_type = HID_API_BUS_UNKNOWN;
	if ((int)bus_type >= (int)(sizeof(HidBusTypeName) / sizeof(HidBusTypeName[0])))
		bus_type = HID_API_BUS_UNKNOWN;

	return HidBusTypeName[bus_type];
}

void print_device(struct hid_device_info* cur_dev) {
	printf("Device Found\n  type: %04hx %04hx\n  path: %s\n  serial_number: %ls", cur_dev->vendor_id, cur_dev->product_id, cur_dev->path, cur_dev->serial_number);
	printf("\n");
	printf("  Manufacturer: %ls\n", cur_dev->manufacturer_string);
	printf("  Product:      %ls\n", cur_dev->product_string);
	printf("  Release:      %hx\n", cur_dev->release_number);
	printf("  Interface:    %d\n", cur_dev->interface_number);
	printf("  Usage (page): 0x%hx (0x%hx)\n", cur_dev->usage, cur_dev->usage_page);
	printf("  Bus type: %d (%s)\n", cur_dev->bus_type, hid_bus_name(cur_dev->bus_type));
	printf("\n");
}

void print_hid_report_descriptor_from_device(hid_device* device) {
	unsigned char descriptor[HID_API_MAX_REPORT_DESCRIPTOR_SIZE];
	int res = 0;

	printf("  Report Descriptor: ");
	res = hid_get_report_descriptor(device, descriptor, sizeof(descriptor));
	if (res < 0) {
		printf("error getting: %ls", hid_error(device));
	}
	else {
		printf("(%d bytes)", res);
	}
	for (int i = 0; i < res; i++) {
		if (i % 10 == 0) {
			printf("\n");
		}
		printf("0x%02x, ", descriptor[i]);
	}
	printf("\n");
}

void print_hid_report_descriptor_from_path(const char* path) {
	hid_device* device = hid_open_path(path);
	if (device) {
		print_hid_report_descriptor_from_device(device);
		hid_close(device);
	}
	else {
		printf("  Report Descriptor: Unable to open device by path\n");
	}
}

void print_devices(struct hid_device_info* cur_dev) {
	for (; cur_dev; cur_dev = cur_dev->next) {
		print_device(cur_dev);
	}
}

hid_device* Handle05 = NULL;
hid_device* Handle06 = NULL;

void print_devices_with_descriptor(struct hid_device_info* cur_dev) {
	for (; cur_dev; cur_dev = cur_dev->next) {
		if (cur_dev->vendor_id == 0x24ae) {
			if ((strstr(cur_dev->path, "Col05") != NULL) || (strstr(cur_dev->path, "Col06") != NULL)) {
				print_device(cur_dev);
				print_hid_report_descriptor_from_path(cur_dev->path);

				if (strstr(cur_dev->path, "Col05") != NULL) {
					Handle05 = hid_open_path(cur_dev->path);
					if (!Handle05) {
						printf("unable to open device\n");
						system("pause");
						hid_exit();
						return;
					}
				}
				if (strstr(cur_dev->path, "Col06") != NULL) {
					Handle06 = hid_open_path(cur_dev->path);
					if (!Handle06) {
						printf("unable to open device\n");
						system("pause");
						hid_exit();
						return;
					}
				}



			}

		}
	}
}

void LightAKey(hid_device* Handle1, hid_device* Handle2, char c, UINT8 value)
{
	res = hid_send_feature_report(Handle1, cmdBuffer, 5);
	if (res < 0) {
		printf("Unable to write() Handle05: %ls\n", hid_error(Handle1));
	}
	LedBuffer[Asc2KeyLEDOffset(c)] = value;
	res = hid_send_feature_report(Handle2, LedBuffer, sizeof(LedBuffer));
	if (res < 0) {
		printf("Unable to write(): %ls Handle06\n", hid_error(Handle2));
	}

}
int main(int argc, char* argv[])
{
	(void)argc;
	(void)argv;

	struct hid_device_info* devs;

	printf("hidapi test/example tool. Compiled with hidapi version %s, runtime version %s.\n", HID_API_VERSION_STR, hid_version_str());
	if (HID_API_VERSION == HID_API_MAKE_VERSION(hid_version()->major, hid_version()->minor, hid_version()->patch)) {
		printf("Compile-time version matches runtime version of hidapi.\n\n");
	}
	else {
		printf("Compile-time version is different than runtime version of hidapi.\n]n");
	}

	if (hid_init())
		return -1;

#if defined(__APPLE__) && HID_API_VERSION >= HID_API_MAKE_VERSION(0, 12, 0)
	// To work properly needs to be called before hid_open/hid_open_path after hid_init.
	// Best/recommended option - call it right after hid_init.
	hid_darwin_set_open_exclusive(0);
#endif

	devs = hid_enumerate(0x0, 0x0);

	print_devices_with_descriptor(devs);
	hid_free_enumeration(devs);

	/*
	res = hid_send_feature_report(Handle05, cmdBuffer, 5);
	if (res < 0) {
		printf("Unable to write() Handle05: %ls\n", hid_error(Handle05));
	}
	LedBuffer[Asc2KeyLEDOffset('a')] = 200;
	res = hid_send_feature_report(Handle06, LedBuffer, sizeof(LedBuffer));
	if (res < 0) {
		printf("Unable to write(): %ls Handle06\n", hid_error(Handle06));
	}
	system("pause");
	*/

	LightAKey(Handle05, Handle06, 'l', 200);
	Sleep(800);
	LightAKey(Handle05, Handle06, 'a', 200);
	Sleep(800);
	LightAKey(Handle05, Handle06, 'b', 200);
	Sleep(800);
	LightAKey(Handle05, Handle06, '-', 200);
	Sleep(800);
	LightAKey(Handle05, Handle06, 'z', 200);
	Sleep(800);
	LightAKey(Handle05, Handle06, '.', 200);
	Sleep(800);
	LightAKey(Handle05, Handle06, 'c', 200);
	Sleep(800);
	LightAKey(Handle05, Handle06, 'o', 200);
	Sleep(800);
	LightAKey(Handle05, Handle06, 'm', 200);
	Sleep(800);

	LightAKey(Handle05, Handle06, 'm', 0);
	Sleep(800);
	LightAKey(Handle05, Handle06, 'o', 0);
	Sleep(800);
	LightAKey(Handle05, Handle06, 'c', 0);
	Sleep(800);
	LightAKey(Handle05, Handle06, '.', 0);
	Sleep(800);
	LightAKey(Handle05, Handle06, 'z', 0);
	Sleep(800);
	LightAKey(Handle05, Handle06, '-', 0);
	Sleep(800);
	LightAKey(Handle05, Handle06, 'b', 0);
	Sleep(800);
	LightAKey(Handle05, Handle06, 'a', 0);
	Sleep(800);
	LightAKey(Handle05, Handle06, 'l', 0);

	hid_close(Handle05);
	hid_close(Handle06);





	/* Free static HIDAPI objects. */
	hid_exit();
	 
#ifdef _WIN32
	system("pause");
#endif

	return 0;
}