This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

nRF52820 USB Generic HID communication

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

Parents
  • Hi

    What exactly do you mean by "I can't do both sending and receiving data". Are you trying to send and receive simultaneously or what? Can you explain in detail what you're trying to do and what problems/errors you're seeing when trying to implement it?

    Best regards,

    Simon

  • Hi.

    After I modified as below, sending data from PC to my device via generic HID was successful.

    #define REPORT_OUT_MAXSIZE  63	//0
    
    /**
     * @brief Feature report maximum size. HID generic class will reserve
     *        this buffer size + 1 memory space. 
     */
    #define REPORT_FEATURE_MAXSIZE  31
    
    /**
     * @brief HID generic class endpoints count.
     * */
    #define HID_GENERIC_EP_COUNT  2
    
    /**
     * @brief List of HID generic class endpoints.
     * */
    #define ENDPOINT_LIST()                                      \
    (                                                            \
            HID_GENERIC_EPIN,                                     \
            HID_GENERIC_EPOUT                                     \
    )

    However, sending data to PC using app_usbd_hid_generic_in_report_set on my device does not work.

    What's wrong with settings?

Reply
  • Hi.

    After I modified as below, sending data from PC to my device via generic HID was successful.

    #define REPORT_OUT_MAXSIZE  63	//0
    
    /**
     * @brief Feature report maximum size. HID generic class will reserve
     *        this buffer size + 1 memory space. 
     */
    #define REPORT_FEATURE_MAXSIZE  31
    
    /**
     * @brief HID generic class endpoints count.
     * */
    #define HID_GENERIC_EP_COUNT  2
    
    /**
     * @brief List of HID generic class endpoints.
     * */
    #define ENDPOINT_LIST()                                      \
    (                                                            \
            HID_GENERIC_EPIN,                                     \
            HID_GENERIC_EPOUT                                     \
    )

    However, sending data to PC using app_usbd_hid_generic_in_report_set on my device does not work.

    What's wrong with settings?

Children
Related