585 lines
17 KiB
C
585 lines
17 KiB
C
/**
|
|
****************************************************************************************
|
|
*
|
|
* @file app.c
|
|
*
|
|
* @brief Application entry point - Example
|
|
*
|
|
* < __weak func as demo, recommend to Override its in 'user porject'/src/myapp.c >
|
|
****************************************************************************************
|
|
*/
|
|
|
|
#include "app.h"
|
|
#include "bledef.h"
|
|
#include "drvs.h"
|
|
#include "prf_api.h"
|
|
|
|
#if (DBG_APP)
|
|
#include "dbg.h"
|
|
#define DEBUG(format, ...) debug("<%s,%d>" format "\r\n", __MODULE__, __LINE__, ##__VA_ARGS__)
|
|
#else
|
|
#define DEBUG(format, ...)
|
|
#endif
|
|
|
|
|
|
/*
|
|
* DEFAULT CONFIGURATION
|
|
****************************************************************************************
|
|
*/
|
|
|
|
#if !defined(BLE_DEV_NAME)
|
|
#define BLE_DEV_NAME "myBle6"
|
|
#endif
|
|
|
|
#if !defined(BLE_ADDR)
|
|
#define BLE_ADDR { 0x30, 0x06, 0x23, 0x20, 0x01, 0xD2 }
|
|
#endif
|
|
|
|
#if !defined(BLE_ROLE)
|
|
#if (BLE_NB_SLAVE && BLE_NB_MASTER)
|
|
#define BLE_ROLE (GAP_ROLE_CENTRAL | GAP_ROLE_PERIPHERAL)
|
|
#elif (BLE_NB_MASTER)
|
|
#define BLE_ROLE (GAP_ROLE_CENTRAL)
|
|
#else // Only Slave
|
|
#define BLE_ROLE (GAP_ROLE_PERIPHERAL)
|
|
#endif
|
|
#endif
|
|
|
|
#if !defined(BLE_PHY)
|
|
#define BLE_PHY (GAP_PHY_LE_1MBPS) // | GAP_PHY_LE_2MBPS)
|
|
#endif
|
|
|
|
#if !defined(BLE_PAIRING)
|
|
#define BLE_PAIRING (GAPM_PAIRING_LEGACY)
|
|
#endif
|
|
|
|
#if !defined(BLE_AUTH)
|
|
#define BLE_AUTH (GAP_AUTH_REQ_NO_MITM_NO_BOND)
|
|
#endif
|
|
|
|
#if !defined(BLE_SECREQ)
|
|
#define BLE_SECREQ (GAP_NO_SEC)
|
|
#endif
|
|
|
|
|
|
/*
|
|
* VARIABLES DEFINITIONS
|
|
****************************************************************************************
|
|
*/
|
|
|
|
/// Application Environment
|
|
__VAR_ENV struct app_env_tag app_env;
|
|
|
|
/// Ble local address (user customize)
|
|
const bd_addr_t ble_dev_addr = { BLE_ADDR };
|
|
|
|
/// GAP device configuration
|
|
const struct gapm_dev_config ble_dev_config =
|
|
{
|
|
// Device Role: Central, Peripheral (@see gap_role)
|
|
.gap_role = BLE_ROLE,
|
|
|
|
// Pairing mode authorized (@see enum gapm_pairing_mode)
|
|
.pairing = BLE_PAIRING,
|
|
|
|
// Preferred LE PHY for data (@see enum gap_phy)
|
|
.pref_phy = BLE_PHY,
|
|
|
|
// Maximal MTU acceptable for device (23~512)
|
|
.max_mtu = BLE_MTU,
|
|
};
|
|
|
|
/// GAP debug LTK for testing
|
|
#if (BLE_DBG_LTK)
|
|
const struct gapc_ltk debugLTK =
|
|
{
|
|
/// Long Term Key
|
|
.ltk = {{0x88, 0x0D, 0x00, 0x20, 0xAC, 0x32, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00}},
|
|
/// Encryption Diversifier
|
|
.ediv = 0xB951,
|
|
/// Random Number
|
|
.randnb = {{0x02, 0x18, 0xAC, 0x32, 0x00, 0x20, 0x00, 0x00}},
|
|
/// Encryption key size (7 to 16)
|
|
.key_size = 16,
|
|
/// Extend Info
|
|
.ext_info =0,
|
|
};
|
|
#endif
|
|
|
|
|
|
/*
|
|
* FUNCTION DEFINITIONS
|
|
****************************************************************************************
|
|
*/
|
|
|
|
/**
|
|
****************************************************************************************
|
|
* @section Profile Interface
|
|
****************************************************************************************
|
|
*/
|
|
|
|
// Connection interval unit in 1.25ms
|
|
#define SLV_PREF_INTV_MIN (10)
|
|
#define SLV_PREF_INTV_MAX (10)
|
|
// Slave latency
|
|
#define SLV_PREF_LATENCY (0)
|
|
// Connection supervision timeout multiplier unit in 10ms
|
|
#define SLV_PREF_TIME_OUT (300)
|
|
|
|
/**
|
|
****************************************************************************************
|
|
* @brief Retrieve Dev Info to Generic Access Profile, User implement for Callback.
|
|
*
|
|
* @param[in] conidx connection index
|
|
* @param[in] req iequest of info type @see enum gapc_dev_info
|
|
* @param[in] maxlen buffer length, DEV_NAME_MAX_LEN or size of gapc_conn_param
|
|
* @param[out] info pointer of buffer
|
|
*
|
|
* @return Length of device information, 0 means an error occurs.
|
|
****************************************************************************************
|
|
*/
|
|
__weak uint16_t gap_svc_get_dev_info(uint8_t conidx, uint8_t req, uint16_t maxlen, uint8_t *info)
|
|
{
|
|
if (req == GAPC_DEV_NAME)
|
|
{
|
|
return app_name_get(DEV_NAME_MAX_LEN, info);
|
|
}
|
|
else if (req == GAPC_DEV_APPEARANCE)
|
|
{
|
|
write16(info, app_icon_get());
|
|
return sizeof(uint16_t);
|
|
}
|
|
#if (GAP_ATT_CFG & 0x40/*PCP_EN*/)
|
|
else if (req == GAPC_DEV_SLV_PREF_PARAMS)
|
|
{
|
|
struct gapc_conn_param *slv_pref = (struct gapc_conn_param *)info;
|
|
// Peripheral Preferred Connection Parameters
|
|
slv_pref->intv_min = SLV_PREF_INTV_MIN;
|
|
slv_pref->intv_max = SLV_PREF_INTV_MAX;
|
|
slv_pref->latency = SLV_PREF_LATENCY;
|
|
slv_pref->time_out = SLV_PREF_TIME_OUT;
|
|
return sizeof(struct gapc_conn_param);
|
|
}
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
****************************************************************************************
|
|
* @brief Create profiles, maybe User Override! (__weak func)
|
|
* Added in order and judged status in each profile-func.
|
|
****************************************************************************************
|
|
*/
|
|
__weak void app_prf_create(void)
|
|
{
|
|
// Generic Access Profile(0x1800)
|
|
gap_svc_init(GAP_START_HDL, GAP_ATT_CFG);
|
|
|
|
// Generic Attribute Profile(0x1801)
|
|
#if (PRF_GATT)
|
|
gatt_svc_init(GATT_START_HDL);
|
|
#endif
|
|
|
|
// Standard Profiles
|
|
#if (PRF_DISS)
|
|
diss_svc_init();
|
|
#endif
|
|
|
|
#if (PRF_BASS)
|
|
bass_svc_init();
|
|
#endif
|
|
|
|
#if (PRF_HIDS)
|
|
hids_prf_init();
|
|
#endif
|
|
|
|
#if (PRF_SCPS)
|
|
scps_svc_init();
|
|
#endif
|
|
|
|
#if (PRF_MESH)
|
|
mesh_svc_init(MESH_START_HDL, MESH_SVC_CFG);
|
|
#endif
|
|
|
|
// Customize Profiles
|
|
#if (PRF_SESS)
|
|
sess_svc_init();
|
|
#endif
|
|
|
|
#if (PRF_OTAS)
|
|
otas_svc_init();
|
|
#endif
|
|
|
|
#if (PRF_PTSS)
|
|
ptss_svc_init();
|
|
#endif
|
|
}
|
|
|
|
|
|
/**
|
|
****************************************************************************************
|
|
* @section App Interface
|
|
****************************************************************************************
|
|
*/
|
|
|
|
/**
|
|
****************************************************************************************
|
|
* @brief API to Init Application, maybe User Override! (__weak func)
|
|
*
|
|
* @param[in] rsn reset reason @see enum rst_src_bfs
|
|
****************************************************************************************
|
|
*/
|
|
__weak void app_init(uint16_t rsn)
|
|
{
|
|
// Init BLE and App to startup or Resume BLE to continue if it wakeup from poweroff.
|
|
#if (BLE_LITELIB)
|
|
if (RSN_IS_BLE_WKUP(rsn))
|
|
{
|
|
// Resume BLE (Only supported in LiteLib)
|
|
ble_resume();
|
|
rc32k_conf(RCLK_DPLL, 7);
|
|
}
|
|
else
|
|
#endif //(BLE_LITELIB)
|
|
{
|
|
heap_cfg_t heap;
|
|
|
|
// Config Heap, resized with special lib
|
|
heap.base[MEM_ENV] = BLE_HEAP_BASE;
|
|
heap.size[MEM_ENV] = BLE_HEAP_ENV_SIZE;
|
|
heap.base[MEM_MSG] = BLE_HEAP_BASE + BLE_HEAP_ENV_SIZE;
|
|
heap.size[MEM_MSG] = BLE_HEAP_MSG_SIZE;
|
|
ble_heap(&heap);
|
|
|
|
// Init BLE and App
|
|
ble_init();
|
|
ble_app();
|
|
|
|
// Init RC32K with Calibration
|
|
#if (CFG_SLEEP || RC32K_CALIB_PERIOD)
|
|
//rc32k_init(); - replace to watch calib result
|
|
rc32k_conf(RCLK_DPLL, 7);
|
|
|
|
uint16_t trim = rc32k_calib();
|
|
DEBUG("RC32K Calib(Msb:%d,Lsb:%d)", trim & 0xF, trim >> 4);
|
|
|
|
#endif //(CFG_SLEEP || RC32K_CALIB_PERIOD)
|
|
}
|
|
|
|
// Init RF & Modem
|
|
rfmdm_init();
|
|
|
|
NVIC_EnableIRQ(BLE_IRQn);
|
|
}
|
|
|
|
/**
|
|
****************************************************************************************
|
|
* @brief API to Set State of Application, maybe User Override! (__weak func)
|
|
*
|
|
* @param[in] state new state
|
|
****************************************************************************************
|
|
*/
|
|
__weak void app_state_set(uint8_t state)
|
|
{
|
|
DEBUG("State(old:%d,new:%d)", app_state_get(), state);
|
|
|
|
app_env.state = state;
|
|
|
|
// Indication, User add more...
|
|
|
|
}
|
|
|
|
/**
|
|
****************************************************************************************
|
|
* @brief API to Get Device Name, maybe User Override! (__weak func)
|
|
*
|
|
* @param[in] size Length of name Buffer
|
|
* @param[out] name Pointer of name buffer
|
|
*
|
|
* @return Length of device name
|
|
****************************************************************************************
|
|
*/
|
|
__weak uint8_t app_name_get(uint8_t size, uint8_t *name)
|
|
{
|
|
uint8_t len = sizeof(BLE_DEV_NAME) - 1;
|
|
|
|
// eg. prefix(BLE_DEV_NAME) + suffix(Addr[0])
|
|
if (size < len + 2)
|
|
{
|
|
// no enough buffer, short copy
|
|
len = size;
|
|
memcpy(name, BLE_DEV_NAME, len);
|
|
}
|
|
else
|
|
{
|
|
// prefix + suffix
|
|
memcpy(name, BLE_DEV_NAME, len);
|
|
name[len++] = co_hex(ble_dev_addr.addr[0] >> 4);
|
|
name[len++] = co_hex(ble_dev_addr.addr[0] & 0x0F);
|
|
}
|
|
|
|
return len;
|
|
}
|
|
|
|
|
|
/**
|
|
****************************************************************************************
|
|
* @section FSM Interface
|
|
****************************************************************************************
|
|
*/
|
|
|
|
/**
|
|
****************************************************************************************
|
|
* @brief Finite state machine for Device Configure, maybe User Override! (__weak func)
|
|
*
|
|
* @param[in] evt configure event @see enum ble_event
|
|
****************************************************************************************
|
|
*/
|
|
__weak void app_conf_fsm(uint8_t evt)
|
|
{
|
|
if (evt == BLE_RESET)
|
|
{
|
|
memset(&app_env, 0, sizeof(app_env));
|
|
|
|
// Set device config
|
|
gapm_set_dev(&ble_dev_config, &ble_dev_addr, NULL);
|
|
}
|
|
else /*if (evt == BLE_CONFIGURED)*/
|
|
{
|
|
#if (CFG_SLEEP)
|
|
// Set Sleep duration if need
|
|
|
|
#if (RC32K_CALIB_PERIOD)
|
|
ke_timer_set(APP_TIMER_RC32K_CORR, TASK_APP, RC32K_CALIB_PERIOD);
|
|
#endif //(RC32K_CALIB_PERIOD)
|
|
#endif //(CFG_SLEEP)
|
|
|
|
app_state_set(APP_IDLE);
|
|
|
|
// Create Profiles
|
|
app_prf_create();
|
|
|
|
#if (APP_ACTV_EN)
|
|
// Create Activities
|
|
app_actv_create();
|
|
#endif //(APP_ACTV_EN)
|
|
|
|
#if (PRF_MESH)
|
|
// Create Mesh Instance
|
|
app_mesh_create();
|
|
#endif //(PRF_MESH)
|
|
}
|
|
}
|
|
|
|
/**
|
|
****************************************************************************************
|
|
* @brief Finite state machine for connection event, maybe User Override! (__weak func)
|
|
*
|
|
* @param[in] evt connection event @see enum ble_event
|
|
* @param[in] conidx connection index
|
|
* @param[in] param param of connection event
|
|
****************************************************************************************
|
|
*/
|
|
__weak void app_conn_fsm(uint8_t evt, uint8_t conidx, const void* param)
|
|
{
|
|
switch (evt)
|
|
{
|
|
case BLE_CONNECTED:
|
|
{
|
|
// Connected state, record Index
|
|
app_env.curidx = conidx;
|
|
app_state_set(APP_CONNECTED);
|
|
|
|
#if (BLE_MULTI_CONN)
|
|
uint8_t role = gapc_get_role(conidx);
|
|
// Set Connection Bit of conidx
|
|
app_env.conbits |= (1 << conidx);
|
|
app_env.conrole = (app_env.conrole & ~(1 << conidx)) | (role << conidx);
|
|
|
|
DEBUG(" multi(cbit:%02X,rbit:%02X,curr:%d)", app_env.conbits, app_env.conrole, app_env.curidx);
|
|
|
|
// Restart Advertising for more connections as slave role - update from v1.3
|
|
if ((role == ROLE_SLAVE)&& (ONE_BITS(app_env.conrole) < BLE_NB_SLAVE))
|
|
{
|
|
app_adv_action(ACTV_START);
|
|
}
|
|
#endif //(BLE_MULTI_CONN)
|
|
|
|
gapc_connect_rsp(conidx, BLE_AUTH);
|
|
// Enable profiles by role
|
|
} break;
|
|
|
|
case BLE_DISCONNECTED:
|
|
{
|
|
#if (BLE_MULTI_CONN)
|
|
DEBUG(" Befor(cbit:%02X,rbit:%02X,curr:%d)", app_env.conbits, app_env.conrole, app_env.curidx);
|
|
// Clr Connection Bit of conidx
|
|
app_env.conbits &= ~(1 << conidx);
|
|
|
|
if (app_env.conbits == 0)
|
|
{
|
|
// Go READY when all disconnected
|
|
app_state_set(APP_READY);
|
|
}
|
|
else
|
|
{
|
|
// Find new index when curr disconnected
|
|
if (conidx == app_env.curidx)
|
|
{
|
|
// Least index of connection or * User customize *
|
|
app_env.curidx = co_ctz(app_env.conbits);
|
|
}
|
|
}
|
|
|
|
// Role Operation
|
|
if (app_env.conrole & (1 << conidx))
|
|
{
|
|
// As slave role, Clr Bit
|
|
app_env.conrole &= ~(1 << conidx);
|
|
|
|
#if (APP_ACTV_EN && BLE_EN_ADV)
|
|
// Restart Advertising
|
|
app_adv_action(ACTV_START);
|
|
#endif //(APP_ACTV_EN && BLE_EN_ADV)
|
|
}
|
|
#if (BLE_NB_MASTER)
|
|
else
|
|
{
|
|
struct gapc_disconnect_ind *param = (struct gapc_disconnect_ind *)param;
|
|
|
|
// As master role, to do * User customize *
|
|
if (param->reason == 8 /*ERR_CON_TIMEOUT*/)
|
|
{
|
|
|
|
}
|
|
}
|
|
#endif // BLE_NB_MASTER
|
|
DEBUG(" After(cbit:%02X,rbit:%02X,curr:%d)", app_env.conbits, app_env.conrole, app_env.curidx);
|
|
#else
|
|
{
|
|
app_state_set(APP_READY);
|
|
|
|
#if (APP_ACTV_EN && BLE_EN_ADV)
|
|
// Slave role, Restart Advertising
|
|
app_adv_action(ACTV_START);
|
|
#endif //(APP_ACTV_EN && BLE_EN_ADV)
|
|
}
|
|
#endif //(BLE_MULTI_CONN)
|
|
} break;
|
|
|
|
case BLE_BONDED:
|
|
{
|
|
// todo, eg. save the generated slave's LTK to flash
|
|
app_ltk_save(conidx, NULL);
|
|
} break;
|
|
|
|
case BLE_ENCRYPTED:
|
|
{
|
|
// todo
|
|
} break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
****************************************************************************************
|
|
* @section SMP Interface
|
|
****************************************************************************************
|
|
*/
|
|
|
|
/**
|
|
****************************************************************************************
|
|
* @brief API to Get Pairing Feature, maybe User Override! (__weak func)
|
|
*
|
|
* @param[out] feat Pointer of pairing buffer to fill
|
|
****************************************************************************************
|
|
*/
|
|
__weak void app_pairing_get(struct gapc_pairing *feat)
|
|
{
|
|
// IO capabilities (@see gap_io_cap)
|
|
feat->iocap = GAP_IO_CAP_NO_INPUT_NO_OUTPUT;
|
|
// OOB information (@see gap_oob)
|
|
feat->oob = GAP_OOB_AUTH_DATA_NOT_PRESENT;
|
|
// Authentication (@see gap_auth)
|
|
feat->auth = BLE_AUTH;
|
|
// Encryption key size (7 to 16)
|
|
feat->key_size = GAP_KEY_LEN;
|
|
//Initiator key distribution (@see gap_kdist)
|
|
feat->ikey_dist = GAP_KDIST_NONE;
|
|
//Responder key distribution (@see gap_kdist)
|
|
feat->rkey_dist = GAP_KDIST_ENCKEY;
|
|
// Device security requirements (@see gap_sec_req)
|
|
feat->sec_req = BLE_SECREQ;
|
|
}
|
|
|
|
/**
|
|
****************************************************************************************
|
|
* @brief API to Generate LTK for bonding, maybe User Override! (__weak func)
|
|
*
|
|
* @param[in] conidx connection index
|
|
* @param[in|out] ltk Pointer of ltk buffer
|
|
****************************************************************************************
|
|
*/
|
|
__weak void app_ltk_gen(uint8_t conidx, struct gapc_ltk *ltk)
|
|
{
|
|
// generate key values, User need record it to save later
|
|
// ltk->ediv = (uint16_t)rand_word();
|
|
// ltk->key_size = GAP_KEY_LEN;
|
|
// ltk->ext_info = 0;
|
|
// for (uint8_t i = 0; i < GAP_RAND_NB_LEN; i++)
|
|
// {
|
|
// ltk->randnb.nb[i] = (uint8_t)rand_word();
|
|
// }
|
|
// for (uint8_t i = 0; i < GAP_KEY_LEN; i++)
|
|
// {
|
|
// ltk->ltk.key[i] = (uint8_t)rand_word();
|
|
// }
|
|
|
|
#if (BLE_DBG_LTK)
|
|
// (here use debugLTK as testing)
|
|
memcpy(ltk, &debugLTK, sizeof(struct gapc_ltk));
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
****************************************************************************************
|
|
* @brief API to Save LTK when bonded, maybe User Override! (__weak func)
|
|
*
|
|
* @param[in] conidx connection index
|
|
* @param[in] ltk Pointer of LTK data
|
|
****************************************************************************************
|
|
*/
|
|
__weak void app_ltk_save(uint8_t conidx, const struct gapc_ltk *ltk)
|
|
{
|
|
// todo, save slave's LTK to flash
|
|
}
|
|
|
|
/**
|
|
****************************************************************************************
|
|
* @brief API to Find LTK when re-encryption, maybe User Override! (__weak func)
|
|
*
|
|
* @param[in] ediv EDIV value for matching
|
|
* @param[in] rand_nb Rand Nb values for matching
|
|
*
|
|
* @return NULL for not matched, else return Pointer of LTK found.
|
|
****************************************************************************************
|
|
*/
|
|
__weak const uint8_t *app_ltk_find(uint16_t ediv, const uint8_t *rand_nb)
|
|
{
|
|
// Compare ediv and rand_nb (here use debugLTK as testing)
|
|
#if (BLE_DBG_LTK)
|
|
if ((ediv == debugLTK.ediv)
|
|
&& (memcmp(rand_nb, debugLTK.randnb.nb, GAP_RAND_NB_LEN) == 0))
|
|
{
|
|
return debugLTK.ltk.key;
|
|
}
|
|
#endif
|
|
|
|
// Not found
|
|
return NULL;
|
|
}
|