1
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
61
62
63
72
73
74
75
76
77
78
79
80
87
88
89
90
91
92
93
94
95
96
97
98
99
104
105
108
109
112
113
114
115
116
117
118
119
120
121
122
123
124
125
132
133
134
141
142
143
147
148
149
153
154
155
156
157
162
163
164
165
166
167
168
169
170
171
172
173
177
178
179
180
181
182
183
184
185
186
187
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
232
233
237
238
239
240
241
242
253
254
255
259
260
261
262
263
264
265
266
267
274
275
276
277
278
279
280
281
282
283
284
285
286
291
292
295
296
299
300
301
302
303
304
305
306
307
311
312
313
314
315
316
317
318
319
320
321
322
323
324
331
332
333
337
338
339
343
344
345
346
347
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
385
386
390
391
392
393
394
395
396
397
398
399
400
404
405
406
407
408
409
410
411
414
415
416
417
418
419
420
421
422
423
427
428
429
430
431
432
433
434
435
442
443
444
445
446
447
448
449
450
451
452
453
454
459
460
463
464
467
468
469
470
471
472
473
474
475
482
483
484
485
486
487
488
489
490
491
496
497
498
499
500
501
502
503
504
505
506
507
508
511
512
517
518
519
520
521
522
523
524
525
526
527
528
529
532
533
538
539
540
541
542
543
544
545
546
547
548
549
553
554
555
559
560
561
562
563
564
569
570
571
572
573
574
575
576
577
578
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
613
614
618
619
620
621
622
623
624
625
626
627
628
629
630
631
634
635
636
640
641
642
643
644
645
646
649
650
651
652
653
654
655
656
657
658
659
660
661
664
665
666
670
671
672
673
674
675
676
679
680
681
682
683
684
685
686
687
688
689
690
691
694
695
696
697
701
702
703
706
707
708
709
710
711
712
713
714
715
716
717
720
721
722
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
743
744
749
750
751
752
753
754
755
756
757
758
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
797
798
799
800
801
805
806
807
808
812
813
814
815
816
820
821
822
823
827
828
829
830
831
835
836
837
838
842
843
844
845
846
850
851
852
853
854
855
856
/* ... */
#include <assert.h>
#include <string.h>
#include "host/ble_hs.h"
#include "esp_central.h"
static void *peer_svc_mem;
static struct os_mempool peer_svc_pool;
static void *peer_chr_mem;
static struct os_mempool peer_chr_pool;
static void *peer_dsc_mem;
static struct os_mempool peer_dsc_pool;
static void *peer_mem;
static struct os_mempool peer_pool;
static SLIST_HEAD(, peer) peers;
static struct peer_svc *
peer_svc_find_range(struct peer *peer, uint16_t attr_handle);
static struct peer_svc *
peer_svc_find(struct peer *peer, uint16_t svc_start_handle,
struct peer_svc **out_prev);
int
peer_svc_is_empty(const struct peer_svc *svc);
uint16_t
chr_end_handle(const struct peer_svc *svc, const struct peer_chr *chr);
int
chr_is_empty(const struct peer_svc *svc, const struct peer_chr *chr);
static struct peer_chr *
peer_chr_find(const struct peer_svc *svc, uint16_t chr_def_handle,
struct peer_chr **out_prev);
static void
peer_disc_chrs(struct peer *peer);
static int
peer_dsc_disced(uint16_t conn_handle, const struct ble_gatt_error *error,
uint16_t chr_val_handle, const struct ble_gatt_dsc *dsc,
void *arg);
struct peer *
peer_find(uint16_t conn_handle)
{
struct peer *peer;
SLIST_FOREACH(peer, &peers, next) {
if (peer->conn_handle == conn_handle) {
return peer;
}{...}
}{...}
return NULL;
}{ ... }
static void
peer_disc_complete(struct peer *peer, int rc)
{
peer->disc_prev_chr_val = 0;
if (peer->disc_cb != NULL) {
peer->disc_cb(peer, rc, peer->disc_cb_arg);
}{...}
}{ ... }
static struct peer_dsc *
peer_dsc_find_prev(const struct peer_chr *chr, uint16_t dsc_handle)
{
struct peer_dsc *prev;
struct peer_dsc *dsc;
prev = NULL;
SLIST_FOREACH(dsc, &chr->dscs, next) {
if (dsc->dsc.handle >= dsc_handle) {
break;
}{...}
prev = dsc;
}{...}
return prev;
}{ ... }
static struct peer_dsc *
peer_dsc_find(const struct peer_chr *chr, uint16_t dsc_handle,
struct peer_dsc **out_prev)
{
struct peer_dsc *prev;
struct peer_dsc *dsc;
prev = peer_dsc_find_prev(chr, dsc_handle);
if (prev == NULL) {
dsc = SLIST_FIRST(&chr->dscs);
}{...} else {
dsc = SLIST_NEXT(prev, next);
}{...}
if (dsc != NULL && dsc->dsc.handle != dsc_handle) {
dsc = NULL;
}{...}
if (out_prev != NULL) {
*out_prev = prev;
}{...}
return dsc;
}{ ... }
static int
peer_dsc_add(struct peer *peer, uint16_t chr_val_handle,
const struct ble_gatt_dsc *gatt_dsc)
{
struct peer_dsc *prev;
struct peer_dsc *dsc;
struct peer_svc *svc;
struct peer_chr *chr;
svc = peer_svc_find_range(peer, chr_val_handle);
if (svc == NULL) {
/* ... */
assert(0);
return BLE_HS_EUNKNOWN;
}{...}
chr = peer_chr_find(svc, chr_val_handle, NULL);
if (chr == NULL) {
/* ... */
assert(0);
return BLE_HS_EUNKNOWN;
}{...}
dsc = peer_dsc_find(chr, gatt_dsc->handle, &prev);
if (dsc != NULL) {
return 0;
}{...}
dsc = os_memblock_get(&peer_dsc_pool);
if (dsc == NULL) {
return BLE_HS_ENOMEM;
}{...}
memset(dsc, 0, sizeof * dsc);
dsc->dsc = *gatt_dsc;
if (prev == NULL) {
SLIST_INSERT_HEAD(&chr->dscs, dsc, next);
}{...} else {
SLIST_NEXT(prev, next) = dsc;
}{...}
return 0;
}{ ... }
static void
peer_disc_dscs(struct peer *peer)
{
struct peer_chr *chr;
struct peer_svc *svc;
int rc;
/* ... */
SLIST_FOREACH(svc, &peer->svcs, next) {
SLIST_FOREACH(chr, &svc->chrs, next) {
if (!chr_is_empty(svc, chr) &&
SLIST_EMPTY(&chr->dscs) &&
peer->disc_prev_chr_val <= chr->chr.def_handle) {
rc = ble_gattc_disc_all_dscs(peer->conn_handle,
chr->chr.val_handle,
chr_end_handle(svc, chr),
peer_dsc_disced, peer);
if (rc != 0) {
peer_disc_complete(peer, rc);
}{...}
peer->disc_prev_chr_val = chr->chr.val_handle;
return;
}{...}
}{...}
}{...}
peer_disc_complete(peer, 0);
}{ ... }
static int
peer_dsc_disced(uint16_t conn_handle, const struct ble_gatt_error *error,
uint16_t chr_val_handle, const struct ble_gatt_dsc *dsc,
void *arg)
{
struct peer *peer;
int rc;
peer = arg;
assert(peer->conn_handle == conn_handle);
switch (error->status) {
case 0:
rc = peer_dsc_add(peer, chr_val_handle, dsc);
break;
...
case BLE_HS_EDONE:
/* ... */
if (peer->disc_prev_chr_val > 0) {
peer_disc_dscs(peer);
}{...}
rc = 0;
break;
...
default:
rc = error->status;
break;...
}{...}
if (rc != 0) {
peer_disc_complete(peer, rc);
}{...}
return rc;
}{ ... }
uint16_t
chr_end_handle(const struct peer_svc *svc, const struct peer_chr *chr)
{
const struct peer_chr *next_chr;
next_chr = SLIST_NEXT(chr, next);
if (next_chr != NULL) {
return next_chr->chr.def_handle - 1;
}{...} else {
return svc->svc.end_handle;
}{...}
}{ ... }
int
chr_is_empty(const struct peer_svc *svc, const struct peer_chr *chr)
{
return chr_end_handle(svc, chr) <= chr->chr.val_handle;
}{ ... }
static struct peer_chr *
peer_chr_find_prev(const struct peer_svc *svc, uint16_t chr_val_handle)
{
struct peer_chr *prev;
struct peer_chr *chr;
prev = NULL;
SLIST_FOREACH(chr, &svc->chrs, next) {
if (chr->chr.val_handle >= chr_val_handle) {
break;
}{...}
prev = chr;
}{...}
return prev;
}{ ... }
static struct peer_chr *
peer_chr_find(const struct peer_svc *svc, uint16_t chr_val_handle,
struct peer_chr **out_prev)
{
struct peer_chr *prev;
struct peer_chr *chr;
prev = peer_chr_find_prev(svc, chr_val_handle);
if (prev == NULL) {
chr = SLIST_FIRST(&svc->chrs);
}{...} else {
chr = SLIST_NEXT(prev, next);
}{...}
if (chr != NULL && chr->chr.val_handle != chr_val_handle) {
chr = NULL;
}{...}
if (out_prev != NULL) {
*out_prev = prev;
}{...}
return chr;
}{ ... }
static void
peer_chr_delete(struct peer_chr *chr)
{
struct peer_dsc *dsc;
while ((dsc = SLIST_FIRST(&chr->dscs)) != NULL) {
SLIST_REMOVE_HEAD(&chr->dscs, next);
os_memblock_put(&peer_dsc_pool, dsc);
}{...}
os_memblock_put(&peer_chr_pool, chr);
}{ ... }
static int
peer_chr_add(struct peer *peer, uint16_t svc_start_handle,
const struct ble_gatt_chr *gatt_chr)
{
struct peer_chr *prev;
struct peer_chr *chr;
struct peer_svc *svc;
svc = peer_svc_find(peer, svc_start_handle, NULL);
if (svc == NULL) {
/* ... */
assert(0);
return BLE_HS_EUNKNOWN;
}{...}
chr = peer_chr_find(svc, gatt_chr->def_handle, &prev);
if (chr != NULL) {
return 0;
}{...}
chr = os_memblock_get(&peer_chr_pool);
if (chr == NULL) {
return BLE_HS_ENOMEM;
}{...}
memset(chr, 0, sizeof * chr);
chr->chr = *gatt_chr;
if (prev == NULL) {
SLIST_INSERT_HEAD(&svc->chrs, chr, next);
}{...} else {
SLIST_NEXT(prev, next) = chr;
}{...}
return 0;
}{ ... }
static int
peer_chr_disced(uint16_t conn_handle, const struct ble_gatt_error *error,
const struct ble_gatt_chr *chr, void *arg)
{
struct peer *peer;
int rc;
peer = arg;
assert(peer->conn_handle == conn_handle);
switch (error->status) {
case 0:
rc = peer_chr_add(peer, peer->cur_svc->svc.start_handle, chr);
break;
...
case BLE_HS_EDONE:
/* ... */
if (peer->disc_prev_chr_val > 0) {
peer_disc_chrs(peer);
}{...}
rc = 0;
break;
...
default:
rc = error->status;
break;...
}{...}
if (rc != 0) {
peer_disc_complete(peer, rc);
}{...}
return rc;
}{ ... }
static void
peer_disc_chrs(struct peer *peer)
{
struct peer_svc *svc;
int rc;
/* ... */
SLIST_FOREACH(svc, &peer->svcs, next) {
if (!peer_svc_is_empty(svc) && SLIST_EMPTY(&svc->chrs)) {
peer->cur_svc = svc;
rc = ble_gattc_disc_all_chrs(peer->conn_handle,
svc->svc.start_handle,
svc->svc.end_handle,
peer_chr_disced, peer);
if (rc != 0) {
peer_disc_complete(peer, rc);
}{...}
return;
}{...}
}{...}
peer_disc_dscs(peer);
}{ ... }
int
peer_svc_is_empty(const struct peer_svc *svc)
{
return svc->svc.end_handle <= svc->svc.start_handle;
}{ ... }
static struct peer_svc *
peer_svc_find_prev(struct peer *peer, uint16_t svc_start_handle)
{
struct peer_svc *prev;
struct peer_svc *svc;
prev = NULL;
SLIST_FOREACH(svc, &peer->svcs, next) {
if (svc->svc.start_handle >= svc_start_handle) {
break;
}{...}
prev = svc;
}{...}
return prev;
}{ ... }
static struct peer_svc *
peer_svc_find(struct peer *peer, uint16_t svc_start_handle,
struct peer_svc **out_prev)
{
struct peer_svc *prev;
struct peer_svc *svc;
prev = peer_svc_find_prev(peer, svc_start_handle);
if (prev == NULL) {
svc = SLIST_FIRST(&peer->svcs);
}{...} else {
svc = SLIST_NEXT(prev, next);
}{...}
if (svc != NULL && svc->svc.start_handle != svc_start_handle) {
svc = NULL;
}{...}
if (out_prev != NULL) {
*out_prev = prev;
}{...}
return svc;
}{ ... }
static struct peer_svc *
peer_svc_find_range(struct peer *peer, uint16_t attr_handle)
{
struct peer_svc *svc;
SLIST_FOREACH(svc, &peer->svcs, next) {
if (svc->svc.start_handle <= attr_handle &&
svc->svc.end_handle >= attr_handle) {
return svc;
}{...}
}{...}
return NULL;
}{ ... }
const struct peer_svc *
peer_svc_find_uuid(const struct peer *peer, const ble_uuid_t *uuid)
{
const struct peer_svc *svc;
SLIST_FOREACH(svc, &peer->svcs, next) {
if (ble_uuid_cmp(&svc->svc.uuid.u, uuid) == 0) {
return svc;
}{...}
}{...}
return NULL;
}{ ... }
const struct peer_chr *
peer_chr_find_uuid(const struct peer *peer, const ble_uuid_t *svc_uuid,
const ble_uuid_t *chr_uuid)
{
const struct peer_svc *svc;
const struct peer_chr *chr;
svc = peer_svc_find_uuid(peer, svc_uuid);
if (svc == NULL) {
return NULL;
}{...}
SLIST_FOREACH(chr, &svc->chrs, next) {
if (ble_uuid_cmp(&chr->chr.uuid.u, chr_uuid) == 0) {
return chr;
}{...}
}{...}
return NULL;
}{ ... }
const struct peer_dsc *
peer_dsc_find_uuid(const struct peer *peer, const ble_uuid_t *svc_uuid,
const ble_uuid_t *chr_uuid, const ble_uuid_t *dsc_uuid)
{
const struct peer_chr *chr;
const struct peer_dsc *dsc;
chr = peer_chr_find_uuid(peer, svc_uuid, chr_uuid);
if (chr == NULL) {
return NULL;
}{...}
SLIST_FOREACH(dsc, &chr->dscs, next) {
if (ble_uuid_cmp(&dsc->dsc.uuid.u, dsc_uuid) == 0) {
return dsc;
}{...}
}{...}
return NULL;
}{ ... }
static int
peer_svc_add(struct peer *peer, const struct ble_gatt_svc *gatt_svc)
{
struct peer_svc *prev;
struct peer_svc *svc;
svc = peer_svc_find(peer, gatt_svc->start_handle, &prev);
if (svc != NULL) {
return 0;
}{...}
svc = os_memblock_get(&peer_svc_pool);
if (svc == NULL) {
return BLE_HS_ENOMEM;
}{...}
memset(svc, 0, sizeof * svc);
svc->svc = *gatt_svc;
SLIST_INIT(&svc->chrs);
if (prev == NULL) {
SLIST_INSERT_HEAD(&peer->svcs, svc, next);
}{...} else {
SLIST_INSERT_AFTER(prev, svc, next);
}{...}
return 0;
}{ ... }
static void
peer_svc_delete(struct peer_svc *svc)
{
struct peer_chr *chr;
while ((chr = SLIST_FIRST(&svc->chrs)) != NULL) {
SLIST_REMOVE_HEAD(&svc->chrs, next);
peer_chr_delete(chr);
}{...}
os_memblock_put(&peer_svc_pool, svc);
}{ ... }
static int
peer_svc_disced(uint16_t conn_handle, const struct ble_gatt_error *error,
const struct ble_gatt_svc *service, void *arg)
{
struct peer *peer;
int rc;
peer = arg;
assert(peer->conn_handle == conn_handle);
switch (error->status) {
case 0:
rc = peer_svc_add(peer, service);
break;
...
case BLE_HS_EDONE:
if (peer->disc_prev_chr_val > 0) {
peer_disc_chrs(peer);
}{...}
rc = 0;
break;
...
default:
rc = error->status;
break;...
}{...}
if (rc != 0) {
peer_disc_complete(peer, rc);
}{...}
return rc;
}{ ... }
int
peer_disc_svc_by_uuid(uint16_t conn_handle, const ble_uuid_t *uuid, peer_disc_fn *disc_cb,
void *disc_cb_arg)
{
struct peer_svc *svc;
struct peer *peer;
int rc;
peer = peer_find(conn_handle);
if (peer == NULL) {
return BLE_HS_ENOTCONN;
}{...}
while ((svc = SLIST_FIRST(&peer->svcs)) != NULL) {
SLIST_REMOVE_HEAD(&peer->svcs, next);
peer_svc_delete(svc);
}{...}
peer->disc_prev_chr_val = 1;
peer->disc_cb = disc_cb;
peer->disc_cb_arg = disc_cb_arg;
rc = ble_gattc_disc_svc_by_uuid(conn_handle, uuid, peer_svc_disced, peer);
if (rc != 0) {
return rc;
}{...}
return 0;
}{ ... }
int
peer_disc_all(uint16_t conn_handle, peer_disc_fn *disc_cb, void *disc_cb_arg)
{
struct peer_svc *svc;
struct peer *peer;
int rc;
peer = peer_find(conn_handle);
if (peer == NULL) {
return BLE_HS_ENOTCONN;
}{...}
while ((svc = SLIST_FIRST(&peer->svcs)) != NULL) {
SLIST_REMOVE_HEAD(&peer->svcs, next);
peer_svc_delete(svc);
}{...}
peer->disc_prev_chr_val = 1;
peer->disc_cb = disc_cb;
peer->disc_cb_arg = disc_cb_arg;
rc = ble_gattc_disc_all_svcs(conn_handle, peer_svc_disced, peer);
if (rc != 0) {
return rc;
}{...}
return 0;
}{ ... }
int
peer_delete(uint16_t conn_handle)
{
struct peer_svc *svc;
struct peer *peer;
int rc;
peer = peer_find(conn_handle);
if (peer == NULL) {
return BLE_HS_ENOTCONN;
}{...}
SLIST_REMOVE(&peers, peer, peer, next);
while ((svc = SLIST_FIRST(&peer->svcs)) != NULL) {
SLIST_REMOVE_HEAD(&peer->svcs, next);
peer_svc_delete(svc);
}{...}
rc = os_memblock_put(&peer_pool, peer);
if (rc != 0) {
return BLE_HS_EOS;
}{...}
return 0;
}{ ... }
int
peer_add(uint16_t conn_handle)
{
struct peer *peer;
peer = peer_find(conn_handle);
if (peer != NULL) {
return BLE_HS_EALREADY;
}{...}
peer = os_memblock_get(&peer_pool);
if (peer == NULL) {
return BLE_HS_ENOMEM;
}{...}
memset(peer, 0, sizeof * peer);
peer->conn_handle = conn_handle;
SLIST_INSERT_HEAD(&peers, peer, next);
return 0;
}{ ... }
void
peer_traverse_all(peer_traverse_fn *trav_cb, void *arg)
{
struct peer *peer;
if (!trav_cb) {
return;
}{...}
SLIST_FOREACH(peer, &peers, next) {
if (trav_cb(peer, arg)) {
return;
}{...}
}{...}
}{ ... }
#if MYNEWT_VAL(ENC_ADV_DATA)
int
peer_set_addr(uint16_t conn_handle, uint8_t *peer_addr)
{
struct peer *peer;
peer = peer_find(conn_handle);
if (peer == NULL) {
return BLE_HS_ENOTCONN;
}{...}
memcpy(&peer->peer_addr, peer_addr, PEER_ADDR_VAL_SIZE);
return 0;
}{...}
/* ... */#endif
static void
peer_free_mem(void)
{
free(peer_mem);
peer_mem = NULL;
free(peer_svc_mem);
peer_svc_mem = NULL;
free(peer_chr_mem);
peer_chr_mem = NULL;
free(peer_dsc_mem);
peer_dsc_mem = NULL;
}{ ... }
int
peer_init(int max_peers, int max_svcs, int max_chrs, int max_dscs)
{
int rc;
peer_free_mem();
peer_mem = malloc(
OS_MEMPOOL_BYTES(max_peers, sizeof (struct peer)));
if (peer_mem == NULL) {
rc = BLE_HS_ENOMEM;
goto err;
}{...}
rc = os_mempool_init(&peer_pool, max_peers,
sizeof (struct peer), peer_mem,
"peer_pool");
if (rc != 0) {
rc = BLE_HS_EOS;
goto err;
}{...}
peer_svc_mem = malloc(
OS_MEMPOOL_BYTES(max_svcs, sizeof (struct peer_svc)));
if (peer_svc_mem == NULL) {
rc = BLE_HS_ENOMEM;
goto err;
}{...}
rc = os_mempool_init(&peer_svc_pool, max_svcs,
sizeof (struct peer_svc), peer_svc_mem,
"peer_svc_pool");
if (rc != 0) {
rc = BLE_HS_EOS;
goto err;
}{...}
peer_chr_mem = malloc(
OS_MEMPOOL_BYTES(max_chrs, sizeof (struct peer_chr)));
if (peer_chr_mem == NULL) {
rc = BLE_HS_ENOMEM;
goto err;
}{...}
rc = os_mempool_init(&peer_chr_pool, max_chrs,
sizeof (struct peer_chr), peer_chr_mem,
"peer_chr_pool");
if (rc != 0) {
rc = BLE_HS_EOS;
goto err;
}{...}
peer_dsc_mem = malloc(
OS_MEMPOOL_BYTES(max_dscs, sizeof (struct peer_dsc)));
if (peer_dsc_mem == NULL) {
rc = BLE_HS_ENOMEM;
goto err;
}{...}
rc = os_mempool_init(&peer_dsc_pool, max_dscs,
sizeof (struct peer_dsc), peer_dsc_mem,
"peer_dsc_pool");
if (rc != 0) {
rc = BLE_HS_EOS;
goto err;
}{...}
return 0;
err:
peer_free_mem();
return rc;
}{ ... }