initial commit
This commit is contained in:
615
project/ble_peripheral/ble_app_vivaMayo/ble/ble_core.c
Normal file
615
project/ble_peripheral/ble_app_vivaMayo/ble/ble_core.c
Normal file
@@ -0,0 +1,615 @@
|
||||
/*******************************************************************************
|
||||
* @file ble_core.c
|
||||
* @brief BLE Core Functions - Stack, GAP, GATT, Advertising
|
||||
* @author Charles KWON <charleskwon@medithings.co.kr>
|
||||
* @date 2025-01-30
|
||||
* @copyright (c) 2025 Medithings Inc. All rights reserved.
|
||||
*
|
||||
* @details BLE stack initialization, GAP/GATT configuration, advertising.
|
||||
******************************************************************************/
|
||||
|
||||
#include "ble_core.h"
|
||||
#include "ble_data_tx.h"
|
||||
#include "power_ctrl.h"
|
||||
#include "device_config.h"
|
||||
|
||||
#include "nordic_common.h"
|
||||
#include "nrf.h"
|
||||
#include "ble_hci.h"
|
||||
#include "ble_advdata.h"
|
||||
#include "ble_advertising.h"
|
||||
#include "ble_srv_common.h"
|
||||
#include "ble_conn_params.h"
|
||||
#include "ble_nus.h"
|
||||
#include "nrf_sdh.h"
|
||||
#include "nrf_sdh_soc.h"
|
||||
#include "nrf_sdh_ble.h"
|
||||
#include "nrf_ble_gatt.h"
|
||||
#include "nrf_ble_qwr.h"
|
||||
#include "app_timer.h"
|
||||
#include "app_error.h"
|
||||
#include "bsp.h"
|
||||
#include "debug_print.h"
|
||||
#include "main_timer.h"
|
||||
#include "battery_saadc.h"
|
||||
#include "measurements.h"
|
||||
#include "power_control.h"
|
||||
#include "main.h"
|
||||
#include <cmd_parse.h>
|
||||
|
||||
#if FEATURE_SECURE_CONNECTION
|
||||
#include "peer_manager.h"
|
||||
#include "peer_manager_handler.h"
|
||||
#include "nrf_ble_lesc.h"
|
||||
#endif
|
||||
|
||||
#if BLE_DFU_ENABLED
|
||||
#include "ble_dfu.h"
|
||||
#include "nrf_pwr_mgmt.h"
|
||||
#include "nrf_power.h"
|
||||
#include "nrf_bootloader_info.h"
|
||||
#include "nrf_dfu_ble_svci_bond_sharing.h"
|
||||
#include "nrf_svci_async_function.h"
|
||||
#include "nrf_svci_async_handler.h"
|
||||
#include "ble_conn_state.h"
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/*==============================================================================
|
||||
* BLE SERVICE INSTANCES
|
||||
*============================================================================*/
|
||||
|
||||
BLE_NUS_DEF(m_nus, NRF_SDH_BLE_TOTAL_LINK_COUNT);
|
||||
NRF_BLE_GATT_DEF(m_gatt);
|
||||
NRF_BLE_QWR_DEF(m_qwr);
|
||||
BLE_ADVERTISING_DEF(m_advertising);
|
||||
|
||||
/*==============================================================================
|
||||
* GLOBAL VARIABLES
|
||||
*============================================================================*/
|
||||
|
||||
uint16_t m_conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
uint16_t m_ble_nus_max_data_len = BLE_GATT_ATT_MTU_DEFAULT - 3;
|
||||
|
||||
static ble_uuid_t m_adv_uuids[] =
|
||||
{
|
||||
{BLE_UUID_NUS_SERVICE, NUS_SERVICE_UUID_TYPE}
|
||||
};
|
||||
|
||||
/*==============================================================================
|
||||
* FORWARD DECLARATIONS
|
||||
*============================================================================*/
|
||||
|
||||
static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context);
|
||||
static void on_adv_evt(ble_adv_evt_t ble_adv_evt);
|
||||
static void on_conn_params_evt(ble_conn_params_evt_t * p_evt);
|
||||
static void conn_params_error_handler(uint32_t nrf_error);
|
||||
static void nus_data_handler(ble_nus_evt_t * p_evt);
|
||||
static void nrf_qwr_error_handler(uint32_t nrf_error);
|
||||
void gatt_evt_handler(nrf_ble_gatt_t * p_gatt, nrf_ble_gatt_evt_t const * p_evt);
|
||||
|
||||
#if BLE_DFU_ENABLED
|
||||
static bool app_shutdown_handler(nrf_pwr_mgmt_evt_t event);
|
||||
static void buttonless_dfu_sdh_state_observer(nrf_sdh_state_evt_t state, void * p_context);
|
||||
static void advertising_config_get(ble_adv_modes_config_t * p_config);
|
||||
static void ble_dfu_evt_handler(ble_dfu_buttonless_evt_type_t event);
|
||||
#endif
|
||||
|
||||
/*==============================================================================
|
||||
* BLE STACK INITIALIZATION
|
||||
*============================================================================*/
|
||||
|
||||
void ble_stack_init(void)
|
||||
{
|
||||
ret_code_t err_code;
|
||||
|
||||
err_code = nrf_sdh_enable_request();
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
/* Configure BLE stack using default settings */
|
||||
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 BLE event handler */
|
||||
NRF_SDH_BLE_OBSERVER(m_ble_observer, APP_BLE_OBSERVER_PRIO, ble_evt_handler, NULL);
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* GAP INITIALIZATION
|
||||
*============================================================================*/
|
||||
|
||||
void gap_params_init(void)
|
||||
{
|
||||
uint32_t err_code;
|
||||
ble_gap_conn_params_t gap_conn_params;
|
||||
ble_gap_conn_sec_mode_t sec_mode;
|
||||
#if FEATURE_STATIC_PASSKEY
|
||||
ble_opt_t ble_opt;
|
||||
#endif
|
||||
|
||||
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode);
|
||||
|
||||
/* Set device name from EEPROM serial number */
|
||||
err_code = sd_ble_gap_device_name_set(&sec_mode,
|
||||
(const uint8_t *) SERIAL_NO,
|
||||
strlen(SERIAL_NO));
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
/* Configure preferred connection parameters */
|
||||
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);
|
||||
|
||||
#if FEATURE_STATIC_PASSKEY
|
||||
/* Set static passkey for pairing */
|
||||
ble_opt.gap_opt.passkey.p_passkey = (const uint8_t *)m_static_passkey;
|
||||
err_code = sd_ble_opt_set(BLE_GAP_OPT_PASSKEY, &ble_opt);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* GATT INITIALIZATION
|
||||
*============================================================================*/
|
||||
|
||||
void gatt_evt_handler(nrf_ble_gatt_t * p_gatt, nrf_ble_gatt_evt_t const * p_evt)
|
||||
{
|
||||
if ((m_conn_handle == p_evt->conn_handle) && (p_evt->evt_id == NRF_BLE_GATT_EVT_ATT_MTU_UPDATED))
|
||||
{
|
||||
m_ble_nus_max_data_len = p_evt->params.att_mtu_effective - OPCODE_LENGTH - HANDLE_LENGTH;
|
||||
}
|
||||
}
|
||||
|
||||
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_periph_set(&m_gatt, NRF_SDH_BLE_GATT_MAX_MTU_SIZE);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* CONNECTION PARAMETERS
|
||||
*============================================================================*/
|
||||
|
||||
static void on_conn_params_evt(ble_conn_params_evt_t * p_evt)
|
||||
{
|
||||
uint32_t err_code;
|
||||
|
||||
if (p_evt->evt_type == BLE_CONN_PARAMS_EVT_FAILED)
|
||||
{
|
||||
err_code = sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_CONN_INTERVAL_UNACCEPTABLE);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
}
|
||||
|
||||
static void conn_params_error_handler(uint32_t nrf_error)
|
||||
{
|
||||
APP_ERROR_HANDLER(nrf_error);
|
||||
}
|
||||
|
||||
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);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* NUS DATA HANDLER
|
||||
*============================================================================*/
|
||||
|
||||
extern which_cmd_t cmd_type_t;
|
||||
|
||||
static void nus_data_handler(ble_nus_evt_t * p_evt)
|
||||
{
|
||||
if (p_evt->type == BLE_NUS_EVT_RX_DATA)
|
||||
{
|
||||
cmd_type_t = CMD_BLE;
|
||||
DBG_PRINTF("recv :%s \n", p_evt->params.rx_data.p_data);
|
||||
DBG_PRINTF("length %d \r\n", p_evt->params.rx_data.length);
|
||||
received_command_process(p_evt->params.rx_data.p_data, CMD_BLE, p_evt->params.rx_data.length);
|
||||
}
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* QWR ERROR HANDLER
|
||||
*============================================================================*/
|
||||
|
||||
static void nrf_qwr_error_handler(uint32_t nrf_error)
|
||||
{
|
||||
APP_ERROR_HANDLER(nrf_error);
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* DFU HANDLERS
|
||||
*============================================================================*/
|
||||
|
||||
#if BLE_DFU_ENABLED
|
||||
NRF_PWR_MGMT_HANDLER_REGISTER(app_shutdown_handler, 0);
|
||||
|
||||
NRF_SDH_STATE_OBSERVER(m_buttonless_dfu_state_obs, 0) =
|
||||
{
|
||||
.handler = buttonless_dfu_sdh_state_observer,
|
||||
};
|
||||
|
||||
static bool app_shutdown_handler(nrf_pwr_mgmt_evt_t event)
|
||||
{
|
||||
switch (event)
|
||||
{
|
||||
case NRF_PWR_MGMT_EVT_PREPARE_DFU:
|
||||
DBG_PRINTF("Power management wants to reset to DFU mode.\r\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
|
||||
DBG_PRINTF("Power management allowed to reset to DFU mode.\r\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
static void buttonless_dfu_sdh_state_observer(nrf_sdh_state_evt_t state, void * p_context)
|
||||
{
|
||||
if (state == NRF_SDH_EVT_STATE_DISABLED)
|
||||
{
|
||||
nrf_power_gpregret2_set(BOOTLOADER_DFU_SKIP_CRC);
|
||||
nrf_pwr_mgmt_shutdown(NRF_PWR_MGMT_SHUTDOWN_GOTO_SYSOFF);
|
||||
}
|
||||
}
|
||||
|
||||
static void advertising_config_get(ble_adv_modes_config_t * p_config)
|
||||
{
|
||||
memset(p_config, 0, sizeof(ble_adv_modes_config_t));
|
||||
|
||||
p_config->ble_adv_fast_enabled = true;
|
||||
p_config->ble_adv_fast_interval = APP_ADV_INTERVAL;
|
||||
p_config->ble_adv_fast_timeout = APP_ADV_DURATION;
|
||||
}
|
||||
|
||||
static void ble_dfu_evt_handler(ble_dfu_buttonless_evt_type_t event)
|
||||
{
|
||||
switch (event)
|
||||
{
|
||||
case BLE_DFU_EVT_BOOTLOADER_ENTER_PREPARE:
|
||||
{
|
||||
DBG_PRINTF("Device is preparing to enter bootloader mode.\r\n");
|
||||
|
||||
ble_adv_modes_config_t config;
|
||||
advertising_config_get(&config);
|
||||
config.ble_adv_on_disconnect_disabled = true;
|
||||
ble_advertising_modes_config_set(&m_advertising, &config);
|
||||
|
||||
uint32_t conn_count = ble_conn_state_for_each_connected(disconnect, NULL);
|
||||
DBG_PRINTF("Disconnected %d links.\r\n", conn_count);
|
||||
break;
|
||||
}
|
||||
|
||||
case BLE_DFU_EVT_BOOTLOADER_ENTER:
|
||||
DBG_PRINTF("Device will enter bootloader mode.\r\n");
|
||||
break;
|
||||
|
||||
case BLE_DFU_EVT_BOOTLOADER_ENTER_FAILED:
|
||||
DBG_PRINTF("Request to enter bootloader mode failed asynchroneously.\r\n");
|
||||
break;
|
||||
|
||||
case BLE_DFU_EVT_RESPONSE_SEND_ERROR:
|
||||
DBG_PRINTF("Request to send a response to client failed.\r\n");
|
||||
APP_ERROR_CHECK(false);
|
||||
break;
|
||||
|
||||
default:
|
||||
DBG_PRINTF("Unknown event from ble_dfu_buttonless.\r\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void dfu_init(void)
|
||||
{
|
||||
ret_code_t err_code = ble_dfu_buttonless_async_svci_init();
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*==============================================================================
|
||||
* SERVICES INITIALIZATION
|
||||
*============================================================================*/
|
||||
|
||||
void services_init(void)
|
||||
{
|
||||
uint32_t err_code;
|
||||
ble_nus_init_t nus_init;
|
||||
nrf_ble_qwr_init_t qwr_init = {0};
|
||||
|
||||
/* Initialize Queued Write Module */
|
||||
qwr_init.error_handler = nrf_qwr_error_handler;
|
||||
err_code = nrf_ble_qwr_init(&m_qwr, &qwr_init);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
/* Initialize Nordic UART Service */
|
||||
memset(&nus_init, 0, sizeof(nus_init));
|
||||
nus_init.data_handler = nus_data_handler;
|
||||
err_code = ble_nus_init(&m_nus, &nus_init);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
#if BLE_DFU_ENABLED
|
||||
/* Initialize DFU service */
|
||||
ble_dfu_buttonless_init_t dfus_init = {0};
|
||||
dfus_init.evt_handler = ble_dfu_evt_handler;
|
||||
err_code = ble_dfu_buttonless_init(&dfus_init);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* WRAPPER FUNCTIONS FOR STATIC VARIABLES
|
||||
*============================================================================*/
|
||||
|
||||
uint32_t ble_nus_data_send_wrapper(uint8_t *p_data, uint16_t *p_length, uint16_t conn_handle)
|
||||
{
|
||||
return ble_nus_data_send(&m_nus, p_data, p_length, conn_handle);
|
||||
}
|
||||
|
||||
uint32_t ble_advertising_restart_without_whitelist_wrapper(void)
|
||||
{
|
||||
return ble_advertising_restart_without_whitelist(&m_advertising);
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* ADVERTISING
|
||||
*============================================================================*/
|
||||
|
||||
static void on_adv_evt(ble_adv_evt_t ble_adv_evt)
|
||||
{
|
||||
uint32_t err_code;
|
||||
|
||||
switch (ble_adv_evt)
|
||||
{
|
||||
case BLE_ADV_EVT_FAST:
|
||||
err_code = bsp_indication_set(BSP_INDICATE_ADVERTISING);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
break;
|
||||
|
||||
case BLE_ADV_EVT_IDLE:
|
||||
/* Advertising timeout - enter sleep mode */
|
||||
go_sleep_mode_enter = true;
|
||||
main_timer_start();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void advertising_init(void)
|
||||
{
|
||||
uint32_t err_code;
|
||||
ble_advertising_init_t init;
|
||||
|
||||
memset(&init, 0, sizeof(init));
|
||||
|
||||
init.advdata.name_type = BLE_ADVDATA_FULL_NAME;
|
||||
init.advdata.include_appearance = true;
|
||||
#if FEATURE_NO_SLEEP
|
||||
init.advdata.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;
|
||||
#else
|
||||
init.advdata.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_LIMITED_DISC_MODE;
|
||||
#endif
|
||||
init.srdata.uuids_complete.uuid_cnt = sizeof(m_adv_uuids) / sizeof(m_adv_uuids[0]);
|
||||
init.srdata.uuids_complete.p_uuids = m_adv_uuids;
|
||||
|
||||
init.config.ble_adv_fast_enabled = true;
|
||||
init.config.ble_adv_fast_interval = APP_ADV_INTERVAL;
|
||||
init.config.ble_adv_fast_timeout = APP_ADV_DURATION;
|
||||
init.evt_handler = on_adv_evt;
|
||||
|
||||
err_code = ble_advertising_init(&m_advertising, &init);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
ble_advertising_conn_cfg_tag_set(&m_advertising, APP_BLE_CONN_CFG_TAG);
|
||||
}
|
||||
|
||||
#if FEATURE_SECURE_CONNECTION
|
||||
void advertising_start(bool erase_bonds)
|
||||
{
|
||||
extern void delete_bonds(void);
|
||||
|
||||
DBG_PRINTF("adv_start(erase=%d)\r\n", erase_bonds);
|
||||
if (erase_bonds == true) {
|
||||
bond_data_delete = false;
|
||||
DBG_PRINTF("delete_bonds\r\n");
|
||||
delete_bonds();
|
||||
/* Advertising started by PM_EVT_PEERS_DELETE_SUCCEEDED event */
|
||||
} else {
|
||||
DBG_PRINTF("ble_adv_start...\r\n");
|
||||
ret_code_t err_code = ble_advertising_start(&m_advertising, BLE_ADV_MODE_FAST);
|
||||
DBG_PRINTF("err=%d\r\n", err_code);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
}
|
||||
#else
|
||||
void advertising_start(void)
|
||||
{
|
||||
uint32_t err_code = ble_advertising_start(&m_advertising, BLE_ADV_MODE_FAST);
|
||||
/* Ignore INVALID_STATE - already advertising or not ready */
|
||||
if (err_code != NRF_SUCCESS && err_code != NRF_ERROR_INVALID_STATE) {
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*==============================================================================
|
||||
* DISCONNECT
|
||||
*============================================================================*/
|
||||
|
||||
void disconnect(uint16_t conn_handle, void * p_context)
|
||||
{
|
||||
UNUSED_PARAMETER(p_context);
|
||||
|
||||
ret_code_t err_code = sd_ble_gap_disconnect(conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
DBG_PRINTF("Failed to disconnect connection. Connection handle: %d Error: %d\r\n", conn_handle, err_code);
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG_PRINTF("Disconnected connection handle %d\r\n", conn_handle);
|
||||
}
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* BLE EVENT HANDLER
|
||||
*============================================================================*/
|
||||
|
||||
static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
|
||||
{
|
||||
uint32_t err_code;
|
||||
extern void ble_data_tx_complete(void);
|
||||
|
||||
#if FEATURE_SECURE_CONNECTION
|
||||
pm_handler_secure_on_connection(p_ble_evt);
|
||||
#endif
|
||||
|
||||
switch (p_ble_evt->header.evt_id)
|
||||
{
|
||||
case BLE_GAP_EVT_DISCONNECTED:
|
||||
DBG_PRINTF("Disconnected\r\n");
|
||||
ble_connection_st = 0;
|
||||
m_conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
|
||||
/* Put device to sleep on disconnect if active */
|
||||
if (device_status == true) {
|
||||
LED_ALLOFF();
|
||||
PD_ALLOFF();
|
||||
if (device_sleep_mode() == 0) {
|
||||
device_status = false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Restart advertising to allow reconnection */
|
||||
/* Delay to let PC complete disconnect processing */
|
||||
nrf_delay_ms(100);
|
||||
#if FEATURE_SECURE_CONNECTION
|
||||
advertising_start(false);
|
||||
#else
|
||||
advertising_start();
|
||||
#endif
|
||||
DBG_PRINTF("Advertising restarted\r\n");
|
||||
break;
|
||||
|
||||
case BLE_GAP_EVT_CONNECTED:
|
||||
{
|
||||
DBG_PRINTF("Connected\r\n");
|
||||
ble_connection_st = 1;
|
||||
battery_timer_start();
|
||||
m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
|
||||
err_code = nrf_ble_qwr_conn_handle_assign(&m_qwr, m_conn_handle);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
/* Set TX power to +8 dBm for connected state */
|
||||
sd_ble_gap_tx_power_set(BLE_GAP_TX_POWER_ROLE_CONN, m_conn_handle, 8);
|
||||
|
||||
err_code = bsp_indication_set(BSP_INDICATE_CONNECTED);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
break;
|
||||
}
|
||||
|
||||
case BLE_GAP_EVT_PHY_UPDATE_REQUEST:
|
||||
{
|
||||
DBG_PRINTF("PHY update request.\r\n");
|
||||
/* Use 1M PHY only for better PC compatibility */
|
||||
ble_gap_phys_t const phys =
|
||||
{
|
||||
.rx_phys = BLE_GAP_PHY_1MBPS,
|
||||
.tx_phys = BLE_GAP_PHY_1MBPS,
|
||||
};
|
||||
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:
|
||||
DBG_PRINTF("Client Timeout.\r\n");
|
||||
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:
|
||||
DBG_PRINTF("Server Timeout.\r\n");
|
||||
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_GAP_EVT_SEC_PARAMS_REQUEST:
|
||||
#if !FEATURE_SECURE_CONNECTION
|
||||
/* Reject pairing when security is disabled */
|
||||
err_code = sd_ble_gap_sec_params_reply(m_conn_handle, BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP, NULL, NULL);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
#endif
|
||||
break;
|
||||
|
||||
#if FEATURE_SECURE_CONNECTION
|
||||
case BLE_GAP_EVT_PASSKEY_DISPLAY:
|
||||
{
|
||||
/* Display passkey for user verification */
|
||||
char passkey[7];
|
||||
memcpy(passkey, p_ble_evt->evt.gap_evt.params.passkey_display.passkey, 6);
|
||||
passkey[6] = 0;
|
||||
DBG_PRINTF("Passkey: %s\r\n", passkey);
|
||||
} break;
|
||||
|
||||
case BLE_GAP_EVT_AUTH_KEY_REQUEST:
|
||||
#if FEATURE_STATIC_PASSKEY
|
||||
/* Provide static passkey for authentication */
|
||||
if (p_ble_evt->evt.gap_evt.params.auth_key_request.key_type == BLE_GAP_AUTH_KEY_TYPE_PASSKEY)
|
||||
{
|
||||
err_code = sd_ble_gap_auth_key_reply(p_ble_evt->evt.gap_evt.conn_handle,
|
||||
BLE_GAP_AUTH_KEY_TYPE_PASSKEY,
|
||||
(const uint8_t *)m_static_passkey);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
case BLE_GAP_EVT_LESC_DHKEY_REQUEST:
|
||||
/* Handled by LESC module */
|
||||
break;
|
||||
#endif
|
||||
|
||||
case BLE_GATTS_EVT_HVN_TX_COMPLETE:
|
||||
/* TX complete - ready for next transmission */
|
||||
ble_data_tx_complete();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
123
project/ble_peripheral/ble_app_vivaMayo/ble/ble_core.h
Normal file
123
project/ble_peripheral/ble_app_vivaMayo/ble/ble_core.h
Normal file
@@ -0,0 +1,123 @@
|
||||
/*******************************************************************************
|
||||
* @file ble_core.h
|
||||
* @brief BLE Core Functions - Stack, GAP, GATT, Advertising
|
||||
* @author Charles KWON <charleskwon@medithings.co.kr>
|
||||
* @date 2025-01-30
|
||||
* @copyright (c) 2025 Medithings Inc. All rights reserved.
|
||||
*
|
||||
* @details BLE stack initialization, GAP/GATT configuration, advertising.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef BLE_CORE_H
|
||||
#define BLE_CORE_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "ble.h"
|
||||
#include "ble_advertising.h"
|
||||
#include "nrf_ble_gatt.h"
|
||||
|
||||
/*==============================================================================
|
||||
* CONSTANTS
|
||||
*============================================================================*/
|
||||
|
||||
#define APP_BLE_CONN_CFG_TAG 1
|
||||
#define NUS_SERVICE_UUID_TYPE BLE_UUID_TYPE_VENDOR_BEGIN
|
||||
#define APP_BLE_OBSERVER_PRIO 3
|
||||
#define APP_ADV_INTERVAL 64 /* 40 ms in 0.625 ms units */
|
||||
|
||||
#if FEATURE_NO_SLEEP
|
||||
#define APP_ADV_DURATION 0 /* Infinite advertising */
|
||||
#else
|
||||
#define APP_ADV_DURATION 18000 /* 180 seconds */
|
||||
#endif
|
||||
|
||||
/* Connection Parameters */
|
||||
#define MIN_CONN_INTERVAL MSEC_TO_UNITS(20, UNIT_1_25_MS)
|
||||
#define MAX_CONN_INTERVAL MSEC_TO_UNITS(75, UNIT_1_25_MS)
|
||||
#define SLAVE_LATENCY 0
|
||||
#define CONN_SUP_TIMEOUT MSEC_TO_UNITS(4000, UNIT_10_MS)
|
||||
#define FIRST_CONN_PARAMS_UPDATE_DELAY APP_TIMER_TICKS(5000)
|
||||
#define NEXT_CONN_PARAMS_UPDATE_DELAY APP_TIMER_TICKS(30000)
|
||||
#define MAX_CONN_PARAMS_UPDATE_COUNT 3
|
||||
|
||||
/* GATT Constants */
|
||||
#define OPCODE_LENGTH 1
|
||||
#define HANDLE_LENGTH 2
|
||||
|
||||
/*==============================================================================
|
||||
* EXTERNAL VARIABLES
|
||||
*============================================================================*/
|
||||
|
||||
extern uint16_t m_conn_handle;
|
||||
extern uint16_t m_ble_nus_max_data_len;
|
||||
|
||||
/*==============================================================================
|
||||
* FUNCTION PROTOTYPES
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Initialize BLE SoftDevice stack
|
||||
*/
|
||||
void ble_stack_init(void);
|
||||
|
||||
/**
|
||||
* @brief Initialize GAP parameters
|
||||
*/
|
||||
void gap_params_init(void);
|
||||
|
||||
/**
|
||||
* @brief Initialize GATT module
|
||||
*/
|
||||
void gatt_init(void);
|
||||
|
||||
/**
|
||||
* @brief Initialize connection parameters module
|
||||
*/
|
||||
void conn_params_init(void);
|
||||
|
||||
/**
|
||||
* @brief Initialize BLE advertising
|
||||
*/
|
||||
void advertising_init(void);
|
||||
|
||||
/**
|
||||
* @brief Start BLE advertising
|
||||
* @param erase_bonds If true, delete bonds before advertising
|
||||
*/
|
||||
#if FEATURE_SECURE_CONNECTION
|
||||
void advertising_start(bool erase_bonds);
|
||||
#else
|
||||
void advertising_start(void);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Disconnect a connection
|
||||
* @param conn_handle Connection handle to disconnect
|
||||
* @param p_context Unused context pointer
|
||||
*/
|
||||
void disconnect(uint16_t conn_handle, void *p_context);
|
||||
|
||||
/**
|
||||
* @brief Initialize BLE services (NUS, DFU)
|
||||
*/
|
||||
void services_init(void);
|
||||
|
||||
/**
|
||||
* @brief Wrapper for ble_nus_data_send (accesses static m_nus)
|
||||
*/
|
||||
uint32_t ble_nus_data_send_wrapper(uint8_t *p_data, uint16_t *p_length, uint16_t conn_handle);
|
||||
|
||||
/**
|
||||
* @brief Wrapper for ble_advertising_restart_without_whitelist (accesses static m_advertising)
|
||||
*/
|
||||
uint32_t ble_advertising_restart_without_whitelist_wrapper(void);
|
||||
|
||||
#if BLE_DFU_ENABLED
|
||||
/**
|
||||
* @brief Initialize DFU async SVCI
|
||||
*/
|
||||
void dfu_init(void);
|
||||
#endif
|
||||
|
||||
#endif /* BLE_CORE_H */
|
||||
223
project/ble_peripheral/ble_app_vivaMayo/ble/ble_data_tx.c
Normal file
223
project/ble_peripheral/ble_app_vivaMayo/ble/ble_data_tx.c
Normal file
@@ -0,0 +1,223 @@
|
||||
/*******************************************************************************
|
||||
* @file ble_data_tx.c
|
||||
* @brief BLE Data Transmission Functions
|
||||
* @author Charles KWON <charleskwon@medithings.co.kr>
|
||||
* @date 2025-01-30
|
||||
* @copyright (c) 2025 Medithings Inc. All rights reserved.
|
||||
*
|
||||
* @details BLE NUS data transmission with CRC16 checksum.
|
||||
******************************************************************************/
|
||||
|
||||
#include "ble_data_tx.h"
|
||||
#include "ble_core.h"
|
||||
#include "ble_nus.h"
|
||||
#include "crc16.h"
|
||||
#include "nrf_delay.h"
|
||||
#include "app_error.h"
|
||||
#include "debug_print.h"
|
||||
#include <string.h>
|
||||
|
||||
/*==============================================================================
|
||||
* GLOBAL VARIABLES
|
||||
*============================================================================*/
|
||||
|
||||
volatile bool ble_connection_st = 0;
|
||||
volatile bool data_tx_in_progress = false;
|
||||
|
||||
uint8_t ble_bin_buffer[BLE_NUS_MAX_DATA_LEN];
|
||||
|
||||
/*==============================================================================
|
||||
* PRIVATE VARIABLES
|
||||
*============================================================================*/
|
||||
|
||||
static uint8_t m_tx_buffer[BLE_NUS_MAX_DATA_LEN];
|
||||
static uint16_t m_tx_len = 0;
|
||||
static bool m_tx_in_progress = false;
|
||||
|
||||
/*==============================================================================
|
||||
* DATA TRANSMISSION FUNCTIONS
|
||||
*============================================================================*/
|
||||
|
||||
void data_tx_handler(char const *p_data_to_send)
|
||||
{
|
||||
if (m_tx_in_progress)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* Find string length by locating '\r' terminator */
|
||||
char const *p_end_char = strchr(p_data_to_send, '\r');
|
||||
if (p_end_char == NULL)
|
||||
{
|
||||
DBG_PRINTF("TX data has no '\\r' terminator. Aborting send.");
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t data_len = p_end_char - p_data_to_send;
|
||||
|
||||
/* Validate length (need space for 2-byte CRC) */
|
||||
if (data_len > (BLE_NUS_MAX_DATA_LEN - 2))
|
||||
{
|
||||
DBG_PRINTF("TX data is too long to fit CRC. Len: %d", data_len);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Prepare buffer with data and CRC16 */
|
||||
memcpy(m_tx_buffer, p_data_to_send, data_len);
|
||||
uint16_t crc = crc16_compute(m_tx_buffer, data_len, NULL);
|
||||
m_tx_buffer[data_len] = (uint8_t)(crc & 0xFF);
|
||||
m_tx_buffer[data_len + 1] = (uint8_t)((crc >> 8) & 0xFF);
|
||||
|
||||
m_tx_len = data_len + 2;
|
||||
|
||||
/* Attempt to send */
|
||||
uint32_t err_code;
|
||||
|
||||
if (ble_connection_st == BLE_CONNECTED_ST)
|
||||
{
|
||||
m_tx_in_progress = true;
|
||||
|
||||
err_code = ble_nus_data_send_wrapper( m_tx_buffer, &m_tx_len, m_conn_handle);
|
||||
|
||||
if (err_code == NRF_SUCCESS)
|
||||
{
|
||||
DBG_PRINTF("NUS data sent to SoftDevice buffer.");
|
||||
}
|
||||
else if (err_code == NRF_ERROR_RESOURCES)
|
||||
{
|
||||
DBG_PRINTF("NUS buffer full. Will retry later.");
|
||||
}
|
||||
else if (err_code == NRF_ERROR_INVALID_STATE || err_code == NRF_ERROR_NOT_FOUND)
|
||||
{
|
||||
ble_connection_st = BLE_DISCONNECTED_ST;
|
||||
DBG_PRINTF("Failed to send NUS data, device not connected.");
|
||||
m_tx_in_progress = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_tx_in_progress = false;
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void binary_tx_handler(uint8_t const *ble_bin_buff, uint16_t length)
|
||||
{
|
||||
uint32_t err_code;
|
||||
static uint8_t tx_buffer[BLE_NUS_MAX_DATA_LEN] = {0};
|
||||
|
||||
if (ble_connection_st == 0) {
|
||||
DBG_PRINTF("Lost!\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
data_tx_in_progress = true;
|
||||
|
||||
if (length * sizeof(uint16_t) > (BLE_NUS_MAX_DATA_LEN - 2)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ble_connection_st == BLE_CONNECTED_ST) {
|
||||
memcpy(tx_buffer, ble_bin_buff, length * sizeof(uint16_t));
|
||||
uint16_t crc = crc16_compute(tx_buffer, length * sizeof(uint16_t), NULL);
|
||||
|
||||
tx_buffer[length * sizeof(uint16_t)] = (uint8_t)(crc & 0xFF);
|
||||
tx_buffer[length * sizeof(uint16_t) + 1] = (uint8_t)((crc >> 8) & 0xFF);
|
||||
|
||||
uint16_t total_len = length * sizeof(uint16_t) + 2;
|
||||
|
||||
do {
|
||||
err_code = ble_nus_data_send_wrapper( tx_buffer, &total_len, m_conn_handle);
|
||||
|
||||
if ((err_code != NRF_ERROR_INVALID_STATE) &&
|
||||
(err_code != NRF_ERROR_RESOURCES) &&
|
||||
(err_code != NRF_ERROR_NOT_FOUND))
|
||||
{
|
||||
nrf_delay_ms(10);
|
||||
}
|
||||
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
} while (err_code == NRF_ERROR_RESOURCES);
|
||||
|
||||
data_tx_in_progress = false;
|
||||
}
|
||||
}
|
||||
|
||||
void dr_binary_tx_safe(uint8_t const *ble_bin_buff, uint16_t length)
|
||||
{
|
||||
binary_tx_handler(ble_bin_buff, length);
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* DATA FORMATTING FUNCTIONS
|
||||
*============================================================================*/
|
||||
|
||||
void single_format_data(uint8_t *buffer, const char *tag, const uint16_t value)
|
||||
{
|
||||
uint16_t tag1 = ((uint16_t)tag[1] << 8) | (uint16_t)tag[0];
|
||||
uint16_t tag2 = ((uint16_t)tag[3] << 8) | (uint16_t)tag[2];
|
||||
|
||||
buffer[0] = (uint8_t)(tag1 & 0xFF);
|
||||
buffer[1] = (uint8_t)((tag1 >> 8) & 0xFF);
|
||||
buffer[2] = (uint8_t)(tag2 & 0xFF);
|
||||
buffer[3] = (uint8_t)((tag2 >> 8) & 0xFF);
|
||||
|
||||
buffer[5] = (uint8_t)(value & 0xFF);
|
||||
buffer[4] = (uint8_t)((value >> 8) & 0xFF);
|
||||
}
|
||||
|
||||
void format_data(uint8_t *buffer, const char *tag, const uint16_t *data_array, size_t length)
|
||||
{
|
||||
uint16_t tag1 = ((uint16_t)tag[1] << 8) | (uint16_t)tag[0];
|
||||
uint16_t tag2 = ((uint16_t)tag[3] << 8) | (uint16_t)tag[2];
|
||||
|
||||
buffer[0] = (uint8_t)(tag1 & 0xFF);
|
||||
buffer[1] = (uint8_t)((tag1 >> 8) & 0xFF);
|
||||
buffer[2] = (uint8_t)(tag2 & 0xFF);
|
||||
buffer[3] = (uint8_t)((tag2 >> 8) & 0xFF);
|
||||
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
buffer[4 + i * 2 + 1] = (uint8_t)(data_array[i] & 0xFF);
|
||||
buffer[4 + i * 2] = (uint8_t)((data_array[i] >> 8) & 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
void format_data_byte(uint8_t *buffer, const char *tag, const uint8_t *data_array, size_t length)
|
||||
{
|
||||
uint16_t tag1 = ((uint16_t)tag[1] << 8) | (uint16_t)tag[0];
|
||||
uint16_t tag2 = ((uint16_t)tag[3] << 8) | (uint16_t)tag[2];
|
||||
|
||||
buffer[0] = (uint8_t)(tag1 & 0xFF);
|
||||
buffer[1] = (uint8_t)((tag1 >> 8) & 0xFF);
|
||||
buffer[2] = (uint8_t)(tag2 & 0xFF);
|
||||
buffer[3] = (uint8_t)((tag2 >> 8) & 0xFF);
|
||||
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
buffer[4 + i] = (uint8_t)(data_array[i] & 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
void ascii_format_data(uint8_t *buffer, const char *tag, const char *data_ascii, size_t length)
|
||||
{
|
||||
uint16_t tag1 = ((uint16_t)tag[1] << 8) | (uint16_t)tag[0];
|
||||
uint16_t tag2 = ((uint16_t)tag[3] << 8) | (uint16_t)tag[2];
|
||||
|
||||
buffer[0] = (uint8_t)(tag1 & 0xFF);
|
||||
buffer[1] = (uint8_t)((tag1 >> 8) & 0xFF);
|
||||
buffer[2] = (uint8_t)(tag2 & 0xFF);
|
||||
buffer[3] = (uint8_t)((tag2 >> 8) & 0xFF);
|
||||
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
buffer[4 + i] = (uint8_t)(data_ascii[i] & 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* TX COMPLETE HANDLER (called from ble_evt_handler)
|
||||
*============================================================================*/
|
||||
|
||||
void ble_data_tx_complete(void)
|
||||
{
|
||||
m_tx_in_progress = false;
|
||||
}
|
||||
82
project/ble_peripheral/ble_app_vivaMayo/ble/ble_data_tx.h
Normal file
82
project/ble_peripheral/ble_app_vivaMayo/ble/ble_data_tx.h
Normal file
@@ -0,0 +1,82 @@
|
||||
/*******************************************************************************
|
||||
* @file ble_data_tx.h
|
||||
* @brief BLE Data Transmission Functions
|
||||
* @author Charles KWON <charleskwon@medithings.co.kr>
|
||||
* @date 2025-01-30
|
||||
* @copyright (c) 2025 Medithings Inc. All rights reserved.
|
||||
*
|
||||
* @details BLE NUS data transmission with CRC16 checksum.
|
||||
* - ASCII data transmission
|
||||
* - Binary data transmission
|
||||
* - Data formatting functions
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef BLE_DATA_TX_H
|
||||
#define BLE_DATA_TX_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include "main.h"
|
||||
|
||||
/*==============================================================================
|
||||
* EXTERNAL VARIABLES
|
||||
*============================================================================*/
|
||||
|
||||
extern volatile bool ble_connection_st;
|
||||
extern volatile bool data_tx_in_progress;
|
||||
extern uint8_t ble_bin_buffer[];
|
||||
|
||||
/*==============================================================================
|
||||
* FUNCTION PROTOTYPES
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Send ASCII data over BLE NUS with CRC
|
||||
* @param p_data_to_send Null-terminated string ending with '\r'
|
||||
*/
|
||||
void data_tx_handler(char const *p_data_to_send);
|
||||
|
||||
/**
|
||||
* @brief Send binary data over BLE NUS with CRC
|
||||
* @param ble_bin_buff Binary data buffer
|
||||
* @param length Number of 16-bit words to send
|
||||
*/
|
||||
void binary_tx_handler(uint8_t const *ble_bin_buff, uint16_t length);
|
||||
|
||||
/**
|
||||
* @brief Format single 16-bit value with 4-character tag
|
||||
* @param buffer Output buffer (minimum 6 bytes)
|
||||
* @param tag 4-character tag string
|
||||
* @param value 16-bit value to format
|
||||
*/
|
||||
void single_format_data(uint8_t *buffer, const char *tag, const uint16_t value);
|
||||
|
||||
/**
|
||||
* @brief Format 16-bit array with 4-character tag
|
||||
* @param buffer Output buffer
|
||||
* @param tag 4-character tag string
|
||||
* @param data_array Array of 16-bit values
|
||||
* @param length Number of elements in array
|
||||
*/
|
||||
void format_data(uint8_t *buffer, const char *tag, const uint16_t *data_array, size_t length);
|
||||
|
||||
/**
|
||||
* @brief Format 8-bit array with 4-character tag
|
||||
* @param buffer Output buffer
|
||||
* @param tag 4-character tag string
|
||||
* @param data_array Array of 8-bit values
|
||||
* @param length Number of bytes in array
|
||||
*/
|
||||
void format_data_byte(uint8_t *buffer, const char *tag, const uint8_t *data_array, size_t length);
|
||||
|
||||
/**
|
||||
* @brief Format ASCII string with 4-character tag
|
||||
* @param buffer Output buffer
|
||||
* @param tag 4-character tag string
|
||||
* @param data_ascii ASCII string data
|
||||
* @param length String length
|
||||
*/
|
||||
void ascii_format_data(uint8_t *buffer, const char *tag, const char *data_ascii, size_t length);
|
||||
|
||||
#endif /* BLE_DATA_TX_H */
|
||||
199
project/ble_peripheral/ble_app_vivaMayo/ble/ble_security.c
Normal file
199
project/ble_peripheral/ble_app_vivaMayo/ble/ble_security.c
Normal file
@@ -0,0 +1,199 @@
|
||||
/*******************************************************************************
|
||||
* @file ble_security.c
|
||||
* @brief BLE Security - Peer Manager, LESC, Bonding
|
||||
* @author Charles KWON <charleskwon@medithings.co.kr>
|
||||
* @date 2025-01-30
|
||||
* @copyright (c) 2025 Medithings Inc. All rights reserved.
|
||||
*
|
||||
* @details Peer Manager initialization and security event handling.
|
||||
******************************************************************************/
|
||||
|
||||
#include "sdk_config.h"
|
||||
#include "ble_security.h"
|
||||
|
||||
#if FEATURE_SECURE_CONNECTION
|
||||
|
||||
#include "ble_core.h"
|
||||
#include "ble_data_tx.h"
|
||||
#include "power_ctrl.h"
|
||||
#include "device_config.h"
|
||||
|
||||
#include "peer_manager.h"
|
||||
#include "peer_manager_handler.h"
|
||||
#include "nrf_ble_lesc.h"
|
||||
#include "ble_conn_state.h"
|
||||
#include "app_error.h"
|
||||
#include "debug_print.h"
|
||||
#include "battery_saadc.h"
|
||||
#include "ble_quick_security.h"
|
||||
#include <string.h>
|
||||
|
||||
/*==============================================================================
|
||||
* GLOBAL VARIABLES
|
||||
*============================================================================*/
|
||||
|
||||
bool erase_bonds = false;
|
||||
|
||||
/*==============================================================================
|
||||
* PRIVATE VARIABLES
|
||||
*============================================================================*/
|
||||
|
||||
static pm_peer_id_t m_peer_to_be_deleted = PM_PEER_ID_INVALID;
|
||||
static uint8_t c_addr[6];
|
||||
|
||||
/*==============================================================================
|
||||
* PEER MANAGER EVENT HANDLER
|
||||
*============================================================================*/
|
||||
|
||||
static void pm_evt_handler(pm_evt_t const * p_evt)
|
||||
{
|
||||
pm_peer_data_bonding_t peer_bonding_data;
|
||||
uint32_t return_code;
|
||||
ret_code_t err_code;
|
||||
|
||||
/* Standard Peer Manager handlers */
|
||||
pm_handler_on_pm_evt(p_evt);
|
||||
pm_handler_disconnect_on_sec_failure(p_evt);
|
||||
pm_handler_flash_clean(p_evt);
|
||||
|
||||
/* Security module (automatic mode handling) */
|
||||
ble_security_quick_pm_handler(p_evt);
|
||||
|
||||
/* Application-specific event handling */
|
||||
switch (p_evt->evt_id)
|
||||
{
|
||||
case PM_EVT_CONN_SEC_SUCCEEDED:
|
||||
{
|
||||
pm_conn_sec_status_t conn_sec_status;
|
||||
err_code = pm_conn_sec_status_get(p_evt->conn_handle, &conn_sec_status);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
/* Accept if: MITM protected OR dev mode (no security) */
|
||||
if (conn_sec_status.mitm_protected || BLE_DEV_MODE)
|
||||
{
|
||||
DBG_PRINTF("Link secured. Role: %d, conn_handle: %d, Procedure: %d\r\n",
|
||||
ble_conn_state_role(p_evt->conn_handle),
|
||||
p_evt->conn_handle,
|
||||
p_evt->params.conn_sec_succeeded.procedure);
|
||||
|
||||
/* Start battery monitoring after secure connection */
|
||||
ble_connection_st = 1;
|
||||
battery_timer_start();
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Security insufficient - disconnect (production mode) */
|
||||
DBG_PRINTF("Link security FAILED\r\n");
|
||||
err_code = pm_peer_id_get(m_conn_handle, &m_peer_to_be_deleted);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
err_code = sd_ble_gap_disconnect(m_conn_handle,
|
||||
BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PM_EVT_CONN_SEC_FAILED:
|
||||
{
|
||||
DBG_PRINTF("Security failed: peer_id=%d, error=%d\r\n",
|
||||
p_evt->peer_id,
|
||||
p_evt->params.conn_sec_failed.error);
|
||||
|
||||
/* Auto-retry if key missing (supports rebonding) */
|
||||
if (p_evt->params.conn_sec_failed.error == PM_CONN_SEC_ERROR_PIN_OR_KEY_MISSING)
|
||||
{
|
||||
err_code = pm_conn_secure(p_evt->conn_handle, true);
|
||||
if (err_code != NRF_ERROR_INVALID_STATE)
|
||||
{
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PM_EVT_PEERS_DELETE_SUCCEEDED:
|
||||
/* Restart advertising after bond deletion */
|
||||
advertising_start(false);
|
||||
break;
|
||||
|
||||
case PM_EVT_CONN_SEC_CONFIG_REQ:
|
||||
{
|
||||
/* Allow repairing for rebonding support */
|
||||
pm_conn_sec_config_t conn_sec_config = {
|
||||
.allow_repairing = true
|
||||
};
|
||||
pm_conn_sec_config_reply(p_evt->conn_handle, &conn_sec_config);
|
||||
}
|
||||
break;
|
||||
|
||||
case PM_EVT_PEER_DATA_UPDATE_SUCCEEDED:
|
||||
{
|
||||
/* Store peer address for tracking */
|
||||
return_code = pm_peer_data_bonding_load(p_evt->peer_id, &peer_bonding_data);
|
||||
|
||||
if (return_code == NRF_SUCCESS)
|
||||
{
|
||||
DBG_PRINTF("Peer updated: %02x:%02x:%02x:%02x:%02x:%02x\r\n",
|
||||
peer_bonding_data.peer_ble_id.id_addr_info.addr[5],
|
||||
peer_bonding_data.peer_ble_id.id_addr_info.addr[4],
|
||||
peer_bonding_data.peer_ble_id.id_addr_info.addr[3],
|
||||
peer_bonding_data.peer_ble_id.id_addr_info.addr[2],
|
||||
peer_bonding_data.peer_ble_id.id_addr_info.addr[1],
|
||||
peer_bonding_data.peer_ble_id.id_addr_info.addr[0]);
|
||||
|
||||
memcpy(c_addr,
|
||||
peer_bonding_data.peer_ble_id.id_addr_info.addr,
|
||||
sizeof(c_addr));
|
||||
|
||||
DBG_PRINTF("Stored c_addr[3]: %02x\r\n", c_addr[3]);
|
||||
m_reset_status = 10;
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG_PRINTF("Failed to load peer data: error=%d\r\n", return_code);
|
||||
m_reset_status = 10;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* PUBLIC FUNCTIONS
|
||||
*============================================================================*/
|
||||
|
||||
void peer_manager_init(void)
|
||||
{
|
||||
ret_code_t err_code;
|
||||
|
||||
/* Security mode auto-configuration */
|
||||
ble_security_quick_init(BLE_DEV_MODE);
|
||||
|
||||
/* Register PM event handler */
|
||||
err_code = pm_register(pm_evt_handler);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
DBG_PRINTF("BLE Security initialized (mode=%d)\r\n", BLE_DEV_MODE);
|
||||
}
|
||||
|
||||
void delete_bonds(void)
|
||||
{
|
||||
ret_code_t err_code;
|
||||
|
||||
DBG_PRINTF("Erase bonds!\r\n");
|
||||
|
||||
err_code = pm_peers_delete();
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
|
||||
void security_idle_state_handle(void)
|
||||
{
|
||||
ret_code_t err_code;
|
||||
err_code = nrf_ble_lesc_request_handler();
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
|
||||
#endif /* FEATURE_SECURE_CONNECTION */
|
||||
69
project/ble_peripheral/ble_app_vivaMayo/ble/ble_security.h
Normal file
69
project/ble_peripheral/ble_app_vivaMayo/ble/ble_security.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/*******************************************************************************
|
||||
* @file ble_security.h
|
||||
* @brief BLE Security - Peer Manager, LESC, Bonding
|
||||
* @author Charles KWON <charleskwon@medithings.co.kr>
|
||||
* @date 2025-01-30
|
||||
* @copyright (c) 2025 Medithings Inc. All rights reserved.
|
||||
*
|
||||
* @details Peer Manager initialization and security event handling.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef BLE_SECURITY_H
|
||||
#define BLE_SECURITY_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#if FEATURE_SECURE_CONNECTION
|
||||
#include "ble_gap.h"
|
||||
|
||||
/*==============================================================================
|
||||
* CONSTANTS
|
||||
*============================================================================*/
|
||||
#define LESC_DEBUG_MODE 0
|
||||
#define SEC_PARAM_BOND 1
|
||||
#define SEC_PARAM_MITM 1
|
||||
#if FEATURE_STATIC_PASSKEY
|
||||
#define SEC_PARAM_LESC 0
|
||||
#else
|
||||
#define SEC_PARAM_LESC 1
|
||||
#endif
|
||||
#define SEC_PARAM_KEYPRESS 0
|
||||
#define SEC_PARAM_IO_CAPABILITIES BLE_GAP_IO_CAPS_DISPLAY_ONLY
|
||||
#define SEC_PARAM_OOB 0
|
||||
#define SEC_PARAM_MIN_KEY_SIZE 7
|
||||
#define SEC_PARAM_MAX_KEY_SIZE 16
|
||||
#define PASSKEY_TXT_LENGTH 8
|
||||
#define PASSKEY_LENGTH 6
|
||||
|
||||
#define BLE_DEV_MODE 1 /* 1=Dev mode, 0=Production */
|
||||
#endif
|
||||
|
||||
/*==============================================================================
|
||||
* FUNCTION PROTOTYPES
|
||||
*============================================================================*/
|
||||
|
||||
#if FEATURE_SECURE_CONNECTION
|
||||
|
||||
/*==============================================================================
|
||||
* EXTERNAL VARIABLES (SECURE CONNECTION ONLY)
|
||||
*============================================================================*/
|
||||
|
||||
extern bool erase_bonds;
|
||||
/**
|
||||
* @brief Initialize Peer Manager with security configuration
|
||||
*/
|
||||
void peer_manager_init(void);
|
||||
|
||||
/**
|
||||
* @brief Delete all bond information from flash
|
||||
*/
|
||||
void delete_bonds(void);
|
||||
|
||||
/**
|
||||
* @brief Handle idle state for LESC
|
||||
*/
|
||||
void security_idle_state_handle(void);
|
||||
#endif
|
||||
|
||||
#endif /* BLE_SECURITY_H */
|
||||
19
project/ble_peripheral/ble_app_vivaMayo/ble/ble_services.c
Normal file
19
project/ble_peripheral/ble_app_vivaMayo/ble/ble_services.c
Normal file
@@ -0,0 +1,19 @@
|
||||
/*******************************************************************************
|
||||
* @file ble_services.c
|
||||
* @brief BLE Services - NUS and DFU (Stub file)
|
||||
* @author Charles KWON <charleskwon@medithings.co.kr>
|
||||
* @date 2025-01-30
|
||||
* @copyright (c) 2025 Medithings Inc. All rights reserved.
|
||||
*
|
||||
* @details This is now a stub file. All service initialization code has been
|
||||
* moved to ble_core.c to avoid static variable access issues with
|
||||
* Nordic SDK macros (BLE_NUS_DEF, NRF_BLE_QWR_DEF, etc.).
|
||||
*
|
||||
* See ble_core.c for:
|
||||
* - services_init()
|
||||
* - dfu_init()
|
||||
* - NUS data handler
|
||||
* - DFU event handlers
|
||||
******************************************************************************/
|
||||
|
||||
/* Empty stub - all code moved to ble_core.c */
|
||||
33
project/ble_peripheral/ble_app_vivaMayo/ble/ble_services.h
Normal file
33
project/ble_peripheral/ble_app_vivaMayo/ble/ble_services.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/*******************************************************************************
|
||||
* @file ble_services.h
|
||||
* @brief BLE Services - NUS and DFU
|
||||
* @author Charles KWON <charleskwon@medithings.co.kr>
|
||||
* @date 2025-01-30
|
||||
* @copyright (c) 2025 Medithings Inc. All rights reserved.
|
||||
*
|
||||
* @details Nordic UART Service and DFU service initialization.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef BLE_SERVICES_H
|
||||
#define BLE_SERVICES_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/*==============================================================================
|
||||
* FUNCTION PROTOTYPES
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Initialize BLE services (NUS, DFU)
|
||||
*/
|
||||
void services_init(void);
|
||||
|
||||
#if BLE_DFU_ENABLED
|
||||
/**
|
||||
* @brief Initialize DFU async SVCI
|
||||
*/
|
||||
void dfu_init(void);
|
||||
#endif
|
||||
|
||||
#endif /* BLE_SERVICES_H */
|
||||
Reference in New Issue
Block a user