微波EDA网,见证研发工程师的成长!
首页 > 研发问答 > 无线和射频 > TI蓝牙设计交流 > 咨询如何关于CC2541从机向主机发送多数据(数组)s

咨询如何关于CC2541从机向主机发送多数据(数组)s

时间:10-02 整理:3721RD 点击:

各位专家好:

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(&paramsUART);

      if(status == SUCCESS)
      {
        SerialPortService_SetUartConfig(&paramsUART);
      }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);
  }
}

/*********************************************************************
*********************************************************************/

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top