咨询如何关于CC2541从机向主机发送多数据(数组)s
各位专家好:
TI的simpleBLEPeripheral的代码或其他项目中,每次发送的数据量都比较小,一般都是8bits 或16bits。我这里的需求是从机每2ms采样向主机发送16bit的数据,也就是1秒钟发送500次的16bit, 如果每2ms调用GATT_Notification,那么每次的开销比较大,测试发现会把主机搞死。我想能否把100次的数据合并成1600bits的数据发往主机,这样可以减少发送量,请问如果可性的话,代码应该如何修改?谢谢。
MINGJIAN,
BLE空中的数据包内容长度最长是一个包20字节,就是20x8=160bits。
这个只需要你稍微修改一下程序就能达到。TI的示例只是用1个字节做例子而已。比如simpleBLEPeripheral中的characteristic 4 就是notification属性,你把这个改成一个20字节的数组:static uint8 simpleProfileChar4 = 0; , 在simpleProfile_ReadAttrCB() 里面*pLen = 1; 改成20,然后编译不过的地方相应修改一下即可。
1)蓝牙最小连接时间为6ms,也就是说,你需要把数据收集起来,然后集中发送
2)蓝牙每帧允许20字节,也就是160bit,你的总发送数据量为 50*160bit;所以可以20ms发送一次数据就好了
3)参考例子就是基本的SimplePeripheral从机例子,将长度设置20字节,触发时间设置20ms
也可以参考这个例子
http://processors.wiki.ti.com/index.php/SerialBLEbridge_V_1.4.1
hi Y,
我用的是cc2640,用SPPBLEServer工程做串口透传,现在手机端发往pc端发数据一次只能发20个字节,是程序里面限制了么?我应该如何修改程序,让它一个时间间隔内发多个字节呢?下面是spp_ble_server.c代码。
/********************************************************************* * INCLUDES */ #include <string.h> #include <xdc/std.h> #include <xdc/runtime/Error.h> #include <xdc/runtime/System.h> #include <ti/sysbios/BIOS.h> #include <ti/sysbios/knl/Task.h> #include <ti/sysbios/knl/Clock.h> #include <ti/sysbios/knl/Semaphore.h> #include <ti/sysbios/knl/Queue.h> #include <ICall.h> #include "gatt.h" #include "hci.h" #include "gapgattserver.h" #include "gattservapp.h" #include "devinfoservice.h" #ifdef FEATURE_OAD #include "oad_target.h" #include "oad.h" #endif #include "peripheral.h" #include "gapbondmgr.h" #include "osal_snv.h" #include "ICallBleAPIMSG.h" #include "util.h" #include "board_lcd.h" #include "board_key.h" #include "Board.h" #include "spp_ble_server.h" #include "SerialPortService.h" #include "inc/sdi_task.h" #include <ti/drivers/lcd/LCDDogm1286.h> #include "inc/sdi_tl_uart.h" /********************************************************************* * CONSTANTS */ // Advertising interval when device is discoverable (units of 625us, 160=100ms) #define DEFAULT_ADVERTISING_INTERVAL 32 //=20ms // Limited discoverable mode advertises for 30.72s, and then stops // General discoverable mode advertises indefinitely #define DEFAULT_DISCOVERABLE_MODE GAP_ADTYPE_FLAGS_GENERAL // Minimum connection interval (units of 1.25ms, 80=100ms) if automatic // parameter update request is enabled #define DEFAULT_DESIRED_MIN_CONN_INTERVAL 16 //16*1.25 = 20ms // Maximum connection interval (units of 1.25ms, 800=1000ms) if automatic // parameter update request is enabled #define DEFAULT_DESIRED_MAX_CONN_INTERVAL 16 // Slave latency to use if automatic parameter update request is enabled #define DEFAULT_DESIRED_SLAVE_LATENCY 0 // Supervision timeout value (units of 10ms, 1000=10s) if automatic parameter // update request is enabled #define DEFAULT_DESIRED_CONN_TIMEOUT 200 //2s // Whether to enable automatic parameter update request when a connection is // formed #define DEFAULT_ENABLE_UPDATE_REQUEST TRUE //FALSE //CONFIG // 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 // How often to perform periodic event (in msec) #define SBP_UART_CONFIG_EVT_PERIOD 1000 // Task configuration #define SBP_TASK_PRIORITY 1 #ifndef SBP_TASK_STACK_SIZE #define SBP_TASK_STACK_SIZE 644 #endif // Internal Events for RTOS application #define SBP_STATE_CHANGE_EVT 0x0001 #define SPB_CHAR_CHANGE_EVT 0x0002 #define SBP_PERIODIC_EVT 0x0004 #define SBP_UART_CONFIG_EVT 0x0010 #ifdef FEATURE_OAD #define SBP_OAD_WRITE_EVT 0x0008 #endif //FEATURE_OAD /********************************************************************* * TYPEDEFS */ // RTOS queue for profile/app messages. typedef struct _queueRec_ { Queue_Elem _elem; // queue element uint8_t *pData; // pointer to app data } queueRec_t; // App event passed from profiles. typedef struct { uint8_t event; // Which profile's event uint8_t status; // New status } sbpEvt_t; // App event passed from profiles. typedef struct { uint8_t event; // Type of event uint8_t data[20]; // New data uint8_t length; // New status } sbpUARTEvt_t; //size = 22 bytes /********************************************************************* * LOCAL VARIABLES */ // Entity ID globally used to check for source and/or destination of messages static ICall_EntityID selfEntity; // Semaphore globally used to post events to the application thread static ICall_Semaphore sem; // Clock instances for internal periodic events. static Clock_Struct periodicClock; static Clock_Struct UARTEventClock; // Queue object used for app messages static Queue_Struct appMsg; static Queue_Handle appMsgQueue; // Queue object used for UART messages static Queue_Struct appUARTMsg; static Queue_Handle appUARTMsgQueue; // events flag for internal application events. static uint16_t events; // Task configuration Task_Struct sbpTask; Char sbpTaskStack[SBP_TASK_STACK_SIZE]; // Profile state and parameters static gaprole_States_t gapProfileState = GAPROLE_INIT; // GAP - SCAN RSP data (max size = 31 bytes) static uint8_t scanRspData[] = { // complete name 0x0F, // length of this data GAP_ADTYPE_LOCAL_NAME_COMPLETE, 'S', 'P', 'P', ' ', 'B', 'L', 'E', ' ', 'S', 'e', 'r', 'v', 'e', 'r', // 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 }; // GAP - Advertisement data (max size = 31 bytes, though this is // best kept short to conserve power while advertisting) static uint8_t advertData[] = { // Flags; this sets the device to use limited discoverable // mode (advertises for 30 seconds at a time) instead of general // discoverable mode (advertises indefinitely) 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 0x03, // length of this data GAP_ADTYPE_16BIT_MORE, // some of the UUID's, but not all #ifdef FEATURE_OAD LO_UINT16(OAD_SERVICE_UUID), HI_UINT16(OAD_SERVICE_UUID) #else LO_UINT16(SERIALPORTSERVICE_SERV_UUID), HI_UINT16(SERIALPORTSERVICE_SERV_UUID) #endif //!FEATURE_OAD }; // GAP GATT Attributes static uint8_t attDeviceName[GAP_DEVICE_NAME_LEN] = "SPP BLE Server"; #if FEATURE_OAD // Event data from OAD profile. static oadTargetWrite_t oadWriteEventData; #endif //FEATURE_OAD /********************************************************************* * LOCAL FUNCTIONS */ static void SPPBLEServer_init( void ); static void SPPBLEServer_taskFxn(UArg a0, UArg a1); static void SPPBLEServer_processStackMsg(ICall_Hdr *pMsg); static void SPPBLEServer_processGATTMsg(gattMsgEvent_t *pMsg); static void SPPBLEServer_processAppMsg(sbpEvt_t *pMsg); static void SPPBLEServer_processStateChangeEvt(gaprole_States_t newState); static void SPPBLEServer_processCharValueChangeEvt(uint8_t paramID); static void SPPBLEServer_performPeriodicTask(void); static void SPPBLEServer_stateChangeCB(gaprole_States_t newState); #ifndef FEATURE_OAD static void SPPBLEServer_charValueChangeCB(uint8_t paramID); #endif //!FEATURE_OAD static void SPPBLEServer_enqueueMsg(uint8_t event, uint8_t status); void SPPBLEServer_enqueueUARTMsg(uint8_t event, uint8_t *data, uint8_t len); #ifdef FEATURE_OAD void SPPBLEServer_processOadWriteCB(uint8_t event, uint16_t connHandle, uint8_t *pData); #endif //FEATURE_OAD static void SPPBLEServer_setEvent(UArg arg); /********************************************************************* * PROFILE CALLBACKS */ // GAP Role Callbacks static gapRolesCBs_t SPPBLEServer_gapRoleCBs = { SPPBLEServer_stateChangeCB, // Profile State Change Callbacks NULL // When a valid RSSI is read from // controller (not used by app) }; // GAP Bond Manager Callbacks static gapBondCBs_t SPPBLEServer_BondMgrCBs = { NULL, // Passcode callback (not used by application) NULL // Pairing / Bonding state Callback (not used by application) }; // SerialPort BLE GATT Profile Callbacks static SerialPortServiceCBs_t SPPBLEServer_SerialPortService_CBs = { SPPBLEServer_charValueChangeCB // Characteristic value change callback }; #ifdef FEATURE_OAD static oadTargetCBs_t SPPBLEServer_oadCBs = { NULL, // Read Callback. Optional. SPPBLEServer_processOadWriteCB // Write Callback. Mandatory. }; #endif //FEATURE_OAD /********************************************************************* * PUBLIC FUNCTIONS */ /********************************************************************* * @fn SPPBLEServer_createTask * * @brief Task creation function for the SPP BLE Server. * * @param None. * * @return None. */ void SPPBLEServer_createTask(void) { Task_Params taskParams; // Configure task Task_Params_init(&taskParams); taskParams.stack = sbpTaskStack; taskParams.stackSize = SBP_TASK_STACK_SIZE; taskParams.priority = SBP_TASK_PRIORITY; Task_construct(&sbpTask, SPPBLEServer_taskFxn, &taskParams, NULL); } /********************************************************************* * @fn SPPBLEServer_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 SPPBLEServer_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, &sem); // Hard code the BD Address till CC2650 board gets its own IEEE address uint8 bdAddress[B_ADDR_LEN] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 }; HCI_EXT_SetBDADDRCmd(bdAddress); // Set device's Sleep Clock Accuracy //HCI_EXT_SetSCACmd(40); // Create an RTOS queue for message from profile to be sent to app. appMsgQueue = Util_constructQueue(&appMsg); appUARTMsgQueue = Util_constructQueue(&appUARTMsg); // Create one-shot clocks for internal periodic events. Util_constructClock(&periodicClock, SPPBLEServer_setEvent, SBP_PERIODIC_EVT_PERIOD, 0, false, SBP_PERIODIC_EVT); Util_constructClock(&UARTEventClock, SPPBLEServer_setEvent, SBP_UART_CONFIG_EVT_PERIOD, 0, false, SBP_UART_CONFIG_EVT); Board_openLCD(); // Setup the GAP GAP_SetParamValue(TGAP_CONN_PAUSE_PERIPHERAL, DEFAULT_CONN_PAUSE_PERIPHERAL); // Setup the GAP Peripheral Role Profile { // For all hardware platforms, device starts advertising upon initialization uint8_t initialAdvertEnable = TRUE; // By setting this to zero, the device will go into the waiting state after // being discoverable for 30.72 second, and will not being advertising again // until the enabler is set back to TRUE 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; // Set the GAP Role Parameters GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8_t), &initialAdvertEnable); 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); } // Set the GAP Characteristics GGS_SetParameter(GGS_DEVICE_NAME_ATT, GAP_DEVICE_NAME_LEN, attDeviceName); // Set advertising interval { 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); } // Setup the GAP Bond Manager { uint32_t passkey = 0; // passkey "000000" 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; GAPBondMgr_SetParameter(GAPBOND_DEFAULT_PASSCODE, sizeof(uint32_t), &passkey); 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); } // Initialize GATT attributes GGS_AddService(GATT_ALL_SERVICES); // GAP GATTServApp_AddService(GATT_ALL_SERVICES); // GATT attributes DevInfo_AddService(); // Device Information Service #ifndef FEATURE_OAD SerialPortService_AddService(GATT_ALL_SERVICES); //SerialPortBLE service #endif //!FEATURE_OAD #ifdef FEATURE_OAD VOID OAD_addService(); // OAD Profile OAD_register((oadTargetCBs_t *)&SPPBLEServer_oadCBs); #endif #ifndef FEATURE_OAD // Register callback with SerialPortService SerialPortService_RegisterAppCBs(&SPPBLEServer_SerialPortService_CBs); #endif //!FEATURE_OAD // Start the Device VOID GAPRole_StartDevice(&SPPBLEServer_gapRoleCBs); // Start Bond Manager VOID GAPBondMgr_Register(&SPPBLEServer_BondMgrCBs); //Initialize UART parameters { //Initialize UART to 115200 8N1 paramsUART.baudRate = 115200; paramsUART.stopBits = UART_STOP_ONE; paramsUART.parityType = UART_PAR_NONE; //set the event to change params Util_startClock(&UARTEventClock); } //Register to receive UART messages SDITask_registerIncomingRXEventAppCB(SPPBLEServer_enqueueUARTMsg); //Register to receive UART error messages SDITLUART_registerIncomingRXErrorStatusAppCB(SPPBLEServer_enqueueUARTMsg); #if defined FEATURE_OAD #if defined (HAL_IMAGE_A) LCD_WRITE_STRING("BLE Peripheral A", LCD_PAGE0); #else LCD_WRITE_STRING("BLE Peripheral B", LCD_PAGE0); #endif // HAL_IMAGE_A #else LCD_WRITE_STRING("SPP BLE Server", LCD_PAGE0); #endif // FEATURE_OAD unsigned char hello[] = "Hello from SPP BLE Server!\n\r"; DEBUG(hello); } /********************************************************************* * @fn getLocalGATThandle * * @brief Get handle for GATT variables. * * @param var - pointer to data variable used in GATT table. * * @return handle. */ static uint16 getLocalGATThandle(void* var) { gattAttribute_t* pAttr; //Alloc array for GATT message pAttr = ICall_malloc(sizeof(gattAttribute_t)); //Get the handle for the data characteristic on local GATT database pAttr = GATTServApp_FindAttr( SerialPortServiceAttrTbl, GATT_NUM_ATTRS( SerialPortServiceAttrTbl ), var ); //LCD_WRITE_STRING_VALUE("SP Data Handle:", ((gattAttribute_t*)pAttr)->handle, 10, LCD_PAGE5); return ((gattAttribute_t*)pAttr)->handle; } /********************************************************************* * @fn SPPBLEServer_taskFxn * * @brief Application task entry point for the SPPBLEServer. * * @param a0, a1 - not used. * * @return None. */ static void SPPBLEServer_taskFxn(UArg a0, UArg a1) { // Initialize application SPPBLEServer_init(); // Application main loop for (;;) { // Waits for a signal to the semaphore associated with the calling thread. // Note that the semaphore associated with a thread is signaled when a // message is queued to the message receive queue of the thread or when // ICall_signal() function is called onto the semaphore. ICall_Errno errno = ICall_wait(ICALL_TIMEOUT_FOREVER); if (errno == ICALL_ERRNO_SUCCESS) { ICall_EntityID dest; ICall_ServiceEnum src; ICall_HciExtEvt *pMsg = NULL; if (ICall_fetchServiceMsg(&src, &dest, (void **)&pMsg) == ICALL_ERRNO_SUCCESS) { if ((src == ICALL_SERVICE_CLASS_BLE) && (dest == selfEntity)) { // Process inter-task message SPPBLEServer_processStackMsg((ICall_Hdr *)pMsg); } if (pMsg) { ICall_freeMsg(pMsg); } } // If RTOS queue is not empty, process app message. if (!Queue_empty(appUARTMsgQueue)) { //Get the message at the front of the queue but still keep it in the queue queueRec_t *pRec = Queue_head(appUARTMsgQueue); sbpUARTEvt_t *pMsg = (sbpUARTEvt_t *)pRec->pData; if (pMsg && ((gapProfileState == GAPROLE_CONNECTED) || (gapProfileState == GAPROLE_CONNECTED_ADV))) { bStatus_t retVal = FAILURE; switch(pMsg->event) { case SBP_UART_ERROR_EVT: { SerialPortService_AddStatusErrorCount((UART_Status)pMsg->data); //Remove from queue Util_dequeueMsg(appUARTMsgQueue); // Free the space from the message. ICall_free(pMsg); break; } case SBP_UART_DATA_EVT: { //Send the notification retVal = SerialPortService_SetParameter(SERIALPORTSERVICE_CHAR_DATA, pMsg->length, pMsg->data); if(retVal != SUCCESS) { LCD_WRITE_STRING_VALUE("NotiFAIL:", retVal, 10, LCD_PAGE4); LCD_WRITE_STRING_VALUE("Data length:", pMsg->length, 10, LCD_PAGE5); LCD_WRITE_STRING(pMsg->data, LCD_PAGE6); } else { //Increment TX status counter SerialPortService_AddStatusTXBytes(pMsg->length); //Remove from queue Util_dequeueMsg(appUARTMsgQueue); if(!Queue_empty(appUARTMsgQueue)) { // Wake up the application to flush out any remaining UART data in the queue. Semaphore_post(sem); } // Free the space from the message. ICall_free(pMsg); } break; } default: break; } } } // If RTOS queue is not empty, process app message. if (!Queue_empty(appMsgQueue)) { sbpEvt_t *pMsg = (sbpEvt_t *)Util_dequeueMsg(appMsgQueue); if (pMsg) { // Process message. SPPBLEServer_processAppMsg(pMsg); // Free the space from the message. ICall_free(pMsg); } } } if (events & SBP_PERIODIC_EVT) { events &= ~SBP_PERIODIC_EVT; Util_startClock(&periodicClock); // Perform periodic application task //SPPBLEServer_performPeriodicTask(); } if (events & SBP_UART_CONFIG_EVT) { uint8 status; events &= ~SBP_UART_CONFIG_EVT; //Configure UART params defined in SerialPortService status = SDITLUART_configureUARTParams(¶msUART); if(status == SUCCESS) { SerialPortService_SetUartConfig(¶msUART); }else { //DEBUG("FAILURE in UART Config"); LCD_WRITE_STRING_VALUE("FAILURE UART Config:", status, 10, LCD_PAGE5); } } #ifdef FEATURE_OAD if (events & SBP_OAD_WRITE_EVT) { events &= ~SBP_OAD_WRITE_EVT; // Identify new image. if (oadWriteEventData.event == OAD_WRITE_IDENTIFY_REQ) { OAD_imgIdentifyWrite(oadWriteEventData.connHandle, oadWriteEventData.pData); } // Write a next block request. else if (oadWriteEventData.event == OAD_WRITE_BLOCK_REQ) { OAD_imgBlockWrite(oadWriteEventData.connHandle, oadWriteEventData.pData); } // Free buffer. ICall_free(oadWriteEventData.pData); } #endif //FEATURE_OAD } } /********************************************************************* * @fn SPPBLEServer_processStackMsg * * @brief Process an incoming stack message. * * @param pMsg - message to process * * @return None. */ static void SPPBLEServer_processStackMsg(ICall_Hdr *pMsg) { switch (pMsg->event) { case GATT_MSG_EVENT: // Process GATT message SPPBLEServer_processGATTMsg((gattMsgEvent_t *)pMsg); break; default: // do nothing break; } } /********************************************************************* * @fn SPPBLEServer_processGATTMsg * * @brief Process GATT messages * * @return None. */ static void SPPBLEServer_processGATTMsg(gattMsgEvent_t *pMsg) { GATT_bm_free(&pMsg->msg, pMsg->method); } /********************************************************************* * @fn SPPBLEServer_processAppMsg * * @brief Process an incoming callback from a profile. * * @param pMsg - message to process * * @return None. */ static void SPPBLEServer_processAppMsg(sbpEvt_t *pMsg) { switch (pMsg->event) { case SBP_STATE_CHANGE_EVT: SPPBLEServer_processStateChangeEvt((gaprole_States_t)pMsg->status); break; case SPB_CHAR_CHANGE_EVT: SPPBLEServer_processCharValueChangeEvt(pMsg->status); break; default: // Do nothing. break; } } /********************************************************************* * @fn SPPBLEServer_stateChangeCB * * @brief Callback from GAP Role indicating a role state change. * * @param newState - new state * * @return None. */ static void SPPBLEServer_stateChangeCB(gaprole_States_t newState) { SPPBLEServer_enqueueMsg(SBP_STATE_CHANGE_EVT, newState); } /********************************************************************* * @fn SPPBLEServer_processStateChangeEvt * * @brief Process a pending GAP Role state change event. * * @param newState - new state * * @return None. */ static void SPPBLEServer_processStateChangeEvt(gaprole_States_t newState) { #ifdef PLUS_BROADCASTER static bool firstConnFlag = false; #endif // PLUS_BROADCASTER 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 LCD_WRITE_STRING(Util_convertBdAddr2Str(ownAddress), LCD_PAGE1); LCD_WRITE_STRING("Initialized", LCD_PAGE2); } break; case GAPROLE_ADVERTISING: LCD_WRITE_STRING("Advertising", LCD_PAGE2); DEBUG("Advertising...Waiting for connection..."); DEBUG_NEWLINE(); break; case GAPROLE_CONNECTED: { uint8_t peerAddress[B_ADDR_LEN]; GAPRole_GetParameter(GAPROLE_CONN_BD_ADDR, peerAddress); //Util_startClock(&periodicClock); DEBUG("Connected"); DEBUG_NEWLINE(); LCD_WRITE_STRING("Connected", LCD_PAGE2); LCD_WRITE_STRING(Util_convertBdAddr2Str(peerAddress), LCD_PAGE3); #ifdef PLUS_BROADCASTER // Only turn advertising on for this state when we first connect // otherwise, when we go from connected_advertising back to this state // we will be turning advertising back on. if (firstConnFlag == false) { uint8_t advertEnabled = TRUE; // Turn on Advertising GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8_t), &advertEnabled); firstConnFlag = true; } #endif // PLUS_BROADCASTER } break; case GAPROLE_CONNECTED_ADV: LCD_WRITE_STRING("Connected Advertising", LCD_PAGE2); break; case GAPROLE_WAITING: //Util_stopClock(&periodicClock); LCD_WRITE_STRING("Disconnected", LCD_PAGE2); DEBUG_NEWLINE(); DEBUG("Disconnected"); DEBUG_NEWLINE(); // Clear remaining lines LCD_WRITE_STRING("", LCD_PAGE3); LCD_WRITE_STRING("", LCD_PAGE4); break; case GAPROLE_WAITING_AFTER_TIMEOUT: LCD_WRITE_STRING("Timed Out", LCD_PAGE2); DEBUG("Disconnected...Timed Out"); DEBUG_NEWLINE(); #ifdef PLUS_BROADCASTER // Reset flag for next connection. firstConnFlag = false; #endif //#ifdef (PLUS_BROADCASTER) break; case GAPROLE_ERROR: LCD_WRITE_STRING("Error", LCD_PAGE2); break; default: LCD_WRITE_STRING("", LCD_PAGE2); break; } // Update the state gapProfileState = newState; } #ifndef FEATURE_OAD /********************************************************************* * @fn SPPBLEServer_charValueChangeCB * * @brief Callback from Serial Port Profile indicating a characteristic * value change. * * @param paramID - parameter ID of the value that was changed. * * @return None. */ static void SPPBLEServer_charValueChangeCB(uint8_t paramID) { SPPBLEServer_enqueueMsg(SPB_CHAR_CHANGE_EVT, paramID); } #endif //!FEATURE_OAD /********************************************************************* * @fn SPPBLEServer_processCharValueChangeEvt * * @brief Process a pending Serial Port Profile characteristic value change * event. * * @param paramID - parameter ID of the value that was changed. * * @return None. */ static void SPPBLEServer_processCharValueChangeEvt(uint8_t paramID) { #ifndef FEATURE_OAD uint8 newValue[20]={0,}; switch(paramID) { case SERIALPORTSERVICE_CHAR_DATA: SerialPortService_GetParameter(SERIALPORTSERVICE_CHAR_DATA, &newValue); //Data already sent at lower layer(SerialPortService) //SDITask_sendToUART(newValue, len); break; case SERIALPORTSERVICE_CHAR_CONFIG: SerialPortService_GetParameter(SERIALPORTSERVICE_CHAR_CONFIG, &newValue); //Set event to change hardware UART parameters Util_startClock(&UARTEventClock); break; default: // should not reach here! break; } #endif //!FEATURE_OAD } /********************************************************************* * @fn SPPBLEServer_performPeriodicTask * * @brief Perform a periodic application task. This function gets called * every SBP_PERIODIC_EVT_PERIOD seconds. * * @param None. * * @return None. */ static void SPPBLEServer_performPeriodicTask(void) { #ifndef FEATURE_OAD #endif //!FEATURE_OAD } #if FEATURE_OAD /********************************************************************* * @fn SPPBLEServer_processOadWriteCB * * @brief Process a write request to the OAD profile. * * @param event - event type: * OAD_WRITE_IDENTIFY_REQ * OAD_WRITE_BLOCK_REQ * @param connHandle - the connection Handle this request is from. * @param pData - pointer to data for processing and/or storing. * * @return None. */ void SPPBLEServer_processOadWriteCB(uint8_t event, uint16_t connHandle, uint8_t *pData) { uint8_t numOfBytes = (event == OAD_WRITE_IDENTIFY_REQ) ? 8 : 18; // Store OAD Identify Request dynamically. if (oadWriteEventData.pData = ICall_malloc(sizeof(uint8_t) * numOfBytes)) { // Set the event. events |= SBP_OAD_WRITE_EVT; oadWriteEventData.event = event; oadWriteEventData.connHandle = connHandle; memcpy(oadWriteEventData.pData, pData, numOfBytes); // Post the application's semaphore. Semaphore_post(sem); } } #endif //FEATURE_OAD /********************************************************************* * @fn SPPBLEServer_setEvent * * @brief Handler function for clock timeouts. * * @param arg - event type * * @return None. */ static void SPPBLEServer_setEvent(UArg arg) { // Store the event. events |= arg; // Wake up the application. Semaphore_post(sem); } /********************************************************************* * @fn SPPBLEServer_enqueueMsg * * @brief Creates a message and puts the message in RTOS queue. * * @param event - message event. * @param status - message status. * * @return None. */ void SPPBLEServer_enqueueUARTMsg(uint8_t event, uint8_t *data, uint8_t len) { sbpUARTEvt_t *pMsg; //Enqueue message only in a connected state if((gapProfileState == GAPROLE_CONNECTED) || (gapProfileState == GAPROLE_CONNECTED_ADV)) { // Create dynamic pointer to message. if (pMsg = ICall_malloc(sizeof(sbpUARTEvt_t))) { pMsg->event = event; memcpy(pMsg->data , data, len); pMsg->length = len; // Enqueue the message. Util_enqueueMsg(appUARTMsgQueue, sem, (uint8*)pMsg); } } } /********************************************************************* * @fn SPPBLEServer_enqueueMsg * * @brief Creates a message and puts the message in RTOS queue. * * @param event - message event. * @param status - message status. * * @return None. */ static void SPPBLEServer_enqueueMsg(uint8_t event, uint8_t status) { sbpEvt_t *pMsg; // Create dynamic pointer to message. if (pMsg = ICall_malloc(sizeof(sbpEvt_t))) { pMsg->event = event; pMsg->status = status; // Enqueue the message. Util_enqueueMsg(appMsgQueue, sem, (uint8*)pMsg); } } /********************************************************************* *********************************************************************/