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.c
from 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.c
when 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.c
inside the library?
-
-
How can I properly handle dependencies on
xdc/std.h
and TI-RTOS headers when building a static library?-
The library does not seem to recognize
xdc/std.h
even 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; } }
