杰理AC632N实现custom hid

news/2025/2/5 4:46:57/

1. 设备描述符修改

设备描述符主要修改的是PID、VID、设备发现版本号以及字符串描述。

static const u8 sDeviceDescriptor[] = { //<Device DescriptorUSB_DT_DEVICE_SIZE,      // bLength: Size of descriptorUSB_DT_DEVICE,       // bDescriptorType: Device
#if defined(FUSB_MODE) && FUSB_MODE0x10, 0x01,     // bcdUSB: USB 1.1
#elif defined(FUSB_MODE) && (FUSB_MODE ==0 )0x00, 0x02,     // bcdUSB: USB 2.0
#else
#error "USB_SPEED_MODE not defined"
#endif0x00,       // bDeviceClass: none0x00,       // bDeviceSubClass: none0x00,       // bDeviceProtocol: noneEP0_SETUP_LEN,//EP0_LEN,      // bMaxPacketSize0: 8/64 bytes'Y', 'D',     // idVendor: 59 44 - YD,电脑上小端格式显示为0x4459'Z', 'L',     // idProduct: 5a 4c - ZL,电脑上小端格式显示为0x4c5a0x00, 0x01,     // bcdDevice: version 1.00x01,       // iManufacturer: Index to string descriptor that contains the string <Your Name> in Unicode0x02,       // iProduct: Index to string descriptor that contains the string <Your Product Name> in Unicode0x00,       // iSerialNumber: none//usb设备序列号0x01        // bNumConfigurations: 1
};

iManufacturer和iProduct如果不想用可以全部填0x00,这样主机不会去请求字符串描述符。

  • Manufacturer string

static const u8 product_string[] = {38,			//该描述符的长度为38字节,全部长度,含长度和类型字段0x03,		//字符串描述符的类型编码为0x03'U', 0x00,'S', 0x00,'B', 0x00,' ', 0x00,'B', 0x00,'L', 0x00,'E', 0x00,'_', 0x00,'N', 0x00,'F', 0x00,'C', 0x00,' ', 0x00,'W', 0x00,'r', 0x00,'i', 0x00,'t', 0x00,'e', 0x00,'r', 0x00,
};
  • iProduc string
static const u8 MANUFACTURE_STR[] = {38,         //该描述符的长度为38字节,全部长度,含长度和类型字段0x03,       //字符串描述符的类型编码为0x030x59, 0x00, //Y0x75, 0x00, //u0x61, 0x00, //a0x6e, 0x00, //n0x44, 0x00, //D'o', 0x00, //o'u', 0x00, //u0x20, 0x00, //0x54, 0x00, //T0x65, 0x00, //e0x63, 0x00, //c0x68, 0x00, //h0x6e, 0x00, //n0x6f, 0x00, //o0x6c, 0x00, //l0x6f, 0x00, //o0x67, 0x00, //g0x79, 0x00, //y
};

2. 配置描述符修改

配置描述符保留原样,不做修改。当然,也可以自己修改是否支持唤醒和供电电流最大限值等。

static const u8 sConfigDescriptor[] = {	//<Config Descriptor
//ConfiguraTIonUSB_DT_CONFIG_SIZE,    //bLengthUSB_DT_CONFIG,    //DescriptorType : ConfigDescriptor0, 0, //TotalLength0,//bNumInterfaces: 在set_descriptor函数里面计算0x01,    //bConfigurationValue - ID of this configuration0x00,    //Unused
#if USB_ROOT2 || USB_SUSPEND_RESUME || USB_SUSPEND_RESUME_SYSTEM_NO_SLEEP0xA0,    //Attributes:Bus Power remotewakeup
#else0x80,    //Attributes:Bus Power
#endif50,     //MaxPower * 2ma
};

3. 接口描述符、HID类描述符、端点描述符修改

  • 接口描述符里设置接口编号、端点数量和USB设备类别为HID类。
  • HID类描述符主要设置了HID协议版本号,以及下级描述符得数量为1个,类型为报表描述符、报表描述符的长度值
  • 端点描述符描述了一个输入端点0x84,一个输出端点0x04。输入端点用于设备向主机上传数据,输出端点用于主机向设备下传数据。传输方式均设置为中断传输。注意,如果不配置输出端点,会默认走控制传输通道默认端点0。

接口描述符、HID类描述符、端点描述符一般是与配置描述符一起被主机请求的。

static const u8 sHIDDescriptor[] = {
//HID//InterfaceDeszcriptor:USB_DT_INTERFACE_SIZE,     // LengthUSB_DT_INTERFACE,          // DescriptorType,接口描述符0x00,                       // bInterface number,接口编号为00x00,                      // AlternateSetting,无备用接口描述符0x02,                      // NumEndpoint,端点2个USB_CLASS_HID,             // Class = Human Interface Device0x00,                      // Subclass, 0 No subclass, 1 Boot Interface subclass0x00,                      // Procotol, 0 None, 1 Keyboard, 2 Mouse0x00,                      // Interface Name,字符串描述符里无接口说明//HIDDescriptor:0x09,                      // bLengthUSB_HID_DT_HID,            // bDescriptorType, HID Descriptor0x10, 0x01,                // bcdHID, HID Class Specification release NO.HID协议版本V1.10x00,                      // bCuntryCode, Country localization (=none)0x01,                       // bNumDescriptors, Number of descriptors to follow//下一级描述符数量0x22,                       // bDescriptorType, Report Desc. 0x22, Physical Desc. 0x23//下一级描述符类型:报表描述符sizeof(sHIDReportDesc), 0,  // wDescriptorLength//下一级的报表描述符长度//EndpointDescriptor:USB_DT_ENDPOINT_SIZE,       // bLength,长度:9bytesUSB_DT_ENDPOINT,            // bDescriptorType, Type,类型:端点描述符USB_DIR_IN | CUSTOM_HID_EP_IN,     // bEndpointAddress,设备上传端点地址,0x84USB_ENDPOINT_XFER_INT,      // Interrupt,传输类型:中断LOBYTE(MAXP_SIZE_CUSTOM_HIDIN), HIBYTE(MAXP_SIZE_CUSTOM_HIDIN),// Maximum packet size,端点一次最大传输字节数:64bytes0x01,                       // bInterval, for high speed 2^(n-1) * 125us, for full/low speed n * 1ms,主机1ms从端点取一次数据//Endpoint Descriptor:USB_DT_ENDPOINT_SIZE,       // bLengthUSB_DT_ENDPOINT,            // bDescriptorType, Type,类型:端点描述符CUSTOM_HID_EP_OUT,   // bEndpointAddress,主机下传端点地址,0x04USB_ENDPOINT_XFER_INT,      // Interrupt,传输类型:中断LOBYTE(MAXP_SIZE_CUSTOM_HIDOUT), HIBYTE(MAXP_SIZE_CUSTOM_HIDOUT),// Maximum packet size,,端点一次最大传输字节数:64bytes0x01,                       // bInterval, for high speed 2^(n-1) * 125us, for full/low speed n * 1ms,主机向端点写入数据间隔为1ms
};

4. 报表描述符修改

对HID设备来说,报表描述符是最关键的。它定义了数据格式和意义,主机必须遵守报表的规则,下发数据给设备和解析设备上传的数据。
这里简单写了一个自定义的报表描述符,主要功能是进行数据通讯。因此LOGICAL_MINIMUM是0,LOGICAL_MAXIMUM是255。

  • LOGICAL_MAXIMUM

注意LOGICAL_MAXIMUM不能写作0x25, 0xFF,必须写成0x26, 0xFF, 0x00。
因为最高位是表示符号,如果用0x25, 0xFF,那是一个负数了。为了保证为正数,大于127(0x7F)的数,必须进位,255(0xFF)应该表示为0x00FF。因为多加了1个字节,所以0x25要改成0x26。

  • REPORT_SIZE
    设为0x08,即一个字节。

  • REPORT_COUNT
    设为0x20,即规定一个完整的报表应传输32bytes。如果不足这个数量,数据留在驱动层不会报到应用层。实际测试HID调试助手是把不足的字节自动补0了,凑齐了再发送。REPORT_COUNT具体数值可以根据实际应用需求来设置。

//自定义hid报表描述符----custom hid
static const u8 sHIDReportDesc[] = {0x06, 0x00, 0xFF,           //USAGE_PAGE (Vendor Defined Page 1)0x09, 0x00,                 //USAGE (Undefined)0xA1, 0x01,                 //COLLECTION (Application)//开一个集合0x09, 0x00,             //USAGE (Undefined)0x15, 0x00,             //LOGICAL_MINIMUM (0)0x26, 0xFF, 0x00,       //LOGICAL_MAXIMUM (255)0x75, 0x08,             //REPORT_SIZE (8)0x95, 0x20,             //REPORT_COUNT (32)//一次报表32个字节,如果端点传输不满32bytes,不会向应用层报告0x81, 0x06,             //INPUT (Data,Var,Rel)0x09, 0x00,             //USAGE (Undefined)0x91, 0x06,             //OUTPUT (Data,Var,Rel)0xC0                        //END_COLLECTION//集合关闭
};

5. 实现自己的hid接收回调函数

在\apps\common\device\usb\device\task_pc.c文件里,实现自己的HID接收回调功能函数。
下面的代码例子,只是简单的对hid收到的数据进行了串口输出打印,然后将接收数据按位取反,然后重新发回主机。


#if TCFG_USB_CUSTOM_HID_ENABLE
static void custom_hid_rx_handler(void *priv, u8 *buf, u32 len)
{printf("%s,%d,\n", __func__, __LINE__);put_buf(buf, len);//串口打印hid收到的数据for(int i=0;i<len;i++){buf[i]=(unsigned char)~buf[i];//对数据按位取反}custom_hid_tx_data(0, buf, len);//将收到的数据填入上传端点,让主机取走
}
#endif

以上修改完成以后需要屏蔽一个USB升级函数,主要是给dongle例程使用的。如果不屏蔽,编译会报错,因为我们并没有链接dongle相关的.c和.h文件。编译器会报告找不到dongle_send_data_to_pc_3(data, len)函数。

static int update_send_user_data_do(void *priv, void *data, u16 len)
{
//#if TCFG_USB_CUSTOM_HID_ENABLE
//    //-------------------!!!!!!!!!!考虑关闭RCSP_BTMATE_EN使能编译报错
//    extern void dongle_send_data_to_pc_3(u8 * data, u16 len);
//    dongle_send_data_to_pc_3(data, len);
//#endifreturn 0;
}

6. 添加void usb_start()函数到app start程序里

  • void usb_start()函数如下:
void usb_start()
{//......此处省略1万字,,,,,无关代码省略.......//#ifdef USB_DEVICE_CLASS_CONFIGg_printf("USB_DEVICE_CLASS_CONFIG:%x", USB_DEVICE_CLASS_CONFIG);usb_device_mode(usbfd, USB_DEVICE_CLASS_CONFIG);//根据设定的类别,初始化USB
#endif//......此处省略1万字,,,,,无关代码省略.......//#if TCFG_USB_CUSTOM_HID_ENABLEcustom_hid_set_rx_hook(NULL, custom_hid_rx_handler);//设置USB中断接收回调函数printf("custom_hid rx_hook\n");
#endif
}
  • 添加位置如下:
    我这里用的spp_ble例程,直接加到末尾即可。
/*************************************************************************************************/
/*!*  \brief      app start**  \param      [in]**  \return**  \note*/
/*************************************************************************************************/
static void spple_app_start()
{log_info("=======================================");log_info("-----------spp_and_le demo-------------");log_info("=======================================");log_info("app_file: %s", __FILE__);if (enter_btstack_num == 0) {enter_btstack_num = 1;clk_set("sys", BT_NORMAL_HZ);//有蓝牙
#if (TCFG_USER_EDR_ENABLE || TCFG_USER_BLE_ENABLE)u32 sys_clk =  clk_get("sys");bt_pll_para(TCFG_CLOCK_OSC_HZ, sys_clk, 0, 0);#if TCFG_USER_EDR_ENABLEbtstack_edr_start_before_init(NULL, 0);
#if DOUBLE_BT_SAME_MAC//手机自带搜索界面,默认搜索到EDR__change_hci_class_type(BD_CLASS_TRANSFER_HEALTH);//
#endif
#endif#if TCFG_USER_BLE_ENABLEbtstack_ble_start_before_init(&trans_data_ble_config, 0);
#endifbtstack_init();#else
//no bt,to for testsys_timer_add(NULL, spple_timer_handle_test, 1000);
#endif}/* 按键消息使能 */sys_key_event_enable();#if (TCFG_PC_ENABLE)extern void usb_start();extern void usb_hid_set_repport_map(const u8 * map, int size);//配置选择上报PC的描述符log_info("my usb_hid_set_repport_map.");extern const u8 sHIDReportDesc_custom[];extern int HID_REPORTDESC_LEN;usb_hid_set_repport_map(sHIDReportDesc_custom, HID_REPORTDESC_LEN);usb_start();//添加USB初始化函数#endif
}

7. 测试实例

  • 通过计算机设备管理器查看人机接口设备变化

USB插入前:
在这里插入图片描述
USB插入后:多了一个标准的供应商自定义HID设备。
在这里插入图片描述

  • 通过计算机设备管理器查看自定义设备的硬件ID
    可以点击查看详细信息,看到VID和PDI是刚才代码里设备描述符设置的,VID: 0x4459,PID: 0x4C5A。其中REV_0100是设备描述符里自己定义的设备发行版本号BCD格式,V1.0。

在这里插入图片描述

  • 使用USB HID调试助手进行数据通讯测试
    使用USB HID调试助手测试,配置好VID、PID和接口、端点地址后,发送32bytes数据,可以看到接收区域收到取反的32bytes数据。这是在回调函数里进行简单取反测试通讯功能的。
    在这里插入图片描述 - 使用SSCOM串口助手查看USB主机发来的数据
    hid接收回调函数里进行了串口打印输出。

在这里插入图片描述- 使用USB BusHound软件查看收发数据流
在这里插入图片描述


http://www.ppmy.cn/news/99618.html

相关文章

python中的流程控制语句

文章目录 if-else语句代码演示&#xff1a; if-elif-else语句代码演示1&#xff1a;代码演示2&#xff1a; while 循环语句循环语句练习1.求100以内所有的奇数之和2.求100以内所有7的倍数之和&#xff0c;以及个数3.求1000内的水仙花数4.获取用户输入的任意数&#xff0c;判断是…

批处理文件(.bat)启动redis及任何软件(同理)

批处理文件 每次从文件根目录用配置文件格式来启动redis太麻烦了 可以在桌面上使用批处理文件&#xff08;.bat&#xff09;启动Redis&#xff0c;请按照以下步骤进行操作&#xff1a; 打开文本编辑器&#xff0c;如记事本。 在编辑器中输入以下内容&#xff1a; 将文件保存…

case when用法

case when的基本使用&#xff1a; Case when 的用法: 一旦满足了某一个WHEN, 则这一条数据就会退出CASE WHEN , 而不再考虑 其他CASE。 Case when 的用法 -- -搜索Case函数: Case函数(Case搜索函数): 判断表达式的真假,如果为真,返回结果;如果为假,返回else值;如果未定义el…

2023 年面向初学者的 5 大自由写作技巧

在这篇文章中&#xff0c;我们将讨论初学者的自由写作技巧 译自&#xff1a;https://jitendra.co/freelance-writing-tips-for-beginners/ 比较平易近人&#xff0c;在做独立站并且自己写原创时候可以参考下&#xff0c;面对的甲方爸爸不同而已 最初的兼职活动最终成为我生活中…

大数据Doris(二十九):Broker Load导入HDFS csv 格式数据并提取文件路径中的分区字段

文章目录 Broker Load导入HDFS csv 格式数据并提取文件路径中的分区字段 一、创建Doris表 二、准备HDFS数据<

JAVAWEB(上)

一、HTML和CSS 1.盒子 2.表单 3.机器人回答&#xff1a; 3.1 label标签 <label>标签用于关联表单元素和文本标签&#xff0c;通过为表单元素定义文本标签&#xff0c;可以使表单更易于使用和访问。它的基本语法如下&#xff1a;<label for"input_id">…

柱状图中最大的矩形

题目链接 柱状图中最大的矩形 题目描述 注意点 无 解答思路 暴力破解根据每根柱子x以x的高度作为矩形的高度找到其相邻能组成矩形的柱子&#xff0c;遍历所有柱子即可找到最大矩形&#xff0c;但是时间复杂度是O(n)&#xff0c;最终运行结果也超时了上面暴力破解的方法中…

PAT A1152 Google Recruitment

1152 Google Recruitment 分数 20 作者 陈越 单位 浙江大学 In July 2004, Google posted on a giant billboard along Highway 101 in Silicon Valley (shown in the picture below) for recruitment. The content is super-simple, a URL consisting of the first 10-dig…