杰理AC632N实现custom hid

news2025/4/7 8:30:07

1. 设备描述符修改

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

static const u8 sDeviceDescriptor[] = { //<Device Descriptor
    USB_DT_DEVICE_SIZE,      // bLength: Size of descriptor
    USB_DT_DEVICE,       // bDescriptorType: Device
#if defined(FUSB_MODE) && FUSB_MODE
    0x10, 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"
#endif
    0x00,       // bDeviceClass: none
    0x00,       // bDeviceSubClass: none
    0x00,       // bDeviceProtocol: none
    EP0_SETUP_LEN,//EP0_LEN,      // bMaxPacketSize0: 8/64 bytes
    'Y', 'D',     // idVendor: 59 44 - YD,电脑上小端格式显示为0x4459
    'Z', 'L',     // idProduct: 5a 4c - ZL,电脑上小端格式显示为0x4c5a
    0x00, 0x01,     // bcdDevice: version 1.0
    0x01,       // iManufacturer: Index to string descriptor that contains the string <Your Name> in Unicode
    0x02,       // iProduct: Index to string descriptor that contains the string <Your Product Name> in Unicode
    0x00,       // 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,       //字符串描述符的类型编码为0x03
    0x59, 0x00, //Y
    0x75, 0x00, //u
    0x61, 0x00, //a
    0x6e, 0x00, //n
    0x44, 0x00, //D
    'o', 0x00, //o
    'u', 0x00, //u
    0x20, 0x00, //
    0x54, 0x00, //T
    0x65, 0x00, //e
    0x63, 0x00, //c
    0x68, 0x00, //h
    0x6e, 0x00, //n
    0x6f, 0x00, //o
    0x6c, 0x00, //l
    0x6f, 0x00, //o
    0x67, 0x00, //g
    0x79, 0x00, //y
};

2. 配置描述符修改

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

static const u8 sConfigDescriptor[] = {	//<Config Descriptor
//ConfiguraTIon
    USB_DT_CONFIG_SIZE,    //bLength
    USB_DT_CONFIG,    //DescriptorType : ConfigDescriptor
    0, 0, //TotalLength
    0,//bNumInterfaces: 在set_descriptor函数里面计算
    0x01,    //bConfigurationValue - ID of this configuration
    0x00,    //Unused
#if USB_ROOT2 || USB_SUSPEND_RESUME || USB_SUSPEND_RESUME_SYSTEM_NO_SLEEP
    0xA0,    //Attributes:Bus Power remotewakeup
#else
    0x80,    //Attributes:Bus Power
#endif
    50,     //MaxPower * 2ma
};

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

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

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

static const u8 sHIDDescriptor[] = {
//HID
    //InterfaceDeszcriptor:
    USB_DT_INTERFACE_SIZE,     // Length
    USB_DT_INTERFACE,          // DescriptorType,接口描述符
    0x00,                       // bInterface number,接口编号为0
    0x00,                      // AlternateSetting,无备用接口描述符
    0x02,                      // NumEndpoint,端点2个
    USB_CLASS_HID,             // Class = Human Interface Device
    0x00,                      // Subclass, 0 No subclass, 1 Boot Interface subclass
    0x00,                      // Procotol, 0 None, 1 Keyboard, 2 Mouse
    0x00,                      // Interface Name,字符串描述符里无接口说明

    //HIDDescriptor:
    0x09,                      // bLength
    USB_HID_DT_HID,            // bDescriptorType, HID Descriptor
    0x10, 0x01,                // bcdHID, HID Class Specification release NO.HID协议版本V1.1
    0x00,                      // 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,长度:9bytes
    USB_DT_ENDPOINT,            // bDescriptorType, Type,类型:端点描述符
    USB_DIR_IN | CUSTOM_HID_EP_IN,     // bEndpointAddress,设备上传端点地址,0x84
    USB_ENDPOINT_XFER_INT,      // Interrupt,传输类型:中断
    LOBYTE(MAXP_SIZE_CUSTOM_HIDIN), HIBYTE(MAXP_SIZE_CUSTOM_HIDIN),// Maximum packet size,端点一次最大传输字节数:64bytes
    0x01,                       // bInterval, for high speed 2^(n-1) * 125us, for full/low speed n * 1ms,主机1ms从端点取一次数据

    //Endpoint Descriptor:
    USB_DT_ENDPOINT_SIZE,       // bLength
    USB_DT_ENDPOINT,            // bDescriptorType, Type,类型:端点描述符
    CUSTOM_HID_EP_OUT,   // bEndpointAddress,主机下传端点地址,0x04
    USB_ENDPOINT_XFER_INT,      // Interrupt,传输类型:中断
    LOBYTE(MAXP_SIZE_CUSTOM_HIDOUT), HIBYTE(MAXP_SIZE_CUSTOM_HIDOUT),// Maximum packet size,,端点一次最大传输字节数:64bytes
    0x01,                       // 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);
//#endif
    return 0;
}

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

  • void usb_start()函数如下:
void usb_start()
{

//......此处省略1万字,,,,,无关代码省略.......//

#ifdef USB_DEVICE_CLASS_CONFIG
    g_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_ENABLE
    custom_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_ENABLE
        btstack_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_ENABLE
        btstack_ble_start_before_init(&trans_data_ble_config, 0);
#endif

        btstack_init();

#else
//no bt,to for test
        sys_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.coloradmin.cn/o/580375.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

langchain简版教程附案例

简介 LangChain是一个开源的应用开发框架。基于该开源框架&#xff0c;我们可以把大模型与各种工具结合从而实现各种功能&#xff0c;比如基本文档的问答&#xff0c;解析网页内容、查询表格数据等。目前支持Python和TypeScript两种编程语言。当前Python框架支持的模型和功能最…

腾讯云服务器ping不通解决方法(公网IP/安全组/系统多维度)

腾讯云服务器ping不通什么原因&#xff1f;ping不通公网IP地址还是域名&#xff1f;新手站长从云服务器公网IP、安全组、Linux系统和Windows操作系统多方面来详细说明腾讯云服务器ping不通的解决方法&#xff1a; 目录 腾讯云服务器ping不通原因分析及解决方法 安全组ICMP协…

智能计价器-第14届蓝桥杯省赛Scratch中级组真题第5题

[导读]&#xff1a;超平老师的《Scratch蓝桥杯真题解析100讲》已经全部完成&#xff0c;后续会不定期解读蓝桥杯真题&#xff0c;这是Scratch蓝桥杯真题解析第140讲。 智能计价器&#xff0c;本题是2023年5月7日举行的第14届蓝桥杯省赛Scratch图形化编程中级组真题第5题&#…

楼宇租赁管理系统-什么是楼宇租赁系统

楼宇租赁管理系统是一种综合管理平台&#xff0c;它为不同规模楼宇的租赁管理提供了全面的解决方案。楼宇租赁管理系统的主要功能包括租赁管理、财务管理、维修管理、报告管理以及客户服务管理等。让我们逐一介绍每一个功能点。 一、租赁管理 楼宇租赁管理系统通过集成租户信息…

路径规划算法:基于群居蜘蛛优化的路径规划算法- 附代码

路径规划算法&#xff1a;基于群居蜘蛛优化的路径规划算法- 附代码 文章目录 路径规划算法&#xff1a;基于群居蜘蛛优化的路径规划算法- 附代码1.算法原理1.1 环境设定1.2 约束条件1.3 适应度函数 2.算法结果3.MATLAB代码4.参考文献 摘要&#xff1a;本文主要介绍利用智能优化…

博学谷学习记录】超强总结,用心分享 | 架构师 MySQL调优MVCC学习总结

文章目录 1 概述2 快照读与当前读当前读快照读隔离级别&#xff1a;undo log版本链&#xff1a; 3 Read View3.1 什么是Read View?3.2 实现原理3.3 Read View规则&#xff08;可见性算法&#xff09; 4 MVCC整体流程4.1 可重复读是如何工作的&#xff1f;4.2 读提交是如何工作…

ChatGPT国内镜像,以及如何使用ChatGPT帮你制作PPT

一&#xff1a;前言 ChatGPT&#xff1a;智能AI助你畅聊天地 在现代人日益忙碌的生活中&#xff0c;难免需要一些轻松愉快的聊天来放松身心。而现在&#xff0c;有了 ChatGPT&#xff0c;轻松愉快的聊天变得更加智能、有趣且不受时间、地点限制&#xff01; 什么是 ChatGPT&…

Python中模块的使用方法4

1 模块、包和库的区别 Python中&#xff0c;模块的英文是“module”&#xff0c;是一个以py为后缀名的文件&#xff1b;包的英文是“package”&#xff0c;是一个包含了多个模块的目录&#xff1b;库的英文是“library”&#xff0c;包含了具有相关功能的包和模块。 2 模块的…

ChatGPT 在自动化测试领域的应用,我们真的要被代替了吗?

目录 前言 一、ChatGPT 简介 二、ChatGPT 的应用场景 三、ChatGPT 的优势 四、ChatGPT 的局限性 五、ChatGPT 在自动化测试领域的拓展应用 六、ChatGPT真的可以代替软件测试人员吗 七、结语 前言 人工智能技术在近年来得到了快速发展&#xff0c;不少领域都开始尝试融合…

入理解深度学习——正则化(Regularization):多任务学习

分类目录&#xff1a;《深入理解深度学习》总目录 多任务学习是通过合并几个任务中的样例&#xff08;可以视为对参数施加的软约束&#xff09;来提高泛化的一种方式。正如额外的训练样本能够将模型参数推向具有更好泛化能力的值一样&#xff0c;当模型的一部分被多个额外的任务…

redis主从复制策略的原理:主从节点间如何同步数据?

redis的主从复制原理经历了多个版本的更新。 redis2.8之前的SYNC方案 命令&#xff1a; SYNChttps://www.yuque.com/snailclimb/mf2z3k/ks9olb19hc9wse5k#5935f46a 存在的问题&#xff1a; slave加载RDB的过程中不能对外提供读服务slave和master断开连接后&#xff0c;sla…

HCIA-VLAN间通信之路由器

目录 路由信息获取方式&#xff1a; 最佳路由条目选择&#xff08;根据路由的优先级和开销选择&#xff09;&#xff1a; VLAN间通信 方案1&#xff0c;使用路由器的物理接口来实现不同vlan间的通信 方案2&#xff1a;使用路由器的子接口来实现 路由&#xff1a;指导报文转…

【Vue】二:Vue核心处理---计算属性 监视属性

文章目录 1.计算属性示例2. 监听属性3.补充 1.计算属性示例 实际上计算属性与methods中定义方法基本上没有什么区别&#xff0c;只是计算属性基于响应式依赖缓存&#xff0c;只要数据没有发生改变&#xff0c;计算属性从缓存中取值&#xff0c;只有当数据发送改变&#xff0c;才…

Linux 用户与组群管理

1 用户账户与群组概念 Linux操作系统是多用户多任务的操作系统&#xff0c;允许多个用户同时登录到系统&#xff0c;使 用系统资源。用户账户是用户的身份标识。用户通过用户账户可以登录到系统&#xff0c; 并且访问已经被授权的资源。系统依据账户来区分属于每个用户的文件…

Flutter 笔记 | Flutter 动画

Flutter中的动画抽象 为了方便开发者创建动画&#xff0c;不同的UI系统对动画都进行了一些抽象&#xff0c; Flutter中也对动画进行了抽象&#xff0c;主要涉及 Animation、Curve、Controller、Tween这四个角色&#xff0c;它们一起配合来完成一个完整动画&#xff0c;下面我们…

整数在内存中原来是这样存储的,看完表示头好痒,感觉要长脑子了!

本篇文章来介绍一下整形在内存中的存储&#xff0c;内容丰富&#xff0c;干货慢慢。 目录 1.整形家族 2.整形在内存中的存储 3.大端小端存储 4.练习 1.整形家族 在开始之前&#xff0c;我们先来简单回顾一下整形家族&#xff1a; char unsigned char signed char short u…

chatgpt赋能python:Python补0——让你的数字更规整

Python 补0——让你的数字更规整 在编写代码的过程中&#xff0c;我们经常需要将数字格式化&#xff0c;以便更好地呈现给用户。例如&#xff0c;一个价格可能需要显示为“$100.00”而不是“$100”或“$100.0”。这时候&#xff0c;我们就需要使用 Python 的补0功能。本文将为…

【015】C++的函数详解

C的函数详解 引言一、函数介绍1.1、函数的概述1.2、函数的分类 二、函数定义、声明、调用等2.1、定义函数2.2、函数声明2.3、调用函数2.4、默认参数2.5、函数重载2.6、函数的调用过程 三、函数的传参3.1、普通变量作为函数的参数3.2、数组作为函数的参数 总结 引言 &#x1f4a…

浅浅入门SpringCloud

Spring Cloud是一系列框架的有序集合。它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发&#xff0c;如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等&#xff0c;都可以用Spring Boot的开发风格做到一键启动和部署。Spring Cloud并没有…

如何在Linux机器中测试存储/磁盘I/O性能?

在Linux环境中&#xff0c;了解存储/磁盘I/O性能对于评估系统性能和优化存储子系统非常重要。通过测试存储/磁盘I/O性能&#xff0c;我们可以确定磁盘的读写速度、延迟和吞吐量等指标。本文将介绍几种常用的方法来测试Linux机器中的存储/磁盘I/O性能。 方法一&#xff1a;使用d…