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(); } }