Hi,
I am trying to implement Generic HID that can transmit/receive data like CDC using the generic HID example source of nRF52820 SDK 17.0.2.
But I can't do both sending and receiving data. The HID descriptor is a setting value previously used when initializing HID in other MCU.
What is wrong??? Are there any projects I can refer to?
static bool m_report_pending;
/**
* @brief User event handler.
* */
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);
/**
* @brief Mouse state
*
* Current mouse status
*/
struct
{
int16_t acc_x; /**< Accumulated x state */
int16_t acc_y; /**< Accumulated y state */
uint8_t btn; /**< Current btn state */
uint8_t last_btn; /**< Last transfered button state */
}m_mouse_state;
/**
* @brief Mark the ongoing transmission
*
* Marks that the report buffer is busy and cannot be used until transmission finishes
* or invalidates (by USB reset or suspend event).
*/
#define APP_USBD_HID_METER_REPORT_DSC() { \
0x06, 0x80, 0xFF, /* USAGE_PAGE | Vender Define */ \
0x09, 0x01, /* USAGE | Vender Define */ \
0xa1, 0x01, /* COLLECTION | Application */ \
0x06, 0xFF, 0xFF, /* Usage Page | Vender Define */ \
0x19, 0x00, /* Usage Minimum | 0 */ \
0x29, 0x7F, /* Usage Maximum | 127 */ \
0x15, 0x00, /* Logical Minimum | 0 */ \
0x25, 0x7F, /* Logical Maximum | 127 */ \
0x75, 0x08, /* Report Size | 8�r�b�g */ \
0x95, 0x40, /* Report Count | 64 */ \
0x81, 0x02, /* Input | Variable */ \
0x06, 0xFF, 0xFF, /* Usage Page | Vender Define */ \
0x19, 0x00, /* Usage Minimum | 0 */ \
0x29, 0x7F, /* Usage Maximum | 127 */ \
0x15, 0x00, /* Logical Minimum | 0 */ \
0x25, 0x7F, /* Logical Maximum | 127 */ \
0x75, 0x08, /* Report Size | 8�r�b�g */ \
0x95, 0x40, /* Report Count | 64 */ \
0x91, 0x02, /* Output | Variable */ \
0xc0 /* END_COLLECTION */ \
}
/**
* @brief Reuse HID mouse report descriptor for HID generic class
*/
APP_USBD_HID_GENERIC_SUBCLASS_REPORT_DESC(meter_desc,APP_USBD_HID_METER_REPORT_DSC());
static const app_usbd_hid_subclass_desc_t * reps[] = {&meter_desc};
/*lint -save -e26 -e64 -e123 -e505 -e651*/
/**
* @brief Global HID generic instance
*/
APP_USBD_HID_GENERIC_GLOBAL_DEF(m_app_hid_generic,
HID_GENERIC_INTERFACE,
hid_user_ev_handler,
ENDPOINT_LIST(),
reps,
REPORT_IN_QUEUE_SIZE,
REPORT_OUT_MAXSIZE,
REPORT_FEATURE_MAXSIZE,
APP_USBD_HID_SUBCLASS_NONE,
APP_USBD_HID_PROTO_GENERIC);
static const app_usbd_config_t usbd_config = {
.ev_state_proc = usbd_user_ev_handler
};
//===============================================================================================
//= Explanation : =
//= Argument(s) : =
//= Return Value: =
//= Comment : =
//===============================================================================================
/**
* @brief Get maximal allowed accumulated value
*
* Function gets maximal value from the accumulated input.
* @sa m_mouse_state::acc_x, m_mouse_state::acc_y
*/
static int8_t hid_acc_for_report_get(int16_t acc)
{
if(acc > INT8_MAX)
{
return INT8_MAX;
}
else if(acc < INT8_MIN)
{
return INT8_MIN;
}
else
{
return (int8_t)(acc);
}
}
static ret_code_t idle_handle(app_usbd_class_inst_t const * p_inst, uint8_t report_id)
{
switch (report_id)
{
case 0:
{
uint8_t report[] = {0xBE, 0xEF};
return app_usbd_hid_generic_idle_report_set(
&m_app_hid_generic,
report,
sizeof(report));
}
default:
return NRF_ERROR_NOT_SUPPORTED;
}
}
/**
* @brief Internal function that process mouse state
*
* This function checks current mouse state and tries to send
* new report if required.
* If report sending was successful it clears accumulated positions
* and mark last button state that was transfered.
*/
global void hid_generic_mouse_process_state(void)
{
if (m_report_pending)
return;
if ((m_mouse_state.acc_x != 0) || (m_mouse_state.acc_y != 0) || (m_mouse_state.btn != m_mouse_state.last_btn))
{
ret_code_t ret;
static uint8_t report[HID_REP_SIZE];
/* We have some status changed that we need to transfer */
report[HID_BTN_IDX] = m_mouse_state.btn;
report[HID_X_IDX] = (uint8_t)hid_acc_for_report_get(m_mouse_state.acc_x);
report[HID_Y_IDX] = (uint8_t)hid_acc_for_report_get(m_mouse_state.acc_y);
/* Start the transfer */
ret = app_usbd_hid_generic_in_report_set(
&m_app_hid_generic,
report,
sizeof(report));
if (ret == NRF_SUCCESS)
{
m_report_pending = true;
m_mouse_state.last_btn = report[HID_BTN_IDX];
CRITICAL_REGION_ENTER();
/* This part of the code can fail if interrupted by BSP keys processing.
* Lock interrupts to be safe */
m_mouse_state.acc_x -= (int8_t)report[HID_X_IDX];
m_mouse_state.acc_y -= (int8_t)report[HID_Y_IDX];
CRITICAL_REGION_EXIT();
}
}
}
/**
* @brief HID generic IN report send handling
* */
global void hid_generic_mouse_action(hid_generic_mouse_action_t action, int8_t param)
{
CRITICAL_REGION_ENTER();
/*
* Update mouse state
*/
switch (action)
{
#if 0
case HID_GENERIC_MOUSE_X:
m_mouse_state.acc_x += param;
break;
case HID_GENERIC_MOUSE_Y:
m_mouse_state.acc_y += param;
break;
#endif
case HID_GENERIC_MOUSE_BTN_RIGHT:
if(param == 1)
{
m_mouse_state.btn |= HID_BTN_RIGHT_MASK;
}
else
{
m_mouse_state.btn &= ~HID_BTN_RIGHT_MASK;
}
break;
case HID_GENERIC_MOUSE_BTN_LEFT:
if(param == 1)
{
m_mouse_state.btn |= HID_BTN_LEFT_MASK;
}
else
{
m_mouse_state.btn &= ~HID_BTN_LEFT_MASK;
}
break;
}
CRITICAL_REGION_EXIT();
}
size_t out_report_size;
uint8_t *out_report;
uint8_t out_report_0;
uint8_t out_report_1;
uint8_t out_report_2;
uint8_t out_report_3;
/**
* @brief Class specific event handler.
*
* @param p_inst Class instance.
* @param event Class specific event.
* */
static void hid_user_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:
{
/* No output report defined for this example.*/
out_report = (uint8_t *) app_usbd_hid_generic_out_report_get(&m_app_hid_generic, &out_report_size);
out_report_0 = out_report[0];
out_report_1 = out_report[1];
out_report_2 = out_report[2];
out_report_3 = out_report[3];
//ASSERT(0);
break;
}
case APP_USBD_HID_USER_EVT_IN_REPORT_DONE:
{
m_report_pending = false;
hid_generic_mouse_process_state();
//bsp_board_led_invert(LED_HID_REP_IN);
break;
}
case APP_USBD_HID_USER_EVT_SET_BOOT_PROTO:
{
UNUSED_RETURN_VALUE(hid_generic_clear_buffer(p_inst));
NRF_LOG_INFO("SET_BOOT_PROTO");
break;
}
case APP_USBD_HID_USER_EVT_SET_REPORT_PROTO:
{
UNUSED_RETURN_VALUE(hid_generic_clear_buffer(p_inst));
NRF_LOG_INFO("SET_REPORT_PROTO");
break;
}
default:
break;
}
}
/**
* @brief USBD library specific event handler.
*
* @param event USBD library 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_RESET:
m_report_pending = false;
break;
case APP_USBD_EVT_DRV_SUSPEND:
m_report_pending = false;
app_usbd_suspend_req(); // Allow the library to put the peripheral into sleep mode
//bsp_board_leds_off();
break;
case APP_USBD_EVT_DRV_RESUME:
m_report_pending = false;
//bsp_board_led_on(LED_USB_START);
break;
case APP_USBD_EVT_STARTED:
m_report_pending = false;
//bsp_board_led_on(LED_USB_START);
break;
case APP_USBD_EVT_STOPPED:
app_usbd_disable();
//bsp_board_leds_off();
break;
case APP_USBD_EVT_POWER_DETECTED:
NRF_LOG_INFO("USB power detected");
if (!nrf_drv_usbd_is_enabled())
{
app_usbd_enable();
}
break;
case APP_USBD_EVT_POWER_REMOVED:
NRF_LOG_INFO("USB power removed");
app_usbd_stop();
break;
case APP_USBD_EVT_POWER_READY:
NRF_LOG_INFO("USB ready");
app_usbd_start();
break;
default:
break;
}
}
//===============================================================================================
//= Explanation : =
//= Argument(s) : =
//= Return Value: =
//= Comment : =
//===============================================================================================
global void gvUSB_HID_Initialize()
{
ret_code_t ret;
ret = app_usbd_init(&usbd_config);
APP_ERROR_CHECK(ret);
NRF_LOG_INFO("USBD HID generic example started.");
//EPIN
app_usbd_class_inst_t const * class_inst_generic;
class_inst_generic = app_usbd_hid_generic_class_inst_get(&m_app_hid_generic);
ret = hid_generic_idle_handler_set(class_inst_generic, idle_handle);
APP_ERROR_CHECK(ret);
ret = app_usbd_class_append(class_inst_generic);
APP_ERROR_CHECK(ret);
#if 0
//EPOUT
class_inst_generic = app_usbd_hid_generic_class_inst_get(&m_app_hid_generic);
ret = hid_generic_idle_handler_set(class_inst_generic, idle_handle);
APP_ERROR_CHECK(ret);
ret = app_usbd_class_append(class_inst_generic);
APP_ERROR_CHECK(ret);
#endif
if (USBD_POWER_DETECTION)
{
ret = app_usbd_power_events_enable();
APP_ERROR_CHECK(ret);
}
else
{
NRF_LOG_INFO("No USB power detection enabled\r\nStarting USB now");
app_usbd_enable();
app_usbd_start();
}
}