Other Parts Discussed in Thread: CC2640
I am using CC2640R2_LAUNCHXL Board for the development.
I am using a simple peripheral example from BLE Stack, So far, I am able to get and ADC Sensor data in to Notify characteristic of the BLE. It is working good.
Now I am trying to add few more sensors and, send those sensors data to smartphone bluetooth via different notify characteristic.
my application is like
1) Continously transmission of data from one characteristic.
2) Data Transmission at a fixed interval of time like an interval of an 1 minute.
I tried few methods but not working, or i am doing something wrong probably, Is there any guide if how i should do it properly. I have attached my code here.
#include <string.h> #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 <semaphore.h> #include <pthread.h> #include <time.h> #include <ti/display/Display.h> #include <icall.h> #include "util.h" #include "att_rsp.h" /* This Header file contains all BLE API and icall structure definition */ #include "icall_ble_api.h" #include "devinfoservice.h" #include "ll_common.h" #include "peripheral.h" #include "EcgService.h" #include "board_key.h" #include "board.h" #include "simple_peripheral.h" #include <ti/devices/DeviceFamily.h> #include DeviceFamily_constructPath(driverlib/aon_batmon.h) /********************************************************************* * CONSTANTS */ // Advertising interval when device is discoverable (units of 625us, 160=100ms) #define DEFAULT_ADVERTISING_INTERVAL 160 // General discoverable mode: advertise indefinitely #define DEFAULT_DISCOVERABLE_MODE GAP_ADTYPE_FLAGS_GENERAL // Minimum connection interval (units of 1.25ms, 80=100ms) for automatic // parameter update request #define DEFAULT_DESIRED_MIN_CONN_INTERVAL 80 // Maximum connection interval (units of 1.25ms, 800=1000ms) for automatic // parameter update request #define DEFAULT_DESIRED_MAX_CONN_INTERVAL 800 // Slave latency to use for automatic parameter update request #define DEFAULT_DESIRED_SLAVE_LATENCY 0 // Supervision timeout value (units of 10ms, 1000=10s) for automatic parameter // update request #define DEFAULT_DESIRED_CONN_TIMEOUT 1000 // After the connection is formed, the peripheral waits until the central // device asks for its preferred connection parameters #define DEFAULT_ENABLE_UPDATE_REQUEST GAPROLE_LINK_PARAM_UPDATE_WAIT_REMOTE_PARAMS // Connection Pause Peripheral time value (in seconds) #define DEFAULT_CONN_PAUSE_PERIPHERAL 6 // How often to perform periodic event (in msec) #define SBP_PERIODIC_EVT_PERIOD 5000 // Application specific event ID for HCI Connection Event End Events #define SBP_HCI_CONN_EVT_END_EVT 0x0001 // Type of Display to open #if !defined(Display_DISABLE_ALL) #if defined(BOARD_DISPLAY_USE_LCD) && (BOARD_DISPLAY_USE_LCD!=0) #define SBP_DISPLAY_TYPE Display_Type_LCD #elif defined (BOARD_DISPLAY_USE_UART) && (BOARD_DISPLAY_USE_UART!=0) #define SBP_DISPLAY_TYPE Display_Type_UART #else // !BOARD_DISPLAY_USE_LCD && !BOARD_DISPLAY_USE_UART #define SBP_DISPLAY_TYPE 0 // Option not supported #endif // BOARD_DISPLAY_USE_LCD && BOARD_DISPLAY_USE_UART #else // BOARD_DISPLAY_USE_LCD && BOARD_DISPLAY_USE_UART #define SBP_DISPLAY_TYPE 0 // No Display #endif // !Display_DISABLE_ALL // Task configuration #define SBP_TASK_PRIORITY 1 #ifndef TASK1STACKSIZE #define TASK1STACKSIZE 644 #define TASK2STACKSIZE 768 #endif // Application events #define SBP_STATE_CHANGE_EVT 0x0001 #define SBP_CHAR_CHANGE_EVT 0x0002 #define SBP_PAIRING_STATE_EVT 0x0004 #define SBP_PASSCODE_NEEDED_EVT 0x0008 #define SBP_CONN_EVT 0x0010 // Internal Events for RTOS application #define SBP_ICALL_EVT ICALL_MSG_EVENT_ID // Event_Id_31 #define SBP_QUEUE_EVT UTIL_QUEUE_EVENT_ID // Event_Id_30 #define SBP_PERIODIC_EVT Event_Id_00 #define SBP_PERIODIC_EVT1 Event_Id_01 // Bitwise OR of all events to pend on #define SBP_ALL_EVENTS (SBP_ICALL_EVT | \ SBP_QUEUE_EVT | \ SBP_PERIODIC_EVT | \ SBP_PERIODIC_EVT1) // Set the register cause to the registration bit-mask #define CONNECTION_EVENT_REGISTER_BIT_SET(RegisterCause) (connectionEventRegisterCauseBitMap |= RegisterCause ) // Remove the register cause from the registration bit-mask #define CONNECTION_EVENT_REGISTER_BIT_REMOVE(RegisterCause) (connectionEventRegisterCauseBitMap &= (~RegisterCause) ) // Gets whether the current App is registered to the receive connection events #define CONNECTION_EVENT_IS_REGISTERED (connectionEventRegisterCauseBitMap > 0) // Gets whether the RegisterCause was registered to recieve connection event #define CONNECTION_EVENT_REGISTRATION_CAUSE(RegisterCause) (connectionEventRegisterCauseBitMap & RegisterCause ) /********************************************************************* * TYPEDEFS */ #include <ti/drivers/ADC.h>//add #include <ti/drivers/ADC.h> #include <ti/drivers/adc/ADCCC26XX.h> ADCCC26XX_Object adcCC26xxObjects[1]; const ADCCC26XX_HWAttrs adcCC26xxHWAttrs[1] = { { .adcDIO = IOID_8, .adcCompBInput = ADC_COMPB_IN_AUXIO6, .refSource = ADCCC26XX_FIXED_REFERENCE, .samplingDuration = ADCCC26XX_SAMPLING_DURATION_10P9_MS, .inputScalingEnabled = true, .triggerSource = ADCCC26XX_TRIGGER_MANUAL, .returnAdjustedVal = false } }; const ADC_Config ADC_config[1] = { {&ADCCC26XX_fxnTable, &adcCC26xxObjects[0], &adcCC26xxHWAttrs[0]}, }; const uint_least8_t ADC_count = 1; // App event passed from profiles. typedef struct { appEvtHdr_t hdr; // event header. uint8_t *pData; // event data } sbpEvt_t; /********************************************************************* * GLOBAL VARIABLES */ uint8_t EcgService_EcgService_DataChar1UUIDVal[ECGSERVICE_ECGSERVICE_DATACHAR1UUID_LEN] = {0}; uint8_t EcgService_EcgService_DataChar2UUIDVal[ECGSERVICE_ECGSERVICE_DATACHAR2UUID_LEN] = {0}; uint8_t EcgService_EcgService_DataCharUUIDVal[ECGSERVICE_ECGSERVICE_DATACHARUUID_LEN] = {0XAA, 0xBB, 0x00, 0x00, 0x00,0X00, 0x00, 0x00, 0x00, 0x00}; #define ADC_ecg IOID_8 //IO_pin-5 #define ADC_X Board_X //IO_pin-8 #define ADC_Y Board_X //IO_pin-9 #define ADC_Z Board_X //IO_pin-0 // Define names for Lead-Off Detection (LO+, LO-) #define LO1 IOID_1 //IO_pin-6 #define LO2 IOID_2 //IO_pin-7 unsigned int state1, state2; uint16_t adcValue0[10] = { NULL }; uint32_t adcValue0MicroVolt; uint16_t batteryValue; uint16_t read_batteryValue; uint8_t battery_percent; uint16_t xValue; uint16_t yValue; uint16_t zValue; uint16_t MPUValue[] = { 1, 2, 3, 4, 5, 6 }; uint16_t noData[10] = { 0 }; // Display Interface Display_Handle dispHandle = NULL; ADC_Handle adc; ADC_Params params; /********************************************************************* * LOCAL VARIABLES */ // Entity ID globally used to check for source and/or destination of messages static ICall_EntityID selfEntity; // Event globally used to post local events and pend on system and // local events. static ICall_SyncHandle syncEvent; // Clock instances for internal periodic events. static Clock_Struct periodicClock; // Queue object used for app messages static Queue_Struct appMsg; static Queue_Handle appMsgQueue; // Task configuration Task_Struct task1Struct, task2Struct; Char task1Stack[TASK1STACKSIZE], task2Stack[TASK2STACKSIZE]; Task_Handle benchmarkHandle, task1Handle; Task_Params taskParams; // Scan response data (max size = 31 bytes) static uint8_t scanRspData[] = { // complete name 0x0C, // length of this data GAP_ADTYPE_LOCAL_NAME_COMPLETE, 'H', 'O', 'P', 'S', '_', 'C', 'A', 'R', 'D', 'I', 'O', // connection interval range 0x05, // length of this data GAP_ADTYPE_SLAVE_CONN_INTERVAL_RANGE, LO_UINT16(DEFAULT_DESIRED_MIN_CONN_INTERVAL), // 100ms HI_UINT16(DEFAULT_DESIRED_MIN_CONN_INTERVAL), LO_UINT16(DEFAULT_DESIRED_MAX_CONN_INTERVAL), // 1s HI_UINT16(DEFAULT_DESIRED_MAX_CONN_INTERVAL), // Tx power level 0x02, // length of this data GAP_ADTYPE_POWER_LEVEL, 0 // 0dBm }; // Advertisement data (max size = 31 bytes, though this is // best kept short to conserve power while advertising) static uint8_t advertData[] = { // Flags: this field sets the device to use general discoverable // mode (advertises indefinitely) instead of general // discoverable mode (advertise for 30 seconds at a time) 0x02, // length of this data GAP_ADTYPE_FLAGS, DEFAULT_DISCOVERABLE_MODE | GAP_ADTYPE_FLAGS_BREDR_NOT_SUPPORTED, // service UUID, to notify central devices what services are included // in this peripheral 0x01, // length of this data GAP_ADTYPE_16BIT_MORE, // some of the UUID's, but not all // LO_UINT16(SIMPLEPROFILE_SERV_UUID), // HI_UINT16(SIMPLEPROFILE_SERV_UUID) }; // GAP GATT Attributes static uint8_t attDeviceName[GAP_DEVICE_NAME_LEN] = "Hops Cardio"; /********************************************************************* * LOCAL FUNCTIONS */ static void SimplePeripheral_init( void ); static void SimplePeripheral_taskFxn(UArg a0, UArg a1); static uint8_t SimplePeripheral_processStackMsg(ICall_Hdr *pMsg); static uint8_t SimplePeripheral_processGATTMsg(gattMsgEvent_t *pMsg); static void SimplePeripheral_processAppMsg(sbpEvt_t *pMsg); static void SimplePeripheral_processStateChangeEvt(gaprole_States_t newState); static void SimplePeripheral_processCharValueChangeEvt(uint8_t paramID); static void SimplePeripheral_performPeriodicTask(void); static void SimplePeripheral_performPeriodicTask1(void); static void SimplePeripheral_clockHandler(UArg arg); static void SimplePeripheral_passcodeCB(uint8_t *deviceAddr, uint16_t connHandle, uint8_t uiInputs, uint8_t uiOutputs, uint32_t numComparison); static void SimplePeripheral_pairStateCB(uint16_t connHandle, uint8_t state, uint8_t status); static void SimplePeripheral_processPairState(uint8_t state, uint8_t status); static void SimplePeripheral_processPasscode(uint8_t uiOutputs); static void SimplePeripheral_stateChangeCB(gaprole_States_t newState); static uint8_t SimplePeripheral_enqueueMsg(uint8_t event, uint8_t state, uint8_t *pData); static void SimplePeripheral_connEvtCB(Gap_ConnEventRpt_t *pReport); static void SimplePeripheral_processConnEvt(Gap_ConnEventRpt_t *pReport); void SimpleEcg_read(); double map(double v, float x_min, float x_max, float y_min, float y_max); /********************************************************************* * EXTERN FUNCTIONS */ extern void AssertHandler(uint8 assertCause, uint8 assertSubcause); /********************************************************************* * PROFILE CALLBACKS */ // Peripheral GAPRole Callbacks static gapRolesCBs_t SimplePeripheral_gapRoleCBs = { SimplePeripheral_stateChangeCB // GAPRole State Change Callbacks }; // GAP Bond Manager Callbacks // These are set to NULL since they are not needed. The application // is set up to only perform justworks pairing. static gapBondCBs_t simplePeripheral_BondMgrCBs = { SimplePeripheral_passcodeCB, // Passcode callback SimplePeripheral_pairStateCB // Pairing / Bonding state Callback }; /********************************************************************* * The following typedef and global handle the registration to connection event */ typedef enum { NOT_REGISTER = 0, FOR_AOA_SCAN = 1, FOR_ATT_RSP = 2, FOR_AOA_SEND = 4, FOR_TOF_SEND = 8 }connectionEventRegisterCause_u; // Handle the registration and un-registration for the connection event, since only one can be registered. uint32_t connectionEventRegisterCauseBitMap = NOT_REGISTER; //see connectionEventRegisterCause_u /********************************************************************* * @fn SimplePeripheral_RegistertToAllConnectionEvent() * * @brief register to receive connection events for all the connection * * @param connectionEventRegisterCause represents the reason for registration * * @return @ref SUCCESS * */ bStatus_t SimplePeripheral_RegistertToAllConnectionEvent (connectionEventRegisterCause_u connectionEventRegisterCause) { bStatus_t status = SUCCESS; // in case there is no registration for the connection event, make the registration if (!CONNECTION_EVENT_IS_REGISTERED) { status = GAP_RegisterConnEventCb(SimplePeripheral_connEvtCB, GAP_CB_REGISTER, LINKDB_CONNHANDLE_ALL); } if(status == SUCCESS) { //add the reason bit to the bitamap. CONNECTION_EVENT_REGISTER_BIT_SET(connectionEventRegisterCause); } return(status); } /********************************************************************* * @fn SimplePeripheral_UnRegistertToAllConnectionEvent() * * @brief Unregister connection events * * @param connectionEventRegisterCause represents the reason for registration * * @return @ref SUCCESS * */ bStatus_t SimplePeripheral_UnRegistertToAllConnectionEvent (connectionEventRegisterCause_u connectionEventRegisterCause) { bStatus_t status = SUCCESS; CONNECTION_EVENT_REGISTER_BIT_REMOVE(connectionEventRegisterCause); // in case there is no more registration for the connection event than unregister if (!CONNECTION_EVENT_IS_REGISTERED) { GAP_RegisterConnEventCb(SimplePeripheral_connEvtCB, GAP_CB_UNREGISTER, LINKDB_CONNHANDLE_ALL); } return(status); } /********************************************************************* * @fn SimplePeripheral_createTask * * @brief Task creation function for the Simple Peripheral. * * @param None. * * @return None. */ void SimplePeripheral_createTask(void) { // Configure task Task_Params_init(&taskParams); taskParams.stackSize = TASK1STACKSIZE; taskParams.priority = 1; taskParams.stack = &task1Stack; Task_construct(&task1Struct, (Task_FuncPtr)SimplePeripheral_taskFxn, &taskParams, NULL); task1Handle = Task_handle(&task1Struct); // Task_Params_init(&taskParams); // taskParams.stackSize = TASK2STACKSIZE; // taskParams.stack = &task2Stack; // Task_construct(&task2Struct, (Task_FuncPtr)SimplePeripheral_performPeriodicTask1, // &taskParams, NULL); // // benchmarkHandle = Task_handle(&task2Struct); BIOS_start(); } /********************************************************************* * @fn SimplePeripheral_init * * @brief Called during initialization and contains application * specific initialization (ie. hardware initialization/setup, * table initialization, power up notification, etc), and * profile initialization/setup. * * @param None. * * @return None. */ static void SimplePeripheral_init(void) { // ****************************************************************** // N0 STACK API CALLS CAN OCCUR BEFORE THIS CALL TO ICall_registerApp // ****************************************************************** // Register the current thread as an ICall dispatcher application // so that the application can send and receive messages. ICall_registerApp(&selfEntity, &syncEvent); // Create an RTOS queue for message from profile to be sent to app. appMsgQueue = Util_constructQueue(&appMsg); // appMsgQueue1 = Util_constructQueue(&appMsg); // Create one-shot clocks for internal periodic events. Util_constructClock(&periodicClock, SimplePeripheral_clockHandler, SBP_PERIODIC_EVT_PERIOD, 0, false, SBP_ALL_EVENTS); dispHandle = Display_open(SBP_DISPLAY_TYPE, NULL); GAP_SetParamValue(TGAP_CONN_PAUSE_PERIPHERAL, DEFAULT_CONN_PAUSE_PERIPHERAL); { uint16_t advertOffTime = 0; uint8_t enableUpdateRequest = DEFAULT_ENABLE_UPDATE_REQUEST; uint16_t desiredMinInterval = DEFAULT_DESIRED_MIN_CONN_INTERVAL; uint16_t desiredMaxInterval = DEFAULT_DESIRED_MAX_CONN_INTERVAL; uint16_t desiredSlaveLatency = DEFAULT_DESIRED_SLAVE_LATENCY; uint16_t desiredConnTimeout = DEFAULT_DESIRED_CONN_TIMEOUT; GAPRole_SetParameter(GAPROLE_ADVERT_OFF_TIME, sizeof(uint16_t), &advertOffTime); GAPRole_SetParameter(GAPROLE_SCAN_RSP_DATA, sizeof(scanRspData), scanRspData); GAPRole_SetParameter(GAPROLE_ADVERT_DATA, sizeof(advertData), advertData); GAPRole_SetParameter(GAPROLE_PARAM_UPDATE_ENABLE, sizeof(uint8_t), &enableUpdateRequest); GAPRole_SetParameter(GAPROLE_MIN_CONN_INTERVAL, sizeof(uint16_t), &desiredMinInterval); GAPRole_SetParameter(GAPROLE_MAX_CONN_INTERVAL, sizeof(uint16_t), &desiredMaxInterval); GAPRole_SetParameter(GAPROLE_SLAVE_LATENCY, sizeof(uint16_t), &desiredSlaveLatency); GAPRole_SetParameter(GAPROLE_TIMEOUT_MULTIPLIER, sizeof(uint16_t), &desiredConnTimeout); } GGS_SetParameter(GGS_DEVICE_NAME_ATT, GAP_DEVICE_NAME_LEN, attDeviceName); { uint16_t advInt = DEFAULT_ADVERTISING_INTERVAL; GAP_SetParamValue(TGAP_LIM_DISC_ADV_INT_MIN, advInt); GAP_SetParamValue(TGAP_LIM_DISC_ADV_INT_MAX, advInt); GAP_SetParamValue(TGAP_GEN_DISC_ADV_INT_MIN, advInt); GAP_SetParamValue(TGAP_GEN_DISC_ADV_INT_MAX, advInt); } { uint8_t pairMode = GAPBOND_PAIRING_MODE_WAIT_FOR_REQ; uint8_t mitm = TRUE; uint8_t ioCap = GAPBOND_IO_CAP_DISPLAY_ONLY; uint8_t bonding = TRUE; uint8_t replaceBonds = FALSE; GAPBondMgr_SetParameter(GAPBOND_PAIRING_MODE, sizeof(uint8_t), &pairMode); GAPBondMgr_SetParameter(GAPBOND_MITM_PROTECTION, sizeof(uint8_t), &mitm); GAPBondMgr_SetParameter(GAPBOND_IO_CAPABILITIES, sizeof(uint8_t), &ioCap); GAPBondMgr_SetParameter(GAPBOND_BONDING_ENABLED, sizeof(uint8_t), &bonding); GAPBondMgr_SetParameter(GAPBOND_LRU_BOND_REPLACEMENT, sizeof(uint8_t), &replaceBonds); } // Initialize GATT attributes GGS_AddService(GATT_ALL_SERVICES); // GAP GATT Service GATTServApp_AddService(GATT_ALL_SERVICES); // GATT Service DevInfo_AddService(); // Device Information Service EcgService_AddService( selfEntity ); // Initalization of characteristics in EcgService that are readable. EcgService_SetParameter(ECGSERVICE_ECGSERVICE_DATACHARUUID_ID, ECGSERVICE_ECGSERVICE_DATACHARUUID_LEN, EcgService_EcgService_DataCharUUIDVal); EcgService_SetParameter(ECGSERVICE_ECGSERVICE_DATACHAR1UUID_ID, ECGSERVICE_ECGSERVICE_DATACHAR1UUID_LEN, EcgService_EcgService_DataChar1UUIDVal); EcgService_SetParameter(ECGSERVICE_ECGSERVICE_DATACHAR2UUID_ID, ECGSERVICE_ECGSERVICE_DATACHAR2UUID_LEN, EcgService_EcgService_DataChar2UUIDVal); VOID GAPRole_StartDevice(&SimplePeripheral_gapRoleCBs); // Start Bond Manager and register callback VOID GAPBondMgr_Register(&simplePeripheral_BondMgrCBs); // Register with GAP for HCI/Host messages. This is needed to receive HCI // events. For more information, see the section in the User's Guide: // http://software-dl.ti.com/lprf/sdg-latest/html GAP_RegisterForMsgs(selfEntity); // Register for GATT local events and ATT Responses pending for transmission GATT_RegisterForMsgs(selfEntity); //Set default values for Data Length Extension { //Set initial values to maximum, RX is set to max. by default(251 octets, 2120us) #define APP_SUGGESTED_PDU_SIZE 251 //default is 27 octets(TX) #define APP_SUGGESTED_TX_TIME 2120 //default is 328us(TX) //This API is documented in hci.h //See the LE Data Length Extension section in the BLE-Stack User's Guide for information on using this command: //http://software-dl.ti.com/lprf/sdg-latest/html/cc2640/index.html //HCI_LE_WriteSuggestedDefaultDataLenCmd(APP_SUGGESTED_PDU_SIZE, APP_SUGGESTED_TX_TIME); } #if !defined (USE_LL_CONN_PARAM_UPDATE) // Get the currently set local supported LE features // The HCI will generate an HCI event that will get received in the main // loop HCI_LE_ReadLocalSupportedFeaturesCmd(); #endif // !defined (USE_LL_CONN_PARAM_UPDATE) Display_print0(dispHandle, 0, 0, "BLE Peripheral"); } /********************************************************************* * @fn SimplePeripheral_taskFxn * * @brief Application task entry point for the Simple Peripheral. * * @param a0, a1 - not used. * * @return None. */ static void SimplePeripheral_taskFxn(UArg a0, UArg a1) { SimplePeripheral_init(); HCI_EXT_SetTxPowerCmd(0x0C); // Application main loop for (;;) { uint32_t events; events = Event_pend(syncEvent, Event_Id_NONE, SBP_ALL_EVENTS,ICALL_TIMEOUT_FOREVER); if (events) { ICall_EntityID dest; ICall_ServiceEnum src; ICall_HciExtEvt *pMsg = NULL; // Fetch any available messages that might have been sent from the stack if (ICall_fetchServiceMsg(&src, &dest, (void **)&pMsg) == ICALL_ERRNO_SUCCESS) { uint8 safeToDealloc = TRUE; if ((src == ICALL_SERVICE_CLASS_BLE) && (dest == selfEntity)) { ICall_Stack_Event *pEvt = (ICall_Stack_Event *)pMsg; if (pEvt->signature != 0xffff) { // Process inter-task message safeToDealloc = SimplePeripheral_processStackMsg((ICall_Hdr *)pMsg); } } if (pMsg && safeToDealloc) { ICall_freeMsg(pMsg); } } // If RTOS queue is not empty, process app message. if (events & SBP_QUEUE_EVT) { while (!Queue_empty(appMsgQueue)) { sbpEvt_t *pMsg = (sbpEvt_t *)Util_dequeueMsg(appMsgQueue); if (pMsg) { // Process message. SimplePeripheral_processAppMsg(pMsg); // Free the space from the message. ICall_free(pMsg); } } } if (events & SBP_PERIODIC_EVT) { Util_startClock(&periodicClock); SimplePeripheral_performPeriodicTask(); } if(event1 & SBP_PERIODIC_EVT1) { SimplePeripheral_performPeriodicTask1(); } } } } static uint8_t SimplePeripheral_processStackMsg(ICall_Hdr *pMsg) { uint8_t safeToDealloc = TRUE; switch (pMsg->event) { case GATT_MSG_EVENT: // Process GATT message safeToDealloc = SimplePeripheral_processGATTMsg((gattMsgEvent_t *)pMsg); break; case HCI_GAP_EVENT_EVENT: { // Process HCI message switch(pMsg->status) { case HCI_COMMAND_COMPLETE_EVENT_CODE: // Process HCI Command Complete Event { #if !defined (USE_LL_CONN_PARAM_UPDATE) // This code will disable the use of the LL_CONNECTION_PARAM_REQ // control procedure (for connection parameter updates, the // L2CAP Connection Parameter Update procedure will be used // instead). To re-enable the LL_CONNECTION_PARAM_REQ control // procedures, define the symbol USE_LL_CONN_PARAM_UPDATE // The L2CAP Connection Parameter Update procedure is used to // support a delta between the minimum and maximum connection // intervals required by some iOS devices. // Parse Command Complete Event for opcode and status hciEvt_CmdComplete_t* command_complete = (hciEvt_CmdComplete_t*) pMsg; uint8_t pktStatus = command_complete->pReturnParam[0]; //find which command this command complete is for switch (command_complete->cmdOpcode) { case HCI_LE_READ_LOCAL_SUPPORTED_FEATURES: { if (pktStatus == SUCCESS) { uint8_t featSet[8]; // Get current feature set from received event (bits 1-9 // of the returned data memcpy( featSet, &command_complete->pReturnParam[1], 8 ); // Clear bit 1 of byte 0 of feature set to disable LL // Connection Parameter Updates CLR_FEATURE_FLAG( featSet[0], LL_FEATURE_CONN_PARAMS_REQ ); // Update controller with modified features HCI_EXT_SetLocalSupportedFeaturesCmd( featSet ); } } break; default: //do nothing break; } #endif // !defined (USE_LL_CONN_PARAM_UPDATE) } break; case HCI_BLE_HARDWARE_ERROR_EVENT_CODE: AssertHandler(HAL_ASSERT_CAUSE_HARDWARE_ERROR,0); break; default: break; } } break; default: // do nothing break; } return (safeToDealloc); } /********************************************************************* * @fn SimplePeripheral_processGATTMsg * * @brief Process GATT messages and events. * * @return TRUE if safe to deallocate incoming message, FALSE otherwise. */ static uint8_t SimplePeripheral_processGATTMsg(gattMsgEvent_t *pMsg) { // See if GATT server was unable to transmit an ATT response if (attRsp_isAttRsp(pMsg)) { // No HCI buffer was available. Let's try to retransmit the response // on the next connection event. if( SimplePeripheral_RegistertToAllConnectionEvent(FOR_ATT_RSP) == SUCCESS) { // Don't free the response message yet return (FALSE); } } else if (pMsg->method == ATT_FLOW_CTRL_VIOLATED_EVENT) { // ATT request-response or indication-confirmation flow control is // violated. All subsequent ATT requests or indications will be dropped. // The app is informed in case it wants to drop the connection. // Display the opcode of the message that caused the violation. Display_print1(dispHandle, 5, 0, "FC Violated: %d", pMsg->msg.flowCtrlEvt.opcode); } else if (pMsg->method == ATT_MTU_UPDATED_EVENT) { // MTU size updated Display_print1(dispHandle, 5, 0, "MTU Size: %d", pMsg->msg.mtuEvt.MTU); } // Free message payload. Needed only for ATT Protocol messages GATT_bm_free(&pMsg->msg, pMsg->method); // It's safe to free the incoming message return (TRUE); } /********************************************************************* * @fn SimplePeripheral_processConnEvt * * @brief Process connection event. * * @param pReport pointer to connection event report */ static void SimplePeripheral_processConnEvt(Gap_ConnEventRpt_t *pReport) { if( CONNECTION_EVENT_REGISTRATION_CAUSE(FOR_ATT_RSP)) { // The GATT server might have returned a blePending as it was trying // to process an ATT Response. Now that we finished with this // connection event, let's try sending any remaining ATT Responses // on the next connection event. // Try to retransmit pending ATT Response (if any) if (attRsp_sendAttRsp() == SUCCESS) { // Disable connection event end notice SimplePeripheral_UnRegistertToAllConnectionEvent (FOR_ATT_RSP); } } } /********************************************************************* * @fn SimplePeripheral_processAppMsg * * @brief Process an incoming callback from a profile. * * @param pMsg - message to process * * @return None. */ static void SimplePeripheral_processAppMsg(sbpEvt_t *pMsg) { switch (pMsg->hdr.event) { case SBP_STATE_CHANGE_EVT: { SimplePeripheral_processStateChangeEvt((gaprole_States_t)pMsg-> hdr.state); } break; case SBP_CHAR_CHANGE_EVT: { SimplePeripheral_processCharValueChangeEvt(pMsg->hdr.state); } break; // Pairing event case SBP_PAIRING_STATE_EVT: { SimplePeripheral_processPairState(pMsg->hdr.state, *pMsg->pData); ICall_free(pMsg->pData); break; } // Passcode event case SBP_PASSCODE_NEEDED_EVT: { SimplePeripheral_processPasscode(*pMsg->pData); ICall_free(pMsg->pData); break; } case SBP_CONN_EVT: { SimplePeripheral_processConnEvt((Gap_ConnEventRpt_t *)(pMsg->pData)); ICall_free(pMsg->pData); break; } default: // Do nothing. break; } } /********************************************************************* * @fn SimplePeripheral_stateChangeCB * * @brief Callback from GAP Role indicating a role state change. * * @param newState - new state * * @return None. */ static void SimplePeripheral_stateChangeCB(gaprole_States_t newState) { SimplePeripheral_enqueueMsg(SBP_STATE_CHANGE_EVT, newState, NULL); } /********************************************************************* * @fn SimplePeripheral_processStateChangeEvt * * @brief Process a pending GAP Role state change event. * * @param newState - new state * * @return None. */ static void SimplePeripheral_processStateChangeEvt(gaprole_States_t newState) { switch ( newState ) { case GAPROLE_STARTED: { uint8_t ownAddress[B_ADDR_LEN]; uint8_t systemId[DEVINFO_SYSTEM_ID_LEN]; GAPRole_GetParameter(GAPROLE_BD_ADDR, ownAddress); // use 6 bytes of device address for 8 bytes of system ID value systemId[0] = ownAddress[0]; systemId[1] = ownAddress[1]; systemId[2] = ownAddress[2]; // set middle bytes to zero systemId[4] = 0x00; systemId[3] = 0x00; // shift three bytes up systemId[7] = ownAddress[5]; systemId[6] = ownAddress[4]; systemId[5] = ownAddress[3]; DevInfo_SetParameter(DEVINFO_SYSTEM_ID, DEVINFO_SYSTEM_ID_LEN, systemId); // Display device address Display_print0(dispHandle, 1, 0, Util_convertBdAddr2Str(ownAddress)); Display_print0(dispHandle, 2, 0, "Initialized"); // Device starts advertising upon initialization of GAP uint8_t initialAdvertEnable = TRUE; // Set the Peripheral GAPRole Parameters GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8_t), &initialAdvertEnable); } break; case GAPROLE_ADVERTISING: Display_print0(dispHandle, 2, 0, "Advertising"); break; case GAPROLE_CONNECTED: { linkDBInfo_t linkInfo; uint8_t numActive = 0; Util_startClock(&periodicClock); numActive = linkDB_NumActive(); // Use numActive to determine the connection handle of the last // connection if ( linkDB_GetInfo( numActive - 1, &linkInfo ) == SUCCESS ) { Display_print1(dispHandle, 2, 0, "Num Conns: %d", (uint16_t)numActive); Display_print0(dispHandle, 3, 0, Util_convertBdAddr2Str(linkInfo.addr)); } else { uint8_t peerAddress[B_ADDR_LEN]; GAPRole_GetParameter(GAPROLE_CONN_BD_ADDR, peerAddress); Display_print0(dispHandle, 2, 0, "Connected"); Display_print0(dispHandle, 3, 0, Util_convertBdAddr2Str(peerAddress)); } } break; case GAPROLE_CONNECTED_ADV: Display_print0(dispHandle, 2, 0, "Connected Advertising"); break; case GAPROLE_WAITING: { uint8_t advertReEnable = TRUE; Util_stopClock(&periodicClock); attRsp_freeAttRsp(bleNotConnected); // Clear remaining lines Display_clearLines(dispHandle, 3, 5); GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8_t), &advertReEnable); Display_print0(dispHandle, 2, 0, "Advertising"); } break; case GAPROLE_WAITING_AFTER_TIMEOUT: attRsp_freeAttRsp(bleNotConnected); Display_print0(dispHandle, 2, 0, "Timed Out"); // Clear remaining lines Display_clearLines(dispHandle, 3, 5); break; case GAPROLE_ERROR: Display_print0(dispHandle, 2, 0, "Error"); break; default: Display_clearLine(dispHandle, 2); break; } } /********************************************************************* * @fn SimplePeripheral_processCharValueChangeEvt * * @brief Process a pending Simple Profile characteristic value change * event. * * @param paramID - parameter ID of the value that was changed. * * @return None. */ static void SimplePeripheral_processCharValueChangeEvt(uint8_t paramID) { switch(paramID) { default: // should not reach here! break; } } //ECG, Battery, Position data collection Function void SimpleEcg_read() { //Battery Service (No IO_pin needed) // enable battery monitor enable AONBatMonEnable(); //Get battery voltage (this will return battery voltage in decimal form you need to convert) read_batteryValue = (AONBatMonBatteryVoltageGet() * 125) >> 5; //convert in floating point value batteryValue = (float) read_batteryValue; //convert in batteryValue to battery_percent battery_percent = map(batteryValue,2700,3800,0,100); EcgService_SetParameter(ECGSERVICE_ECGSERVICE_DATACHAR1UUID_ID, ECGSERVICE_ECGSERVICE_DATACHAR1UUID_LEN, &battery_percent); //ADXL335 Position (IO_pin-8,9,0) /* ADC_Params_init(¶msx); adcx = ADC_open(ADC_X, ¶msx); ADC_convert(adcx, &xValue); ADC_close(adcx); ADC_Params_init(¶msy); adcy = ADC_open(ADC_Y, ¶msy); ADC_convert(adcy, &yValue); ADC_close(adcy); ADC_Params_init(¶msz); adcz = ADC_open(ADC_Z, ¶msz); ADC_convert(adcz, &zValue); ADC_close(adcz); if (zValue >= 1700 || zValue <= 1300) { // Display_printf(display, 0, 0, "Laydown"); EcgService_SetParameter(ECGSERVICE_DATACHAR2_ID, ECGSERVICE_DATACHAR2_LEN, &MPUValue[1]); } else if (xValue >= 1700 || xValue <= 1300) { // Display_printf(display, 0, 0, "Stand"); EcgService_SetParameter(ECGSERVICE_DATACHAR2_ID, ECGSERVICE_DATACHAR2_LEN, &MPUValue[0]); } else if (yValue >= 1600) { // Display_printf(display, 0, 0, "Right"); EcgService_SetParameter(ECGSERVICE_DATACHAR2_ID, ECGSERVICE_DATACHAR2_LEN, &MPUValue[2]); } else if (yValue <= 1300) { //Display_printf(display, 0, 0, "Left"); EcgService_SetParameter(ECGSERVICE_DATACHAR2_ID, ECGSERVICE_DATACHAR2_LEN, &MPUValue[3]); } */ } //Battery Mapping Function double map(double v, float x_min, float x_max, float y_min, float y_max) { float m = 0.0; m = ((y_max - y_min) / (x_max - x_min)); return (y_min + (m * (v - x_min))); } static void SimplePeripheral_performPeriodicTask(void) { ADC_init(); GPIO_init(); while(1){ state1 = GPIO_read(LO1); state2 = GPIO_read(LO2); ADC_Params_init(¶ms); // adc = ADC_open(ADC_ecg, ¶ms); adc = ADC_open(0, ¶ms); ADC_convert(adc, &adcValue0[0]); ADC_convert(adc, &adcValue0[1]); ADC_convert(adc, &adcValue0[2]); ADC_convert(adc, &adcValue0[3]); ADC_convert(adc, &adcValue0[4]); ADC_convert(adc, &adcValue0[5]); ADC_convert(adc, &adcValue0[6]); ADC_convert(adc, &adcValue0[7]); ADC_convert(adc, &adcValue0[8]); ADC_convert(adc, &adcValue0[9]); ADC_close(adc); if ((state1 == 1) || (state2 == 1)) { EcgService_SetParameter(ECGSERVICE_ECGSERVICE_DATACHARUUID_ID, ECGSERVICE_ECGSERVICE_DATACHARUUID_LEN, &adcValue0); } else { EcgService_SetParameter(ECGSERVICE_ECGSERVICE_DATACHARUUID_ID, ECGSERVICE_ECGSERVICE_DATACHARUUID_LEN, &adcValue0[0]); } // AONBatMonEnable(); // //Get battery voltage (this will return battery voltage in decimal form you need to convert) // read_batteryValue = (AONBatMonBatteryVoltageGet() * 125) >> 5; // //convert in floating point valu // batteryValue = (float) read_batteryValue; // //convert in batteryValue to battery_percent // battery_percent = map(batteryValue,2700,3800,0,100); // EcgService_SetParameter(ECGSERVICE_ECGSERVICE_DATACHAR1UUID_ID, ECGSERVICE_ECGSERVICE_DATACHAR1UUID_LEN, &battery_percent); } } static void SimplePeripheral_performPeriodicTask1(void) { while(1){ AONBatMonEnable(); //Get battery voltage (this will return battery voltage in decimal form you need to convert) read_batteryValue = (AONBatMonBatteryVoltageGet() * 125) >> 5; //convert in floating point valu batteryValue = (float) read_batteryValue; //convert in batteryValue to battery_percent battery_percent = map(batteryValue,2700,3800,0,100); EcgService_SetParameter(ECGSERVICE_ECGSERVICE_DATACHAR1UUID_ID, ECGSERVICE_ECGSERVICE_DATACHAR1UUID_LEN, &battery_percent); } } /********************************************************************* * @fn SimplePeripheral_pairStateCB * * @brief Pairing state callback. * * @return none */ static void SimplePeripheral_pairStateCB(uint16_t connHandle, uint8_t state, uint8_t status) { uint8_t *pData; // Allocate space for the event data. if ((pData = ICall_malloc(sizeof(uint8_t)))) { *pData = status; // Queue the event. SimplePeripheral_enqueueMsg(SBP_PAIRING_STATE_EVT, state, pData); } } /********************************************************************* * @fn SimplePeripheral_processPairState * * @brief Process the new paring state. * * @return none */ static void SimplePeripheral_processPairState(uint8_t state, uint8_t status) { if (state == GAPBOND_PAIRING_STATE_STARTED) { Display_print0(dispHandle, 2, 0, "Pairing started"); } else if (state == GAPBOND_PAIRING_STATE_COMPLETE) { if (status == SUCCESS) { Display_print0(dispHandle, 2, 0, "Pairing success"); } else { Display_print1(dispHandle, 2, 0, "Pairing fail: %d", status); } } else if (state == GAPBOND_PAIRING_STATE_BONDED) { if (status == SUCCESS) { Display_print0(dispHandle, 2, 0, "Bonding success"); } } else if (state == GAPBOND_PAIRING_STATE_BOND_SAVED) { if (status == SUCCESS) { Display_print0(dispHandle, 2, 0, "Bond save success"); } else { Display_print1(dispHandle, 2, 0, "Bond save failed: %d", status); } } } /********************************************************************* * @fn SimplePeripheral_passcodeCB * * @brief Passcode callback. * * @return none */ static void SimplePeripheral_passcodeCB(uint8_t *deviceAddr, uint16_t connHandle, uint8_t uiInputs, uint8_t uiOutputs, uint32_t numComparison) { uint8_t *pData; // Allocate space for the passcode event. if ((pData = ICall_malloc(sizeof(uint8_t)))) { *pData = uiOutputs; // Enqueue the event. SimplePeripheral_enqueueMsg(SBP_PASSCODE_NEEDED_EVT, 0, pData); } } /********************************************************************* * @fn SimplePeripheral_processPasscode * * @brief Process the Passcode request. * * @return none */ static void SimplePeripheral_processPasscode(uint8_t uiOutputs) { // This app uses a default passcode. A real-life scenario would handle all // pairing scenarios and likely generate this randomly. uint32_t passcode = B_APP_DEFAULT_PASSCODE; // Display passcode to user if (uiOutputs != 0) { Display_print1(dispHandle, 4, 0, "Passcode: %d", passcode); } uint16_t connectionHandle; GAPRole_GetParameter(GAPROLE_CONNHANDLE, &connectionHandle); // Send passcode response GAPBondMgr_PasscodeRsp(connectionHandle, SUCCESS, passcode); } /********************************************************************* * @fn SimplePeripheral_clockHandler * * @brief Handler function for clock timeouts. * * @param arg - event type * * @return None. */ static void SimplePeripheral_clockHandler(UArg arg) { // Wake up the application. Event_post(syncEvent, arg); } /********************************************************************* * @fn SimplePeripheral_connEvtCB * * @brief Connection event callback. * * @param pReport pointer to connection event report */ static void SimplePeripheral_connEvtCB(Gap_ConnEventRpt_t *pReport) { // Enqueue the event for processing in the app context. if( SimplePeripheral_enqueueMsg(SBP_CONN_EVT, 0 ,(uint8_t *) pReport) == FALSE) { ICall_free(pReport); } } /********************************************************************* * * @brief Creates a message and puts the message in RTOS queue. * * @param event - message event. * @param state - message state. * @param pData - message data pointer. * * @return TRUE or FALSE */ static uint8_t SimplePeripheral_enqueueMsg(uint8_t event, uint8_t state, uint8_t *pData) { sbpEvt_t *pMsg = ICall_malloc(sizeof(sbpEvt_t)); // Create dynamic pointer to message. if (pMsg) { pMsg->hdr.event = event; pMsg->hdr.state = state; pMsg->pData = pData; // Enqueue the message. return Util_enqueueMsg(appMsgQueue, syncEvent, (uint8_t *)pMsg); // SimplePeripheral_enqueueMsg(SBP_STATE_CHANGE_EVT, newState, NULL); } return FALSE; } /********************************************************************* *********************************************************************/