Hello,
The intent of the implementation is to first connected to a central using fast advertisement and once they are connected the first time, if they disconnect, the peripheral (this device) would start low duty cycle direct advertisement just for the particular central over a long period.
I had the direct advertisement realized few days ago, but the code was not reliable, and now after some restructure of my program, I can not have direct advertisement start again after a Ble disconnect. Here is my code, hope someone could point out what I am missing, thanks.
app_timer, and all the non-static functions are initialized in main.
#include "appBle.h"
dm_application_instance_t m_app_handle; /**< Application identifier allocated by device manager. */
dm_handle_t m_bonded_peer_handle; /**< Device reference handle to the current connected peer. */
ble_nus_t m_nus;
uint16_t m_conn_handle = BLE_CONN_HANDLE_INVALID;
ble_uuid_t m_adv_uuids[] = {{BLE_UUID_NUS_SERVICE, NUS_SERVICE_UUID_TYPE}};
void gap_params_init(void)
{
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);
sd_ble_gap_device_name_set(&sec_mode,
(const uint8_t *) DEVICE_NAME,
strlen(DEVICE_NAME));
sd_ble_gap_appearance_set(BLE_APPEARANCE_GENERIC_WATCH);
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;
sd_ble_gap_ppcp_set(&gap_conn_params);
}
static void nus_data_handler(ble_nus_t * p_nus, uint8_t * p_data, uint16_t length)
{
// Todo
}
void services_init(void)
{
ble_nus_init_t nus_init;
memset(&nus_init, 0, sizeof(nus_init));
nus_init.data_handler = nus_data_handler;
ble_nus_init(&m_nus, &nus_init);
}
static void on_conn_params_evt(ble_conn_params_evt_t * p_evt)
{
SEGGER_RTT_printf(0, "[Ble] conn event: %X", p_evt->evt_type);
if(p_evt->evt_type == BLE_CONN_PARAMS_EVT_FAILED)
{
sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_CONN_INTERVAL_UNACCEPTABLE);
SEGGER_RTT_WriteString(0, "[Ble] conn event Disconnected");
}
}
static void conn_params_error_handler(uint32_t nrf_error)
{
// TBD
}
void conn_params_init(void)
{
uint32_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 = false;
cp_init.evt_handler = on_conn_params_evt;
cp_init.error_handler = conn_params_error_handler;
err_code = ble_conn_params_init(&cp_init);
SEGGER_RTT_printf(0, "[Ble] conn params init error: %8X\n", err_code);
}
static void on_adv_evt(ble_adv_evt_t ble_adv_evt)
{
uint32_t err_code;
SEGGER_RTT_printf(0, "[Ble] Adv event: %2X\n", ble_adv_evt);
switch (ble_adv_evt)
{
case BLE_ADV_EVT_FAST:
SEGGER_RTT_WriteString(0, "[Ble] Adv Fast\n");
break;
case BLE_ADV_EVT_IDLE:
SEGGER_RTT_WriteString(0, "[Ble] Adv Idle\n");
break;
case BLE_ADV_EVT_DIRECTED:
SEGGER_RTT_WriteString(0, "[Ble] Adv Directed\n");
break;
case BLE_ADV_EVT_DIRECTED_SLOW:
SEGGER_RTT_WriteString(0, "[Ble] Adv Directed Slow\n");
break;
case BLE_ADV_EVT_PEER_ADDR_REQUEST:
{
SEGGER_RTT_WriteString(0, "[Ble] Adv Peer Addr Req\n");
ble_gap_addr_t peer_address;
if(m_bonded_peer_handle.appl_id != DM_INVALID_ID)
{
err_code = dm_peer_addr_get(&m_bonded_peer_handle, &peer_address);
if (err_code != (NRF_ERROR_NOT_FOUND | DEVICE_MANAGER_ERR_BASE))
{
ble_advertising_peer_addr_reply(&peer_address);
SEGGER_RTT_WriteString(0, "[Ble] Adv Peer Addr Reply\n");
}
}
break;
}
default:
break;
}
}
static void on_ble_evt(ble_evt_t * p_ble_evt)
{
const ble_gap_evt_t * const p_gap_evt = &p_ble_evt->evt.gap_evt;
SEGGER_RTT_printf(0, "[Ble] Event ID: %2X\n", p_ble_evt->header.evt_id);
switch (p_ble_evt->header.evt_id)
{
case BLE_GAP_EVT_CONNECTED:
m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
setState(STATE_READY);
break;
case BLE_GAP_EVT_DISCONNECTED:
m_conn_handle = BLE_CONN_HANDLE_INVALID;
if(curState != STATE_SETUP)
{
setState(STATE_RECONNECT);
}
break;
case BLE_GAP_EVT_SEC_PARAMS_REQUEST:
sd_ble_gap_sec_params_reply(m_conn_handle, BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP, NULL, NULL);
break;
case BLE_GATTS_EVT_SYS_ATTR_MISSING:
sd_ble_gatts_sys_attr_set(m_conn_handle, NULL, 0, 0);
break;
case BLE_GAP_EVT_TIMEOUT:
{
SEGGER_RTT_printf(0, "[Ble] Adv Timeout: %2X\n", p_gap_evt->params.timeout.src);
switch(p_gap_evt->params.timeout.src)
{
case BLE_GAP_TIMEOUT_SRC_ADVERTISING:
if (curState == STATE_SETUP)
{
setState(STATE_SLEEP);
}
else if (curState == STATE_RECONNECT)
{
setState(STATE_RECONNECT); // continue until reset
}
break;
default:
break;
}
} break; // BLE_GAP_EVT_TIMEOUT
default:
break;
}
}
static void ble_evt_dispatch(ble_evt_t * p_ble_evt)
{
SEGGER_RTT_printf(0, "[Ble] evt dispatch: %2X\n", p_ble_evt->evt);
SEGGER_RTT_printf(0, "[Ble] evt dispatch: %2X\n", p_ble_evt->header);
on_ble_evt(p_ble_evt);
ble_advertising_on_ble_evt(p_ble_evt);
ble_conn_params_on_ble_evt(p_ble_evt);
ble_nus_on_ble_evt(&m_nus, p_ble_evt);
dm_ble_evt_handler(p_ble_evt);
// if this handler happens before adv, it causes error
}
static void sys_evt_dispatch(uint32_t sys_evt)
{
pstorage_sys_event_handler(sys_evt);
ble_advertising_on_sys_evt(sys_evt);
}
void ble_stack_init(void)
{
uint32_t err_code;
nrf_clock_lf_cfg_t clock_lf_cfg = NRF_CLOCK_LFCLKSRC;
// Initialize SoftDevice.
SOFTDEVICE_HANDLER_INIT(&clock_lf_cfg, NULL);
ble_enable_params_t ble_enable_params;
err_code = softdevice_enable_get_default_config(CENTRAL_LINK_COUNT,
PERIPHERAL_LINK_COUNT,
&ble_enable_params);
SEGGER_RTT_printf(0, "[Ble] Softdevice config error: %8X\n", err_code);
//Check the ram settings against the used number of links
CHECK_RAM_START_ADDR(CENTRAL_LINK_COUNT,PERIPHERAL_LINK_COUNT);
// Enable BLE stack.
err_code = softdevice_enable(&ble_enable_params);
SEGGER_RTT_printf(0, "[Ble] Softdevice enable error: %8X\n", err_code);
// Subscribe for BLE events.
err_code = softdevice_ble_evt_handler_set(ble_evt_dispatch);
SEGGER_RTT_printf(0, "[Ble] Softdevice event handler set error: %8X\n", err_code);
// Register with the SoftDevice handler module for BLE events.
err_code = softdevice_sys_evt_handler_set(sys_evt_dispatch);
SEGGER_RTT_printf(0, "[Ble] Softdevice sys event set error: %8X\n", err_code);
}
static uint32_t device_manager_evt_handler(dm_handle_t const * p_handle,
dm_event_t const * p_event,
ret_code_t event_result)
{
switch (p_event->event_id)
{
case DM_EVT_DEVICE_CONTEXT_LOADED: // Fall through.
case DM_EVT_SECURITY_SETUP_COMPLETE:
m_bonded_peer_handle = (*p_handle);
SEGGER_RTT_WriteString(0, "Peer handle bonded");
break;
}
return NRF_SUCCESS;
}
void device_manager_init(bool erase_bonds)
{
uint32_t err_code;
dm_init_param_t init_param = {.clear_persistent_data = erase_bonds};
dm_application_param_t register_param;
// Initialize peer device handle.
err_code = dm_handle_initialize(&m_bonded_peer_handle);
SEGGER_RTT_printf(0, "[Ble] dm handle init error: %8X\n", err_code);
// Initialize persistent storage module.
err_code = pstorage_init();
SEGGER_RTT_printf(0, "[Ble] pstorage init: %8X\n", err_code);
err_code = dm_init(&init_param);
SEGGER_RTT_printf(0, "[Ble] dm init: %8X\n", err_code);
memset(®ister_param.sec_param, 0, sizeof(ble_gap_sec_params_t));
register_param.sec_param.bond = SEC_PARAM_BOND;
register_param.sec_param.mitm = SEC_PARAM_MITM;
register_param.sec_param.lesc = SEC_PARAM_LESC;
register_param.sec_param.keypress = SEC_PARAM_KEYPRESS;
register_param.sec_param.io_caps = SEC_PARAM_IO_CAPABILITIES;
register_param.sec_param.oob = SEC_PARAM_OOB;
register_param.sec_param.min_key_size = SEC_PARAM_MIN_KEY_SIZE;
register_param.sec_param.max_key_size = SEC_PARAM_MAX_KEY_SIZE;
register_param.evt_handler = device_manager_evt_handler;
register_param.service_type = DM_PROTOCOL_CNTXT_GATT_SRVR_ID;
err_code = dm_register(&m_app_handle, ®ister_param);
SEGGER_RTT_printf(0, "[Ble] dm register error: %8X\n", err_code);
}
void advertising_init(void)
{
uint32_t err_code;
ble_advdata_t advdata;
ble_advdata_t scanrsp;
memset(&advdata, 0, sizeof(advdata));
advdata.name_type = BLE_ADVDATA_FULL_NAME;
advdata.include_appearance = false;
advdata.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_LIMITED_DISC_MODE;
memset(&scanrsp, 0, sizeof(scanrsp));
scanrsp.uuids_complete.uuid_cnt = sizeof(m_adv_uuids) / sizeof(m_adv_uuids[0]);
scanrsp.uuids_complete.p_uuids = m_adv_uuids;
ble_adv_modes_config_t options = {0};
options.ble_adv_whitelist_enabled = false;
options.ble_adv_directed_enabled = false;
options.ble_adv_directed_slow_enabled = true;
options.ble_adv_directed_slow_interval = APP_ADV_DIRECTED_INTERVAL;
options.ble_adv_directed_slow_timeout = APP_ADV_DIRECTED_TIMEOUT_IN_SECONDS;
options.ble_adv_fast_enabled = BLE_ADV_FAST_ENABLED;
options.ble_adv_fast_interval = APP_ADV_INTERVAL;
options.ble_adv_fast_timeout = APP_ADV_TIMEOUT_IN_SECONDS;
err_code = ble_advertising_init(&advdata, &scanrsp, &options, on_adv_evt, NULL);
SEGGER_RTT_printf(0, "[Ble] Adv Init error: %8X\n", err_code);
}