nrf52840 DK usbhid generic received message divided to multi packet

Hi,

I'm using nrf52840 DK to connect and receive usbhid message with the message size > 64 bytes (examples 343 bytes), so the message is divided to multi packages. I modified usb_hid_generic example, but I just received 2 packages. That is some change in my code:

#define REPORT_IN_QUEUE_SIZE    63
#define REPORT_OUT_MAXSIZE  63
#define REPORT_FEATURE_MAXSIZE  31

#define ENDPOINT_LIST()                                      \
(                                                            \
        HID_GENERIC_EPIN,                                     \
        HID_GENERIC_EPOUT                                    \
)

static void hid_user_ev_handler(app_usbd_class_inst_t const * p_inst,
                                app_usbd_hid_user_event_t event);

#define USBD_GENERIC_REPORT_DESCRIPTOR { \
  0x06, 0xD0, 0xF1 , /*USAGE_PAGE (FIDO Alliance) */ \
  0x09, 0x01 , /* USAGE (U2F HID Authenticator Device) */ \
  0xa1, 0x01 , /* COLLECTION (Application) */ \
  0x09, 0x20 , /*   USAGE (Input Report Data) */ \
  0x15, 0x00 , /*   LOGICAL_MINIMUM (0) */ \
  0x26, 0xff, 0x00 , /*   LOGICAL_MAXIMUM (255) */ \
  0x75, 0x08 , /*   REPORT_SIZE (8) */ \
  0x95, 0x40 , /*   REPORT_COUNT (64) */ \
  0x81, 0x02 , /*   INPUT (Data,Var,Abs) */ \
  0x09, 0x21 , /*   USAGE(Output Report Data) */ \
  0x15, 0x00 , /*   LOGICAL_MINIMUM (0) */ \
  0x26, 0xff, 0x00 , /*   LOGICAL_MAXIMUM (255) */ \
  0x75, 0x08 , /*   REPORT_SIZE (8) */ \
  0x95, 0x40 , /*   REPORT_COUNT (64) */ \
  0x91, 0x02 , /*   OUTPUT (Data,Var,Abs) */ \
  0xc0 , /* END_COLLECTION */ \
}
APP_USBD_HID_GENERIC_SUBCLASS_REPORT_DESC(mouse_desc,USBD_GENERIC_REPORT_DESCRIPTOR);
static const app_usbd_hid_subclass_desc_t * reps[] = {&mouse_desc};
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 void hid_user_ev_handler(app_usbd_class_inst_t const * p_inst,
                                app_usbd_hid_user_event_t event)
{
    NRF_LOG_INFO("hid_user_ev_handler %d", event);
    switch (event)
    {
        case APP_USBD_HID_USER_EVT_OUT_REPORT_READY:
        {
            NRF_LOG_INFO("APP_USBD_HID_USER_EVT_OUT_REPORT_READY");
            size_t recv_size;
            uint8_t* recv_buf;
            recv_buf = (uint8_t *)app_usbd_hid_generic_out_report_get(&m_app_hid_generic,&recv_size);
            NRF_LOG_INFO("received data length:%d", recv_size);
            NRF_LOG_HEXDUMP_INFO(recv_buf, recv_size);
            break;
        }
        case APP_USBD_HID_USER_EVT_IN_REPORT_DONE:
        {
            NRF_LOG_INFO("APP_USBD_HID_USER_EVT_IN_REPORT_DONE");
            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:
            NRF_LOG_INFO("UNDEFINDED_EVENT %d", event);
            break;
    }
}
What is problem in here?
Thanks!
  • Hi

    I am a bit confused by your report descriptor. It seems to set up 64 bytes of IN data and 64 bytes of OUT data, not more than that. 

    Are you using a different descriptor when trying to send more than 64 bytes in one go?

    When you receive two packets, how much data is there in each packet?

    Best regards
    Torbjørn

  • report

    Hi

    I want to setup a full-speed usb device with two 64-bits endpoints (1 IN and 1 OUT).

    I just changed report descriptor (USBD_GENERIC_REPORT_DESCRIPTOR) in examples/peripheral/usbd_hid_generic.

    I want to received a message (>300 bytes) but I just received 2 packets:

    In Packet 1: Len = 0x0157 = 343 bytes is length of message, Data has length = 64 - 4 (CID bytes) -1 (CMD) - 2 (Len) = 57 bytes

    In Packet 2: index is index of continue packet, Data has length = 64 - 4 - 1 = 59 bytes

    Packet 3 has 59 bytes data with index = 01, but I don't receive it and following packets

    And one more infomation, I tested on macOS 10.14.6

    Please help me, thanks!

  • Hi, it is main.c for test, please replace main.c in examples/peripheral/usbd_hid_generic and test with https://www.passwordless.dev/passwordless#heroFoot 

    8750.main.c
    /**
     * Copyright (c) 2017 - 2019, Nordic Semiconductor ASA
     *
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without modification,
     * are permitted provided that the following conditions are met:
     *
     * 1. Redistributions of source code must retain the above copyright notice, this
     *    list of conditions and the following disclaimer.
     *
     * 2. Redistributions in binary form, except as embedded into a Nordic
     *    Semiconductor ASA integrated circuit in a product or a software update for
     *    such product, must reproduce the above copyright notice, this list of
     *    conditions and the following disclaimer in the documentation and/or other
     *    materials provided with the distribution.
     *
     * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
     *    contributors may be used to endorse or promote products derived from this
     *    software without specific prior written permission.
     *
     * 4. This software, with or without modification, must only be used with a
     *    Nordic Semiconductor ASA integrated circuit.
     *
     * 5. Any software provided in binary form under this license must not be reverse
     *    engineered, decompiled, modified and/or disassembled.
     *
     * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
     * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
     * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
     * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
     * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
     * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     *
     */
    #include <stdint.h>
    #include <stdbool.h>
    #include <stddef.h>
    
    #include "nrf.h"
    #include "app_util_platform.h"
    #include "nrf_drv_usbd.h"
    #include "nrf_drv_clock.h"
    #include "nrf_gpio.h"
    #include "nrf_drv_power.h"
    
    #include "app_timer.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_hid_kbd.h"
    #include "app_error.h"
    #include "bsp.h"
    
    #include "bsp_cli.h"
    #include "nrf_cli.h"
    #include "nrf_cli_uart.h"
    
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    
    #if NRF_CLI_ENABLED
    /**
     * @brief CLI interface over UART
     */
    NRF_CLI_UART_DEF(m_cli_uart_transport, 0, 64, 16);
    NRF_CLI_DEF(m_cli_uart,
                "uart_cli:~$ ",
                &m_cli_uart_transport.transport,
                '\r',
                4);
    #endif
    
    /**
     * @brief Enable USB power detection
     */
    #ifndef USBD_POWER_DETECTION
    #define USBD_POWER_DETECTION true
    #endif
    
    /**
     * @brief HID generic class interface number.
     * */
    #define HID_GENERIC_INTERFACE  0
    
    /**
     * @brief HID generic class endpoint number.
     * */
    #define HID_GENERIC_EPIN       NRF_DRV_USBD_EPIN1
    #define HID_GENERIC_EPOUT       NRF_DRV_USBD_EPOUT1
    
    /**
     * @brief Mouse speed (value sent via HID when board button is pressed).
     * */
    #define CONFIG_MOUSE_MOVE_SPEED (3)
    
    /**
     * @brief Mouse move repeat time in milliseconds
     */
    #define CONFIG_MOUSE_MOVE_TIME_MS (5)
    
    
    /* GPIO used as LED & buttons in this example */
    #define LED_USB_START    (BSP_BOARD_LED_0)
    #define LED_HID_REP_IN   (BSP_BOARD_LED_2)
    
    #define BTN_MOUSE_X_POS  0
    #define BTN_MOUSE_Y_POS  1
    #define BTN_MOUSE_LEFT   2
    #define BTN_MOUSE_RIGHT  3
    
    /**
     * @brief Left button mask in buttons report
     */
    #define HID_BTN_LEFT_MASK  (1U << 0)
    
    /**
     * @brief Right button mask in buttons report
     */
    #define HID_BTN_RIGHT_MASK (1U << 1)
    
    /* HID report layout */
    #define HID_BTN_IDX   0 /**< Button bit mask position */
    #define HID_X_IDX     1 /**< X offset position */
    #define HID_Y_IDX     2 /**< Y offset position */
    #define HID_W_IDX     3 /**< Wheel position  */
    #define HID_REP_SIZE  4 /**< The size of the report */
    
    /**
     * @brief Number of reports defined in report descriptor.
     */
    #define REPORT_IN_QUEUE_SIZE    63
    
    /**
     * @brief Size of maximum output report. HID generic class will reserve
     *        this buffer size + 1 memory space. 
     *
     * Maximum value of this define is 63 bytes. Library automatically adds
     * one byte for report ID. This means that output report size is limited
     * to 64 bytes.
     */
    #define REPORT_OUT_MAXSIZE  63
    
    /**
     * @brief Feature report maximum size. HID generic class will reserve
     *        this buffer size + 1 memory space. 
     */
    #define REPORT_FEATURE_MAXSIZE  63
    
    /**
     * @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                                    \
    )
    
    /**
     * @brief Additional key release events
     *
     * This example needs to process release events of used buttons
     */
    enum {
        BSP_USER_EVENT_RELEASE_0 = BSP_EVENT_KEY_LAST + 1, /**< Button 0 released */
        BSP_USER_EVENT_RELEASE_1,                          /**< Button 1 released */
        BSP_USER_EVENT_RELEASE_2,                          /**< Button 2 released */
        BSP_USER_EVENT_RELEASE_3,                          /**< Button 3 released */
        BSP_USER_EVENT_RELEASE_4,                          /**< Button 4 released */
        BSP_USER_EVENT_RELEASE_5,                          /**< Button 5 released */
        BSP_USER_EVENT_RELEASE_6,                          /**< Button 6 released */
        BSP_USER_EVENT_RELEASE_7,                          /**< Button 7 released */
    };
    
    /**
     * @brief HID generic mouse action types
     */
    typedef enum {
        HID_GENERIC_MOUSE_X,
        HID_GENERIC_MOUSE_Y,
        HID_GENERIC_MOUSE_BTN_LEFT,
        HID_GENERIC_MOUSE_BTN_RIGHT,
    } hid_generic_mouse_action_t;
    
    #define USBD_GENERIC_REPORT_DESCRIPTOR { \
      0x06, 0xD0, 0xF1 , /*USAGE_PAGE (FIDO Alliance) */ \
      0x09, 0x01 , /* USAGE (U2F HID Authenticator Device) */ \
      0xa1, 0x01 , /* COLLECTION (Application) */ \
      0x09, 0x20 , /*   USAGE (Input Report Data) */ \
      0x15, 0x00 , /*   LOGICAL_MINIMUM (0) */ \
      0x26, 0xff, 0x00 , /*   LOGICAL_MAXIMUM (255) */ \
      0x75, 0x08 , /*   REPORT_SIZE (8) */ \
      0x95, 0x40 , /*   REPORT_COUNT (64) */ \
      0x81, 0x02 , /*   INPUT (Data,Var,Abs) */ \
      0x09, 0x21 , /*   USAGE(Output Report Data) */ \
      0x15, 0x00 , /*   LOGICAL_MINIMUM (0) */ \
      0x26, 0xff, 0x00 , /*   LOGICAL_MAXIMUM (255) */ \
      0x75, 0x08 , /*   REPORT_SIZE (8) */ \
      0x95, 0x40 , /*   REPORT_COUNT (64) */ \
      0x91, 0x02 , /*   OUTPUT (Data,Var,Abs) */ \
      0xc0 , /* END_COLLECTION */ \
    }
    
    /**
     * @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);
    
    /**
     * @brief Reuse HID mouse report descriptor for HID generic class
     */
    APP_USBD_HID_GENERIC_SUBCLASS_REPORT_DESC(mouse_desc,USBD_GENERIC_REPORT_DESCRIPTOR);
    
    static const app_usbd_hid_subclass_desc_t * reps[] = {&mouse_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);
    
    /*lint -restore*/
    
    
    /**
     * @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).
     */
    static bool m_report_pending;
    static bool m_report_received = false;
    
    /**
     * @brief Timer to repeat mouse move
     */
    APP_TIMER_DEF(m_mouse_move_timer);
    
    /**
     * @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);
        }
    }
    
    /**
     * @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.
     */
    static 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
     * */
    static void hid_generic_mouse_action(hid_generic_mouse_action_t action, int8_t param)
    {
        CRITICAL_REGION_ENTER();
        /*
         * Update mouse state
         */
        switch (action)
        {
            case HID_GENERIC_MOUSE_X:
                m_mouse_state.acc_x += param;
                break;
            case HID_GENERIC_MOUSE_Y:
                m_mouse_state.acc_y += param;
                break;
            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();
    }
    
    /**
     * @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.*/
                NRF_LOG_INFO("APP_USBD_HID_USER_EVT_OUT_REPORT_READY");
                m_report_received = true;
                size_t recv_size;
                uint8_t* recv_buf;
                recv_buf = (uint8_t *)app_usbd_hid_generic_out_report_get(&m_app_hid_generic,&recv_size);
                NRF_LOG_INFO("received data length:%d", recv_size);
                NRF_LOG_HEXDUMP_INFO(recv_buf, recv_size);
                break;
            }
            case APP_USBD_HID_USER_EVT_IN_REPORT_DONE:
            {
                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;
        }
    }
    
    static void mouse_move_timer_handler(void * p_context)
    {
        UNUSED_PARAMETER(p_context);
        bool used = false;
    
        if (bsp_button_is_pressed(BTN_MOUSE_X_POS))
        {
            hid_generic_mouse_action(HID_GENERIC_MOUSE_X, CONFIG_MOUSE_MOVE_SPEED);
            used = true;
        }
        if (bsp_button_is_pressed(BTN_MOUSE_Y_POS))
        {
            hid_generic_mouse_action(HID_GENERIC_MOUSE_Y, CONFIG_MOUSE_MOVE_SPEED);
            used = true;
        }
    
        if(!used)
        {
            UNUSED_RETURN_VALUE(app_timer_stop(m_mouse_move_timer));
        }
    }
    
    static void bsp_event_callback(bsp_event_t ev)
    {
        switch ((unsigned int)ev)
        {
            case CONCAT_2(BSP_EVENT_KEY_, BTN_MOUSE_X_POS):
                hid_generic_mouse_action(HID_GENERIC_MOUSE_X, CONFIG_MOUSE_MOVE_SPEED);
                UNUSED_RETURN_VALUE(app_timer_start(m_mouse_move_timer, APP_TIMER_TICKS(CONFIG_MOUSE_MOVE_TIME_MS), NULL));
                break;
    
            case CONCAT_2(BSP_EVENT_KEY_, BTN_MOUSE_Y_POS):
                hid_generic_mouse_action(HID_GENERIC_MOUSE_Y, CONFIG_MOUSE_MOVE_SPEED);
                UNUSED_RETURN_VALUE(app_timer_start(m_mouse_move_timer, APP_TIMER_TICKS(CONFIG_MOUSE_MOVE_TIME_MS), NULL));
                break;
    
            case CONCAT_2(BSP_EVENT_KEY_, BTN_MOUSE_RIGHT):
                hid_generic_mouse_action(HID_GENERIC_MOUSE_BTN_RIGHT, 1);
                break;
            case CONCAT_2(BSP_USER_EVENT_RELEASE_, BTN_MOUSE_RIGHT):
                hid_generic_mouse_action(HID_GENERIC_MOUSE_BTN_RIGHT, -1);
                break;
    
            case CONCAT_2(BSP_EVENT_KEY_, BTN_MOUSE_LEFT):
                hid_generic_mouse_action(HID_GENERIC_MOUSE_BTN_LEFT, 1);
                break;
            case CONCAT_2(BSP_USER_EVENT_RELEASE_, BTN_MOUSE_LEFT):
                hid_generic_mouse_action(HID_GENERIC_MOUSE_BTN_LEFT, -1);
                break;
    
            default:
                return; // no implementation needed
        }
    }
    
    
    /**
     * @brief Auxiliary internal macro
     *
     * Macro used only in @ref init_bsp to simplify the configuration
     */
    #define INIT_BSP_ASSIGN_RELEASE_ACTION(btn)                      \
        APP_ERROR_CHECK(                                             \
            bsp_event_to_button_action_assign(                       \
                btn,                                                 \
                BSP_BUTTON_ACTION_RELEASE,                           \
                (bsp_event_t)CONCAT_2(BSP_USER_EVENT_RELEASE_, btn)) \
        )
    
    static void init_bsp(void)
    {
        ret_code_t ret;
        ret = bsp_init(BSP_INIT_BUTTONS, bsp_event_callback);
        APP_ERROR_CHECK(ret);
    
        INIT_BSP_ASSIGN_RELEASE_ACTION(BTN_MOUSE_LEFT );
        INIT_BSP_ASSIGN_RELEASE_ACTION(BTN_MOUSE_RIGHT);
    
        /* Configure LEDs */
        bsp_board_init(BSP_INIT_LEDS);
    }
    
    #if NRF_CLI_ENABLED
    static void init_cli(void)
    {
        ret_code_t ret;
        ret = bsp_cli_init(bsp_event_callback);
        APP_ERROR_CHECK(ret);
        nrf_drv_uart_config_t uart_config = NRF_DRV_UART_DEFAULT_CONFIG;
        uart_config.pseltxd = TX_PIN_NUMBER;
        uart_config.pselrxd = RX_PIN_NUMBER;
        uart_config.hwfc    = NRF_UART_HWFC_DISABLED;
        ret = nrf_cli_init(&m_cli_uart, &uart_config, true, true, NRF_LOG_SEVERITY_INFO);
        APP_ERROR_CHECK(ret);
        ret = nrf_cli_start(&m_cli_uart);
        APP_ERROR_CHECK(ret);
    }
    #endif
    
    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;
        }
        
    }
    
    void send_pkt(uint8_t * msg){
        ret_code_t ret;
        while (app_usbd_event_queue_process())
        {
            /* Nothing to do */
        }
    
        NRF_LOG_INFO("send_pkt");
        NRF_LOG_HEXDUMP_INFO(msg, 64);
        ret = app_usbd_hid_generic_in_report_set(
            &m_app_hid_generic,
            (uint8_t *)msg,
            64);
    
        if(ret == NRF_SUCCESS)
        {
            //NRF_LOG_INFO("send success");
        }
    }
    
    static void test_process(){
        size_t recv_size;
        uint8_t* recv_buf;
        uint8_t tx_buff[64];
        memset(tx_buff, 0, 64);
        m_report_received = false;
        recv_buf = (uint8_t *)app_usbd_hid_generic_out_report_get(&m_app_hid_generic,&recv_size);
    
        if (recv_buf[0] == 0xff){
            memcpy(tx_buff, recv_buf, 22);
            tx_buff[6] = 0x11;
            tx_buff[15] = 0x02;
            tx_buff[19] = 0x02;
            tx_buff[23] = 0x05;
            send_pkt(tx_buff);
        } else if (recv_buf[4]==0x90 && recv_buf[7]==0x04){
            uint8_t packet1[64] = {0x02,0x00,0x00,0x00,0x90,0x00,0x56,0x00,0xA6,0x01,0x82,0x66,0x55,0x32,0x46,0x5F,0x56,0x32,0x68,0x46,0x49,0x44,0x4F,0x5F,0x32,0x5F,0x30,0x02,0x81,0x6B,0x68,0x6D,0x61,0x63,0x2D,0x73,0x65,0x63,0x72,0x65,0x74,0x03,0x50,0x88,0x76,0x63,0x1B,0xD4,0xA0,0x42,0x7F,0x57,0x73,0x0E,0xC7,0x1C,0x9E,0x02,0x79,0x04,0xA4,0x62,0x72,0x6B};
            send_pkt(packet1);
            uint8_t packet2[64] = {0x02,0x00,0x00,0x00,0x00,0xF5,0x62,0x75,0x70,0xF5,0x64,0x70,0x6C,0x61,0x74,0xF4,0x69,0x63,0x6C,0x69,0x65,0x6E,0x74,0x50,0x69,0x6E,0xF4,0x05,0x19,0x04,0xB0,0x06,0x81,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
            send_pkt(packet2);
        }
    }
    
    int main(void)
    {
        ret_code_t ret;
        static const app_usbd_config_t usbd_config = {
            .ev_state_proc = usbd_user_ev_handler
        };
    
        ret = NRF_LOG_INIT(NULL);
        APP_ERROR_CHECK(ret);
    
        ret = nrf_drv_clock_init();
        APP_ERROR_CHECK(ret);
    
        nrf_drv_clock_lfclk_request(NULL);
    
        while(!nrf_drv_clock_lfclk_is_running())
        {
            /* Just waiting */
        }
    
        ret = app_timer_init();
        APP_ERROR_CHECK(ret);
    
        ret = app_timer_create(&m_mouse_move_timer, APP_TIMER_MODE_REPEATED, mouse_move_timer_handler);
        APP_ERROR_CHECK(ret);
    
        init_bsp();
    #if NRF_CLI_ENABLED
        init_cli();
    #endif
        NRF_LOG_INFO("Hello USB!");
    
        ret = app_usbd_init(&usbd_config);
        APP_ERROR_CHECK(ret);
    
        NRF_LOG_INFO("USBD HID generic example started.");
    
        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 (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();
        }
    
        while (true)
        {
            while (app_usbd_event_queue_process())
            {
                /* Nothing to do */
            }
            //hid_generic_mouse_process_state();
            if(m_report_received) test_process();
    #if NRF_CLI_ENABLED
            nrf_cli_process(&m_cli_uart);
    #endif
    
            UNUSED_RETURN_VALUE(NRF_LOG_PROCESS());
            /* Sleep CPU only if there was no interrupt since last loop processing */
            __WFE();
        }
    }
    

Related