ble_main.c 30.3 KB
Newer Older
1
2
3
4
5
6
7
/* card10:
 * Copied from lib/sdk/Libraries/BTLE/stack/ble-profiles/sources/apps/fit/fit_main.c
 *
 * Also have a look at lib/sdk/Applications/EvKitExamples/BLE_fit/fit_main.c which has some changes
 * to this file regarding handling of OOB paring data
 *
 * This file contains some application logic taken from the "fit" example.
8
9
10
11
12
 *
 * Things have been renamed:
 * fit -> ble
 * Fit -> Ble
 * FIT -> BLE
13
 */
schneider's avatar
schneider committed
14
15
/* clang-format off */
/* clang-formet turned off for easier diffing against orginal file */
16
#include <stdio.h>
17
18
19
#include <string.h>
#include "wsf_types.h"
#include "util/bstream.h"
20
#include "fs/fs_util.h"
21
22
23
#include "wsf_msg.h"
#include "wsf_trace.h"
#include "hci_api.h"
24
#include "l2c_api.h"
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include "dm_api.h"
#include "att_api.h"
#include "smp_api.h"
#include "app_api.h"
#include "app_db.h"
#include "app_ui.h"
#include "app_hw.h"
#include "svc_ch.h"
#include "svc_core.h"
#include "svc_hrs.h"
#include "svc_dis.h"
#include "svc_batt.h"
#include "svc_rscs.h"
#include "bas/bas_api.h"
#include "hrps/hrps_api.h"
#include "rscp/rscp_api.h"
41
#include "profiles/gap_api.h"
schneider's avatar
schneider committed
42
#include "cccd.h"
43

44
#include "ble_api.h"
45
46
#include "epicardium.h"
#include "api/interrupt-sender.h"
47
48
#include "modules/log.h"

49
50
#define SCAN_REPORTS_NUM	16

51
static bool active;
52
53
static uint8_t advertising_mode = APP_MODE_NONE;
static uint8_t advertising_mode_target = APP_MODE_NONE;
54
static enum ble_event_type ble_event;
55
56
57
static struct epic_scan_report scan_reports[SCAN_REPORTS_NUM];
static int scan_reports_head;
static int scan_reports_tail;
58

59
60
61
62
63
/**************************************************************************************************
  Macros
**************************************************************************************************/

/*! WSF message event starting value */
64
#define BLE_MSG_START               0xA0
65
66
67
68

/*! WSF message event enumeration */
enum
{
69
  BLE_BATT_TIMER_IND = BLE_MSG_START,                     /*! Battery measurement timer expired */
70
71
72
73
74
75
76
77
78
79
80
81
82
};

/**************************************************************************************************
  Data Types
**************************************************************************************************/

/*! Application message type */
typedef union
{
  wsfMsgHdr_t     hdr;
  dmEvt_t         dm;
  attsCccEvt_t    ccc;
  attEvt_t        att;
83
} bleMsg_t;
84
85
86
87
88
89

/**************************************************************************************************
  Configurable Parameters
**************************************************************************************************/

/*! configurable parameters for advertising */
90
static const appAdvCfg_t bleAdvCfg =
91
{
92
93
  {0,             0},                  /*! Advertising durations in ms */
  {500/0.625,     0}                   /*! Advertising intervals in 0.625 ms units */
94
95
96
};

/*! configurable parameters for slave */
97
static const appSlaveCfg_t bleSlaveCfg =
98
99
100
101
102
{
  1,                                      /*! Maximum connections */
};

/*! configurable parameters for security */
103
static const appSecCfg_t bleSecCfg =
104
{
105
106
107
108
109
  .auth = DM_AUTH_MITM_FLAG | DM_AUTH_BOND_FLAG | DM_AUTH_SC_FLAG, /*! Authentication and bonding flags */
  .iKeyDist = 0,                               /*! Initiator key distribution flags */
  .rKeyDist = DM_KEY_DIST_LTK,                 /*! Responder key distribution flags */
  .oob=FALSE,                                  /*! TRUE if Out-of-band pairing data is present */
  .initiateSec = TRUE                          /*! TRUE to initiate security upon connection */
110
111
112
};

/*! configurable parameters for connection parameter update */
113
static const appUpdateCfg_t bleUpdateCfg =
114
115
116
{
  6000,                                   /*! Connection idle period in ms before attempting
                                              connection parameter update; set to zero to disable */
117
118
119
  30/1.25,                                 /*! Minimum connection interval in 1.25ms units.
                                              Values < 8 didn't work with my Tinkpad T470 */
  40/1.25,                                /*! Maximum connection interval in 1.25ms units */
120
  0,                                      /*! Connection latency */
121
  9000/10,                                /*! Supervision timeout in 10ms units */
122
123
124
125
  5                                       /*! Number of update attempts before giving up */
};

/*! battery measurement configuration */
126
static const basCfg_t bleBasCfg =
127
128
129
130
131
132
133
{
  30,       /*! Battery measurement timer expiration period in seconds */
  1,        /*! Perform battery measurement after this many timer periods */
  100       /*! Send battery level notification to peer when below this level. */
};

/*! SMP security parameter configuration */
134
static const smpCfg_t bleSmpCfg =
135
{
136
137
138
139
140
141
142
143
144
  .attemptTimeout = 3000,                          /*! 'Repeated attempts' timeout in msec */
  .ioCap = SMP_IO_DISP_YES_NO,                     /*! I/O Capability */
  .minKeyLen = 16,                                 /*! Minimum encryption key length */
  .maxKeyLen = 16,                                 /*! Maximum encryption key length */
  .maxAttempts = 3,                                /*! Attempts to trigger 'repeated attempts' timeout */
  .auth = DM_AUTH_MITM_FLAG | DM_AUTH_SC_FLAG,     /*! Device authentication requirements */
  .maxAttemptTimeout = 64000,                      /*! Maximum 'Repeated attempts' timeout in msec */
  .attemptDecTimeout = 64000,                      /*! Time msec before attemptExp decreases */
  .attemptExp = 2,                                 /*! Exponent to raise attemptTimeout on maxAttempts */
145
146
};

schneider's avatar
schneider committed
147
148
149
150
151
152
/*! Configurable parameters for service and characteristic discovery */
static const appDiscCfg_t bleDiscCfg =
{
  FALSE                                   /*! TRUE to wait for a secure connection before initiating discovery */
};

153
154
155
156
157
158
159
160
161
/* Configuration structure */
static const attCfg_t bleAttCfg =
{
  15,                                  /* ATT server service discovery connection idle timeout in seconds */
  241,                                 /* desired ATT MTU */
  ATT_MAX_TRANS_TIMEOUT,               /* transaction timeout in seconds */
  1                                    /* number of queued prepare writes supported by server */
};

162
163
164
165
166
/**************************************************************************************************
  Advertising Data
**************************************************************************************************/

/*! advertising data, discoverable mode */
167
static const uint8_t bleAdvDataDisc[] =
168
169
170
171
{
  /*! flags */
  2,                                      /*! length */
  DM_ADV_TYPE_FLAGS,                      /*! AD type */
172
  DM_FLAG_LE_LIMITED_DISC |               /*! flags */
173
174
  DM_FLAG_LE_BREDR_NOT_SUP,

175
176
177
  3,
  DM_ADV_TYPE_APPEARANCE,
  UINT16_TO_BYTES(CH_APPEAR_WATCH),
178
179

  /*! service UUID list */
180
181
  17,
  DM_ADV_TYPE_128_UUID_PART,
182
183
184
185
186
  CARD10_UUID_SUFFIX, 0x0, CARD10_UUID_PREFIX,

  2,                                      /*! length */
  DM_ADV_TYPE_TX_POWER,                   /*! AD type */
  0,                                      /*! tx power */
187
188
189
};

/*! scan data, discoverable mode */
190
uint8_t bleScanDataDisc[] =
191
192
{
  /*! device name */
193
  14,                                      /*! length */
194
  DM_ADV_TYPE_LOCAL_NAME,                 /*! AD type */
195
196
197
198
199
  'c','a','r','d','1','0','-','0','0','0','0','0','0',

  3,                                      /*! length */
  DM_ADV_TYPE_16_SOLICIT,                 /*! AD type */
  UINT16_TO_BYTES(ATT_UUID_CURRENT_TIME_SERVICE),
200
201
};

202
203
204
205
206
207
208
209
210
/*! advertising data, connectable mode */
static const uint8_t bleAdvDataConn[] =
{
  /*! flags */
  2,                                      /*! length */
  DM_ADV_TYPE_FLAGS,                      /*! AD type */
  DM_FLAG_LE_BREDR_NOT_SUP,
};

211
212
213
214
215
216
217
218
219
static const appMasterCfg_t scannerMasterCfg =
{
  420,                                     /*! The scan interval, in 0.625 ms units */
  420,                                     /*! The scan window, in 0.625 ms units  */
  0,                                       /*! The scan duration in ms */
  DM_DISC_MODE_NONE,                       /*! The GAP discovery mode */
  DM_SCAN_TYPE_PASSIVE
                                           /*!< The scan type (active or passive) */
};
220

221
222
223
224
225
/**************************************************************************************************
  Client Characteristic Configuration Descriptors
**************************************************************************************************/

/*! client characteristic configuration descriptors settings, indexed by above enumeration */
226
static const attsCccSet_t bleCccSet[BLE_NUM_CCC_IDX] =
227
228
{
  /* cccd handle          value range               security level */
229
230
  {GATT_SC_CH_CCC_HDL,    ATT_CLIENT_CFG_INDICATE,  DM_SEC_LEVEL_NONE},   /* BLE_GATT_SC_CCC_IDX */
  {BATT_LVL_CH_CCC_HDL,   ATT_CLIENT_CFG_NOTIFY,    DM_SEC_LEVEL_NONE},   /* BLE_BATT_LVL_CCC_IDX */
231
232
233
234
235
236
237
};

/**************************************************************************************************
  Global Variables
**************************************************************************************************/

/*! WSF handler ID */
238
wsfHandlerId_t bleHandlerId;
239

240
241
static dmConnId_t pair_connId = DM_CONN_ID_NONE;
static uint32_t pair_confirm_value;
242
static appDbHdl_t last_pairing = NULL;
243

244
static void BleHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg);
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347

static const char * const att_events[] = {
	"ATTC_FIND_INFO_RSP",
	"ATTC_FIND_BY_TYPE_VALUE_RSP",
	"ATTC_READ_BY_TYPE_RSP",
	"ATTC_READ_RSP",
	"ATTC_READ_LONG_RSP",
	"ATTC_READ_MULTIPLE_RSP",
	"ATTC_READ_BY_GROUP_TYPE_RSP",
	"ATTC_WRITE_RSP",
	"ATTC_WRITE_CMD_RSP",
	"ATTC_PREPARE_WRITE_RSP",
	"ATTC_EXECUTE_WRITE_RSP",
	"ATTC_HANDLE_VALUE_NTF",
	"ATTC_HANDLE_VALUE_IND",
	/* ATT server callback events */
	"ATTS_HANDLE_VALUE_CNF",
	"ATTS_CCC_STATE_IND",
	"ATTS_DB_HASH_CALC_CMPL_IND",
	/* ATT common callback events */
	"ATT_MTU_UPDATE_IND"
};

static const char * const dm_events[] = {
    "DM_RESET_CMPL_IND",
    "DM_ADV_START_IND",
    "DM_ADV_STOP_IND",
    "DM_ADV_NEW_ADDR_IND",
    "DM_SCAN_START_IND",
    "DM_SCAN_STOP_IND",
    "DM_SCAN_REPORT_IND",
    "DM_CONN_OPEN_IND",
    "DM_CONN_CLOSE_IND",
    "DM_CONN_UPDATE_IND",
    "DM_SEC_PAIR_CMPL_IND",
    "DM_SEC_PAIR_FAIL_IND",
    "DM_SEC_ENCRYPT_IND",
    "DM_SEC_ENCRYPT_FAIL_IND",
    "DM_SEC_AUTH_REQ_IND",
    "DM_SEC_KEY_IND",
    "DM_SEC_LTK_REQ_IND",
    "DM_SEC_PAIR_IND",
    "DM_SEC_SLAVE_REQ_IND",
    "DM_SEC_CALC_OOB_IND",
    "DM_SEC_ECC_KEY_IND",
    "DM_SEC_COMPARE_IND",
    "DM_SEC_KEYPRESS_IND",
    "DM_PRIV_RESOLVED_ADDR_IND",
    "DM_PRIV_GENERATE_ADDR_IND",
    "DM_CONN_READ_RSSI_IND",
    "DM_PRIV_ADD_DEV_TO_RES_LIST_IND",
    "DM_PRIV_REM_DEV_FROM_RES_LIST_IND",
    "DM_PRIV_CLEAR_RES_LIST_IND",
    "DM_PRIV_READ_PEER_RES_ADDR_IND",
    "DM_PRIV_READ_LOCAL_RES_ADDR_IND",
    "DM_PRIV_SET_ADDR_RES_ENABLE_IND",
    "DM_REM_CONN_PARAM_REQ_IND",
    "DM_CONN_DATA_LEN_CHANGE_IND",
    "DM_CONN_WRITE_AUTH_TO_IND",
    "DM_CONN_AUTH_TO_EXPIRED_IND",
    "DM_PHY_READ_IND",
    "DM_PHY_SET_DEF_IND",
    "DM_PHY_UPDATE_IND",
    "DM_ADV_SET_START_IND",
    "DM_ADV_SET_STOP_IND",
    "DM_SCAN_REQ_RCVD_IND",
    "DM_EXT_SCAN_START_IND",
    "DM_EXT_SCAN_STOP_IND",
    "DM_EXT_SCAN_REPORT_IND",
    "DM_PER_ADV_SET_START_IND",
    "DM_PER_ADV_SET_STOP_IND",
    "DM_PER_ADV_SYNC_EST_IND",
    "DM_PER_ADV_SYNC_EST_FAIL_IND",
    "DM_PER_ADV_SYNC_LOST_IND",
    "DM_PER_ADV_SYNC_TRSF_EST_IND",
    "DM_PER_ADV_SYNC_TRSF_EST_FAIL_IND",
    "DM_PER_ADV_SYNC_TRSF_IND",
    "DM_PER_ADV_SET_INFO_TRSF_IND",
    "DM_PER_ADV_REPORT_IND",
    "DM_REMOTE_FEATURES_IND",
    "DM_READ_REMOTE_VER_INFO_IND",
    "DM_CONN_IQ_REPORT_IND",
    "DM_CTE_REQ_FAIL_IND",
    "DM_CONN_CTE_RX_SAMPLE_START_IND",
    "DM_CONN_CTE_RX_SAMPLE_STOP_IND",
    "DM_CONN_CTE_TX_CFG_IND",
    "DM_CONN_CTE_REQ_START_IND",
    "DM_CONN_CTE_REQ_STOP_IND",
    "DM_CONN_CTE_RSP_START_IND",
    "DM_CONN_CTE_RSP_STOP_IND",
    "DM_READ_ANTENNA_INFO_IND",
    "DM_L2C_CMD_REJ_IND",
    "DM_ERROR_IND",
    "DM_HW_ERROR_IND",
    "DM_VENDOR_SPEC_IND"
};

static const char * const l2c_coc_events[] = {
	"L2C_COC_CONNECT_IND",
	"L2C_COC_DISCONNECT_IND",
	"L2C_COC_DATA_IND",
	"L2C_COC_DATA_CNF"
};
348
349
350
351
352
353
354
355
356
/*************************************************************************************************/
/*!
 *  \brief  Application DM callback.
 *
 *  \param  pDmEvt  DM callback event
 *
 *  \return None.
 */
/*************************************************************************************************/
357
static void bleDmCback(dmEvt_t *pDmEvt)
358
359
360
361
362
363
364
365
366
{
  dmEvt_t *pMsg;
  uint16_t len;

  len = DmSizeOfEvt(pDmEvt);

  if ((pMsg = WsfMsgAlloc(len)) != NULL)
  {
    memcpy(pMsg, pDmEvt, len);
367
    WsfMsgSend(bleHandlerId, pMsg);
368
369
370
371
372
373
374
375
376
377
378
379
  }
}

/*************************************************************************************************/
/*!
 *  \brief  Application ATT callback.
 *
 *  \param  pEvt    ATT callback event
 *
 *  \return None.
 */
/*************************************************************************************************/
380
static void bleAttCback(attEvt_t *pEvt)
381
382
383
384
385
386
387
388
{
  attEvt_t *pMsg;

  if ((pMsg = WsfMsgAlloc(sizeof(attEvt_t) + pEvt->valueLen)) != NULL)
  {
    memcpy(pMsg, pEvt, sizeof(attEvt_t));
    pMsg->pValue = (uint8_t *) (pMsg + 1);
    memcpy(pMsg->pValue, pEvt->pValue, pEvt->valueLen);
389
    WsfMsgSend(bleHandlerId, pMsg);
390
391
392
393
394
395
396
397
398
399
400
401
  }
}

/*************************************************************************************************/
/*!
 *  \brief  Application ATTS client characteristic configuration callback.
 *
 *  \param  pDmEvt  DM callback event
 *
 *  \return None.
 */
/*************************************************************************************************/
402
static void bleCccCback(attsCccEvt_t *pEvt)
403
404
405
406
407
408
409
410
411
412
{
  attsCccEvt_t  *pMsg;
  appDbHdl_t    dbHdl;

  /* if CCC not set from initialization and there's a device record */
  if ((pEvt->handle != ATT_HANDLE_NONE) &&
      ((dbHdl = AppDbGetHdl((dmConnId_t) pEvt->hdr.param)) != APP_DB_HDL_NONE))
  {
    /* store value in device database */
    AppDbSetCccTblValue(dbHdl, pEvt->idx, pEvt->value);
413
    AppDbNvmStoreCccTbl(dbHdl);
414
415
416
417
418
  }

  if ((pMsg = WsfMsgAlloc(sizeof(attsCccEvt_t))) != NULL)
  {
    memcpy(pMsg, pEvt, sizeof(attsCccEvt_t));
419
    WsfMsgSend(bleHandlerId, pMsg);
420
421
422
423
424
425
426
427
428
429
430
431
432
433
  }
}



/*************************************************************************************************/
/*!
 *  \brief  Process CCC state change.
 *
 *  \param  pMsg    Pointer to message.
 *
 *  \return None.
 */
/*************************************************************************************************/
434
static void bleProcCccState(bleMsg_t *pMsg)
435
436
437
438
{
  APP_TRACE_INFO3("ccc state ind value:%d handle:%d idx:%d", pMsg->ccc.value, pMsg->ccc.handle, pMsg->ccc.idx);

  /* handle battery level CCC */
439
  if (pMsg->ccc.idx == BLE_BATT_LVL_CCC_IDX)
440
441
442
  {
    if (pMsg->ccc.value == ATT_CLIENT_CFG_NOTIFY)
    {
443
      BasMeasBattStart((dmConnId_t) pMsg->ccc.hdr.param, BLE_BATT_TIMER_IND, BLE_BATT_LVL_CCC_IDX);
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
    }
    else
    {
      BasMeasBattStop((dmConnId_t) pMsg->ccc.hdr.param);
    }
    return;
  }
}

/*************************************************************************************************/
/*!
 *  \brief  Perform UI actions on connection close.
 *
 *  \param  pMsg    Pointer to message.
 *
 *  \return None.
 */
/*************************************************************************************************/
462
static void bleClose(bleMsg_t *pMsg)
463
464
465
{
  /* stop battery measurement */
  BasMeasBattStop((dmConnId_t) pMsg->hdr.param);
466
  GapClearDeviceName();
467
468
469
470
471
472
473
474
475
476
477
478
}

/*************************************************************************************************/
/*!
 *  \brief  Set up advertising and other procedures that need to be performed after
 *          device reset.
 *
 *  \param  pMsg    Pointer to message.
 *
 *  \return None.
 */
/*************************************************************************************************/
479
static void bleSetup(bleMsg_t *pMsg)
480
{
481
  char buf[32];
482
  char a, b, c, d, e, f, K;
483

484
485
  int result = epic_config_get_string("ble_mac", buf, sizeof(buf));
  if (result == 0)
486
  {
487
    if (sscanf(buf, "%c%c:%c%c:%c%c:%c%c:%c%c:%c%c", &K,&K,&K,&K,&K,&K, &a, &b, &c, &d, &e, &f) == 12)
488
489
490
491
492
493
494
495
496
    {
      bleScanDataDisc[9]  = a;
      bleScanDataDisc[10] = b;
      bleScanDataDisc[11] = c;
      bleScanDataDisc[12] = d;
      bleScanDataDisc[13] = e;
      bleScanDataDisc[14] = f;
    }
  }
Rahix's avatar
Rahix committed
497

498
  /* set advertising and scan response data for discoverable mode */
499
500
  AppAdvSetData(APP_ADV_DATA_DISCOVERABLE, sizeof(bleAdvDataDisc), (uint8_t *) bleAdvDataDisc);
  AppAdvSetData(APP_SCAN_DATA_DISCOVERABLE, sizeof(bleScanDataDisc), (uint8_t *) bleScanDataDisc);
501
502

  /* set advertising and scan response data for connectable mode */
503
  AppAdvSetData(APP_ADV_DATA_CONNECTABLE, sizeof(bleAdvDataConn), (uint8_t *) bleAdvDataConn);
504
505
  AppAdvSetData(APP_SCAN_DATA_CONNECTABLE, 0, NULL);

506
  active = true;
507
  /* TODO: Sadly, not advertising leads to a higher current consumption... */
508
  epic_ble_set_mode(false, false);
509
510
}

511
void epic_ble_set_mode(bool bondable, bool scanner)
512
513
514
515
516
{
	if(!active) {
		return;
	}

517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
	if(scanner && bondable) {
		/* TODO: return error */
		return;
	}

	if(scanner) {
		if(advertising_mode != APP_MODE_NONE) {
			advertising_mode_target = APP_MODE_NONE;
			advertising_mode = APP_MODE_NONE;
			AppAdvStop();
		}

		dmConnId_t      connId;
		if ((connId = AppConnIsOpen()) != DM_CONN_ID_NONE) {
			AppConnClose(connId);
		}

		/* Normal scanning filters out duplicates. We don't
		* want that for now... */
		//AppScanStart(scannerMasterCfg.discMode, scannerMasterCfg.scanType, scannerMasterCfg.scanDuration);
		DmScanSetInterval(HCI_SCAN_PHY_LE_1M_BIT, &pAppMasterCfg->scanInterval,
				&pAppMasterCfg->scanWindow);
		DmScanStart(HCI_SCAN_PHY_LE_1M_BIT, scannerMasterCfg.discMode,
				&scannerMasterCfg.scanType, FALSE, scannerMasterCfg.scanDuration, 0);

		return;
	} else {
		AppScanStop();
	}

547
548
	if(bondable) {
		/* We need to stop advertising in between or the
549
550
551
552
553
		 * adv set will not be changed.
		 * Also need to wait for the stop operation to finish
		 * before we can start again
		 * Also need to set the variables first as we don't
		 * have a lock on the stack.*/
554
		AppSetBondable(TRUE);
555
556
557
558
559
560
561
562
563
564
565
566
		if(advertising_mode != APP_MODE_DISCOVERABLE) {
			LOG_INFO("ble", "Making bondable and discoverable");
			if(advertising_mode != APP_MODE_NONE) {
				advertising_mode_target = APP_MODE_DISCOVERABLE;
				advertising_mode = APP_MODE_NONE;
				AppAdvStop();
			} else {
				advertising_mode = APP_MODE_DISCOVERABLE;
				advertising_mode_target = APP_MODE_DISCOVERABLE;
				AppAdvStart(advertising_mode);
			}
		}
567
568
569
	} else {
		AppSetBondable(FALSE);
		if(AppDbCheckBonded()) {
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
			if(advertising_mode != APP_MODE_CONNECTABLE) {
				LOG_INFO("ble", "Bonded. Making connectable");
				if(advertising_mode != APP_MODE_NONE) {
					advertising_mode_target = APP_MODE_CONNECTABLE;
					advertising_mode = APP_MODE_NONE;
					AppAdvStop();
				} else {
					advertising_mode = APP_MODE_CONNECTABLE;
					advertising_mode_target = APP_MODE_CONNECTABLE;
					AppAdvStart(advertising_mode);
				}
			}
		} else {
			if(advertising_mode != APP_MODE_NONE) {
				LOG_INFO("ble", "Not bonded. Stop advertising");
				advertising_mode = APP_MODE_NONE;
				advertising_mode_target = APP_MODE_NONE;
				AppAdvStop();
			}
589
590
		}
	}
591
592
}

593
uint32_t epic_ble_get_compare_value(void)
594
{
595
596
597
	return pair_confirm_value;
}

598
599
600
601
602
603
604
605
606
int epic_ble_get_peer_device_name(char *buf, size_t buf_size)
{
	if (AppConnIsOpen() != DM_CONN_ID_NONE) {
		return GapGetDeviceName(buf, buf_size);
	} else {
		return -ENOENT;
	}
}

607
608
609
610
611
612
613
614
615
int epic_ble_get_last_pairing_name(char *buf, size_t buf_size)
{
	if(last_pairing == NULL) {
		return -ENOENT;
	}

	return AppDbGetPairingName(last_pairing, buf, buf_size);
}

616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
void epic_ble_compare_response(bool confirmed)
{
	if(!active) {
		return;
	}

	if(pair_connId != DM_CONN_ID_NONE) {
		LOG_INFO("ble", "Value confirmed: %u", confirmed);
		DmSecCompareRsp(pair_connId, confirmed);
	} else {
		/* error condition */
	}
}
static void trigger_event(enum ble_event_type event)
{
	bool enabled;
	epic_interrupt_is_enabled(EPIC_INT_BLE, &enabled);
633
634
635
636

	/* Print a warning if the app is missing events. Missing scan results
	 * is considered OK though, as they are queued and periodic. */
	if(ble_event && enabled && ble_event != BLE_EVENT_SCAN_REPORT) {
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
		LOG_WARN("ble", "Application missed event %u", ble_event);
	}

	ble_event = event;
	api_interrupt_trigger(EPIC_INT_BLE);
}

enum ble_event_type epic_ble_get_event(void)
{
	enum ble_event_type event = ble_event;
	ble_event = 0;
	return event;
}

static void bleHandleNumericComparison(dmSecCnfIndEvt_t *pCnfInd)
{
	if(!active) {
		return;
	}

657
	pair_connId = (dmConnId_t)pCnfInd->hdr.param;
658
659
660
	pair_confirm_value = DmSecGetCompareValue(pCnfInd->confirm);
	LOG_INFO("ble", "Confirm Value: %ld", pair_confirm_value);
	trigger_event(BLE_EVENT_HANDLE_NUMERIC_COMPARISON);
661
}
662

663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
int epic_ble_get_scan_report(struct epic_scan_report *rpt)
{
	if(scan_reports_head == scan_reports_tail) {
		return -ENOENT;
	}

	int new_tail = (scan_reports_tail + 1) % SCAN_REPORTS_NUM;
	*rpt = scan_reports[new_tail];
	scan_reports_tail = new_tail;
	return 0;
}

static void scannerScanReport(dmEvt_t *pMsg)
{
	struct epic_scan_report *scan_report;

	int next_head = (scan_reports_head + 1) % SCAN_REPORTS_NUM;
	if(next_head == scan_reports_tail) {
		trigger_event(BLE_EVENT_SCAN_REPORT);
		return;
	}
	scan_reports_head = next_head;
	scan_report = &scan_reports[scan_reports_head];

	memset(scan_report->data, 0, sizeof(scan_report->data));
	memccpy(scan_report->data, pMsg->scanReport.pData, pMsg->scanReport.len, sizeof(scan_report->data));
	scan_report->len = pMsg->scanReport.len;
	scan_report->rssi = pMsg->scanReport.rssi;
	scan_report->eventType = pMsg->scanReport.eventType;
	scan_report->addrType = pMsg->scanReport.addrType;
	memcpy(scan_report->addr, pMsg->scanReport.addr, BDA_ADDR_LEN);

	scan_report->directAddrType = pMsg->scanReport.directAddrType;
	memcpy(scan_report->directAddr, pMsg->scanReport.directAddr, BDA_ADDR_LEN);
	trigger_event(BLE_EVENT_SCAN_REPORT);

	if((scan_reports_head + 1) % SCAN_REPORTS_NUM == scan_reports_tail) {
		LOG_WARN("ble", "Application missing scan results");
	}
}

704
705
706
707
708
709
710
711
712
/*************************************************************************************************/
/*!
 *  \brief  Process messages from the event handler.
 *
 *  \param  pMsg    Pointer to message.
 *
 *  \return None.
 */
/*************************************************************************************************/
713
static void bleProcMsg(bleMsg_t *pMsg)
714
{
715
  hciLeConnCmplEvt_t *connOpen;
716
717
718

  switch(pMsg->hdr.event)
  {
719
    case BLE_BATT_TIMER_IND:
720
721
722
      BasProcMsg(&pMsg->hdr);
      break;

schneider's avatar
schneider committed
723
724
725
726
727
    case ATTC_READ_RSP:
    case ATTC_HANDLE_VALUE_IND:
      bleValueUpdate((attEvt_t *) pMsg);
      break;

728
729
730
731
732
    case ATTS_HANDLE_VALUE_CNF:
      BasProcMsg(&pMsg->hdr);
      break;

    case ATTS_CCC_STATE_IND:
733
      bleProcCccState(pMsg);
734
735
736
737
      break;

    case DM_RESET_CMPL_IND:
      DmSecGenerateEccKeyReq();
738
      bleSetup(pMsg);
739
740
741
      break;

    case DM_ADV_START_IND:
742
      LOG_INFO("ble", "Advertisement started %u %u", advertising_mode, advertising_mode_target);
743
      if(advertising_mode != advertising_mode_target || advertising_mode_target == APP_MODE_NONE) {
744
745
        AppAdvStop();
      }
746
747
748
      break;

    case DM_ADV_STOP_IND:
749
750
751
752
753
      LOG_INFO("ble", "Advertisement stopped %u %u", advertising_mode, advertising_mode_target);
      if(advertising_mode != advertising_mode_target) {
        advertising_mode = advertising_mode_target;
        AppAdvStart(advertising_mode);
      }
754
755
756
      break;

    case DM_CONN_OPEN_IND:
757
758
      connOpen = &pMsg->dm.connOpen;
      LOG_INFO("ble", "connection from %02X:%02X:%02X:%02X:%02X:%02X opened",
759
760
761
               connOpen->peerAddr[5], connOpen->peerAddr[4],
               connOpen->peerAddr[3], connOpen->peerAddr[2],
               connOpen->peerAddr[1], connOpen->peerAddr[0]);
762
763
764
765
      BasProcMsg(&pMsg->hdr);
      break;

    case DM_CONN_CLOSE_IND:
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
      switch (pMsg->dm.connClose.reason)
      {
        case HCI_ERR_CONN_TIMEOUT:
          LOG_INFO("ble", "Connection closed (0x%02X), Connection timeout",
                   pMsg->dm.connClose.reason);
          break;
        case HCI_ERR_LOCAL_TERMINATED:
          LOG_INFO("ble", "Connection closed (0x%02X), Connection terminated by local host",
                   pMsg->dm.connClose.reason);
          break;
        case HCI_ERR_REMOTE_TERMINATED:
          LOG_INFO("ble", "Connection closed (0x%02X), Remote user terminated connection",
                   pMsg->dm.connClose.reason);
          break;
        case HCI_ERR_CONN_FAIL:
          LOG_INFO("ble", "Connection closed (0x%02X), Connection failed to be established",
                   pMsg->dm.connClose.reason);
          break;
        case HCI_ERR_MIC_FAILURE:
          LOG_INFO("ble", "Connection closed (0x%02X), Connection terminated due to MIC failure",
                   pMsg->dm.connClose.reason);
          break;
        default:
          LOG_INFO("ble", "Connection closed (0x%02X)",
                   pMsg->dm.connClose.reason);
          break;
      }
793
794
795
796
797
798
      /* Stack overwrites advertising mode after connection close.
       * Force our desired mode.
       */
      advertising_mode = APP_MODE_NONE;
      AppAdvStop();

799
      bleClose(pMsg);
800
801
802
      break;

    case DM_SEC_PAIR_CMPL_IND:
803
804
      LOG_INFO("ble", "Secure pairing successful, auth: 0x%02X",
               pMsg->dm.pairCmpl.auth);
805

806
      DmSecGenerateEccKeyReq();
807
808
      last_pairing = AppDbGetHdl((dmConnId_t) pMsg->hdr.param);
      AppDbNvmStoreBond(last_pairing);
809

810
811
      pair_connId = DM_CONN_ID_NONE;
      trigger_event(BLE_EVENT_PAIRING_COMPLETE);
812
813
814
      /* After a successful pairing, bonding is disabled again.
       * We don't want that for now. */
      AppSetBondable(TRUE);
815
816
817
      break;

    case DM_SEC_PAIR_FAIL_IND:
818
819
820
821
822
823
824
825
826
827
828
829
830
831
      switch (pMsg->hdr.status) {
        case SMP_ERR_TIMEOUT:
          LOG_INFO("ble", "Secure pairing failed (0x%02X), Transaction timeout",
                   pMsg->hdr.status);
          break;
        case SMP_ERR_ATTEMPTS:
          LOG_INFO("ble", "Secure pairing failed (0x%02X), Repeated attempts",
                   pMsg->hdr.status);
          break;
        default:
          LOG_INFO("ble", "Secure pairing failed (0x%02X)",
                   pMsg->hdr.status);
          break;
      }
832
833
834

      DmSecGenerateEccKeyReq();

835
836
      pair_connId = DM_CONN_ID_NONE;
      trigger_event(BLE_EVENT_PAIRING_FAILED);
837
838
839
      break;

    case DM_SEC_ENCRYPT_IND:
840
      LOG_INFO("ble", "Encrypted handshake successful");
841
842
843
      break;

    case DM_SEC_ENCRYPT_FAIL_IND:
844
      LOG_INFO("ble", "Encrypted handshake failed");
845
846
847
848
849
850
851
852
853
854
855
      break;

    case DM_SEC_AUTH_REQ_IND:
      AppHandlePasskey(&pMsg->dm.authReq);
      break;

    case DM_SEC_ECC_KEY_IND:
      DmSecSetEccKey(&pMsg->dm.eccMsg.data.key);
      break;

    case DM_SEC_COMPARE_IND:
856
      bleHandleNumericComparison(&pMsg->dm.cnfInd);
857
858
      break;

859
860
861
862
    case DM_SCAN_REPORT_IND:
      scannerScanReport((dmEvt_t *)pMsg);
      break;

863
    case DM_HW_ERROR_IND:
864
      LOG_ERR("ble", "HW Error");
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
      break;

    default:
      break;
  }
}

/*************************************************************************************************/
/*!
 *  \brief  Application handler init function called during system initialization.
 *
 *  \param  handlerID  WSF handler ID.
 *
 *  \return None.
 */
/*************************************************************************************************/
881
static void BleHandlerInit(void)
882
{
883
  APP_TRACE_INFO0("BleHandlerInit");
884
885

  /* store handler ID */
886
  bleHandlerId =WsfOsSetNextHandler(BleHandler);
887
888

  /* Set configuration pointers */
889
890
891
892
  pAppAdvCfg = (appAdvCfg_t *) &bleAdvCfg;
  pAppSlaveCfg = (appSlaveCfg_t *) &bleSlaveCfg;
  pAppSecCfg = (appSecCfg_t *) &bleSecCfg;
  pAppUpdateCfg = (appUpdateCfg_t *) &bleUpdateCfg;
schneider's avatar
schneider committed
893
  pAppDiscCfg = (appDiscCfg_t *) &bleDiscCfg;
894
  pAppMasterCfg = (appMasterCfg_t *) &scannerMasterCfg;
895
896
897

  /* Initialize application framework */
  AppSlaveInit();
schneider's avatar
schneider committed
898
  AppDiscInit();
899
900

  /* Set stack configuration pointers */
901
  pSmpCfg = (smpCfg_t *) &bleSmpCfg;
902
  pAttCfg = (attCfg_t *) &bleAttCfg;
903
904

  /* initialize battery service server */
905
  BasInit(bleHandlerId, (basCfg_t *) &bleBasCfg);
906
907
908
909
910
911
912
913
914
915
916
917
}

/*************************************************************************************************/
/*!
 *  \brief  WSF event handler for application.
 *
 *  \param  event   WSF event mask.
 *  \param  pMsg    WSF message.
 *
 *  \return None.
 */
/*************************************************************************************************/
918
static void BleHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg)
919
920
921
{
  if (pMsg != NULL)
  {
922
    APP_TRACE_INFO1("Ble got evt %d", pMsg->event);
923
924
925

    if (pMsg->event >= DM_CBACK_START && pMsg->event <= DM_CBACK_END)
    {
926
      if(pMsg->event != DM_SCAN_REPORT_IND) LOG_INFO("ble", "Ble got evt %d: %s", pMsg->event, dm_events[pMsg->event - DM_CBACK_START]);
927
928
929
930
931
      /* process advertising and connection-related messages */
      AppSlaveProcDmMsg((dmEvt_t *) pMsg);

      /* process security-related messages */
      AppSlaveSecProcDmMsg((dmEvt_t *) pMsg);
schneider's avatar
schneider committed
932
933
934

      /* process discovery-related messages */
      AppDiscProcDmMsg((dmEvt_t *) pMsg);
935
    }
936
937
938
    else if (pMsg->event >= ATT_CBACK_START && pMsg->event <= ATT_CBACK_END)
    {
      LOG_INFO("ble", "Ble got evt %d: %s", pMsg->event, att_events[pMsg->event - ATT_CBACK_START]);
schneider's avatar
schneider committed
939
940
      /* process discovery-related ATT messages */
      AppDiscProcAttMsg((attEvt_t *) pMsg);
941
942
943
944
945
946
947
948
949
    }
    else if (pMsg->event >= L2C_COC_CBACK_START && pMsg->event <= L2C_COC_CBACK_CBACK_END)
    {
      LOG_INFO("ble", "Ble got evt %d: %s", pMsg->event, l2c_coc_events[pMsg->event - L2C_COC_CBACK_START]);
    }
    else
    {
      LOG_INFO("ble", "Ble got evt %d", pMsg->event);
    }
950
951

    /* perform profile and user interface-related operations */
952
    bleProcMsg((bleMsg_t *) pMsg);
953
954
955
956
957
958
959
960
961
962
  }
}

/*************************************************************************************************/
/*!
 *  \brief  Start the application.
 *
 *  \return None.
 */
/*************************************************************************************************/
963
void BleStart(void)
964
{
schneider's avatar
schneider committed
965

966
  BleHandlerInit();
schneider's avatar
schneider committed
967

968
  /* Register for stack callbacks */
969
970
971
  DmRegister(bleDmCback);
  DmConnRegister(DM_CLIENT_ID_APP, bleDmCback);
  AttRegister(bleAttCback);
972
  AttConnRegister(AppServerConnCback);
973
  AttsCccRegister(BLE_NUM_CCC_IDX, (attsCccSet_t *) bleCccSet, bleCccCback);
974

schneider's avatar
schneider committed
975
976
977
  /* Register for app framework discovery callbacks */
  AppDiscRegister(bleDiscCback);

978
979
  /* Initialize attribute server database */
  SvcCoreAddGroup();
980
  SvcDisAddGroup(); // Device Information Service
981
982
983
984
985
986
  SvcBattCbackRegister(BasReadCback, NULL);
  SvcBattAddGroup();

  /* Reset the device */
  DmDevReset();
}
schneider's avatar
schneider committed
987
/* clang-format on */