Part Number: LAUNCHXL-CC1352R1
Tool/software:
I am trying to convert the Project Zero BLE example from the SimpleLink CC13x2 SDK into a static library so I can reuse it across multiple projects. However, I am facing compilation errors after removing hardware-specific files like ble_user_config.c.
Here’s what I have done so far:
-
Removed OAD (Over-the-Air Download) support since I don’t need it.
-
Excluded
ble_user_config.cfrom the static library because it contains hardware-dependent configurations that should remain in the main project. -
Defined necessary preprocessor symbols from the example project in the library.
Issues & Errors
After compiling, I encountered the following errors:
1965 cannot open source file "xdc/std.h"
20 identifier "coexUseCaseConfig_t" is undefined
20 identifier "cteAntProp_t" is undefined
20 identifier "ECCParams_CurveParams" is undefined
20 identifier "rfOpCmd_cntBranch_t" is undefined
20 identifier "rfOpCmd_runImmedCmd_t" is undefined
20 identifier "rtosApiTblPtr_t" is undefined
These errors seem to be related to missing dependencies from ble_user_config.c.
Questions:
-
What is the recommended way to handle
ble_user_config.cwhen converting a BLE project into a static library?-
Should I manually define missing structs (
coexUseCaseConfig_t,cteAntProp_t, etc.) inmain.c? -
Or should I include a minimal version of
ble_user_config.cinside the library?
-
-
How can I properly handle dependencies on
xdc/std.hand TI-RTOS headers when building a static library?-
The library does not seem to recognize
xdc/std.heven though I have included TI-RTOS paths.
-
-
Are there any best practices for structuring a BLE project as a static library in Code Composer Studio?
Any insights would be greatly appreciated!
System Details:
-
Platform: TI LaunchPad CC1352R1
-
SDK Version: simplelink_cc13x2_26x2_sdk_5_20_00_52
-
Compiler: TI Clang / TI ARM Compiler
Thank you!
//#include <ti/sysbios/BIOS.h>
#include <ti/sysbios/knl/Task.h>
#include <ti/sysbios/knl/Clock.h>
#include <ti/sysbios/knl/Event.h>
#include <ti/sysbios/knl/Queue.h>
#include <icall.h>
#include <icall_ble_api.h>
#include <gapbondmgr.h>
#include <gapgattserver.h>
#include <gattservapp.h>
#include <devinfoservice.h>
#include <linkdb.h>
#include <project_zero.h>
#include <led_service.h>
#include <button_service.h>
#include <data_service.h>
// Task configuration
#define PZ_TASK_PRIORITY 1
#define PZ_TASK_STACK_SIZE 2048
static Task_Struct pzTask;
static uint8_t pzTaskStack[PZ_TASK_STACK_SIZE];
// Application events
#define PZ_STATE_CHANGE_EVT 0x0001
#define PZ_READ_RPA_EVT 0x0002
#define PZ_SEND_PARAM_UPDATE_EVT 0x0004
#define PZ_CONN_EVT 0x0008
// Internal Events for RTOS application
#define PZ_ICALL_EVT ICALL_MSG_EVENT_ID
#define PZ_QUEUE_EVT UTIL_QUEUE_EVENT_ID
#define PZ_PERIODIC_EVT Event_Id_00
// Service events
#define PZ_SERVICE_WRITE_EVT Event_Id_01 /* A characteristic value has been written */
#define PZ_SERVICE_CFG_EVT Event_Id_02 /* A characteristic configuration has changed */
#define PZ_ALL_EVENTS (PZ_ICALL_EVT | PZ_QUEUE_EVT | PZ_PERIODIC_EVT | \
PZ_SERVICE_WRITE_EVT | PZ_SERVICE_CFG_EVT)
// Connection handle of current connection
#define INVALID_CONNHANDLE 0xFFFF
// Suggested TX time for DLE (us)
#define APP_SUGGESTED_TX_TIME 2120
// Struct for messages sent to the application task
typedef struct {
uint32_t event;
void *pData;
} pzMsg_t;
// Struct for messages about characteristic data
typedef struct {
uint16_t svcUUID; // UUID of the service
uint16_t dataLen; //
uint8_t paramID; // Index of the characteristic
uint8_t data[]; // Flexible array member, extended to malloc - sizeof(.)
} pzCharacteristicData_t;
// Connection event structure
typedef struct {
uint16_t connHandle;
uint8_t role;
uint8_t addrType;
uint8_t addr[B_ADDR_LEN];
} pzConnRec_t;
// Application state
static ICall_EntityID selfEntity;
static ICall_SyncHandle syncEvent;
static Queue_Struct appMsgQueue;
static Queue_Handle appMsgQueueHandle;
static Clock_Struct clkRpaRead;
static Clock_Struct clkSendParamUpdate;
static pzConnRec_t *connList = NULL;
static PzHardwareAbstraction_t hwAbstraction;
static PzBleConfig_t bleConfig;
// GAP Bond Manager Callbacks
static gapBondCBs_t ProjectZero_BondMgrCBs = {
NULL, // Passcode callback
NULL // Pairing state callback
};
// LED Service Callbacks
static ledServiceCBs_t ProjectZero_LED_ServiceCBs = {
.pfnChangeCb = ProjectZero_LedService_ValueChangeCB, // Characteristic value change callback handler
.pfnCfgChangeCb = NULL // No notification-/indication enabled chars in LED Service
};
// Button Service Callbacks
static buttonServiceCBs_t ProjectZero_Button_ServiceCBs = {
.pfnChangeCb = NULL, // No writable chars in Button Service, so no change handler
.pfnCfgChangeCb = ProjectZero_ButtonService_CfgChangeCB // Noti/ind configuration callback handler
};
// Data Service Callbacks
static dataServiceCBs_t ProjectZero_Data_ServiceCBs = {
.pfnChangeCb = ProjectZero_DataService_ValueChangeCB, // Characteristic value change callback handler
.pfnCfgChangeCb = ProjectZero_DataService_CfgChangeCB // Noti/ind configuration callback handler
};
// Function prototypes
static void ProjectZero_taskFxn(UArg a0, UArg a1);
static void ProjectZero_processAppMsg(uint32_t evt, void *pMsg);
static void ProjectZero_processGapMessage(gapEventHdr_t *pMsg);
static void ProjectZero_processGATTMsg(gattMsgEvent_t *pMsg);
static void ProjectZero_processConnEvt(uint16_t connHandle, uint8_t event);
static void ProjectZero_clearConnListEntry(uint16_t connHandle);
static void ProjectZero_clockHandler(UArg arg);
static pzConnRec_t *ProjectZero_findConnRec(uint16_t connHandle);
static uint8_t ProjectZero_addConn(uint16_t connHandle);
static uint8_t ProjectZero_removeConn(uint16_t connHandle);
static status_t ProjectZero_enqueueMsg(uint32_t event, void *pData);
static void ProjectZero_LedService_ValueChangeCB(uint16_t connHandle, uint8_t paramID, uint16_t len, uint8_t *pValue);
static void ProjectZero_DataService_ValueChangeCB(uint16_t connHandle, uint8_t paramID, uint16_t len, uint8_t *pValue);
static void ProjectZero_ButtonService_CfgChangeCB(uint16_t connHandle, uint8_t paramID, uint16_t len, uint8_t *pValue);
static void ProjectZero_DataService_CfgChangeCB(uint16_t connHandle, uint8_t paramID, uint16_t len, uint8_t *pValue);
static void ProjectZero_LedService_ValueChangeHandler(pzCharacteristicData_t *pCharData);
static void ProjectZero_DataService_ValueChangeHandler(pzCharacteristicData_t *pCharData);
static void ProjectZero_ButtonService_CfgChangeHandler(pzCharacteristicData_t *pCharData);
static void ProjectZero_DataService_CfgChangeHandler(pzCharacteristicData_t *pCharData);
// Initialize the Project Zero library
void ProjectZero_initWithConfig(const PzHardwareAbstraction_t *hwAbstractionPtr, const PzBleConfig_t *bleConfigPtr, ICall_EntityID entity)
{
// Store the hardware abstraction, BLE configuration, and selfEntity
hwAbstraction = *hwAbstractionPtr;
bleConfig = *bleConfigPtr;
selfEntity = entity;
// Create a sync event for event processing
syncEvent = ICall_createSyncHandle();
// Initialize queue for application messages
Queue_construct(&appMsgQueue, NULL);
appMsgQueueHandle = Queue_handle(&appMsgQueue);
// Dynamically allocate the connection list based on maxNumBleConns
connList = ICall_malloc(sizeof(pzConnRec_t) * bleConfig.maxNumBleConns);
if (!connList) {
if (hwAbstraction.logCallback) {
hwAbstraction.logCallback("Failed to allocate connection list");
}
return;
}
memset(connList, 0, sizeof(pzConnRec_t) * bleConfig.maxNumBleConns);
// Set the Device Name characteristic in the GAP GATT Service
GGS_SetParameter(GGS_DEVICE_NAME_ATT, bleConfig.deviceNameLen, (void *)bleConfig.deviceName);
// Configure GAP for param update
GAP_SetParameter(GAP_PARAM_LINK_UPDATE_DECISION, bleConfig.paramUpdateDecision);
// BLE Service initialization
GGS_AddService(GATT_ALL_SERVICES);
GATTServApp_AddService(GATT_ALL_SERVICES);
DevInfo_AddService();
LedService_AddService(selfEntity);
ButtonService_AddService(selfEntity);
DataService_AddService(selfEntity);
// Register callbacks with the services
LedService_RegisterAppCBs(&ProjectZero_LED_ServiceCBs);
ButtonService_RegisterAppCBs(&ProjectZero_Button_ServiceCBs);
DataService_RegisterAppCBs(&ProjectZero_Data_ServiceCBs);
// Placeholder variable for characteristic initialization
uint8_t initVal[40] = {0};
uint8_t initString[] = "This is a pretty long string, isn't it!";
// Initialization of characteristics in LED_Service that can provide data
LedService_SetParameter(LS_LED0_ID, LS_LED0_LEN, initVal);
LedService_SetParameter(LS_LED1_ID, LS_LED1_LEN, initVal);
// Initialization of characteristics in Button_Service that can provide data
ButtonService_SetParameter(BS_BUTTON0_ID, BS_BUTTON0_LEN, initVal);
ButtonService_SetParameter(BS_BUTTON1_ID, BS_BUTTON1_LEN, initVal);
// Initialization of characteristics in Data_Service that can provide data
DataService_SetParameter(DS_STRING_ID, sizeof(initString), initString);
DataService_SetParameter(DS_STREAM_ID, DS_STREAM_LEN, initVal);
// Start Bond Manager and register callback
VOID GAPBondMgr_Register(&ProjectZero_BondMgrCBs);
// Register with GAP for HCI/Host messages
GAP_RegisterForMsgs(selfEntity);
// Register for GATT local events and ATT Responses
GATT_RegisterForMsgs(selfEntity);
// Set default values for Data Length Extension
HCI_LE_WriteSuggestedDefaultDataLenCmd(bleConfig.maxPduSize, APP_SUGGESTED_TX_TIME);
// Initialize GATT Client
GATT_InitClient();
// Initialize Connection List
ProjectZero_clearConnListEntry(LINKDB_CONNHANDLE_ALL);
// Create one-shot clock for RPA check event if using random address
if (bleConfig.addressMode > ADDRMODE_RANDOM) {
Util_constructClock(&clkRpaRead, ProjectZero_clockHandler, bleConfig.readRpaPeriod, 0, true, PZ_READ_RPA_EVT);
}
}
// Create the Project Zero task
void ProjectZero_createTask(void)
{
Task_Params taskParams;
Task_Params_init(&taskParams);
taskParams.stack = pzTaskStack;
taskParams.stackSize = PZ_TASK_STACK_SIZE;
taskParams.priority = PZ_TASK_PRIORITY;
Task_construct(&pzTask, ProjectZero_taskFxn, &taskParams, NULL);
}
// Update button state (called by the main executable)
void ProjectZero_updateButtonState(uint8_t buttonId, uint8_t state)
{
// Update the Button Service characteristic (implementation depends on button_service.c)
ButtonService_SetParameter(buttonId, sizeof(state), &state);
if (hwAbstraction.logCallback) {
hwAbstraction.logCallback("%s %s", buttonId == BS_BUTTON0_ID ? "Button 0" : "Button 1",
state ? "pressed" : "released");
}
}
// Task function
static void ProjectZero_taskFxn(UArg a0, UArg a1)
{
// Initialize application
Event_Handle evtHandle = Event_create(NULL, NULL);
// Register to receive connection events
linkDB_Register(ProjectZero_processConnEvt);
// Enter main loop
while (1) {
uint32_t events = Event_pend(evtHandle, 0, PZ_ALL_EVENTS, BIOS_WAIT_FOREVER);
// Process periodic events
if (events & PZ_PERIODIC_EVT) {
// Handle periodic events (not used in this example)
}
// Process ICall messages
if (events & PZ_ICALL_EVT) {
ICall_ServiceEnum status;
ICall_Event *pEvt;
while ((pEvt = ICall_fetchServiceMsg(&status, &selfEntity, syncEvent)) != NULL) {
if (status == ICALL_SERVICE_CLASS_BLE) {
ProjectZero_processAppMsg(pEvt->event, pEvt->data);
}
ICall_freeMsg(pEvt);
}
}
// Process application messages
if (events & PZ_QUEUE_EVT) {
while (!Queue_empty(appMsgQueueHandle)) {
pzMsg_t *pMsg = (pzMsg_t *)Queue_get(appMsgQueueHandle);
if (pMsg) {
ProjectZero_processAppMsg(pMsg->event, pMsg->pData);
ICall_free(pMsg);
}
}
}
}
}
// Process application messages
static void ProjectZero_processAppMsg(uint32_t evt, void *pMsg)
{
pzCharacteristicData_t *pCharData = (pzCharacteristicData_t *)pMsg;
switch (evt) {
case GAP_MSG_EVENT:
ProjectZero_processGapMessage((gapEventHdr_t *)pMsg);
break;
case GATT_MSG_EVENT:
ProjectZero_processGATTMsg((gattMsgEvent_t *)pMsg);
break;
case PZ_READ_RPA_EVT:
// Handle RPA read event (not implemented in this example)
break;
case PZ_SEND_PARAM_UPDATE_EVT:
// Handle parameter update event (not implemented in this example)
break;
case PZ_CONN_EVT:
// Handle connection event (not implemented in this example)
break;
case PZ_SERVICE_WRITE_EVT:
switch (pCharData->svcUUID) {
case LED_SERVICE_SERV_UUID:
ProjectZero_LedService_ValueChangeHandler(pCharData);
break;
case DATA_SERVICE_SERV_UUID:
ProjectZero_DataService_ValueChangeHandler(pCharData);
break;
}
break;
case PZ_SERVICE_CFG_EVT:
switch (pCharData->svcUUID) {
case BUTTON_SERVICE_SERV_UUID:
ProjectZero_ButtonService_CfgChangeHandler(pCharData);
break;
case DATA_SERVICE_SERV_UUID:
ProjectZero_DataService_CfgChangeHandler(pCharData);
break;
}
break;
default:
break;
}
// Free the message data if it exists
if (evt == PZ_SERVICE_WRITE_EVT || evt == PZ_SERVICE_CFG_EVT) {
ICall_free(pMsg);
}
}
// Process GAP messages
static void ProjectZero_processGapMessage(gapEventHdr_t *pMsg)
{
switch (pMsg->opcode) {
case GAP_DEVICE_INIT_DONE_EVENT:
{
gapDeviceInitDoneEvent_t *pPkt = (gapDeviceInitDoneEvent_t *)pMsg;
if (pPkt->hdr.status == SUCCESS) {
// Store the system ID
uint8_t systemId[DEVINFO_SYSTEM_ID_LEN];
systemId[0] = pPkt->devAddr[0];
systemId[1] = pPkt->devAddr[1];
systemId[2] = pPkt->devAddr[2];
systemId[4] = 0x00;
systemId[3] = 0x00;
systemId[7] = pPkt->devAddr[5];
systemId[6] = pPkt->devAddr[4];
systemId[5] = pPkt->devAddr[3];
DevInfo_SetParameter(DEVINFO_SYSTEM_ID, DEVINFO_SYSTEM_ID_LEN, systemId);
if (hwAbstraction.logCallback) {
static char addrStr[3 * B_ADDR_LEN + 1];
snprintf(addrStr, sizeof(addrStr), "%02X:%02X:%02X:%02X:%02X:%02X",
pPkt->devAddr[5], pPkt->devAddr[4], pPkt->devAddr[3],
pPkt->devAddr[2], pPkt->devAddr[1], pPkt->devAddr[0]);
hwAbstraction.logCallback("GAP is started. Our address: %s", addrStr);
}
}
// Start advertising
GapAdv_create(NULL, bleConfig.advParams, NULL);
GapAdv_loadByBuffer(bleConfig.advDataLen, bleConfig.advData);
GapAdv_loadByBuffer(bleConfig.scanResDataLen, bleConfig.scanResData);
GapAdv_enable(0, GAP_ADV_ENABLE_OPTIONS_USE_MAX, 0);
break;
}
case GAP_LINK_ESTABLISHED_EVENT:
{
gapEstLinkReqEvent_t *pEvt = (gapEstLinkReqEvent_t *)pMsg;
if (pEvt->hdr.status == SUCCESS) {
ProjectZero_addConn(pEvt->connectionHandle);
if (hwAbstraction.logCallback) {
static char addrStr[3 * B_ADDR_LEN + 1];
snprintf(addrStr, sizeof(addrStr), "%02X:%02X:%02X:%02X:%02X:%02X",
pEvt->devAddr[5], pEvt->devAddr[4], pEvt->devAddr[3],
pEvt->devAddr[2], pEvt->devAddr[1], pEvt->devAddr[0]);
hwAbstraction.logCallback("Connected. Peer address: %s", addrStr);
}
}
break;
}
case GAP_LINK_TERMINATED_EVENT:
{
gapTermLinkEvent_t *pEvt = (gapTermLinkEvent_t *)pMsg;
ProjectZero_removeConn(pEvt->connectionHandle);
if (hwAbstraction.logCallback) {
hwAbstraction.logCallback("Link Terminated: ConnHandle 0x%04X", pEvt->connectionHandle);
}
// Restart advertising
GapAdv_enable(0, GAP_ADV_ENABLE_OPTIONS_USE_MAX, 0);
break;
}
default:
break;
}
}
// Process GATT messages
static void ProjectZero_processGATTMsg(gattMsgEvent_t *pMsg)
{
if (pMsg->method == ATT_FLOW_CTRL_VIOLATED_EVENT) {
if (hwAbstraction.logCallback) {
hwAbstraction.logCallback("FC Violated: %d", pMsg->msg.flowCtrlEvt.opcode);
}
}
// Forward GATT messages to the services
GATT_bm_free(&pMsg->msg, pMsg->method);
}
// Process connection events
static void ProjectZero_processConnEvt(uint16_t connHandle, uint8_t event)
{
if (hwAbstraction.logCallback) {
hwAbstraction.logCallback("Connection event done for connHandle: 0x%04X", connHandle);
}
}
// Clear connection list entry
static void ProjectZero_clearConnListEntry(uint16_t connHandle)
{
for (uint8_t i = 0; i < bleConfig.maxNumBleConns; i++) {
if (connList[i].connHandle == connHandle || connHandle == LINKDB_CONNHANDLE_ALL) {
connList[i].connHandle = INVALID_CONNHANDLE;
memset(&connList[i], 0, sizeof(pzConnRec_t));
}
}
}
// Add a device to the connected device list
static uint8_t ProjectZero_addConn(uint16_t connHandle)
{
pzConnRec_t *rec = ProjectZero_findConnRec(INVALID_CONNHANDLE);
if (rec) {
rec->connHandle = connHandle;
return SUCCESS;
}
return bleNoResources;
}
// Remove a device from the connected device list
static uint8_t ProjectZero_removeConn(uint16_t connHandle)
{
pzConnRec_t *rec = ProjectZero_findConnRec(connHandle);
if (rec) {
ProjectZero_clearConnListEntry(connHandle);
return SUCCESS;
}
return bleInvalidRange;
}
// Clock handler
static void ProjectZero_clockHandler(UArg arg)
{
uint32_t evt = (uint32_t)arg;
Event_post(Event_handle(NULL), evt);
}
// Find connection record
static pzConnRec_t *ProjectZero_findConnRec(uint16_t connHandle)
{
for (uint8_t i = 0; i < bleConfig.maxNumBleConns; i++) {
if (connList[i].connHandle == connHandle) {
return &connList[i];
}
}
return NULL;
}
// Utility function to enqueue messages to the application task
static status_t ProjectZero_enqueueMsg(uint32_t event, void *pData)
{
uint8_t success;
pzMsg_t *pMsg = ICall_malloc(sizeof(pzMsg_t));
if (pMsg) {
pMsg->event = event;
pMsg->pData = pData;
success = Queue_put(appMsgQueueHandle, (Queue_Elem *)pMsg);
return (success) ? SUCCESS : FAILURE;
}
return bleMemAllocError;
}
// LED Service Value Change Callback
static void ProjectZero_LedService_ValueChangeCB(uint16_t connHandle, uint8_t paramID, uint16_t len, uint8_t *pValue)
{
if (hwAbstraction.logCallback) {
hwAbstraction.logCallback("(CB) LED Svc Characteristic value change: paramID(%d). Sending msg to app.", paramID);
}
pzCharacteristicData_t *pValChange = ICall_malloc(sizeof(pzCharacteristicData_t) + len);
if (pValChange != NULL) {
pValChange->svcUUID = LED_SERVICE_SERV_UUID;
pValChange->paramID = paramID;
memcpy(pValChange->data, pValue, len);
pValChange->dataLen = len;
if (ProjectZero_enqueueMsg(PZ_SERVICE_WRITE_EVT, pValChange) != SUCCESS) {
ICall_free(pValChange);
}
}
}
// Data Service Value Change Callback
static void ProjectZero_DataService_ValueChangeCB(uint16_t connHandle, uint8_t paramID, uint16_t len, uint8_t *pValue)
{
if (hwAbstraction.logCallback) {
hwAbstraction.logCallback("(CB) Data Svc Characteristic value change: paramID(%d). Sending msg to app.", paramID);
}
pzCharacteristicData_t *pValChange = ICall_malloc(sizeof(pzCharacteristicData_t) + len);
if (pValChange != NULL) {
pValChange->svcUUID = DATA_SERVICE_SERV_UUID;
pValChange->paramID = paramID;
memcpy(pValChange->data, pValue, len);
pValChange->dataLen = len;
if (ProjectZero_enqueueMsg(PZ_SERVICE_WRITE_EVT, pValChange) != SUCCESS) {
ICall_free(pValChange);
}
}
}
// Button Service CCCD Change Callback
static void ProjectZero_ButtonService_CfgChangeCB(uint16_t connHandle, uint8_t paramID, uint16_t len, uint8_t *pValue)
{
if (hwAbstraction.logCallback) {
hwAbstraction.logCallback("(CB) Button Svc Char config change paramID(%d). Sending msg to app.", paramID);
}
pzCharacteristicData_t *pValChange = ICall_malloc(sizeof(pzCharacteristicData_t) + len);
if (pValChange != NULL) {
pValChange->svcUUID = BUTTON_SERVICE_SERV_UUID;
pValChange->paramID = paramID;
memcpy(pValChange->data, pValue, len);
pValChange->dataLen = len;
if (ProjectZero_enqueueMsg(PZ_SERVICE_CFG_EVT, pValChange) != SUCCESS) {
ICall_free(pValChange);
}
}
}
// Data Service CCCD Change Callback
static void ProjectZero_DataService_CfgChangeCB(uint16_t connHandle, uint8_t paramID, uint16_t len, uint8_t *pValue)
{
if (hwAbstraction.logCallback) {
hwAbstraction.logCallback("(CB) Data Svc Char config change paramID(%d). Sending msg to app.", paramID);
}
pzCharacteristicData_t *pValChange = ICall_malloc(sizeof(pzCharacteristicData_t) + len);
if (pValChange != NULL) {
pValChange->svcUUID = DATA_SERVICE_SERV_UUID;
pValChange->paramID = paramID;
memcpy(pValChange->data, pValue, len);
pValChange->dataLen = len;
if (ProjectZero_enqueueMsg(PZ_SERVICE_CFG_EVT, pValChange) != SUCCESS) {
ICall_free(pValChange);
}
}
}
// LED Service Value Change Handler
static void ProjectZero_LedService_ValueChangeHandler(pzCharacteristicData_t *pCharData)
{
static uint8_t pretty_data_holder[16]; // 5 bytes as hex string "AA:BB:CC:DD:EE"
snprintf((char *)pretty_data_holder, sizeof(pretty_data_holder), "%02X", pCharData->data[0]);
switch (pCharData->paramID) {
case LS_LED0_ID:
if (hwAbstraction.logCallback) {
hwAbstraction.logCallback("Value Change msg: LED Service LED0: %s", pretty_data_holder);
}
if (hwAbstraction.setLedCallback) {
hwAbstraction.setLedCallback(0, pCharData->data[0]);
}
if (hwAbstraction.logCallback) {
hwAbstraction.logCallback("Turning LED0 %s", pCharData->data[0] ? "on" : "off");
}
break;
case LS_LED1_ID:
if (hwAbstraction.logCallback) {
hwAbstraction.logCallback("Value Change msg: LED Service LED1: %s", pretty_data_holder);
}
if (hwAbstraction.setLedCallback) {
hwAbstraction.setLedCallback(1, pCharData->data[0]);
}
if (hwAbstraction.logCallback) {
hwAbstraction.logCallback("Turning LED1 %s", pCharData->data[0] ? "on" : "off");
}
break;
default:
return;
}
}
// Data Service Value Change Handler
static void ProjectZero_DataService_ValueChangeHandler(pzCharacteristicData_t *pCharData)
{
static uint8_t received_string[DS_STRING_LEN] = {0};
switch (pCharData->paramID) {
case DS_STRING_ID:
memset(received_string, 0, DS_STRING_LEN);
memcpy(received_string, pCharData->data, MIN(pCharData->dataLen, DS_STRING_LEN - 1));
if (hwAbstraction.logCallback) {
hwAbstraction.logCallback("Value Change msg: Data Service String: %s", received_string);
}
break;
case DS_STREAM_ID:
if (hwAbstraction.logCallback) {
hwAbstraction.logCallback("Value Change msg: Data Service Stream: %02x:%02x:%02x...",
pCharData->data[0], pCharData->data[1], pCharData->data[2]);
}
break;
default:
return;
}
}
// Button Service CCCD Change Handler
static void ProjectZero_ButtonService_CfgChangeHandler(pzCharacteristicData_t *pCharData)
{
uint16_t configValue = *(uint16_t *)pCharData->data;
const char *configValString;
switch (configValue) {
case GATT_CFG_NO_OPERATION:
configValString = "Noti/Ind disabled";
break;
case GATT_CLIENT_CFG_NOTIFY:
configValString = "Notifications enabled";
break;
case GATT_CLIENT_CFG_INDICATE:
configValString = "Indications enabled";
break;
default:
configValString = "Unsupported operation";
}
switch (pCharData->paramID) {
case BS_BUTTON0_ID:
if (hwAbstraction.logCallback) {
hwAbstraction.logCallback("CCCD Change msg: Button Service BUTTON0: %s", configValString);
}
break;
case BS_BUTTON1_ID:
if (hwAbstraction.logCallback) {
hwAbstraction.logCallback("CCCD Change msg: Button Service BUTTON1: %s", configValString);
}
break;
}
}
// Data Service CCCD Change Handler
static void ProjectZero_DataService_CfgChangeHandler(pzCharacteristicData_t *pCharData)
{
uint16_t configValue = *(uint16_t *)pCharData->data;
const char *configValString;
switch (configValue) {
case GATT_CFG_NO_OPERATION:
configValString = "Noti/Ind disabled";
break;
case GATT_CLIENT_CFG_NOTIFY:
configValString = "Notifications enabled";
break;
case GATT_CLIENT_CFG_INDICATE:
configValString = "Indications enabled";
break;
default:
configValString = "Unsupported operation";
}
switch (pCharData->paramID) {
case DS_STREAM_ID:
if (hwAbstraction.logCallback) {
hwAbstraction.logCallback("CCCD Change msg: Data Service Stream: %s", configValString);
}
break;
}
}



