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

combining multilink central with usb generic

Hey,

I'm using the nRF52840 dongle with SDK15.3. Am trying to make it a central device that is configured as a HID mouse when plugged. So I'm combining both multilink_central and USB_Generic examples.

/**
 * Copyright (c) 2014 - 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.
 *
 */
/**
 * @brief BLE LED Button Service central and client application main file.
 *
 * This example can be a central for up to 8 peripherals.
 * The peripheral is called ble_app_blinky and can be found in the ble_peripheral
 * folder.
 */

#include <stdint.h>
#include <stdio.h>
#include <string.h>

#include <stdbool.h>
#include <stddef.h>

#include "nordic_common.h"
#include "nrf_sdh.h"
#include "nrf_sdh_ble.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_btn_ble.h"
#include "bsp_cli.h"
#include "nrf_cli.h"
#include "nrf_cli_uart.h"


#include "ble.h"
#include "ble_hci.h"
#include "ble_advertising.h"
#include "ble_conn_params.h"
#include "ble_db_discovery.h"
#include "ble_lbs_c.h"
#include "ble_conn_state.h"



#include "nrf_ble_gatt.h"
#include "nrf_pwr_mgmt.h"
#include "nrf_ble_scan.h"

#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"



/**
 * @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);



#define APP_BLE_CONN_CFG_TAG      1                                     /**< Tag that refers to the BLE stack configuration that is set with @ref sd_ble_cfg_set. The default tag is @ref APP_BLE_CONN_CFG_TAG. */
#define APP_BLE_OBSERVER_PRIO     3                                     /**< BLE observer priority of the application. There is no need to modify this value. */

#define CENTRAL_SCANNING_LED      BSP_BOARD_LED_0
#define CENTRAL_CONNECTED_LED     BSP_BOARD_LED_1
#define LEDBUTTON_LED             BSP_BOARD_LED_2                       /**< LED to indicate a change of state of the Button characteristic on the peer. */

#define LEDBUTTON_BUTTON          BSP_BUTTON_0                          /**< Button that writes to the LED characteristic of the peer. */
#define BUTTON_DETECTION_DELAY    APP_TIMER_TICKS(50)                   /**< Delay from a GPIOTE event until a button is reported as pushed (in number of timer ticks). */

NRF_BLE_GATT_DEF(m_gatt);                                               /**< GATT module instance. */
BLE_LBS_C_ARRAY_DEF(m_lbs_c, NRF_SDH_BLE_CENTRAL_LINK_COUNT);           /**< LED button client instances. */
BLE_DB_DISCOVERY_ARRAY_DEF(m_db_disc, NRF_SDH_BLE_CENTRAL_LINK_COUNT);  /**< Database discovery module instances. */
NRF_BLE_SCAN_DEF(m_scan);                                               /**< Scanning Module instance. */




static char const m_target_periph_name[] = "BLE_HID";             /**< Name of the device to try to connect to. This name is searched for in the scanning report data. */


/**
 * @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

/**
 * @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    1

/**
 * @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  0

/**
 * @brief HID generic class endpoints count.
 * */
#define HID_GENERIC_EP_COUNT  1

/**
 * @brief List of HID generic class endpoints.
 * */
#define ENDPOINT_LIST()                                      \
(                                                            \
        HID_GENERIC_EPIN                                     \
)

/**
 * @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;

/**
 * @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,APP_USBD_HID_MOUSE_REPORT_DSC_BUTTON(2));

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,
                                APP_USBD_HID_SUBCLASS_BOOT,
                                APP_USBD_HID_PROTO_MOUSE);

/*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;

/**
 * @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.*/
            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;
    }
}

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

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

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 Function for handling asserts in the SoftDevice.
 *
 * @details This function is called in case of an assert in the SoftDevice.
 *
 * @warning This handler is only an example and is not meant for the final product. You need to analyze
 *          how your product is supposed to react in case of an assert.
 * @warning On assert from the SoftDevice, the system can only recover on reset.
 *
 * @param[in] line_num     Line number of the failing assert call.
 * @param[in] p_file_name  File name of the failing assert call.
 */
void assert_nrf_callback(uint16_t line_num, const uint8_t * p_file_name)
{
    app_error_handler(0xDEADBEEF, line_num, p_file_name);
}


/**@brief Function for initializing the LEDs.
 *
 * @details Initializes all LEDs used by the application.
 */
static void leds_init(void)
{
    bsp_board_init(BSP_INIT_LEDS);
}


static void scan_evt_handler(scan_evt_t const * p_scan_evt)
{
    ret_code_t err_code;

    switch(p_scan_evt->scan_evt_id)
    {
        case NRF_BLE_SCAN_EVT_CONNECTING_ERROR:
        {
            err_code = p_scan_evt->params.connecting_err.err_code;
            APP_ERROR_CHECK(err_code);
        } break;

        default:
            break;
    }
}


/**@brief Function for initializing the scanning and setting the filters.
 */
static void scan_init(void)
{
    ret_code_t          err_code;
    nrf_ble_scan_init_t init_scan;

    memset(&init_scan, 0, sizeof(init_scan));

    init_scan.connect_if_match = true;
    init_scan.conn_cfg_tag     = APP_BLE_CONN_CFG_TAG;

    err_code = nrf_ble_scan_init(&m_scan, &init_scan, scan_evt_handler);
    APP_ERROR_CHECK(err_code);

    err_code = nrf_ble_scan_filter_set(&m_scan, SCAN_NAME_FILTER, m_target_periph_name);
    APP_ERROR_CHECK(err_code);

    err_code = nrf_ble_scan_filters_enable(&m_scan, NRF_BLE_SCAN_NAME_FILTER, false);
    APP_ERROR_CHECK(err_code);
}


/**@brief Function for starting scanning. */
static void scan_start(void)
{
    ret_code_t ret;

    NRF_LOG_INFO("Start scanning for device name %s.", (uint32_t)m_target_periph_name);
    ret = nrf_ble_scan_start(&m_scan);
    APP_ERROR_CHECK(ret);
    // Turn on the LED to signal scanning.
    bsp_board_led_on(CENTRAL_SCANNING_LED);
}


/**@brief Handles events coming from the LED Button central module.
 *
 * @param[in] p_lbs_c     The instance of LBS_C that triggered the event.
 * @param[in] p_lbs_c_evt The LBS_C event.
 */
static void lbs_c_evt_handler(ble_lbs_c_t * p_lbs_c, ble_lbs_c_evt_t * p_lbs_c_evt)
{
    switch (p_lbs_c_evt->evt_type)
    {
        case BLE_LBS_C_EVT_DISCOVERY_COMPLETE:
        {
            ret_code_t err_code;

            NRF_LOG_INFO("LED Button Service discovered on conn_handle 0x%x",
                         p_lbs_c_evt->conn_handle);

            err_code = app_button_enable();
            APP_ERROR_CHECK(err_code);

            // LED Button Service discovered. Enable notification of Button.
            err_code = ble_lbs_c_button_notif_enable(p_lbs_c);
            APP_ERROR_CHECK(err_code);
        } break; // BLE_LBS_C_EVT_DISCOVERY_COMPLETE

        case BLE_LBS_C_EVT_BUTTON_NOTIFICATION:
        {
            NRF_LOG_INFO("Link 0x%x, Button state changed on peer to 0x%x",
                         p_lbs_c_evt->conn_handle,
                         p_lbs_c_evt->params.button.button_state);

            if (p_lbs_c_evt->params.button.button_state)
            {
                bsp_board_led_on(LEDBUTTON_LED);
            }
            else
            {
                bsp_board_led_off(LEDBUTTON_LED);
            }
        } break; // BLE_LBS_C_EVT_BUTTON_NOTIFICATION

        default:
            // No implementation needed.
            break;
    }
}


/**@brief Function for handling BLE events.
 *
 * @param[in]   p_ble_evt   Bluetooth stack event.
 * @param[in]   p_context   Unused.
 */
static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
{
    ret_code_t err_code;

    // For readability.
    ble_gap_evt_t const * p_gap_evt = &p_ble_evt->evt.gap_evt;

    switch (p_ble_evt->header.evt_id)
    {
        // Upon connection, check which peripheral is connected, initiate DB
        // discovery, update LEDs status, and resume scanning, if necessary.
        case BLE_GAP_EVT_CONNECTED:
        {
            NRF_LOG_INFO("Connection 0x%x established, starting DB discovery.",
                         p_gap_evt->conn_handle);

            APP_ERROR_CHECK_BOOL(p_gap_evt->conn_handle < NRF_SDH_BLE_CENTRAL_LINK_COUNT);

            err_code = ble_lbs_c_handles_assign(&m_lbs_c[p_gap_evt->conn_handle],
                                                p_gap_evt->conn_handle,
                                                NULL);
            APP_ERROR_CHECK(err_code);

            err_code = ble_db_discovery_start(&m_db_disc[p_gap_evt->conn_handle],
                                              p_gap_evt->conn_handle);
            if (err_code != NRF_ERROR_BUSY)
            {
                APP_ERROR_CHECK(err_code);
            }

            // Update LEDs status and check whether it is needed to look for more
            // peripherals to connect to.
            bsp_board_led_on(CENTRAL_CONNECTED_LED);
            if (ble_conn_state_central_conn_count() == NRF_SDH_BLE_CENTRAL_LINK_COUNT)
            {
                bsp_board_led_off(CENTRAL_SCANNING_LED);
            }
            else
            {
                // Resume scanning.
                bsp_board_led_on(CENTRAL_SCANNING_LED);
                scan_start();
            }
        } break; // BLE_GAP_EVT_CONNECTED

        // Upon disconnection, reset the connection handle of the peer that disconnected, update
        // the LEDs status and start scanning again.
        case BLE_GAP_EVT_DISCONNECTED:
        {
            NRF_LOG_INFO("LBS central link 0x%x disconnected (reason: 0x%x)",
                         p_gap_evt->conn_handle,
                         p_gap_evt->params.disconnected.reason);

            if (ble_conn_state_central_conn_count() == 0)
            {
                err_code = app_button_disable();
                APP_ERROR_CHECK(err_code);

                // Turn off the LED that indicates the connection.
                bsp_board_led_off(CENTRAL_CONNECTED_LED);
            }

            // Start scanning.
            scan_start();

            // Turn on the LED for indicating scanning.
            bsp_board_led_on(CENTRAL_SCANNING_LED);

        } break;

        case BLE_GAP_EVT_TIMEOUT:
        {
            // Timeout for scanning is not specified, so only the connection requests can time out.
            if (p_gap_evt->params.timeout.src == BLE_GAP_TIMEOUT_SRC_CONN)
            {
                NRF_LOG_DEBUG("Connection request timed out.");
            }
        } break;

        case BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST:
        {
            NRF_LOG_DEBUG("BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST.");
            // Accept parameters requested by peer.
            err_code = sd_ble_gap_conn_param_update(p_gap_evt->conn_handle,
                                        &p_gap_evt->params.conn_param_update_request.conn_params);
            APP_ERROR_CHECK(err_code);
        } break;

        case BLE_GAP_EVT_PHY_UPDATE_REQUEST:
        {
            NRF_LOG_DEBUG("PHY update request.");
            ble_gap_phys_t const phys =
            {
                .rx_phys = BLE_GAP_PHY_AUTO,
                .tx_phys = BLE_GAP_PHY_AUTO,
            };
            err_code = sd_ble_gap_phy_update(p_ble_evt->evt.gap_evt.conn_handle, &phys);
            APP_ERROR_CHECK(err_code);
        } break;

        case BLE_GATTC_EVT_TIMEOUT:
        {
            // Disconnect on GATT client timeout event.
            NRF_LOG_DEBUG("GATT client timeout.");
            err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gattc_evt.conn_handle,
                                             BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
            APP_ERROR_CHECK(err_code);
        } break;

        case BLE_GATTS_EVT_TIMEOUT:
        {
            // Disconnect on GATT server timeout event.
            NRF_LOG_DEBUG("GATT server timeout.");
            err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gatts_evt.conn_handle,
                                             BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
            APP_ERROR_CHECK(err_code);
        } break;

        default:
            // No implementation needed.
            break;
    }
}


/**@brief LED Button collector initialization. */
static void lbs_c_init(void)
{
    ret_code_t       err_code;
    ble_lbs_c_init_t lbs_c_init_obj;

    lbs_c_init_obj.evt_handler = lbs_c_evt_handler;

    for (uint32_t i = 0; i < NRF_SDH_BLE_CENTRAL_LINK_COUNT; i++)
    {
        err_code = ble_lbs_c_init(&m_lbs_c[i], &lbs_c_init_obj);
        APP_ERROR_CHECK(err_code);
    }
}


/**@brief Function for initializing the BLE stack.
 *
 * @details Initializes the SoftDevice and the BLE event interrupts.
 */
static void ble_stack_init(void)
{
    ret_code_t err_code;

    err_code = nrf_sdh_enable_request();
    APP_ERROR_CHECK(err_code);

    // Configure the BLE stack using the default settings.
    // Fetch the start address of the application RAM.
    uint32_t ram_start = 0;
    err_code = nrf_sdh_ble_default_cfg_set(APP_BLE_CONN_CFG_TAG, &ram_start);
    APP_ERROR_CHECK(err_code);

    // Enable BLE stack.
    err_code = nrf_sdh_ble_enable(&ram_start);
    APP_ERROR_CHECK(err_code);

    // Register a handler for BLE events.
    NRF_SDH_BLE_OBSERVER(m_ble_observer, APP_BLE_OBSERVER_PRIO, ble_evt_handler, NULL);
}


/**@brief Function for writing to the LED characteristic of all connected clients.
 *
 * @details Based on whether the button is pressed or released, this function writes a high or low
 *          LED status to the server.
 *
 * @param[in] button_action The button action (press or release).
 *            Determines whether the LEDs of the servers are ON or OFF.
 *
 * @return If successful, NRF_SUCCESS is returned. Otherwise, returns the error code from @ref ble_lbs_led_status_send.
 */
static ret_code_t led_status_send_to_all(uint8_t button_action)
{
    ret_code_t err_code;

    for (uint32_t i = 0; i< NRF_SDH_BLE_CENTRAL_LINK_COUNT; i++)
    {
        err_code = ble_lbs_led_status_send(&m_lbs_c[i], button_action);
        if (err_code != NRF_SUCCESS &&
            err_code != BLE_ERROR_INVALID_CONN_HANDLE &&
            err_code != NRF_ERROR_INVALID_STATE)
        {
            return err_code;
        }
    }
        return NRF_SUCCESS;
}


/**@brief Function for handling events from the button handler module.
 *
 * @param[in] pin_no        The pin that the event applies to.
 * @param[in] button_action The button action (press or release).
 */
static void button_event_handler(uint8_t pin_no, uint8_t button_action)
{
    ret_code_t err_code;

    switch (pin_no)
    {
        case LEDBUTTON_BUTTON:
            err_code = led_status_send_to_all(button_action);
            if (err_code == NRF_SUCCESS)
            {
                NRF_LOG_INFO("LBS write LED state %d", button_action);
            }
            break;

        default:
            APP_ERROR_HANDLER(pin_no);
            break;
    }
}


/**@brief Function for initializing the button handler module.
 */
static void buttons_init(void)
{
    ret_code_t err_code;

   // The array must be static because a pointer to it is saved in the button handler module.
    static app_button_cfg_t buttons[] =
    {
        {LEDBUTTON_BUTTON, false, BUTTON_PULL, button_event_handler}
    };

    err_code = app_button_init(buttons, ARRAY_SIZE(buttons), BUTTON_DETECTION_DELAY);
    APP_ERROR_CHECK(err_code);
}


/**@brief Function for handling database discovery events.
 *
 * @details This function is a callback function to handle events from the database discovery module.
 *          Depending on the UUIDs that are discovered, this function forwards the events
 *          to their respective services.
 *
 * @param[in] p_event  Pointer to the database discovery event.
 */
static void db_disc_handler(ble_db_discovery_evt_t * p_evt)
{
    NRF_LOG_DEBUG("call to ble_lbs_on_db_disc_evt for instance %d and link 0x%x!",
                  p_evt->conn_handle,
                  p_evt->conn_handle);

    ble_lbs_on_db_disc_evt(&m_lbs_c[p_evt->conn_handle], p_evt);
}


/** @brief Database discovery initialization.
 */
static void db_discovery_init(void)
{
    ret_code_t err_code = ble_db_discovery_init(db_disc_handler);
    APP_ERROR_CHECK(err_code);
}


/**@brief Function for initializing power management.
 */
static void power_management_init(void)
{
    ret_code_t err_code;
    err_code = nrf_pwr_mgmt_init();
    APP_ERROR_CHECK(err_code);
}


/**@brief Function for handling the idle state (main loop).
 *
 * @details This function handles any pending log operations, then sleeps until the next event occurs.
 */
static void idle_state_handle(void)
{
    if (NRF_LOG_PROCESS() == false)
    {
        nrf_pwr_mgmt_run();
    }
}


/** @brief Function for initializing the log module.
 */
static void log_init(void)
{
    ret_code_t err_code = NRF_LOG_INIT(NULL);
    APP_ERROR_CHECK(err_code);

    NRF_LOG_DEFAULT_BACKENDS_INIT();
}


/** @brief Function for initializing the timer.
 */
static void timer_init(void)
{
    ret_code_t err_code = app_timer_init();
    APP_ERROR_CHECK(err_code);
}


/**@brief Function for initializing the GATT module.
 */
static void gatt_init(void)
{
    ret_code_t err_code = nrf_ble_gatt_init(&m_gatt, NULL);
    APP_ERROR_CHECK(err_code);
}


int main(void)
  {

  // Initialize.
   // ret_init();
    init_bsp();
    init_cli();
    log_init();
    timer_init();
    leds_init();
    buttons_init();
    power_management_init();
    ble_stack_init();
    gatt_init();
    db_discovery_init();
    lbs_c_init();
    ble_conn_state_init();
    //


    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();
    init_cli();
    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();
        nrf_cli_process(&m_cli_uart);

        UNUSED_RETURN_VALUE(NRF_LOG_PROCESS());
        /* Sleep CPU only if there was no interrupt since last loop processing */
        __WFE();
    }


    scan_init();
   

    // Start execution.
    NRF_LOG_INFO("Multilink example started.");
    scan_start();
  
    for (;;)
    {
        idle_state_handle();
    }


}

am getting these errors:

am not sure if there is conflict in difinitions or something needs to be changed in config.h file. I have enabled all of both needs but am not sure what is missing.

Aside: is there an easier way to have the dongle be seen as an HID mouse and always looking to pair with the MAC address i provide?

Help is appriciated,

Thanks,

Maher

  • Hi Maher.

    Have you enabled the USBD driver?

    // <e> USBD_ENABLED - nrf_drv_usbd - Software Component
    //==========================================================
    #ifndef USBD_ENABLED
    #define USBD_ENABLED 1
    #endif
    
    // <e> APP_USBD_ENABLED - app_usbd - USB Device library
    //==========================================================
    #ifndef APP_USBD_ENABLED
    #define APP_USBD_ENABLED 1
    #endif

    Best regards,

    Andreas

  • Thanks for your reply. Yes I have that enabled. This is the config.h:

    1031.sdk_config.h

    The problems are:

    1> Output/ble_app_multilink_central_pca10056_s140 Release/Obj/app_usbd.o: In function `sustate_set':

    1> Output/ble_app_multilink_central_pca10056_s140 Release/Obj/app_usbd.o: In function `app_usbd_init':

    1> Output/ble_app_multilink_central_pca10056_s140 Release/Obj/main.o: In function `init_cli':

    1> Output/ble_app_multilink_central_pca10056_s140 Release/Obj/main.o: In function `idle_handle':

    1> Output/ble_app_multilink_central_pca10056_s140 Release/Obj/main.o: In function `hid_user_ev_handler':

    1> Output/ble_app_multilink_central_pca10056_s140 Release/Obj/main.o: In function `main':

  • Hi.

    If you use the nrfx driver (you have the file nrfx_usbd.c) in your project, you also have to enable that.

    #ifndef NRFX_USBD_ENABLED
    #define NRFX_USBD_ENABLED 1

    Best regards,

    Andreas

  • I am not sure of what is the actual problem with the my attempt to combine those two examples. but I tried to combine both USBD and and UART_C and it built no problems. but I is not seen as a mouse anymore. So when I compile only the USBD it is seen as a mouse (only when the processor is set 10056 not to 10059 for some reason, even-though am using the dongle)

    I guess am missing something or my main function is out of order, am not sure.

    /**
     * Copyright (c) 2016 - 2018, 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 <stddef.h> // added from USBD
    #include <stdio.h>
    #include <stdint.h>
    #include <stdbool.h>
    #include "nordic_common.h"
    #include "app_error.h"
    #include "app_uart.h"
    #include "ble_db_discovery.h"
    #include "app_timer.h"
    #include "app_util.h"
    #include "bsp_btn_ble.h"
    #include "ble.h"
    #include "ble_gap.h"
    #include "ble_hci.h"
    #include "nrf_sdh.h"
    #include "nrf_sdh_ble.h"
    #include "nrf_sdh_soc.h"
    #include "ble_nus_c.h"
    #include "nrf_ble_gatt.h"
    #include "nrf_pwr_mgmt.h"
    #include "nrf_ble_scan.h"
    
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    
    // Added headers for USBD
    #include "nrf.h"
    #include "nrf_drv_usbd.h"
    #include "nrf_drv_clock.h"
    #include "nrf_gpio.h"
    #include "nrf_delay.h"
    #include "nrf_drv_power.h"
    #include "app_timer.h"
    #include "app_error.h"
    #include "bsp.h"
    #include "bsp_cli.h"
    #include "nrf_cli.h"
    #include "nrf_cli_uart.h"
    // End of added headers
    
    // Addedd diffinitions for USBD
    #define BTN_MOUSE_MOVE BSP_BOARD_BUTTON_0
    #define BTN_SYSTEM_OFF BSP_BOARD_BUTTON_1
    #define LED_USB_STATUS BSP_BOARD_LED_0
    #define LED_USB_POWER BSP_BOARD_LED_1
    #define LED_RUNNING BSP_BOARD_LED_2
    #define LED_ACTIVE BSP_BOARD_LED_3
    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);
    
    static bool m_send_flag = 0;
    
    #define BTN_DATA_SEND               0
    #define BTN_DATA_KEY_RELEASE        (bsp_event_t)(BSP_EVENT_KEY_LAST + 1)
    
    #ifndef USBD_POWER_DETECTION
    #define USBD_POWER_DETECTION true
    #endif
    
    #define STARTUP_DELAY 100                                 // Number of microseconds to start USBD after powering up. (for port debouncing)
    #define EP0_MAXPACKETSIZE NRF_DRV_USBD_EPSIZE             // Maximum size of the packed transfered by EP0
    
    /** Device descriptor */
    #define USBD_DEVICE_DESCRIPTOR \
        0x12,                        /* bLength | size of descriptor                                                  */\
        0x01,                        /* bDescriptorType | descriptor type                                             */\
        0x00, 0x02,                  /* bcdUSB | USB spec release (ver 2.0)                                           */\
        0x00,                        /* bDeviceClass ¦ class code (each interface specifies class information)        */\
        0x00,                        /* bDeviceSubClass ¦ device sub-class (must be set to 0 because class code is 0) */\
        0x00,                        /* bDeviceProtocol | device protocol (no class specific protocol)                */\
        EP0_MAXPACKETSIZE,           /* bMaxPacketSize0 | maximum packet size (64 bytes)                              */\
        0x15, 0x19,                  /* vendor ID  (0x1915 Nordic)                                                    */\
        0x0A, 0x52,                  /* product ID (0x520A nRF52 HID mouse on nrf_drv)                                */\
        0x01, 0x01,                  /* bcdDevice | final device release number in BCD Format                         */\
        USBD_STRING_MANUFACTURER_IX, /* iManufacturer | index of manufacturer string                                  */\
        USBD_STRING_PRODUCT_IX,      /* iProduct | index of product string                                            */\
        USBD_STRING_SERIAL_IX,       /* iSerialNumber | Serial Number string                                          */\
        0x01                         /* bNumConfigurations | number of configurations                                 */
    
    #define DEVICE_SELF_POWERED 1
    #define REMOTE_WU           1
    
    #define USBD_CONFIG_DESCRIPTOR_SIZE   9
    #define USBD_CONFIG_DESCRIPTOR_FULL_SIZE   (9 + (9 + 9 + 7))
    #define USBD_CONFIG_DESCRIPTOR  \
        0x09,         /* bLength | length of descriptor                                             */\
        0x02,         /* bDescriptorType | descriptor type (CONFIGURATION)                          */\
        USBD_CONFIG_DESCRIPTOR_FULL_SIZE, 0x00,    /* wTotalLength | total length of descriptor(s)  */\
        0x01,         /* bNumInterfaces                                                             */\
        0x01,         /* bConfigurationValue                                                        */\
        0x00,         /* index of string Configuration | configuration string index (not supported) */\
        0x80| (((DEVICE_SELF_POWERED) ? 1U:0U)<<6) | (((REMOTE_WU) ? 1U:0U)<<5), /* bmAttributes    */\
        49            /* maximum power in steps of 2mA (98mA)                                       */
    
    #define USBD_INTERFACE0_DESCRIPTOR  \
        0x09,         /* bLength                                                                          */\
        0x04,         /* bDescriptorType | descriptor type (INTERFACE)                                    */\
        0x00,         /* bInterfaceNumber                                                                 */\
        0x00,         /* bAlternateSetting                                                                */\
        0x01,         /* bNumEndpoints | number of endpoints (1)                                          */\
        0x03,         /* bInterfaceClass | interface class (3..defined by USB spec: HID)                  */\
        0x00,         /* bInterfaceSubClass |interface sub-class (0.. no boot interface)                  */\
        0x02,         /* bInterfaceProtocol | interface protocol (1..defined by USB spec: mouse)          */\
        0x00          /* interface string index (not supported)                                           */
    
    /**
     * HID Table must normally be between Interface and EndPoint Descriptor
     * as written in HID spec§7.1 but it doesn't work with OSR2.1
     */
    #define USBD_HID0_DESCRIPTOR  \
        0x09,         /* bLength | length of descriptor (9 bytes)                    */\
        0x21,         /* bHIDDescriptor | descriptor type (HID)                      */\
        0x11, 0x01,   /* HID wBcdHID | Spec version 01.11                            */\
        0x00,         /* bCountryCode | HW Target country                            */\
        0x01,         /* bNumDescriptors | Number of HID class descriptors to follow */\
        0x22,         /* bDescriptorType | Report descriptor type is 0x22 (report)   */\
        (uint8_t)(USBD_MOUSE_REPORT_DESCRIPTOR_SIZE),      /* Total length of Report descr., low byte */ \
        (uint8_t)(USBD_MOUSE_REPORT_DESCRIPTOR_SIZE / 256) /* Total length of Report descr., high byte */
    
    #define USBD_ENDPOINT1_DESCRIPTOR  \
        0x07,         /* bLength | length of descriptor (7 bytes)                                     */\
        0x05,         /* bDescriptorType | descriptor type (ENDPOINT)                                 */\
        0x81,         /* bEndpointAddress | endpoint address (IN endpoint, endpoint 1)                */\
        0x03,         /* bmAttributes | endpoint attributes (interrupt)                               */\
        0x08,0x00,    /* bMaxPacketSizeLowByte,bMaxPacketSizeHighByte | maximum packet size (8 bytes) */\
        0x08          /* bInterval | polling interval (10ms)                                          */
    
    
    /**
     * String config descriptor
     */
    #define USBD_STRING_LANG_IX  0x00
    #define USBD_STRING_LANG \
        0x04,         /* length of descriptor                   */\
        0x03,         /* descriptor type                        */\
        0x09,         /*                                        */\
        0x04          /* Supported LangID = 0x0409 (US-English) */
    
    #define USBD_STRING_MANUFACTURER_IX  0x01
    #define USBD_STRING_MANUFACTURER \
        42,           /* length of descriptor (? bytes)   */\
        0x03,         /* descriptor type                  */\
        'N', 0x00,    /* Define Unicode String "Nordic Semiconductor  */\
        'o', 0x00, \
        'r', 0x00, \
        'd', 0x00, \
        'i', 0x00, \
        'c', 0x00, \
        ' ', 0x00, \
        'S', 0x00, \
        'e', 0x00, \
        'm', 0x00, \
        'i', 0x00, \
        'c', 0x00, \
        'o', 0x00, \
        'n', 0x00, \
        'd', 0x00, \
        'u', 0x00, \
        'c', 0x00, \
        't', 0x00, \
        'o', 0x00, \
        'r', 0x00
    
    #define USBD_STRING_PRODUCT_IX  0x02
    #define USBD_STRING_PRODUCT \
        72,           /* length of descriptor (? bytes)         */\
        0x03,         /* descriptor type                        */\
        'n', 0x00,    /* generic unicode string for all devices */\
        'R', 0x00, \
        'F', 0x00, \
        '5', 0x00, \
        '2', 0x00, \
        ' ', 0x00, \
        'U', 0x00, \
        'S', 0x00, \
        'B', 0x00, \
        ' ', 0x00, \
        'H', 0x00, \
        'I', 0x00, \
        'D', 0x00, \
        ' ', 0x00, \
        'm', 0x00, \
        'o', 0x00, \
        'u', 0x00, \
        's', 0x00, \
        'e', 0x00, \
        ' ', 0x00, \
        'o', 0x00, \
        'n', 0x00, \
        ' ', 0x00, \
        'n', 0x00, \
        'r', 0x00, \
        'f', 0x00, \
        '_', 0x00, \
        'd', 0x00, \
        'r', 0x00, \
        'v', 0x00, \
        ' ', 0x00, \
        'D', 0x00, \
        'e', 0x00, \
        'm', 0x00, \
        'o', 0x00, \
    
    #define USBD_STRING_SERIAL_IX  0x00
    
    #define USBD_MOUSE_REPORT_DESCRIPTOR_SIZE  46
    #define USBD_MOUSE_REPORT_DESCRIPTOR \
        0x05, 0x01,     /* usage page (generic desktop). Global item, applies to all subsequent items   */\
        0x09, 0x02,     /* usage (mouse). Local item                                                    */\
        0xA1, 0x01,     /* collection (application)                                                     */\
        0x09, 0x01,     /* usage (pointer)                                                              */\
        0xA1, 0x00,     /* collection (physical)                                                        */\
        0x05, 0x09,     /*   usage page (buttons). Global item, applies to all subsequent items         */\
        0x19, 0x01,     /*   usage minimum (1)                                                          */\
        0x29, 0x08,     /*   usage maximum (8)                                                          */\
        0x15, 0x00,     /*   logical minimum (0)                                                        */\
        0x25, 0x01,     /*   logical maximum (1)                                                        */\
        0x95, 0x08,     /*   report count (8)                                                           */\
        0x75, 0x01,     /*   report size (1)                                                            */\
        0x81, 0x02,     /*   input (data, var, abs)                                                     */\
        0x05, 0x01,     /*   usage page (generic desktop). Global item, applies to all subsequent items */\
        0x15, 0x81,     /*   logical minimum (-127)                                                     */\
        0x25, 0x7F,     /*   logical maximum (127)                                                      */\
        0x75, 0x08,     /*   report size (8)                                                            */\
        0x09, 0x30,     /*   usage (X)                                                                  */\
        0x09, 0x31,     /*   usage (Y)                                                                  */\
        0x09, 0x38,     /*   usage wheel                                                                */\
        0x95, 0x03,     /*   report count (3)                                                           */\
        0x81, 0x06,     /*   input (3 position bytes X, Y & roller)                                     */\
        0xC0,           /* end collection                                                               */\
        0xC0            /* End Collection                                                               */
    
    
    static const uint8_t get_descriptor_device[] = {
        USBD_DEVICE_DESCRIPTOR
    };
    
    static const uint8_t get_descriptor_configuration[] = {
        USBD_CONFIG_DESCRIPTOR,
        USBD_INTERFACE0_DESCRIPTOR,
        USBD_HID0_DESCRIPTOR,
        USBD_ENDPOINT1_DESCRIPTOR
    };
    static const uint8_t get_descriptor_string_lang[] = {
        USBD_STRING_LANG
    };
    static const uint8_t get_descriptor_string_manuf[] = {
        USBD_STRING_MANUFACTURER
    };
    static const uint8_t get_descriptor_string_prod[] = {
        USBD_STRING_PRODUCT
    };
    static const uint8_t get_descriptor_report_interface_0[] = {
        USBD_MOUSE_REPORT_DESCRIPTOR
    };
    
    static const uint8_t get_config_resp_configured[]   = {1};
    static const uint8_t get_config_resp_unconfigured[] = {0};
    
    static const uint8_t get_status_device_resp_nrwu[] = {
        ((DEVICE_SELF_POWERED) ? 1 : 0), //LSB first: self-powered, no remoteWk
        0
    };
    static const uint8_t get_status_device_resp_rwu[]  = {
        ((DEVICE_SELF_POWERED) ? 1 : 0) | 2, //LSB first: self-powered, remoteWk
        0
    };
    
    static const uint8_t get_status_interface_resp[] = {0, 0};
    static const uint8_t get_status_ep_halted_resp[] = {1, 0};
    static const uint8_t get_status_ep_active_resp[] = {0, 0};
    
    
    #define GET_CONFIG_DESC_SIZE    sizeof(get_descriptor_configuration)
    #define GET_INTERFACE_DESC_SIZE 9
    #define GET_HID_DESC_SIZE       9
    #define GET_ENDPOINT_DESC_SIZE  7
    
    #define get_descriptor_interface_0 \
        &get_descriptor_configuration[9]
    #define get_descriptor_hid_0       \
        &get_descriptor_configuration[9+GET_INTERFACE_DESC_SIZE]
    #define get_descriptor_endpoint_1  \
        &get_descriptor_configuration[9+GET_INTERFACE_DESC_SIZE+GET_HID_DESC_SIZE]
    
    // End of added diffs for USBD
    
    #define APP_BLE_CONN_CFG_TAG    1                                       /**< Tag that refers to the BLE stack configuration set with @ref sd_ble_cfg_set. The default tag is @ref BLE_CONN_CFG_TAG_DEFAULT. */
    #define APP_BLE_OBSERVER_PRIO   3                                       /**< BLE observer priority of the application. There is no need to modify this value. */
    
    #define UART_TX_BUF_SIZE        256                                     /**< UART TX buffer size. */
    #define UART_RX_BUF_SIZE        256                                     /**< UART RX buffer size. */
    
    #define NUS_SERVICE_UUID_TYPE   BLE_UUID_TYPE_VENDOR_BEGIN              /**< UUID type for the Nordic UART Service (vendor specific). */
    
    #define ECHOBACK_BLE_UART_DATA  1                                       /**< Echo the UART data that is received over the Nordic UART Service (NUS) back to the sender. */
    
    
    // Added functions for USBD
    /**
     * @brief USB configured flag
     *
     * The flag that is used to mark the fact that USB is configured and ready
     * to transmit data
     */
    static volatile bool m_usbd_configured = false;
    
    /**
     * @brief USB suspended
     *
     * The flag that is used to mark the fact that USB is suspended and requires wake up
     * if new data is available.
     *
     * @note This variable is changed from the main loop.
     */
    static bool m_usbd_suspended = false;
    
    /**
     * @brief Mark the fact if remote wake up is enabled
     *
     * The internal flag that marks if host enabled the remote wake up functionality in this device.
     */
    static
    #if REMOTE_WU
        volatile // Disallow optimization only if Remote wakeup is enabled
    #endif
    bool m_usbd_rwu_enabled = false;
    
    /**
     * @brief Current mouse position
     *
     * The index of current mouse position that would be changed to real offset.
     */
    static volatile uint8_t m_mouse_position = 0;
    
    /**
     * @brief The flag for mouse position send pending
     *
     * Setting this flag means that USB endpoint is busy by sending
     * last mouse position.
     */
    static volatile bool m_send_mouse_position = false;
    
    /**
     * @brief The requested suspend state
     *
     * The currently requested suspend state based on the events
     * received from USBD library.
     * If the value here is different than the @ref m_usbd_suspended
     * the state changing would be processed inside main loop.
     */
    static volatile bool m_usbd_suspend_state_req = false;
    
    /**
     * @brief System OFF request flag
     *
     * This flag is used in button event processing and marks the fact that
     * system OFF should be activated from main loop.
     */
    static volatile bool m_system_off_req = false;
    
    
    /**
     * @brief Setup all the endpoints for selected configuration
     *
     * Function sets all the endpoints for specific configuration.
     *
     * @note
     * Setting the configuration index 0 means technically disabling the HID interface.
     * Such configuration should be set when device is starting or USB reset is detected.
     *
     * @param index Configuration index
     *
     * @retval NRF_ERROR_INVALID_PARAM Invalid configuration
     * @retval NRF_SUCCESS             Configuration successfully set
     */
    static ret_code_t ep_configuration(uint8_t index)
    {
        if ( index == 1 )
        {
            nrf_drv_usbd_ep_dtoggle_clear(NRF_DRV_USBD_EPIN1);
            nrf_drv_usbd_ep_stall_clear(NRF_DRV_USBD_EPIN1);
            nrf_drv_usbd_ep_enable(NRF_DRV_USBD_EPIN1);
            m_usbd_configured = true;
            nrf_drv_usbd_setup_clear();
        }
        else if ( index == 0 )
        {
            nrf_drv_usbd_ep_disable(NRF_DRV_USBD_EPIN1);
            m_usbd_configured = false;
            nrf_drv_usbd_setup_clear();
        }
        else
        {
            return NRF_ERROR_INVALID_PARAM;
        }
        return NRF_SUCCESS;
    }
    
    /**
     * @name Processing setup requests
     *
     * @{
     */
    /**
     * @brief Respond on ep 0
     *
     * Auxiliary function for sending respond on endpoint 0
     * @param[in] p_setup Pointer to setup data from current setup request.
     *                    It would be used to calculate the size of data to send.
     * @param[in] p_data  Pointer to the data to send.
     * @param[in] size    Number of bytes to send.
     * @note Data pointed by p_data has to be available till the USBD_EVT_BUFREADY event.
     */
    static void respond_setup_data(
        nrf_drv_usbd_setup_t const * const p_setup,
        void const * p_data, size_t size)
    {
        /* Check the size against required response size */
        if (size > p_setup->wLength)
        {
            size = p_setup->wLength;
        }
        ret_code_t ret;
        nrf_drv_usbd_transfer_t transfer =
        {
            .p_data = {.tx = p_data},
            .size = size
        };
        ret = nrf_drv_usbd_ep_transfer(NRF_DRV_USBD_EPIN0, &transfer);
        if (ret != NRF_SUCCESS)
        {
            NRF_LOG_ERROR("Transfer starting failed: %d", (uint32_t)ret);
        }
        ASSERT(ret == NRF_SUCCESS);
        UNUSED_VARIABLE(ret);
    }
    
    
    /** React to GetStatus */
    static void usbd_setup_GetStatus(nrf_drv_usbd_setup_t const * const p_setup)
    {
        switch (p_setup->bmRequestType)
        {
        case 0x80: // Device
            if (((p_setup->wIndex) & 0xff) == 0)
            {
                respond_setup_data(
                    p_setup,
                    m_usbd_rwu_enabled ? get_status_device_resp_rwu : get_status_device_resp_nrwu,
                    sizeof(get_status_device_resp_nrwu));
                return;
            }
            break;
        case 0x81: // Interface
            if (m_usbd_configured) // Respond only if configured
            {
                if (((p_setup->wIndex) & 0xff) == 0) // Only interface 0 supported
                {
                    respond_setup_data(
                        p_setup,
                        get_status_interface_resp,
                        sizeof(get_status_interface_resp));
                    return;
                }
            }
            break;
        case 0x82: // Endpoint
            if (((p_setup->wIndex) & 0xff) == 0) // Endpoint 0
            {
                respond_setup_data(
                    p_setup,
                    get_status_ep_active_resp,
                    sizeof(get_status_ep_active_resp));
                return;
            }
            if (m_usbd_configured) // Other endpoints responds if configured
            {
                if (((p_setup->wIndex) & 0xff) == NRF_DRV_USBD_EPIN1)
                {
                    if (nrf_drv_usbd_ep_stall_check(NRF_DRV_USBD_EPIN1))
                    {
                        respond_setup_data(
                            p_setup,
                            get_status_ep_halted_resp,
                            sizeof(get_status_ep_halted_resp));
                        return;
                    }
                    else
                    {
                        respond_setup_data(
                            p_setup,
                            get_status_ep_active_resp,
                            sizeof(get_status_ep_active_resp));
                        return;
                    }
                }
            }
            break;
        default:
            break; // Just go to stall
        }
        NRF_LOG_ERROR("Unknown status: 0x%2x", p_setup->bmRequestType);
        nrf_drv_usbd_setup_stall();
    }
    
    static void usbd_setup_ClearFeature(nrf_drv_usbd_setup_t const * const p_setup)
    {
        if ((p_setup->bmRequestType) == 0x02) // standard request, recipient=endpoint
        {
            if ((p_setup->wValue) == 0)
            {
                if ((p_setup->wIndex) == NRF_DRV_USBD_EPIN1)
                {
                    nrf_drv_usbd_ep_stall_clear(NRF_DRV_USBD_EPIN1);
                    nrf_drv_usbd_setup_clear();
                    return;
                }
            }
        }
        else if ((p_setup->bmRequestType) ==  0x0) // standard request, recipient=device
        {
            if (REMOTE_WU)
            {
                if ((p_setup->wValue) == 1) // Feature Wakeup
                {
                    m_usbd_rwu_enabled = false;
                    nrf_drv_usbd_setup_clear();
                    return;
                }
            }
        }
        NRF_LOG_ERROR("Unknown feature to clear");
        nrf_drv_usbd_setup_stall();
    }
    
    static void usbd_setup_SetFeature(nrf_drv_usbd_setup_t const * const p_setup)
    {
        if ((p_setup->bmRequestType) == 0x02) // standard request, recipient=endpoint
        {
            if ((p_setup->wValue) == 0) // Feature HALT
            {
                if ((p_setup->wIndex) == NRF_DRV_USBD_EPIN1)
                {
                    nrf_drv_usbd_ep_stall(NRF_DRV_USBD_EPIN1);
                    nrf_drv_usbd_setup_clear();
                    return;
                }
            }
        }
        else if ((p_setup->bmRequestType) ==  0x0) // standard request, recipient=device
        {
            if (REMOTE_WU)
            {
                if ((p_setup->wValue) == 1) // Feature Wakeup
                {
                    m_usbd_rwu_enabled = true;
                    nrf_drv_usbd_setup_clear();
                    return;
                }
            }
        }
        NRF_LOG_ERROR("Unknown feature to set");
        nrf_drv_usbd_setup_stall();
    }
    
    static void usbd_setup_GetDescriptor(nrf_drv_usbd_setup_t const * const p_setup)
    {
        //determine which descriptor has been asked for
        switch ((p_setup->wValue) >> 8)
        {
        case 1: // Device
            if ((p_setup->bmRequestType) == 0x80)
            {
                respond_setup_data(
                    p_setup,
                    get_descriptor_device,
                    sizeof(get_descriptor_device));
                return;
            }
            break;
        case 2: // Configuration
            if ((p_setup->bmRequestType) == 0x80)
            {
                respond_setup_data(
                    p_setup,
                    get_descriptor_configuration,
                    GET_CONFIG_DESC_SIZE);
                return;
            }
            break;
        case 3: // String
            if ((p_setup->bmRequestType) == 0x80)
            {
                // Select the string
                switch ((p_setup->wValue) & 0xFF)
                {
                case USBD_STRING_LANG_IX:
                    respond_setup_data(
                        p_setup,
                        get_descriptor_string_lang,
                        sizeof(get_descriptor_string_lang));
                    return;
                case USBD_STRING_MANUFACTURER_IX:
                    respond_setup_data(
                        p_setup,
                        get_descriptor_string_manuf,
                        sizeof(get_descriptor_string_manuf));
                    return;
                case USBD_STRING_PRODUCT_IX:
                    respond_setup_data(p_setup,
                        get_descriptor_string_prod,
                        sizeof(get_descriptor_string_prod));
                    return;
                default:
                    break;
                }
            }
            break;
        case 4: // Interface
            if ((p_setup->bmRequestType) == 0x80)
            {
                // Which interface?
                if ((((p_setup->wValue) & 0xFF) == 0))
                {
                    respond_setup_data(
                        p_setup,
                        get_descriptor_interface_0,
                        GET_INTERFACE_DESC_SIZE);
                    return;
                }
            }
            break;
        case 5: // Endpoint
            if ((p_setup->bmRequestType) == 0x80)
            {
                // Which endpoint?
                if (((p_setup->wValue) & 0xFF) == 1)
                {
                    respond_setup_data(
                        p_setup,
                        get_descriptor_endpoint_1,
                        GET_ENDPOINT_DESC_SIZE);
                    return;
                }
            }
            break;
        case 0x21: // HID
            if ((p_setup->bmRequestType) == 0x81)
            {
                // Which interface
                if (((p_setup->wValue) & 0xFF) == 0)
                {
                    respond_setup_data(
                        p_setup,
                        get_descriptor_hid_0,
                        GET_HID_DESC_SIZE);
                    return;
                }
            }
            break;
        case 0x22: // HID report
            if ((p_setup->bmRequestType) == 0x81)
            {
                // Which interface?
                if (((p_setup->wValue) & 0xFF) == 0)
                {
                    respond_setup_data(
                        p_setup,
                        get_descriptor_report_interface_0,
                        sizeof(get_descriptor_report_interface_0));
                    return;
                }
            }
            break;
        default:
            break; // Not supported - go to stall
        }
    
        NRF_LOG_ERROR("Unknown descriptor requested: 0x%2x, type: 0x%2x or value: 0x%2x",
            p_setup->wValue >> 8,
            p_setup->bmRequestType,
            p_setup->wValue & 0xFF);
        nrf_drv_usbd_setup_stall();
    }
    
    static void usbd_setup_GetConfig(nrf_drv_usbd_setup_t const * const p_setup)
    {
        if (m_usbd_configured)
        {
            respond_setup_data(
                p_setup,
                get_config_resp_configured,
                sizeof(get_config_resp_configured));
        }
        else
        {
            respond_setup_data(
                p_setup,
                get_config_resp_unconfigured,
                sizeof(get_config_resp_unconfigured));
        }
    }
    
    static void usbd_setup_SetConfig(nrf_drv_usbd_setup_t const * const p_setup)
    {
        if ((p_setup->bmRequestType) == 0x00)
        {
            // accept only 0 and 1
            if (((p_setup->wIndex) == 0) && ((p_setup->wLength) == 0) &&
                ((p_setup->wValue) <= UINT8_MAX))
            {
                if (NRF_SUCCESS == ep_configuration((uint8_t)(p_setup->wValue)))
                {
                    nrf_drv_usbd_setup_clear();
                    return;
                }
            }
        }
        NRF_LOG_ERROR("Wrong configuration: Index: 0x%2x, Value: 0x%2x.",
            p_setup->wIndex,
            p_setup->wValue);
        nrf_drv_usbd_setup_stall();
    }
    
    static void usbd_setup_SetIdle(nrf_drv_usbd_setup_t const * const p_setup)
    {
        if (p_setup->bmRequestType == 0x21)
        {
            //accept any value
            nrf_drv_usbd_setup_clear();
            return;
        }
        NRF_LOG_ERROR("Set Idle wrong type: 0x%2x.", p_setup->bmRequestType);
        nrf_drv_usbd_setup_stall();
    }
    
    static void usbd_setup_SetInterface(
        nrf_drv_usbd_setup_t const * const p_setup)
    {
        //no alternate setting is supported - STALL always
        NRF_LOG_ERROR("No alternate interfaces supported.");
        nrf_drv_usbd_setup_stall();
    }
    
    static void usbd_setup_SetProtocol(
        nrf_drv_usbd_setup_t const * const p_setup)
    {
        if (p_setup->bmRequestType == 0x21)
        {
            //accept any value
            nrf_drv_usbd_setup_clear();
            return;
        }
        NRF_LOG_ERROR("Set Protocol wrong type: 0x%2x.", p_setup->bmRequestType);
        nrf_drv_usbd_setup_stall();
    }
    
    /** @} */ /* End of processing setup requests functions */
    
    
    static void usbd_event_handler(nrf_drv_usbd_evt_t const * const p_event)
    {
        switch (p_event->type)
        {
        case NRF_DRV_USBD_EVT_SUSPEND:
            NRF_LOG_INFO("SUSPEND state detected");
            m_usbd_suspend_state_req = true;
            break;
        case NRF_DRV_USBD_EVT_RESUME:
            NRF_LOG_INFO("RESUMING from suspend");
            m_usbd_suspend_state_req = false;
            break;
        case NRF_DRV_USBD_EVT_WUREQ:
            NRF_LOG_INFO("RemoteWU initiated");
            m_usbd_suspend_state_req = false;
            break;
        case NRF_DRV_USBD_EVT_RESET:
            {
                ret_code_t ret = ep_configuration(0);
                ASSERT(ret == NRF_SUCCESS);
                UNUSED_VARIABLE(ret);
                m_usbd_suspend_state_req = false;
                break;
            }
        case NRF_DRV_USBD_EVT_SOF:
            {
                static uint32_t cycle = 0;
                ++cycle;
                if ((cycle % (m_usbd_configured ? 500 : 100)) == 0)
                {
                    bsp_board_led_invert(LED_USB_STATUS);
                }
                break;
            }
        case NRF_DRV_USBD_EVT_EPTRANSFER:
            if (NRF_DRV_USBD_EPIN1 == p_event->data.eptransfer.ep)
            {
                m_send_mouse_position = false;
            }
            else
            if (NRF_DRV_USBD_EPIN0 == p_event->data.eptransfer.ep)
            {
                if (NRF_USBD_EP_OK == p_event->data.eptransfer.status)
                {
                    if (!nrf_drv_usbd_errata_154())
                    {
                        /* Transfer ok - allow status stage */
                        nrf_drv_usbd_setup_clear();
                    }
                }
                else if (NRF_USBD_EP_ABORTED == p_event->data.eptransfer.status)
                {
                    /* Just ignore */
                    NRF_LOG_INFO("Transfer aborted event on EPIN0");
                }
                else
                {
                    NRF_LOG_ERROR("Transfer failed on EPIN0: %d", p_event->data.eptransfer.status);
                    nrf_drv_usbd_setup_stall();
                }
            }
            else
            if (NRF_DRV_USBD_EPOUT0 == p_event->data.eptransfer.ep)
            {
                /* NOTE: No EPOUT0 data transfers are used.
                 * The code is here as a pattern how to support such a transfer. */
                if (NRF_USBD_EP_OK == p_event->data.eptransfer.status)
                {
                    /* NOTE: Data values or size may be tested here to decide if clear or stall.
                     * If errata 154 is present the data transfer is acknowledged by the hardware. */
                    if (!nrf_drv_usbd_errata_154())
                    {
                        /* Transfer ok - allow status stage */
                        nrf_drv_usbd_setup_clear();
                    }
                }
                else if (NRF_USBD_EP_ABORTED == p_event->data.eptransfer.status)
                {
                    /* Just ignore */
                    NRF_LOG_INFO("Transfer aborted event on EPOUT0");
                }
                else
                {
                    NRF_LOG_ERROR("Transfer failed on EPOUT0: %d", p_event->data.eptransfer.status);
                    nrf_drv_usbd_setup_stall();
                }
            }
            else
            {
                /* Nothing to do */
            }
            break;
        case NRF_DRV_USBD_EVT_SETUP:
            {
                nrf_drv_usbd_setup_t setup;
                nrf_drv_usbd_setup_get(&setup);
                switch (setup.bmRequest)
                {
                case 0x00: // GetStatus
                    usbd_setup_GetStatus(&setup);
                    break;
                case 0x01: // CleartFeature
                    usbd_setup_ClearFeature(&setup);
                    break;
                case 0x03: // SetFeature
                    usbd_setup_SetFeature(&setup);
                    break;
                case 0x05: // SetAddress
                    //nothing to do, handled by hardware; but don't STALL
                    break;
                case 0x06: // GetDescriptor
                    usbd_setup_GetDescriptor(&setup);
                    break;
                case 0x08: // GetConfig
                    usbd_setup_GetConfig(&setup);
                    break;
                case 0x09: // SetConfig
                    usbd_setup_SetConfig(&setup);
                    break;
                //HID class
                case 0x0A: // SetIdle
                    usbd_setup_SetIdle(&setup);
                    break;
                case 0x0B: // SetProtocol or SetInterface
                    if (setup.bmRequestType == 0x01) // standard request, recipient=interface
                    {
                        usbd_setup_SetInterface(&setup);
                    }
                    else if (setup.bmRequestType == 0x21) // class request, recipient=interface
                    {
                        usbd_setup_SetProtocol(&setup);
                    }
                    else
                    {
                        NRF_LOG_ERROR("Command 0xB. Unknown request: 0x%2x", setup.bmRequestType);
                        nrf_drv_usbd_setup_stall();
                    }
                    break;
                default:
                    NRF_LOG_ERROR("Unknown request: 0x%2x", setup.bmRequest);
                    nrf_drv_usbd_setup_stall();
                    return;
                }
                break;
            }
        default:
            break;
        }
    }
    
    
    static void move_mouse_pointer(void)
    {
        static uint32_t databuffer;
    
        if (!m_usbd_configured)
            return;
        if (!m_send_mouse_position)
        {
            switch (m_mouse_position & 0x3)
            {
            case 0:
                /* X = 10, rest all are unchanged */
                databuffer = 0x00000A00;
                break;
            case 1:
                /* Y = 10, rest all are unchanged */
                databuffer = 0x000A0000;
                break;
            case 2:
                /* X = -10, rest all are unchanged */
                databuffer = 0x0000F600;
                break;
            case 3:
                /* Y = -10, rest all are unchanged */
                databuffer = 0x00F60000;
                break;
            }
            m_mouse_position++;
    
            /* Send data */
            static const nrf_drv_usbd_transfer_t transfer =
            {
                .p_data = {.tx = &databuffer},
                .size = sizeof(databuffer)
            };
            m_send_mouse_position = true;
            UNUSED_RETURN_VALUE(nrf_drv_usbd_ep_transfer(
                NRF_DRV_USBD_EPIN1,
                &transfer));
        }
    }
    
    static void power_usb_event_handler(nrf_drv_power_usb_evt_t event)
    {
        switch (event)
        {
        case NRF_DRV_POWER_USB_EVT_DETECTED:
            NRF_LOG_INFO("USB power detected");
            if (!nrf_drv_usbd_is_enabled())
            {
                nrf_drv_usbd_enable();
            }
            break;
        case NRF_DRV_POWER_USB_EVT_REMOVED:
            NRF_LOG_INFO("USB power removed");
            m_usbd_configured = false;
            m_send_mouse_position = false;
            if (nrf_drv_usbd_is_started())
            {
                nrf_drv_usbd_stop();
            }
            if (nrf_drv_usbd_is_enabled())
            {
                nrf_drv_usbd_disable();
            }
            /* Turn OFF LEDs */
            bsp_board_led_off(LED_USB_STATUS);
            bsp_board_led_off(LED_USB_POWER);
            break;
        case NRF_DRV_POWER_USB_EVT_READY:
            NRF_LOG_INFO("USB ready");
            bsp_board_led_on(LED_USB_POWER);
            if (!nrf_drv_usbd_is_started())
            {
                nrf_drv_usbd_start(true);
            }
            break;
        default:
            ASSERT(false);
        }
    }
    
    static void bsp_evt_handler(bsp_event_t evt)
    {
        switch ((unsigned int)evt)
        {
        case BSP_EVENT_SYSOFF:
        {
            m_system_off_req = true;
            break;
        }
        case CONCAT_2(BSP_EVENT_KEY_, BTN_DATA_SEND):
        {
            m_send_flag = 1;
            break;
        }
        
        case BTN_DATA_KEY_RELEASE:
        {
            m_send_flag = 0;
            break;
        }
        default:
            return;
        }
    }
    
    static void init_power_clock(void)
    {
        ret_code_t ret;
        /* Initializing power and clock */
        ret = nrf_drv_clock_init();
        APP_ERROR_CHECK(ret);
        ret = nrf_drv_power_init(NULL);
        APP_ERROR_CHECK(ret);
        nrf_drv_clock_hfclk_request(NULL);
        nrf_drv_clock_lfclk_request(NULL);
        while (!(nrf_drv_clock_hfclk_is_running() &&
                nrf_drv_clock_lfclk_is_running()))
        {
            /* Just waiting */
        }
    
        ret = app_timer_init();
        APP_ERROR_CHECK(ret);
    
        /* Avoid warnings if assertion is disabled */
        UNUSED_VARIABLE(ret);
    }
    
    static void init_bsp(void)
    {
        ret_code_t ret;
        ret = bsp_init(BSP_INIT_BUTTONS, bsp_evt_handler);
        APP_ERROR_CHECK(ret);
    
        ret = bsp_event_to_button_action_assign(
            BTN_SYSTEM_OFF,
            BSP_BUTTON_ACTION_RELEASE,
            BSP_EVENT_SYSOFF);
        APP_ERROR_CHECK(ret);
        ret = bsp_event_to_button_action_assign(BTN_DATA_SEND,
                                                BSP_BUTTON_ACTION_RELEASE,
                                                BTN_DATA_KEY_RELEASE);
        APP_ERROR_CHECK(ret);
        /* Avoid warnings if assertion is disabled */
        UNUSED_VARIABLE(ret);
    }
    
    static void init_cli(void)
    {
        ret_code_t ret;
        ret = bsp_cli_init(bsp_evt_handler);
        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);
    }
    
    static void log_resetreason(void)
    {
        /* Reset reason */
        uint32_t rr = nrf_power_resetreas_get();
        NRF_LOG_INFO("Reset reasons:");
        if (0 == rr)
        {
            NRF_LOG_INFO("- NONE");
        }
        if (0 != (rr & NRF_POWER_RESETREAS_RESETPIN_MASK))
        {
            NRF_LOG_INFO("- RESETPIN");
        }
        if (0 != (rr & NRF_POWER_RESETREAS_DOG_MASK     ))
        {
            NRF_LOG_INFO("- DOG");
        }
        if (0 != (rr & NRF_POWER_RESETREAS_SREQ_MASK    ))
        {
            NRF_LOG_INFO("- SREQ");
        }
        if (0 != (rr & NRF_POWER_RESETREAS_LOCKUP_MASK  ))
        {
            NRF_LOG_INFO("- LOCKUP");
        }
        if (0 != (rr & NRF_POWER_RESETREAS_OFF_MASK     ))
        {
            NRF_LOG_INFO("- OFF");
        }
        if (0 != (rr & NRF_POWER_RESETREAS_LPCOMP_MASK  ))
        {
            NRF_LOG_INFO("- LPCOMP");
        }
        if (0 != (rr & NRF_POWER_RESETREAS_DIF_MASK     ))
        {
            NRF_LOG_INFO("- DIF");
        }
        if (0 != (rr & NRF_POWER_RESETREAS_NFC_MASK     ))
        {
            NRF_LOG_INFO("- NFC");
        }
        if (0 != (rr & NRF_POWER_RESETREAS_VBUS_MASK    ))
        {
            NRF_LOG_INFO("- VBUS");
        }
    }
    
    // End of added functions for USBD
    
    
    
    BLE_NUS_C_DEF(m_ble_nus_c);                                             /**< BLE Nordic UART Service (NUS) client instance. */
    NRF_BLE_GATT_DEF(m_gatt);                                               /**< GATT module instance. */
    BLE_DB_DISCOVERY_DEF(m_db_disc);                                        /**< Database discovery module instance. */
    NRF_BLE_SCAN_DEF(m_scan);                                               /**< Scanning Module instance. */
    
    static uint16_t m_ble_nus_max_data_len = BLE_GATT_ATT_MTU_DEFAULT - OPCODE_LENGTH - HANDLE_LENGTH; /**< Maximum length of data (in bytes) that can be transmitted to the peer by the Nordic UART service module. */
    
    /**@brief NUS UUID. */
    static ble_uuid_t const m_nus_uuid =
    {
        .uuid = BLE_UUID_NUS_SERVICE,
        .type = NUS_SERVICE_UUID_TYPE
    };
    
    
    /**@brief Function for handling asserts in the SoftDevice.
     *
     * @details This function is called in case of an assert in the SoftDevice.
     *
     * @warning This handler is only an example and is not meant for the final product. You need to analyze
     *          how your product is supposed to react in case of assert.
     * @warning On assert from the SoftDevice, the system can only recover on reset.
     *
     * @param[in] line_num     Line number of the failing assert call.
     * @param[in] p_file_name  File name of the failing assert call.
     */
    void assert_nrf_callback(uint16_t line_num, const uint8_t * p_file_name)
    {
        app_error_handler(0xDEADBEEF, line_num, p_file_name);
    }
    
    
    /**@brief Function for starting scanning. */
    static void scan_start(void)
    {
        ret_code_t ret;
    
        ret = nrf_ble_scan_start(&m_scan);
        APP_ERROR_CHECK(ret);
    
        ret = bsp_indication_set(BSP_INDICATE_SCANNING);
        APP_ERROR_CHECK(ret);
    }
    
    
    /**@brief Function for handling Scanning Module events.
     */
    static void scan_evt_handler(scan_evt_t const * p_scan_evt)
    {
        ret_code_t err_code;
    
        switch(p_scan_evt->scan_evt_id)
        {
             case NRF_BLE_SCAN_EVT_CONNECTING_ERROR:
             {
                  err_code = p_scan_evt->params.connecting_err.err_code;
                  APP_ERROR_CHECK(err_code);
             } break;
    
             case NRF_BLE_SCAN_EVT_CONNECTED:
             {
                  ble_gap_evt_connected_t const * p_connected =
                                   p_scan_evt->params.connected.p_connected;
                 // Scan is automatically stopped by the connection.
                 NRF_LOG_INFO("Connecting to target %02x%02x%02x%02x%02x%02x",
                          p_connected->peer_addr.addr[0],
                          p_connected->peer_addr.addr[1],
                          p_connected->peer_addr.addr[2],
                          p_connected->peer_addr.addr[3],
                          p_connected->peer_addr.addr[4],
                          p_connected->peer_addr.addr[5]
                          );
             } break;
    
             case NRF_BLE_SCAN_EVT_SCAN_TIMEOUT:
             {
                 NRF_LOG_INFO("Scan timed out.");
                 scan_start();
             } break;
    
             default:
                 break;
        }
    }
    
    
    /**@brief Function for initializing the scanning and setting the filters.
     */
    static void scan_init(void)
    {
        ret_code_t          err_code;
        nrf_ble_scan_init_t init_scan;
    
        memset(&init_scan, 0, sizeof(init_scan));
    
        init_scan.connect_if_match = true;
        init_scan.conn_cfg_tag     = APP_BLE_CONN_CFG_TAG;
    
        err_code = nrf_ble_scan_init(&m_scan, &init_scan, scan_evt_handler);
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_ble_scan_filter_set(&m_scan, SCAN_UUID_FILTER, &m_nus_uuid);
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_ble_scan_filters_enable(&m_scan, NRF_BLE_SCAN_UUID_FILTER, false);
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Function for handling database discovery events.
     *
     * @details This function is a callback function to handle events from the database discovery module.
     *          Depending on the UUIDs that are discovered, this function forwards the events
     *          to their respective services.
     *
     * @param[in] p_event  Pointer to the database discovery event.
     */
    static void db_disc_handler(ble_db_discovery_evt_t * p_evt)
    {
        ble_nus_c_on_db_disc_evt(&m_ble_nus_c, p_evt);
    }
    
    
    /**@brief Function for handling characters received by the Nordic UART Service (NUS).
     *
     * @details This function takes a list of characters of length data_len and prints the characters out on UART.
     *          If @ref ECHOBACK_BLE_UART_DATA is set, the data is sent back to sender.
     */
    static void ble_nus_chars_received_uart_print(uint8_t * p_data, uint16_t data_len)
    {
        ret_code_t ret_val;
    
        NRF_LOG_DEBUG("Receiving data.");
        NRF_LOG_HEXDUMP_DEBUG(p_data, data_len);
    
        for (uint32_t i = 0; i < data_len; i++)
        {
            do
            {
                ret_val = app_uart_put(p_data[i]);
                if ((ret_val != NRF_SUCCESS) && (ret_val != NRF_ERROR_BUSY))
                {
                    NRF_LOG_ERROR("app_uart_put failed for index 0x%04x.", i);
                    APP_ERROR_CHECK(ret_val);
                }
            } while (ret_val == NRF_ERROR_BUSY);
        }
        if (p_data[data_len-1] == '\r')
        {
            while (app_uart_put('\n') == NRF_ERROR_BUSY);
        }
        if (ECHOBACK_BLE_UART_DATA)
        {
            // Send data back to the peripheral.
            do
            {
                ret_val = ble_nus_c_string_send(&m_ble_nus_c, p_data, data_len);
                if ((ret_val != NRF_SUCCESS) && (ret_val != NRF_ERROR_BUSY))
                {
                    NRF_LOG_ERROR("Failed sending NUS message. Error 0x%x. ", ret_val);
                    APP_ERROR_CHECK(ret_val);
                }
            } while (ret_val == NRF_ERROR_BUSY);
        }
    }
    
    
    /**@brief   Function for handling app_uart events.
     *
     * @details This function receives a single character from the app_uart module and appends it to
     *          a string. The string is sent over BLE when the last character received is a
     *          'new line' '\n' (hex 0x0A) or if the string reaches the maximum data length.
     */
    void uart_event_handle(app_uart_evt_t * p_event)
    {
        static uint8_t data_array[BLE_NUS_MAX_DATA_LEN];
        static uint16_t index = 0;
        uint32_t ret_val;
    
        switch (p_event->evt_type)
        {
            /**@snippet [Handling data from UART] */
            case APP_UART_DATA_READY:
                UNUSED_VARIABLE(app_uart_get(&data_array[index]));
                index++;
    
                if ((data_array[index - 1] == '\n') || (index >= (m_ble_nus_max_data_len)))
                {
                    NRF_LOG_DEBUG("Ready to send data over BLE NUS");
                    NRF_LOG_HEXDUMP_DEBUG(data_array, index);
    
                    do
                    {
                        ret_val = ble_nus_c_string_send(&m_ble_nus_c, data_array, index);
                        if ( (ret_val != NRF_ERROR_INVALID_STATE) && (ret_val != NRF_ERROR_RESOURCES) )
                        {
                            APP_ERROR_CHECK(ret_val);
                        }
                    } while (ret_val == NRF_ERROR_RESOURCES);
    
                    index = 0;
                }
                break;
    
            /**@snippet [Handling data from UART] */
            case APP_UART_COMMUNICATION_ERROR:
                NRF_LOG_ERROR("Communication error occurred while handling UART.");
                APP_ERROR_HANDLER(p_event->data.error_communication);
                break;
    
            case APP_UART_FIFO_ERROR:
                NRF_LOG_ERROR("Error occurred in FIFO module used by UART.");
                APP_ERROR_HANDLER(p_event->data.error_code);
                break;
    
            default:
                break;
        }
    }
    
    
    /**@brief Callback handling Nordic UART Service (NUS) client events.
     *
     * @details This function is called to notify the application of NUS client events.
     *
     * @param[in]   p_ble_nus_c   NUS client handle. This identifies the NUS client.
     * @param[in]   p_ble_nus_evt Pointer to the NUS client event.
     */
    
    /**@snippet [Handling events from the ble_nus_c module] */
    static void ble_nus_c_evt_handler(ble_nus_c_t * p_ble_nus_c, ble_nus_c_evt_t const * p_ble_nus_evt)
    {
        ret_code_t err_code;
    
        switch (p_ble_nus_evt->evt_type)
        {
            case BLE_NUS_C_EVT_DISCOVERY_COMPLETE:
                NRF_LOG_INFO("Discovery complete.");
                err_code = ble_nus_c_handles_assign(p_ble_nus_c, p_ble_nus_evt->conn_handle, &p_ble_nus_evt->handles);
                APP_ERROR_CHECK(err_code);
    
                err_code = ble_nus_c_tx_notif_enable(p_ble_nus_c);
                APP_ERROR_CHECK(err_code);
                NRF_LOG_INFO("Connected to device with Nordic UART Service.");
                break;
    
            case BLE_NUS_C_EVT_NUS_TX_EVT:
                ble_nus_chars_received_uart_print(p_ble_nus_evt->p_data, p_ble_nus_evt->data_len);
                break;
    
            case BLE_NUS_C_EVT_DISCONNECTED:
                NRF_LOG_INFO("Disconnected.");
                scan_start();
                break;
        }
    }
    /**@snippet [Handling events from the ble_nus_c module] */
    
    
    /**
     * @brief Function for handling shutdown events.
     *
     * @param[in]   event       Shutdown type.
     */
    static bool shutdown_handler(nrf_pwr_mgmt_evt_t event)
    {
        ret_code_t err_code;
    
        err_code = bsp_indication_set(BSP_INDICATE_IDLE);
        APP_ERROR_CHECK(err_code);
    
        switch (event)
        {
            case NRF_PWR_MGMT_EVT_PREPARE_WAKEUP:
                // Prepare wakeup buttons.
                err_code = bsp_btn_ble_sleep_mode_prepare();
                APP_ERROR_CHECK(err_code);
                break;
    
            default:
                break;
        }
    
        return true;
    }
    
    NRF_PWR_MGMT_HANDLER_REGISTER(shutdown_handler, APP_SHUTDOWN_HANDLER_PRIORITY);
    
    
    /**@brief Function for handling BLE events.
     *
     * @param[in]   p_ble_evt   Bluetooth stack event.
     * @param[in]   p_context   Unused.
     */
    static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
    {
        ret_code_t            err_code;
        ble_gap_evt_t const * p_gap_evt = &p_ble_evt->evt.gap_evt;
    
        switch (p_ble_evt->header.evt_id)
        {
            case BLE_GAP_EVT_CONNECTED:
                err_code = ble_nus_c_handles_assign(&m_ble_nus_c, p_ble_evt->evt.gap_evt.conn_handle, NULL);
                APP_ERROR_CHECK(err_code);
    
                err_code = bsp_indication_set(BSP_INDICATE_CONNECTED);
                APP_ERROR_CHECK(err_code);
    
                // start discovery of services. The NUS Client waits for a discovery result
                err_code = ble_db_discovery_start(&m_db_disc, p_ble_evt->evt.gap_evt.conn_handle);
                APP_ERROR_CHECK(err_code);
                break;
    
            case BLE_GAP_EVT_DISCONNECTED:
    
                NRF_LOG_INFO("Disconnected. conn_handle: 0x%x, reason: 0x%x",
                             p_gap_evt->conn_handle,
                             p_gap_evt->params.disconnected.reason);
                break;
    
            case BLE_GAP_EVT_TIMEOUT:
                if (p_gap_evt->params.timeout.src == BLE_GAP_TIMEOUT_SRC_CONN)
                {
                    NRF_LOG_INFO("Connection Request timed out.");
                }
                break;
    
            case BLE_GAP_EVT_SEC_PARAMS_REQUEST:
                // Pairing not supported.
                err_code = sd_ble_gap_sec_params_reply(p_ble_evt->evt.gap_evt.conn_handle, BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP, NULL, NULL);
                APP_ERROR_CHECK(err_code);
                break;
    
            case BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST:
                // Accepting parameters requested by peer.
                err_code = sd_ble_gap_conn_param_update(p_gap_evt->conn_handle,
                                                        &p_gap_evt->params.conn_param_update_request.conn_params);
                APP_ERROR_CHECK(err_code);
                break;
    
            case BLE_GAP_EVT_PHY_UPDATE_REQUEST:
            {
                NRF_LOG_DEBUG("PHY update request.");
                ble_gap_phys_t const phys =
                {
                    .rx_phys = BLE_GAP_PHY_AUTO,
                    .tx_phys = BLE_GAP_PHY_AUTO,
                };
                err_code = sd_ble_gap_phy_update(p_ble_evt->evt.gap_evt.conn_handle, &phys);
                APP_ERROR_CHECK(err_code);
            } break;
    
            case BLE_GATTC_EVT_TIMEOUT:
                // Disconnect on GATT Client timeout event.
                NRF_LOG_DEBUG("GATT Client Timeout.");
                err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gattc_evt.conn_handle,
                                                 BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
                APP_ERROR_CHECK(err_code);
                break;
    
            case BLE_GATTS_EVT_TIMEOUT:
                // Disconnect on GATT Server timeout event.
                NRF_LOG_DEBUG("GATT Server Timeout.");
                err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gatts_evt.conn_handle,
                                                 BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
                APP_ERROR_CHECK(err_code);
                break;
    
            default:
                break;
        }
    }
    
    
    /**@brief Function for initializing the BLE stack.
     *
     * @details Initializes the SoftDevice and the BLE event interrupt.
     */
    static void ble_stack_init(void)
    {
        ret_code_t err_code;
    
        err_code = nrf_sdh_enable_request();
        APP_ERROR_CHECK(err_code);
    
        // Configure the BLE stack using the default settings.
        // Fetch the start address of the application RAM.
        uint32_t ram_start = 0;
        err_code = nrf_sdh_ble_default_cfg_set(APP_BLE_CONN_CFG_TAG, &ram_start);
        APP_ERROR_CHECK(err_code);
    
        // Enable BLE stack.
        err_code = nrf_sdh_ble_enable(&ram_start);
        APP_ERROR_CHECK(err_code);
    
        // Register a handler for BLE events.
        NRF_SDH_BLE_OBSERVER(m_ble_observer, APP_BLE_OBSERVER_PRIO, ble_evt_handler, NULL);
    }
    
    
    /**@brief Function for handling events from the GATT library. */
    void gatt_evt_handler(nrf_ble_gatt_t * p_gatt, nrf_ble_gatt_evt_t const * p_evt)
    {
        if (p_evt->evt_id == NRF_BLE_GATT_EVT_ATT_MTU_UPDATED)
        {
            NRF_LOG_INFO("ATT MTU exchange completed.");
    
            m_ble_nus_max_data_len = p_evt->params.att_mtu_effective - OPCODE_LENGTH - HANDLE_LENGTH;
            NRF_LOG_INFO("Ble NUS max data length set to 0x%X(%d)", m_ble_nus_max_data_len, m_ble_nus_max_data_len);
        }
    }
    
    
    /**@brief Function for initializing the GATT library. */
    void gatt_init(void)
    {
        ret_code_t err_code;
    
        err_code = nrf_ble_gatt_init(&m_gatt, gatt_evt_handler);
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_ble_gatt_att_mtu_central_set(&m_gatt, NRF_SDH_BLE_GATT_MAX_MTU_SIZE);
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Function for handling events from the BSP module.
     *
     * @param[in] event  Event generated by button press.
     */
    void bsp_event_handler(bsp_event_t event)
    {
        ret_code_t err_code;
    
        switch (event)
        {
            case BSP_EVENT_SLEEP:
                nrf_pwr_mgmt_shutdown(NRF_PWR_MGMT_SHUTDOWN_GOTO_SYSOFF);
                break;
    
            case BSP_EVENT_DISCONNECT:
                err_code = sd_ble_gap_disconnect(m_ble_nus_c.conn_handle,
                                                 BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
                if (err_code != NRF_ERROR_INVALID_STATE)
                {
                    APP_ERROR_CHECK(err_code);
                }
                break;
    
            default:
                break;
        }
    }
    
    /**@brief Function for initializing the UART. */
    static void uart_init(void)
    {
        ret_code_t err_code;
    
        app_uart_comm_params_t const comm_params =
        {
            .rx_pin_no    = RX_PIN_NUMBER,
            .tx_pin_no    = TX_PIN_NUMBER,
            .rts_pin_no   = RTS_PIN_NUMBER,
            .cts_pin_no   = CTS_PIN_NUMBER,
            .flow_control = APP_UART_FLOW_CONTROL_DISABLED,
            .use_parity   = false,
            .baud_rate    = UART_BAUDRATE_BAUDRATE_Baud115200
        };
    
        APP_UART_FIFO_INIT(&comm_params,
                           UART_RX_BUF_SIZE,
                           UART_TX_BUF_SIZE,
                           uart_event_handle,
                           APP_IRQ_PRIORITY_LOWEST,
                           err_code);
    
        APP_ERROR_CHECK(err_code);
    }
    
    /**@brief Function for initializing the Nordic UART Service (NUS) client. */
    static void nus_c_init(void)
    {
        ret_code_t       err_code;
        ble_nus_c_init_t init;
    
        init.evt_handler = ble_nus_c_evt_handler;
    
        err_code = ble_nus_c_init(&m_ble_nus_c, &init);
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Function for initializing buttons and leds. */
    static void buttons_leds_init(void)
    {
        ret_code_t err_code;
        bsp_event_t startup_event;
    
        err_code = bsp_init(BSP_INIT_LEDS, bsp_event_handler);
        APP_ERROR_CHECK(err_code);
    
        err_code = bsp_btn_ble_init(NULL, &startup_event);
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Function for initializing the timer. */
    static void timer_init(void)
    {
        ret_code_t err_code = app_timer_init();
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Function for initializing the nrf log module. */
    static void log_init(void)
    {
        ret_code_t err_code = NRF_LOG_INIT(NULL);
        APP_ERROR_CHECK(err_code);
    
        NRF_LOG_DEFAULT_BACKENDS_INIT();
    }
    
    
    /**@brief Function for initializing power management.
     */
    static void power_management_init(void)
    {
        ret_code_t err_code;
        err_code = nrf_pwr_mgmt_init();
        APP_ERROR_CHECK(err_code);
    }
    
    
    /** @brief Function for initializing the database discovery module. */
    static void db_discovery_init(void)
    {
        ret_code_t err_code = ble_db_discovery_init(db_disc_handler);
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Function for handling the idle state (main loop).
     *
     * @details Handles any pending log operations, then sleeps until the next event occurs.
     */
    static void idle_state_handle(void)
    {
        if (NRF_LOG_PROCESS() == false)
        {
            nrf_pwr_mgmt_run();
        }
    }
    
    
    int main(void)
      {
        // From USBD main 
        ret_code_t ret;
        UNUSED_RETURN_VALUE(NRF_LOG_INIT(NULL));
    
        init_power_clock();
        init_bsp();
        init_cli();
        log_resetreason();
        nrf_power_resetreas_clear(nrf_power_resetreas_get());
        /* USB work starts right here */
        ret = nrf_drv_usbd_init(usbd_event_handler);
        APP_ERROR_CHECK(ret);
    
        /* Configure selected size of the packed on EP0 */
        nrf_drv_usbd_ep_max_packet_size_set(NRF_DRV_USBD_EPOUT0, EP0_MAXPACKETSIZE);
        nrf_drv_usbd_ep_max_packet_size_set(NRF_DRV_USBD_EPIN0, EP0_MAXPACKETSIZE);
    
        /* Configure LED and button */
        bsp_board_init(BSP_INIT_LEDS);
        bsp_board_led_on(LED_RUNNING);
        bsp_board_led_on(LED_ACTIVE);
    
    
        if (USBD_POWER_DETECTION)
        {
            static const nrf_drv_power_usbevt_config_t config =
            {
                .handler = power_usb_event_handler
            };
            ret = nrf_drv_power_usbevt_init(&config);
            APP_ERROR_CHECK(ret);
        }
        else
        {
            NRF_LOG_INFO("No USB power detection enabled\r\nStarting USB now");
            nrf_delay_us(STARTUP_DELAY);
            if (!nrf_drv_usbd_is_enabled())
            {
                nrf_drv_usbd_enable();
                ret = ep_configuration(0);
                APP_ERROR_CHECK(ret);
            }
            /* Wait for regulator power up */
            while (NRF_DRV_POWER_USB_STATE_CONNECTED
                  ==
                  nrf_drv_power_usbstatus_get())
            {
                /* Just waiting */
            }
    
            if (NRF_DRV_POWER_USB_STATE_READY == nrf_drv_power_usbstatus_get())
            {
                if (!nrf_drv_usbd_is_started())
                {
                    nrf_drv_usbd_start(true);
                }
            }
            else
            {
                nrf_drv_usbd_disable();
            }
        }
        // End of the first part of the USBD main
    
        // Initialize.
        log_init();
        timer_init();
        uart_init();
        buttons_leds_init();
        db_discovery_init();
        power_management_init();
        ble_stack_init();
        gatt_init();
        nus_c_init();
        scan_init();
    
        // Start execution.
        printf("BLE UART central example started.\r\n");
        NRF_LOG_INFO("BLE UART central example started.");
        scan_start();
    
        // Added second part of the main
            while (true)
        {
            if (m_system_off_req)
            {
                NRF_LOG_INFO("Going to system OFF");
                NRF_LOG_FLUSH();
                bsp_board_led_off(LED_RUNNING);
                bsp_board_led_off(LED_ACTIVE);
                nrf_power_system_off();
            }
            if (m_usbd_suspended != m_usbd_suspend_state_req)
            {
                if (m_usbd_suspend_state_req)
                {
                    m_usbd_suspended = nrf_drv_usbd_suspend();
                    if (m_usbd_suspended)
                    {
                        bsp_board_leds_off();
                    }
                }
                else
                {
                    m_usbd_suspended = false;
                }
            }
    
            if (m_usbd_configured)
            {
                if (m_send_flag)
                {
                    if (m_usbd_suspended)
                    {
                        if (m_usbd_rwu_enabled)
                        {
                            UNUSED_RETURN_VALUE(nrf_drv_usbd_wakeup_req());
                        }
                    }
                    else
                    {
                        NRF_LOG_INFO("   TX pointer");
                        move_mouse_pointer();
                    }
                }
            }
    
             nrf_cli_process(&m_cli_uart);
            UNUSED_RETURN_VALUE(NRF_LOG_PROCESS());
            bsp_board_led_off(LED_RUNNING);
            /* Even if we miss an event enabling USB,
             * USB event would wake us up. */
            __WFE();
            /* Clear SEV flag if CPU was woken up by event */
            __SEV();
            __WFE();
            bsp_board_led_on(LED_RUNNING);
    
        // End of second part of the main
    
        // Enter main loop.
        
        for (;;)
        {
            idle_state_handle();
        }
     }
     }
    

    Help is appreciated Andreas,

    Maher

  • Hi.

    What errors do you get? Can you list them? Could i take a look at the project? I can make this ticket private if you only wish to share it with me.

    Best regards,

    Andreas

Related