杰理AC632N实现custom hid

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软件查看收发数据流
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ydgd118

您的鼓励是我最大的动力!谢赏!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值