-
-
Save schef/f945611d3835dc708371269407b29c6b to your computer and use it in GitHub Desktop.
Nordic SDK14 C++ BLE wrapper
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdint.h> | |
#include <string.h> | |
#include "nordic_common.h" | |
#include "nrf.h" | |
#include "boards.h" | |
#include "app_error.h" | |
#include "ble.h" | |
#include "ble_hci.h" | |
#include "ble_srv_common.h" | |
#include "ble_advdata.h" | |
#include "ble_conn_params.h" | |
#include "ble_conn_state.h" | |
#include "nrf_sdh.h" | |
#include "nrf_sdh_ble.h" | |
#include "app_timer.h" | |
#include "ble_lbs.h" | |
#include "nrf_ble_gatt.h" | |
#include "nrf_log.h" | |
#include "nrf_log_ctrl.h" | |
#include "nrf_log_default_backends.h" | |
#include "ble_wrapper.h" | |
#include "ble_wrapper.h" | |
#include "SEGGER_RTT.h" | |
#include "nrf_log.h" | |
#include "nrf_log_ctrl.h" | |
#define NRF_LOG_MODULE_NAME BLE_WRAPPER | |
NRF_LOG_MODULE_REGISTER(); | |
#define DEVICE_NAME "beaconName" /**< Name of device. Will be included in the advertising data. */ | |
#define APP_BLE_CONN_CFG_TAG 1 /**< A tag identifying the SoftDevice BLE configuration. */ | |
#define LINK_TOTAL NRF_SDH_BLE_PERIPHERAL_LINK_COUNT + \ | |
NRF_SDH_BLE_CENTRAL_LINK_COUNT | |
#define APP_ADV_INTERVAL MSEC_TO_UNITS(100, UNIT_0_625_MS) /**< The advertising interval (in units of 0.625 ms; this value corresponds to 40 ms). */ | |
#define APP_ADV_TIMEOUT_IN_SECONDS BLE_GAP_ADV_TIMEOUT_GENERAL_UNLIMITED /**< The advertising time-out (in units of seconds). When set to 0, we will never time out. */ | |
#define MIN_CONN_INTERVAL MSEC_TO_UNITS(100, UNIT_1_25_MS) /**< Minimum acceptable connection interval (0.5 seconds). */ | |
#define MAX_CONN_INTERVAL MSEC_TO_UNITS(200, UNIT_1_25_MS) /**< Maximum acceptable connection interval (1 second). */ | |
#define SLAVE_LATENCY 0 /**< Slave latency. */ | |
#define CONN_SUP_TIMEOUT MSEC_TO_UNITS(4000, UNIT_10_MS) /**< Connection supervisory time-out (4 seconds). */ | |
#define FIRST_CONN_PARAMS_UPDATE_DELAY APP_TIMER_TICKS(20000) /**< Time from initiating event (connect or start of notification) to first time sd_ble_gap_conn_param_update is called (15 seconds). */ | |
#define NEXT_CONN_PARAMS_UPDATE_DELAY APP_TIMER_TICKS(5000) /**< Time between each call to sd_ble_gap_conn_param_update after the first call (5 seconds). */ | |
#define MAX_CONN_PARAMS_UPDATE_COUNT 3 /**< Number of attempts before giving up the connection parameter negotiation. */ | |
#define APP_FEATURE_NOT_SUPPORTED BLE_GATT_STATUS_ATTERR_APP_BEGIN + 2 /**< Reply when unsupported features are requested. */ | |
#define DEAD_BEEF 0xDEADBEEF /**< Value used as error code on stack dump, can be used to identify stack location on stack unwind. */ | |
/**@brief Priority of the application BLE event handler. | |
* @note You shouldn't need to modify this value. | |
*/ | |
#define APP_BLE_OBSERVER_PRIO 1 | |
#define NRF_APP_PRIORITY_LOW 6 | |
BLE_LBS_DEF(m_lbs); /**< LED Button Service instance. */ | |
NRF_BLE_GATT_DEF(m_gatt); /**< GATT module instance. */ | |
BleWrapper* BleWrapper::_pInstance = NULL; | |
BleWrapper* BleWrapper::getInstance(void) | |
{ | |
if(_pInstance == NULL) | |
{ | |
_pInstance = new BleWrapper(); | |
} | |
return(_pInstance); | |
} | |
BleWrapper::BleWrapper(void) | |
{ | |
NRF_LOG_INFO("constructor"); | |
init(); | |
} | |
/**@brief Function for the Timer initialization. | |
* | |
* @details Initializes the timer module. | |
*/ | |
void BleWrapper::timers_init(void) | |
{ | |
// Initialize timer module, making it use the scheduler | |
ret_code_t err_code = app_timer_init(); | |
APP_ERROR_CHECK(err_code); | |
} | |
/**@brief Function for the GAP initialization. | |
* | |
* @details This function sets up all the necessary GAP (Generic Access Profile) parameters of the | |
* device including the device name, appearance, and the preferred connection parameters. | |
*/ | |
void BleWrapper::gap_params_init(void) | |
{ | |
ret_code_t err_code; | |
ble_gap_conn_params_t gap_conn_params; | |
ble_gap_conn_sec_mode_t sec_mode; | |
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode); | |
err_code = sd_ble_gap_device_name_set(&sec_mode, | |
(const uint8_t *)DEVICE_NAME, | |
strlen(DEVICE_NAME)); | |
APP_ERROR_CHECK(err_code); | |
memset(&gap_conn_params, 0, sizeof(gap_conn_params)); | |
gap_conn_params.min_conn_interval = MIN_CONN_INTERVAL; | |
gap_conn_params.max_conn_interval = MAX_CONN_INTERVAL; | |
gap_conn_params.slave_latency = SLAVE_LATENCY; | |
gap_conn_params.conn_sup_timeout = CONN_SUP_TIMEOUT; | |
err_code = sd_ble_gap_ppcp_set(&gap_conn_params); | |
APP_ERROR_CHECK(err_code); | |
} | |
/**@brief Function for initializing the GATT module. | |
*/ | |
void BleWrapper::gatt_init(void) | |
{ | |
ret_code_t err_code = nrf_ble_gatt_init(&m_gatt, NULL); | |
APP_ERROR_CHECK(err_code); | |
} | |
/**@brief Function for initializing the Advertising functionality. | |
* | |
* @details Encodes the required advertising data and passes it to the stack. | |
* Also builds a structure to be passed to the stack when starting advertising. | |
*/ | |
void BleWrapper::advertising_init(void) | |
{ | |
ret_code_t err_code; | |
ble_advdata_t advdata; | |
// Build and set advertising data | |
memset(&advdata, 0, sizeof(advdata)); | |
advdata.name_type = BLE_ADVDATA_NO_NAME; | |
advdata.include_appearance = false; | |
advdata.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE; | |
err_code = ble_advdata_set(&advdata, NULL); | |
APP_ERROR_CHECK(err_code); | |
} | |
/**@brief Function for initializing services that will be used by the application. | |
*/ | |
void BleWrapper::services_init(void) | |
{ | |
ret_code_t err_code; | |
ble_lbs_init_t init; | |
err_code = ble_lbs_init(&m_lbs, &init); | |
APP_ERROR_CHECK(err_code); | |
ble_conn_state_init(); | |
} | |
/**@brief Function for handling a Connection Parameters error. | |
* | |
* @param[in] nrf_error Error code containing information about what went wrong. | |
*/ | |
void BleWrapper::conn_params_error_handler(uint32_t nrf_error) | |
{ | |
APP_ERROR_HANDLER(nrf_error); | |
} | |
/**@brief Function for initializing the Connection Parameters module. | |
*/ | |
void BleWrapper::conn_params_init(void) | |
{ | |
ret_code_t err_code; | |
ble_conn_params_init_t cp_init; | |
memset(&cp_init, 0, sizeof(cp_init)); | |
cp_init.p_conn_params = NULL; | |
cp_init.first_conn_params_update_delay = FIRST_CONN_PARAMS_UPDATE_DELAY; | |
cp_init.next_conn_params_update_delay = NEXT_CONN_PARAMS_UPDATE_DELAY; | |
cp_init.max_conn_params_update_count = MAX_CONN_PARAMS_UPDATE_COUNT; | |
cp_init.start_on_notify_cccd_handle = BLE_GATT_HANDLE_INVALID; | |
cp_init.disconnect_on_fail = true; | |
cp_init.error_handler = conn_params_error_handler; | |
err_code = ble_conn_params_init(&cp_init); | |
APP_ERROR_CHECK(err_code); | |
} | |
/**@brief Function for starting advertising. | |
*/ | |
void BleWrapper::advertising_start(void) | |
{ | |
ret_code_t err_code; | |
ble_gap_adv_params_t adv_params; | |
// Start advertising | |
memset(&adv_params, 0, sizeof(adv_params)); | |
adv_params.type = BLE_GAP_ADV_TYPE_ADV_IND; | |
adv_params.p_peer_addr = NULL; | |
adv_params.fp = BLE_GAP_ADV_FP_ANY; | |
adv_params.interval = APP_ADV_INTERVAL; | |
adv_params.timeout = APP_ADV_TIMEOUT_IN_SECONDS; | |
err_code = sd_ble_gap_adv_start(&adv_params, APP_BLE_CONN_CFG_TAG); | |
APP_ERROR_CHECK(err_code); | |
} | |
/**@brief Function for handling the Connected event. | |
* | |
* @param[in] p_gap_evt GAP event received from the BLE stack. | |
*/ | |
void BleWrapper::on_connected(const ble_gap_evt_t * const p_gap_evt) | |
{ | |
uint32_t periph_link_cnt = ble_conn_state_n_peripherals(); // Number of peripheral links. | |
NRF_LOG_INFO("Connection with link 0x%x established.", p_gap_evt->conn_handle); | |
if (periph_link_cnt == NRF_SDH_BLE_PERIPHERAL_LINK_COUNT) | |
{ | |
} | |
else | |
{ | |
// Continue advertising. More connections can be established because the maximum link count has not been reached. | |
advertising_start(); | |
} | |
} | |
/**@brief Function for handling the Disconnected event. | |
* | |
* @param[in] p_gap_evt GAP event received from the BLE stack. | |
*/ | |
void BleWrapper::on_disconnected(ble_gap_evt_t const * const p_gap_evt) | |
{ | |
uint32_t periph_link_cnt = ble_conn_state_n_peripherals(); // Number of peripheral links. | |
NRF_LOG_INFO("Connection 0x%x has been disconnected. Reason: 0x%X", | |
p_gap_evt->conn_handle, | |
p_gap_evt->params.disconnected.reason); | |
if (periph_link_cnt == (NRF_SDH_BLE_PERIPHERAL_LINK_COUNT - 1)) | |
{ | |
// Advertising is not running when all connections are taken, and must therefore be started. | |
advertising_start(); | |
} | |
} | |
/**@brief Function for handling the Read/Write Authorization request event. | |
* | |
* @param[in] p_ble_evt Event received from the BLE stack. | |
*/ | |
void BleWrapper::on_authorize_request(ble_evt_t const * p_ble_evt) | |
{ | |
ret_code_t err_code; | |
ble_gatts_evt_rw_authorize_request_t req; | |
ble_gatts_rw_authorize_reply_params_t auth_reply; | |
req = p_ble_evt->evt.gatts_evt.params.authorize_request; | |
if (req.type != BLE_GATTS_AUTHORIZE_TYPE_INVALID) | |
{ | |
if ((req.request.write.op == BLE_GATTS_OP_PREP_WRITE_REQ) || | |
(req.request.write.op == BLE_GATTS_OP_EXEC_WRITE_REQ_NOW) || | |
(req.request.write.op == BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL)) | |
{ | |
if (req.type == BLE_GATTS_AUTHORIZE_TYPE_WRITE) | |
{ | |
auth_reply.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE; | |
} | |
else | |
{ | |
auth_reply.type = BLE_GATTS_AUTHORIZE_TYPE_READ; | |
} | |
auth_reply.params.write.gatt_status = APP_FEATURE_NOT_SUPPORTED; | |
err_code = sd_ble_gatts_rw_authorize_reply(p_ble_evt->evt.gatts_evt.conn_handle, | |
&auth_reply); | |
APP_ERROR_CHECK(err_code); | |
} | |
} | |
} | |
/**@brief Function for handling BLE events. | |
* | |
* @param[in] p_ble_evt Bluetooth stack event. | |
* @param[in] p_context Unused. | |
*/ | |
void BleWrapper::ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context) | |
{ | |
ret_code_t err_code; | |
switch (p_ble_evt->header.evt_id) | |
{ | |
case BLE_GAP_EVT_CONNECTED: | |
on_connected(&p_ble_evt->evt.gap_evt); | |
break; | |
case BLE_GAP_EVT_DISCONNECTED: | |
on_disconnected(&p_ble_evt->evt.gap_evt); | |
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; | |
#if defined(S132) | |
case BLE_GAP_EVT_PHY_UPDATE_REQUEST: | |
{ | |
NRF_LOG_DEBUG("PHY update request."); | |
ble_gap_phys_t const phys = { BLE_GAP_PHY_AUTO, 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; | |
#endif | |
case BLE_GATTS_EVT_SYS_ATTR_MISSING: | |
// No system attributes have been stored. | |
err_code = sd_ble_gatts_sys_attr_set(p_ble_evt->evt.gap_evt.conn_handle, NULL, 0, 0); | |
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; | |
case BLE_EVT_USER_MEM_REQUEST: | |
err_code = sd_ble_user_mem_reply(p_ble_evt->evt.gattc_evt.conn_handle, NULL); | |
APP_ERROR_CHECK(err_code); | |
break; | |
case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST: | |
on_authorize_request(p_ble_evt); | |
break; | |
default: | |
// No implementation needed. | |
break; | |
} | |
} | |
void BleWrapper::static_ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context) | |
{ | |
BleWrapper::getInstance()->ble_evt_handler(p_ble_evt, p_context); | |
} | |
/**@brief Function for initializing the BLE stack. | |
* | |
* @details Initializes the SoftDevice and the BLE event interrupt. | |
*/ | |
void BleWrapper::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, static_ble_evt_handler, NULL); | |
} | |
/**@brief Function for bluetooth init. | |
*/ | |
void BleWrapper::init(void) | |
{ | |
// Initialize. | |
timers_init(); | |
ble_stack_init(); | |
gap_params_init(); | |
gatt_init(); | |
services_init(); | |
advertising_init(); | |
conn_params_init(); | |
} | |
void BleWrapper::start(void) | |
{ | |
NRF_LOG_INFO("start\n"); | |
advertising_start(); | |
} | |
void BleWrapper::getMac(uint8_t * buffer) | |
{ | |
ble_gap_addr_t device_addr; | |
sd_ble_gap_addr_get(&device_addr); | |
buffer[0] = device_addr.addr[5]; | |
buffer[1] = device_addr.addr[4]; | |
buffer[2] = device_addr.addr[3]; | |
buffer[3] = device_addr.addr[2]; | |
buffer[4] = device_addr.addr[1]; | |
buffer[5] = device_addr.addr[0]; | |
} | |
/** | |
* @} | |
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef _ble_wrapper_h | |
#define _ble_wrapper_h | |
#include "ble_gap.h" | |
#include "ble.h" | |
class BleWrapper | |
{ | |
protected: | |
static BleWrapper *_pInstance; | |
BleWrapper(void); | |
void timers_init(void); | |
void gap_params_init(void); | |
void gatt_init(void); | |
void advertising_init(void); | |
void services_init(void); | |
static void conn_params_error_handler(uint32_t nrf_error); | |
void conn_params_init(void); | |
void advertising_start(void); | |
void on_connected(const ble_gap_evt_t * const p_gap_evt); | |
void on_disconnected(ble_gap_evt_t const * const p_gap_evt); | |
void on_authorize_request(ble_evt_t const * p_ble_evt); | |
void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context); | |
static void static_ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context); | |
void ble_stack_init(void); | |
public: | |
static BleWrapper *getInstance(void); | |
void init(void); | |
void start(void); | |
void getMac(uint8_t * buffer); | |
}; | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment