feat: add initial Bluetooth LE module

This commit is contained in:
Dien-Nhung Nguyen-Phu
2024-06-23 19:22:20 +07:00
parent 2383bf65e5
commit 8274cab154
12 changed files with 5167 additions and 3 deletions

246
src/ble/peripheral.c Normal file
View File

@@ -0,0 +1,246 @@
#include "CH58xBLE_LIB.h"
#include "setup.h"
#define ADV_UUID (0xFEE0)
static uint8 taskid = INVALID_TASK_ID;
typedef struct
{
uint16 connHandle; // Connection handle of current connection
uint16 connInterval;
uint16 connSlaveLatency;
uint16 connTimeout;
} peripheralConnItem_t;
#define SBP_PARAM_UPDATE_DELAY 1600 // Parameter update delay (unit of 0.625ms)
#define SLAVE_LATENCY 0
#define MIN_ADV_INTERVAL 100 // Advertising interval (units of 0.625ms)
#define MAX_ADV_INTERVAL 200 // Advertising interval (units of 0.625ms)
#define MIN_CONN_INTERVAL 20 // Connection interval (units of 1.25ms)
#define MAX_CONN_INTERVAL 100 // Connection interval (units of 1.25ms)
#define CONN_TIMEOUT 100 // Supervision timeout (units of 10ms)
// GAP - SCAN RSP data (max size = 31 bytes)
static uint8 scanRspData[] = {
// complete name
16, // length of this section
GAP_ADTYPE_LOCAL_NAME_COMPLETE,
'L', 'E','D', ' ',
'B', 'a','d', 'g', 'e', ' ',
'M', 'a','g', 'i', 'c',
// connection interval range
0x05, // length of this section
GAP_ADTYPE_SLAVE_CONN_INTERVAL_RANGE,
LO_UINT16(MIN_CONN_INTERVAL),
HI_UINT16(MIN_CONN_INTERVAL),
LO_UINT16(MAX_CONN_INTERVAL),
HI_UINT16(MAX_CONN_INTERVAL),
// Tx power level
0x02, // length of this data
GAP_ADTYPE_POWER_LEVEL,
9 // 9dBm
};
// GAP - Advertisement data (max size = 31 bytes)
// keep short, save energy, save the planet
static uint8 advertData[] = {
0x02, // section length
GAP_ADTYPE_FLAGS,
GAP_ADTYPE_FLAGS_GENERAL | GAP_ADTYPE_FLAGS_BREDR_NOT_SUPPORTED,
// advertise UUID
0x03, // section length
GAP_ADTYPE_16BIT_MORE,
LO_UINT16(ADV_UUID),
HI_UINT16(ADV_UUID)
};
// GAP GATT Attributes
static uint8 devName[GAP_DEVICE_NAME_LEN] = "LED Badge Magic";
// Connection item list
static peripheralConnItem_t conn_list;
static void initConn(peripheralConnItem_t *conn)
{
conn->connHandle = GAP_CONNHANDLE_INIT;
conn->connInterval = 0;
conn->connSlaveLatency = 0;
conn->connTimeout = 0;
}
static void processTMOSMsg(tmos_event_hdr_t *pMsg)
{
switch(pMsg->event) {
default:
break;
}
}
static void enable_advertising(uint8_t enable)
{
GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8), &enable);
}
static void link_onEstablished(gapRoleEvent_t *pe)
{
gapEstLinkReqEvent_t *e = (gapEstLinkReqEvent_t *)pe;
// If already connected
if(conn_list.connHandle != GAP_CONNHANDLE_INIT) {
// Only allow 1 connection, so the new connection will be dropped:
GAPRole_TerminateLink(e->connectionHandle);
GAPRole_PeripheralConnParamUpdateReq(e->connectionHandle,
MIN_CONN_INTERVAL,
MAX_CONN_INTERVAL,
SLAVE_LATENCY,
CONN_TIMEOUT,
taskid);
return;
}
conn_list.connHandle = e->connectionHandle;
conn_list.connInterval = e->connInterval;
conn_list.connSlaveLatency = e->connLatency;
conn_list.connTimeout = e->connTimeout;
enable_advertising(FALSE);
}
static void link_onTerminated(gapRoleEvent_t *pe)
{
gapTerminateLinkEvent_t *event = (gapTerminateLinkEvent_t *)pe;
GAPRole_TerminateLink(pe->linkCmpl.connectionHandle);
enable_advertising(TRUE);
if(event->connectionHandle == conn_list.connHandle) {
conn_list.connHandle = GAP_CONNHANDLE_INIT;
conn_list.connInterval = 0;
conn_list.connSlaveLatency = 0;
conn_list.connTimeout = 0;
} else {
// Requested connection is not existed in connection list
}
}
static void gap_onParamUpdate(uint16 connHandle, uint16 connInterval,
uint16 connSlaveLatency, uint16 connTimeout)
{
conn_list.connHandle = connHandle;
conn_list.connInterval = connInterval;
conn_list.connSlaveLatency = connSlaveLatency;
conn_list.connTimeout = connTimeout;
}
static void gap_onStateChange(gapRole_States_t newState, gapRoleEvent_t *pEvent)
{
switch(newState & GAPROLE_STATE_ADV_MASK) {
case GAPROLE_ADVERTISING:
if(pEvent->gap.opcode == GAP_LINK_TERMINATED_EVENT) {
link_onTerminated(pEvent);
}
break;
case GAPROLE_CONNECTED:
if(pEvent->gap.opcode == GAP_LINK_ESTABLISHED_EVENT) {
link_onEstablished(pEvent);
}
break;
case GAPROLE_WAITING:
if(pEvent->gap.opcode == GAP_LINK_TERMINATED_EVENT) {
link_onTerminated(pEvent);
} else {
// refer to pEvent->gap.opcode
}
break;
default:
break;
}
}
// GAP Role Callbacks
static gapRolesCBs_t gap_handlers = {
gap_onStateChange,
NULL,
gap_onParamUpdate
};
// Broadcast Callbacks
static gapRolesBroadcasterCBs_t broadcast_handlers = {
NULL,
NULL
};
// GAP Bond Manager Callbacks
static gapBondCBs_t bond_managers = {
NULL,
NULL
};
static uint16 peripheral_task(uint8 task_id, uint16 events)
{
if(events & SYS_EVENT_MSG) { // Handle BLE stack message
uint8 *pMsg = tmos_msg_receive(taskid);
if(pMsg) {
processTMOSMsg((tmos_event_hdr_t *)pMsg);
tmos_msg_deallocate(pMsg);
}
return (events ^ SYS_EVENT_MSG);
}
return 0;
}
static void gap_init()
{
GAPRole_PeripheralInit();
static uint8 initial_advertising_enable = TRUE;
static uint16 desired_min_interval = 6;
static uint16 desired_max_interval = 500;
// Set the GAP Role Parameters
GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8), &initial_advertising_enable);
GAPRole_SetParameter(GAPROLE_SCAN_RSP_DATA, sizeof(scanRspData), scanRspData);
GAPRole_SetParameter(GAPROLE_ADVERT_DATA, sizeof(advertData), advertData);
GAPRole_SetParameter(GAPROLE_MIN_CONN_INTERVAL, sizeof(uint16), &desired_min_interval);
GAPRole_SetParameter(GAPROLE_MAX_CONN_INTERVAL, sizeof(uint16), &desired_max_interval);
// Set the GAP Characteristics
GGS_SetParameter(GGS_DEVICE_NAME_ATT, GAP_DEVICE_NAME_LEN, devName);
GAP_SetParamValue(TGAP_DISC_ADV_INT_MIN, MIN_ADV_INTERVAL);
GAP_SetParamValue(TGAP_DISC_ADV_INT_MAX, MAX_ADV_INTERVAL);
static uint32 passkey = 0; // passkey "000000"
static uint8 pairMode = GAPBOND_PAIRING_MODE_NO_PAIRING;
static uint8 mitm = FALSE;
static uint8 bonding = FALSE;
static uint8 ioCap = GAPBOND_IO_CAP_DISPLAY_ONLY;
GAPBondMgr_SetParameter(GAPBOND_PERI_DEFAULT_PASSCODE, sizeof(uint32), &passkey);
GAPBondMgr_SetParameter(GAPBOND_PERI_PAIRING_MODE, sizeof(uint8), &pairMode);
GAPBondMgr_SetParameter(GAPBOND_PERI_MITM_PROTECTION, sizeof(uint8), &mitm);
GAPBondMgr_SetParameter(GAPBOND_PERI_IO_CAPABILITIES, sizeof(uint8), &ioCap);
GAPBondMgr_SetParameter(GAPBOND_PERI_BONDING_ENABLED, sizeof(uint8), &bonding);
GAPRole_BroadcasterSetCB(&broadcast_handlers);
GGS_AddService(GATT_ALL_SERVICES);
GATTServApp_AddService(GATT_ALL_SERVICES);
}
void peripheral_init()
{
taskid = TMOS_ProcessEventRegister(peripheral_task);
initConn(&conn_list);
gap_init();
GAPRole_PeripheralStartDevice(taskid, &bond_managers, &gap_handlers);
}