302 lines
8.3 KiB
C

/**
* @file app_ble.c
* @brief BLE application layer implementation, derived from the SDK rdtss
* demo (app_ble.c) and trimmed to a single custom link service (CLS).
*
* NOTE: ke_msg / ke_timer may only run in the BLE schedule task context
* (SDK constraint). rwip_schedule() is therefore only called from the
* dedicated FreeRTOS task created here.
*
* TODO: ns_sleep() low-power mode is intentionally NOT used: it conflicts
* with the FreeRTOS tick. Revisit when sleep support is required.
*/
#include <string.h>
#include <stdio.h>
#include "n32wb03x.h"
#include "rwip.h"
#include "gapm_task.h" // GAP Manager Task API
#include "ns_ble.h"
#include "ns_sec.h"
#include "app_ble.h"
#include "app_cls.h"
#include "app_ble_proto.h"
#include "app_user_config.h"
#include "FreeRTOS.h"
#include "task.h"
#include "bsp_usart.h"
/* Private define ------------------------------------------------------------*/
#define BLE_SCHED_TASK_STACK (512) /* stack in words */
#define BLE_SCHED_TASK_PRIORITY (2)
/* Private variables ---------------------------------------------------------*/
static uint8_t s_ble_connected = 0;
/* Private function prototypes -----------------------------------------------*/
static void app_ble_connected(void);
static void app_ble_disconnected(void);
static void ble_schedule_task(void *argument);
/* Private functions ---------------------------------------------------------*/
/**
* @brief ble message handler
*/
static void app_ble_msg_handler(struct ble_msg_t const *p_ble_msg)
{
switch (p_ble_msg->msg_id)
{
case APP_BLE_OS_READY:
break;
case APP_BLE_GAP_CONNECTED:
app_ble_connected();
break;
case APP_BLE_GAP_DISCONNECTED:
app_ble_disconnected();
break;
case APP_BLE_GATTC_MTU_IND:
bsp_usart_tx_lock();
printf("[BLE] MTU updated: %u\n", (unsigned int)app_env.max_mtu);
bsp_usart_tx_unlock();
break;
default:
break;
}
}
/**
* @brief advertising message handler
*/
static void app_ble_adv_msg_handler(enum app_adv_mode adv_mode)
{
switch (adv_mode)
{
case APP_ADV_MODE_DIRECTED:
break;
case APP_ADV_MODE_FAST:
break;
case APP_ADV_MODE_SLOW:
break;
default:
break;
}
}
/**
* @brief ble GAP initialization
*/
static void app_ble_gap_params_init(void)
{
struct ns_gap_params_t dev_info = {0};
uint8_t *p_mac = SystemGetMacAddr();
//get UUID from trim stored
if (p_mac != NULL)
{
//set the uuid as mac address
memcpy(dev_info.mac_addr.addr, p_mac, BD_ADDR_LEN);
}
else
{
memcpy(dev_info.mac_addr.addr, "\x01\x02\x03\x04\x05\x06", BD_ADDR_LEN);
}
/* init params*/
dev_info.mac_addr_type = GAPM_STATIC_ADDR;
dev_info.appearance = 0;
dev_info.dev_role = GAP_ROLE_PERIPHERAL;
dev_info.dev_name_len = sizeof(CUSTOM_DEVICE_NAME)-1;
memcpy(dev_info.dev_name, CUSTOM_DEVICE_NAME, dev_info.dev_name_len);
dev_info.dev_conn_param.intv_min = MSECS_TO_UNIT(MIN_CONN_INTERVAL, MSECS_UNIT_1_25_MS);
dev_info.dev_conn_param.intv_max = MSECS_TO_UNIT(MAX_CONN_INTERVAL, MSECS_UNIT_1_25_MS);
dev_info.dev_conn_param.latency = SLAVE_LATENCY;
dev_info.dev_conn_param.time_out = MSECS_TO_UNIT(CONN_SUP_TIMEOUT, MSECS_UNIT_10_MS);
dev_info.conn_param_update_delay = FIRST_CONN_PARAMS_UPDATE_DELAY;
ns_ble_gap_init(&dev_info);
}
/**
* @brief ble advertising initialization
*/
static void app_ble_adv_init(void)
{
struct ns_adv_params_t user_adv = {0};
//init advertising data
user_adv.adv_data_len = CUSTOM_USER_ADVERTISE_DATA_LEN;
memcpy(user_adv.adv_data, CUSTOM_USER_ADVERTISE_DATA, CUSTOM_USER_ADVERTISE_DATA_LEN);
user_adv.scan_rsp_data_len = CUSTOM_USER_ADV_SCNRSP_DATA_LEN;
memcpy(user_adv.scan_rsp_data, CUSTOM_USER_ADV_SCNRSP_DATA, CUSTOM_USER_ADV_SCNRSP_DATA_LEN);
user_adv.attach_appearance = false;
user_adv.attach_name = true;
user_adv.ex_adv_enable = false;
user_adv.adv_phy = PHY_1MBPS_VALUE;
//init advertising params
user_adv.directed_adv.enable = false;
user_adv.fast_adv.enable = true;
user_adv.fast_adv.duration = CUSTOM_ADV_FAST_DURATION;
user_adv.fast_adv.adv_intv = CUSTOM_ADV_FAST_INTERVAL;
user_adv.slow_adv.enable = true;
user_adv.slow_adv.duration = CUSTOM_ADV_SLOW_DURATION;
user_adv.slow_adv.adv_intv = CUSTOM_ADV_SLOW_INTERVAL;
user_adv.ble_adv_msg_handler = app_ble_adv_msg_handler;
ns_ble_adv_init(&user_adv);
}
/**
* @brief ble security initialization
*/
static void app_ble_sec_init(void)
{
struct ns_sec_init_t sec_init = {0};
sec_init.rand_pin_enable = false;
sec_init.pin_code = 123456;
sec_init.pairing_feat.auth = ( SEC_PARAM_BOND | (SEC_PARAM_MITM<<2) | (SEC_PARAM_LESC<<3) | (SEC_PARAM_KEYPRESS<<4) );
sec_init.pairing_feat.iocap = SEC_PARAM_IO_CAPABILITIES;
sec_init.pairing_feat.key_size = SEC_PARAM_KEY_SIZE;
sec_init.pairing_feat.oob = SEC_PARAM_OOB;
sec_init.pairing_feat.ikey_dist = SEC_PARAM_IKEY;
sec_init.pairing_feat.rkey_dist = SEC_PARAM_RKEY;
sec_init.pairing_feat.sec_req = SEC_PARAM_SEC_MODE_LEVEL;
sec_init.bond_enable = BOND_STORE_ENABLE;
sec_init.bond_db_addr = BOND_DATA_BASE_ADDR;
sec_init.bond_max_peer = MAX_BOND_PEER;
sec_init.bond_sync_delay = 2000;
sec_init.ns_sec_msg_handler = NULL;
ns_sec_init(&sec_init);
}
/**
* @brief register the custom link service profile
*/
static void app_ble_prf_init(void)
{
//add custom link server (cls)
ns_ble_add_prf_func_register(app_cls_add_cls);
}
/**
* @brief BLE schedule task: the only context allowed to run ke_msg/ke_timer.
*/
static void ble_schedule_task(void *argument)
{
(void)argument;
for (;;)
{
/*schedule all pending events*/
rwip_schedule();
/*flush protocol pending TX frames (notify busy retry)*/
app_ble_proto_poll();
vTaskDelay(pdMS_TO_TICKS(1));
}
}
/**
* @brief ble initialization: stack, parameters, profile, advertising, task.
*/
void app_ble_init(void)
{
struct ns_stack_cfg_t app_handler = {0};
app_handler.ble_msg_handler = app_ble_msg_handler;
app_handler.user_msg_handler = NULL;
app_handler.lsc_cfg = BLE_LSC_LSI_32000HZ;
//initialization ble stack
ns_ble_stack_init(&app_handler);
app_ble_gap_params_init();
app_ble_sec_init();
app_ble_adv_init();
app_ble_prf_init();
/* frame protocol frontend: CLI-over-BLE + OTA receiver */
app_ble_proto_init();
app_ble_set_rx_callback(app_ble_proto_rx_bytes);
//start adv
ns_ble_adv_start();
/* Create the BLE schedule task (rwip_schedule loop) */
xTaskCreate(ble_schedule_task, "BLE", BLE_SCHED_TASK_STACK, NULL,
BLE_SCHED_TASK_PRIORITY, NULL);
}
/**
* @brief ble connected
*/
static void app_ble_connected(void)
{
s_ble_connected = 1;
app_cls_notify_state_reset();
bsp_usart_tx_lock();
printf("[BLE] connected, conidx=%u\n", (unsigned int)app_env.conidx);
bsp_usart_tx_unlock();
}
/**
* @brief ble disconnected
*/
static void app_ble_disconnected(void)
{
s_ble_connected = 0;
app_cls_notify_state_reset();
app_ble_proto_on_disconnect(); /* abort OTA session, drop pending TX */
bsp_usart_tx_lock();
printf("[BLE] disconnected, restart advertising\n");
bsp_usart_tx_unlock();
// Restart Advertising
ns_ble_adv_start();
}
/**
* @brief uplink notify send interface (single packet, busy -> -1)
*/
int app_ble_notify_send(const uint8_t *data, uint16_t len)
{
return app_cls_send_notify(data, len);
}
/**
* @brief register downlink data callback
*/
void app_ble_set_rx_callback(void (*cb)(const uint8_t*, uint16_t))
{
app_cls_set_rx_callback((app_cls_rx_cb_t)cb);
}
/**
* @brief BLE connection state
*/
uint8_t app_ble_is_connected(void)
{
return s_ble_connected;
}
/**
* @brief Max payload per BLE notification packet (att_mtu-3)
*/
uint16_t app_ble_max_payload(void)
{
if (!s_ble_connected || app_env.max_mtu < 23u)
{
return 20u - 3u; /* default ATT MTU 23 */
}
return (uint16_t)(app_env.max_mtu - 3u);
}