· 6 years ago · Mar 12, 2020, 04:20 AM
1/******************************************************************************
2
3 @file simple_central.c
4
5 @brief This file contains the Simple Central sample application for use
6 with the CC2650 Bluetooth Low Energy Protocol Stack.
7
8 Group: WCS, BTS
9 Target Device: cc2640r2
10
11 ******************************************************************************
12
13 Copyright (c) 2013-2019, Texas Instruments Incorporated
14 All rights reserved.
15
16 Redistribution and use in source and binary forms, with or without
17 modification, are permitted provided that the following conditions
18 are met:
19
20 * Redistributions of source code must retain the above copyright
21 notice, this list of conditions and the following disclaimer.
22
23 * Redistributions in binary form must reproduce the above copyright
24 notice, this list of conditions and the following disclaimer in the
25 documentation and/or other materials provided with the distribution.
26
27 * Neither the name of Texas Instruments Incorporated nor the names of
28 its contributors may be used to endorse or promote products derived
29 from this software without specific prior written permission.
30
31 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
32 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
33 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
34 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
35 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
36 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
37 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
38 OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
39 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
40 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
41 EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42
43 ******************************************************************************
44
45
46 *****************************************************************************/
47
48/*********************************************************************
49 * INCLUDES
50 */
51#include <string.h>
52
53#include <ti/sysbios/knl/Task.h>
54#include <ti/sysbios/knl/Clock.h>
55#include <ti/sysbios/knl/Event.h>
56#include <ti/sysbios/knl/Queue.h>
57#include <ti/display/Display.h>
58
59#if defined( USE_FPGA ) || defined( DEBUG_SW_TRACE )
60#include <driverlib/ioc.h>
61#endif // USE_FPGA | DEBUG_SW_TRACE
62
63#include "bcomdef.h"
64
65#include <icall.h>
66#include "util.h"
67/* This Header file contains all BLE API and icall structure definition */
68#include "icall_ble_api.h"
69
70#include "central.h"
71#include "simple_gatt_profile.h"
72
73#include "board_key.h"
74#include "board.h"
75
76#include "simple_central.h"
77
78#include "ble_user_config.h"
79
80/*********************************************************************
81 * MACROS
82 */
83
84/*********************************************************************
85 * CONSTANTS
86 */
87
88#define SBC_STATE_CHANGE_EVT 0x0001
89#define SBC_KEY_CHANGE_EVT 0x0002
90#define SBC_RSSI_READ_EVT 0x0004
91#define SBC_PAIRING_STATE_EVT 0x0008
92#define SBC_PASSCODE_NEEDED_EVT 0x0010
93
94// Simple Central Task Events
95#define SBC_ICALL_EVT ICALL_MSG_EVENT_ID // Event_Id_31
96#define SBC_QUEUE_EVT UTIL_QUEUE_EVENT_ID // Event_Id_30
97#define SBC_START_DISCOVERY_EVT Event_Id_00
98#define SBC_CONN_EST_TIMEOUT_EVT Event_Id_01
99
100#define SBC_ALL_EVENTS (SBC_ICALL_EVT | \
101 SBC_QUEUE_EVT | \
102 SBC_CONN_EST_TIMEOUT_EVT | \
103 SBC_START_DISCOVERY_EVT)
104
105// Enable/Disable Unlimited Scanning Feature
106#define ENABLE_UNLIMITED_SCAN_RES FALSE
107
108// Maximum number of scan responses
109#define DEFAULT_MAX_SCAN_RES 20
110
111// Scan duration in ms
112#define DEFAULT_SCAN_DURATION 500
113
114// Discovery mode (limited, general, all)
115#define DEFAULT_DISCOVERY_MODE DEVDISC_MODE_ALL
116
117// TRUE to use active scan
118#define DEFAULT_DISCOVERY_ACTIVE_SCAN TRUE
119
120// Set desired policy to use during discovery (use values from GAP_Disc_Filter_Policies)
121#define DEFAULT_DISCOVERY_WHITE_LIST GAP_DISC_FILTER_POLICY_ALL
122
123// TRUE to use high scan duty cycle when creating link
124#define DEFAULT_LINK_HIGH_DUTY_CYCLE FALSE
125
126// TRUE to use white list when creating link
127#define DEFAULT_LINK_WHITE_LIST FALSE
128
129// Default RSSI polling period in ms
130#define DEFAULT_RSSI_PERIOD 1000
131
132// After the connection is formed, the central will accept connection parameter
133// update requests from the peripheral
134#define DEFAULT_ENABLE_UPDATE_REQUEST GAPCENTRALROLE_PARAM_UPDATE_REQ_AUTO_ACCEPT
135
136// Minimum connection interval (units of 1.25ms) if automatic parameter update
137// request is enabled
138#define DEFAULT_UPDATE_MIN_CONN_INTERVAL 40
139
140// Maximum connection interval (units of 1.25ms) if automatic parameter update
141// request is enabled
142#define DEFAULT_UPDATE_MAX_CONN_INTERVAL 800
143
144// Slave latency to use if automatic parameter update request is enabled
145#define DEFAULT_UPDATE_SLAVE_LATENCY 0
146
147// Supervision timeout value (units of 10ms) if automatic parameter update
148// request is enabled
149#define DEFAULT_UPDATE_CONN_TIMEOUT 600
150
151// Default GAP pairing mode
152#define DEFAULT_PAIRING_MODE GAPBOND_PAIRING_MODE_WAIT_FOR_REQ
153
154// Default MITM mode (TRUE to require passcode or OOB when pairing)
155#define DEFAULT_MITM_MODE FALSE
156
157// Default bonding mode, TRUE to bond
158#define DEFAULT_BONDING_MODE TRUE
159
160// Default GAP bonding I/O capabilities
161#define DEFAULT_IO_CAPABILITIES GAPBOND_IO_CAP_DISPLAY_ONLY
162
163// Default service discovery timer delay in ms
164#define DEFAULT_SVC_DISCOVERY_DELAY 1000
165
166// TRUE to filter discovery results on desired service UUID
167#define DEFAULT_DEV_DISC_BY_SVC_UUID TRUE
168
169// Length of bd addr as a string
170#define B_ADDR_STR_LEN 15
171
172// Connection esablishement timeout
173#define DEFAULT_CONN_SETUP_TIMEOUT 5000
174
175
176
177
178
179
180
181//Daniel's Defines/Variables
182
183//#define BATTERY_CHAR1_UUID 0x00 00 01 00 A6 7B 40 A4 95 6B 06 BD 57 8D BB 65
184
185
186//uint8_t globalUuid[ATT_UUID_SIZE] = {0x00, 0x00, 0x01, 0x00, 0xA6, 0x7B, 0x40, 0xA4, 0x95, 0x6B, 0x06, 0xBD, 0x57, 0x8D, 0xBB, 0x65};
187uint8_t globalUuid[ATT_UUID_SIZE] = {0x65, 0xBB, 0x8D, 0x57, 0xBD, 0x06, 0x6B, 0x95, 0xA4, 0x40, 0x7B, 0xA6, 0x00, 0x01, 0x00, 0x00};
188
189#define BATTERY_ADV_DATA 0x05FF0D040403
190
191
192
193
194
195
196
197// Type of Display to open
198#if !defined(Display_DISABLE_ALL)
199 #if defined(BOARD_DISPLAY_USE_LCD) && (BOARD_DISPLAY_USE_LCD!=0)
200 #define SBC_DISPLAY_TYPE Display_Type_LCD
201 #elif defined (BOARD_DISPLAY_USE_UART) && (BOARD_DISPLAY_USE_UART!=0)
202 #define SBC_DISPLAY_TYPE Display_Type_UART
203 #else // !BOARD_DISPLAY_USE_LCD && !BOARD_DISPLAY_USE_UART
204 #define SBC_DISPLAY_TYPE 0 // Option not supported
205 #endif // BOARD_DISPLAY_USE_LCD && BOARD_DISPLAY_USE_UART
206#else // Display_DISABLE_ALL
207 #define SBC_DISPLAY_TYPE 0 // No Display
208#endif // Display_DISABLE_ALL
209
210// Task configuration
211#define SBC_TASK_PRIORITY 1
212
213#ifndef SBC_TASK_STACK_SIZE
214#define SBC_TASK_STACK_SIZE 864
215#endif
216
217// Application states
218enum
219{
220 BLE_STATE_IDLE,
221 BLE_STATE_CONNECTING,
222 BLE_STATE_CONNECTED,
223 BLE_STATE_DISCONNECTING
224};
225
226// Discovery states
227enum
228{
229 BLE_DISC_STATE_IDLE, // Idle
230 BLE_DISC_STATE_MTU, // Exchange ATT MTU size
231 BLE_DISC_STATE_SVC, // Service discovery
232 BLE_DISC_STATE_CHAR // Characteristic discovery
233};
234
235// Key states for connections
236typedef enum {
237 GATT_RW, // Perform GATT Read/Write
238 RSSI, // Toggle RSSI updates
239 CONN_UPDATE, // Send Connection Parameter Update
240 GET_CONN_INFO, // Display Current Connection Information
241 DISCONNECT // Disconnect
242} keyPressConnOpt_t;
243
244/*********************************************************************
245 * TYPEDEFS
246 */
247
248// App event passed from profiles.
249typedef struct
250{
251 appEvtHdr_t hdr; // event header
252 uint8_t *pData; // event data
253} sbcEvt_t;
254
255// RSSI read data structure
256typedef struct
257{
258 uint16_t period; // how often to read RSSI
259 uint16_t connHandle; // connection handle
260 Clock_Struct *pClock; // pointer to clock struct
261} readRssi_t;
262
263/*********************************************************************
264 * GLOBAL VARIABLES
265 */
266
267// Display Interface
268Display_Handle dispHandle = NULL;
269
270/*********************************************************************
271 * EXTERNAL VARIABLES
272 */
273
274/*********************************************************************
275 * LOCAL VARIABLES
276 */
277
278// Entity ID globally used to check for source and/or destination of messages
279static ICall_EntityID selfEntity;
280
281// Event globally used to post local events and pend on system and
282// local events.
283static ICall_SyncHandle syncEvent;
284
285// Clock object used to signal timeout
286static Clock_Struct startDiscClock;
287
288// Clock object used to establishement connection timeout
289static Clock_Struct startLinkEstClock;
290
291// Queue object used for app messages
292static Queue_Struct appMsg;
293static Queue_Handle appMsgQueue;
294
295// Task configuration
296Task_Struct sbcTask;
297Char sbcTaskStack[SBC_TASK_STACK_SIZE];
298
299// GAP GATT Attributes
300static const uint8_t attDeviceName[GAP_DEVICE_NAME_LEN] = "Simple Central";
301
302// Number of scan results and scan result index
303static uint8_t scanRes = 0;
304static int8_t scanIdx = -1;
305
306// Scan result list
307static gapDevRec_t devList[DEFAULT_MAX_SCAN_RES];
308
309// Scanning state
310static bool scanningStarted = FALSE;
311
312// Connection handle of current connection
313static uint16_t connHandle = GAP_CONNHANDLE_INIT;
314
315// Application state
316static uint8_t state = BLE_STATE_IDLE;
317
318// Discovery state
319static uint8_t discState = BLE_DISC_STATE_IDLE;
320
321// Discovered service start and end handle
322static uint16_t svcStartHdl = 0;
323static uint16_t svcEndHdl = 0xFFFF;
324
325// Discovered characteristic handle
326static uint16_t charHdl = 0;
327
328// Value to write
329static uint8_t charVal = 0;
330
331// Value read/write toggle
332static bool doWrite = FALSE;
333
334// GATT read/write procedure state
335static bool procedureInProgress = FALSE;
336
337// Maximum PDU size (default = 27 octets)
338static uint16 maxPduSize;
339
340// Array of RSSI read structures
341static readRssi_t readRssi[MAX_NUM_BLE_CONNS];
342
343// Key option state.
344static keyPressConnOpt_t keyPressConnOpt = DISCONNECT;
345
346/*********************************************************************
347 * LOCAL FUNCTIONS
348 */
349static void SimpleCentral_init(void);
350static void SimpleCentral_taskFxn(UArg a0, UArg a1);
351
352static void SimpleCentral_processGATTMsg(gattMsgEvent_t *pMsg);
353static void SimpleCentral_handleKeys(uint8_t shift, uint8_t keys);
354static void SimpleCentral_processStackMsg(ICall_Hdr *pMsg);
355static void SimpleCentral_processAppMsg(sbcEvt_t *pMsg);
356static void SimpleCentral_processRoleEvent(gapCentralRoleEvent_t *pEvent);
357static void SimpleCentral_processGATTDiscEvent(gattMsgEvent_t *pMsg);
358static void SimpleCentral_startDiscovery(void);
359static void SimpleCentral_stopEstablishing(void);
360
361static bool SimpleCentral_findSvcUuid(uint64_t uuid, uint8_t *pData,
362 uint16_t dataLen);
363static void SimpleCentral_addDeviceInfo(uint8_t *pAddr, uint8_t addrType);
364static void SimpleCentral_processPairState(uint8_t state, uint8_t status);
365static void SimpleCentral_processPasscode(uint16_t connectionHandle,
366 uint8_t uiOutputs);
367
368static void SimpleCentral_processCmdCompleteEvt(hciEvt_CmdComplete_t *pMsg);
369static bStatus_t SimpleCentral_StartRssi(uint16_t connHandle, uint16_t period);
370static bStatus_t SimpleCentral_CancelRssi(uint16_t connHandle);
371static readRssi_t *SimpleCentral_RssiAlloc(uint16_t connHandle);
372static readRssi_t *SimpleCentral_RssiFind(uint16_t connHandle);
373static void SimpleCentral_RssiFree(uint16_t connHandle);
374
375static uint8_t SimpleCentral_eventCB(gapCentralRoleEvent_t *pEvent);
376static void SimpleCentral_passcodeCB(uint8_t *deviceAddr, uint16_t connHandle,
377 uint8_t uiInputs, uint8_t uiOutputs,
378 uint32_t numComparison);
379static void SimpleCentral_pairStateCB(uint16_t connHandle, uint8_t state,
380 uint8_t status);
381
382void SimpleCentral_startDiscHandler(UArg a0);
383void SimpleCentral_linkEstClockHandler(UArg a0);
384void SimpleCentral_keyChangeHandler(uint8 keys);
385void SimpleCentral_readRssiHandler(UArg a0);
386
387static uint8_t SimpleCentral_enqueueMsg(uint8_t event, uint8_t status,
388 uint8_t *pData);
389
390#ifdef FPGA_AUTO_CONNECT
391static void SimpleCentral_startGapDiscovery(void);
392static void SimpleCentral_connectToFirstDevice(void);
393#endif // FPGA_AUTO_CONNECT
394
395/*********************************************************************
396 * EXTERN FUNCTIONS
397 */
398extern void AssertHandler(uint8 assertCause, uint8 assertSubcause);
399
400/*********************************************************************
401 * PROFILE CALLBACKS
402 */
403
404// Central GAPRole Callbacks
405static gapCentralRoleCB_t SimpleCentral_roleCB =
406{
407 SimpleCentral_eventCB // GAPRole Event Callback
408};
409
410// Bond Manager Callbacks
411static gapBondCBs_t SimpleCentral_bondCB =
412{
413 SimpleCentral_passcodeCB, // Passcode callback
414 SimpleCentral_pairStateCB // Pairing / Bonding state Callback
415};
416
417/*********************************************************************
418 * PUBLIC FUNCTIONS
419 */
420
421#ifdef FPGA_AUTO_CONNECT
422/*********************************************************************
423 * @fn SimpleCentral_startGapDiscovery
424 *
425 * @brief Start discovering devices
426 *
427 * @param none
428 *
429 * @return none
430 */
431static void SimpleCentral_startGapDiscovery(void)
432{
433 // Start discovery
434 if ((state != BLE_STATE_CONNECTED) && (!scanningStarted))
435 {
436 scanningStarted = TRUE;
437 scanRes = 0;
438
439 Display_print0(dispHandle, 2, 0, "Discovering...");
440 Display_clearLines(dispHandle, 3, 4);
441
442 GAPCentralRole_StartDiscovery(DEFAULT_DISCOVERY_MODE,
443 DEFAULT_DISCOVERY_ACTIVE_SCAN,
444 DEFAULT_DISCOVERY_WHITE_LIST);
445 }
446}
447
448/*********************************************************************
449 * @fn SimpleCentral_connectToFirstDevice
450 *
451 * @brief Connect to first device in list of discovered devices
452 *
453 * @param none
454 *
455 * @return none
456 */
457static void SimpleCentral_connectToFirstDevice(void)
458{
459 uint8_t addrType;
460 uint8_t *peerAddr;
461
462 scanIdx = 0;
463
464 if (state == BLE_STATE_IDLE)
465 {
466 // connect to current device in scan result
467 peerAddr = devList[scanIdx].addr;
468 addrType = devList[scanIdx].addrType;
469
470 state = BLE_STATE_CONNECTING;
471
472 GAPCentralRole_EstablishLink(DEFAULT_LINK_HIGH_DUTY_CYCLE,
473 DEFAULT_LINK_WHITE_LIST,
474 addrType, peerAddr);
475
476 Display_print0(dispHandle, 2, 0, "Connecting");
477 Display_print0(dispHandle, 3, 0, Util_convertBdAddr2Str(peerAddr));
478 Display_clearLine(dispHandle, 4);
479 }
480}
481#endif // FPGA_AUTO_CONNECT
482
483/*********************************************************************
484 * @fn SimpleCentral_createTask
485 *
486 * @brief Task creation function for the Simple Central.
487 *
488 * @param none
489 *
490 * @return none
491 */
492void SimpleCentral_createTask(void)
493{
494 Task_Params taskParams;
495
496 // Configure task
497 Task_Params_init(&taskParams);
498 taskParams.stack = sbcTaskStack;
499 taskParams.stackSize = SBC_TASK_STACK_SIZE;
500 taskParams.priority = SBC_TASK_PRIORITY;
501
502 Task_construct(&sbcTask, SimpleCentral_taskFxn, &taskParams, NULL);
503}
504
505/*********************************************************************
506 * @fn SimpleCentral_Init
507 *
508 * @brief Initialization function for the Simple Central App Task.
509 * This is called during initialization and should contain
510 * any application specific initialization (ie. hardware
511 * initialization/setup, table initialization, power up
512 * notification).
513 *
514 * @param none
515 *
516 * @return none
517 */
518static void SimpleCentral_init(void)
519{
520 uint8_t i;
521
522 // ******************************************************************
523 // N0 STACK API CALLS CAN OCCUR BEFORE THIS CALL TO ICall_registerApp
524 // ******************************************************************
525 // Register the current thread as an ICall dispatcher application
526 // so that the application can send and receive messages.
527 ICall_registerApp(&selfEntity, &syncEvent);
528
529#if defined( USE_FPGA )
530 // configure RF Core SMI Data Link
531 IOCPortConfigureSet(IOID_12, IOC_PORT_RFC_GPO0, IOC_STD_OUTPUT);
532 IOCPortConfigureSet(IOID_11, IOC_PORT_RFC_GPI0, IOC_STD_INPUT);
533
534 // configure RF Core SMI Command Link
535 IOCPortConfigureSet(IOID_10, IOC_IOCFG0_PORT_ID_RFC_SMI_CL_OUT, IOC_STD_OUTPUT);
536 IOCPortConfigureSet(IOID_9, IOC_IOCFG0_PORT_ID_RFC_SMI_CL_IN, IOC_STD_INPUT);
537
538 // configure RF Core tracer IO
539 IOCPortConfigureSet(IOID_8, IOC_PORT_RFC_TRC, IOC_STD_OUTPUT);
540#else // !USE_FPGA
541 #if defined( DEBUG_SW_TRACE )
542 // configure RF Core tracer IO
543 IOCPortConfigureSet(IOID_8, IOC_PORT_RFC_TRC, IOC_STD_OUTPUT | IOC_CURRENT_4MA | IOC_SLEW_ENABLE);
544 #endif // DEBUG_SW_TRACE
545#endif // USE_FPGA
546
547 // Create an RTOS queue for message from profile to be sent to app.
548 appMsgQueue = Util_constructQueue(&appMsg);
549
550 // Setup discovery delay as a one-shot timer
551 Util_constructClock(&startDiscClock, SimpleCentral_startDiscHandler,
552 DEFAULT_SVC_DISCOVERY_DELAY, 0, false, 0);
553
554 Util_constructClock(&startLinkEstClock, SimpleCentral_linkEstClockHandler,
555 DEFAULT_CONN_SETUP_TIMEOUT, 0, false, 0);
556
557 Board_initKeys(SimpleCentral_keyChangeHandler);
558
559 dispHandle = Display_open(SBC_DISPLAY_TYPE, NULL);
560
561 // Initialize internal data
562 for (i = 0; i < MAX_NUM_BLE_CONNS; i++)
563 {
564 readRssi[i].connHandle = GAP_CONNHANDLE_ALL;
565 readRssi[i].pClock = NULL;
566 }
567
568 // Setup the Central GAPRole Profile. For more information see the GAP section
569 // in the User's Guide:
570 // http://software-dl.ti.com/lprf/sdg-latest/html/
571 {
572 uint8_t scanRes = 0;
573
574 // In case that the Unlimited Scanning feature is disabled
575 // send the number of scan results to the GAP
576 if(ENABLE_UNLIMITED_SCAN_RES == FALSE)
577 {
578 scanRes = DEFAULT_MAX_SCAN_RES;
579 }
580
581 GAPCentralRole_SetParameter(GAPCENTRALROLE_MAX_SCAN_RES, sizeof(uint8_t),
582 &scanRes);
583 }
584
585 // Set GAP Parameters to set the discovery duration
586 // For more information, see the GAP section of the User's Guide:
587 // http://software-dl.ti.com/lprf/sdg-latest/html/
588 GAP_SetParamValue(TGAP_GEN_DISC_SCAN, DEFAULT_SCAN_DURATION);
589 GAP_SetParamValue(TGAP_LIM_DISC_SCAN, DEFAULT_SCAN_DURATION);
590 GGS_SetParameter(GGS_DEVICE_NAME_ATT, GAP_DEVICE_NAME_LEN,
591 (void *)attDeviceName);
592
593 // Setup the GAP Bond Manager. For more information see the GAP Bond Manager
594 // section in the User's Guide:
595 // http://software-dl.ti.com/lprf/sdg-latest/html/
596 {
597 // Don't send a pairing request after connecting; the device waits for the
598 // application to start pairing
599 uint8_t pairMode = DEFAULT_PAIRING_MODE;
600 // Do not use authenticated pairing
601 uint8_t mitm = DEFAULT_MITM_MODE;
602 // This is a display only device
603 uint8_t ioCap = DEFAULT_IO_CAPABILITIES;
604 // Create a bond during the pairing process
605 uint8_t bonding = DEFAULT_BONDING_MODE;
606 // Whether to replace the least recently used entry when bond list is full,
607 // and a new device is bonded.
608 // Alternative is pairing succeeds but bonding fails, unless application has
609 // manually erased at least one bond.
610 uint8_t replaceBonds = FALSE;
611
612 GAPBondMgr_SetParameter(GAPBOND_PAIRING_MODE, sizeof(uint8_t), &pairMode);
613 GAPBondMgr_SetParameter(GAPBOND_MITM_PROTECTION, sizeof(uint8_t), &mitm);
614 GAPBondMgr_SetParameter(GAPBOND_IO_CAPABILITIES, sizeof(uint8_t), &ioCap);
615 GAPBondMgr_SetParameter(GAPBOND_BONDING_ENABLED, sizeof(uint8_t), &bonding);
616 GAPBondMgr_SetParameter(GAPBOND_LRU_BOND_REPLACEMENT, sizeof(uint8_t), &replaceBonds);
617 }
618
619 // Initialize GATT Client
620 VOID GATT_InitClient();
621
622 // Register to receive incoming ATT Indications/Notifications
623 GATT_RegisterForInd(selfEntity);
624
625 // Initialize GATT attributes
626 GGS_AddService(GATT_ALL_SERVICES); // GAP
627 GATTServApp_AddService(GATT_ALL_SERVICES); // GATT attributes
628
629 // Start the Device
630 VOID GAPCentralRole_StartDevice(&SimpleCentral_roleCB);
631
632 // Register with bond manager after starting device
633 GAPBondMgr_Register(&SimpleCentral_bondCB);
634
635 // Register with GAP for HCI/Host messages (for RSSI)
636 GAP_RegisterForMsgs(selfEntity);
637
638 // Register for GATT local events and ATT Responses pending for transmission
639 GATT_RegisterForMsgs(selfEntity);
640
641 //Set default values for Data Length Extension
642 {
643 //Set initial values to maximum, RX is set to max. by default(251 octets, 2120us)
644 #define APP_SUGGESTED_PDU_SIZE 251 //default is 27 octets(TX)
645 #define APP_SUGGESTED_TX_TIME 2120 //default is 328us(TX)
646
647 //This API is documented in hci.h
648 //See the LE Data Length Extension section in the BLE-Stack User's Guide for information on using this command:
649 //http://software-dl.ti.com/lprf/sdg-latest/html/cc2640/index.html
650 //HCI_LE_WriteSuggestedDefaultDataLenCmd(APP_SUGGESTED_PDU_SIZE, APP_SUGGESTED_TX_TIME);
651 }
652
653 Display_print0(dispHandle, 0, 0, "BLE Central");
654}
655
656/*********************************************************************
657 * @fn SimpleCentral_taskFxn
658 *
659 * @brief Application task entry point for the Simple Central.
660 *
661 * @param none
662 *
663 * @return events not processed
664 */
665static void SimpleCentral_taskFxn(UArg a0, UArg a1)
666{
667 // Initialize application
668 SimpleCentral_init();
669
670 // Application main loop
671 for (;;)
672 {
673 uint32_t events;
674
675 events = Event_pend(syncEvent, Event_Id_NONE, SBC_ALL_EVENTS,
676 ICALL_TIMEOUT_FOREVER);
677
678 if (events)
679 {
680 ICall_EntityID dest;
681 ICall_ServiceEnum src;
682 ICall_HciExtEvt *pMsg = NULL;
683
684 if (ICall_fetchServiceMsg(&src, &dest,
685 (void **)&pMsg) == ICALL_ERRNO_SUCCESS)
686 {
687 if ((src == ICALL_SERVICE_CLASS_BLE) && (dest == selfEntity))
688 {
689 // Process inter-task message
690 SimpleCentral_processStackMsg((ICall_Hdr *)pMsg);
691 }
692
693 if (pMsg)
694 {
695 ICall_freeMsg(pMsg);
696 }
697 }
698
699 // If RTOS queue is not empty, process app message
700 if (events & SBC_QUEUE_EVT)
701 {
702 while (!Queue_empty(appMsgQueue))
703 {
704 sbcEvt_t *pMsg = (sbcEvt_t *)Util_dequeueMsg(appMsgQueue);
705 if (pMsg)
706 {
707 // Process message
708 SimpleCentral_processAppMsg(pMsg);
709
710 // Free the space from the message
711 ICall_free(pMsg);
712 }
713 }
714 }
715
716 if (events & SBC_START_DISCOVERY_EVT)
717 {
718 SimpleCentral_startDiscovery();
719 }
720
721 if (events & SBC_CONN_EST_TIMEOUT_EVT)
722 {
723 SimpleCentral_stopEstablishing();
724 }
725 }
726 }
727}
728
729/*********************************************************************
730 * @fn SimpleCentral_processStackMsg
731 *
732 * @brief Process an incoming task message.
733 *
734 * @param pMsg - message to process
735 *
736 * @return none
737 */
738static void SimpleCentral_processStackMsg(ICall_Hdr *pMsg)
739{
740 switch (pMsg->event)
741 {
742 case GAP_MSG_EVENT:
743 SimpleCentral_processRoleEvent((gapCentralRoleEvent_t *)pMsg);
744 break;
745
746 case GATT_MSG_EVENT:
747 SimpleCentral_processGATTMsg((gattMsgEvent_t *)pMsg);
748 break;
749
750 case HCI_GAP_EVENT_EVENT:
751 {
752 // Process HCI message
753 switch(pMsg->status)
754 {
755 case HCI_COMMAND_COMPLETE_EVENT_CODE:
756 SimpleCentral_processCmdCompleteEvt((hciEvt_CmdComplete_t *)pMsg);
757 break;
758
759 case HCI_BLE_HARDWARE_ERROR_EVENT_CODE:
760 AssertHandler(HAL_ASSERT_CAUSE_HARDWARE_ERROR,0);
761 break;
762
763 default:
764 break;
765 }
766 }
767 break;
768
769 default:
770 break;
771 }
772}
773
774/*********************************************************************
775 * @fn SimpleCentral_processAppMsg
776 *
777 * @brief Central application event processing function.
778 *
779 * @param pMsg - pointer to event structure
780 *
781 * @return none
782 */
783static void SimpleCentral_processAppMsg(sbcEvt_t *pMsg)
784{
785 switch (pMsg->hdr.event)
786 {
787 case SBC_STATE_CHANGE_EVT:
788 SimpleCentral_processStackMsg((ICall_Hdr *)pMsg->pData);
789
790 // Free the stack message
791 ICall_freeMsg(pMsg->pData);
792 break;
793
794 case SBC_KEY_CHANGE_EVT:
795 SimpleCentral_handleKeys(0, pMsg->hdr.state);
796 break;
797
798 case SBC_RSSI_READ_EVT:
799 {
800 readRssi_t *pRssi = (readRssi_t *)pMsg->pData;
801
802 // If link is up and RSSI reads active
803 if (pRssi->connHandle != GAP_CONNHANDLE_ALL &&
804 linkDB_Up(pRssi->connHandle))
805 {
806 // Restart timer
807 Util_restartClock(pRssi->pClock, pRssi->period);
808
809 // Read RSSI
810 VOID HCI_ReadRssiCmd(pRssi->connHandle);
811 }
812 }
813 break;
814
815 // Pairing event
816 case SBC_PAIRING_STATE_EVT:
817 {
818 SimpleCentral_processPairState(pMsg->hdr.state, *pMsg->pData);
819
820 ICall_free(pMsg->pData);
821 break;
822 }
823
824 // Passcode event
825 case SBC_PASSCODE_NEEDED_EVT:
826 {
827 SimpleCentral_processPasscode(connHandle, *pMsg->pData);
828
829 ICall_free(pMsg->pData);
830 break;
831 }
832
833 default:
834 // Do nothing.
835 break;
836 }
837}
838
839/*********************************************************************
840 * @fn SimpleCentral_processRoleEvent
841 *
842 * @brief Central role event processing function.
843 *
844 * @param pEvent - pointer to event structure
845 *
846 * @return none
847 */
848static void SimpleCentral_processRoleEvent(gapCentralRoleEvent_t *pEvent)
849{
850 switch (pEvent->gap.opcode)
851 {
852 case GAP_DEVICE_INIT_DONE_EVENT:
853 {
854 maxPduSize = pEvent->initDone.dataPktLen;
855
856 Display_print0(dispHandle, 1, 0, Util_convertBdAddr2Str(pEvent->initDone.devAddr));
857 Display_print0(dispHandle, 2, 0, "Initialized");
858
859 // Prompt user to begin scanning.
860 Display_print0(dispHandle, 5, 0, "Discover ->");
861
862#ifdef FPGA_AUTO_CONNECT
863 SimpleCentral_startGapDiscovery();
864#endif // FPGA_AUTO_CONNECT
865 }
866 break;
867
868 case GAP_DEVICE_INFO_EVENT:
869 {
870 uint8 bAddDevice = FALSE;
871
872 if (DEFAULT_DEV_DISC_BY_SVC_UUID == TRUE)
873 {
874 if (SimpleCentral_findSvcUuid(BATTERY_ADV_DATA,
875 pEvent->deviceInfo.pEvtData,
876 pEvent->deviceInfo.dataLen))
877 {
878 bAddDevice = TRUE;
879 }
880 }
881
882 if((ENABLE_UNLIMITED_SCAN_RES == TRUE) && (DEFAULT_DEV_DISC_BY_SVC_UUID == FALSE))
883 {
884 bAddDevice = TRUE;
885 }
886
887 if(bAddDevice)
888 {
889 SimpleCentral_addDeviceInfo(pEvent->deviceInfo.addr,
890 pEvent->deviceInfo.addrType);
891 }
892 }
893 break;
894
895 case GAP_DEVICE_DISCOVERY_EVENT:
896 {
897 if(pEvent->gap.hdr.status == SUCCESS)
898 {
899 // discovery complete
900 scanningStarted = FALSE;
901
902 // if not filtering device discovery results based on service UUID
903 if ((DEFAULT_DEV_DISC_BY_SVC_UUID == FALSE) && (ENABLE_UNLIMITED_SCAN_RES == FALSE))
904 {
905 // Copy results
906 scanRes = pEvent->discCmpl.numDevs;
907 memcpy(devList, pEvent->discCmpl.pDevList,
908 (sizeof(gapDevRec_t) * scanRes));
909 }
910
911 Display_print1(dispHandle, 2, 0, "Devices Found %d", scanRes);
912
913 if (scanRes > 0)
914 {
915#ifndef FPGA_AUTO_CONNECT
916 Display_print0(dispHandle, 3, 0, "<- To Select");
917 }
918
919 // Initialize scan index.
920 scanIdx = -1;
921
922 // Prompt user that re-performing scanning at this state is possible.
923 Display_print0(dispHandle, 5, 0, "Discover ->");
924
925#else // FPGA_AUTO_CONNECT
926 SimpleCentral_connectToFirstDevice();
927 }
928#endif // FPGA_AUTO_CONNECT
929 }
930 else
931 {
932 if(pEvent->gap.hdr.status == GAP_LLERROR_INVALID_PARAMETERS)
933 {
934 Display_print0(dispHandle, 3, 0, "INVALID PARAMETERS");
935 }
936 else if(pEvent->gap.hdr.status == GAP_LLERROR_COMMAND_DISALLOWED)
937 {
938 Display_print0(dispHandle, 3, 0, "COMMAND DISALLOWED");
939 }
940 else
941 {
942 Display_print0(dispHandle, 3, 0, "ERROR");
943 }
944 }
945 }
946 break;
947
948 case GAP_LINK_ESTABLISHED_EVENT:
949 {
950 Util_stopClock(&startLinkEstClock);
951 if (pEvent->gap.hdr.status == SUCCESS)
952 {
953 state = BLE_STATE_CONNECTED;
954 connHandle = pEvent->linkCmpl.connectionHandle;
955 procedureInProgress = TRUE;
956
957 // If service discovery not performed initiate service discovery
958 if (charHdl == 0)
959 {
960 Util_startClock(&startDiscClock);
961 }
962
963 Display_print0(dispHandle, 2, 0, "Connected");
964 Display_print0(dispHandle, 3, 0, Util_convertBdAddr2Str(pEvent->linkCmpl.devAddr));
965 HCI_LE_ReadRemoteUsedFeaturesCmd(connHandle);
966 // Display the initial options for a Right key press.
967 SimpleCentral_handleKeys(0, KEY_LEFT);
968 }
969 else
970 {
971 state = BLE_STATE_IDLE;
972 connHandle = GAP_CONNHANDLE_INIT;
973 discState = BLE_DISC_STATE_IDLE;
974
975 Display_print0(dispHandle, 2, 0, "Connect Failed");
976 Display_print1(dispHandle, 3, 0, "Reason: %d", pEvent->gap.hdr.status);
977 }
978 }
979 break;
980
981 case GAP_LINK_TERMINATED_EVENT:
982 {
983 state = BLE_STATE_IDLE;
984 connHandle = GAP_CONNHANDLE_INIT;
985 discState = BLE_DISC_STATE_IDLE;
986 charHdl = 0;
987 procedureInProgress = FALSE;
988 keyPressConnOpt = DISCONNECT;
989 scanIdx = -1;
990
991 // Cancel RSSI reads
992 SimpleCentral_CancelRssi(pEvent->linkTerminate.connectionHandle);
993
994 Display_print0(dispHandle, 2, 0, "Disconnected");
995 Display_print1(dispHandle, 3, 0, "Reason: %d", pEvent->linkTerminate.reason);
996 Display_clearLine(dispHandle, 4);
997 Display_clearLine(dispHandle, 6);
998
999 // Prompt user to begin scanning.
1000 Display_print0(dispHandle, 5, 0, "Discover ->");
1001 }
1002 break;
1003
1004 case GAP_LINK_PARAM_UPDATE_EVENT:
1005 {
1006 Display_print1(dispHandle, 2, 0, "Param Update: %d", pEvent->linkUpdate.status);
1007 }
1008 break;
1009
1010 default:
1011 break;
1012 }
1013}
1014
1015/*********************************************************************
1016 * @fn SimpleCentral_handleKeys
1017 *
1018 * @brief Handles all key events for this device.
1019 *
1020 * @param shift - true if in shift/alt.
1021 * @param keys - bit field for key events. Valid entries:
1022 * HAL_KEY_SW_2
1023 * HAL_KEY_SW_1
1024 *
1025 * @return none
1026 */
1027static void SimpleCentral_handleKeys(uint8_t shift, uint8_t keys)
1028{
1029 hciActiveConnInfo_t *pConnInfo; // pointer to hold return connection information
1030 (void)shift; // Intentionally unreferenced parameter
1031
1032 if (keys & KEY_LEFT)
1033 {
1034 // If not connected
1035 if (state == BLE_STATE_IDLE)
1036 {
1037 // If not currently scanning
1038 if (!scanningStarted)
1039 {
1040 // Increment index of current result.
1041 scanIdx++;
1042
1043 // If there are no scanned devices
1044 if (scanIdx >= scanRes)
1045 {
1046 // Prompt the user to begin scanning again.
1047 scanIdx = -1;
1048 Display_print0(dispHandle, 2, 0, "");
1049 Display_print0(dispHandle, 3, 0, "");
1050 Display_print0(dispHandle, 5, 0, "Discover ->");
1051 }
1052 else
1053 {
1054 // Display the indexed scanned device.
1055 Display_print1(dispHandle, 2, 0, "Device %d", (scanIdx + 1));
1056 Display_print0(dispHandle, 3, 0, Util_convertBdAddr2Str(devList[scanIdx].addr));
1057 Display_print0(dispHandle, 5, 0, "Connect ->");
1058 Display_print0(dispHandle, 6, 0, "<- Next Option");
1059 }
1060 }
1061 }
1062 else if (state == BLE_STATE_CONNECTED)
1063 {
1064 keyPressConnOpt = (keyPressConnOpt == DISCONNECT) ? GATT_RW :
1065 (keyPressConnOpt_t) (keyPressConnOpt + 1);
1066
1067 //clear excess lines to keep display clean if another option chosen
1068 Display_doClearLines(dispHandle, 7, 16);
1069
1070 switch (keyPressConnOpt)
1071 {
1072 case GATT_RW:
1073 Display_print0(dispHandle, 5, 0, "GATT Read/Write ->");
1074 break;
1075
1076 case RSSI:
1077 Display_print0(dispHandle, 5, 0, "Toggle Read RSSI ->");
1078 break;
1079
1080 case CONN_UPDATE:
1081 Display_print0(dispHandle, 5, 0, "Connection Update ->");
1082 break;
1083
1084 case GET_CONN_INFO:
1085 Display_print0(dispHandle, 5, 0, "Connection Info ->");
1086 break;
1087
1088 case DISCONNECT:
1089 Display_print0(dispHandle, 5, 0, "Disconnect ->");
1090 break;
1091
1092 default:
1093 break;
1094 }
1095
1096 Display_print0(dispHandle, 6, 0, "<- Next Option");
1097 }
1098
1099 return;
1100 }
1101
1102 if (keys & KEY_RIGHT)
1103 {
1104 if (state == BLE_STATE_IDLE)
1105 {
1106 if (scanIdx == -1)
1107 {
1108 if (!scanningStarted)
1109 {
1110 scanningStarted = TRUE;
1111 scanRes = 0;
1112
1113 Display_print0(dispHandle, 2, 0, "Discovering...");
1114 Display_print0(dispHandle, 3, 0, "");
1115 Display_print0(dispHandle, 4, 0, "");
1116 Display_print0(dispHandle, 5, 0, "");
1117 Display_print0(dispHandle, 6, 0, "");
1118
1119 GAPCentralRole_StartDiscovery(DEFAULT_DISCOVERY_MODE,
1120 DEFAULT_DISCOVERY_ACTIVE_SCAN,
1121 DEFAULT_DISCOVERY_WHITE_LIST);
1122 }
1123 }
1124 // Connect if there is a scan result
1125 else
1126 {
1127 // connect to current device in scan result
1128 uint8_t *peerAddr = devList[scanIdx].addr;
1129 uint8_t addrType = devList[scanIdx].addrType;
1130
1131 state = BLE_STATE_CONNECTING;
1132
1133 // Set a timelimit on the connection establishement
1134 Util_startClock(&startLinkEstClock);
1135
1136 GAPCentralRole_EstablishLink(DEFAULT_LINK_HIGH_DUTY_CYCLE,
1137 DEFAULT_LINK_WHITE_LIST,
1138 addrType, peerAddr);
1139
1140 Display_print0(dispHandle, 2, 0, "Connecting");
1141 Display_print0(dispHandle, 3, 0, Util_convertBdAddr2Str(peerAddr));
1142 Display_clearLine(dispHandle, 4);
1143
1144 // Forget the scan results.
1145 scanRes = 0;
1146 scanIdx = -1;
1147 }
1148 }
1149 else if (state == BLE_STATE_CONNECTED)
1150 {
1151 switch (keyPressConnOpt)
1152 {
1153 case GATT_RW:
1154 if (charHdl != 0 &&
1155 procedureInProgress == FALSE)
1156 {
1157 uint8_t status;
1158
1159 // Do a read or write as long as no other read or write is in progress
1160// if (doWrite)
1161// {
1162// // Do a write
1163// attWriteReq_t req;
1164//
1165// req.pValue = GATT_bm_alloc(connHandle, ATT_WRITE_REQ, 1, NULL);
1166// if ( req.pValue != NULL )
1167// {
1168//// req.handle = charHdl;
1169//// req.len = 1;
1170//// req.pValue[0] = charVal;
1171//// req.sig = 0;
1172//// req.cmd = 0;
1173////
1174//// status = GATT_WriteCharValue(connHandle, &req, selfEntity);
1175//// if ( status != SUCCESS )
1176//// {
1177//// GATT_bm_free((gattMsg_t *)&req, ATT_WRITE_REQ);
1178//// }
1179// }
1180// else
1181// {
1182// status = bleMemAllocError;
1183// }
1184// }
1185// else
1186// {
1187 // Do a read
1188 attReadReq_t req;
1189
1190 req.handle = charHdl;
1191 status = GATT_ReadCharValue(connHandle, &req, selfEntity);
1192// }
1193
1194 if (status == SUCCESS)
1195 {
1196 procedureInProgress = TRUE;
1197 doWrite = !doWrite;
1198 }
1199 }
1200 break;
1201
1202 case RSSI:
1203 // Start or cancel RSSI polling
1204 if (SimpleCentral_RssiFind(connHandle) == NULL)
1205 {
1206 SimpleCentral_StartRssi(connHandle, DEFAULT_RSSI_PERIOD);
1207 }
1208 else
1209 {
1210 SimpleCentral_CancelRssi(connHandle);
1211
1212 Display_print0(dispHandle, 4, 0, "RSSI Cancelled");
1213 }
1214 break;
1215
1216 case CONN_UPDATE:
1217 // Connection update
1218 GAPCentralRole_UpdateLink(connHandle,
1219 DEFAULT_UPDATE_MIN_CONN_INTERVAL,
1220 DEFAULT_UPDATE_MAX_CONN_INTERVAL,
1221 DEFAULT_UPDATE_SLAVE_LATENCY,
1222 DEFAULT_UPDATE_CONN_TIMEOUT);
1223 break;
1224
1225 case GET_CONN_INFO:
1226 pConnInfo= ICall_malloc(sizeof(hciActiveConnInfo_t));
1227
1228 if (pConnInfo != NULL)
1229 {
1230 // This is hard coded to assume we want connection info for a single
1231 // valid connection as is the normal use case for simple central.
1232 // A full featured application may chose to use HCI_EXT_GetConnInfoCmd()
1233 // to obtain a full list of all active connections and their connId's
1234 // to retrive more specific conneciton information if more than one
1235 // valid connectin is expected to exist.
1236 HCI_EXT_GetActiveConnInfoCmd(0, pConnInfo);
1237 Display_print1(dispHandle, 7, 0, "AccessAddress: 0x%x", pConnInfo->accessAddr);
1238 Display_print1(dispHandle, 8, 0, "Connection Interval: %d", pConnInfo->connInterval);
1239 Display_print3(dispHandle, 9, 0, "HopVal:%d, nxtCh:%d, mSCA:%d", \
1240 pConnInfo->hopValue, pConnInfo->nextChan, \
1241 pConnInfo->mSCA);
1242 Display_print5(dispHandle, 10, 0, "ChanMap: \"%x:%x:%x:%x:%x\"",\
1243 pConnInfo->chanMap[4], pConnInfo->chanMap[3],\
1244 pConnInfo->chanMap[2], pConnInfo->chanMap[1],\
1245 pConnInfo->chanMap[0]);
1246
1247 ICall_free(pConnInfo);
1248 }
1249 else
1250 {
1251 Display_print0(dispHandle, 4, 0, "ERROR: Failed to allocate memory for return connection information");
1252 }
1253 break;
1254
1255 case DISCONNECT:
1256 state = BLE_STATE_DISCONNECTING;
1257
1258 GAPCentralRole_TerminateLink(connHandle);
1259
1260 Display_print0(dispHandle, 2, 0, "Disconnecting");
1261 Display_print0(dispHandle, 3, 0, "");
1262 Display_print0(dispHandle, 4, 0, "");
1263 Display_print0(dispHandle, 5, 0, "");
1264
1265 keyPressConnOpt = GATT_RW;
1266 break;
1267
1268 default:
1269 break;
1270 }
1271 }
1272
1273 return;
1274 }
1275}
1276
1277/*********************************************************************
1278 * @fn SimpleCentral_processGATTMsg
1279 *
1280 * @brief Process GATT messages and events.
1281 *
1282 * @return none
1283 */
1284static void SimpleCentral_processGATTMsg(gattMsgEvent_t *pMsg)
1285{
1286 if (state == BLE_STATE_CONNECTED)
1287 {
1288 // See if GATT server was unable to transmit an ATT response
1289 if (pMsg->hdr.status == blePending)
1290 {
1291 // No HCI buffer was available. App can try to retransmit the response
1292 // on the next connection event. Drop it for now.
1293 Display_print1(dispHandle, 4, 0, "ATT Rsp dropped %d", pMsg->method);
1294 }
1295 else if ((pMsg->method == ATT_READ_RSP) ||
1296 ((pMsg->method == ATT_ERROR_RSP) &&
1297 (pMsg->msg.errorRsp.reqOpcode == ATT_READ_REQ)))
1298 {
1299 if (pMsg->method == ATT_ERROR_RSP)
1300 {
1301 Display_print1(dispHandle, 4, 0, "Read Error %d", pMsg->msg.errorRsp.errCode);
1302 }
1303 else
1304 {
1305 // After a successful read, display the read value
1306 Display_print4(dispHandle, 4, 0, "Read rsp: 0x%02x%02x%02x%02x", pMsg->msg.readRsp.pValue[0], pMsg->msg.readRsp.pValue[1], pMsg->msg.readRsp.pValue[2], pMsg->msg.readRsp.pValue[3]);
1307
1308
1309 }
1310
1311 procedureInProgress = FALSE;
1312 }
1313 else if ((pMsg->method == ATT_WRITE_RSP) ||
1314 ((pMsg->method == ATT_ERROR_RSP) &&
1315 (pMsg->msg.errorRsp.reqOpcode == ATT_WRITE_REQ)))
1316 {
1317 if (pMsg->method == ATT_ERROR_RSP)
1318 {
1319 Display_print1(dispHandle, 4, 0, "Write Error %d", pMsg->msg.errorRsp.errCode);
1320 }
1321 else
1322 {
1323 // After a successful write, display the value that was written and
1324 // increment value
1325 Display_print1(dispHandle, 4, 0, "Write sent: %d", charVal++);
1326 }
1327
1328 procedureInProgress = FALSE;
1329
1330 }
1331 else if (pMsg->method == ATT_FLOW_CTRL_VIOLATED_EVENT)
1332 {
1333 // ATT request-response or indication-confirmation flow control is
1334 // violated. All subsequent ATT requests or indications will be dropped.
1335 // The app is informed in case it wants to drop the connection.
1336
1337 // Display the opcode of the message that caused the violation.
1338 Display_print1(dispHandle, 4, 0, "FC Violated: %d", pMsg->msg.flowCtrlEvt.opcode);
1339 }
1340 else if (pMsg->method == ATT_MTU_UPDATED_EVENT)
1341 {
1342 // MTU size updated
1343 Display_print1(dispHandle, 4, 0, "MTU Size: %d", pMsg->msg.mtuEvt.MTU);
1344 }
1345 else if (discState != BLE_DISC_STATE_IDLE || pMsg->method == ATT_READ_BY_GRP_TYPE_RSP)
1346 {
1347 SimpleCentral_processGATTDiscEvent(pMsg);
1348 }
1349 } // else - in case a GATT message came after a connection has dropped, ignore it.
1350
1351 // Needed only for ATT Protocol messages
1352 GATT_bm_free(&pMsg->msg, pMsg->method);
1353
1354//
1355// static int temp = 0;
1356// temp++;
1357// Display_print1(dispHandle, temp, 0, "msg: %d ", pMsg->method);
1358// temp++;
1359// Display_print1(dispHandle, temp, 0, "discState: %d ", discState);
1360
1361
1362
1363}
1364
1365/*********************************************************************
1366 * @fn SimpleCentral_processCmdCompleteEvt
1367 *
1368 * @brief Process an incoming OSAL HCI Command Complete Event.
1369 *
1370 * @param pMsg - message to process
1371 *
1372 * @return none
1373 */
1374static void SimpleCentral_processCmdCompleteEvt(hciEvt_CmdComplete_t *pMsg)
1375{
1376 switch (pMsg->cmdOpcode)
1377 {
1378 case HCI_READ_RSSI:
1379 {
1380#ifndef Display_DISABLE_ALL
1381 int8 rssi = (int8)pMsg->pReturnParam[3];
1382
1383 Display_print1(dispHandle, 4, 0, "RSSI dB: %d", (uint32_t)(rssi));
1384#endif
1385 }
1386 break;
1387
1388 default:
1389 break;
1390 }
1391}
1392
1393/*********************************************************************
1394 * @fn SimpleCentral_StartRssi
1395 *
1396 * @brief Start periodic RSSI reads on a link.
1397 *
1398 * @param connHandle - connection handle of link
1399 * @param period - RSSI read period in ms
1400 *
1401 * @return SUCCESS: Terminate started
1402 * bleIncorrectMode: No link
1403 * bleNoResources: No resources
1404 */
1405static bStatus_t SimpleCentral_StartRssi(uint16_t connHandle, uint16_t period)
1406{
1407 readRssi_t *pRssi;
1408
1409 // Verify link is up
1410 if (!linkDB_Up(connHandle))
1411 {
1412 return bleIncorrectMode;
1413 }
1414
1415 // If already allocated
1416 if ((pRssi = SimpleCentral_RssiFind(connHandle)) != NULL)
1417 {
1418 // Stop timer
1419 Util_stopClock(pRssi->pClock);
1420
1421 pRssi->period = period;
1422 }
1423 // Allocate structure
1424 else if ((pRssi = SimpleCentral_RssiAlloc(connHandle)) != NULL)
1425 {
1426 pRssi->period = period;
1427 }
1428 // Allocate failed
1429 else
1430 {
1431 return bleNoResources;
1432 }
1433
1434 // Start timer
1435 Util_restartClock(pRssi->pClock, period);
1436
1437 return SUCCESS;
1438}
1439
1440/*********************************************************************
1441 * @fn SimpleCentral_CancelRssi
1442 *
1443 * @brief Cancel periodic RSSI reads on a link.
1444 *
1445 * @param connHandle - connection handle of link
1446 *
1447 * @return SUCCESS: Operation successful
1448 * bleIncorrectMode: No link
1449 */
1450static bStatus_t SimpleCentral_CancelRssi(uint16_t connHandle)
1451{
1452 readRssi_t *pRssi;
1453
1454 if ((pRssi = SimpleCentral_RssiFind(connHandle)) != NULL)
1455 {
1456 // Stop timer
1457 Util_stopClock(pRssi->pClock);
1458
1459 // Free RSSI structure
1460 SimpleCentral_RssiFree(connHandle);
1461
1462 return SUCCESS;
1463 }
1464
1465 // Not found
1466 return bleIncorrectMode;
1467}
1468
1469/*********************************************************************
1470 * @fn gapCentralRole_RssiAlloc
1471 *
1472 * @brief Allocate an RSSI structure.
1473 *
1474 * @param connHandle - Connection handle
1475 *
1476 * @return pointer to structure or NULL if allocation failed.
1477 */
1478static readRssi_t *SimpleCentral_RssiAlloc(uint16_t connHandle)
1479{
1480 uint8_t i;
1481
1482 // Find free RSSI structure
1483 for (i = 0; i < MAX_NUM_BLE_CONNS; i++)
1484 {
1485 if (readRssi[i].connHandle == GAP_CONNHANDLE_ALL)
1486 {
1487 readRssi_t *pRssi = &readRssi[i];
1488
1489 pRssi->pClock = (Clock_Struct *)ICall_malloc(sizeof(Clock_Struct));
1490 if (pRssi->pClock)
1491 {
1492 Util_constructClock(pRssi->pClock, SimpleCentral_readRssiHandler,
1493 0, 0, false, i);
1494 pRssi->connHandle = connHandle;
1495
1496 return pRssi;
1497 }
1498 }
1499 }
1500
1501 // No free structure found
1502 return NULL;
1503}
1504
1505/*********************************************************************
1506 * @fn gapCentralRole_RssiFind
1507 *
1508 * @brief Find an RSSI structure.
1509 *
1510 * @param connHandle - Connection handle
1511 *
1512 * @return pointer to structure or NULL if not found.
1513 */
1514static readRssi_t *SimpleCentral_RssiFind(uint16_t connHandle)
1515{
1516 uint8_t i;
1517
1518 // Find free RSSI structure
1519 for (i = 0; i < MAX_NUM_BLE_CONNS; i++)
1520 {
1521 if (readRssi[i].connHandle == connHandle)
1522 {
1523 return &readRssi[i];
1524 }
1525 }
1526
1527 // Not found
1528 return NULL;
1529}
1530
1531/*********************************************************************
1532 * @fn gapCentralRole_RssiFree
1533 *
1534 * @brief Free an RSSI structure.
1535 *
1536 * @param connHandle - Connection handle
1537 *
1538 * @return none
1539 */
1540static void SimpleCentral_RssiFree(uint16_t connHandle)
1541{
1542 uint8_t i;
1543
1544 // Find RSSI structure
1545 for (i = 0; i < MAX_NUM_BLE_CONNS; i++)
1546 {
1547 if (readRssi[i].connHandle == connHandle)
1548 {
1549 readRssi_t *pRssi = &readRssi[i];
1550 if (pRssi->pClock)
1551 {
1552 Clock_destruct(pRssi->pClock);
1553
1554 // Free clock struct
1555 ICall_free(pRssi->pClock);
1556 pRssi->pClock = NULL;
1557 }
1558
1559 pRssi->connHandle = GAP_CONNHANDLE_ALL;
1560 break;
1561 }
1562 }
1563}
1564
1565/*********************************************************************
1566 * @fn SimpleCentral_processPairState
1567 *
1568 * @brief Process the new paring state.
1569 *
1570 * @return none
1571 */
1572static void SimpleCentral_processPairState(uint8_t state, uint8_t status)
1573{
1574 if (state == GAPBOND_PAIRING_STATE_STARTED)
1575 {
1576 Display_print0(dispHandle, 2, 0, "Pairing started");
1577 }
1578 else if (state == GAPBOND_PAIRING_STATE_COMPLETE)
1579 {
1580 if (status == SUCCESS)
1581 {
1582 Display_print0(dispHandle, 2, 0, "Pairing success");
1583 }
1584 else
1585 {
1586 Display_print1(dispHandle, 2, 0, "Pairing fail: %d", status);
1587 }
1588 }
1589 else if (state == GAPBOND_PAIRING_STATE_BONDED)
1590 {
1591 if (status == SUCCESS)
1592 {
1593 Display_print0(dispHandle, 2, 0, "Bonding success");
1594 }
1595 }
1596 else if (state == GAPBOND_PAIRING_STATE_BOND_SAVED)
1597 {
1598 if (status == SUCCESS)
1599 {
1600 Display_print0(dispHandle, 2, 0, "Bond save success");
1601 }
1602 else
1603 {
1604 Display_print1(dispHandle, 2, 0, "Bond save failed: %d", status);
1605 }
1606 }
1607}
1608
1609/*********************************************************************
1610 * @fn SimpleCentral_processPasscode
1611 *
1612 * @brief Process the Passcode request.
1613 *
1614 * @return none
1615 */
1616static void SimpleCentral_processPasscode(uint16_t connectionHandle,
1617 uint8_t uiOutputs)
1618{
1619 // This app uses a default passcode. A real-life scenario would handle all
1620 // pairing scenarios and likely generate this randomly.
1621 uint32_t passcode = B_APP_DEFAULT_PASSCODE;
1622
1623 // Display passcode to user
1624 if (uiOutputs != 0)
1625 {
1626 Display_print1(dispHandle, 4, 0, "Passcode: %d", passcode);
1627 }
1628
1629 // Send passcode response
1630 GAPBondMgr_PasscodeRsp(connectionHandle, SUCCESS, passcode);
1631}
1632
1633/*********************************************************************
1634 * @fn SimpleCentral_startDiscovery
1635 *
1636 * @brief Start service discovery.
1637 *
1638 * @return none
1639 */
1640static void SimpleCentral_startDiscovery(void)
1641{
1642 attExchangeMTUReq_t req;
1643
1644 // Initialize cached handles
1645 svcStartHdl = svcEndHdl = charHdl = 0;
1646
1647 discState = BLE_DISC_STATE_MTU;
1648
1649 // Discover GATT Server's Rx MTU size
1650 req.clientRxMTU = maxPduSize - L2CAP_HDR_SIZE;
1651
1652 // ATT MTU size should be set to the minimum of the Client Rx MTU
1653 // and Server Rx MTU values
1654 VOID GATT_ExchangeMTU(connHandle, &req, selfEntity);
1655}
1656
1657/*********************************************************************
1658 * @fn SimpleCentral_stopEstablishing
1659 *
1660 * @brief Stop Connection Establishement.
1661 *
1662 * @return none
1663 */
1664static void SimpleCentral_stopEstablishing(void)
1665{
1666 GAPCentralRole_TerminateLink(GAP_CONNHANDLE_INIT);
1667 Display_print0(dispHandle, 4, 0, "Conn. Establishement Timeout");
1668 state = BLE_STATE_IDLE;
1669}
1670
1671/*********************************************************************
1672 * @fn SimpleCentral_processGATTDiscEvent
1673 *
1674 * @brief Process GATT discovery event
1675 *
1676 * @return none
1677 */
1678static void SimpleCentral_processGATTDiscEvent(gattMsgEvent_t *pMsg)
1679{
1680
1681 Display_print1(dispHandle, 8, 0, "discState: %d", discState);
1682
1683
1684 if (discState == BLE_DISC_STATE_MTU)
1685 {
1686 // MTU size response received, discover simple service
1687 if (pMsg->method == ATT_EXCHANGE_MTU_RSP)
1688 {
1689
1690 // Just in case we're using the default MTU size (23 octets)
1691 Display_print1(dispHandle, 4, 0, "MTU Size: %d", ATT_MTU_SIZE);
1692
1693 discState = BLE_DISC_STATE_SVC;
1694
1695
1696 int status = GATT_DiscPrimaryServiceByUUID(connHandle, globalUuid, ATT_UUID_SIZE, selfEntity);
1697
1698
1699
1700 }
1701 }
1702 else if (discState == BLE_DISC_STATE_SVC)
1703 {
1704 // Service found, store handles
1705 if (pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP &&
1706 pMsg->msg.findByTypeValueRsp.numInfo > 0)
1707 {
1708
1709 svcStartHdl = ATT_ATTR_HANDLE(pMsg->msg.findByTypeValueRsp.pHandlesInfo, 0);
1710 svcEndHdl = ATT_GRP_END_HANDLE(pMsg->msg.findByTypeValueRsp.pHandlesInfo, 0);
1711 }
1712
1713
1714
1715
1716// // If procedure complete
1717 if ((pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP || pMsg->method == ATT_READ_BY_GRP_TYPE_RSP) &&
1718 (pMsg->hdr.status == bleProcedureComplete)||
1719 (pMsg->method == ATT_ERROR_RSP))
1720 {
1721
1722 attReadByTypeReq_t req;
1723
1724 // Discover characteristic
1725 discState = BLE_DISC_STATE_CHAR;
1726
1727 req.startHandle = svcStartHdl;
1728 req.endHandle = svcEndHdl;
1729 req.type.len = ATT_UUID_SIZE;
1730
1731 uint8 tempArray[ATT_UUID_SIZE] = {0x65, 0xBB, 0x8D, 0x57, 0xBD, 0x06, 0x6B, 0x95, 0xA4, 0x40, 0x7B, 0xA6, 0x01, 0x01, 0x00, 0x00};
1732
1733 for(int i = 0; i < 16; i++){
1734
1735 req.type.uuid[i] = tempArray[i];
1736
1737 }
1738
1739 VOID GATT_DiscCharsByUUID(connHandle, &req, selfEntity);
1740
1741 }
1742 }
1743 else if (discState == BLE_DISC_STATE_CHAR)
1744 {
1745 // Characteristic found, store handle
1746 if ((pMsg->method == ATT_READ_BY_TYPE_RSP) &&
1747 (pMsg->msg.readByTypeRsp.numPairs > 0))
1748 {
1749 charHdl = BUILD_UINT16(pMsg->msg.readByTypeRsp.pDataList[3],
1750 pMsg->msg.readByTypeRsp.pDataList[4]);
1751
1752 Display_print0(dispHandle, 2, 0, "Simple Svc Found");
1753 procedureInProgress = FALSE;
1754 }
1755
1756 discState = BLE_DISC_STATE_IDLE;
1757 }
1758}
1759
1760/*********************************************************************
1761 * @fn SimpleCentral_findSvcUuid
1762 *
1763 * @brief Find a given UUID in an advertiser's service UUID list.
1764 *
1765 * @return TRUE if service UUID found
1766 */
1767static bool SimpleCentral_findSvcUuid(uint64_t uuid, uint8_t *pData,
1768 uint16_t dataLen)
1769{
1770 uint8_t adLen;
1771 uint8_t adType;
1772 uint8_t *pEnd;
1773
1774 if (dataLen > 0)
1775 {
1776 pEnd = pData + dataLen - 1;
1777
1778 // While end of data not reached
1779 while (pData < pEnd)
1780 {
1781 // Get length of next AD item
1782 adLen = *pData++;
1783 if (adLen > 0)
1784 {
1785 adType = *pData;
1786
1787 // If AD type is for 16-bit service UUID
1788 if ((adType == GAP_ADTYPE_16BIT_MORE) ||
1789 (adType == GAP_ADTYPE_16BIT_COMPLETE)||
1790 (adType == GAP_ADTYPE_FLAGS))
1791 {
1792 pData++;
1793 adLen--;
1794
1795 // For each UUID in list
1796 while (pData < pEnd)
1797 {
1798 // Check for match
1799 //if ((pData[0] == LO_UINT16(uuid)) && (pData[1] == LO_UINT16(uuid>>8)) && (pData[2] == LO_UINT16(uuid>>16)) && (pData[3] == LO_UINT16(uuid>>24)) && (pData[4] == LO_UINT16(uuid>>32)) && (pData[5] == LO_UINT16(uuid>>40)))
1800 if ((pData[5] == LO_UINT16(uuid)) && (pData[4] == LO_UINT16(uuid>>8)) && (pData[3] == LO_UINT16(uuid>>16)) && (pData[2] == LO_UINT16(uuid>>24)) && (pData[1] == LO_UINT16(uuid>>32)) && (pData[0] == LO_UINT16(uuid>>40)))
1801
1802 {
1803 // Match found
1804 return TRUE;
1805 }
1806
1807 // Go to next
1808 pData += 1;
1809 //adLen -= 2;
1810 }
1811
1812 // Handle possible erroneous extra byte in UUID list
1813// if (adLen == 1)
1814// {
1815// pData++;
1816// }
1817 }
1818 else
1819 {
1820 // Go to next item
1821 pData += adLen;
1822 }
1823 }
1824 }
1825 }
1826
1827 // Match not found
1828 return FALSE;
1829}
1830/*********************************************************************
1831 * @fn SimpleCentral_addDeviceInfo
1832 *
1833 * @brief Add a device to the device discovery result list
1834 *
1835 * @return none
1836 */
1837static void SimpleCentral_addDeviceInfo(uint8_t *pAddr, uint8_t addrType)
1838{
1839 uint8_t i;
1840
1841 // If result count not at max
1842 if (scanRes < DEFAULT_MAX_SCAN_RES)
1843 {
1844 // Check if device is already in scan results
1845 for (i = 0; i < scanRes; i++)
1846 {
1847 if (memcmp(pAddr, devList[i].addr , B_ADDR_LEN) == 0)
1848 {
1849 return;
1850 }
1851 }
1852
1853 // Add addr to scan result list
1854 memcpy(devList[scanRes].addr, pAddr, B_ADDR_LEN);
1855 devList[scanRes].addrType = addrType;
1856
1857 // Increment scan result count
1858 scanRes++;
1859 }
1860}
1861
1862/*********************************************************************
1863 * @fn SimpleCentral_eventCB
1864 *
1865 * @brief Central event callback function.
1866 *
1867 * @param pEvent - pointer to event structure
1868 *
1869 * @return TRUE if safe to deallocate event message, FALSE otherwise.
1870 */
1871static uint8_t SimpleCentral_eventCB(gapCentralRoleEvent_t *pEvent)
1872{
1873 // Forward the role event to the application
1874 if (SimpleCentral_enqueueMsg(SBC_STATE_CHANGE_EVT,
1875 SUCCESS, (uint8_t *)pEvent))
1876 {
1877 // App will process and free the event
1878 return FALSE;
1879 }
1880
1881 // Caller should free the event
1882 return TRUE;
1883}
1884
1885/*********************************************************************
1886 * @fn SimpleCentral_pairStateCB
1887 *
1888 * @brief Pairing state callback.
1889 *
1890 * @return none
1891 */
1892static void SimpleCentral_pairStateCB(uint16_t connHandle, uint8_t state,
1893 uint8_t status)
1894{
1895 uint8_t *pData;
1896
1897 // Allocate space for the event data.
1898 if ((pData = ICall_malloc(sizeof(uint8_t))))
1899 {
1900 *pData = status;
1901
1902 // Queue the event.
1903 SimpleCentral_enqueueMsg(SBC_PAIRING_STATE_EVT, state, pData);
1904 }
1905}
1906
1907/*********************************************************************
1908 * @fn SimpleCentral_passcodeCB
1909 *
1910 * @brief Passcode callback.
1911 *
1912 * @return none
1913 */
1914static void SimpleCentral_passcodeCB(uint8_t *deviceAddr, uint16_t connHandle,
1915 uint8_t uiInputs, uint8_t uiOutputs,
1916 uint32_t numComparison)
1917{
1918 uint8_t *pData;
1919
1920 // Allocate space for the passcode event.
1921 if ((pData = ICall_malloc(sizeof(uint8_t))))
1922 {
1923 *pData = uiOutputs;
1924
1925 // Enqueue the event.
1926 SimpleCentral_enqueueMsg(SBC_PASSCODE_NEEDED_EVT, 0, pData);
1927 }
1928}
1929
1930/*********************************************************************
1931 * @fn SimpleCentral_linkEstClockHandler
1932 *
1933 * @brief Clock handler function
1934 *
1935 * @param a0 - ignored
1936 *
1937 * @return none
1938 */
1939void SimpleCentral_linkEstClockHandler(UArg a0)
1940{
1941 Event_post(syncEvent, SBC_CONN_EST_TIMEOUT_EVT);
1942}
1943
1944/*********************************************************************
1945 * @fn SimpleCentral_startDiscHandler
1946 *
1947 * @brief Clock handler function
1948 *
1949 * @param a0 - ignored
1950 *
1951 * @return none
1952 */
1953void SimpleCentral_startDiscHandler(UArg a0)
1954{
1955 Event_post(syncEvent, SBC_START_DISCOVERY_EVT);
1956}
1957
1958/*********************************************************************
1959 * @fn SimpleCentral_keyChangeHandler
1960 *
1961 * @brief Key event handler function
1962 *
1963 * @param a0 - ignored
1964 *
1965 * @return none
1966 */
1967void SimpleCentral_keyChangeHandler(uint8 keys)
1968{
1969 SimpleCentral_enqueueMsg(SBC_KEY_CHANGE_EVT, keys, NULL);
1970}
1971
1972/*********************************************************************
1973 * @fn SimpleCentral_readRssiHandler
1974 *
1975 * @brief Read RSSI handler function
1976 *
1977 * @param a0 - read RSSI index
1978 *
1979 * @return none
1980 */
1981void SimpleCentral_readRssiHandler(UArg a0)
1982{
1983 SimpleCentral_enqueueMsg(SBC_RSSI_READ_EVT, SUCCESS,
1984 (uint8_t *)&readRssi[a0]);
1985}
1986
1987/*********************************************************************
1988 * @fn SimpleCentral_enqueueMsg
1989 *
1990 * @brief Creates a message and puts the message in RTOS queue.
1991 *
1992 * @param event - message event.
1993 * @param state - message state.
1994 * @param pData - message data pointer.
1995 *
1996 * @return TRUE or FALSE
1997 */
1998static uint8_t SimpleCentral_enqueueMsg(uint8_t event, uint8_t state,
1999 uint8_t *pData)
2000{
2001 sbcEvt_t *pMsg = ICall_malloc(sizeof(sbcEvt_t));
2002
2003 // Create dynamic pointer to message.
2004 if (pMsg)
2005 {
2006 pMsg->hdr.event = event;
2007 pMsg->hdr.state = state;
2008 pMsg->pData = pData;
2009
2010 // Enqueue the message.
2011 return Util_enqueueMsg(appMsgQueue, syncEvent, (uint8_t *)pMsg);
2012 }
2013
2014 return FALSE;
2015}
2016
2017/*********************************************************************
2018*********************************************************************/