#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; } void ble_enable_advertise() { uint8 e = TRUE; GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8), &e); } void ble_disable_advertise() { uint8 e = FALSE; GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8), &e); } static void gap_init() { GAPRole_PeripheralInit(); static uint16 desired_min_interval = 6; static uint16 desired_max_interval = 500; // Set the GAP Role Parameters 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); }