Other Parts Discussed in Thread: SYSCONFIG
HI
Im using multirole for peripheral+observer(scanning for only to read Advrt data). its working but scanning is happening slow when peripheral is connected
using sdk 5.20 tool 11.1
This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
/****************************************************************************** @file multi_role.c @brief This file contains the multi_role sample application for use with the CC2650 Bluetooth Low Energy Protocol Stack. Group: WCS, BTS Target Device: cc13x2_26x2 ****************************************************************************** Copyright (c) 2013-2021, 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> #include <ti/display/Display.h> #if !(defined __TI_COMPILER_VERSION__) && !(defined __GNUC__) #include <intrinsics.h> #endif #include <ti/drivers/utils/List.h> #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> #include <ti_drivers_config.h> #include <board_key.h> #include <menu/two_btn_menu.h> #include "ti_ble_config.h" #include "multi_role_menu.h" #include "multi_role.h" /********************************************************************* * MACROS */ /********************************************************************* * CONSTANTS */ // Application events #define MR_EVT_CHAR_CHANGE 1 #define MR_EVT_KEY_CHANGE 2 #define MR_EVT_ADV_REPORT 3 #define MR_EVT_SCAN_ENABLED 4 #define MR_EVT_SCAN_DISABLED 5 #define MR_EVT_SVC_DISC 6 #define MR_EVT_ADV 7 #define MR_EVT_PAIRING_STATE 8 #define MR_EVT_PASSCODE_NEEDED 9 #define MR_EVT_SEND_PARAM_UPDATE 10 #define MR_EVT_PERIODIC 11 #define MR_EVT_READ_RPA 12 #define MR_EVT_INSUFFICIENT_MEM 13 // Internal Events for RTOS application #define MR_ICALL_EVT ICALL_MSG_EVENT_ID // Event_Id_31 #define MR_QUEUE_EVT UTIL_QUEUE_EVENT_ID // Event_Id_30 #define MR_ALL_EVENTS (MR_ICALL_EVT | \ MR_QUEUE_EVT) // Supervision timeout conversion rate to miliseconds #define CONN_TIMEOUT_MS_CONVERSION 10 // Task configuration #define MR_TASK_PRIORITY 4 #ifndef MR_TASK_STACK_SIZE #define MR_TASK_STACK_SIZE 1024 #endif // Discovery states typedef enum { BLE_DISC_STATE_IDLE, // Idle BLE_DISC_STATE_MTU, // Exchange ATT MTU size BLE_DISC_STATE_SVC, // Service discovery BLE_DISC_STATE_CHAR // Characteristic discovery } discState_t; // Row numbers for two-button menu #define MR_ROW_SEPARATOR (TBM_ROW_APP + 0) #define MR_ROW_CUR_CONN (TBM_ROW_APP + 1) #define MR_ROW_ANY_CONN (TBM_ROW_APP + 2) #define MR_ROW_NON_CONN (TBM_ROW_APP + 3) #define MR_ROW_NUM_CONN (TBM_ROW_APP + 4) #define MR_ROW_CHARSTAT (TBM_ROW_APP + 5) #define MR_ROW_ADVERTIS (TBM_ROW_APP + 6) #define MR_ROW_MYADDRSS (TBM_ROW_APP + 7) #define MR_ROW_SECURITY (TBM_ROW_APP + 8) #define MR_ROW_RPA (TBM_ROW_APP + 9) #define DEVICE_NAME0 (TBM_ROW_APP + 10) #define DEVICE_NAME1 (TBM_ROW_APP + 11) #define DEVICE_NAME2 (TBM_ROW_APP + 12) #define DEVICE_NAME3 (TBM_ROW_APP + 13) #define DEVICE_NAME4 (TBM_ROW_APP + 14) #define DEVICE_NAME5 (TBM_ROW_APP + 15) #define DEVICE_NAME6 (TBM_ROW_APP + 16) #define DEVICE_NAME7 (TBM_ROW_APP + 17) #define DEVICE_NAME8 (TBM_ROW_APP + 18) #define DEVICE_NAME9 (TBM_ROW_APP + 19) #define DEVICE_NAME10 (TBM_ROW_APP + 20) #define DEVICE_NAME11 (TBM_ROW_APP + 21) #define DEVICE_NAME12 (TBM_ROW_APP + 22) #define DEVICE_NAME13 (TBM_ROW_APP + 23) #define DEVICE_NAME14 (TBM_ROW_APP + 24) #define DEVICE_NAME15 (TBM_ROW_APP + 25) #define DEVICE_NAME16 (TBM_ROW_APP + 26) #define DEVICE_NAME17 (TBM_ROW_APP + 27) #define DEVICE_NAME18 (TBM_ROW_APP + 28) #define DEVICE_NAME19 (TBM_ROW_APP + 29) #define DEVICE_NAME20 (TBM_ROW_APP + 30) #define DEVICE_NAME21 (TBM_ROW_APP + 31) #define DEVICE_NAME22 (TBM_ROW_APP + 32) // address string length is an ascii character for each digit + #define MR_ADDR_STR_SIZE 15 // How often to perform periodic event (in msec) #define MR_PERIODIC_EVT_PERIOD 5000 #define CONNINDEX_INVALID 0xFF // Spin if the expression is not true #define MULTIROLE_ASSERT(expr) if (!(expr)) multi_role_spin(); /********************************************************************* * TYPEDEFS */ // App event passed from profiles. typedef struct { uint8_t event; // event type void *pData; // event data pointer } mrEvt_t; // Container to store paring state info 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; } mrPairStateData_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; } mrPasscodeData_t; // Scanned device information record typedef struct { uint8_t addrType; // Peer Device's Address Type uint8_t addr[B_ADDR_LEN]; // Peer Device Address } scanRec_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[]; } mrClockEventData_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; } mrGapAdvEventData_t; // List element for parameter update and PHY command status lists typedef struct { List_Elem elem; uint16_t connHandle; } mrConnHandleEntry_t; // Connected device information typedef struct { uint16_t connHandle; // Connection Handle mrClockEventData_t* pParamUpdateEventData;// pointer to paramUpdateEventData uint16_t charHandle; // Characteristic Handle uint8_t addr[B_ADDR_LEN]; // Peer Device Address Clock_Struct* pUpdateClock; // pointer to clock struct uint8_t discState; // Per connection deiscovery state } mrConnRec_t; /********************************************************************* * GLOBAL VARIABLES */ // Display Interface Display_Handle dispHandle = NULL; /********************************************************************* * LOCAL VARIABLES */ #define APP_EVT_EVENT_MAX 0x13 char *appEventStrings[] = { "APP_ZERO ", "APP_CHAR_CHANGE ", "APP_KEY_CHANGE ", "APP_ADV_REPORT ", "APP_SCAN_ENABLED ", "APP_SCAN_DISABLED ", "APP_SVC_DISC ", "APP_ADV ", "APP_PAIRING_STATE ", "APP_SEND_PARAM_UPDATE", "APP_PERIODIC ", "APP_READ_RPA ", "APP_INSUFFICIENT_MEM ", }; /********************************************************************* * LOCAL VARIABLES */ // Entity ID globally used to check for source and/or destination of messages static ICall_EntityID selfEntity; // Event globally used to post local events and pend on system and // local events. static ICall_SyncHandle syncEvent; // Clock instances for internal periodic events. static Clock_Struct clkPeriodic; // Clock instance for RPA read events. static Clock_Struct clkRpaRead; // Memory to pass periodic event to clock handler mrClockEventData_t periodicUpdateData = { .event = MR_EVT_PERIODIC }; // Memory to pass RPA read event ID to clock handler mrClockEventData_t argRpaRead = { .event = MR_EVT_READ_RPA }; // Queue object used for app messages static Queue_Struct appMsg; static Queue_Handle appMsgQueue; // Task configuration Task_Struct mrTask; #if defined __TI_COMPILER_VERSION__ #pragma DATA_ALIGN(mrTaskStack, 8) #else #pragma data_alignment=8 #endif uint8_t mrTaskStack[MR_TASK_STACK_SIZE]; // Maximim PDU size (default = 27 octets) static uint16 mrMaxPduSize; #if (DEFAULT_DEV_DISC_BY_SVC_UUID == TRUE) // Number of scan results filtered by Service UUID static uint8_t numScanRes = 0; // Scan results filtered by Service UUID static scanRec_t scanList[DEFAULT_MAX_SCAN_RES]; #endif // DEFAULT_DEV_DISC_BY_SVC_UUID // Discovered service start and end handle static uint16_t svcStartHdl = 0; static uint16_t svcEndHdl = 0; // Value to write static uint8_t charVal = 0; // Number of connected devices static uint8_t numConn = 0; // Connection handle of current connection static uint16_t mrConnHandle = LINKDB_CONNHANDLE_INVALID; // List to store connection handles for queued param updates static List_List paramUpdateList; // Per-handle connection info static mrConnRec_t connList[MAX_NUM_BLE_CONNS]; // Advertising handles static uint8 advHandle; static bool mrIsAdvertising = false; // Address mode static GAP_Addr_Modes_t addrMode = DEFAULT_ADDRESS_MODE; // Current Random Private Address static uint8 rpa[B_ADDR_LEN] = {0}; // Initiating PHY static uint8_t mrInitPhy = INIT_PHY_1M; /********************************************************************* * LOCAL FUNCTIONS */ static void multi_role_init(void); static void multi_role_scanInit(void); static void multi_role_advertInit(void); static void multi_role_taskFxn(UArg a0, UArg a1); static uint8_t multi_role_processStackMsg(ICall_Hdr *pMsg); static uint8_t multi_role_processGATTMsg(gattMsgEvent_t *pMsg); static void multi_role_processAppMsg(mrEvt_t *pMsg); static void multi_role_processCharValueChangeEvt(uint8_t paramID); static void multi_role_processGATTDiscEvent(gattMsgEvent_t *pMsg); static void multi_role_processPasscode(mrPasscodeData_t *pData); static void multi_role_processPairState(mrPairStateData_t* pairingEvent); static void multi_role_processGapMsg(gapEventHdr_t *pMsg); static void multi_role_processParamUpdate(uint16_t connHandle); static void multi_role_processAdvEvent(mrGapAdvEventData_t *pEventData); static void multi_role_charValueChangeCB(uint8_t paramID); static status_t multi_role_enqueueMsg(uint8_t event, void *pData); static void multi_role_handleKeys(uint8_t keys); static uint16_t multi_role_getConnIndex(uint16_t connHandle); static void multi_role_keyChangeHandler(uint8_t keys); static uint8_t multi_role_addConnInfo(uint16_t connHandle, uint8_t *pAddr, uint8_t role); static void multi_role_performPeriodicTask(void); static void multi_role_clockHandler(UArg arg); static uint8_t multi_role_clearConnListEntry(uint16_t connHandle); #if (DEFAULT_DEV_DISC_BY_SVC_UUID == TRUE) static void multi_role_addScanInfo(uint8_t *pAddr, uint8_t addrType); static bool multi_role_findSvcUuid(uint16_t uuid, uint8_t *pData, uint16_t dataLen); #endif // DEFAULT_DEV_DISC_BY_SVC_UUID static uint8_t multi_role_removeConnInfo(uint16_t connHandle); static void multi_role_menuSwitchCb(tbmMenuObj_t* pMenuObjCurr, tbmMenuObj_t* pMenuObjNext); static void multi_role_startSvcDiscovery(void); #ifndef Display_DISABLE_ALL static char* multi_role_getConnAddrStr(uint16_t connHandle); #endif static void multi_role_advCB(uint32_t event, void *pBuf, uintptr_t arg); static void multi_role_scanCB(uint32_t evt, void* msg, uintptr_t arg); static void multi_role_passcodeCB(uint8_t *deviceAddr, uint16_t connHandle, uint8_t uiInputs, uint8_t uiOutputs, uint32_t numComparison); static void multi_role_pairStateCB(uint16_t connHandle, uint8_t state, uint8_t status); static void multi_role_updateRPA(void); int findpat(uint8_t *buf, char *pat, int buflen); /********************************************************************* * EXTERN FUNCTIONS */ extern void AssertHandler(uint8 assertCause, uint8 assertSubcause); /********************************************************************* * PROFILE CALLBACKS */ // Simple GATT Profile Callbacks static simpleProfileCBs_t multi_role_simpleProfileCBs = { multi_role_charValueChangeCB // Characteristic value change callback }; // GAP Bond Manager Callbacks static gapBondCBs_t multi_role_BondMgrCBs = { multi_role_passcodeCB, // Passcode callback multi_role_pairStateCB // Pairing state callback }; /********************************************************************* * PUBLIC FUNCTIONS */ /********************************************************************* * @fn multi_role_spin * * @brief Spin forever * * @param none */ static void multi_role_spin(void) { volatile uint8_t x = 0; while(1) { x++; } } /********************************************************************* * @fn multi_role_createTask * * @brief Task creation function for multi_role. * * @param None. * * @return None. */ void multi_role_createTask(void) { Task_Params taskParams; // Configure task Task_Params_init(&taskParams); taskParams.stack = mrTaskStack; taskParams.stackSize = MR_TASK_STACK_SIZE; taskParams.priority = MR_TASK_PRIORITY; Task_construct(&mrTask, multi_role_taskFxn, &taskParams, NULL); } /********************************************************************* * @fn multi_role_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 multi_role_init(void) { BLE_LOG_INT_TIME(0, BLE_LOG_MODULE_APP, "APP : ---- init ", MR_TASK_PRIORITY); // Create the menu //multi_role_build_menu(); // ****************************************************************** // 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); // Open Display. dispHandle = Display_open(Display_Type_ANY, NULL); // Disable all items in the main menu //tbm_setItemStatus(&mrMenuMain, MR_ITEM_NONE, MR_ITEM_ALL); // Init two button menu // tbm_initTwoBtnMenu(dispHandle, &mrMenuMain, 5, multi_role_menuSwitchCb); Display_printf(dispHandle, MR_ROW_SEPARATOR, 0, "===================="); //clear out connection menu // tbm_setItemStatus(&mrMenuConnect, MR_ITEM_NONE, MR_ITEM_ALL); // Create an RTOS queue for message from profile to be sent to app. appMsgQueue = Util_constructQueue(&appMsg); // Create one-shot clock for internal periodic events. Util_constructClock(&clkPeriodic, multi_role_clockHandler, MR_PERIODIC_EVT_PERIOD, 0, false, (UArg)&periodicUpdateData); // Init key debouncer //Board_initKeys(multi_role_keyChangeHandler); // Initialize Connection List multi_role_clearConnListEntry(LINKDB_CONNHANDLE_ALL); // 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, (void *)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); } // 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, used by GAPBondMgr to look for RPAO characteristic for network privacy GATT_InitClient(); // Register to receive incoming ATT Indications/Notifications GATT_RegisterForInd(selfEntity); // Setup the GAP Bond Manager setBondManagerParameters(); // Initialize GATT attributes GGS_AddService(GATT_ALL_SERVICES); // GAP GATTServApp_AddService(GATT_ALL_SERVICES); // GATT attributes 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(&multi_role_simpleProfileCBs); // Start Bond Manager and register callback VOID GAPBondMgr_Register(&multi_role_BondMgrCBs); // 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); BLE_LOG_INT_TIME(0, BLE_LOG_MODULE_APP, "APP : ---- call GAP_DeviceInit", GAP_PROFILE_PERIPHERAL | GAP_PROFILE_CENTRAL); //Initialize GAP layer for Peripheral and Central role and register to receive GAP events GAP_DeviceInit(GAP_PROFILE_PERIPHERAL | GAP_PROFILE_OBSERVER, selfEntity, addrMode, &pRandomAddress); } /********************************************************************* * @fn multi_role_taskFxn * * @brief Application task entry point for the multi_role. * * @param a0, a1 - not used. * * @return None. */ static void multi_role_taskFxn(UArg a0, UArg a1) { // Initialize application multi_role_init(); //Setup scanning // multi_role_scanInit(); // 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, MR_ALL_EVENTS, ICALL_TIMEOUT_FOREVER); if (events) { ICall_EntityID dest; ICall_ServiceEnum src; ICall_HciExtEvt *pMsg = NULL; if (ICall_fetchServiceMsg(&src, &dest, (void **)&pMsg) == ICALL_ERRNO_SUCCESS) { uint8_t 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 = multi_role_processStackMsg((ICall_Hdr *)pMsg); } } if (pMsg && safeToDealloc) { ICall_freeMsg(pMsg); } } // If RTOS queue is not empty, process app message. if (events & MR_QUEUE_EVT) { while (!Queue_empty(appMsgQueue)) { mrEvt_t *pMsg = (mrEvt_t *)Util_dequeueMsg(appMsgQueue); if (pMsg) { // Process message. multi_role_processAppMsg(pMsg); // Free the space from the message. ICall_free(pMsg); } } } } } } /********************************************************************* * @fn multi_role_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 multi_role_processStackMsg(ICall_Hdr *pMsg) { uint8_t safeToDealloc = TRUE; BLE_LOG_INT_INT(0, BLE_LOG_MODULE_APP, "APP : Stack msg status=%d, event=0x%x\n", pMsg->status, pMsg->event); switch (pMsg->event) { case GAP_MSG_EVENT: //multi_role_processRoleEvent((gapMultiRoleEvent_t *)pMsg); multi_role_processGapMsg((gapEventHdr_t*) pMsg); break; case GATT_MSG_EVENT: // Process GATT message safeToDealloc = multi_role_processGATTMsg((gattMsgEvent_t *)pMsg); break; case HCI_GAP_EVENT_EVENT: { // Process HCI message switch (pMsg->status) { case HCI_COMMAND_COMPLETE_EVENT_CODE: break; case HCI_BLE_HARDWARE_ERROR_EVENT_CODE: AssertHandler(HAL_ASSERT_CAUSE_HARDWARE_ERROR,0); break; // HCI Commands Events case HCI_COMMAND_STATUS_EVENT_CODE: { hciEvt_CommandStatus_t *pMyMsg = (hciEvt_CommandStatus_t *)pMsg; switch ( pMyMsg->cmdOpcode ) { case HCI_LE_SET_PHY: { if (pMyMsg->cmdStatus == HCI_ERROR_CODE_UNSUPPORTED_REMOTE_FEATURE) { Display_printf(dispHandle, MR_ROW_CUR_CONN, 0, "PHY Change failure, peer does not support this"); } else { Display_printf(dispHandle, MR_ROW_CUR_CONN, 0, "PHY Update Status: 0x%02x", pMyMsg->cmdStatus); } } break; case HCI_DISCONNECT: break; default: { Display_printf(dispHandle, MR_ROW_NON_CONN, 0, "Unknown Cmd Status: 0x%04x::0x%02x", pMyMsg->cmdOpcode, pMyMsg->cmdStatus); } break; } } break; // LE Events case HCI_LE_EVENT_CODE: { hciEvt_BLEPhyUpdateComplete_t *pPUC = (hciEvt_BLEPhyUpdateComplete_t*) pMsg; if (pPUC->BLEEventCode == HCI_BLE_PHY_UPDATE_COMPLETE_EVENT) { if (pPUC->status != SUCCESS) { Display_printf(dispHandle, MR_ROW_ANY_CONN, 0, "%s: PHY change failure", multi_role_getConnAddrStr(pPUC->connHandle)); } else { Display_printf(dispHandle, MR_ROW_ANY_CONN, 0, "%s: PHY updated to %s", multi_role_getConnAddrStr(pPUC->connHandle), // Only symmetrical PHY is supported. // rxPhy should be equal to txPhy. (pPUC->rxPhy == PHY_UPDATE_COMPLETE_EVENT_1M) ? "1 Mbps" : (pPUC->rxPhy == PHY_UPDATE_COMPLETE_EVENT_2M) ? "2 Mbps" : (pPUC->rxPhy == PHY_UPDATE_COMPLETE_EVENT_CODED) ? "Coded" : "Unexpected PHY Value"); } } break; } default: break; } break; } case L2CAP_SIGNAL_EVENT: // place holder for L2CAP Connection Parameter Reply break; default: // Do nothing break; } return (safeToDealloc); } /********************************************************************* * @fn multi_role_processGapMsg * * @brief GAP message processing function. * * @param pMsg - pointer to event message structure * * @return none */ static void multi_role_processGapMsg(gapEventHdr_t *pMsg) { switch (pMsg->opcode) { case GAP_DEVICE_INIT_DONE_EVENT: { gapDeviceInitDoneEvent_t *pPkt = (gapDeviceInitDoneEvent_t *)pMsg; BLE_LOG_INT_TIME(0, BLE_LOG_MODULE_APP, "APP : ---- got GAP_DEVICE_INIT_DONE_EVENT", 0); 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); BLE_LOG_INT_INT(0, BLE_LOG_MODULE_APP, "APP : ---- start advert %d,%d\n", 0, 0); //Setup and start advertising multi_role_advertInit(); multi_role_scanInit(); } //Setup scanning multi_role_scanInit(); mrMaxPduSize = pPkt->dataPktLen; // Enable "Discover Devices", "Set Scanning PHY", and "Set Address Type" // in the main menu // tbm_setItemStatus(&mrMenuMain, MR_ITEM_STARTDISC | MR_ITEM_ADVERTISE | MR_ITEM_PHY, MR_ITEM_NONE); //Display initialized state status Display_printf(dispHandle, MR_ROW_NUM_CONN, 0, "Num Conns: %d", numConn); Display_printf(dispHandle, MR_ROW_NON_CONN, 0, "Initialized"); Display_printf(dispHandle, MR_ROW_MYADDRSS, 0, "Multi-Role Address: %s",(char *)Util_convertBdAddr2Str(pPkt->devAddr)); break; } case GAP_CONNECTING_CANCELLED_EVENT: { uint16_t itemsToEnable = MR_ITEM_STARTDISC| MR_ITEM_ADVERTISE | MR_ITEM_PHY; if (numConn > 0) { itemsToEnable |= MR_ITEM_SELECTCONN; } Display_printf(dispHandle, MR_ROW_NON_CONN, 0, "Conneting attempt cancelled"); // Enable "Discover Devices", "Connect To", and "Set Scanning PHY" // and disable everything else. tbm_setItemStatus(&mrMenuMain, itemsToEnable, MR_ITEM_ALL & ~itemsToEnable); break; } case GAP_LINK_ESTABLISHED_EVENT: { uint16_t connHandle = ((gapEstLinkReqEvent_t*) pMsg)->connectionHandle; uint8_t role = ((gapEstLinkReqEvent_t*) pMsg)->connRole; uint8_t* pAddr = ((gapEstLinkReqEvent_t*) pMsg)->devAddr; uint8_t connIndex; uint32_t itemsToDisable = MR_ITEM_STOPDISC | MR_ITEM_CANCELCONN; uint8_t* pStrAddr; uint8_t i; uint8_t numConnectable = 0; BLE_LOG_INT_TIME(0, BLE_LOG_MODULE_APP, "APP : ---- got GAP_LINK_ESTABLISHED_EVENT", 0); // Add this connection info to the list connIndex = multi_role_addConnInfo(connHandle, pAddr, role); // connIndex cannot be equal to or greater than MAX_NUM_BLE_CONNS MULTIROLE_ASSERT(connIndex < MAX_NUM_BLE_CONNS); connList[connIndex].charHandle = 0; Util_startClock(&clkPeriodic); pStrAddr = (uint8_t*) Util_convertBdAddr2Str(connList[connIndex].addr); Display_printf(dispHandle, MR_ROW_NON_CONN, 0, "Connected to %s", pStrAddr); Display_printf(dispHandle, MR_ROW_NUM_CONN, 0, "Num Conns: %d", numConn); // Disable "Connect To" until another discovery is performed itemsToDisable |= MR_ITEM_CONNECT; // If we already have maximum allowed number of connections, // disable device discovery and additional connection making. if (numConn >= MAX_NUM_BLE_CONNS) { itemsToDisable |= MR_ITEM_STARTDISC; } for (i = 0; i < TBM_GET_NUM_ITEM(&mrMenuConnect); i++) { if (!memcmp(TBM_GET_ACTION_DESC(&mrMenuConnect, i), pStrAddr, MR_ADDR_STR_SIZE)) { // Disable this device from the connection choices tbm_setItemStatus(&mrMenuConnect, MR_ITEM_NONE, 1 << i); } else if (TBM_IS_ITEM_ACTIVE(&mrMenuConnect, i)) { numConnectable++; } } // Enable/disable Main menu items properly tbm_setItemStatus(&mrMenuMain, MR_ITEM_ALL & ~(itemsToDisable), itemsToDisable); if (numConn < MAX_NUM_BLE_CONNS) { // Start advertising since there is room for more connections GapAdv_enable(advHandle, GAP_ADV_ENABLE_OPTIONS_USE_MAX, 0); } else { // Stop advertising since there is no room for more connections GapAdv_disable(advHandle); } break; } case GAP_LINK_TERMINATED_EVENT: { uint16_t connHandle = ((gapTerminateLinkEvent_t*) pMsg)->connectionHandle; uint8_t connIndex; uint32_t itemsToEnable = MR_ITEM_STARTDISC | MR_ITEM_ADVERTISE | MR_ITEM_PHY; uint8_t* pStrAddr; uint8_t i; uint8_t numConnectable = 0; BLE_LOG_INT_STR(0, BLE_LOG_MODULE_APP, "APP : GAP msg: status=%d, opcode=%s\n", 0, "GAP_LINK_TERMINATED_EVENT"); // Mark this connection deleted in the connected device list. connIndex = multi_role_removeConnInfo(connHandle); // connIndex cannot be equal to or greater than MAX_NUM_BLE_CONNS MULTIROLE_ASSERT(connIndex < MAX_NUM_BLE_CONNS); pStrAddr = (uint8_t*) Util_convertBdAddr2Str(connList[connIndex].addr); Display_printf(dispHandle, MR_ROW_NON_CONN, 0, "%s is disconnected", pStrAddr); Display_printf(dispHandle, MR_ROW_NUM_CONN, 0, "Num Conns: %d", numConn); for (i = 0; i < TBM_GET_NUM_ITEM(&mrMenuConnect); i++) { if (!memcmp(TBM_GET_ACTION_DESC(&mrMenuConnect, i), pStrAddr, MR_ADDR_STR_SIZE)) { // Enable this device in the connection choices tbm_setItemStatus(&mrMenuConnect, 1 << i, MR_ITEM_NONE); } if (TBM_IS_ITEM_ACTIVE(&mrMenuConnect, i)) { numConnectable++; } } // Start advertising since there is room for more connections GapAdv_enable(advHandle, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0); if (numConn > 0) { // There still is an active connection to select itemsToEnable |= MR_ITEM_SELECTCONN; } // If no active connections if (numConn == 0) { // Stop periodic clock Util_stopClock(&clkPeriodic); tbm_setItemStatus(&mrMenuMain, TBM_ITEM_NONE, TBM_ITEM_ALL); tbm_setItemStatus(&mrMenuMain, MR_ITEM_NONE, MR_ITEM_ALL ^(MR_ITEM_STARTDISC | MR_ITEM_ADVERTISE | MR_ITEM_PHY)); } // Enable/disable items properly. tbm_setItemStatus(&mrMenuMain, itemsToEnable, MR_ITEM_ALL & ~itemsToEnable); // If we are in the context which the teminated connection was associated // with, go to main menu. if (connHandle == mrConnHandle) { tbm_goTo(&mrMenuMain); } break; } case GAP_UPDATE_LINK_PARAM_REQ_EVENT: { gapUpdateLinkParamReqReply_t rsp; gapUpdateLinkParamReqEvent_t *pReq = (gapUpdateLinkParamReqEvent_t *)pMsg; rsp.connectionHandle = pReq->req.connectionHandle; rsp.signalIdentifier = pReq->req.signalIdentifier; // 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; } case GAP_LINK_PARAM_UPDATE_EVENT: { gapLinkUpdateEvent_t *pPkt = (gapLinkUpdateEvent_t *)pMsg; // Get the address from the connection handle linkDBInfo_t linkInfo; if (linkDB_GetInfo(pPkt->connectionHandle, &linkInfo) == SUCCESS) { if(pPkt->status == SUCCESS) { Display_printf(dispHandle, MR_ROW_CUR_CONN, 0, "Updated: %s, connTimeout:%d", Util_convertBdAddr2Str(linkInfo.addr), linkInfo.connTimeout*CONN_TIMEOUT_MS_CONVERSION); } else { // Display the address of the connection update failure Display_printf(dispHandle, MR_ROW_CUR_CONN, 0, "Update Failed 0x%h: %s", pPkt->opcode, Util_convertBdAddr2Str(linkInfo.addr)); } } // Check if there are any queued parameter updates mrConnHandleEntry_t *connHandleEntry = (mrConnHandleEntry_t *)List_get(¶mUpdateList); if (connHandleEntry != NULL) { // Attempt to send queued update now multi_role_processParamUpdate(connHandleEntry->connHandle); // Free list element ICall_free(connHandleEntry); } break; } #if defined ( NOTIFY_PARAM_UPDATE_RJCT ) case GAP_LINK_PARAM_UPDATE_REJECT_EVENT: { linkDBInfo_t linkInfo; gapLinkUpdateEvent_t *pPkt = (gapLinkUpdateEvent_t *)pMsg; // Get the address from the connection handle linkDB_GetInfo(pPkt->connectionHandle, &linkInfo); // Display the address of the connection update failure Display_printf(dispHandle, MR_ROW_CUR_CONN, 0, "Peer Device's Update Request Rejected 0x%h: %s", pPkt->opcode, Util_convertBdAddr2Str(linkInfo.addr)); break; } #endif default: break; } } /********************************************************************* * @fn multi_role_scanInit * * @brief Setup initial device scan settings. * * @return None. */ static void multi_role_scanInit(void) { uint8_t temp8; uint16_t temp16; // Setup scanning // For more information, see the GAP section in the User's Guide: // http://software-dl.ti.com/lprf/ble5stack-latest/ // Register callback to process Scanner events GapScan_registerCb(multi_role_scanCB, NULL); // Set Scanner Event Mask GapScan_setEventMask(GAP_EVT_SCAN_ENABLED | GAP_EVT_SCAN_DISABLED | GAP_EVT_ADV_REPORT); // Set Scan PHY parameters GapScan_setPhyParams(DEFAULT_SCAN_PHY, SCAN_TYPE_ACTIVE, DEFAULT_SCAN_INTERVAL, DEFAULT_SCAN_WINDOW); // Set Advertising report fields to keep temp16 = ADV_RPT_FIELDS; GapScan_setParam(SCAN_PARAM_RPT_FIELDS, &temp16); // Set Scanning Primary PHY temp8 = DEFAULT_SCAN_PHY; GapScan_setParam(SCAN_PARAM_PRIM_PHYS, &temp8); // Set LL Duplicate Filter temp8 = SCANNER_DUPLICATE_FILTER; GapScan_setParam(SCAN_PARAM_FLT_DUP, &temp8); // Set PDU type filter - // Only 'Connectable' and 'Complete' packets are desired. // It doesn't matter if received packets are // whether Scannable or Non-Scannable, whether Directed or Undirected, // whether Scan_Rsp's or Advertisements, and whether Legacy or Extended. temp16 = SCAN_FLT_PDU_NONCONNECTABLE_ONLY | SCAN_FLT_PDU_COMPLETE_ONLY; GapScan_setParam(SCAN_PARAM_FLT_PDU_TYPE, &temp16); /* // Set initiating PHY parameters GapInit_setPhyParam(DEFAULT_INIT_PHY, INIT_PHYPARAM_CONN_INT_MIN, INIT_PHYPARAM_MIN_CONN_INT); GapInit_setPhyParam(DEFAULT_INIT_PHY, INIT_PHYPARAM_CONN_INT_MAX, INIT_PHYPARAM_MAX_CONN_INT);*/ // Set initiating PHY parameters GapInit_setPhyParam(DEFAULT_SCAN_PHY, INIT_PHYPARAM_CONN_INT_MIN, 0); GapInit_setPhyParam(DEFAULT_SCAN_PHY, INIT_PHYPARAM_CONN_INT_MAX, 0); } /********************************************************************* * @fn multi_role_scanInit * * @brief Setup initial advertisment and start advertising from device init. * * @return None. */ static void multi_role_advertInit(void) { uint8_t status = FAILURE; // Setup and start Advertising // For more information, see the GAP section in the User's Guide: // http://software-dl.ti.com/lprf/ble5stack-latest/tera BLE_LOG_INT_INT(0, BLE_LOG_MODULE_APP, "APP : ---- call GapAdv_create set=%d,%d\n", 1, 0); // Create Advertisement set #1 and assign handle GapAdv_create(&multi_role_advCB, &advParams1, &advHandle); // Load advertising data for set #1 that is statically allocated by the app GapAdv_loadByHandle(advHandle, GAP_ADV_DATA_TYPE_ADV, sizeof(advData1), advData1); // Load scan response data for set #1 that is statically allocated by the app GapAdv_loadByHandle(advHandle, GAP_ADV_DATA_TYPE_SCAN_RSP, sizeof(scanResData1), scanResData1); // Set event mask for set #1 GapAdv_setEventMask(advHandle, GAP_ADV_EVT_MASK_START_AFTER_ENABLE | GAP_ADV_EVT_MASK_END_AFTER_DISABLE | GAP_ADV_EVT_MASK_SET_TERMINATED); BLE_LOG_INT_TIME(0, BLE_LOG_MODULE_APP, "APP : ---- GapAdv_enable", 0); // Enable legacy advertising for set #1 status = GapAdv_enable(advHandle, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0); if(status != SUCCESS) { mrIsAdvertising = false; Display_printf(dispHandle, MR_ROW_ADVERTIS, 0, "Error: Failed to Start Advertising!"); } if (addrMode > ADDRMODE_RANDOM) { multi_role_updateRPA(); // Create one-shot clock for RPA check event. Util_constructClock(&clkRpaRead, multi_role_clockHandler, READ_RPA_PERIOD, 0, true, (UArg) &argRpaRead); } } /********************************************************************* * @fn multi_role_advCB * * @brief GapAdv module callback * * @param pMsg - message to process */ static void multi_role_advCB(uint32_t event, void *pBuf, uintptr_t arg) { mrGapAdvEventData_t *pData = ICall_malloc(sizeof(mrGapAdvEventData_t)); if (pData) { pData->event = event; pData->pBuf = pBuf; if(multi_role_enqueueMsg(MR_EVT_ADV, pData) != SUCCESS) { ICall_free(pData); } } } /********************************************************************* * @fn multi_role_processGATTMsg * * @brief Process GATT messages and events. * * @return TRUE if safe to deallocate incoming message, FALSE otherwise. */ static uint8_t multi_role_processGATTMsg(gattMsgEvent_t *pMsg) { // Get connection index from handle uint8_t connIndex = multi_role_getConnIndex(pMsg->connHandle); MULTIROLE_ASSERT(connIndex < MAX_NUM_BLE_CONNS); if (pMsg->method == ATT_FLOW_CTRL_VIOLATED_EVENT) { // ATT request-response or indication-confirmation flow control is // violated. All subsequent ATT requests or indications will be dropped. // The app is informed in case it wants to drop the connection. // Display the opcode of the message that caused the violation. Display_printf(dispHandle, MR_ROW_CUR_CONN, 0, "FC Violated: %d", pMsg->msg.flowCtrlEvt.opcode); } else if (pMsg->method == ATT_MTU_UPDATED_EVENT) { // MTU size updated Display_printf(dispHandle, MR_ROW_CUR_CONN, 0, "MTU Size: %d", pMsg->msg.mtuEvt.MTU); } // Messages from GATT server if (linkDB_Up(pMsg->connHandle)) { if ((pMsg->method == ATT_READ_RSP) || ((pMsg->method == ATT_ERROR_RSP) && (pMsg->msg.errorRsp.reqOpcode == ATT_READ_REQ))) { if (pMsg->method == ATT_ERROR_RSP) { Display_printf(dispHandle, MR_ROW_CUR_CONN, 0, "Read Error %d", pMsg->msg.errorRsp.errCode); } else { // After a successful read, display the read value Display_printf(dispHandle, MR_ROW_CUR_CONN, 0, "Read rsp: %d", pMsg->msg.readRsp.pValue[0]); } } else if ((pMsg->method == ATT_WRITE_RSP) || ((pMsg->method == ATT_ERROR_RSP) && (pMsg->msg.errorRsp.reqOpcode == ATT_WRITE_REQ))) { if (pMsg->method == ATT_ERROR_RSP) { Display_printf(dispHandle, MR_ROW_CUR_CONN, 0, "Write Error %d", pMsg->msg.errorRsp.errCode); } else { // After a succesful write, display the value that was written and // increment value Display_printf(dispHandle, MR_ROW_CUR_CONN, 0, "Write sent: %d", charVal); } tbm_goTo(&mrMenuPerConn); } else if (connList[connIndex].discState != BLE_DISC_STATE_IDLE) { multi_role_processGATTDiscEvent(pMsg); } } // Else - in case a GATT message came after a connection has dropped, ignore it. // 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 multi_role_processParamUpdate * * @brief Process connection parameters update * * @param connHandle - connection handle to update * * @return None. */ static void multi_role_processParamUpdate(uint16_t connHandle) { gapUpdateLinkParamReq_t req; uint8_t connIndex; req.connectionHandle = connHandle; #ifdef DEFAULT_SEND_PARAM_UPDATE_REQ req.connLatency = DEFAULT_DESIRED_SLAVE_LATENCY; req.connTimeout = DEFAULT_DESIRED_CONN_TIMEOUT; req.intervalMin = DEFAULT_DESIRED_MIN_CONN_INTERVAL; req.intervalMax = DEFAULT_DESIRED_MAX_CONN_INTERVAL; #endif connIndex = multi_role_getConnIndex(connHandle); MULTIROLE_ASSERT(connIndex < MAX_NUM_BLE_CONNS); // Deconstruct the clock object Clock_destruct(connList[connIndex].pUpdateClock); // Free clock struct, only in case it is not NULL if (connList[connIndex].pUpdateClock != NULL) { ICall_free(connList[connIndex].pUpdateClock); connList[connIndex].pUpdateClock = NULL; } // Free ParamUpdateEventData, only in case it is not NULL if (connList[connIndex].pParamUpdateEventData != NULL) { ICall_free(connList[connIndex].pParamUpdateEventData); } // Send parameter update bStatus_t status = GAP_UpdateLinkParamReq(&req); // If there is an ongoing update, queue this for when the udpate completes if (status == bleAlreadyInRequestedMode) { mrConnHandleEntry_t *connHandleEntry = ICall_malloc(sizeof(mrConnHandleEntry_t)); if (connHandleEntry) { connHandleEntry->connHandle = connHandle; List_put(¶mUpdateList, (List_Elem *)connHandleEntry); } } } /********************************************************************* * @fn multi_role_processAppMsg * * @brief Process an incoming callback from a profile. * * @param pMsg - message to process * * @return None. */int cnt=0; static void multi_role_processAppMsg(mrEvt_t *pMsg) { bool safeToDealloc = TRUE; if (pMsg->event <= APP_EVT_EVENT_MAX) { BLE_LOG_INT_STR(0, BLE_LOG_MODULE_APP, "APP : App msg status=%d, event=%s\n", 0, appEventStrings[pMsg->event]); } else { BLE_LOG_INT_INT(0, BLE_LOG_MODULE_APP, "APP : App msg status=%d, event=0x%x\n", 0, pMsg->event); } switch (pMsg->event) { case MR_EVT_CHAR_CHANGE: { multi_role_processCharValueChangeEvt(*(uint8_t*)(pMsg->pData)); break; } case MR_EVT_KEY_CHANGE: { multi_role_handleKeys(*(uint8_t *)(pMsg->pData)); break; } case MR_EVT_ADV_REPORT: { GapScan_Evt_AdvRpt_t* pAdvRpt = (GapScan_Evt_AdvRpt_t*) (pMsg->pData); #if (DEFAULT_DEV_DISC_BY_SVC_UUID == TRUE) if (multi_role_findSvcUuid(SIMPLEPROFILE_SERV_UUID, pAdvRpt->pData, pAdvRpt->dataLen)) { multi_role_addScanInfo(pAdvRpt->addr, pAdvRpt->addrType); Display_printf(dispHandle, MR_ROW_CUR_CONN, 0, "Discovered: %s", Util_convertBdAddr2Str(pAdvRpt->addr)); } #else // !DEFAULT_DEV_DISC_BY_SVC_UUID Display_printf(dispHandle, MR_ROW_CUR_CONN, 0, "Discovered: %s", Util_convertBdAddr2Str(pAdvRpt->addr)); #endif // DEFAULT_DEV_DISC_BY_SVC_UUID cnt++; if(findpat( Util_convertBdAddr2Str(pAdvRpt->addr),"0xF05ECD39E1E7",14)>-1){ //F0:5E:CD:39:E1:E6 //tele-tpms // varcnt++;x5C17CF5D4AD8 0xF9E0C82045D4 // Display_printf(dispHandle, DEVICE_NAME19, 0, "ADVT: %s", Util_convertBytes2Str(pAdvRpt->pData, pAdvRpt->dataLen)); // Calculate the offset to the last 4 bytes int offset = pAdvRpt->dataLen - 4; // Check if the offset is non-negative if (offset >= 0) { // Print the last 4 bytes Display_printf(dispHandle,DEVICE_NAME20,0,"ADVT2: %s", Util_convertBytes2Str(&pAdvRpt->pData[offset], 4)); } } if(findpat( Util_convertBdAddr2Str(pAdvRpt->addr),"0x907BC68422D3",14)>-1){ //F0:5E:CD:39:E1:E6 // varcnt++;x5C17CF5D4AD8 0xF9E0C82045D4 // Display_printf(dispHandle, DEVICE_NAME19, 0, "ADVT: %s", Util_convertBytes2Str(pAdvRpt->pData, pAdvRpt->dataLen)); // Calculate the offset to the last 4 bytes int offset = pAdvRpt->dataLen - 4; // Check if the offset is non-negative if (offset >= 0) { // Print the last 4 bytes Display_printf(dispHandle,DEVICE_NAME21,0,"ADVT2: %s", Util_convertBytes2Str(&pAdvRpt->pData[offset], 4)); } } //#if 1 if(cnt != 19) { if(cnt == 1) { Display_printf(dispHandle, DEVICE_NAME0, 0, "1: %s \n", Util_convertBdAddr2Str(pAdvRpt->addr)); } if(cnt == 2){ Display_printf(dispHandle, DEVICE_NAME1, 0, "2: %s \n", Util_convertBdAddr2Str(pAdvRpt->addr)); } if(cnt == 3){ Display_printf(dispHandle, DEVICE_NAME2, 0, "3: %s \n", Util_convertBdAddr2Str(pAdvRpt->addr)); } if(cnt == 4){ Display_printf(dispHandle, DEVICE_NAME3, 0, "4: %s \n", Util_convertBdAddr2Str(pAdvRpt->addr)); } if(cnt == 5){ Display_printf(dispHandle, DEVICE_NAME4, 0, "5: %s \n", Util_convertBdAddr2Str(pAdvRpt->addr)); } if(cnt == 6){ Display_printf(dispHandle, DEVICE_NAME5, 0, "6: %s \n", Util_convertBdAddr2Str(pAdvRpt->addr)); } if(cnt == 7){ Display_printf(dispHandle, DEVICE_NAME6, 0, "7: %s \n", Util_convertBdAddr2Str(pAdvRpt->addr)); } if(cnt == 8){ Display_printf(dispHandle, DEVICE_NAME7, 0, "8: %s \n", Util_convertBdAddr2Str(pAdvRpt->addr)); } if(cnt == 9){ Display_printf(dispHandle, DEVICE_NAME8, 0, "9: %s \n", Util_convertBdAddr2Str(pAdvRpt->addr)); } if(cnt == 10){ Display_printf(dispHandle, DEVICE_NAME9, 0, "9: %s \n", Util_convertBdAddr2Str(pAdvRpt->addr)); } if(cnt == 11){ Display_printf(dispHandle, DEVICE_NAME10, 0, "10: %s \n", Util_convertBdAddr2Str(pAdvRpt->addr)); } if(cnt == 12){ Display_printf(dispHandle, DEVICE_NAME11, 0, "11: %s \n", Util_convertBdAddr2Str(pAdvRpt->addr)); } if(cnt == 13){ Display_printf(dispHandle, DEVICE_NAME12, 0, "12: %s \n", Util_convertBdAddr2Str(pAdvRpt->addr)); } if(cnt == 14){ Display_printf(dispHandle, DEVICE_NAME13, 0, "13: %s \n", Util_convertBdAddr2Str(pAdvRpt->addr)); } if(cnt == 15){ Display_printf(dispHandle, DEVICE_NAME14, 0, "14: %s \n", Util_convertBdAddr2Str(pAdvRpt->addr)); } if(cnt == 16){ Display_printf(dispHandle, DEVICE_NAME15, 0, "15: %s \n", Util_convertBdAddr2Str(pAdvRpt->addr)); } if(cnt == 17){ Display_printf(dispHandle, DEVICE_NAME16, 0, "16: %s \n", Util_convertBdAddr2Str(pAdvRpt->addr)); } if(cnt == 18){ Display_printf(dispHandle, DEVICE_NAME17, 0, "17: %s \n", Util_convertBdAddr2Str(pAdvRpt->addr)); } } else{ cnt = 0; Display_printf(dispHandle, DEVICE_NAME18, 0, "18: %s \n", Util_convertBdAddr2Str(pAdvRpt->addr)); } // Free scan payload data if (pAdvRpt->pData != NULL) { ICall_free(pAdvRpt->pData); } break; } case MR_EVT_SCAN_ENABLED: { // Disable everything but "Stop Discovering" on the menu // tbm_setItemStatus(&mrMenuMain, MR_ITEM_STOPDISC, // (MR_ITEM_ALL & ~MR_ITEM_STOPDISC)); Display_printf(dispHandle, DEVICE_NAME0, 0, "Discovering..."); break; } case MR_EVT_SCAN_DISABLED: { uint8_t numReport; uint8_t i; static uint8_t* pAddrs = NULL; uint8_t* pAddrTemp; uint16_t itemsToEnable = MR_ITEM_STARTDISC | MR_ITEM_ADVERTISE | MR_ITEM_PHY; #if (DEFAULT_DEV_DISC_BY_SVC_UUID == TRUE) numReport = numScanRes; #else // !DEFAULT_DEV_DISC_BY_SVC_UUID GapScan_Evt_AdvRpt_t advRpt; numReport = ((GapScan_Evt_End_t*) (pMsg->pData))->numReport; #endif // DEFAULT_DEV_DISC_BY_SVC_UUID Display_printf(dispHandle, MR_ROW_NON_CONN, 0, "%d devices discovered", numReport); if (numReport > 0) { // Also enable "Connect to" //itemsToEnable |= MR_ITEM_CONNECT; } if (numConn > 0) { // Also enable "Work with" // itemsToEnable |= MR_ITEM_SELECTCONN; } // Enable "Discover Devices", "Set Scanning PHY", and possibly // "Connect to" and/or "Work with". // Disable "Stop Discovering". // tbm_setItemStatus(&mrMenuMain, itemsToEnable, MR_ITEM_STOPDISC); if (pAddrs != NULL) { ICall_free(pAddrs); } // Allocate buffer to display addresses pAddrs = ICall_malloc(numReport * MR_ADDR_STR_SIZE); if (pAddrs == NULL) { numReport = 0; } // TBM_SET_NUM_ITEM(&mrMenuConnect, numReport); if (pAddrs != NULL) { pAddrTemp = pAddrs; for (i = 0; i < numReport; i++, pAddrTemp += MR_ADDR_STR_SIZE) { #if (DEFAULT_DEV_DISC_BY_SVC_UUID == TRUE) // Get the address from the list, convert it to string, and // copy the string to the address buffer memcpy(pAddrTemp, Util_convertBdAddr2Str(scanList[i].addr), MR_ADDR_STR_SIZE); #else // !DEFAULT_DEV_DISC_BY_SVC_UUID // Get the address from the report, convert it to string, and // copy the string to the address buffer GapScan_getAdvReport(i, &advRpt); memcpy(pAddrTemp, Util_convertBdAddr2Str(advRpt.addr), MR_ADDR_STR_SIZE); #endif // DEFAULT_DEV_DISC_BY_SVC_UUID // Assign the string to the corresponding action description of the menu // TBM_SET_ACTION_DESC(&mrMenuConnect, i, pAddrTemp); // tbm_setItemStatus(&mrMenuConnect, (1 << i) , TBM_ITEM_NONE); } // Disable any non-active scan results for(; i < DEFAULT_MAX_SCAN_RES; i++) { //tbm_setItemStatus(&mrMenuConnect, TBM_ITEM_NONE, (1 << i)); } } break; } case MR_EVT_SVC_DISC: { multi_role_startSvcDiscovery(); break; } case MR_EVT_ADV: { multi_role_processAdvEvent((mrGapAdvEventData_t*)(pMsg->pData)); break; } case MR_EVT_PAIRING_STATE: { multi_role_processPairState((mrPairStateData_t*)(pMsg->pData)); break; } case MR_EVT_PASSCODE_NEEDED: { multi_role_processPasscode((mrPasscodeData_t*)(pMsg->pData)); break; } case MR_EVT_SEND_PARAM_UPDATE: { // Extract connection handle from data uint16_t locConnHandle = *(uint16_t *)(((mrClockEventData_t *)pMsg->pData)->data); multi_role_processParamUpdate(locConnHandle); safeToDealloc = FALSE; break; } case MR_EVT_PERIODIC: { multi_role_performPeriodicTask(); break; } case MR_EVT_READ_RPA: { multi_role_updateRPA(); break; } case MR_EVT_INSUFFICIENT_MEM: { // We are running out of memory. Display_printf(dispHandle, MR_ROW_ANY_CONN, 0, "Insufficient Memory"); // We might be in the middle of scanning, try stopping it. GapScan_disable(); break; } default: // Do nothing. break; } if ((safeToDealloc == TRUE) && (pMsg->pData != NULL)) { ICall_free(pMsg->pData); } } /********************************************************************* * @fn multi_role_processAdvEvent * * @brief Process advertising event in app context * * @param pEventData */ static void multi_role_processAdvEvent(mrGapAdvEventData_t *pEventData) { switch (pEventData->event) { case GAP_EVT_ADV_START_AFTER_ENABLE: BLE_LOG_INT_TIME(0, BLE_LOG_MODULE_APP, "APP : ---- GAP_EVT_ADV_START_AFTER_ENABLE", 0); mrIsAdvertising = true; Display_printf(dispHandle, MR_ROW_ADVERTIS, 0, "Adv Set %d Enabled", *(uint8_t *)(pEventData->pBuf)); break; case GAP_EVT_ADV_END_AFTER_DISABLE: mrIsAdvertising = false; Display_printf(dispHandle, MR_ROW_ADVERTIS, 0, "Adv Set %d Disabled", *(uint8_t *)(pEventData->pBuf)); break; case GAP_EVT_ADV_START: Display_printf(dispHandle, MR_ROW_ADVERTIS, 0, "Adv Started %d Enabled", *(uint8_t *)(pEventData->pBuf)); break; case GAP_EVT_ADV_END: Display_printf(dispHandle, MR_ROW_ADVERTIS, 0, "Adv Ended %d Disabled", *(uint8_t *)(pEventData->pBuf)); break; case GAP_EVT_ADV_SET_TERMINATED: { mrIsAdvertising = false; #ifndef Display_DISABLE_ALL GapAdv_setTerm_t *advSetTerm = (GapAdv_setTerm_t *)(pEventData->pBuf); #endif Display_printf(dispHandle, MR_ROW_ADVERTIS, 0, "Adv Set %d disabled after conn %d", advSetTerm->handle, advSetTerm->connHandle ); } 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 (DEFAULT_DEV_DISC_BY_SVC_UUID == TRUE) /********************************************************************* * @fn multi_role_findSvcUuid * * @brief Find a given UUID in an advertiser's service UUID list. * * @return TRUE if service UUID found */ static bool multi_role_findSvcUuid(uint16_t uuid, uint8_t *pData, uint16_t dataLen) { uint8_t adLen; uint8_t adType; uint8_t *pEnd; if (dataLen > 0) { pEnd = pData + dataLen - 1; // While end of data not reached while (pData < pEnd) { // Get length of next AD item adLen = *pData++; if (adLen > 0) { adType = *pData; // If AD type is for 16-bit service UUID if ((adType == GAP_ADTYPE_16BIT_MORE) || (adType == GAP_ADTYPE_16BIT_COMPLETE)) { pData++; adLen--; // For each UUID in list while (adLen >= 2 && pData < pEnd) { // Check for match if ((pData[0] == LO_UINT16(uuid)) && (pData[1] == HI_UINT16(uuid))) { // Match found return TRUE; } // Go to next pData += 2; adLen -= 2; } // Handle possible erroneous extra byte in UUID list if (adLen == 1) { pData++; } } else { // Go to next item pData += adLen; } } } } // Match not found return FALSE; } /********************************************************************* * @fn multi_role_addScanInfo * * @brief Add a device to the scanned device list * * @return none */ static void multi_role_addScanInfo(uint8_t *pAddr, uint8_t addrType) { uint8_t i; // If result count not at max if (numScanRes < DEFAULT_MAX_SCAN_RES) { // Check if device is already in scan results for (i = 0; i < numScanRes; i++) { if (memcmp(pAddr, scanList[i].addr , B_ADDR_LEN) == 0) { return; } } // Add addr to scan result list memcpy(scanList[numScanRes].addr, pAddr, B_ADDR_LEN); scanList[numScanRes].addrType = addrType; // Increment scan result count numScanRes++; } } #endif // DEFAULT_DEV_DISC_BY_SVC_UUID /********************************************************************* * @fn multi_role_scanCB * * @brief Callback called by GapScan module * * @param evt - event * @param msg - message coming with the event * @param arg - user argument * * @return none */ void multi_role_scanCB(uint32_t evt, void* pMsg, uintptr_t arg) { uint8_t event; if (evt & GAP_EVT_ADV_REPORT) { event = MR_EVT_ADV_REPORT; } else if (evt & GAP_EVT_SCAN_ENABLED) { event = MR_EVT_SCAN_ENABLED; } else if (evt & GAP_EVT_SCAN_DISABLED) { event = MR_EVT_SCAN_DISABLED; } else if (evt & GAP_EVT_INSUFFICIENT_MEMORY) { event = MR_EVT_INSUFFICIENT_MEM; } else { return; } if(multi_role_enqueueMsg(event, pMsg) != SUCCESS) { ICall_free(pMsg); } } /********************************************************************* * @fn multi_role_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 multi_role_charValueChangeCB(uint8_t paramID) { uint8_t *pData; // Allocate space for the event data. if ((pData = ICall_malloc(sizeof(uint8_t)))) { *pData = paramID; // Queue the event. if(multi_role_enqueueMsg(MR_EVT_CHAR_CHANGE, pData) != SUCCESS) { ICall_free(pData); } } } /********************************************************************* * @fn multi_role_enqueueMsg * * @brief Creates a message and puts the message in RTOS queue. * * @param event - message event. * @param state - message state. * @param pData - message data pointer. * * @return TRUE or FALSE */ static status_t multi_role_enqueueMsg(uint8_t event, void *pData) { uint8_t success; mrEvt_t *pMsg = ICall_malloc(sizeof(mrEvt_t)); // Create dynamic pointer to message. if (pMsg) { pMsg->event = event; pMsg->pData = pData; // Enqueue the message. success = Util_enqueueMsg(appMsgQueue, syncEvent, (uint8_t *)pMsg); return (success) ? SUCCESS : FAILURE; } return(bleMemAllocError); } /********************************************************************* * @fn multi_role_processCharValueChangeEvt * * @brief Process a pending Simple Profile characteristic value change * event. * * @param paramID - parameter ID of the value that was changed. */ static void multi_role_processCharValueChangeEvt(uint8_t paramId) { uint8_t newValue; switch(paramId) { case SIMPLEPROFILE_CHAR1: SimpleProfile_GetParameter(SIMPLEPROFILE_CHAR1, &newValue); Display_printf(dispHandle, MR_ROW_CHARSTAT, 0, "Char 1: %d", (uint16_t)newValue); break; case SIMPLEPROFILE_CHAR3: SimpleProfile_GetParameter(SIMPLEPROFILE_CHAR3, &newValue); Display_printf(dispHandle, MR_ROW_CHARSTAT, 0, "Char 3: %d", (uint16_t)newValue); break; default: // should not reach here! break; } } /********************************************************************* * @fn multi_role_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 multi_role_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 multi_role_updateRPA * * @brief Read the current RPA from the stack and update display * if the RPA has changed. * * @param None. * * @return None. */ static void multi_role_updateRPA(void) { uint8_t* pRpaNew; // Read the current RPA. pRpaNew = GAP_GetDevAddress(FALSE); if (memcmp(pRpaNew, rpa, B_ADDR_LEN)) { // If the RPA has changed, update the display Display_printf(dispHandle, MR_ROW_RPA, 0, "RP Addr: %s", Util_convertBdAddr2Str(pRpaNew)); memcpy(rpa, pRpaNew, B_ADDR_LEN); } } /********************************************************************* * @fn multi_role_clockHandler * * @brief Handler function for clock timeouts. * * @param arg - event type * * @return None. */ static void multi_role_clockHandler(UArg arg) { mrClockEventData_t *pData = (mrClockEventData_t *)arg; if (pData->event == MR_EVT_PERIODIC) { // Start the next period Util_startClock(&clkPeriodic); // Send message to perform periodic task multi_role_enqueueMsg(MR_EVT_PERIODIC, NULL); } else if (pData->event == MR_EVT_READ_RPA) { // Start the next period Util_startClock(&clkRpaRead); // Send message to read the current RPA multi_role_enqueueMsg(MR_EVT_READ_RPA, NULL); } else if (pData->event == MR_EVT_SEND_PARAM_UPDATE) { // Send message to app multi_role_enqueueMsg(MR_EVT_SEND_PARAM_UPDATE, pData); } } /********************************************************************* * @fn multi_role_keyChangeHandler * * @brief Key event handler function * * @param a0 - ignored * * @return none */ static void multi_role_keyChangeHandler(uint8_t keys) { uint8_t *pValue = ICall_malloc(sizeof(uint8_t)); if (pValue) { *pValue = keys; multi_role_enqueueMsg(MR_EVT_KEY_CHANGE, pValue); } } /********************************************************************* * @fn multi_role_handleKeys * * @brief Handles all key events for this device. * * @param keys - bit field for key events. Valid entries: * HAL_KEY_SW_2 * HAL_KEY_SW_1 * * @return none */ static void multi_role_handleKeys(uint8_t keys) { uint32_t rtnVal = 0; if (keys & KEY_LEFT) { // Check if the key is still pressed if (PIN_getInputValue(CONFIG_PIN_BTN1) == 0) { tbm_buttonLeft(); } } else if (keys & KEY_RIGHT) { // Check if the key is still pressed rtnVal = PIN_getInputValue(CONFIG_PIN_BTN2); if (rtnVal == 0) { tbm_buttonRight(); } } } /********************************************************************* * @fn multi_role_processGATTDiscEvent * * @brief Process GATT discovery event * * @param pMsg - pointer to discovery event stack message * * @return none */ static void multi_role_processGATTDiscEvent(gattMsgEvent_t *pMsg) { uint8_t connIndex = multi_role_getConnIndex(pMsg->connHandle); MULTIROLE_ASSERT(connIndex < MAX_NUM_BLE_CONNS); if (connList[connIndex].discState == BLE_DISC_STATE_MTU) { // MTU size response received, discover simple service if (pMsg->method == ATT_EXCHANGE_MTU_RSP) { uint8_t uuid[ATT_BT_UUID_SIZE] = { LO_UINT16(SIMPLEPROFILE_SERV_UUID), HI_UINT16(SIMPLEPROFILE_SERV_UUID) }; connList[connIndex].discState = BLE_DISC_STATE_SVC; // Discovery simple service VOID GATT_DiscPrimaryServiceByUUID(pMsg->connHandle, uuid, ATT_BT_UUID_SIZE, selfEntity); } } else if (connList[connIndex].discState == BLE_DISC_STATE_SVC) { // Service found, store handles if (pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP && pMsg->msg.findByTypeValueRsp.numInfo > 0) { svcStartHdl = ATT_ATTR_HANDLE(pMsg->msg.findByTypeValueRsp.pHandlesInfo, 0); svcEndHdl = ATT_GRP_END_HANDLE(pMsg->msg.findByTypeValueRsp.pHandlesInfo, 0); } // If procedure complete if (((pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP) && (pMsg->hdr.status == bleProcedureComplete)) || (pMsg->method == ATT_ERROR_RSP)) { if (svcStartHdl != 0) { attReadByTypeReq_t req; // Discover characteristic connList[connIndex].discState = BLE_DISC_STATE_CHAR; req.startHandle = svcStartHdl; req.endHandle = svcEndHdl; req.type.len = ATT_BT_UUID_SIZE; req.type.uuid[0] = LO_UINT16(SIMPLEPROFILE_CHAR1_UUID); req.type.uuid[1] = HI_UINT16(SIMPLEPROFILE_CHAR1_UUID); VOID GATT_DiscCharsByUUID(pMsg->connHandle, &req, selfEntity); } } } else if (connList[connIndex].discState == BLE_DISC_STATE_CHAR) { // Characteristic found, store handle if ((pMsg->method == ATT_READ_BY_TYPE_RSP) && (pMsg->msg.readByTypeRsp.numPairs > 0)) { uint8_t connIndex = multi_role_getConnIndex(mrConnHandle); // connIndex cannot be equal to or greater than MAX_NUM_BLE_CONNS MULTIROLE_ASSERT(connIndex < MAX_NUM_BLE_CONNS); // Store the handle of the simpleprofile characteristic 1 value connList[connIndex].charHandle = BUILD_UINT16(pMsg->msg.readByTypeRsp.pDataList[3], pMsg->msg.readByTypeRsp.pDataList[4]); Display_printf(dispHandle, MR_ROW_CUR_CONN, 0, "Simple Svc Found"); // Now we can use GATT Read/Write tbm_setItemStatus(&mrMenuPerConn, MR_ITEM_GATTREAD | MR_ITEM_GATTWRITE, MR_ITEM_NONE); } connList[connIndex].discState = BLE_DISC_STATE_IDLE; } } /********************************************************************* * @fn multi_role_getConnIndex * * @brief Translates connection handle to index * * @param connHandle - the connection handle * * @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 uint16_t multi_role_getConnIndex(uint16_t connHandle) { uint8_t i; // Loop through connection for (i = 0; i < MAX_NUM_BLE_CONNS; i++) { // If matching connection handle found if (connList[i].connHandle == connHandle) { return i; } } // Not found if we got here return(MAX_NUM_BLE_CONNS); } #ifndef Display_DISABLE_ALL /********************************************************************* * @fn multi_role_getConnAddrStr * * @brief Return, in string form, the address of the peer associated with * the connHandle. * * @return A null-terminated string of the address. * if there is no match, NULL will be returned. */ static char* multi_role_getConnAddrStr(uint16_t connHandle) { uint8_t i; for (i = 0; i < MAX_NUM_BLE_CONNS; i++) { if (connList[i].connHandle == connHandle) { return Util_convertBdAddr2Str(connList[i].addr); } } return NULL; } #endif /********************************************************************* * @fn multi_role_clearConnListEntry * * @brief clear device list by connHandle * * @return SUCCESS if connHandle found valid index or bleInvalidRange * if index wasn't found. LINKDB_CONNHANDLE_ALL will always succeed. */ static uint8_t multi_role_clearConnListEntry(uint16_t connHandle) { uint8_t i; // Set to invalid connection index initially uint8_t connIndex = MAX_NUM_BLE_CONNS; if(connHandle != LINKDB_CONNHANDLE_ALL) { connIndex = multi_role_getConnIndex(connHandle); // Get connection index from handle 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 == LINKDB_CONNHANDLE_ALL)) { connList[i].connHandle = LINKDB_CONNHANDLE_INVALID; connList[i].charHandle = 0; connList[i].discState = 0; } } return SUCCESS; } /************************************************************************ * @fn multi_role_pairStateCB * * @param connHandle - the connection handle * * @param state - pairing state * * @param status - status of pairing state * * @return none */ static void multi_role_pairStateCB(uint16_t connHandle, uint8_t state, uint8_t status) { mrPairStateData_t *pData = ICall_malloc(sizeof(mrPairStateData_t)); // Allocate space for the event data. if (pData) { pData->state = state; pData->connHandle = connHandle; pData->status = status; // Queue the event. if (multi_role_enqueueMsg(MR_EVT_PAIRING_STATE, pData) != SUCCESS) { ICall_free(pData); } } } /********************************************************************* * @fn multi_role_passcodeCB * * @brief Passcode callback. * * @param deviceAddr - pointer to device address * * @param connHandle - the connection handle * * @param uiInputs - pairing User Interface Inputs * * @param uiOutputs - pairing User Interface Outputs * * @param numComparison - numeric Comparison 20 bits * * @return none */ static void multi_role_passcodeCB(uint8_t *deviceAddr, uint16_t connHandle, uint8_t uiInputs, uint8_t uiOutputs, uint32_t numComparison) { mrPasscodeData_t *pData = ICall_malloc(sizeof(mrPasscodeData_t)); // Allocate space for the passcode event. if (pData) { pData->connHandle = connHandle; memcpy(pData->deviceAddr, deviceAddr, B_ADDR_LEN); pData->uiInputs = uiInputs; pData->uiOutputs = uiOutputs; pData->numComparison = numComparison; // Enqueue the event. if (multi_role_enqueueMsg(MR_EVT_PASSCODE_NEEDED, pData) != SUCCESS) { ICall_free(pData); } } } /********************************************************************* * @fn multi_role_processPairState * * @brief Process the new paring state. * * @param pairingEvent - pairing event received from the stack * * @return none */ static void multi_role_processPairState(mrPairStateData_t *pPairData) { uint8_t state = pPairData->state; uint8_t status = pPairData->status; switch (state) { case GAPBOND_PAIRING_STATE_STARTED: Display_printf(dispHandle, MR_ROW_SECURITY, 0, "Pairing started"); break; case GAPBOND_PAIRING_STATE_COMPLETE: if (status == SUCCESS) { linkDBInfo_t linkInfo; Display_printf(dispHandle, MR_ROW_SECURITY, 0, "Pairing success"); if (linkDB_GetInfo(pPairData->connHandle, &linkInfo) == SUCCESS) { // If the peer was using private address, update with ID address if ((linkInfo.addrType == ADDRTYPE_PUBLIC_ID || linkInfo.addrType == ADDRTYPE_RANDOM_ID) && !Util_isBufSet(linkInfo.addrPriv, 0, B_ADDR_LEN)) { // Update the address of the peer to the ID address Display_printf(dispHandle, MR_ROW_NON_CONN, 0, "Addr updated: %s", Util_convertBdAddr2Str(linkInfo.addr)); // Update the connection list with the ID address uint8_t i = multi_role_getConnIndex(pPairData->connHandle); MULTIROLE_ASSERT(i < MAX_NUM_BLE_CONNS); memcpy(connList[i].addr, linkInfo.addr, B_ADDR_LEN); } } } else { Display_printf(dispHandle, MR_ROW_SECURITY, 0, "Pairing fail: %d", status); } break; case GAPBOND_PAIRING_STATE_ENCRYPTED: if (status == SUCCESS) { Display_printf(dispHandle, MR_ROW_SECURITY, 0, "Encryption success"); } else { Display_printf(dispHandle, MR_ROW_SECURITY, 0, "Encryption failed: %d", status); } break; case GAPBOND_PAIRING_STATE_BOND_SAVED: if (status == SUCCESS) { Display_printf(dispHandle, MR_ROW_SECURITY, 0, "Bond save success"); } else { Display_printf(dispHandle, MR_ROW_SECURITY, 0, "Bond save failed: %d", status); } break; default: break; } } /********************************************************************* * @fn multi_role_processPasscode * * @brief Process the Passcode request. * * @return none */ static void multi_role_processPasscode(mrPasscodeData_t *pData) { // Display passcode to user if (pData->uiOutputs != 0) { Display_printf(dispHandle, MR_ROW_SECURITY, 0, "Passcode: %d", B_APP_DEFAULT_PASSCODE); } // Send passcode response GAPBondMgr_PasscodeRsp(pData->connHandle, SUCCESS, B_APP_DEFAULT_PASSCODE); } /********************************************************************* * @fn multi_role_startSvcDiscovery * * @brief Start service discovery. * * @return none */ static void multi_role_startSvcDiscovery(void) { uint8_t connIndex = multi_role_getConnIndex(mrConnHandle); // connIndex cannot be equal to or greater than MAX_NUM_BLE_CONNS MULTIROLE_ASSERT(connIndex < MAX_NUM_BLE_CONNS); attExchangeMTUReq_t req; // Initialize cached handles svcStartHdl = svcEndHdl = 0; connList[connIndex].discState = BLE_DISC_STATE_MTU; // Discover GATT Server's Rx MTU size req.clientRxMTU = mrMaxPduSize - L2CAP_HDR_SIZE; // ATT MTU size should be set to the minimum of the Client Rx MTU // and Server Rx MTU values VOID GATT_ExchangeMTU(mrConnHandle, &req, selfEntity); } /********************************************************************* * @fn multi_role_addConnInfo * * @brief add a new connection to the index-to-connHandle map * * @param connHandle - the connection handle * * @param addr - pointer to device address * * @return index of connection handle */ static uint8_t multi_role_addConnInfo(uint16_t connHandle, uint8_t *pAddr, uint8_t role) { uint8_t i; for (i = 0; i < MAX_NUM_BLE_CONNS; i++) { if (connList[i].connHandle == LINKDB_CONNHANDLE_INVALID) { // Found available entry to put a new connection info in connList[i].connHandle = connHandle; memcpy(connList[i].addr, pAddr, B_ADDR_LEN); numConn++; #ifdef DEFAULT_SEND_PARAM_UPDATE_REQ // If a peripheral, start the clock to send a connection parameter update if(role == GAP_PROFILE_PERIPHERAL) { // Allocate data to send through clock handler connList[i].pParamUpdateEventData = ICall_malloc(sizeof(mrClockEventData_t) + sizeof(uint16_t)); if(connList[i].pParamUpdateEventData) { // Set clock data connList[i].pParamUpdateEventData->event = MR_EVT_SEND_PARAM_UPDATE; *((uint16_t *)connList[i].pParamUpdateEventData->data) = connHandle; // Create a clock object and start connList[i].pUpdateClock = (Clock_Struct*) ICall_malloc(sizeof(Clock_Struct)); if (connList[i].pUpdateClock) { Util_constructClock(connList[i].pUpdateClock, multi_role_clockHandler, SEND_PARAM_UPDATE_DELAY, 0, true, (UArg) connList[i].pParamUpdateEventData); } else { // Clean up ICall_free(connList[i].pParamUpdateEventData); } } else { // Memory allocation failed MULTIROLE_ASSERT(false); } } #endif break; } } return i; } /********************************************************************* * @fn multi_role_clearPendingParamUpdate * * @brief clean pending param update request in the paramUpdateList list * * @param connHandle - connection handle to clean * * @return none */ void multi_role_clearPendingParamUpdate(uint16_t connHandle) { List_Elem *curr; for (curr = List_head(¶mUpdateList); curr != NULL; curr = List_next(curr)) { if (((mrConnHandleEntry_t *)curr)->connHandle == connHandle) { List_remove(¶mUpdateList, curr); } } } /********************************************************************* * @fn multi_role_removeConnInfo * * @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 multi_role_removeConnInfo(uint16_t connHandle) { uint8_t connIndex = multi_role_getConnIndex(connHandle); if(connIndex < MAX_NUM_BLE_CONNS) { Clock_Struct* pUpdateClock = connList[connIndex].pUpdateClock; if (pUpdateClock != NULL) { // Stop and destruct the RTOS clock if it's still alive if (Util_isActive(pUpdateClock)) { Util_stopClock(pUpdateClock); } // Destruct the clock object Clock_destruct(pUpdateClock); // Free clock struct ICall_free(pUpdateClock); // Free ParamUpdateEventData ICall_free(connList[connIndex].pParamUpdateEventData); } // Clear pending update requests from paramUpdateList multi_role_clearPendingParamUpdate(connHandle); // Clear Connection List Entry multi_role_clearConnListEntry(connHandle); numConn--; } return connIndex; } /********************************************************************* * @fn multi_role_doDiscoverDevices * * @brief Respond to user input to start scanning * * @param index - not used * * @return TRUE since there is no callback to use this value */ bool multi_role_doDiscoverDevices(uint8_t index) { (void) index; #if (DEFAULT_DEV_DISC_BY_SVC_UUID == TRUE) // Scanning for DEFAULT_SCAN_DURATION x 10 ms. // The stack does not need to record advertising reports // since the application will filter them by Service UUID and save. // Reset number of scan results to 0 before starting scan numScanRes = 0; GapScan_enable(0, DEFAULT_SCAN_DURATION, 0); #else // !DEFAULT_DEV_DISC_BY_SVC_UUID // Scanning for DEFAULT_SCAN_DURATION x 10 ms. // Let the stack record the advertising reports as many as up to DEFAULT_MAX_SCAN_RES. GapScan_enable(0, DEFAULT_SCAN_DURATION, DEFAULT_MAX_SCAN_RES); #endif // DEFAULT_DEV_DISC_BY_SVC_UUID // Enable only "Stop Discovering" and disable all others in the main menu // tbm_setItemStatus(&mrMenuMain, MR_ITEM_STOPDISC, // (MR_ITEM_ALL & ~MR_ITEM_STOPDISC)); return (true); } /********************************************************************* * @fn multi_role_doStopDiscovering * * @brief Stop on-going scanning * * @param index - item index from the menu * * @return always true */ bool multi_role_doStopDiscovering(uint8_t index) { (void) index; GapScan_disable(); return (true); } /********************************************************************* * @fn multi_role_doCancelConnecting * * @brief Cancel on-going connection attempt * * @param index - item index from the menu * * @return always true */ bool multi_role_doCancelConnecting(uint8_t index) { (void) index; GapInit_cancelConnect(); return (true); } /********************************************************************* * @fn multi_role_doConnect * * @brief Respond to user input to form a connection * * @param index - index as selected from the mrMenuConnect * * @return TRUE since there is no callback to use this value */ bool multi_role_doConnect(uint8_t index) { // Temporarily disable advertising GapAdv_disable(advHandle); #if (DEFAULT_DEV_DISC_BY_SVC_UUID == TRUE) GapInit_connect(scanList[index].addrType & MASK_ADDRTYPE_ID, scanList[index].addr, mrInitPhy, 0); #else // !DEFAULT_DEV_DISC_BY_SVC_UUID GapScan_Evt_AdvRpt_t advRpt; GapScan_getAdvReport(index, &advRpt); GapInit_connect(advRpt.addrType & MASK_ADDRTYPE_ID, advRpt.addr, mrInitPhy, 0); #endif // DEFAULT_DEV_DISC_BY_SVC_UUID // Re-enable advertising GapAdv_enable(advHandle, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0); // Enable only "Cancel Connecting" and disable all others in the main menu tbm_setItemStatus(&mrMenuMain, MR_ITEM_CANCELCONN, (MR_ITEM_ALL & ~MR_ITEM_CANCELCONN)); Display_printf(dispHandle, MR_ROW_NON_CONN, 0, "Connecting..."); tbm_goTo(&mrMenuMain); return (true); } /********************************************************************* * @fn multi_role_doSelectConn * * @brief Select a connection to communicate with * * @param index - item index from the menu * * @return always true */ bool multi_role_doSelectConn(uint8_t index) { uint32_t itemsToDisable = MR_ITEM_NONE; // index cannot be equal to or greater than MAX_NUM_BLE_CONNS MULTIROLE_ASSERT(index < MAX_NUM_BLE_CONNS); mrConnHandle = connList[index].connHandle; if (connList[index].charHandle == 0) { // Initiate service discovery multi_role_enqueueMsg(MR_EVT_SVC_DISC, NULL); // Diable GATT Read/Write until simple service is found itemsToDisable = MR_ITEM_GATTREAD | MR_ITEM_GATTWRITE; } // Set the menu title and go to this connection's context TBM_SET_TITLE(&mrMenuPerConn, TBM_GET_ACTION_DESC(&mrMenuSelectConn, index)); tbm_setItemStatus(&mrMenuPerConn, MR_ITEM_NONE, itemsToDisable); // Clear non-connection-related message Display_clearLine(dispHandle, MR_ROW_NON_CONN); tbm_goTo(&mrMenuPerConn); return (true); } /********************************************************************* * @fn multi_role_doGattRead * * @brief GATT Read * * @param index - item index from the menu * * @return always true */ bool multi_role_doGattRead(uint8_t index) { attReadReq_t req; uint8_t connIndex = multi_role_getConnIndex(mrConnHandle); // connIndex cannot be equal to or greater than MAX_NUM_BLE_CONNS MULTIROLE_ASSERT(connIndex < MAX_NUM_BLE_CONNS); req.handle = connList[connIndex].charHandle; GATT_ReadCharValue(mrConnHandle, &req, selfEntity); return (true); } /********************************************************************* * @fn multi_role_doGattWrite * * @brief GATT Write * * @param index - item index from the menu * * @return always true */ bool multi_role_doGattWrite(uint8_t index) { status_t status; uint8_t charVals[4] = { 0x00, 0x55, 0xAA, 0xFF }; // Should be consistent with // those in scMenuGattWrite attWriteReq_t req; req.pValue = GATT_bm_alloc(mrConnHandle, ATT_WRITE_REQ, 1, NULL); if ( req.pValue != NULL ) { uint8_t connIndex = multi_role_getConnIndex(mrConnHandle); // connIndex cannot be equal to or greater than MAX_NUM_BLE_CONNS MULTIROLE_ASSERT(connIndex < MAX_NUM_BLE_CONNS); req.handle = connList[connIndex].charHandle; req.len = 1; charVal = charVals[index]; req.pValue[0] = charVal; req.sig = 0; req.cmd = 0; status = GATT_WriteCharValue(mrConnHandle, &req, selfEntity); if ( status != SUCCESS ) { GATT_bm_free((gattMsg_t *)&req, ATT_WRITE_REQ); } } return (true); } /********************************************************************* * @fn multi_role_doConnUpdate * * @brief Respond to user input to do a connection update * * @param index - index as selected from the mrMenuConnUpdate * * @return TRUE since there is no callback to use this value */ bool multi_role_doConnUpdate(uint8_t index) { gapUpdateLinkParamReq_t params; (void) index; //may need to get the real connHandle? params.connectionHandle = mrConnHandle; params.intervalMin = 10;//DEFAULT_UPDATE_MIN_CONN_INTERVAL; params.intervalMax = 12;//DEFAULT_UPDATE_MAX_CONN_INTERVAL; params.connLatency = 0;//DEFAULT_UPDATE_SLAVE_LATENCY; linkDBInfo_t linkInfo; if (linkDB_GetInfo(mrConnHandle, &linkInfo) == SUCCESS) { if (linkInfo.connTimeout == 6000)//DEFAULT_UPDATE_CONN_TIMEOUT) { params.connTimeout = 6000+200;//DEFAULT_UPDATE_CONN_TIMEOUT + 200; } else { params.connTimeout =6000;// DEFAULT_UPDATE_CONN_TIMEOUT; } GAP_UpdateLinkParamReq(¶ms); Display_printf(dispHandle, MR_ROW_CUR_CONN, 0, "Param update Request:connTimeout =%d", params.connTimeout*CONN_TIMEOUT_MS_CONVERSION); } else { Display_printf(dispHandle, MR_ROW_CUR_CONN, 0, "update :%s, Unable to find link information", Util_convertBdAddr2Str(linkInfo.addr)); } return (true); } /********************************************************************* * @fn multi_role_doConnPhy * * @brief Set Connection PHY preference. * * @param index - item number in MRMenu_connPhy list * * @return always true */ bool multi_role_doConnPhy(uint8_t index) { // Set Phy Preference on the current connection. Apply the same value // for RX and TX. For more information, see the LE 2M PHY section in the User's Guide: // http://software-dl.ti.com/lprf/ble5stack-latest/ // Note PHYs are already enabled by default in build_config.opt in stack project. HCI_LE_SetPhyCmd(mrConnHandle, 0, MRMenu_connPhy[index].value, MRMenu_connPhy[index].value, 0); Display_printf(dispHandle, MR_ROW_CUR_CONN, 0, "Connection PHY preference: %s", TBM_GET_ACTION_DESC(&mrMenuConnPhy, index)); return (true); } /********************************************************************* * @fn multi_role_doSetInitPhy * * @brief Set initialize PHY preference. * * @param index - item number in MRMenu_initPhy list * * @return always true */ bool multi_role_doSetInitPhy(uint8_t index) { mrInitPhy = MRMenu_initPhy[index].value; Display_printf(dispHandle, MR_ROW_CUR_CONN, 0, "Initialize PHY preference: %s", TBM_GET_ACTION_DESC(&mrMenuInitPhy, index)); return (true); } /********************************************************************* * @fn multi_role_doSetScanPhy * * @brief Set PHYs for scanning. * * @param index - item number in MRMenu_scanPhy list * * @return always true */ bool multi_role_doSetScanPhy(uint8_t index) { // Set scanning primary PHY GapScan_setParam(SCAN_PARAM_PRIM_PHYS, &MRMenu_scanPhy[index].value); Display_printf(dispHandle, MR_ROW_NON_CONN, 0, "Primary Scan PHY: %s", TBM_GET_ACTION_DESC(&mrMenuScanPhy, index)); return (true); } /********************************************************************* * @fn multi_role_doSetAdvPhy * * @brief Set advertise PHY preference. * * @param index - item number in MRMenu_advPhy list * * @return always true */ bool multi_role_doSetAdvPhy(uint8_t index) { uint16_t props; GapAdv_primaryPHY_t phy; bool isAdvActive = mrIsAdvertising; switch (MRMenu_advPhy[index].value) { case MR_ADV_LEGACY_PHY_1_MBPS: props = GAP_ADV_PROP_CONNECTABLE | GAP_ADV_PROP_SCANNABLE | GAP_ADV_PROP_LEGACY; phy = GAP_ADV_PRIM_PHY_1_MBPS; break; case MR_ADV_EXT_PHY_1_MBPS: props = GAP_ADV_PROP_CONNECTABLE; phy = GAP_ADV_PRIM_PHY_1_MBPS; break; case MR_ADV_EXT_PHY_CODED: props = GAP_ADV_PROP_CONNECTABLE; phy = GAP_ADV_PRIM_PHY_CODED_S2; break; default: return (false); } if (isAdvActive) { // Turn off advertising GapAdv_disable(advHandle); } GapAdv_setParam(advHandle,GAP_ADV_PARAM_PROPS,&props); GapAdv_setParam(advHandle,GAP_ADV_PARAM_PRIMARY_PHY,&phy); GapAdv_setParam(advHandle,GAP_ADV_PARAM_SECONDARY_PHY,&phy); if (isAdvActive) { // Turn on advertising GapAdv_enable(advHandle, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0); } Display_printf(dispHandle, MR_ROW_CUR_CONN, 0, "Advertise PHY preference: %s", TBM_GET_ACTION_DESC(&mrMenuAdvPhy, index)); return (true); } /********************************************************************* * @fn multi_role_doDisconnect * * @brief Respond to user input to terminate a connection * * @param index - index as selected from the mrMenuConnUpdate * * @return always true */ bool multi_role_doDisconnect(uint8_t index) { (void) index; // Disconnect GAP_TerminateLinkReq(mrConnHandle, HCI_DISCONNECT_REMOTE_USER_TERM); return (true); } /********************************************************************* * @fn multi_role_doAdvertise * * @brief Respond to user input to terminate a connection * * @param index - index as selected from the mrMenuConnUpdate * * @return always true */ bool multi_role_doAdvertise(uint8_t index) { (void) index; // If we're currently advertising if (mrIsAdvertising) { // Turn off advertising GapAdv_disable(advHandle); } // If we're not currently advertising else { if (numConn < MAX_NUM_BLE_CONNS) { // Start advertising since there is room for more connections GapAdv_enable(advHandle, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0); } else { Display_printf(dispHandle, MR_ROW_ADVERTIS, 0, "At Maximum Connection Limit, Cannot Enable Advertisment"); } } return (true); } /********************************************************************* * @fn multi_role_menuSwitchCb * * @brief Detect menu context switching * * @param pMenuObjCurr - the current menu object * @param pMenuObjNext - the menu object the context is about to switch to * * @return none */ static void multi_role_menuSwitchCb(tbmMenuObj_t* pMenuObjCurr, tbmMenuObj_t* pMenuObjNext) { // interested in only the events of // entering mrMenuConnect, mrMenuSelectConn, and mrMenuMain for now if (pMenuObjNext == &mrMenuConnect) { uint8_t i, j; uint32_t itemsToDisable = MR_ITEM_NONE; for (i = 0; i < TBM_GET_NUM_ITEM(&mrMenuConnect); i++) { for (j = 0; j < MAX_NUM_BLE_CONNS; j++) { if ((connList[j].connHandle != LINKDB_CONNHANDLE_INVALID) && !memcmp(TBM_GET_ACTION_DESC(&mrMenuConnect, i), Util_convertBdAddr2Str(connList[j].addr), MR_ADDR_STR_SIZE)) { // Already connected. Add to the set to be disabled. itemsToDisable |= (1 << i); } } } // Eventually only non-connected device addresses will be displayed. tbm_setItemStatus(&mrMenuConnect, MR_ITEM_ALL & ~itemsToDisable, itemsToDisable); } else if (pMenuObjNext == &mrMenuSelectConn) { static uint8_t* pAddrs; uint8_t* pAddrTemp; if (pAddrs != NULL) { ICall_free(pAddrs); } // Allocate buffer to display addresses pAddrs = ICall_malloc(numConn * MR_ADDR_STR_SIZE); if (pAddrs == NULL) { TBM_SET_NUM_ITEM(&mrMenuSelectConn, 0); } else { uint8_t i; TBM_SET_NUM_ITEM(&mrMenuSelectConn, MAX_NUM_BLE_CONNS); pAddrTemp = pAddrs; // Add active connection info to the menu object for (i = 0; i < MAX_NUM_BLE_CONNS; i++) { if (connList[i].connHandle != LINKDB_CONNHANDLE_INVALID) { // This connection is active. Set the corresponding menu item with // the address of this connection and enable the item. memcpy(pAddrTemp, Util_convertBdAddr2Str(connList[i].addr), MR_ADDR_STR_SIZE); TBM_SET_ACTION_DESC(&mrMenuSelectConn, i, pAddrTemp); tbm_setItemStatus(&mrMenuSelectConn, (1 << i), MR_ITEM_NONE); pAddrTemp += MR_ADDR_STR_SIZE; } else { // This connection is not active. Disable the corresponding menu item. tbm_setItemStatus(&mrMenuSelectConn, MR_ITEM_NONE, (1 << i)); } } } } else if (pMenuObjNext == &mrMenuMain) { // Now we are not in a specific connection's context mrConnHandle = LINKDB_CONNHANDLE_INVALID; // Clear connection-related message Display_clearLine(dispHandle, MR_ROW_CUR_CONN); } } int findpat(uint8_t *buf, char *pat, int buflen) { int i=0,j=0,k; int x; j = (int)strlen(pat); x = 1; while (i < buflen ) { for (k = 0;k < j;k++) x = x && (buf[i+k] == pat[k]); if (x == 1) { return (i); // string beginning found at buf+i } i++; x=1; // reset true } return (-1); // string not found } /********************************************************************* *********************************************************************/ void disable_ble(void){ GapAdv_disable(advHandle); GapAdv_disable(advHandle); } void enable_ble(void){ GapAdv_enable(advHandle, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0); GapAdv_enable(advHandle, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0); strncpy(scanResData1+2,"1234567890",14); GapAdv_loadByHandle(advHandle, GAP_ADV_DATA_TYPE_SCAN_RSP, sizeof(scanResData1), scanResData1); }
/* * Copyright (c) 2015-2019, 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. */ /* * */ /* For usleep() */ #include <unistd.h> #include <stdint.h> #include <stddef.h> #include <string.h> #include <stdlib.h> #include <stdio.h> //#include <Include/global.h> //#include <ti/drivers/Timer.h> #include <ti/sysbios/knl/Task.h> /* Driver Header files */ #include <ti/drivers/GPIO.h> // #include <ti/drivers/I2C.h> #include <ti/drivers/SPI.h> #include <ti/drivers/UART.h> #include <ti/drivers/Power.h> #include <ti/drivers/Watchdog.h> /* Driver configuration */ #include "ti_drivers_config.h" #include "icall.h" #include "multi_role.h" #include "gap_scanner.h" #include "application.h" /********************************************************************* * MACROS */ #define TIMEOUT_MS 10000 #define SLEEP_US 500000 #define APP_TASK_STACK_SIZE 3072 #define APP_TASK_PRIORITY 3 /*********************************************************************/ /********************************************************************* * TYPEDEFS */ // Task configuration Task_Struct sappTask; // 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; /********************************************************************* * GLOBAL VARIABLES */ char sappTaskStack[APP_TASK_STACK_SIZE]; //int cnt = 0; //Watchdog Watchdog_Handle watchdogHandle; Watchdog_Params params; uint32_t reloadValue; //// static void APP_taskFxn(unsigned int a0, unsigned int a1); /* * ======== watchdogCallback ======== */ void watchdogCallback(uintptr_t watchdogHandle) { /* * If the Watchdog Non-Maskable Interrupt (NMI) is called, * loop until the device resets. Some devices will invoke * this callback upon watchdog expiration while others will * reset. See the device specific watchdog driver documentation * for your device. */ while (1) {} } /*********************************************************************************************************************** * Function Name: APP_createTask * Description : creates task for application. * pin muxing : None * Arguments : index of GPIO * Return Value : None ***********************************************************************************************************************/ void APP_createTask(void) { Task_Params taskParams; // Configure task Task_Params_init(&taskParams); taskParams.stack = sappTaskStack; taskParams.stackSize = APP_TASK_STACK_SIZE; taskParams.priority = APP_TASK_PRIORITY; Task_construct(&sappTask, APP_taskFxn, &taskParams, NULL); } /*********************************************************************************************************************** * Function Name: APP_taskFxn * Description : All the task needed for the application is done inside the function. * pin muxing : None * Arguments : a0,a1 * Return Value : None ***********************************************************************************************************************/ static void APP_taskFxn(unsigned int a0, unsigned int a1) { // Register the current thread as an ICall dispatcher application // so that the application can send and receive messages. ICall_registerApp(&selfEntity, &syncEvent); /* 1 second delay */ // uint32_t time = 1000; /* Call driver init functions */ GPIO_init(); Watchdog_init(); disable_ble(); /* Open a Watchdog driver instance */ Watchdog_Params_init(¶ms); params.callbackFxn = (Watchdog_Callback) watchdogCallback; params.debugStallMode = Watchdog_DEBUG_STALL_ON; params.resetMode = Watchdog_RESET_ON; watchdogHandle = Watchdog_open(CONFIG_WATCHDOG_0, ¶ms); if (watchdogHandle == NULL) { /* Error opening Watchdog */ while (1) {} } reloadValue = Watchdog_convertMsToTicks(watchdogHandle, TIMEOUT_MS); /* * A value of zero (0) indicates the converted value exceeds 32 bits * OR that the API is not applicable for this specific device. */ if (reloadValue != 0) { Watchdog_setReload(watchdogHandle, reloadValue); } enable_ble(); while (1) { // SimpleCentral_ControlDiscover(); GapScan_enable(0, 50, 15); Watchdog_clear(watchdogHandle); // what is the max duration the watchdog can wait??? }//end of main while loop }
multirole.c and created own application.C in that scanning the devices ,please suggest a way to scan fast after connection
Hi,
Thank you for reaching out.
First of all, please note GapScan_enable() cannot be called into a loop as you do in the code you have shared. Instead, you should wait until the scan operation terminates (cf. MR_EVT_SCAN_DISABLED) and eventually start a new one.
As of the question about "slow scanning" - When scanning and maintaining a connection concurrently, the air time is split between the two operations. In general, connection operations are set to have higher priority.
The air time split can easily be seen by enabling the RF debug signals (see here: https://software-dl.ti.com/simplelink/esd/simplelink_cc13xx_cc26xx_sdk/7.40.00.77/exports/docs/ble5stack/ble_user_guide/html/ble-stack-5.x-guide/debugging-index.html#debugging-rf-output) and probing these signals.
To offer more air time to scanning operations, you should increase the connection interval and/or enable connection latency.
I hope this will help,
Best regards,
Hi clement its working, now scanning air time increased.
and how to integrate OAD onchip in multi role project,(im using 5.2 sdk and 11.1IDE tool , in simplelink academy its showed with uing 6.4 sdk and 12.1 IDE tool , if we integrate this OAD onchip it will work ?).
thanks and regards
chandra shekar
Hi,
Great to see you managed to fix the scanning issue. Please make sure to mark the thread as resolved.
When it comes to OAD, I expect the procedure to be similar. Also, you can display older SimpleLink Academy modules as shown below. Note that, you won't be able to show the SDK 5.20 as it is too old (you will only find 5.30).
In case further assistance with regards to OAD is required, please open a new ticket.
Best regards,
Hi clemet,
Their is pairing problem , when connected with third party BLE applications like "LightBlue,Blescanner,NRFconnect " pairing popup is appearing
,but we created own application for connecting the devices at that time popup is not enabling from the mobile .
this is the configuration for IO capabilities.
this is how its showing ,unable connect
Hi,
Please open a new thread to discuss the questions non-directly related to the initial topic "scanning is slow". This is important as it helps us keeping the forum easy to read and ensure we always have the right experts assigned to the topics.
Appreciate your comprehension.
Best regards,
Hi clement
One issue we got while working , initially we given some ID (600....)for advertisement as u can see in above multirole.c file ,device is advertising with same Id but, after some time device ID name is changing automatically
Hi Abinesh,
Clement is currently on holiday and will be returning to answer forum posts on Tuesday, May 21st in the order and priority in which they were received. Thank you for your patience.
Regards,
Ryan
Hi,
By default, the BLE examples set the device to use Random Private Address (RPA) and update this address periodically to ensure privacy.
The address type used can be changed in SysConfig.
If more support is required on this topic, please open a new thread.
Best regards,