/
bluetooth.c
2965 lines (2627 loc) · 115 KB
/
bluetooth.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
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
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
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
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
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
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
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
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/**
* This file is part of Espruino, a JavaScript interpreter for Microcontrollers
*
* Copyright (C) 2013 Gordon Williams <gw@pur3.co.uk>
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* ----------------------------------------------------------------------------
* Platform Specific Bluetooth Functionality
* ----------------------------------------------------------------------------
*/
#ifdef BLUETOOTH
#include "jswrap_bluetooth.h"
#include "jsinteractive.h"
#include "jsdevices.h"
#include "jshardware.h"
#include "nrf5x_utils.h"
#include "bluetooth.h"
#include "bluetooth_utils.h"
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include "nordic_common.h"
#include "nrf.h"
#if NRF_SD_BLE_API_VERSION<5
#include "softdevice_handler.h"
#else
#include "nrf_sdm.h" // for softdevice_disable
#include "nrf_sdh.h"
#include "nrf_sdh_ble.h"
#include "nrf_sdh_soc.h"
#endif
#include "nrf_log.h"
#include "ble_hci.h"
#include "ble_advdata.h"
#include "ble_conn_params.h"
#include "app_timer.h"
#include "ble_nus.h"
#include "app_util_platform.h"
#include "nrf_delay.h"
#ifdef USE_NFC
#include "hal_t2t/hal_nfc_t2t.h"
#endif
#if BLE_HIDS_ENABLED
#include "ble_hids.h"
#endif
#if PEER_MANAGER_ENABLED
#include "peer_manager.h"
#include "fds.h"
#if NRF_SD_BLE_API_VERSION<5
#include "fstorage.h"
#include "fstorage_internal_defs.h"
#endif
#include "ble_conn_state.h"
static pm_peer_id_t m_peer_id; /**< Device reference handle to the current bonded central. */
static pm_peer_id_t m_whitelist_peers[BLE_GAP_WHITELIST_ADDR_MAX_COUNT]; /**< List of peers currently in the whitelist. */
static uint32_t m_whitelist_peer_cnt; /**< Number of peers currently in the whitelist. */
static bool m_is_wl_changed; /**< Indicates if the whitelist has been changed since last time it has been updated in the Peer Manager. */
// needed for peer_manager_init so we can smoothly upgrade from pre 1v92 firmwares
#include "fds_internal_defs.h"
// If we have peer manager we have central mode and NRF52
// So just enable link security
#define LINK_SECURITY
#endif
#ifdef LINK_SECURITY
// Code to handle secure Bluetooth links
#include "ecc.h"
#define BLE_GAP_LESC_P256_SK_LEN 32
/**@brief GAP LE Secure Connections P-256 Private Key. */
typedef struct
{
uint8_t sk[BLE_GAP_LESC_P256_SK_LEN]; /**< LE Secure Connections Elliptic Curve Diffie-Hellman P-256 Private Key in little-endian. */
} ble_gap_lesc_p256_sk_t;
__ALIGN(4) static ble_gap_lesc_p256_sk_t m_lesc_sk; /**< LESC ECC Private Key */
__ALIGN(4) static ble_gap_lesc_p256_pk_t m_lesc_pk; /**< LESC ECC Public Key */
__ALIGN(4) static ble_gap_lesc_dhkey_t m_lesc_dhkey; /**< LESC ECC DH Key*/
#endif
// -----------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------
#if NRF_SD_BLE_API_VERSION < 5
#define NRF_BLE_MAX_MTU_SIZE GATT_MTU_SIZE_DEFAULT /**< MTU size used in the softdevice enabling and to reply to a BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST event. */
#define FIRST_CONN_PARAMS_UPDATE_DELAY APP_TIMER_TICKS(100, APP_TIMER_PRESCALER) /**< Time from initiating event (connect or start of notification) to first time sd_ble_gap_conn_param_update is called (5 seconds). */
#define NEXT_CONN_PARAMS_UPDATE_DELAY APP_TIMER_TICKS(10000, APP_TIMER_PRESCALER) /**< Time between each call to sd_ble_gap_conn_param_update after the first call (30 seconds). */
#define MAX_CONN_PARAMS_UPDATE_COUNT 3 /**< Number of attempts before giving up the connection parameter negotiation. */
#else
#define NRF_BLE_MAX_MTU_SIZE NRF_SDH_BLE_GATT_MAX_MTU_SIZE /**< MTU size used in the softdevice enabling and to reply to a BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST event. */
#define FIRST_CONN_PARAMS_UPDATE_DELAY APP_TIMER_TICKS(100) /**< Time from initiating event (connect or start of notification) to first time sd_ble_gap_conn_param_update is called (5 seconds). */
#define NEXT_CONN_PARAMS_UPDATE_DELAY APP_TIMER_TICKS(10000) /**< Time between each call to sd_ble_gap_conn_param_update after the first call (30 seconds). */
#define MAX_CONN_PARAMS_UPDATE_COUNT 3 /**< Number of attempts before giving up the connection parameter negotiation. */
#endif
#define CONN_SUP_TIMEOUT MSEC_TO_UNITS(4000, UNIT_10_MS) /**< Connection Supervision Timeout in 10 ms units, see @ref BLE_GAP_CP_LIMITS.*/
#define SLAVE_LATENCY 0 /**< Slave Latency in number of connection events, see @ref BLE_GAP_CP_LIMITS.*/
#define APP_BLE_CONN_CFG_TAG 1 /**< A tag identifying the SoftDevice BLE configuration. */
#define APP_BLE_OBSERVER_PRIO 2 /**< Application's BLE observer priority. You shouldn't need to modify this value. */
#define APP_SOC_OBSERVER_PRIO 1 /**< Applications' SoC observer priority. You shoulnd't need to modify this value. */
/* We want to listen as much of the time as possible. Not sure if 100/100 is feasible (50/100 is what's used in examples), but it seems to work fine like this. */
#define SCAN_INTERVAL MSEC_TO_UNITS(100, UNIT_0_625_MS) /**< Scan interval in units of 0.625 millisecond - 100 msec */
#define SCAN_WINDOW MSEC_TO_UNITS(100, UNIT_0_625_MS) /**< Scan window in units of 0.625 millisecond - 100 msec */
#define APP_ADV_TIMEOUT_IN_SECONDS 180 /**< The advertising timeout (in units of seconds). */
// BLE HID stuff
#define BASE_USB_HID_SPEC_VERSION 0x0101 /**< Version number of base USB HID Specification implemented by this application. */
#define HID_OUTPUT_REPORT_INDEX 0 /**< Index of Output Report. */
#define HID_OUTPUT_REPORT_MAX_LEN 1 /**< Maximum length of Output Report. */
#define HID_INPUT_REPORT_KEYS_INDEX 0 /**< Index of Input Report. */
#define HID_INPUT_REP_REF_ID 0 /**< Id of reference to Keyboard Input Report. */
#define HID_OUTPUT_REP_REF_ID 0 /**< Id of reference to Keyboard Output Report. */
#define HID_INPUT_REPORT_KEYS_MAX_LEN 8
#define APP_FEATURE_NOT_SUPPORTED BLE_GATT_STATUS_ATTERR_APP_BEGIN + 2 /**< Reply when unsupported features are requested. */
/* Check for errors when in an IRQ, when we're pretty sure an error won't
* cause a hard reset. Error is then reported outside of the IRQ without
* rebooting Espruino. */
#define APP_ERROR_CHECK_NOT_URGENT(ERR_CODE) if (ERR_CODE) { uint32_t line = __LINE__; jsble_queue_pending_buf(BLEP_ERROR, ERR_CODE, &line, 4); }
// -----------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------
#define ADVERTISE_MAX_UUIDS 4 ///< maximum custom UUIDs to advertise
#if NRF_SD_BLE_API_VERSION < 5
static ble_nus_t m_nus; /**< Structure to identify the Nordic UART Service. */
#elif NRF_SD_BLE_API_VERSION < 6
BLE_NUS_DEF(m_nus); /**< Structure to identify the Nordic UART Service. */
#else
BLE_NUS_DEF(m_nus, NRF_SDH_BLE_TOTAL_LINK_COUNT); /**< Structure to identify the Nordic UART Service. */
#endif
#if BLE_HIDS_ENABLED
#if NRF_SD_BLE_API_VERSION < 5
static ble_hids_t m_hids; /**< Structure used to identify the HID service. */
#elif NRF_SD_BLE_API_VERSION < 6
BLE_HIDS_DEF(m_hids);
#else
BLE_HIDS_DEF(m_hids,
NRF_SDH_BLE_TOTAL_LINK_COUNT,
HID_INPUT_REPORT_KEYS_MAX_LEN,
HID_OUTPUT_REPORT_MAX_LEN);
#endif
static bool m_in_boot_mode = false;
#endif
#if NRF_SD_BLE_API_VERSION > 5
static uint8_t m_adv_handle = BLE_GAP_ADV_SET_HANDLE_NOT_SET; /**< Advertising handle used to identify an advertising set. */
#endif
volatile uint16_t m_peripheral_conn_handle = BLE_CONN_HANDLE_INVALID; /**< Handle of the current connection. */
#if CENTRAL_LINK_COUNT>0
volatile uint16_t m_central_conn_handle = BLE_CONN_HANDLE_INVALID; /**< Handle for central mode connection */
#endif
#ifdef USE_NFC
volatile bool nfcEnabled = false;
#endif
uint16_t bleAdvertisingInterval = DEFAULT_ADVERTISING_INTERVAL;
volatile BLEStatus bleStatus = 0;
ble_uuid_t bleUUIDFilter;
/// When doing service discovery, this is the last handle we'll need to discover with
uint16_t bleFinalHandle;
/// Array of data waiting to be sent over Bluetooth NUS
uint8_t nusTxBuf[BLE_NUS_MAX_DATA_LEN];
/// Number of bytes ready to send inside nusTxBuf
uint16_t nuxTxBufLength = 0;
#ifdef NRF52
#define DYNAMIC_INTERVAL_ADJUSTMENT
#endif
/* Dynamic interval adjustment kicks Espruino into a low power mode after
* a certain amount of time of being connected with nothing happening. The next time
* stuff happens it renegotiates back to the high rate, but this could take a second
* or two.
*/
#ifdef DYNAMIC_INTERVAL_ADJUSTMENT
#define BLE_DYNAMIC_INTERVAL_LOW_RATE 200 // connection interval when idle (milliseconds)
#define BLE_DYNAMIC_INTERVAL_HIGH_RATE 7.5 // connection interval when not idle (milliseconds) - 7.5ms is fastest possible
#define BLE_DEFAULT_HIGH_INTERVAL true
#define DEFAULT_PERIPH_MAX_CONN_INTERVAL BLE_DYNAMIC_INTERVAL_HIGH_RATE // highest possible on connect
#define BLE_DYNAMIC_INTERVAL_IDLE_TIME (int)(120000 / BLE_DYNAMIC_INTERVAL_HIGH_RATE) // time in milliseconds at which we enter idle
/// How many connection intervals has BLE been idle for? Use for dynamic interval adjustment
uint16_t bleIdleCounter = 0;
/// Are we using a high speed or low speed interval at the moment?
bool bleHighInterval;
#else
// No interval adjustment - allow us to enter a slightly lower power connection state
#define DEFAULT_PERIPH_MAX_CONN_INTERVAL 20
#endif
static ble_gap_sec_params_t get_gap_sec_params();
// -----------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------
/// Checks for error and reports an exception string if there was one, else 0 if no error
JsVar *jsble_get_error_string(uint32_t err_code) {
if (!err_code) return 0;
const char *name = 0;
switch (err_code) {
case NRF_ERROR_NO_MEM : name="NO_MEM"; break;
case NRF_ERROR_INVALID_PARAM : name="INVALID_PARAM"; break;
case NRF_ERROR_INVALID_STATE : name="INVALID_STATE"; break;
case NRF_ERROR_INVALID_LENGTH: name="INVALID_LENGTH"; break;
case NRF_ERROR_INVALID_FLAGS : name="INVALID_FLAGS"; break;
case NRF_ERROR_DATA_SIZE : name="DATA_SIZE"; break;
case NRF_ERROR_FORBIDDEN : name="FORBIDDEN"; break;
case NRF_ERROR_BUSY : name="BUSY"; break;
case NRF_ERROR_INVALID_ADDR : name="INVALID ADDR"; break;
case BLE_ERROR_INVALID_CONN_HANDLE
: name="INVALID_CONN_HANDLE"; break;
case BLE_ERROR_GAP_INVALID_BLE_ADDR
: name="INVALID_BLE_ADDR"; break;
#if NRF_SD_BLE_API_VERSION<5
case BLE_ERROR_NO_TX_PACKETS : name="NO_TX_PACKETS"; break;
#endif
}
if (name) return jsvVarPrintf("BLE error 0x%x (%s)", err_code, name);
else return jsvVarPrintf("BLE error 0x%x", err_code);
}
// -----------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------
/// Add a new bluetooth event to the queue with a buffer of data
void jsble_queue_pending_buf(BLEPending blep, uint16_t data, char *ptr, size_t len) {
// check to ensure we have space for the data we're adding
if (!jshHasEventSpaceForChars(len+IOEVENT_MAXCHARS)) {
jsErrorFlags |= JSERR_RX_FIFO_FULL;
return;
}
// Push the data for the event first
while (len) {
int evtLen = len;
if (evtLen > IOEVENT_MAXCHARS) evtLen=IOEVENT_MAXCHARS;
IOEvent evt;
evt.flags = EV_BLUETOOTH_PENDING_DATA;
IOEVENTFLAGS_SETCHARS(evt.flags, evtLen);
memcpy(evt.data.chars, ptr, evtLen);
jshPushEvent(&evt);
ptr += evtLen;
len -= evtLen;
}
// Push the actual event
JsSysTime d = (JsSysTime)((data<<8)|blep);
jshPushIOEvent(EV_BLUETOOTH_PENDING, d);
jshHadEvent();
}
/// Add a new bluetooth event to the queue with 16 bits of data
void jsble_queue_pending(BLEPending blep, uint16_t data) {
JsSysTime d = (JsSysTime)((data<<8)|blep);
jshPushIOEvent(EV_BLUETOOTH_PENDING, d);
jshHadEvent();
}
/// Executes a pending BLE event - returns the number of events Handled
int jsble_exec_pending(IOEvent *event) {
int eventsHandled = 1;
// if we got event data, unpack it first into a buffer
unsigned char buffer[64];
assert(sizeof(buffer) >= sizeof(ble_gap_evt_adv_report_t));
assert(sizeof(buffer) >= NRF_BLE_MAX_MTU_SIZE);
size_t bufferLen = 0;
while (IOEVENTFLAGS_GETTYPE(event->flags) == EV_BLUETOOTH_PENDING_DATA) {
int i, chars = IOEVENTFLAGS_GETCHARS(event->flags);
for (i=0;i<chars;i++) {
assert(bufferLen < sizeof(buffer));
if (bufferLen < sizeof(buffer))
buffer[bufferLen++] = event->data.chars[i];
}
jshPopIOEvent(event);
eventsHandled++;
}
assert(IOEVENTFLAGS_GETTYPE(event->flags) == EV_BLUETOOTH_PENDING);
// Now handle the actual event
BLEPending blep = (BLEPending)event->data.time;
uint16_t data = (uint16_t)(event->data.time>>8);
switch (blep) {
case BLEP_NONE: break;
case BLEP_ERROR: {
JsVar *v = jsble_get_error_string(data);
jsWarn("Softdevice error %v (bluetooth.c:%d)",v, *(uint32_t*)buffer);
jsvUnLock(v);
break;
}
case BLEP_CONNECTED: {
assert(bufferLen == sizeof(ble_gap_addr_t));
ble_gap_addr_t *peer_addr = (ble_gap_addr_t*)buffer;
bleQueueEventAndUnLock(JS_EVENT_PREFIX"connect", bleAddrToStr(*peer_addr));
jshHadEvent();
break;
}
case BLEP_DISCONNECTED: {
JsVar *reason = jsvNewFromInteger(data);
bleQueueEventAndUnLock(JS_EVENT_PREFIX"disconnect", reason);
break;
}
case BLEP_RSSI_PERIPH: {
JsVar *evt = jsvNewFromInteger((signed char)data);
if (evt) jsiQueueObjectCallbacks(execInfo.root, BLE_RSSI_EVENT, &evt, 1);
jsvUnLock(evt);
break;
}
case BLEP_ADV_REPORT: {
ble_gap_evt_adv_report_t *p_adv = (ble_gap_evt_adv_report_t *)buffer;
#if NRF_SD_BLE_API_VERSION<6
int dataLen = p_adv->dlen;
char *dataPtr = (char*)p_adv->data;
#else
int dataLen = p_adv->data.len;
char *dataPtr = (char*)p_adv->data.p_data;
#endif
size_t len = sizeof(ble_gap_evt_adv_report_t) + dataLen - BLE_GAP_ADV_MAX_SIZE;
if (bufferLen != len) {
assert(0);
break;
}
JsVar *evt = jsvNewObject();
if (evt) {
jsvObjectSetChildAndUnLock(evt, "rssi", jsvNewFromInteger(p_adv->rssi));
//jsvObjectSetChildAndUnLock(evt, "addr_type", jsvNewFromInteger(blePendingAdvReport.peer_addr.addr_type));
jsvObjectSetChildAndUnLock(evt, "id", bleAddrToStr(p_adv->peer_addr));
JsVar *data = jsvNewStringOfLength(dataLen, dataPtr);
if (data) {
JsVar *ab = jsvNewArrayBufferFromString(data, dataLen);
jsvUnLock(data);
jsvObjectSetChildAndUnLock(evt, "data", ab);
}
// push onto queue
jsiQueueObjectCallbacks(execInfo.root, BLE_SCAN_EVENT, &evt, 1);
jsvUnLock(evt);
}
break;
}
case BLEP_WRITE: {
JsVar *evt = jsvNewObject();
if (evt) {
JsVar *str = jsvNewStringOfLength(bufferLen, (char*)buffer);
if (str) {
JsVar *ab = jsvNewArrayBufferFromString(str, bufferLen);
jsvUnLock(str);
jsvObjectSetChildAndUnLock(evt, "data", ab);
}
char eventName[12];
bleGetWriteEventName(eventName, data);
jsiQueueObjectCallbacks(execInfo.root, eventName, &evt, 1);
jsvUnLock(evt);
}
break;
}
#if CENTRAL_LINK_COUNT>0
case BLEP_RSSI_CENTRAL: {
JsVar *gattServer = bleGetActiveBluetoothGattServer();
if (gattServer) {
JsVar *rssi = jsvNewFromInteger((signed char)data);
JsVar *bluetoothDevice = jsvObjectGetChild(gattServer, "device", 0);
if (bluetoothDevice) {
jsvObjectSetChild(bluetoothDevice, "rssi", rssi);
}
jsiQueueObjectCallbacks(gattServer, BLE_RSSI_EVENT, &rssi, 1);
jsvUnLock3(rssi, gattServer, bluetoothDevice);
}
break;
}
case BLEP_TASK_FAIL_CONN_TIMEOUT:
bleCompleteTaskFailAndUnLock(bleGetCurrentTask(), jsvNewFromString("Connection Timeout"));
break;
case BLEP_TASK_FAIL_DISCONNECTED:
bleCompleteTaskFailAndUnLock(bleGetCurrentTask(), jsvNewFromString("Disconnected"));
break;
case BLEP_TASK_CENTRAL_CONNECTED:
jsvObjectSetChildAndUnLock(bleTaskInfo, "connected", jsvNewFromBool(true));
bleCompleteTaskSuccess(BLETASK_CONNECT, bleTaskInfo);
break;
case BLEP_TASK_DISCOVER_SERVICE: {
if (!bleInTask(BLETASK_PRIMARYSERVICE)) {
jsExceptionHere(JSET_INTERNALERROR,"Wrong task: %d vs %d", bleGetCurrentTask(), BLETASK_PRIMARYSERVICE);
break;
}
ble_gattc_service_t *p_srv = (ble_gattc_service_t*)buffer;
if (!bleTaskInfo) bleTaskInfo = jsvNewEmptyArray();
if (!bleTaskInfo) break;
JsVar *o = jspNewObject(0, "BluetoothRemoteGATTService");
if (o) {
jsvObjectSetChildAndUnLock(o,"uuid", bleUUIDToStr(p_srv->uuid));
jsvObjectSetChildAndUnLock(o,"isPrimary", jsvNewFromBool(true));
jsvObjectSetChildAndUnLock(o,"start_handle", jsvNewFromInteger(p_srv->handle_range.start_handle));
jsvObjectSetChildAndUnLock(o,"end_handle", jsvNewFromInteger(p_srv->handle_range.end_handle));
jsvArrayPushAndUnLock(bleTaskInfo, o);
}
break;
}
case BLEP_TASK_DISCOVER_SERVICE_COMPLETE: {
// When done, send the result to the handler
if (bleTaskInfo && bleUUIDFilter.type != BLE_UUID_TYPE_UNKNOWN) {
// single item because filtering
JsVar *t = jsvSkipNameAndUnLock(jsvArrayPopFirst(bleTaskInfo));
jsvUnLock(bleTaskInfo);
bleTaskInfo = t;
}
if (bleTaskInfo) bleCompleteTaskSuccess(BLETASK_PRIMARYSERVICE, bleTaskInfo);
else bleCompleteTaskFailAndUnLock(BLETASK_PRIMARYSERVICE, jsvNewFromString("No Services found"));
break;
}
case BLEP_TASK_DISCOVER_CHARACTERISTIC: {
if (!bleInTask(BLETASK_CHARACTERISTIC)) {
jsExceptionHere(JSET_INTERNALERROR,"Wrong task: %d vs %d", bleGetCurrentTask(), BLETASK_PRIMARYSERVICE);
break;
}
ble_gattc_char_t *p_chr = (ble_gattc_char_t*)buffer;
if (!bleTaskInfo) bleTaskInfo = jsvNewEmptyArray();
if (!bleTaskInfo) break;
JsVar *o = jspNewObject(0, "BluetoothRemoteGATTCharacteristic");
if (o) {
jsvObjectSetChildAndUnLock(o,"uuid", bleUUIDToStr(p_chr->uuid));
jsvObjectSetChildAndUnLock(o,"handle_value", jsvNewFromInteger(p_chr->handle_value));
jsvObjectSetChildAndUnLock(o,"handle_decl", jsvNewFromInteger(p_chr->handle_decl));
JsVar *p = jsvNewObject();
if (p) {
jsvObjectSetChildAndUnLock(p,"broadcast",jsvNewFromBool(p_chr->char_props.broadcast));
jsvObjectSetChildAndUnLock(p,"read",jsvNewFromBool(p_chr->char_props.read));
jsvObjectSetChildAndUnLock(p,"writeWithoutResponse",jsvNewFromBool(p_chr->char_props.write_wo_resp));
jsvObjectSetChildAndUnLock(p,"write",jsvNewFromBool(p_chr->char_props.write));
jsvObjectSetChildAndUnLock(p,"notify",jsvNewFromBool(p_chr->char_props.notify));
jsvObjectSetChildAndUnLock(p,"indicate",jsvNewFromBool(p_chr->char_props.indicate));
jsvObjectSetChildAndUnLock(p,"authenticatedSignedWrites",jsvNewFromBool(p_chr->char_props.auth_signed_wr));
jsvObjectSetChildAndUnLock(o,"properties", p);
}
// char_props?
jsvArrayPushAndUnLock(bleTaskInfo, o);
}
break;
}
case BLEP_TASK_DISCOVER_CHARACTERISTIC_COMPLETE: {
// When done, send the result to the handler
if (bleTaskInfo && bleUUIDFilter.type != BLE_UUID_TYPE_UNKNOWN) {
// single item because filtering
JsVar *t = jsvSkipNameAndUnLock(jsvArrayPopFirst(bleTaskInfo));
jsvUnLock(bleTaskInfo);
bleTaskInfo = t;
}
if (bleTaskInfo) bleCompleteTaskSuccess(BLETASK_CHARACTERISTIC, bleTaskInfo);
else bleCompleteTaskFailAndUnLock(BLETASK_CHARACTERISTIC, jsvNewFromString("No Characteristics found"));
break;
}
case BLEP_TASK_DISCOVER_CCCD: {
uint16_t cccd_handle = data;
if (cccd_handle) {
if(bleTaskInfo)
jsvObjectSetChildAndUnLock(bleTaskInfo, "handle_cccd", jsvNewFromInteger(cccd_handle));
// Switch task here rather than completing...
bleSwitchTask(BLETASK_CHARACTERISTIC_NOTIFY);
jsble_central_characteristicNotify(bleTaskInfo, true);
} else {
// Couldn't find anything - just report error
bleCompleteTaskFailAndUnLock(BLETASK_CHARACTERISTIC_DESC_AND_STARTNOTIFY, jsvNewFromString("CCCD Handle not found"));
}
break;
}
case BLEP_TASK_CHARACTERISTIC_READ: {
JsVar *d = jsvNewDataViewWithData(bufferLen, buffer);
jsvObjectSetChild(bleTaskInfo, "value", d); // set this.value
bleCompleteTaskSuccessAndUnLock(BLETASK_CHARACTERISTIC_READ, d);
break;
}
case BLEP_TASK_CHARACTERISTIC_WRITE: {
bleCompleteTaskSuccess(BLETASK_CHARACTERISTIC_WRITE, 0);
break;
}
case BLEP_TASK_CHARACTERISTIC_NOTIFY: {
bleCompleteTaskSuccess(BLETASK_CHARACTERISTIC_NOTIFY, 0);
break;
}
case BLEP_CENTRAL_DISCONNECTED: {
bleCompleteTaskSuccess(BLETASK_DISCONNECT, bleTaskInfo);
JsVar *gattServer = bleGetActiveBluetoothGattServer();
if (gattServer) {
JsVar *bluetoothDevice = jsvObjectGetChild(gattServer, "device", 0);
jsvObjectSetChildAndUnLock(gattServer, "connected", jsvNewFromBool(false));
if (bluetoothDevice) {
// HCI error code, see BLE_HCI_STATUS_CODES in ble_hci.h
JsVar *reason = jsvNewFromInteger(data);
jsiQueueObjectCallbacks(bluetoothDevice, JS_EVENT_PREFIX"gattserverdisconnected", &reason, 1);
jsvUnLock(reason);
jshHadEvent();
}
jsvUnLock2(gattServer, bluetoothDevice);
}
bleSetActiveBluetoothGattServer(0);
break;
}
case BLEP_NOTIFICATION: {
JsVar *handles = jsvObjectGetChild(execInfo.hiddenRoot, "bleHdl", 0);
if (handles) {
JsVar *characteristic = jsvGetArrayItem(handles, data/*the handle*/);
if (characteristic) {
// Set characteristic.value, and return {target:characteristic}
jsvObjectSetChildAndUnLock(characteristic, "value",
jsvNewDataViewWithData(bufferLen, (unsigned char*)buffer));
JsVar *evt = jsvNewObject();
if (evt) {
jsvObjectSetChild(evt, "target", characteristic);
jsiQueueObjectCallbacks(characteristic, JS_EVENT_PREFIX"characteristicvaluechanged", &evt, 1);
jshHadEvent();
jsvUnLock(evt);
}
}
jsvUnLock2(characteristic, handles);
}
break;
}
#endif
#if PEER_MANAGER_ENABLED
case BLEP_TASK_BONDING: {
if (data) bleCompleteTaskSuccess(BLETASK_BONDING, 0);
else bleCompleteTaskFailAndUnLock(BLETASK_BONDING, jsvNewFromString("Securing failed"));
break;
}
#endif
#ifdef USE_NFC
case BLEP_NFC_STATUS:
bleQueueEventAndUnLock(data ? JS_EVENT_PREFIX"NFCon" : JS_EVENT_PREFIX"NFCoff", 0);
break;
case BLEP_NFC_TX:
bleQueueEventAndUnLock(JS_EVENT_PREFIX"NFCtx", 0);
break;
case BLEP_NFC_RX: {
/* try to fetch NfcData data */
JsVar *nfcData = jsvObjectGetChild(execInfo.hiddenRoot, "NfcData", 0);
if(nfcData) {
/* success - handle request internally */
JSV_GET_AS_CHAR_ARRAY(nfcDataPtr, nfcDataLen, nfcData);
jsvUnLock(nfcData);
/* check data, on error let request go into timeout - reader will retry. */
if (!nfcDataPtr || !nfcDataLen) {
break;
}
/* check rx data length and read block command code (0x30) */
if(bufferLen < 2 || buffer[0] != 0x30) {
jsble_nfc_send_rsp(0, 0); /* switch to rx */
break;
}
/* fetch block index (addressing is done in multiples of 4 byte */
size_t idx = buffer[1] * 4;
/* assemble 16 byte block */
uint8_t buf[16]; memset(buf, '\0', 16);
if(idx + 16 < nfcDataLen) {
memcpy(buf, nfcDataPtr + idx, 16);
} else
if(idx < nfcDataLen) {
memcpy(buf, nfcDataPtr + idx, nfcDataLen - idx);
}
/* send response */
jsble_nfc_send(buf, 16);
} else {
/* no NfcData available, fire js-event */
bleQueueEventAndUnLock(JS_EVENT_PREFIX"NFCrx",
jsvNewArrayBufferWithData(bufferLen, buffer));
}
break;
}
#endif
#if BLE_HIDS_ENABLED
case BLEP_HID_SENT:
jsiQueueObjectCallbacks(execInfo.root, BLE_HID_SENT_EVENT, 0, 0);
jsvObjectSetChild(execInfo.root, BLE_HID_SENT_EVENT, 0); // fire only once
jshHadEvent();
break;
case BLEP_HID_VALUE:
bleQueueEventAndUnLock(JS_EVENT_PREFIX"HID", jsvNewFromInteger(data));
break;
#endif
#ifdef LINK_SECURITY
case BLEP_TASK_PASSKEY_DISPLAY: {
/* TODO: yes/no passkey
uint8_t match_request : 1; If 1 requires the application to report the match using @ref sd_ble_gap_auth_key_reply
with either @ref BLE_GAP_AUTH_KEY_TYPE_NONE if there is no match or
@ref BLE_GAP_AUTH_KEY_TYPE_PASSKEY if there is a match. */
if (bufferLen==BLE_GAP_PASSKEY_LEN) {
buffer[BLE_GAP_PASSKEY_LEN] = 0;
JsVar *gattServer = bleGetActiveBluetoothGattServer();
if (gattServer) {
JsVar *passkey = jsvNewFromString((char*)buffer);
JsVar *bluetoothDevice = jsvObjectGetChild(gattServer, "device", 0);
if (bluetoothDevice) {
jsiQueueObjectCallbacks(bluetoothDevice, JS_EVENT_PREFIX"passkey", &passkey, 1);
jshHadEvent();
}
jsvUnLock3(passkey, bluetoothDevice, gattServer);
}
}
break;
}
case BLEP_TASK_PASSKEY_REQUEST: {
JsVar *gattServer = bleGetActiveBluetoothGattServer();
if (gattServer) {
JsVar *bluetoothDevice = jsvObjectGetChild(gattServer, "device", 0);
jsvObjectSetChildAndUnLock(gattServer, "connected", jsvNewFromBool(false));
if (bluetoothDevice) {
// HCI error code, see BLE_HCI_STATUS_CODES in ble_hci.h
jsiQueueObjectCallbacks(bluetoothDevice, JS_EVENT_PREFIX"passkeyRequest", 0, 0);
jshHadEvent();
}
jsvUnLock2(gattServer, bluetoothDevice);
}
break;
}
#endif
default:
jsWarn("jsble_exec_pending: Unknown enum type %d",(int)blep);
}
return eventsHandled;
}
// -----------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------
/** Set the connection interval of the peripheral connection. Returns an error code. */
uint32_t jsble_set_periph_connection_interval(JsVarFloat min, JsVarFloat max) {
ble_gap_conn_params_t gap_conn_params;
memset(&gap_conn_params, 0, sizeof(gap_conn_params));
gap_conn_params.min_conn_interval = (uint16_t)(0.5+MSEC_TO_UNITS(min, UNIT_1_25_MS)); // Minimum acceptable connection interval
gap_conn_params.max_conn_interval = (uint16_t)(0.5+MSEC_TO_UNITS(max, UNIT_1_25_MS)); // Maximum acceptable connection interval
gap_conn_params.slave_latency = SLAVE_LATENCY;
gap_conn_params.conn_sup_timeout = CONN_SUP_TIMEOUT;
if (jsble_has_peripheral_connection()) {
// Connected - initiate dynamic change
return ble_conn_params_change_conn_params(
#if NRF_SD_BLE_API_VERSION>=5
m_peripheral_conn_handle,
#endif
&gap_conn_params);
} else {
// Not connected, just tell the stack
return sd_ble_gap_ppcp_set(&gap_conn_params);
}
}
/** Is BLE connected to any device at all? */
bool jsble_has_connection() {
#if CENTRAL_LINK_COUNT>0
return (m_central_conn_handle != BLE_CONN_HANDLE_INVALID) ||
(m_peripheral_conn_handle != BLE_CONN_HANDLE_INVALID);
#else
return m_peripheral_conn_handle != BLE_CONN_HANDLE_INVALID;
#endif
}
/** Is BLE connected to a central device at all? */
bool jsble_has_central_connection() {
#if CENTRAL_LINK_COUNT>0
return (m_central_conn_handle != BLE_CONN_HANDLE_INVALID);
#else
return false;
#endif
}
/** Is BLE connected to a server device at all (eg, the simple, 'slave' mode)? */
bool jsble_has_peripheral_connection() {
return (m_peripheral_conn_handle != BLE_CONN_HANDLE_INVALID);
}
/** Call this when something happens on BLE with this as
* a peripheral - used with Dynamic Interval Adjustment */
void jsble_peripheral_activity() {
#ifdef DYNAMIC_INTERVAL_ADJUSTMENT
if (jsble_has_peripheral_connection() &&
!(bleStatus & BLE_DISABLE_DYNAMIC_INTERVAL) &&
bleIdleCounter < 10) {
// so we must have been called once before
if (!bleHighInterval) {
bleHighInterval = true;
jsble_set_periph_connection_interval(BLE_DYNAMIC_INTERVAL_HIGH_RATE, BLE_DYNAMIC_INTERVAL_HIGH_RATE);
}
}
bleIdleCounter = 0;
#endif
}
/// Checks for error and reports an exception if there was one. Return true on error
bool jsble_check_error(uint32_t err_code) {
JsVar *v = jsble_get_error_string(err_code);
if (!v) return 0;
jsExceptionHere(JSET_ERROR, "%v", v);
jsvUnLock(v);
return true;
}
// -----------------------------------------------------------------------------------
// --------------------------------------------------------------------------- ERRORS
void ble_app_error_handler(uint32_t error_code, uint32_t line_num, const uint8_t * p_file_name) {
#ifdef LED1_PININDEX
jshPinOutput(LED1_PININDEX, LED1_ONSTATE);
#endif
#ifdef LED2_PININDEX
jshPinOutput(LED2_PININDEX, LED2_ONSTATE);
#endif
#ifdef LED3_PININDEX
jshPinOutput(LED3_PININDEX, LED3_ONSTATE);
#endif
jsiConsolePrintf("NRF ERROR 0x%x at %s:%d\n", error_code, p_file_name?(const char *)p_file_name:"?", line_num);
jsiConsolePrint("REBOOTING.\n");
/* don't flush - just delay. If this happened in an IRQ, waiting to flush
* will result in the device locking up. */
nrf_delay_ms(1000);
NVIC_SystemReset();
}
void assert_nrf_callback(uint16_t line_num, const uint8_t * p_file_name) {
ble_app_error_handler(0xDEADBEEF, line_num, p_file_name);
}
void app_error_fault_handler(uint32_t id, uint32_t pc, uint32_t info) {
if (id == NRF_FAULT_ID_SDK_ERROR) {
error_info_t *error_info = (error_info_t *)info;
ble_app_error_handler(error_info->err_code, error_info->line_num, error_info->p_file_name);
} else
ble_app_error_handler(id, pc, 0);
}
/// Function for handling errors from the Connection Parameters module.
static void conn_params_error_handler(uint32_t nrf_error) {
/* connection parameters module can produce this if the connection
* is disconnected at just the right point while it is trying to
* negotiate connection parameters. Ignore it, since we don't
* want it to be able to reboot the device!
*/
if (nrf_error == NRF_ERROR_INVALID_STATE)
return;
APP_ERROR_CHECK_NOT_URGENT(nrf_error);
}
#if BLE_HIDS_ENABLED
static void service_error_handler(uint32_t nrf_error) {
APP_ERROR_CHECK_NOT_URGENT(nrf_error);
}
#endif
#if NRF_LOG_ENABLED
void nrf_log_frontend_std_0(uint32_t severity_mid, char const * const p_str) {
nrf_log_frontend_std_6(severity_mid, p_str,0,0,0,0,0,0);
}
void nrf_log_frontend_std_1(uint32_t severity_mid,
char const * const p_str,
uint32_t val0) {
nrf_log_frontend_std_6(severity_mid, p_str,val0,0,0,0,0,0);
}
void nrf_log_frontend_std_2(uint32_t severity_mid,
char const * const p_str,
uint32_t val0,
uint32_t val1) {
nrf_log_frontend_std_6(severity_mid, p_str,val0,val1,0,0,0,0);
}
void nrf_log_frontend_std_3(uint32_t severity_mid,
char const * const p_str,
uint32_t val0,
uint32_t val1,
uint32_t val2) {
nrf_log_frontend_std_6(severity_mid, p_str,val0,val1,val2,0,0,0);
}
void nrf_log_frontend_std_4(uint32_t severity_mid,
char const * const p_str,
uint32_t val0,
uint32_t val1,
uint32_t val2,
uint32_t val3) {
nrf_log_frontend_std_6(severity_mid, p_str,val0,val1,val2,val3,0,0);
}
void nrf_log_frontend_std_5(uint32_t severity_mid,
char const * const p_str,
uint32_t val0,
uint32_t val1,
uint32_t val2,
uint32_t val3,
uint32_t val4) {
nrf_log_frontend_std_6(severity_mid, p_str,val0,val1,val2,val3,val4,0);
}
void nrf_log_frontend_std_6(uint32_t severity_mid,
char const * const p_str,
uint32_t val0,
uint32_t val1,
uint32_t val2,
uint32_t val3,
uint32_t val4,
uint32_t val5) {
#ifdef DEFAULT_CONSOLE_DEVICE
jshTransmitPrintf(DEFAULT_CONSOLE_DEVICE, p_str, val0, val1, val2, val3, val4, val5);
jshTransmit(DEFAULT_CONSOLE_DEVICE, '\r');
jshTransmit(DEFAULT_CONSOLE_DEVICE, '\n');
#endif
}
nrf_log_module_dynamic_data_t NRF_LOG_MODULE_DATA_DYNAMIC = {
.module_id = 0
};
#endif
/// Function for handling an event from the Connection Parameters Module.
static void on_conn_params_evt(ble_conn_params_evt_t * p_evt) {
}
/// Sigh - NFC has lots of these, so we need to define it to build
void log_uart_printf(const char * format_msg, ...) {
// jsiConsolePrintf("NFC: %s\n", format_msg);
}
// -----------------------------------------------------------------------------------
// -------------------------------------------------------------------------- HANDLERS
#if NRF_SD_BLE_API_VERSION<5
static void nus_data_handler(ble_nus_t * p_nus, uint8_t * p_data, uint16_t length) {
jsble_peripheral_activity(); // flag that we've been busy
jshPushIOCharEvents(EV_BLUETOOTH, (char*)p_data, length);
jshHadEvent();
}
#else
static void nus_data_handler(ble_nus_evt_t * p_evt) {
if (p_evt->type == BLE_NUS_EVT_RX_DATA) {
jsble_peripheral_activity(); // flag that we've been busy
jshPushIOCharEvents(EV_BLUETOOTH, (char*)p_evt->params.rx_data.p_data, p_evt->params.rx_data.length);
jshHadEvent();
}
}
#endif
void nus_transmit_string() {
if (!jsble_has_peripheral_connection() ||
!(bleStatus & BLE_NUS_INITED) ||
(bleStatus & BLE_IS_SLEEPING)) {
// If no connection, drain the output buffer
nuxTxBufLength = 0;
while (jshGetCharToTransmit(EV_BLUETOOTH)>=0);
return;
}
/* 6 is the max number of packets we can send
* in one connection interval on nRF52. We could
* do 5, but it seems some things have issues with
* this (eg nRF cloud gateways) so only send 1 packet
* for now. */
for (int packet=0;packet<1;packet++) {
// No data? try and get some from our queue
if (!nuxTxBufLength) {
nuxTxBufLength = 0;
int ch = jshGetCharToTransmit(EV_BLUETOOTH);
while (ch>=0) {
nusTxBuf[nuxTxBufLength++] = ch;
if (nuxTxBufLength>=BLE_NUS_MAX_DATA_LEN) break;
ch = jshGetCharToTransmit(EV_BLUETOOTH);
}
}
// If there's no data in the queue, nothing to do - leave
if (!nuxTxBufLength) return;
jsble_peripheral_activity(); // flag that we've been busy
// We have data - try and send it
#if NRF_SD_BLE_API_VERSION>5
uint32_t err_code = ble_nus_data_send(&m_nus, nusTxBuf, &nuxTxBufLength, m_peripheral_conn_handle);
if (err_code == NRF_SUCCESS) nuxTxBufLength=0; // everything sent Ok
#elif NRF_SD_BLE_API_VERSION<5
uint32_t err_code = ble_nus_string_send(&m_nus, nusTxBuf, nuxTxBufLength);
if (err_code == NRF_SUCCESS) nuxTxBufLength=0; // everything sent Ok
#else
uint16_t bytesSent = nuxTxBufLength;
uint32_t err_code = ble_nus_string_send(&m_nus, nusTxBuf, &bytesSent);
if (nuxTxBufLength==bytesSent) {
nuxTxBufLength = 0;
} else if (bytesSent) {
for (uint16_t n=bytesSent;n<nuxTxBufLength;n++)
nusTxBuf[n-bytesSent] = nusTxBuf[n];
nuxTxBufLength -= bytesSent;
}
#endif
if (err_code == NRF_SUCCESS) {
bleStatus |= BLE_IS_SENDING;
}
/* if it failed to send all or any data we keep it around in
* nusTxBuf (with count in nuxTxBufLength) so next time around
* we can try again. */
}
}
/// Radio Notification handler
void SWI1_IRQHandler(bool radio_evt) {
if (bleStatus & BLE_NUS_INITED)
nus_transmit_string();
// If we're doing multiple advertising, iterate through advertising options
if (bleStatus & BLE_IS_ADVERTISING_MULTIPLE) {
int idx = (bleStatus&BLE_ADVERTISING_MULTIPLE_MASK)>>BLE_ADVERTISING_MULTIPLE_SHIFT;
JsVar *advData = jsvObjectGetChild(execInfo.hiddenRoot, BLE_NAME_ADVERTISE_DATA, 0);
bool ok = true;
if (jsvIsArray(advData)) {
JsVar *data = jsvGetArrayItem(advData, idx);
idx = (idx+1) % jsvGetArrayLength(advData);
bleStatus = (bleStatus&~BLE_ADVERTISING_MULTIPLE_MASK) | (idx<<BLE_ADVERTISING_MULTIPLE_SHIFT);
JSV_GET_AS_CHAR_ARRAY(dPtr, dLen, data);
if (dPtr && dLen) {
uint32_t err_code;
#if NRF_SD_BLE_API_VERSION>5
ble_gap_adv_data_t d;
memset(&d,0,sizeof(d));
d.adv_data.p_data = (char*)dPtr;
d.adv_data.len = dLen;
// TODO: scan_rsp_data? Does not setting this remove it?
err_code = sd_ble_gap_adv_set_configure(&m_adv_handle, &d, NULL);
#else
err_code = sd_ble_gap_adv_data_set((uint8_t *)dPtr, dLen, NULL, 0);
#endif
if (err_code)
ok = false; // error setting BLE - disable
} else {
// Invalid adv data - disable
ok = false;
}
jsvUnLock(data);
} else {
// no advdata - disable multiple advertising
ok = false;
}
if (!ok) {
bleStatus &= ~(BLE_IS_ADVERTISING_MULTIPLE|BLE_ADVERTISING_MULTIPLE_MASK);
}
jsvUnLock(advData);
}
#ifdef DYNAMIC_INTERVAL_ADJUSTMENT
// Handle Dynamic Interval Adjustment
if (bleIdleCounter<BLE_DYNAMIC_INTERVAL_IDLE_TIME) {
bleIdleCounter++;
} else {
if (jsble_has_peripheral_connection() &&
!(bleStatus & BLE_DISABLE_DYNAMIC_INTERVAL) &&
bleHighInterval) {
bleHighInterval = false;
jsble_set_periph_connection_interval(BLE_DYNAMIC_INTERVAL_LOW_RATE, BLE_DYNAMIC_INTERVAL_LOW_RATE);
}
}
#endif
#ifndef NRF52
/* NRF52 has a systick. On nRF51 we just hook on
to this, since it happens quite often */
void SysTick_Handler(void);
SysTick_Handler();
#endif
}
#if PEER_MANAGER_ENABLED
static void ble_update_whitelist() {
uint32_t err_code;
if (m_is_wl_changed) {
// The whitelist has been modified, update it in the Peer Manager.
err_code = pm_whitelist_set(m_whitelist_peers, m_whitelist_peer_cnt);
APP_ERROR_CHECK_NOT_URGENT(err_code);
err_code = pm_device_identities_list_set(m_whitelist_peers, m_whitelist_peer_cnt);
if (err_code != NRF_ERROR_NOT_SUPPORTED)
APP_ERROR_CHECK_NOT_URGENT(err_code);
m_is_wl_changed = false;
}