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