咨询如何关于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);
}
}
/*********************************************************************
*********************************************************************/
