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
412
415
416
417
418
419
420
421
422
423
424
428
429
430
431
432
433
434
435
436
443
444
445
446
447
448
449
450
451
452
453
454
455
460
461
464
465
468
469
470
471
472
473
474
475
476
483
484
485
486
487
488
489
490
491
492
497
498
499
500
501
502
503
504
505
506
507
508
509
512
513
518
519
520
521
522
523
524
525
526
527
528
529
530
533
534
539
540
541
542
543
544
545
546
547
548
549
550
554
555
556
560
561
562
563
564
565
570
571
572
573
574
575
576
577
578
579
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
614
615
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
667
671
672
673
676
677
678
679
680
681
682
683
684
685
686
687
690
691
692
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
735
736
737
738
739
743
744
745
746
750
751
752
753
754
758
759
760
761
765
766
767
768
769
773
774
775
776
780
781
782
783
784
788
789
790
791
792
793
794
795
/* ... */
#include <assert.h>
#include <string.h>
#include "host/ble_hs.h"
#include "gattc.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 ((uuid != NULL) && (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 ((chr_uuid != NULL) && (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 ((dsc_uuid != NULL) && (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_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;
}{ ... }
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();
ESP_LOGE("ERROR", "Error while allocating mem");
return rc;
}{ ... }