1
6
7
17
18
19
20
21
22
23
24
28
29
30
31
32
39
40
44
45
46
47
48
49
50
51
52
53
54
58
59
60
61
62
63
64
65
66
67
71
72
73
74
75
76
81
82
83
84
85
86
87
88
89
90
94
95
96
97
98
99
100
101
102
103
104
108
109
110
111
112
113
114
115
116
117
121
122
123
124
125
126
127
132
133
134
135
136
137
138
139
143
144
145
146
147
148
149
150
151
155
156
157
160
161
162
163
164
165
166
167
168
173
174
175
176
177
178
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
217
218
219
220
225
226
227
228
229
230
231
232
235
236
237
238
239
246
247
251
252
253
254
257
258
259
260
263
264
265
266
267
268
269
270
271
272
276
277
280
281
282
286
287
288
289
290
291
292
293
294
295
296
300
301
302
307
308
309
310
311
312
313
314
315
316
319
320
321
322
323
324
325
328
329
330
333
334
335
336
339
340
341
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
368
369
370
373
374
375
376
377
378
379
380
383
384
385
388
393
394
395
396
397
398
403
404
405
406
407
408
409
410
411
412
416
420
421
422
429
430
431
432
436
437
440
441
442
443
444
445
446
447
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
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
508
509
510
511
512
513
514
515
516
517
524
525
533
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
560
561
562
563
564
565
566
567
568
576
577
578
579
580
581
582
583
584
585
586
587
588
589
591
592
593
600
601
605
606
607
608
609
610
611
614
615
616
617
623
624
625
627
628
629
630
631
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
668
669
670
671
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
/* ... */
#include "esp_log.h"
#include "nvs_flash.h"
#include "nimble/nimble_port.h"
#include "nimble/nimble_port_freertos.h"
#include "host/ble_hs.h"
#include "host/util/util.h"
#include "console/console.h"
#include "services/gap/ble_svc_gap.h"
#include "ble_htp_cent.h"9 includes
static const char *tag = "NimBLE_HTP_CENT";
static int ble_htp_cent_gap_event(struct ble_gap_event *event, void *arg);
static uint8_t peer_addr[6];
void ble_store_config_init(void);
static void ble_htp_cent_scan(void);
/* ... */
static int
ble_htp_cent_on_subscribe_temp(uint16_t conn_handle,
const struct ble_gatt_error *error,
struct ble_gatt_attr *attr,
void *arg)
{
MODLOG_DFLT(INFO, "Subscribe to intermediate temperature char completed; status=%d "
"conn_handle=%d attr_handle=%d\n",
error->status, conn_handle, attr->handle);
return 0;
}{ ... }
/* ... */
static int
ble_htp_cent_on_subscribe(uint16_t conn_handle,
const struct ble_gatt_error *error,
struct ble_gatt_attr *attr,
void *arg)
{
MODLOG_DFLT(INFO, "Subscribe to temperature measurement char completed; status=%d "
"conn_handle=%d attr_handle=%d\n",
error->status, conn_handle, attr->handle);
/* ... */
const struct peer_dsc *dsc;
uint8_t value[2];
int rc;
const struct peer *peer = peer_find(conn_handle);
dsc = peer_dsc_find_uuid(peer,
BLE_UUID16_DECLARE(BLE_SVC_HTP_UUID16),
BLE_UUID16_DECLARE(BLE_SVC_HTP_CHR_UUID16_INTERMEDIATE_TEMP),
BLE_UUID16_DECLARE(BLE_SVC_HTP_DSC_CLT_CFG_UUID16));
if (dsc == NULL) {
MODLOG_DFLT(ERROR, "Error: Peer lacks a CCCD characteristic\n ");
goto err;
}{...}
value[0] = 1;
value[1] = 0;
rc = ble_gattc_write_flat(conn_handle, dsc->dsc.handle,
&value, sizeof value, ble_htp_cent_on_subscribe_temp, NULL);
if (rc != 0) {
MODLOG_DFLT(ERROR, "Error: Failed to subscribe to characteristic; "
"rc=%d\n", rc);
goto err;
}{...}
return 0;
err:
return ble_gap_terminate(peer->conn_handle, BLE_ERR_REM_USER_CONN_TERM);
return 0;
}{ ... }
/* ... */
static int
ble_htp_cent_on_write(uint16_t conn_handle,
const struct ble_gatt_error *error,
struct ble_gatt_attr *attr,
void *arg)
{
MODLOG_DFLT(INFO, "Write to measurement interval char completed; status=%d "
"conn_handle=%d attr_handle=%d\n",
error->status, conn_handle, attr->handle);
/* ... */
const struct peer_dsc *dsc;
uint8_t value[2];
int rc;
const struct peer *peer = peer_find(conn_handle);
dsc = peer_dsc_find_uuid(peer,
BLE_UUID16_DECLARE(BLE_SVC_HTP_UUID16),
BLE_UUID16_DECLARE(BLE_SVC_HTP_CHR_UUID16_TEMP_MEASUREMENT),
BLE_UUID16_DECLARE(BLE_SVC_HTP_DSC_CLT_CFG_UUID16));
if (dsc == NULL) {
MODLOG_DFLT(ERROR, "Error: Peer lacks a CCCD characteristic\n ");
goto err;
}{...}
value[0] = 2;
value[1] = 0;
rc = ble_gattc_write_flat(conn_handle, dsc->dsc.handle,
&value, sizeof value, ble_htp_cent_on_subscribe, NULL);
if (rc != 0) {
MODLOG_DFLT(ERROR, "Error: Failed to subscribe to characteristic; "
"rc=%d\n", rc);
goto err;
}{...}
return 0;
err:
return ble_gap_terminate(peer->conn_handle, BLE_ERR_REM_USER_CONN_TERM);
}{ ... }
/* ... */
static int
ble_htp_cent_on_read(uint16_t conn_handle,
const struct ble_gatt_error *error,
struct ble_gatt_attr *attr,
void *arg)
{
MODLOG_DFLT(INFO, "Read temperature type char completed; status=%d conn_handle=%d",
error->status, conn_handle);
if (error->status == 0) {
MODLOG_DFLT(INFO, " attr_handle=%d value=", attr->handle);
print_mbuf(attr->om);
}{...}
MODLOG_DFLT(INFO, "\n");
/* ... */
const struct peer_chr *chr;
uint16_t value;
int rc;
const struct peer *peer = peer_find(conn_handle);
chr = peer_chr_find_uuid(peer,
BLE_UUID16_DECLARE(BLE_SVC_HTP_UUID16),
BLE_UUID16_DECLARE(BLE_SVC_HTP_CHR_UUID16_MEASUREMENT_ITVL));
if (chr == NULL) {
MODLOG_DFLT(ERROR, "Error: Peer doesn't support the"
"measurement interval characteristic\n");
goto err;
}{...}
value = 2;
rc = ble_gattc_write_flat(conn_handle, chr->chr.val_handle,
&value, sizeof value, ble_htp_cent_on_write, NULL);
if (rc != 0) {
MODLOG_DFLT(ERROR, "Error: Failed to write characteristic; rc=%d\n",
rc);
goto err;
}{...}
return 0;
err:
return ble_gap_terminate(peer->conn_handle, BLE_ERR_REM_USER_CONN_TERM);
}{ ... }
/* ... */
static void
ble_htp_cent_read_write_subscribe(const struct peer *peer)
{
const struct peer_chr *chr;
int rc;
chr = peer_chr_find_uuid(peer,
BLE_UUID16_DECLARE(BLE_SVC_HTP_UUID16),
BLE_UUID16_DECLARE(BLE_SVC_HTP_CHR_UUID16_TEMP_TYPE));
if (chr == NULL) {
MODLOG_DFLT(ERROR, "Error: Peer doesn't support the Temperature Type"
" characteristic\n");
goto err;
}{...}
rc = ble_gattc_read(peer->conn_handle, chr->chr.val_handle,
ble_htp_cent_on_read, NULL);
if (rc != 0) {
MODLOG_DFLT(ERROR, "Error: Failed to read characteristic; rc=%d\n",
rc);
goto err;
}{...}
return;
err:
ble_gap_terminate(peer->conn_handle, BLE_ERR_REM_USER_CONN_TERM);
}{ ... }
/* ... */
static void
ble_htp_cent_on_disc_complete(const struct peer *peer, int status, void *arg)
{
if (status != 0) {
MODLOG_DFLT(ERROR, "Error: Service discovery failed; status=%d "
"conn_handle=%d\n", status, peer->conn_handle);
ble_gap_terminate(peer->conn_handle, BLE_ERR_REM_USER_CONN_TERM);
return;
}{...}
/* ... */
MODLOG_DFLT(INFO, "Service discovery complete; status=%d "
"conn_handle=%d\n", status, peer->conn_handle);
/* ... */
ble_htp_cent_read_write_subscribe(peer);
}{ ... }
/* ... */
static void
ble_htp_cent_scan(void)
{
uint8_t own_addr_type;
struct ble_gap_disc_params disc_params;
int rc;
rc = ble_hs_id_infer_auto(0, &own_addr_type);
if (rc != 0) {
MODLOG_DFLT(ERROR, "error determining address type; rc=%d\n", rc);
return;
}{...}
/* ... */
disc_params.filter_duplicates = 1;
/* ... */
disc_params.passive = 1;
disc_params.itvl = 0;
disc_params.window = 0;
disc_params.filter_policy = 0;
disc_params.limited = 0;
rc = ble_gap_disc(own_addr_type, BLE_HS_FOREVER, &disc_params,
ble_htp_cent_gap_event, NULL);
if (rc != 0) {
MODLOG_DFLT(ERROR, "Error initiating GAP discovery procedure; rc=%d\n",
rc);
}{...}
}{ ... }
/* ... */
#if CONFIG_EXAMPLE_EXTENDED_ADV
static int
ext_ble_htp_cent_should_connect(const struct ble_gap_ext_disc_desc *disc)
{
int offset = 0;
int ad_struct_len = 0;
if (disc->legacy_event_type != BLE_HCI_ADV_RPT_EVTYPE_ADV_IND &&
disc->legacy_event_type != BLE_HCI_ADV_RPT_EVTYPE_DIR_IND) {
return 0;
}{...}
if (strlen(CONFIG_EXAMPLE_PEER_ADDR) && (strncmp(CONFIG_EXAMPLE_PEER_ADDR, "ADDR_ANY", strlen ("ADDR_ANY")) != 0)) {
ESP_LOGI(tag, "Peer address from menuconfig: %s", CONFIG_EXAMPLE_PEER_ADDR);
sscanf(CONFIG_EXAMPLE_PEER_ADDR, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
&peer_addr[5], &peer_addr[4], &peer_addr[3],
&peer_addr[2], &peer_addr[1], &peer_addr[0]);
if (memcmp(peer_addr, disc->addr.val, sizeof(disc->addr.val)) != 0) {
return 0;
}{...}
}{...}
/* ... */
do {
ad_struct_len = disc->data[offset];
if (!ad_struct_len) {
break;
}{...}
if (disc->data[offset] == 0x03 && disc->data[offset + 1] == 0x03) {
if ( disc->data[offset + 2] == 0x18 && disc->data[offset + 3] == 0x09 ) {
return 1;
}{...}
}{...}
offset += ad_struct_len + 1;
}{...} while ( offset < disc->length_data );
return 0;
}{...}
/* ... */#else
static int
ble_htp_cent_should_connect(const struct ble_gap_disc_desc *disc)
{
struct ble_hs_adv_fields fields;
int rc;
int i;
if (disc->event_type != BLE_HCI_ADV_RPT_EVTYPE_ADV_IND &&
disc->event_type != BLE_HCI_ADV_RPT_EVTYPE_DIR_IND) {
return 0;
}{...}
rc = ble_hs_adv_parse_fields(&fields, disc->data, disc->length_data);
if (rc != 0) {
return 0;
}{...}
if (strlen(CONFIG_EXAMPLE_PEER_ADDR) && (strncmp(CONFIG_EXAMPLE_PEER_ADDR, "ADDR_ANY", strlen("ADDR_ANY")) != 0)) {
ESP_LOGI(tag, "Peer address from menuconfig: %s", CONFIG_EXAMPLE_PEER_ADDR);
sscanf(CONFIG_EXAMPLE_PEER_ADDR, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
&peer_addr[5], &peer_addr[4], &peer_addr[3],
&peer_addr[2], &peer_addr[1], &peer_addr[0]);
if (memcmp(peer_addr, disc->addr.val, sizeof(disc->addr.val)) != 0) {
return 0;
}{...}
}{...}
/* ... */
for (i = 0; i < fields.num_uuids16; i++) {
if (ble_uuid_u16(&fields.uuids16[i].u) == BLE_SVC_HTP_UUID16) {
return 1;
}{...}
}{...}
return 0;
}{ ... }
#endif/* ... */
/* ... */
static void
ble_htp_cent_connect_if_interesting(void *disc)
{
uint8_t own_addr_type;
int rc;
ble_addr_t *addr;
#if CONFIG_EXAMPLE_EXTENDED_ADV
if (!ext_ble_htp_cent_should_connect((struct ble_gap_ext_disc_desc *)disc)) {
return;
}{...}
#else/* ... */
if (!ble_htp_cent_should_connect((struct ble_gap_disc_desc *)disc)) {
return;
}{...}
#endif/* ... */
#if !(MYNEWT_VAL(BLE_HOST_ALLOW_CONNECT_WITH_SCAN))
rc = ble_gap_disc_cancel();
if (rc != 0) {
MODLOG_DFLT(DEBUG, "Failed to cancel scan; rc=%d\n", rc);
return;
}{...}
#endif/* ... */
rc = ble_hs_id_infer_auto(0, &own_addr_type);
if (rc != 0) {
MODLOG_DFLT(ERROR, "error determining address type; rc=%d\n", rc);
return;
}{...}
/* ... */
#if CONFIG_EXAMPLE_EXTENDED_ADV
addr = &((struct ble_gap_ext_disc_desc *)disc)->addr;
#else
addr = &((struct ble_gap_disc_desc *)disc)->addr;
#endif
rc = ble_gap_connect(own_addr_type, addr, 30000, NULL,
ble_htp_cent_gap_event, NULL);
if (rc != 0) {
MODLOG_DFLT(ERROR, "Error: Failed to connect to device; addr_type=%d "
"addr=%s; rc=%d\n",
addr->type, addr_str(addr->val), rc);
return;
}{...}
}{ ... }
/* ... */
static int
ble_htp_cent_gap_event(struct ble_gap_event *event, void *arg)
{
struct ble_gap_conn_desc desc;
struct ble_hs_adv_fields fields;
int rc;
switch (event->type) {
case BLE_GAP_EVENT_DISC:
rc = ble_hs_adv_parse_fields(&fields, event->disc.data,
event->disc.length_data);
if (rc != 0) {
return 0;
}{...}
print_adv_fields(&fields);
ble_htp_cent_connect_if_interesting(&event->disc);
return 0;
...
case BLE_GAP_EVENT_LINK_ESTAB:
if (event->link_estab.status == 0) {
MODLOG_DFLT(INFO, "Connection established ");
rc = ble_gap_conn_find(event->link_estab.conn_handle, &desc);
assert(rc == 0);
print_conn_desc(&desc);
MODLOG_DFLT(INFO, "\n");
rc = peer_add(event->link_estab.conn_handle);
if (rc != 0) {
MODLOG_DFLT(ERROR, "Failed to add peer; rc=%d\n", rc);
return 0;
}{...}
#if CONFIG_EXAMPLE_ENCRYPTION
/* ... */
rc = ble_gap_security_initiate(event->link_estab.conn_handle);
if (rc != 0) {
MODLOG_DFLT(INFO, "Security could not be initiated, rc = %d\n", rc);
return ble_gap_terminate(event->link_estab.conn_handle,
BLE_ERR_REM_USER_CONN_TERM);
}{...} else {
MODLOG_DFLT(INFO, "Connection secured\n");
}{...}
#else/* ... */
rc = peer_disc_all(event->link_estab.conn_handle,
ble_htp_cent_on_disc_complete, NULL);
if (rc != 0) {
MODLOG_DFLT(ERROR, "Failed to discover services; rc=%d\n", rc);
return 0;
}{...}
#endif/* ... */
}{...} else {
MODLOG_DFLT(ERROR, "Error: Connection failed; status=%d\n",
event->link_estab.status);
ble_htp_cent_scan();
}{...}
return 0;
...
case BLE_GAP_EVENT_DISCONNECT:
MODLOG_DFLT(INFO, "disconnect; reason=%d ", event->disconnect.reason);
print_conn_desc(&event->disconnect.conn);
MODLOG_DFLT(INFO, "\n");
peer_delete(event->disconnect.conn.conn_handle);
ble_htp_cent_scan();
return 0;
...
case BLE_GAP_EVENT_DISC_COMPLETE:
MODLOG_DFLT(INFO, "discovery complete; reason=%d\n",
event->disc_complete.reason);
return 0;
...
case BLE_GAP_EVENT_ENC_CHANGE:
MODLOG_DFLT(INFO, "encryption change event; status=%d ",
event->enc_change.status);
rc = ble_gap_conn_find(event->enc_change.conn_handle, &desc);
assert(rc == 0);
print_conn_desc(&desc);
#if CONFIG_EXAMPLE_ENCRYPTION
rc = peer_disc_all(event->link_estab.conn_handle,
ble_htp_cent_on_disc_complete, NULL);
if (rc != 0) {
MODLOG_DFLT(ERROR, "Failed to discover services; rc=%d\n", rc);
return 0;
}{...}
#endif/* ... */
return 0;
...
case BLE_GAP_EVENT_NOTIFY_RX:
MODLOG_DFLT(INFO, "received %s; conn_handle=%d attr_handle=%d "
"attr_len=%d\n",
event->notify_rx.indication ?
"indication" :
"notification",
event->notify_rx.conn_handle,
event->notify_rx.attr_handle,
OS_MBUF_PKTLEN(event->notify_rx.om));
/* ... */
return 0;
...
case BLE_GAP_EVENT_MTU:
MODLOG_DFLT(INFO, "mtu update event; conn_handle=%d cid=%d mtu=%d\n",
event->mtu.conn_handle,
event->mtu.channel_id,
event->mtu.value);
return 0;
...
case BLE_GAP_EVENT_REPEAT_PAIRING:
/* ... */
rc = ble_gap_conn_find(event->repeat_pairing.conn_handle, &desc);
assert(rc == 0);
ble_store_util_delete_peer(&desc.peer_id_addr);
/* ... */
return BLE_GAP_REPEAT_PAIRING_RETRY;
#if CONFIG_EXAMPLE_EXTENDED_ADV...
case BLE_GAP_EVENT_EXT_DISC:
ext_print_adv_report(&event->disc);
ble_htp_cent_connect_if_interesting(&event->disc);
return 0;/* ... */
#endif
default:
return 0;...
}{...}
}{ ... }
static void
ble_htp_cent_on_reset(int reason)
{
MODLOG_DFLT(ERROR, "Resetting state; reason=%d\n", reason);
}{ ... }
static void
ble_htp_cent_on_sync(void)
{
int rc;
rc = ble_hs_util_ensure_addr(0);
assert(rc == 0);
ble_htp_cent_scan();
}{ ... }
void ble_htp_cent_host_task(void *param)
{
ESP_LOGI(tag, "BLE Host Task Started");
nimble_port_run();
nimble_port_freertos_deinit();
}{ ... }
void
app_main(void)
{
int rc;
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}{...}
ESP_ERROR_CHECK(ret);
ret = nimble_port_init();
if (ret != ESP_OK) {
ESP_LOGE(tag, "Failed to init nimble %d ", ret);
return;
}{...}
ble_hs_cfg.reset_cb = ble_htp_cent_on_reset;
ble_hs_cfg.sync_cb = ble_htp_cent_on_sync;
ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
rc = peer_init(MYNEWT_VAL(BLE_MAX_CONNECTIONS), 64, 64, 64);
assert(rc == 0);
rc = ble_svc_gap_device_name_set("nimble-htp-cent");
assert(rc == 0);
ble_store_config_init();
nimble_port_freertos_init(ble_htp_cent_host_task);
}{ ... }