USB设备(USBD)控制器实现全速USB设备功能,满足2.0版本的USB规范。
这里列出的是USBD的主要特性:
- 全速度(12mbps)设备完全符合通用串行总线规范修订2.0,包括以下是USB实施者论坛发布的工程更改通知:
- 上拉/下拉电阻ECN
- 5V短路耐受要求变更ECN
- USB设备栈在北欧SDK中可用
- 集成(芯片上)USB收发器(PHY)
- 软件控制的芯片上拉在D+
- 端点:
- 两个控制(1 IN, 1 OUT)
- 14 bulk/interrupt (7 IN, 7 OUT)
- 两个同步(1in, 1out)
- 双缓冲等时(ISO)端点(IN/OUT)支持
- USB挂起、恢复和远程唤醒支持
- 每个bulk/中断端点的64字节缓冲区大小
- 高达1023字节的ISO端点缓冲区大小
- 所有数据传输EasyDMA
USB设备状态
USB设备的行为可以通过状态图来建模。
usb2.0规范(见第9章USB设备框架)定义了USB设备的许多状态,如下图所示。
设备必须根据主机发起的流量和USB总线状态改变状态。由软件来实现匹配上述定义的状态机。为了检测是否存在USB供应(VBUS),两个事件USBDETECTED和USBREMOVED可以用来实现状态机。有关这些事件的更多细节,请参阅65页的USB电源。
作为实现软件的一般规则,主机的行为永远不能被认为是可预测的。特别是在枚举期间接收的命令序列。软件应始终对当前总线条件或主机发送的命令作出反应。
一、app_usbd_string_desc(USB字符串描述符/当前系统类型)
#include "sdk_config.h"
#if APP_USBD_ENABLED
#include "app_usbd_string_desc.h"
#include "app_usbd_langid.h"
#include "app_usbd_core.h"
#include "nordic_common.h"
#include "utf.h"
#include "biz_usb.h"
#include "app_main.h"
#include "business_function.h"
#include "log.h"
#define USB_DEVICE_LANGID_STRING 0x409
#define USB_DESC_TYPE_DEVICE 1
#define USB_DESC_TYPE_CONFIGURATION 2
#define USB_DESC_TYPE_STRING 3
#define USB_DESC_TYPE_INTERFACE 4
#define USB_DESC_TYPE_ENDPOINT 5
#define USB_DESC_TYPE_DEVICE_QUALIFIER 6
#define USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION 7
#define USB_DESC_TYPE_BOS 0x0F
bool get_usb_string_bus = false;
bool g_flash_write_usb_string_flag = false;
usbd_comm_system_t g_sys_type = USB_COMM_SYSTEM_UNKNOWN;
__attribute__((aligned(4))) uint8_t string_0[] =
{
4, USB_DESC_TYPE_STRING,
LOBYTE(USB_DEVICE_LANGID_STRING),
HIBYTE(USB_DEVICE_LANGID_STRING),
};
__attribute__((aligned(4))) uint16_t string_1[] = USB_STRING1_MANUFACTURER;
__attribute__((aligned(4))) uint16_t string_2[] = USB_STRING2_PRODUCT;
__attribute__((aligned(4))) uint16_t string_3[] = USB_STRING3_SERIAL_NUMBER;
__attribute__((aligned(4))) uint16_t string_4[] = USB_STRING4_FIRMWARE_VERSION;
__attribute__((aligned(4))) uint16_t string_5[] = USB_STRING5_FIRMWARE_DATE;
__attribute__((aligned(4))) uint8_t string_100[] = USB_STRING100_TABLET_PROPERTIES;
__attribute__((aligned(4))) uint16_t string_102[] = USB_STRING102_COMPANY;
#if BS_BLE_SUPPORT || BS_NRF_BLE_SUPPORT
uint8_t string_103[] = USB_STRING103_MAC_ADDR;
#endif
__attribute__((aligned(4))) uint8_t string_104[] = USB_STRING104_WITH_PEN;
__attribute__((aligned(4))) uint8_t string_105[] = USB_STRING105_EXPAND_PROPERTIES;
__attribute__((aligned(4))) uint8_t string_110[] = USB_STRING110_DEVICE_TYPE;
__attribute__((aligned(4))) uint8_t string_120[] = USB_STRING120_DONGLE_MAC;
__attribute__((aligned(4))) uint16_t string_131[] = USB_STRING131_AGREEMENT_VER_NUM;
/**
* @brief [usb设备描述符-字符串5] 设置HWIC固件版本字符串
* @note 由于上位机按uint16_t取字符串,所以string_5按uint16_t定义数组。 string_5[22] = string[0]; 相当于只对uint16_t高8位进行赋值,低八位自动为0。
* @param *string: HWIC固件版本字符串
* @param len: 字符串长度
*/
void set_usb_comm_string5(uint8_t *string, uint8_t len)
{
string_5[10] = string[0];
string_5[11] = string[1];
string_5[12] = string[2];
string_5[13] = string[3];
string_5[14] = string[4];
string_5[15] = string[5];
}
#if BS_BLE_SUPPORT || BS_NRF_BLE_SUPPORT
/**
* @brief [usb设备描述符-字符串103] 设置BLE_MAC_ADDR
* @param *string: BLE MAC ADDR地址
* @param len: 字符串长度
*/
void set_usb_comm_string103(uint8_t *data, uint8_t len)
{
if (memcmp(&string_103[2], data, BLE_MAC_MAX_VAL) == 0)
{
return;
}
if (data[0] == 0 && data[1] == 0 && data[2] == 0 &&
data[3] == 0 && data[4] == 0 && data[5] == 0)
{
return;
}
string_103[2] = data[0];
string_103[3] = data[1];
string_103[4] = data[2];
string_103[5] = data[3];
string_103[6] = data[4];
string_103[7] = data[5];
//LOG_D("BLE_MAC:%02x %02x %02x %02x %02x %02x\r\n", data[0], data[1], data[2], data[3], data[4], data[5]);
}
#endif
#if BS_BLE_SUPPORT || BS_NRF_BLE_SUPPORT
void set_usb_comm_string120_dongle_mac(uint8_t *p_dongle_mac, uint8_t len)
{
if(p_dongle_mac[0] == 0 || p_dongle_mac[1] == 0 || p_dongle_mac[2] == 0 ||
p_dongle_mac[3] == 0 || p_dongle_mac[4] == 0 || p_dongle_mac[5] == 0)
{
return;
}
string_120[6] = p_dongle_mac[0];
string_120[7] = p_dongle_mac[1];
string_120[8] = p_dongle_mac[2];
string_120[9] = p_dongle_mac[3];
string_120[10] = p_dongle_mac[4];
string_120[11] = p_dongle_mac[5];
}
#endif
uint16_t const * app_usbd_string_desc_get(uint8_t idx, uint16_t langid)
{
if ((nrf_usbd_setup_windex_get() & 0x00ff) == 0)
{
if (nrf_usbd_setup_wlength_get() == 254)
{
set_current_system(USB_COMM_SYSTEM_ANDROID);
}
else
{
set_current_system(USB_COMM_SYSTEM_WINDOS);
}
}
/* LANGID string. */
LOG_D("<DEBUG> Request usb string %03d | %04x\r\n", idx, nrf_usbd_setup_wlength_get());
uint8_t *p_str;
switch (idx)
{
case 0:
p_str = (uint8_t*)string_0;
get_usb_string_bus = true;
return (uint16_t *)p_str;
case 1:
p_str = (uint8_t*)string_1;
p_str[0] = sizeof(string_1)-2;
p_str[1] = USB_DESC_TYPE_STRING;
get_usb_string_bus = true;
return (uint16_t *)p_str;
case 2:
p_str = (uint8_t*)string_2;
p_str[0] = sizeof(string_2)-2;
p_str[1] = USB_DESC_TYPE_STRING;
get_usb_string_bus = true;
return (uint16_t *)p_str;
case 3:
p_str = (uint8_t*)string_3;
p_str[0] = sizeof(string_3)-2;
p_str[1] = USB_DESC_TYPE_STRING;
return (uint16_t *)p_str;
case 4:
p_str = (uint8_t*)string_4;
p_str[0] = sizeof(string_4)-2;
p_str[1] = USB_DESC_TYPE_STRING;
return (uint16_t *)p_str;
case 5:
p_str = (uint8_t*)string_5;
p_str[0] = sizeof(string_5)-2;
p_str[1] = USB_DESC_TYPE_STRING;
return (uint16_t *)p_str;
#if BS_BLE_SUPPORT
case 30:
main_send_signal(SIGNAL_BLE_DTM);
break;
case 31:
main_send_signal(SIGNAL_BLE_FIXED_FREQUENCY);
break;
#endif
case 100:
p_str = (uint8_t*)string_100;
return (uint16_t *)p_str;
case 102:
p_str = (uint8_t*)string_102;
return (uint16_t *)p_str;
#if BS_BLE_SUPPORT || BS_NRF_BLE_SUPPORT
case 103:
p_str = (uint8_t*)string_103;
return (uint16_t *)p_str;
#endif
case 104:
p_str = (uint8_t*)string_104;
return (uint16_t *)p_str;
case 105:
p_str = (uint8_t*)string_105;
return (uint16_t *)p_str;
case 110:
p_str = (uint8_t*)string_110;
return (uint16_t *)p_str;
#if BS_24G_SUPPORT
case 120:
p_str = (uint8_t*)string_120;
return (uint16_t *)p_str;
#endif
case 131:
p_str = (uint8_t*)string_131;
p_str[0] = sizeof(string_131)-2;
p_str[1] = USB_DESC_TYPE_STRING;
return (uint16_t *)p_str;
case 0xc8:
#if BOOT_SUPPORT
main_send_signal(SIGNAL_SYS_GOTO_BOOT);
#else
#endif
break;
default:
LOG_E("<ERR> Request usb string %d\r\n", idx);
}
return (uint16_t *)string_0;
}
/**
* @brief 设置当前系统类型
* @param sys_type: 系统类型
*/
void set_current_system(usbd_comm_system_t sys_type)
{
if (g_sys_type != sys_type)
{
g_sys_type = sys_type;
main_send_signal(SIGNAL_SYS_CHANGE);
}
}
usbd_comm_system_t get_current_system(void)
{
return g_sys_type;
}
/** @} */
#endif // APP_USBD_ENABLED
#ifndef APP_USBD_STRING_DESC_H__
#define APP_USBD_STRING_DESC_H__
#include <stdint.h>
#include "sdk_common.h"
#include "app_usbd.h"
#include "business_function.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup app_usbd_string_desc USBD string descriptors
* @ingroup app_usbd
*
* @brief @tagAPI52840 USBD string descriptor management.
* @{
*/
/**
* @brief USB Language identifier initialization.
*
* @param[in] lang Language identifier.
*/
#define APP_USBD_LANG(lang) \
((app_usbd_langid_t) lang)
/**
* @brief USB Language identifier with sublanguage initialization.
*
* @param[in] lang Language identifier.
* @param[in] sublang Sublanguage identifier.
*/
#define APP_USBD_LANG_AND_SUBLANG(lang, sublang) \
((app_usbd_langid_t) lang | (app_usbd_langid_t) sublang)
/**
* @brief USB string initialization.
*
* Macro that creates initialization values for the USB string.
* The string must be declared as a NULL-terminated string.
*
* @param[in] str NULL-terminated string.
*
* @return String descriptor initialization data.
*/
#define APP_USBD_STRING_DESC(str) (const uint8_t *)(const char[]){str}
/**
* @brief USB raw 8-bit string initialization.
*
* Macro that creates header for raw values passed into descriptor.
* Values must be of the uint8_t type and separated by commas.
*
* @param[in] ... comma-separated values.
*
* @return String descriptor initialization data.
*/
#define APP_USBD_STRING_RAW8_DESC(...) (const uint8_t[]){ \
0x00, 0x00, /* NULL character at start to differentiate from normal string */ \
(0xff & (sizeof((uint8_t[]){__VA_ARGS__}) + 2)), \
(APP_USBD_DESCRIPTOR_STRING), \
__VA_ARGS__ }
/**
* @brief USB raw 16-bit string initialization.
*
* Macro that creates header for raw values passed into descriptor.
* Values must be of the uint16_t type and separated by commas.
*
* @param[in] ... comma-separated values.
*
* @return String descriptor initialization data.
*/
#define APP_USBD_STRING_RAW16_DESC(...) (const uint8_t *) ((const uint16_t[]){ \
0x00, /* NULL character at start to differentiate from normal string */ \
(0xff & (sizeof((uint16_t[]){__VA_ARGS__}) + 2)) | \
((uint16_t)APP_USBD_DESCRIPTOR_STRING) << 8, \
__VA_ARGS__ })
#if (APP_USBD_STRING_ID_MANUFACTURER != 0)
#define APP_USBD_STRING_ID_MANUFACTURER_LEN 1
#else
#define APP_USBD_STRING_ID_MANUFACTURER_LEN 0
#endif
#if (APP_USBD_STRING_ID_PRODUCT != 0)
#define APP_USBD_STRING_ID_PRODUCT_LEN 1
#else
#define APP_USBD_STRING_ID_PRODUCT_LEN 0
#endif
#if (APP_USBD_STRING_ID_SERIAL != 0)
#define APP_USBD_STRING_ID_SERIAL_LEN 1
#else
#define APP_USBD_STRING_ID_SERIAL_LEN 0
#endif
#if (APP_USBD_STRING_ID_CONFIGURATION != 0)
#define APP_USBD_STRING_ID_CONFIGURATION_LEN 1
#else
#define APP_USBD_STRING_ID_CONFIGURATION_LEN 0
#endif
/** @brief Total number of USB strings */
#define APP_USBD_STRINGS_NUM \
((APP_USBD_STRINGS_USER 0) + 1 + APP_USBD_STRING_ID_MANUFACTURER_LEN + APP_USBD_STRING_ID_PRODUCT_LEN + APP_USBD_STRING_ID_SERIAL_LEN + APP_USBD_STRING_ID_CONFIGURATION_LEN)
/**
* @brief USB string descriptors IDs
*/
typedef enum {
APP_USBD_STRING_ID_LANGIDS = 0, /**< Supported language identifiers */
/// Placeholders used only for alignement of user strings. Do not use or modify them.
#if (APP_USBD_STRING_ID_MANUFACTURER != 0)
APP_USBD_STRING_ID_MANUFACTURER_PLACEHOLDER = APP_USBD_STRING_ID_MANUFACTURER,
#endif // (APP_USBD_STRING_ID_MANUFACTURER != 0)
#if (APP_USBD_STRING_ID_PRODUCT != 0)
APP_USBD_STRING_ID_PRODUCT_PLACEHOLDER = APP_USBD_STRING_ID_PRODUCT,
#endif // (APP_USBD_STRING_ID_PRODUCT != 0)
#if (APP_USBD_STRING_ID_SERIAL != 0)
APP_USBD_STRING_ID_SERIAL_PLACEHOLDER = APP_USBD_STRING_ID_SERIAL,
#endif // (APP_USBD_STRING_ID_SERIAL != 0)
#if (APP_USBD_STRING_ID_CONFIGURATION != 0)
APP_USBD_STRING_ID_CONFIGURATION_PLACEHOLDER = APP_USBD_STRING_ID_CONFIGURATION,
#endif // (APP_USBD_STRING_ID_CONFIGURATION != 0)
#define X(mnemonic, str_idx, ...) mnemonic str_idx,
APP_USBD_STRINGS_USER
#undef X
} app_usbd_string_desc_idx_t;
/** @brief String ID conversion struct */
typedef struct {
uint8_t const identifier;
uint8_t const array_pos;
} app_usbd_strings_convert_t;
/**
* @brief Get string descriptor.
*
* @param[in] idx String descriptor index.
* @param[in] langid Selected language for the string.
* @return String descriptor, or NULL if it does not exist.
* */
uint16_t const * app_usbd_string_desc_get(uint8_t idx, uint16_t langid);
/**
* @brief Get string length.
*
* Function for getting string length from descriptor (descriptor returned by @ref app_usbd_string_desc_get).
*
* @param[in] p_str String descriptor pointer.
* @return Total descriptor length in bytes.
*/
static inline size_t app_usbd_string_desc_length(uint16_t const * p_str)
{
return ((const app_usbd_descriptor_string_t *)p_str)->bLength;
}
/** @} */
typedef enum
{
USB_COMM_SYSTEM_UNKNOWN = 0,
USB_COMM_SYSTEM_WINDOS,
USB_COMM_SYSTEM_ANDROID
}usbd_comm_system_t;
void set_current_system(usbd_comm_system_t sys_type);
usbd_comm_system_t get_current_system(void);
extern uint16_t string_1[];
extern uint16_t string_2[];
extern uint16_t string_3[];
extern uint16_t string_4[];
extern uint16_t string_5[];
extern uint8_t string_100[];
extern uint8_t string_104[];
extern uint8_t string_105[];
extern uint8_t string_110[];
extern uint8_t string_120[];
extern uint16_t string_131[];
extern bool g_flash_write_usb_string_flag;
void set_usb_comm_string5(uint8_t *string, uint8_t len);
#if BS_BLE_SUPPORT || BS_NRF_BLE_SUPPORT
void set_usb_comm_string103(uint8_t *data, uint8_t len);
void set_usb_comm_string120_dongle_mac(uint8_t *p_dongle_mac, uint8_t len);
#endif
#ifdef __cplusplus
}
#endif
#endif /* APP_USBD_STRING_DESC_H__ */
节点描述符
#define HID_MOUSE_INTERFACE 0
#define HID_TABLET_INTERFACE 1
#define HID_GENERIC_INTERFACE 2
// NRF端点实际默认+1,即填写7,实际上显示最大支持8字节
#define MOUSE_REPORT_OUT_MAXSIZE 7
#define TABLET_REPORT_OUT_MAXSIZE 9
#define GENERIC_REPORT_OUT_MAXSIZE 63
#define MOUSE_REPORT_FEATURE_MAXSIZE 31
#define TABLET_REPORT_FEATURE_MAXSIZE 31
#define GENERIC_REPORT_FEATURE_MAXSIZE 63
#define HID_MOUSE_EPIN NRF_DRV_USBD_EPIN1
#define HID_TABLET_EPIN NRF_DRV_USBD_EPIN2
#define HID_GENERIC_EPIN NRF_DRV_USBD_EPIN3
#define HID_GENERIC_EPOUT NRF_DRV_USBD_EPOUT3
#define APP_USBD_HID_MOUSE_REPORT_DSC() \
{ \
/* =====================节点 0 === Mouse (安卓鼠标)============*/ \
0x05, 0x01, /* Usage Page (Generic Desktop) */ \
0x09, 0x02, /* Usage (Mouse) */ \
0xA1, 0x01, /* Collection (Application) */ \
0x85, 0x09, /* Report ID(9) */ \
0x09, 0x01, /* Usage (Pointer) */ \
0xA1, 0x00, /* Collection (Physical) */ \
0x05, 0x09, /* Usage Page (Button) */ \
0x19, 0x01, /* Usage MINIMUM (Button 1) */ \
0x29, 0x06, /* Usage MAXIMUM (Button 6) */ \
0x15, 0x00, /* LOGICAL_MINIMUM (0) */ \
0x25, 0x01, /* LOGICAL_MAXIMUM (1) */ \
0x95, 0x03, /* Report Count (3) */ \
0x75, 0x01, /* Report Size (1) */ \
0x81, 0x02, /* INPUT (Data,Var,Abs) */ \
0x95, 0x05, /* Report Count (5) */ \
0x81, 0x01, /* INPUT (Cnst,Ary,Abs) */ \
0x05, 0x01, /* Usage Page (Generic Desktop) */ \
0x09, 0x30, /* Usage(X) */ \
0x09, 0x31, /* Usage(Y) */ \
0x26, 0xFF, 0x7F, /* LOGICAL_MAXIMUM (32767) */ \
0x95, 0x02, /* Report Count (2) */ \
0x75, 0x10, /* Report Size (16) */ \
0x81, 0x02, /* INPUT (Data,Var,Abs) */ \
0x05, 0x0D, /* USAGE_PAGE (Digitizers) */ \
0x09, 0x30, /* USAGE (Tip Pressure) */ \
0x26, 0xFF, 0x07, /* LOGICAL_MAXIMUM (2047) */ \
0x95, 0x01, /* Report Count (2) */ \
0x75, 0x10, /* Report Size (16) */ \
0x81, 0x02, /* INPUT (Data,Var,Abs) */ \
0xC0, /* End Collection */ \
0xC0, /* End Collection */ \
/* =====================节点 0 === END =========================*/ \
\
/* =====================节点 1 === Mouse (磁滚轮)===============*/ \
0x05, 0x01, /* Usage Page (Generic Desktop) */ \
0x09, 0x02, /* Usage (Mouse) */ \
0xA1, 0x01, /* Collection (Application) */ \
0x09, 0x01, /* Usage (Pointer) */ \
0xA1, 0x00, /* Collection (Physical) */ \
0x85, 0x01, /* Report ID(1) */ \
0x05, 0x09, /* Usage Page (Button) */ \
0x19, 0x01, /* Usage MINIMUM (Button 1) */ \
0x29, 0x06, /* Usage MAXIMUM (Button 6) */ \
0x95, 0x05, /* Report Count (5) */ \
0x75, 0x01, /* Report Size (1) */ \
0x15, 0x00, /* LOGICAL_MINIMUM (0) */ \
0x25, 0x01, /* LOGICAL_MAXIMUM (1) */ \
0x81, 0x02, /* INPUT (Data,Var,Abs) */ \
0x95, 0x03, /* Report Count (3) */ \
0x81, 0x01, /* INPUT (Cnst,Ary,Abs) */ \
0x05, 0x01, /* Usage Page (Generic Desktop) */ \
0x09, 0x30, /* Usage(X) */ \
0x09, 0x31, /* Usage(Y) */ \
0x95, 0x02, /* Report Count (2) */ \
0x75, 0x10, /* Report Size (16) */ \
0x16, 0x00, 0x80, /* LOGICAL_MINIMUM (-32767) */ \
0x26, 0xFF, 0x7F, /* LOGICAL_MAXIMUM (32767) */ \
0x81, 0x06, /* INPUT (Data,Var,Rel) */ \
/* =====================节点 1 === Wheel ======================*/ \
0x09, 0x38, /* Usage (Wheel) */ \
0x15, 0x81, /* LOGICAL_MINIMUM (-127) */ \
0x25, 0x7F, /* LOGICAL_MAXIMUM (127) */ \
0x95, 0x01, /* Report Count (1) */ \
0x75, 0x08, /* Report Size (8) */ \
0x81, 0x06, /* INPUT (Data,Var,Rel) */ \
0x05, 0x0C, /* Usage Page (Consumer Devices) */ \
0x0A, 0x38, 0x02, /* Usage (AC Pen) */ \
0x95, 0x01, /* Report Count (1) */ \
0x75, 0x08, /* Report Size (8) */ \
0x81, 0x06, /* INPUT (Data,Var,Rel) */ \
0xC0, /* End Collection */ \
0xC0, /* End Collection */ \
/* =====================节点 1 === END =========================*/ \
\
/* =====================节点 2 === Keyboard (标准键盘)==========*/ \
0x05, 0x01, /* Usage Page (Generic Desktop) */ \
0x09, 0x06, /* Usage (Keyboard) */ \
0xA1, 0x01, /* Collection (Application) */ \
0x85, 0x06, /* Report ID(6) */ \
0x05, 0x07, /* Usage Page (Keyboard/Keypad) */ \
0x19, 0xE0, /* Usage MINIMUM (Keyboard Left Control)*/\
0x29, 0xE7, /* Usage MAXIMUM (Keyboard Right GUI)*/ \
0x15, 0x00, /* LOGICAL_MINIMUM (0) */ \
0x25, 0x01, /* LOGICAL_MAXIMUM (1) */ \
0x75, 0x01, /* Report Size (1) */ \
0x95, 0x08, /* Report Count (8) */ \
0x81, 0x02, /* INPUT (Cnst,Var,Abs) */ \
0x05, 0x07, /* Usage Page (Keyboard/Keypad) */ \
0x19, 0x00, /* Usage MINIMUM (Undefined) */ \
0x29, 0xFF, /* Usage MAXIMUM */ \
0x26, 0xFF, 0x00, /* LOGICAL_MAXIMUM (255) */ \
0x75, 0x08, /* Report Size (8) */ \
0x95, 0x06, /* Report Count (6) */ \
0x81, 0x00, /* INPUT (Data,Ary,Abs) */ \
0xC0 /* End Collection */ \
}
#define USB_HID_TYPE_HAND_WRITE_DATA \
0x09, 0x02, /* USAGE (Touch Screen) */ \
0xa1, 0x01, /* COLLECTION (Application) */ \
0x85, 0x07, /* report(ID 7), */ \
0x09, 0x20, /* USAGE (Stylus) */ \
0xA1, 0x00, /* COLLECTION (Physical) */ \
0x09, 0x42, /* USAGE (Tip Switch) */ \
0x09, 0x44, /* USAGE (Barrel Switch) */ \
0x09, 0x45, /* USAGE (Eraser Switch) */ \
0x09, 0x3c, /* USAGE (Invert) */ \
0x15, 0x00, /* LOGICAL_MINIMUM (0) */ \
0x25, 0x01, /* LOGICAL_MAXIMUM (1) */ \
0x75, 0x01, /* REPORT_SIZE (1) */ \
0x95, 0x04, /* REPORT_COUNT (4) */ \
0x81, 0x02, /* INPUT (Data,Var,Abs) */ \
0x95, 0x01, /* REPORT_COUNT (2) */ \
0x81, 0x03, /* INPUT (Cnst,Ary,Abs) */ \
0x09, 0x32, /* USAGE (In Range) */ \
0x15, 0x00, /* LOGICAL_MINIMUM (0) */ \
0x25, 0x01, /* LOGICAL_MAXIMUM (1) */ \
0x95, 0x01, /* REPORT_COUNT (1) */ \
0x81, 0x02, /* INPUT (Data,Var,Abs) */ \
0x95, 0x02, /* REPORT_COUNT (2) */ \
0x81, 0x03, /* INPUT (Cnst,Ary,Abs) */ \
#define USB_HID_TYPE_TOUCH_PANEL_DATA \
0x09, 0x04, /* USAGE (Touch Screen) */ \
0xa1, 0x01, /* COLLECTION (Application) */ \
0x85, 0x07, /* report(ID 7), */ \
0x09, 0x22, /* USAGE (Finger) */ \
0xA1, 0x00, /* COLLECTION (Physical) */ \
0x09, 0x42, /* USAGE (Tip Switch) */ \
0x15, 0x00, /* LOGICAL_MINIMUM (0) */ \
0x25, 0x01, /* LOGICAL_MAXIMUM (1) */ \
0x75, 0x01, /* REPORT_SIZE (1) */ \
0x95, 0x01, /* REPORT_COUNT (1) */ \
0x81, 0x02, /* INPUT (Data,Var,Abs) */ \
0x09, 0x32, /* */ \
0x15, 0x00, /* */ \
0x25, 0x01, /* */ \
0x81, 0x02, /* */ \
0x09, 0x51, /* */ \
0x75, 0x05, /* */ \
0x81, 0x02, /* */ \
0x09, 0x47, /* */ \
0x75, 0x01, /* */ \
0x15, 0x00, /* */ \
0x25, 0x01, /* */ \
0x81, 0x02, /* */ \
// 根据产品类型决定自定义通道的端点类型(手写板/触摸屏)
#if BS_HAND_WRITE_TYPE != 1
#define USB_HID_TYPE_DATA USB_HID_TYPE_HAND_WRITE_DATA
#else
#define USB_HID_TYPE_DATA USB_HID_TYPE_TOUCH_PANEL_DATA
#endif
#define APP_USBD_HID_TABLET_REPORT_DSC() { \
0x05, 0x0D, /* USAGE_PAGE (Digitizers) */ \
USB_HID_TYPE_DATA \
0x75, 0x10, /* REPORT_SIZE (16) */ \
0x95, 0x01, /* REPORT_COUNT (1) */ \
0x35, 0x00, /* PHYSICAL_MINIMUM (0) */ \
0xa4, \
0x05, 0x01, /* USAGE_PAGE (desktop) */ \
0x09, 0x30, /* USAGE (X) */ \
0x65, 0x13, /* UNIT (Inch,EngLinear) */ \
0x55, 0x0D, /* UNIT_EXPONENT (-3) */ \
\
0x46, DESC_CONFIG_WORD(X_MIL), \
0x26, 0xFF, 0x7F, \
0x81, 0x02, \
0x09, 0x31, /* USAGE (Y) */ \
0x46, DESC_CONFIG_WORD(Y_MIL), /* y_size */ \
0x26, 0xFF, 0x7F, \
0x81, 0x02, \
0xB4, \
0x09, 0x30, /* USAGE (Tip Pressure) */ \
0x45, 0x00, \
\
0x26, DESC_CONFIG_WORD(PRESSURE_MAX), /* LOGICAL_MAXIMUM*/ \
0x81, 0x42, /* INPUT (Data,Var,Abs) */ \
/*=====================Interfce 0 === Tilt 20 bytes============*/ \
0x09, 0x3D, /* USAGE( X Tilt) */ \
0x15, 0x81, /* Logical Minimum (-127) */ \
0x25, 0x7F, /* Logical Maximum (127) */ \
0x75, 0x08, /* REPORT_SIZE (8) */ \
0x95, 0x01, /* REPORT_COUNT (1) */ \
0x81, 0x02, /* INPUT (Data,Var,Abs) */ \
0x09, 0x3E, /* USAGE( Y Tilt) */ \
0x15, 0x81, /* Logical Minimum (-127) */ \
0x25, 0x7F, /* Logical Maximum (127) */ \
0x81, 0x02, /* INPUT (Data,Var,Abs) */ \
0xC0, /* end collection */ \
0xC0, /* end collection */ \
}
#define APP_USBD_HID_GENERIC_REPORT_DSC() { \
0x06, 0x0A, 0xFF, /* Usage Page (Vendor-Defined 11) */ \
0x09, 0x01, /* Usage (Vendor-Defined 11) */ \
0xA1, 0x01, /* Collection (Application) */ \
0x85, 0x02, /* REPORT_ID (mouse) */ \
0x09, 0x02, /* Usage (Vendor-Defined 1) */ \
0x75, 0x08, /* Report Size (8) */ \
0x95, 0x0b, /* Report Count (20) */ \
0x15, 0x00, /* Usage Minimum (0) */ \
0x26, 0xFF, 0x00, /* Usage Maximum (255) */ \
0x81, 0x02, /* Output (Data,Var,Abs) */ \
0x09, 0x03, /* Usage (Vendor-Defined 3) */ \
0x75, 0x08, /* Report Size (8) */ \
0x95, 0x20, /* Report Count (32) */ \
0x15, 0x00, /* Logical Minimum (0) */ \
0x26, 0xFF, 0x00, /* Logical Maximum (255) */ \
0x91, 0x02, /* input (Data,Var,Abs) */ \
0xC0 /* END_COLLECTION */ \
}
三、业务USB功能
/********************************************************************************
* @file biz_usb.c
* @author jianqiang.xue
* @version V1.0.0
* @date 2021-07-20
* @brief [业务] usb管理
********************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include <stdbool.h>
#include <string.h>
#include "nrf.h"
#include "nrf_drv_clock.h"
#include "nrf_drv_power.h"
#include "nrf_error.h"
#include "app_usbd.h"
#include "app_usbd_core.h"
#include "app_usbd_hid_generic.h"
#include "app_usbd_hid_mouse.h"
#include "app_usbd_serial_num.h"
#include "app_util.h"
/* Private Includes ----------------------------------------------------------*/
#include "business_function.h"
#include "business_gpio.h"
#include "log.h"
#include "os_api.h"
#include "biz_usb_hid.h"
#include "biz_usb.h"
/* Private Define ------------------------------------------------------------*/
#ifndef USBD_POWER_DETECTION
#define USBD_POWER_DETECTION true
#endif
#define HID_MOUSE_INTERFACE 0
#define HID_TABLET_INTERFACE 1
#define HID_GENERIC_INTERFACE 2
#define GENERIC_REPORT_IN_QUEUE_SIZE 63
#define GENERIC_REPORT_OUT_MAXSIZE 63
#define MOUSE_REPORT_IN_QUEUE_SIZE 10
#define MOUSE_REPORT_OUT_MAXSIZE 7
#define TABLET_REPORT_IN_QUEUE_SIZE 10
#define TABLET_REPORT_OUT_MAXSIZE 9
#define GENERIC_REPORT_FEATURE_MAXSIZE 63
#define MOUSE_REPORT_FEATURE_MAXSIZE 31
#define TABLET_REPORT_FEATURE_MAXSIZE 31
#define HID_GENERIC_EPIN NRF_DRV_USBD_EPIN3
#define HID_GENERIC_EPOUT NRF_DRV_USBD_EPOUT3
#define HID_MOUSE_EPIN NRF_DRV_USBD_EPIN1
#define HID_TABLET_EPIN NRF_DRV_USBD_EPIN2
#define SIGNAL_USB_MSG (1<<0)
/* Private Macro -------------------------------------------------------------*/
static void hid_generic_ev_handler(app_usbd_class_inst_t const * p_inst, app_usbd_hid_user_event_t event);
static void hid_user_ev_handler(app_usbd_class_inst_t const * p_inst, app_usbd_hid_user_event_t event);
// usb信息
biz_usb_info_t g_biz_usb_info = {
.pid = APP_USBD_PID,
.channel = USB_DEVICE_DATA_MODE_STANDARD_PEN, // 0--鼠标模式 1--标准笔模式 4-- 自定义数据模式
.angle = 0 // 0--NULL 1--默认 2--顺时针90° 3--顺时针180° 4--顺时针270°
};
/* External Variables --------------------------------------------------------*/
/* Private Variables ---------------------------------------------------------*/
#define GENERIC_ENDPOINT_LIST() \
( \
HID_GENERIC_EPIN, \
HID_GENERIC_EPOUT \
)
#define MOUSE_ENDPOINT_LIST() \
( \
HID_MOUSE_EPIN \
)
#define TABLET_ENDPOINT_LIST() \
( \
HID_TABLET_EPIN \
)
APP_USBD_HID_GENERIC_SUBCLASS_REPORT_DESC(mouse_desc, APP_USBD_HID_MOUSE_REPORT_DSC());
static const app_usbd_hid_subclass_desc_t *mouse_reps[] = {&mouse_desc};
APP_USBD_HID_GENERIC_SUBCLASS_REPORT_DESC(tablet_desc, APP_USBD_HID_TABLET_REPORT_DSC());
static const app_usbd_hid_subclass_desc_t *tablet_reps[] = {&tablet_desc};
APP_USBD_HID_GENERIC_SUBCLASS_REPORT_DESC(generic_desc, APP_USBD_HID_GENERIC_REPORT_DSC());
static const app_usbd_hid_subclass_desc_t * generic_reps[] = {&generic_desc};
APP_USBD_HID_GENERIC_GLOBAL_DEF(m_app_hid_mouse,
HID_MOUSE_INTERFACE,
hid_user_ev_handler,
MOUSE_ENDPOINT_LIST(),
mouse_reps,
MOUSE_REPORT_IN_QUEUE_SIZE,
MOUSE_REPORT_OUT_MAXSIZE,
MOUSE_REPORT_FEATURE_MAXSIZE,
APP_USBD_HID_SUBCLASS_NONE,
APP_USBD_HID_PROTO_MOUSE);
APP_USBD_HID_GENERIC_GLOBAL_DEF(m_app_hid_tablet,
HID_TABLET_INTERFACE,
hid_user_ev_handler,
TABLET_ENDPOINT_LIST(),
tablet_reps,
TABLET_REPORT_IN_QUEUE_SIZE,
TABLET_REPORT_OUT_MAXSIZE,
TABLET_REPORT_FEATURE_MAXSIZE,
APP_USBD_HID_SUBCLASS_NONE,
APP_USBD_HID_PROTO_MOUSE);
APP_USBD_HID_GENERIC_GLOBAL_DEF(m_app_hid_generic,
HID_GENERIC_INTERFACE,
hid_generic_ev_handler,
GENERIC_ENDPOINT_LIST(),
generic_reps,
GENERIC_REPORT_IN_QUEUE_SIZE,
GENERIC_REPORT_OUT_MAXSIZE,
GENERIC_REPORT_FEATURE_MAXSIZE,
APP_USBD_HID_SUBCLASS_NONE,
APP_USBD_HID_PROTO_GENERIC);
/* Private Function Prototypes -----------------------------------------------*/
/**
* @brief [m_app_hid_generic]通用类通道 事件回调
* @param p_inst: 通道信息结构体
* @param event: 事件类型
*/
static void hid_generic_ev_handler(app_usbd_class_inst_t const * p_inst, app_usbd_hid_user_event_t event)
{
switch (event)
{
case APP_USBD_HID_USER_EVT_OUT_REPORT_READY:
{
size_t size;
uint8_t *ptr;
ptr = (uint8_t *)app_usbd_hid_generic_out_report_get(&m_app_hid_generic, &size);
LOG_D("<DEBUG> [USB_RX] %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x|%d\r\n",
ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7], ptr[8], ptr[9], ptr[10], ptr[11], ptr[12], ptr[13], ptr[14], size);
if(ptr);
// 将接到的数据交给外部处理 (自行补充)
// xxxx(ptr, size);
break;
}
default:
break;
}
}
/**
* @brief [m_app_hid_mouse/m_app_hid_tablet]键鼠类通道 事件回调
* @param p_inst: 通道信息结构体
* @param event: 事件类型
*/
static void hid_user_ev_handler(app_usbd_class_inst_t const * p_inst, app_usbd_hid_user_event_t event)
{
}
static void usbd_user_ev_handler(app_usbd_event_type_t event)
{
switch (event)
{
case APP_USBD_EVT_DRV_SOF:
break;
case APP_USBD_EVT_DRV_SUSPEND:
app_usbd_suspend_req(); // Allow the library to put the peripheral into sleep mode
break;
case APP_USBD_EVT_DRV_RESUME:
break;
case APP_USBD_EVT_STARTED:
break;
case APP_USBD_EVT_STOPPED:
app_usbd_disable();
break;
case APP_USBD_EVT_POWER_DETECTED:
if (!nrf_drv_usbd_is_enabled())
{
app_usbd_enable();
}
break;
case APP_USBD_EVT_POWER_REMOVED:
app_usbd_stop();
break;
case APP_USBD_EVT_POWER_READY:
app_usbd_start();
break;
default:
break;
}
}
/**
* @brief 启动USB驱动
* @retval 状态值
*/
uint8_t biz_usb_start(void)
{
ret_code_t ret = NRF_SUCCESS;
if (USBD_POWER_DETECTION)
{
ret = app_usbd_power_events_enable();
APP_ERROR_CHECK(ret);
}
else
{
app_usbd_enable();
app_usbd_start();
}
return (uint8_t)ret;
}
void biz_usb_stop(void)
{
app_usbd_disable();
}
uint8_t biz_usb_generic_send(const void *buff, size_t size)
{
return app_usbd_hid_generic_in_report_set(&m_app_hid_generic, buff, size);
}
uint8_t biz_usb_mouse_send(const void *buff, size_t size)
{
return app_usbd_hid_generic_in_report_set(&m_app_hid_mouse, buff, size);
}
uint8_t biz_usb_tablet_send(const void *buff, size_t size)
{
return app_usbd_hid_generic_in_report_set(&m_app_hid_tablet, buff, size);
}
uint8_t biz_usb_drives_init(void)
{
ret_code_t ret = NRF_SUCCESS;
static const app_usbd_config_t usbd_config = {
.ev_state_proc = usbd_user_ev_handler,
};
nrf_drv_clock_init();
nrf_drv_clock_lfclk_request(NULL);
while(!nrf_drv_clock_lfclk_is_running())
{
}
ret = app_usbd_init(&usbd_config);
APP_ERROR_CHECK(ret);
app_usbd_class_inst_t const * class_inst_generic;
// 注册鼠标接口
class_inst_generic = app_usbd_hid_generic_class_inst_get(&m_app_hid_mouse);
ret = app_usbd_class_append(class_inst_generic);
APP_ERROR_CHECK(ret);
// 注册数位板/屏接口
class_inst_generic = app_usbd_hid_generic_class_inst_get(&m_app_hid_tablet);
ret = app_usbd_class_append(class_inst_generic);
APP_ERROR_CHECK(ret);
// 厂商自定义数据格式接口
class_inst_generic = app_usbd_hid_generic_class_inst_get(&m_app_hid_generic);
ret = app_usbd_class_append(class_inst_generic);
APP_ERROR_CHECK(ret);
return (uint8_t)ret;
}
/**
* @brief 得到usb_info结构体指针
*/
void* get_usb_info_p(void)
{
return &g_biz_usb_info;
}
uint16_t get_usb_pid(void)
{
return g_biz_usb_info.pid;
}
void set_usb_pid(uint16_t pid)
{
g_biz_usb_info.pid = pid;
}
void set_current_android_angle(uint8_t angle)
{
if (g_biz_usb_info.angle != angle)
{
g_biz_usb_info.write_in = true;
}
g_biz_usb_info.angle = angle;
}
uint8_t get_current_android_angle(void)
{
if(g_biz_usb_info.angle == 0)
{
g_biz_usb_info.angle = 2;
}
return g_biz_usb_info.angle;
}
/**
* @brief 设置当前usb数据通讯模式
* @param channel: USB_DEVICE_DATA_MODE_MOUSE = 1 (鼠标模式), USB_DEVICE_DATA_MODE_STANDARD_PEN = 2 (标准笔模式)
USB_DEVICE_DATA_MODE_CUSTOM = 4 (自定义数据模式)
*/
void set_usb_comm_channel(usb_device_data_mode_t channel)
{
g_biz_usb_info.channel = channel;
LOG_D("<DEBUG> set channel:%d \r\n", channel);
}
/**
* @brief 获取当前usb数据通讯模式
* @retval USB_DEVICE_DATA_MODE_MOUSE = 1 (鼠标模式), USB_DEVICE_DATA_MODE_STANDARD_PEN = 2 (标准笔模式)
USB_DEVICE_DATA_MODE_CUSTOM = 4 (自定义数据模式)
*/
usb_device_data_mode_t get_usb_comm_channel(void)
{
// 如无模式,则默认使用标准笔模式
if (g_biz_usb_info.channel == 0)
{
g_biz_usb_info.channel = USB_DEVICE_DATA_MODE_STANDARD_PEN;
}
return g_biz_usb_info.channel;
}
/**
* @brief 检测usb驱动是否启动
* @retval 0--未启动 1--启动
*/
bool biz_get_usbd_active_check(void)
{
return app_usbd_active_check();
}