打造一个通用性MCU架构,支持CX32/AT32/NRF51/NRF52等。 OS支持RTX4/RTX5/FreeRtos。 采用VsCode+GCC组合,VsCode+KEIL5,超强开发方式。 QQ群:524408033

LiSun

打造一个通用性MCU架构,支持CX32/AT32/NRF51/NRF52等。 OS支持RTX4/RTX5/FreeRtos。 采用VsCode+GCC组合,VsCode+KEIL5,超强开发方式。 QQ群:524408033

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

USB设备(USBD)控制器实现全速USB设备功能,满足2.0版本的USB规范。
在这里插入图片描述
这里列出的是USBD的主要特性:

  • 全速度(12mbps)设备完全符合通用串行总线规范修订2.0,包括以下是USB实施者论坛发布的工程更改通知:
  1. 上拉/下拉电阻ECN
  2. 5V短路耐受要求变更ECN
  • USB设备栈在北欧SDK中可用
  • 集成(芯片上)USB收发器(PHY)
  • 软件控制的芯片上拉在D+
  • 端点:
  1. 两个控制(1 IN, 1 OUT)
  2. 14 bulk/interrupt (7 IN, 7 OUT)
  3. 两个同步(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();
}

posted on 2022-08-13 11:00  xuejianqiang  阅读(474)  评论(0编辑  收藏  举报
打造一个通用性MCU架构,支持CX32/AT32/NRF51/NRF52等。 OS支持RTX4/RTX5/FreeRtos。 采用VsCode+GCC组合,VsCode+KEIL5,超强开发方式。 QQ群:524408033