Part Number: CC2640R2F
CC2640R2 (BLE5)
Note: The following instructions have been written for SDK 3_40_00_10 but can be adapted to quite any SDK version (that is why I provided the sources but also the diff files)
At the end of this lab the functionality allowing RPA (Resolvable Private Address) refresh will not be any longer presents in the application code.
The goal is to save FLASH and processor time.
How to do this?
- Import the project you want (the OOB ble5_simple_peripheral or the project where you have already removed all the other functionalities)
- Verify you are not using RPA. To do so, in simple_peripheral.c, verify the value of DEFAULT_ADDRESS_MODE. DEFAULT_ADDRESS_MODE must be set to ADDRMODE_PUBLIC or to ADDRMODE_RANDOM.
Note: By default DEFAULT_ADDRESS_MODE is already set to ADDRMODE_PUBLIC
- Do the following in simple_peripheral.c
- Remove the SP_READ_RPA_EVT event and all the code using this symbol
- Delete the symbol SP_READ_RPA_EVT_PERIOD
- Remove the variable argRpaRead and all the code using it
- Remove the function SimplePeripheral_updateRPA()
- Remove the clock structure clkRpaRead (and all the code using it if some is remaining)
- Remove the variable rpa[] (and all the code using it if some is remaining)
Here are the diff file and the file you would get if you followed all the others tutorials:
index 8f7ca82..ae30195 100644
@@ -117,9 +117,6 @@
// How often to perform periodic event (in ms)
#define SP_PERIODIC_EVT_PERIOD 5000
-// How often to read current current RPA (in ms)
-#define SP_READ_RPA_EVT_PERIOD 3000
-
// Delay (in ms) after connection establishment before sending a parameter update requst
#define SP_SEND_PARAM_UPDATE_DELAY 6000
@@ -137,7 +134,6 @@
#define SP_PAIR_STATE_EVT 4
#define SP_PASSCODE_EVT 5
#define SP_PERIODIC_EVT 6
-#define SP_READ_RPA_EVT 7
#define SP_SEND_PARAM_UPDATE_EVT 8
#define SP_CONN_EVT 9
@@ -243,17 +239,11 @@ static Queue_Handle appMsgQueueHandle;
// Clock instance for internal periodic events. Only one is needed since
// GattServApp will handle notifying all connected GATT clients
static Clock_Struct clkPeriodic;
-// Clock instance for RPA read events.
-static Clock_Struct clkRpaRead;
// Memory to pass periodic event ID to clock handler
spClockEventData_t argPeriodic =
{ .event = SP_PERIODIC_EVT };
-// Memory to pass RPA read event ID to clock handler
-spClockEventData_t argRpaRead =
-{ .event = SP_READ_RPA_EVT };
-
// Per-handle connection info
static spConnRec_t connList[MAX_NUM_BLE_CONNS];
@@ -318,11 +308,6 @@ static uint8 advHandleLegacy;
// Address mode
static GAP_Addr_Modes_t addrMode = DEFAULT_ADDRESS_MODE;
-#if defined(BLE_V42_FEATURES) && (BLE_V42_FEATURES & PRIVACY_1_2_CFG)
-// Current Random Private Address
-static uint8 rpa[B_ADDR_LEN] = {0};
-#endif // PRIVACY_1_2_CFG
-
/*********************************************************************
* LOCAL FUNCTIONS
*/
@@ -338,9 +323,6 @@ static void SimplePeripheral_processAdvEvent(spGapAdvEventData_t *pEventData);
static void SimplePeripheral_processAppMsg(spEvt_t *pMsg);
static void SimplePeripheral_processCharValueChangeEvt(uint8_t paramId);
static void SimplePeripheral_performPeriodicTask(void);
-#if defined(BLE_V42_FEATURES) && (BLE_V42_FEATURES & PRIVACY_1_2_CFG)
-static void SimplePeripheral_updateRPA(void);
-#endif // PRIVACY_1_2_CFG
static void SimplePeripheral_clockHandler(UArg arg);
#if defined(GAP_BOND_MGR)
static void SimplePeripheral_passcodeCb(uint8_t *pDeviceAddr, uint16_t connHandle,
@@ -822,12 +804,6 @@ static void SimplePeripheral_processAppMsg(spEvt_t *pMsg)
SimplePeripheral_performPeriodicTask();
break;
-#if defined(BLE_V42_FEATURES) && (BLE_V42_FEATURES & PRIVACY_1_2_CFG)
- case SP_READ_RPA_EVT:
- SimplePeripheral_updateRPA();
- break;
-#endif // PRIVACY_1_2_CFG
-
default:
// Do nothing.
break;
@@ -911,18 +887,6 @@ static void SimplePeripheral_processGapMessage(gapEventHdr_t *pMsg)
// Enable legacy advertising for set #1
status = GapAdv_enable(advHandleLegacy, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0);
SIMPLEPERIPHERAL_ASSERT(status == SUCCESS);
-
-#if defined(BLE_V42_FEATURES) && (BLE_V42_FEATURES & PRIVACY_1_2_CFG)
- if (addrMode > ADDRMODE_RANDOM)
- {
- SimplePeripheral_updateRPA();
-
- // Create one-shot clock for RPA check event.
- Util_constructClock(&clkRpaRead, SimplePeripheral_clockHandler,
- SP_READ_RPA_EVT_PERIOD, 0, true,
- (UArg) &argRpaRead);
- }
-#endif // PRIVACY_1_2_CFG
}
break;
@@ -1090,31 +1054,6 @@ static void SimplePeripheral_performPeriodicTask(void)
}
}
-#if defined(BLE_V42_FEATURES) && (BLE_V42_FEATURES & PRIVACY_1_2_CFG)
-/*********************************************************************
- * @fn SimplePeripheral_updateRPA
- *
- * @brief Read the current RPA from the stack and update display
- * if the RPA has changed.
- *
- * @param None.
- *
- * @return None.
- */
-static void SimplePeripheral_updateRPA(void)
-{
- uint8_t* pRpaNew;
-
- // Read the current RPA.
- pRpaNew = GAP_GetDevAddress(FALSE);
-
- if (memcmp(pRpaNew, rpa, B_ADDR_LEN))
- {
- memcpy(rpa, pRpaNew, B_ADDR_LEN);
- }
-}
-#endif // PRIVACY_1_2_CFG
-
/*********************************************************************
* @fn SimplePeripheral_clockHandler
*
@@ -1136,14 +1075,6 @@ static void SimplePeripheral_clockHandler(UArg arg)
// Post event to wake up the application
SimplePeripheral_enqueueMsg(SP_PERIODIC_EVT, NULL);
}
- else if (pData->event == SP_READ_RPA_EVT)
- {
- // Start the next period
- Util_startClock(&clkRpaRead);
-
- // Post event to read the current RPA
- SimplePeripheral_enqueueMsg(SP_READ_RPA_EVT, NULL);
- }
else if (pData->event == SP_SEND_PARAM_UPDATE_EVT)
{
// Send message to app
/******************************************************************************
@file simple_peripheral.c
@brief This file contains the Simple Peripheral sample application for use
with the CC2650 Bluetooth Low Energy Protocol Stack.
Group: WCS, BTS
Target Device: cc2640r2
******************************************************************************
Copyright (c) 2013-2020, Texas Instruments Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of Texas Instruments Incorporated nor the names of
its contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************
*****************************************************************************/
/*********************************************************************
* INCLUDES
*/
#include <string.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>
#if !(defined __TI_COMPILER_VERSION__)
#include <intrinsics.h>
#endif
#include <icall.h>
#include "util.h"
#include <bcomdef.h>
/* This Header file contains all BLE API and icall structure definition */
#include <icall_ble_api.h>
#include <devinfoservice.h>
#include <simple_gatt_profile.h>
#ifdef USE_RCOSC
#include <rcosc_calibration.h>
#endif //USE_RCOSC
#include <board.h>
#include "simple_peripheral.h"
#ifdef PTM_MODE
#include "npi_task.h" // To allow RX event registration
#include "npi_ble.h" // To enable transmission of messages to UART
#include "icall_hci_tl.h" // To allow ICall HCI Transport Layer
#endif // PTM_MODE
/*********************************************************************
* MACROS
*/
/*********************************************************************
* CONSTANTS
*/
// Address mode of the local device
// Note: When using the DEFAULT_ADDRESS_MODE as ADDRMODE_RANDOM or
// ADDRMODE_RP_WITH_RANDOM_ID, GAP_DeviceInit() should be called with
// it's last parameter set to a static random address
#define DEFAULT_ADDRESS_MODE ADDRMODE_PUBLIC
// General discoverable mode: advertise indefinitely
#define DEFAULT_DISCOVERABLE_MODE GAP_ADTYPE_FLAGS_GENERAL
// Minimum connection interval (units of 1.25ms, 80=100ms) for parameter update request
#define DEFAULT_DESIRED_MIN_CONN_INTERVAL 80
// Maximum connection interval (units of 1.25ms, 104=130ms) for parameter update request
#define DEFAULT_DESIRED_MAX_CONN_INTERVAL 104
// Slave latency to use for parameter update request
#define DEFAULT_DESIRED_SLAVE_LATENCY 0
// Supervision timeout value (units of 10ms, 300=3s) for parameter update request
#define DEFAULT_DESIRED_CONN_TIMEOUT 300
// Pass parameter updates to the app for it to decide.
#define DEFAULT_PARAM_UPDATE_REQ_DECISION GAP_UPDATE_REQ_PASS_TO_APP
// How often to perform periodic event (in ms)
#define SP_PERIODIC_EVT_PERIOD 5000
// Delay (in ms) after connection establishment before sending a parameter update requst
#define SP_SEND_PARAM_UPDATE_DELAY 6000
// Task configuration
#define SP_TASK_PRIORITY 1
#ifndef SP_TASK_STACK_SIZE
#define SP_TASK_STACK_SIZE 644
#endif
// Application events
#define SP_STATE_CHANGE_EVT 0
#define SP_CHAR_CHANGE_EVT 1
#define SP_ADV_EVT 3
#define SP_PAIR_STATE_EVT 4
#define SP_PASSCODE_EVT 5
#define SP_PERIODIC_EVT 6
#define SP_SEND_PARAM_UPDATE_EVT 8
#define SP_CONN_EVT 9
// Internal Events for RTOS application
#define SP_ICALL_EVT ICALL_MSG_EVENT_ID // Event_Id_31
#define SP_QUEUE_EVT UTIL_QUEUE_EVENT_ID // Event_Id_30
// Bitwise OR of all RTOS events to pend on
#define SP_ALL_EVENTS (SP_ICALL_EVT | \
SP_QUEUE_EVT)
// Size of string-converted device address ("0xXXXXXXXXXXXX")
#define SP_ADDR_STR_SIZE 15
// Spin if the expression is not true
#define SIMPLEPERIPHERAL_ASSERT(expr) if (!(expr)) simple_peripheral_spin();
/*********************************************************************
* TYPEDEFS
*/
// App event passed from stack modules. This type is defined by the application
// since it can queue events to itself however it wants.
typedef struct
{
uint8_t event; // event type
void *pData; // pointer to message
} spEvt_t;
// Container to store passcode data when passing from gapbondmgr callback
// to app event. See the pfnPairStateCB_t documentation from the gapbondmgr.h
// header file for more information on each parameter.
typedef struct
{
uint8_t state;
uint16_t connHandle;
uint8_t status;
} spPairStateData_t;
// Container to store passcode data when passing from gapbondmgr callback
// to app event. See the pfnPasscodeCB_t documentation from the gapbondmgr.h
// header file for more information on each parameter.
typedef struct
{
uint8_t deviceAddr[B_ADDR_LEN];
uint16_t connHandle;
uint8_t uiInputs;
uint8_t uiOutputs;
uint32_t numComparison;
} spPasscodeData_t;
// Container to store advertising event data when passing from advertising
// callback to app event. See the respective event in GapAdvScan_Event_IDs
// in gap_advertiser.h for the type that pBuf should be cast to.
typedef struct
{
uint32_t event;
void *pBuf;
} spGapAdvEventData_t;
// Container to store information from clock expiration using a flexible array
// since data is not always needed
typedef struct
{
uint8_t event; //
uint8_t data[];
} spClockEventData_t;
// Connected device information
typedef struct
{
uint16_t connHandle; // Connection Handle
} spConnRec_t;
/*********************************************************************
* GLOBAL VARIABLES
*/
// Task configuration
Task_Struct spTask;
#if defined __TI_COMPILER_VERSION__
#pragma DATA_ALIGN(spTaskStack, 8)
#else
#pragma data_alignment=8
#endif
uint8_t spTaskStack[SP_TASK_STACK_SIZE];
/*********************************************************************
* 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;
// Queue object used for app messages
static Queue_Struct appMsgQueue;
static Queue_Handle appMsgQueueHandle;
// Clock instance for internal periodic events. Only one is needed since
// GattServApp will handle notifying all connected GATT clients
static Clock_Struct clkPeriodic;
// Memory to pass periodic event ID to clock handler
spClockEventData_t argPeriodic =
{ .event = SP_PERIODIC_EVT };
// Per-handle connection info
static spConnRec_t connList[MAX_NUM_BLE_CONNS];
// GAP GATT Attributes
static uint8_t attDeviceName[GAP_DEVICE_NAME_LEN] = "Simple Peripheral";
// Advertisement data
static uint8_t advertData[] =
{
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
LO_UINT16(SIMPLEPROFILE_SERV_UUID),
HI_UINT16(SIMPLEPROFILE_SERV_UUID)
};
// Scan Response Data
static uint8_t scanRspData[] =
{
// complete name
17, // length of this data
GAP_ADTYPE_LOCAL_NAME_COMPLETE,
'S',
'i',
'm',
'p',
'l',
'e',
'P',
'e',
'r',
'i',
'p',
'h',
'e',
'r',
'a',
'l',
// connection interval range
5, // 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
2, // length of this data
GAP_ADTYPE_POWER_LEVEL,
0 // 0dBm
};
// Advertising handles
static uint8 advHandleLegacy;
// Address mode
static GAP_Addr_Modes_t addrMode = DEFAULT_ADDRESS_MODE;
/*********************************************************************
* 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_processGapMessage(gapEventHdr_t *pMsg);
static void SimplePeripheral_advCallback(uint32_t event, void *pBuf, uintptr_t arg);
static void SimplePeripheral_processAdvEvent(spGapAdvEventData_t *pEventData);
static void SimplePeripheral_processAppMsg(spEvt_t *pMsg);
static void SimplePeripheral_processCharValueChangeEvt(uint8_t paramId);
static void SimplePeripheral_performPeriodicTask(void);
static void SimplePeripheral_clockHandler(UArg arg);
#if defined(GAP_BOND_MGR)
static void SimplePeripheral_passcodeCb(uint8_t *pDeviceAddr, 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);
#endif
static void SimplePeripheral_processPairState(spPairStateData_t *pPairState);
static void SimplePeripheral_processPasscode(spPasscodeData_t *pPasscodeData);
static void SimplePeripheral_charValueChangeCB(uint8_t paramId);
static status_t SimplePeripheral_enqueueMsg(uint8_t event, void *pData);
static uint8_t SimplePeripheral_addConn(uint16_t connHandle);
static uint8_t SimplePeripheral_getConnIndex(uint16_t connHandle);
static uint8_t SimplePeripheral_removeConn(uint16_t connHandle);
static uint8_t SimplePeripheral_clearConnListEntry(uint16_t connHandle);
#ifdef PTM_MODE
void simple_peripheral_handleNPIRxInterceptEvent(uint8_t *pMsg); // Declaration
static void simple_peripheral_sendToNPI(uint8_t *buf, uint16_t len); // Declaration
#endif // PTM_MODE
/*********************************************************************
* EXTERN FUNCTIONS
*/
extern void AssertHandler(uint8 assertCause, uint8 assertSubcause);
/*********************************************************************
* PROFILE CALLBACKS
*/
#if defined(GAP_BOND_MGR)
// GAP Bond Manager Callbacks
static gapBondCBs_t SimplePeripheral_BondMgrCBs =
{
SimplePeripheral_passcodeCb, // Passcode callback
SimplePeripheral_pairStateCb // Pairing/Bonding state Callback
};
#endif
// Simple GATT Profile Callbacks
static simpleProfileCBs_t SimplePeripheral_simpleProfileCBs =
{
SimplePeripheral_charValueChangeCB // Simple GATT Characteristic value change callback
};
/*********************************************************************
* PUBLIC FUNCTIONS
*/
/*********************************************************************
* @fn simple_peripheral_spin
*
* @brief Spin forever
*
* @param none
*/
static void simple_peripheral_spin(void)
{
volatile uint8_t x = 0;
while(1)
{
x++;
}
}
#ifdef PTM_MODE
/*********************************************************************
* @fn simple_peripheral_handleNPIRxInterceptEvent
*
* @brief Intercept an NPI RX serial message and queue for this application.
*
* @param pMsg - a NPIMSG_msg_t containing the intercepted message.
*
* @return none.
*/
void simple_peripheral_handleNPIRxInterceptEvent(uint8_t *pMsg)
{
// Send Command via HCI TL
HCI_TL_SendToStack(((NPIMSG_msg_t *)pMsg)->pBuf);
// The data is stored as a message, free this first.
ICall_freeMsg(((NPIMSG_msg_t *)pMsg)->pBuf);
// Free container.
ICall_free(pMsg);
}
/*********************************************************************
* @fn simple_peripheral_sendToNPI
*
* @brief Create an NPI packet and send to NPI to transmit.
*
* @param buf - pointer HCI event or data.
*
* @param len - length of buf in bytes.
*
* @return none
*/
static void simple_peripheral_sendToNPI(uint8_t *buf, uint16_t len)
{
npiPkt_t *pNpiPkt = (npiPkt_t *)ICall_allocMsg(sizeof(npiPkt_t) + len);
if (pNpiPkt)
{
pNpiPkt->hdr.event = buf[0]; //Has the event status code in first byte of payload
pNpiPkt->hdr.status = 0xFF;
pNpiPkt->pktLen = len;
pNpiPkt->pData = (uint8 *)(pNpiPkt + 1);
memcpy(pNpiPkt->pData, buf, len);
// Send to NPI
// Note: there is no need to free this packet. NPI will do that itself.
NPITask_sendToHost((uint8_t *)pNpiPkt);
}
}
#endif // PTM_MODE
/*********************************************************************
* @fn SimplePeripheral_createTask
*
* @brief Task creation function for the Simple Peripheral.
*/
void SimplePeripheral_createTask(void)
{
Task_Params taskParams;
// Configure task
Task_Params_init(&taskParams);
taskParams.stack = spTaskStack;
taskParams.stackSize = SP_TASK_STACK_SIZE;
taskParams.priority = SP_TASK_PRIORITY;
Task_construct(&spTask, SimplePeripheral_taskFxn, &taskParams, NULL);
}
/*********************************************************************
* @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.
*/
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);
#ifdef USE_RCOSC
RCOSC_enableCalibration();
#endif // USE_RCOSC
// Create an RTOS queue for message from profile to be sent to app.
appMsgQueueHandle = Util_constructQueue(&appMsgQueue);
// Create one-shot clock for internal periodic events.
Util_constructClock(&clkPeriodic, SimplePeripheral_clockHandler,
SP_PERIODIC_EVT_PERIOD, 0, false, (UArg)&argPeriodic);
// Set the Device Name characteristic in the GAP GATT Service
// For more information, see the section in the User's Guide:
// http://software-dl.ti.com/lprf/ble5stack-latest/
GGS_SetParameter(GGS_DEVICE_NAME_ATT, GAP_DEVICE_NAME_LEN, attDeviceName);
// Configure GAP
{
uint16_t paramUpdateDecision = DEFAULT_PARAM_UPDATE_REQ_DECISION;
// Pass all parameter update requests to the app for it to decide
GAP_SetParamValue(GAP_PARAM_LINK_UPDATE_DECISION, paramUpdateDecision);
}
#if defined(GAP_BOND_MGR)
// Setup the GAP Bond Manager. For more information see the GAP Bond Manager
// section in the User's Guide:
// http://software-dl.ti.com/lprf/ble5stack-latest/
{
// Pairing is not possible
uint8_t pairMode = GAPBOND_PAIRING_MODE_NO_PAIRING;
// Use authenticated pairing: require passcode.
uint8_t mitm = TRUE;
// This device has no display capabilities.
uint8_t ioCap = GAPBOND_IO_CAP_NO_INPUT_NO_OUTPUT;
// Request bonding (storing long-term keys for re-encryption upon subsequent
// connections without repairing)
uint8_t bonding = TRUE;
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);
}
#endif
// Initialize GATT attributes
GGS_AddService(GATT_ALL_SERVICES); // GAP GATT Service
GATTServApp_AddService(GATT_ALL_SERVICES); // GATT Service
DevInfo_AddService(); // Device Information Service
SimpleProfile_AddService(GATT_ALL_SERVICES); // Simple GATT Profile
// Setup the SimpleProfile Characteristic Values
// For more information, see the GATT and GATTServApp sections in the User's Guide:
// http://software-dl.ti.com/lprf/ble5stack-latest/
{
uint8_t charValue1 = 1;
uint8_t charValue2 = 2;
uint8_t charValue3 = 3;
uint8_t charValue4 = 4;
uint8_t charValue5[SIMPLEPROFILE_CHAR5_LEN] = { 1, 2, 3, 4, 5 };
SimpleProfile_SetParameter(SIMPLEPROFILE_CHAR1, sizeof(uint8_t),
&charValue1);
SimpleProfile_SetParameter(SIMPLEPROFILE_CHAR2, sizeof(uint8_t),
&charValue2);
SimpleProfile_SetParameter(SIMPLEPROFILE_CHAR3, sizeof(uint8_t),
&charValue3);
SimpleProfile_SetParameter(SIMPLEPROFILE_CHAR4, sizeof(uint8_t),
&charValue4);
SimpleProfile_SetParameter(SIMPLEPROFILE_CHAR5, SIMPLEPROFILE_CHAR5_LEN,
charValue5);
}
// Register callback with SimpleGATTprofile
SimpleProfile_RegisterAppCBs(&SimplePeripheral_simpleProfileCBs);
#if defined(GAP_BOND_MGR)
// Start Bond Manager and register callback
VOID GAPBondMgr_Register(&SimplePeripheral_BondMgrCBs);
#endif
// Register with GAP for HCI/Host messages. This is needed to receive HCI
// events. For more information, see the HCI section in the User's Guide:
// http://software-dl.ti.com/lprf/ble5stack-latest/
GAP_RegisterForMsgs(selfEntity);
// Register for GATT local events and ATT Responses pending for transmission
GATT_RegisterForMsgs(selfEntity);
// Set default values for Data Length Extension
// Extended Data Length Feature is already enabled by default
{
// Set initial values to maximum, RX is set to max. by default(251 octets, 2120us)
// Some brand smartphone is essentially needing 251/2120, so we set them here.
#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 BLE5-Stack User's Guide for information on using this command:
// http://software-dl.ti.com/lprf/ble5stack-latest/
HCI_LE_WriteSuggestedDefaultDataLenCmd(APP_SUGGESTED_PDU_SIZE, APP_SUGGESTED_TX_TIME);
}
// Initialize GATT Client
GATT_InitClient();
// Initialize Connection List
SimplePeripheral_clearConnListEntry(CONNHANDLE_ALL);
//Initialize GAP layer for Peripheral role and register to receive GAP events
GAP_DeviceInit(GAP_PROFILE_PERIPHERAL, selfEntity, addrMode, NULL);
}
/*********************************************************************
* @fn SimplePeripheral_taskFxn
*
* @brief Application task entry point for the Simple Peripheral.
*
* @param a0, a1 - not used.
*/
static void SimplePeripheral_taskFxn(UArg a0, UArg a1)
{
// Initialize application
SimplePeripheral_init();
// Application main loop
for (;;)
{
uint32_t events;
// Waits for an event to be posted associated with the calling thread.
// Note that an event associated with a thread is posted when a
// message is queued to the message receive queue of the thread
events = Event_pend(syncEvent, Event_Id_NONE, SP_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;
// Check for BLE stack events first
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 & SP_QUEUE_EVT)
{
while (!Queue_empty(appMsgQueueHandle))
{
spEvt_t *pMsg = (spEvt_t *)Util_dequeueMsg(appMsgQueueHandle);
if (pMsg)
{
// Process message.
SimplePeripheral_processAppMsg(pMsg);
// Free the space from the message.
ICall_free(pMsg);
}
}
}
}
}
}
/*********************************************************************
* @fn SimplePeripheral_processStackMsg
*
* @brief Process an incoming stack message.
*
* @param pMsg - message to process
*
* @return TRUE if safe to deallocate incoming message, FALSE otherwise.
*/
static uint8_t SimplePeripheral_processStackMsg(ICall_Hdr *pMsg)
{
// Always dealloc pMsg unless set otherwise
uint8_t safeToDealloc = TRUE;
switch (pMsg->event)
{
case GAP_MSG_EVENT:
SimplePeripheral_processGapMessage((gapEventHdr_t*) pMsg);
break;
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_BLE_HARDWARE_ERROR_EVENT_CODE:
AssertHandler(HAL_ASSERT_CAUSE_HARDWARE_ERROR,0);
break;
default:
break;
}
break;
}
default:
// do nothing
break;
}
#ifdef PTM_MODE
// Check for NPI Messages
hciPacket_t *pBuf = (hciPacket_t *)pMsg;
// Serialized HCI Event
if (pBuf->hdr.event == HCI_CTRL_TO_HOST_EVENT)
{
uint16_t len = 0;
// Determine the packet length
switch(pBuf->pData[0])
{
case HCI_EVENT_PACKET:
len = HCI_EVENT_MIN_LENGTH + pBuf->pData[2];
break;
case HCI_ACL_DATA_PACKET:
len = HCI_DATA_MIN_LENGTH + BUILD_UINT16(pBuf->pData[3], pBuf->pData[4]);
break;
default:
break;
}
// Send to Remote Host.
simple_peripheral_sendToNPI(pBuf->pData, len);
// Free buffers if needed.
switch (pBuf->pData[0])
{
case HCI_ACL_DATA_PACKET:
case HCI_SCO_DATA_PACKET:
BM_free(pBuf->pData);
default:
break;
}
}
#endif // PTM_MODE
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)
{
// 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_processAppMsg
*
* @brief Process an incoming callback from a profile.
*
* @param pMsg - message to process
*
* @return None.
*/
static void SimplePeripheral_processAppMsg(spEvt_t *pMsg)
{
bool dealloc = TRUE;
switch (pMsg->event)
{
case SP_CHAR_CHANGE_EVT:
SimplePeripheral_processCharValueChangeEvt(*(uint8_t*)(pMsg->pData));
break;
case SP_ADV_EVT:
SimplePeripheral_processAdvEvent((spGapAdvEventData_t*)(pMsg->pData));
break;
case SP_PAIR_STATE_EVT:
SimplePeripheral_processPairState((spPairStateData_t*)(pMsg->pData));
break;
case SP_PASSCODE_EVT:
SimplePeripheral_processPasscode((spPasscodeData_t*)(pMsg->pData));
break;
case SP_PERIODIC_EVT:
SimplePeripheral_performPeriodicTask();
break;
default:
// Do nothing.
break;
}
// Free message data if it exists and we are to dealloc
if ((dealloc == TRUE) && (pMsg->pData != NULL))
{
ICall_free(pMsg->pData);
}
}
/*********************************************************************
* @fn SimplePeripheral_processGapMessage
*
* @brief Process an incoming GAP event.
*
* @param pMsg - message to process
*/
static void SimplePeripheral_processGapMessage(gapEventHdr_t *pMsg)
{
switch(pMsg->opcode)
{
case GAP_DEVICE_INIT_DONE_EVENT:
{
bStatus_t status = FAILURE;
gapDeviceInitDoneEvent_t *pPkt = (gapDeviceInitDoneEvent_t *)pMsg;
if(pPkt->hdr.status == SUCCESS)
{
// Store the system ID
uint8_t systemId[DEVINFO_SYSTEM_ID_LEN];
// use 6 bytes of device address for 8 bytes of system ID value
systemId[0] = pPkt->devAddr[0];
systemId[1] = pPkt->devAddr[1];
systemId[2] = pPkt->devAddr[2];
// set middle bytes to zero
systemId[4] = 0x00;
systemId[3] = 0x00;
// shift three bytes up
systemId[7] = pPkt->devAddr[5];
systemId[6] = pPkt->devAddr[4];
systemId[5] = pPkt->devAddr[3];
// Set Device Info Service Parameter
DevInfo_SetParameter(DEVINFO_SYSTEM_ID, DEVINFO_SYSTEM_ID_LEN, systemId);
// Setup and start Advertising
// For more information, see the GAP section in the User's Guide:
// http://software-dl.ti.com/lprf/ble5stack-latest/
// Temporary memory for advertising parameters for set #1. These will be copied
// by the GapAdv module
GapAdv_params_t advParamLegacy = GAPADV_PARAMS_LEGACY_SCANN_CONN;
// Create Advertisement set #1 and assign handle
status = GapAdv_create(&SimplePeripheral_advCallback, &advParamLegacy,
&advHandleLegacy);
SIMPLEPERIPHERAL_ASSERT(status == SUCCESS);
// Load advertising data for set #1 that is statically allocated by the app
status = GapAdv_loadByHandle(advHandleLegacy, GAP_ADV_DATA_TYPE_ADV,
sizeof(advertData), advertData);
SIMPLEPERIPHERAL_ASSERT(status == SUCCESS);
// Load scan response data for set #1 that is statically allocated by the app
status = GapAdv_loadByHandle(advHandleLegacy, GAP_ADV_DATA_TYPE_SCAN_RSP,
sizeof(scanRspData), scanRspData);
SIMPLEPERIPHERAL_ASSERT(status == SUCCESS);
// Set event mask for set #1
status = GapAdv_setEventMask(advHandleLegacy,
GAP_ADV_EVT_MASK_START_AFTER_ENABLE |
GAP_ADV_EVT_MASK_END_AFTER_DISABLE |
GAP_ADV_EVT_MASK_SET_TERMINATED);
// Enable legacy advertising for set #1
status = GapAdv_enable(advHandleLegacy, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0);
SIMPLEPERIPHERAL_ASSERT(status == SUCCESS);
}
break;
}
case GAP_LINK_ESTABLISHED_EVENT:
{
gapEstLinkReqEvent_t *pPkt = (gapEstLinkReqEvent_t *)pMsg;
uint8_t numActive = linkDB_NumActive();
if (pPkt->hdr.status == SUCCESS)
{
// Add connection to list
SimplePeripheral_addConn(pPkt->connectionHandle);
// Start Periodic Clock.
Util_startClock(&clkPeriodic);
}
if (numActive < MAX_NUM_BLE_CONNS)
{
// Start advertising since there is room for more connections
GapAdv_enable(advHandleLegacy, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0);
}
break;
}
case GAP_LINK_TERMINATED_EVENT:
{
gapTerminateLinkEvent_t *pPkt = (gapTerminateLinkEvent_t *)pMsg;
uint8_t numActive = linkDB_NumActive();
// Remove the connection from the list
SimplePeripheral_removeConn(pPkt->connectionHandle);
// If no active connections
if (numActive == 0)
{
// Stop periodic clock
Util_stopClock(&clkPeriodic);
}
// Start advertising since there is room for more connections
GapAdv_enable(advHandleLegacy, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0);
break;
}
case GAP_UPDATE_LINK_PARAM_REQ_EVENT:
{
gapUpdateLinkParamReqReply_t rsp;
gapUpdateLinkParamReqEvent_t *pReq = (gapUpdateLinkParamReqEvent_t *)pMsg;
rsp.connectionHandle = pReq->req.connectionHandle;
// Only accept connection intervals with slave latency of 0
// This is just an example of how the application can send a response
if(pReq->req.connLatency == 0)
{
rsp.intervalMin = pReq->req.intervalMin;
rsp.intervalMax = pReq->req.intervalMax;
rsp.connLatency = pReq->req.connLatency;
rsp.connTimeout = pReq->req.connTimeout;
rsp.accepted = TRUE;
}
else
{
rsp.accepted = FALSE;
}
// Send Reply
VOID GAP_UpdateLinkParamReqReply(&rsp);
break;
}
default:
break;
}
}
/*********************************************************************
* @fn SimplePeripheral_charValueChangeCB
*
* @brief Callback from Simple Profile indicating a characteristic
* value change.
*
* @param paramId - parameter Id of the value that was changed.
*
* @return None.
*/
static void SimplePeripheral_charValueChangeCB(uint8_t paramId)
{
uint8_t *pValue = ICall_malloc(sizeof(uint8_t));
if (pValue)
{
*pValue = paramId;
if (SimplePeripheral_enqueueMsg(SP_CHAR_CHANGE_EVT, pValue) != SUCCESS)
{
ICall_free(pValue);
}
}
}
/*********************************************************************
* @fn SimplePeripheral_processCharValueChangeEvt
*
* @brief Process a pending Simple Profile characteristic value change
* event.
*
* @param paramID - parameter ID of the value that was changed.
*/
static void SimplePeripheral_processCharValueChangeEvt(uint8_t paramId)
{
uint8_t newValue;
switch(paramId)
{
case SIMPLEPROFILE_CHAR1:
SimpleProfile_GetParameter(SIMPLEPROFILE_CHAR1, &newValue);
break;
case SIMPLEPROFILE_CHAR3:
SimpleProfile_GetParameter(SIMPLEPROFILE_CHAR3, &newValue);
break;
default:
// should not reach here!
break;
}
}
/*********************************************************************
* @fn SimplePeripheral_performPeriodicTask
*
* @brief Perform a periodic application task. This function gets called
* every five seconds (SP_PERIODIC_EVT_PERIOD). In this example,
* the value of the third characteristic in the SimpleGATTProfile
* service is retrieved from the profile, and then copied into the
* value of the the fourth characteristic.
*
* @param None.
*
* @return None.
*/
static void SimplePeripheral_performPeriodicTask(void)
{
uint8_t valueToCopy;
// Call to retrieve the value of the third characteristic in the profile
if (SimpleProfile_GetParameter(SIMPLEPROFILE_CHAR3, &valueToCopy) == SUCCESS)
{
// Call to set that value of the fourth characteristic in the profile.
// Note that if notifications of the fourth characteristic have been
// enabled by a GATT client device, then a notification will be sent
// every time this function is called.
SimpleProfile_SetParameter(SIMPLEPROFILE_CHAR4, sizeof(uint8_t),
&valueToCopy);
}
}
/*********************************************************************
* @fn SimplePeripheral_clockHandler
*
* @brief Handler function for clock timeouts.
*
* @param arg - event type
*
* @return None.
*/
static void SimplePeripheral_clockHandler(UArg arg)
{
spClockEventData_t *pData = (spClockEventData_t *)arg;
if (pData->event == SP_PERIODIC_EVT)
{
// Start the next period
Util_startClock(&clkPeriodic);
// Post event to wake up the application
SimplePeripheral_enqueueMsg(SP_PERIODIC_EVT, NULL);
}
else if (pData->event == SP_SEND_PARAM_UPDATE_EVT)
{
// Send message to app
SimplePeripheral_enqueueMsg(SP_SEND_PARAM_UPDATE_EVT, pData);
}
}
/*********************************************************************
* @fn SimplePeripheral_advCallback
*
* @brief GapAdv module callback
*
* @param pMsg - message to process
*/
static void SimplePeripheral_advCallback(uint32_t event, void *pBuf, uintptr_t arg)
{
spGapAdvEventData_t *pData = ICall_malloc(sizeof(spGapAdvEventData_t));
if (pData)
{
pData->event = event;
pData->pBuf = pBuf;
if(SimplePeripheral_enqueueMsg(SP_ADV_EVT, pData) != SUCCESS)
{
ICall_free(pData);
}
}
}
/*********************************************************************
* @fn SimplePeripheral_processAdvEvent
*
* @brief Process advertising event in app context
*
* @param pEventData
*/
static void SimplePeripheral_processAdvEvent(spGapAdvEventData_t *pEventData)
{
switch (pEventData->event)
{
case GAP_EVT_ADV_START_AFTER_ENABLE:
break;
case GAP_EVT_ADV_END_AFTER_DISABLE:
break;
case GAP_EVT_ADV_START:
break;
case GAP_EVT_ADV_END:
break;
case GAP_EVT_ADV_SET_TERMINATED:
break;
case GAP_EVT_SCAN_REQ_RECEIVED:
break;
case GAP_EVT_INSUFFICIENT_MEMORY:
break;
default:
break;
}
// All events have associated memory to free except the insufficient memory
// event
if (pEventData->event != GAP_EVT_INSUFFICIENT_MEMORY)
{
ICall_free(pEventData->pBuf);
}
}
#if defined(GAP_BOND_MGR)
/*********************************************************************
* @fn SimplePeripheral_pairStateCb
*
* @brief Pairing state callback.
*
* @return none
*/
static void SimplePeripheral_pairStateCb(uint16_t connHandle, uint8_t state,
uint8_t status)
{
spPairStateData_t *pData = ICall_malloc(sizeof(spPairStateData_t));
// Allocate space for the event data.
if (pData)
{
pData->state = state;
pData->connHandle = connHandle;
pData->status = status;
// Queue the event.
if(SimplePeripheral_enqueueMsg(SP_PAIR_STATE_EVT, pData) != SUCCESS)
{
ICall_free(pData);
}
}
}
/*********************************************************************
* @fn SimplePeripheral_passcodeCb
*
* @brief Passcode callback.
*
* @return none
*/
static void SimplePeripheral_passcodeCb(uint8_t *pDeviceAddr,
uint16_t connHandle,
uint8_t uiInputs,
uint8_t uiOutputs,
uint32_t numComparison)
{
spPasscodeData_t *pData = ICall_malloc(sizeof(spPasscodeData_t));
// Allocate space for the passcode event.
if (pData )
{
pData->connHandle = connHandle;
memcpy(pData->deviceAddr, pDeviceAddr, B_ADDR_LEN);
pData->uiInputs = uiInputs;
pData->uiOutputs = uiOutputs;
pData->numComparison = numComparison;
// Enqueue the event.
if(SimplePeripheral_enqueueMsg(SP_PASSCODE_EVT, pData) != SUCCESS)
{
ICall_free(pData);
}
}
}
#endif
/*********************************************************************
* @fn SimplePeripheral_processPairState
*
* @brief Process the new paring state.
*
* @return none
*/
static void SimplePeripheral_processPairState(spPairStateData_t *pPairData)
{
uint8_t state = pPairData->state;
switch (state)
{
case GAPBOND_PAIRING_STATE_STARTED:
break;
case GAPBOND_PAIRING_STATE_COMPLETE:
break;
case GAPBOND_PAIRING_STATE_ENCRYPTED:
break;
case GAPBOND_PAIRING_STATE_BOND_SAVED:
break;
default:
break;
}
}
/*********************************************************************
* @fn SimplePeripheral_processPasscode
*
* @brief Process the Passcode request.
*
* @return none
*/
static void SimplePeripheral_processPasscode(spPasscodeData_t *pPasscodeData)
{
#if defined(GAP_BOND_MGR)
// Send passcode response
GAPBondMgr_PasscodeRsp(pPasscodeData->connHandle , SUCCESS,
B_APP_DEFAULT_PASSCODE);
#endif
}
/*********************************************************************
* @fn SimplePeripheral_enqueueMsg
*
* @brief Creates a message and puts the message in RTOS queue.
*
* @param event - message event.
* @param state - message state.
*/
static status_t SimplePeripheral_enqueueMsg(uint8_t event, void *pData)
{
uint8_t success;
spEvt_t *pMsg = ICall_malloc(sizeof(spEvt_t));
// Create dynamic pointer to message.
if(pMsg)
{
pMsg->event = event;
pMsg->pData = pData;
// Enqueue the message.
success = Util_enqueueMsg(appMsgQueueHandle, syncEvent, (uint8_t *)pMsg);
return (success) ? SUCCESS : FAILURE;
}
return(bleMemAllocError);
}
/*********************************************************************
* @fn SimplePeripheral_doSelectConn
*
* @brief Select a connection to communicate with
*
* @param index - item index from the menu
*
* @return always true
*/
bool SimplePeripheral_doSelectConn(uint8_t index)
{
return (true);
}
/*********************************************************************
* @fn SimplePeripheral_addConn
*
* @brief Add a device to the connected device list
*
* @return index of the connected device list entry where the new connection
* info is put in.
* if there is no room, MAX_NUM_BLE_CONNS will be returned.
*/
static uint8_t SimplePeripheral_addConn(uint16_t connHandle)
{
uint8_t i;
uint8_t status = bleNoResources;
// Try to find an available entry
for (i = 0; i < MAX_NUM_BLE_CONNS; i++)
{
if (connList[i].connHandle == CONNHANDLE_INVALID)
{
// Found available entry to put a new connection info in
connList[i].connHandle = connHandle;
break;
}
}
return status;
}
/*********************************************************************
* @fn SimplePeripheral_getConnIndex
*
* @brief Find index in the connected device list by connHandle
*
* @return the index of the entry that has the given connection handle.
* if there is no match, MAX_NUM_BLE_CONNS will be returned.
*/
static uint8_t SimplePeripheral_getConnIndex(uint16_t connHandle)
{
uint8_t i;
for (i = 0; i < MAX_NUM_BLE_CONNS; i++)
{
if (connList[i].connHandle == connHandle)
{
return i;
}
}
return(MAX_NUM_BLE_CONNS);
}
/*********************************************************************
* @fn SimplePeripheral_getConnIndex
*
* @brief Find index in the connected device list by connHandle
*
* @return SUCCESS if connHandle found valid index or bleInvalidRange
* if index wasn't found. CONNHANDLE_ALL will always succeed.
*/
static uint8_t SimplePeripheral_clearConnListEntry(uint16_t connHandle)
{
uint8_t i;
// Set to invalid connection index initially
uint8_t connIndex = MAX_NUM_BLE_CONNS;
if(connHandle != CONNHANDLE_ALL)
{
// Get connection index from handle
connIndex = SimplePeripheral_getConnIndex(connHandle);
if(connIndex >= MAX_NUM_BLE_CONNS)
{
return(bleInvalidRange);
}
}
// Clear specific handle or all handles
for(i = 0; i < MAX_NUM_BLE_CONNS; i++)
{
if((connIndex == i) || (connHandle == CONNHANDLE_ALL))
{
connList[i].connHandle = CONNHANDLE_INVALID;
}
}
return(SUCCESS);
}
/*********************************************************************
* @fn SimplePeripheral_removeConn
*
* @brief Remove a device from the connected device list
*
* @return index of the connected device list entry where the new connection
* info is removed from.
* if connHandle is not found, MAX_NUM_BLE_CONNS will be returned.
*/
static uint8_t SimplePeripheral_removeConn(uint16_t connHandle)
{
uint8_t connIndex = SimplePeripheral_getConnIndex(connHandle);
if(connIndex != MAX_NUM_BLE_CONNS)
{
// Clear Connection List Entry
SimplePeripheral_clearConnListEntry(connHandle);
}
return connIndex;
}
#ifdef PTM_MODE
/*********************************************************************
* @fn SimplePeripheral_doEnablePTMMode
*
* @brief Stop advertising, configure & start PTM mode
*
* @param index - item index from the menu
*
* @return always true
*/
bool SimplePeripheral_doEnablePTMMode(uint8_t index)
{
// Start NPI task
NPITask_createTask(ICALL_SERVICE_CLASS_BLE);
// Disable Advertising and destroy sets
GapAdv_destroy(advHandleLegacy,GAP_ADV_FREE_OPTION_ALL_DATA);
// Intercept NPI RX events.
NPITask_registerIncomingRXEventAppCB(simple_peripheral_handleNPIRxInterceptEvent, INTERCEPT);
// Register for Command Status information
HCI_TL_Init(NULL, (HCI_TL_CommandStatusCB_t) simple_peripheral_sendToNPI, NULL, selfEntity);
// Register for Events
HCI_TL_getCmdResponderID(ICall_getLocalMsgEntityId(ICALL_SERVICE_CLASS_BLE_MSG, selfEntity));
// Inform Stack to Initialize PTM
HCI_EXT_EnablePTMCmd();
return TRUE;
}
#endif
/*********************************************************************
*********************************************************************/
- Test your program. Everything should still work smoothly!