Browse Source

implement ble service and characteristic discovery and value write for volcano. still crashing unfortunately.

Thomas Buck 1 year ago
parent
commit
395ef608e6
4 changed files with 291 additions and 25 deletions
  1. 3
    2
      include/ble.h
  2. 252
    17
      src/ble.c
  3. 25
    0
      src/console.c
  4. 11
    6
      src/volcano.c

+ 3
- 2
include/ble.h View File

@@ -51,7 +51,8 @@ void ble_connect(bd_addr_t addr, bd_addr_type_t type);
51 51
 bool ble_is_connected(void);
52 52
 void ble_disconnect(void);
53 53
 
54
-int32_t ble_read(const uint8_t *uuid, uint8_t *buff, uint16_t buff_len);
55
-int32_t ble_write(const uint8_t *uuid, uint8_t *buff, uint16_t buff_len);
54
+int32_t ble_read(const uint8_t *characteristic, uint8_t *buff, uint16_t buff_len);
55
+int8_t ble_write(const uint8_t *service, const uint8_t *characteristic,
56
+                 uint8_t *buff, uint16_t buff_len);
56 57
 
57 58
 #endif // __BLE_H__

+ 252
- 17
src/ble.c View File

@@ -27,6 +27,8 @@
27 27
 #include "ble.h"
28 28
 
29 29
 #define BLE_MAX_SCAN_AGE_MS (10 * 1000)
30
+#define BLE_MAX_SERVICES 8
31
+#define BLE_MAX_CHARACTERISTICS 8
30 32
 
31 33
 enum ble_state {
32 34
     TC_OFF = 0,
@@ -36,15 +38,35 @@ enum ble_state {
36 38
     TC_READY,
37 39
     TC_W4_READ,
38 40
     TC_READ_COMPLETE,
41
+    TC_W4_SERVICE,
42
+    TC_W4_CHARACTERISTIC,
43
+    TC_W4_WRITE,
44
+    TC_WRITE_COMPLETE,
45
+};
46
+
47
+struct ble_characteristic {
48
+    bool set;
49
+    gatt_client_characteristic_t c;
50
+};
51
+
52
+struct ble_service {
53
+    bool set;
54
+    gatt_client_service_t service;
55
+    struct ble_characteristic chars[BLE_MAX_CHARACTERISTICS];
39 56
 };
40 57
 
41 58
 static btstack_packet_callback_registration_t hci_event_callback_registration;
42 59
 static hci_con_handle_t connection_handle;
43
-
44 60
 static enum ble_state state = TC_OFF;
61
+
45 62
 static struct ble_scan_result scans[BLE_MAX_SCAN_RESULTS] = {0};
63
+
46 64
 static uint16_t read_len = 0;
47
-static uint8_t read_buff[BLE_MAX_VALUE_LEN] = {0};
65
+static uint8_t data_buff[BLE_MAX_VALUE_LEN] = {0};
66
+
67
+static struct ble_service services[BLE_MAX_SERVICES] = {0};
68
+static uint8_t service_idx = 0;
69
+static uint8_t characteristic_idx = 0;
48 70
 
49 71
 static void hci_add_scan_result(bd_addr_t addr, bd_addr_type_t type, int8_t rssi) {
50 72
     int unused = -1;
@@ -196,7 +218,7 @@ static void hci_event_handler(uint8_t packet_type, uint16_t channel, uint8_t *pa
196 218
 
197 219
     case GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT:
198 220
         if (state != TC_W4_READ) {
199
-            debug("gatt query result in invalid state %d", state);
221
+            debug("gatt value query result in invalid state %d", state);
200 222
             return;
201 223
         }
202 224
         uint16_t len = gatt_event_characteristic_value_query_result_get_value_length(packet);
@@ -204,20 +226,65 @@ static void hci_event_handler(uint8_t packet_type, uint16_t channel, uint8_t *pa
204 226
             debug("not enough space for value (%d + %d > %d)", read_len, len, BLE_MAX_VALUE_LEN);
205 227
             return;
206 228
         }
207
-        memcpy(read_buff + read_len,
229
+        memcpy(data_buff + read_len,
208 230
                gatt_event_characteristic_value_query_result_get_value(packet),
209 231
                len);
210 232
         read_len += len;
211 233
         break;
212 234
 
213
-    case GATT_EVENT_QUERY_COMPLETE:
214
-        if (state != TC_W4_READ) {
215
-            debug("gatt query complete in invalid state %d", state);
235
+    case GATT_EVENT_SERVICE_QUERY_RESULT:
236
+        if (state != TC_W4_SERVICE) {
237
+            debug("gatt service query result in invalid state %d", state);
238
+            return;
239
+        }
240
+        gatt_event_service_query_result_get_service(packet, &services[service_idx].service);
241
+        debug("got service %s result", uuid128_to_str(services[service_idx].service.uuid128));
242
+        break;
243
+
244
+    case GATT_EVENT_CHARACTERISTIC_QUERY_RESULT:
245
+        if (state != TC_W4_CHARACTERISTIC) {
246
+            debug("gatt characteristic query result in invalid state %d", state);
216 247
             return;
217 248
         }
218
-        state = TC_READ_COMPLETE;
249
+        gatt_event_characteristic_query_result_get_characteristic(packet, &services[service_idx].chars[characteristic_idx].c);
250
+        debug("got characteristic %s result", uuid128_to_str(services[service_idx].chars[characteristic_idx].c.uuid128));
219 251
         break;
220 252
 
253
+    case GATT_EVENT_QUERY_COMPLETE: {
254
+        uint8_t att_status = gatt_event_query_complete_get_att_status(packet);
255
+        if (att_status != ATT_ERROR_SUCCESS){
256
+            debug("query result has ATT Error 0x%02x in %d", att_status, state);
257
+            state = TC_READY;
258
+            break;
259
+        }
260
+
261
+        switch (state) {
262
+        case TC_W4_READ:
263
+            state = TC_READ_COMPLETE;
264
+            break;
265
+
266
+        case TC_W4_SERVICE:
267
+            debug("service %s complete", uuid128_to_str(services[service_idx].service.uuid128));
268
+            state = TC_READY;
269
+            break;
270
+
271
+        case TC_W4_CHARACTERISTIC:
272
+            debug("characteristic %s complete", uuid128_to_str(services[service_idx].chars[characteristic_idx].c.uuid128));
273
+            state = TC_READY;
274
+            break;
275
+
276
+        case TC_W4_WRITE:
277
+            debug("write complete");
278
+            state = TC_WRITE_COMPLETE;
279
+            break;
280
+
281
+        default:
282
+            debug("gatt query complete in invalid state %d", state);
283
+            break;
284
+        }
285
+        break;
286
+    }
287
+
221 288
     default:
222 289
         //debug("unexpected event 0x%02X", hci_event_packet_get_type(packet));
223 290
         break;
@@ -227,10 +294,16 @@ static void hci_event_handler(uint8_t packet_type, uint16_t channel, uint8_t *pa
227 294
 void ble_init(void) {
228 295
     cyw43_thread_enter();
229 296
 
297
+    state = TC_OFF;
230 298
     for (uint i = 0; i < BLE_MAX_SCAN_RESULTS; i++) {
231 299
         scans[i].set = false;
232 300
     }
233
-    state = TC_OFF;
301
+    for (uint i = 0; i < BLE_MAX_SERVICES; i++) {
302
+        services[i].set = false;
303
+        for (uint j = 0; j < BLE_MAX_CHARACTERISTICS; j++) {
304
+            services[i].chars[j].set = false;
305
+        }
306
+    }
234 307
 
235 308
     cyw43_thread_exit();
236 309
 
@@ -389,7 +462,7 @@ void ble_disconnect(void) {
389 462
     cyw43_thread_exit();
390 463
 }
391 464
 
392
-int32_t ble_read(const uint8_t *uuid, uint8_t *buff, uint16_t buff_len) {
465
+int32_t ble_read(const uint8_t *characteristic, uint8_t *buff, uint16_t buff_len) {
393 466
     cyw43_thread_enter();
394 467
 
395 468
     if (state != TC_READY) {
@@ -400,7 +473,8 @@ int32_t ble_read(const uint8_t *uuid, uint8_t *buff, uint16_t buff_len) {
400 473
 
401 474
     uint8_t r = gatt_client_read_value_of_characteristics_by_uuid128(hci_event_handler,
402 475
                                                                      connection_handle,
403
-                                                                     0x0001, 0xFFFF, uuid);
476
+                                                                     0x0001, 0xFFFF,
477
+                                                                     characteristic);
404 478
     if (r != ERROR_CODE_SUCCESS) {
405 479
         cyw43_thread_exit();
406 480
         debug("gatt read failed %d", r);
@@ -435,15 +509,176 @@ int32_t ble_read(const uint8_t *uuid, uint8_t *buff, uint16_t buff_len) {
435 509
         return -3;
436 510
     }
437 511
 
438
-    memcpy(buff, read_buff, read_len);
512
+    memcpy(buff, data_buff, read_len);
439 513
 
440 514
     cyw43_thread_exit();
441 515
     return read_len;
442 516
 }
443 517
 
444
-int32_t ble_write(const uint8_t *uuid, uint8_t *buff, uint16_t buff_len) {
445
-    UNUSED(uuid);
446
-    UNUSED(buff);
447
-    UNUSED(buff_len);
448
-    return -1;
518
+int8_t ble_write(const uint8_t *service, const uint8_t *characteristic,
519
+                  uint8_t *buff, uint16_t buff_len) {
520
+    cyw43_thread_enter();
521
+
522
+    if (state != TC_READY) {
523
+        cyw43_thread_exit();
524
+        debug("invalid state for write (%d)", state);
525
+        return -1;
526
+    }
527
+
528
+    // check if service has already been discovered
529
+    int srvc = -1, free_srvc = -1;
530
+    for (int i = 0; i < BLE_MAX_SERVICES; i++) {
531
+        if (!services[i].set) {
532
+            if (free_srvc < 0) {
533
+                free_srvc = i;
534
+            }
535
+            continue;
536
+        }
537
+
538
+        if (memcmp(services[i].service.uuid128, service, 16) == 0) {
539
+            srvc = i;
540
+            break;
541
+        }
542
+    }
543
+
544
+    // if this service has not been discovered yet, add it
545
+    if (srvc < 0) {
546
+        if (free_srvc < 0) {
547
+            debug("no space left for BLE service. overwriting.");
548
+            free_srvc = 0;
549
+        }
550
+        srvc = free_srvc;
551
+        services[srvc].set = true;
552
+
553
+        debug("discovering service %s at %d", uuid128_to_str(service), srvc);
554
+
555
+        uint8_t r = gatt_client_discover_primary_services_by_uuid128(hci_event_handler,
556
+                                                                     connection_handle,
557
+                                                                     service);
558
+        if (r != ERROR_CODE_SUCCESS) {
559
+            cyw43_thread_exit();
560
+            debug("gatt service discovery failed %d", r);
561
+            return -2;
562
+        }
563
+
564
+        state = TC_W4_SERVICE;
565
+        service_idx = srvc;
566
+        cyw43_thread_exit();
567
+
568
+        debug("waiting for service discovery");
569
+        while (1) {
570
+            sleep_ms(1);
571
+
572
+            // TODO timeout
573
+
574
+            cyw43_thread_enter();
575
+            enum ble_state state_cached = state;
576
+            cyw43_thread_exit();
577
+
578
+            if (state_cached == TC_READY) {
579
+            debug("service discovery done");
580
+                break;
581
+            }
582
+        }
583
+    }
584
+
585
+    // check if characteristic has already been discovered
586
+    int ch = -1, free_ch = -1;
587
+    for (int i = 0; i < BLE_MAX_CHARACTERISTICS; i++) {
588
+        if (!services[srvc].chars[i].set) {
589
+            if (free_ch < 0) {
590
+                free_ch = i;
591
+            }
592
+            continue;
593
+        }
594
+
595
+        if (memcmp(services[srvc].chars[i].c.uuid128, characteristic, 16) == 0) {
596
+            ch = i;
597
+            break;
598
+        }
599
+    }
600
+
601
+    // if this characteristic has not been discovered yet, add it
602
+    if (ch < 0) {
603
+        if (free_ch < 0) {
604
+            debug("no space left for BLE characteristic. overwriting.");
605
+            free_ch = 0;
606
+        }
607
+        ch = free_ch;
608
+        services[srvc].chars[ch].set = true;
609
+
610
+        debug("discovering characteristic %s at %d", uuid128_to_str(characteristic), ch);
611
+
612
+        uint8_t r = gatt_client_discover_characteristics_for_service_by_uuid128(hci_event_handler,
613
+                                                                                connection_handle,
614
+                                                                                &services[srvc].service,
615
+                                                                                characteristic);
616
+        if (r != ERROR_CODE_SUCCESS) {
617
+            cyw43_thread_exit();
618
+            debug("gatt characteristic discovery failed %d", r);
619
+            return -3;
620
+        }
621
+
622
+        state = TC_W4_CHARACTERISTIC;
623
+        characteristic_idx = ch;
624
+        cyw43_thread_exit();
625
+
626
+        debug("waiting for characteristic discovery");
627
+        while (1) {
628
+            sleep_ms(1);
629
+
630
+            // TODO timeout
631
+
632
+            cyw43_thread_enter();
633
+            enum ble_state state_cached = state;
634
+            cyw43_thread_exit();
635
+
636
+            if (state_cached == TC_READY) {
637
+                debug("characteristic discovery done");
638
+                break;
639
+            }
640
+        }
641
+    }
642
+
643
+    if (buff_len > BLE_MAX_VALUE_LEN) {
644
+        buff_len = BLE_MAX_VALUE_LEN;
645
+    }
646
+    memcpy(data_buff, buff, buff_len);
647
+
648
+    uint8_t r = gatt_client_write_value_of_characteristic(hci_event_handler,
649
+                                                          connection_handle,
650
+                                                          services[srvc].chars[ch].c.value_handle,
651
+                                                          buff_len, data_buff);
652
+    if (r != ERROR_CODE_SUCCESS) {
653
+        cyw43_thread_exit();
654
+        debug("gatt write failed %d", r);
655
+        return -4;
656
+    }
657
+
658
+    state = TC_W4_WRITE;
659
+    cyw43_thread_exit();
660
+
661
+    debug("waiting for write");
662
+    while (1) {
663
+        sleep_ms(1);
664
+
665
+        // TODO timeout
666
+
667
+        cyw43_thread_enter();
668
+        enum ble_state state_cached = state;
669
+        cyw43_thread_exit();
670
+
671
+        if ((state_cached == TC_WRITE_COMPLETE) || (state_cached == TC_READY)) {
672
+            debug("write done (%s)", (state_cached == TC_READY) ? "error" : "success");
673
+            break;
674
+        }
675
+    }
676
+
677
+    cyw43_thread_enter();
678
+
679
+    int8_t ret = (state == TC_WRITE_COMPLETE) ? 0 : -1;
680
+    state = TC_READY;
681
+
682
+    cyw43_thread_exit();
683
+    return ret;
449 684
 }

+ 25
- 0
src/console.c View File

@@ -108,6 +108,7 @@ static void cnsl_interpret(const char *line) {
108 108
         println("");
109 109
         println("   vrct - Volcano read current temperature");
110 110
         println("   vrtt - Volcano read target temperature");
111
+        println(" vwtt X - Volcano write target temperature");
111 112
         println("");
112 113
         println("Press Enter with no input to repeat last command.");
113 114
         println("Use repeat to continuously execute last command.");
@@ -234,6 +235,30 @@ static void cnsl_interpret(const char *line) {
234 235
 #ifdef TEST_VOLCANO_AUTO_CONNECT
235 236
         ble_disconnect();
236 237
 #endif // TEST_VOLCANO_AUTO_CONNECT
238
+    } else if (str_startswith(line, "vwtt ")) {
239
+        float val;
240
+        int r = sscanf(line, "vwtt %f", &val);
241
+        if (r != 1) {
242
+            println("invalid input (%d)", r);
243
+        } else {
244
+            uint16_t v = val * 10.0;
245
+
246
+#ifdef TEST_VOLCANO_AUTO_CONNECT
247
+            VOLCANO_AUTO_CONNECT
248
+#endif // TEST_VOLCANO_AUTO_CONNECT
249
+
250
+            int8_t r = volcano_set_target_temp(v);
251
+
252
+#ifdef TEST_VOLCANO_AUTO_CONNECT
253
+            ble_disconnect();
254
+#endif // TEST_VOLCANO_AUTO_CONNECT
255
+
256
+            if (r < 0) {
257
+                println("error writing target temp %d", r);
258
+            } else {
259
+                println("success");
260
+            }
261
+        }
237 262
     } else {
238 263
         println("unknown command \"%s\"", line);
239 264
     }

+ 11
- 6
src/volcano.c View File

@@ -23,6 +23,7 @@
23 23
 #include "volcano.h"
24 24
 
25 25
 // Volcano UUIDs are always the same, except for the 4th byte
26
+#define UUID_WRITE_SRVC   0x00
26 27
 #define UUID_CURRENT_TEMP 0x01
27 28
 #define UUID_TARGET_TEMP  0x03
28 29
 #define UUID_HEATER_ON    0x0F
@@ -35,6 +36,10 @@ static uint8_t uuid_base[16] = {
35 36
     0x10, 0x11, 0x00, 0xFF, 0x53, 0x54, 0x4f, 0x52,
36 37
     0x5a, 0x26, 0x42, 0x49, 0x43, 0x4b, 0x45, 0x4c,
37 38
 };
39
+static uint8_t uuid_base2[16] = {
40
+    0x10, 0x11, 0x00, 0xFF, 0x53, 0x54, 0x4f, 0x52,
41
+    0x5a, 0x26, 0x42, 0x49, 0x43, 0x4b, 0x45, 0x4c,
42
+};
38 43
 
39 44
 int16_t volcano_get_current_temp(void) {
40 45
     uuid_base[3] = UUID_CURRENT_TEMP;
@@ -65,16 +70,16 @@ int16_t volcano_get_target_temp(void) {
65 70
 }
66 71
 
67 72
 int8_t volcano_set_target_temp(uint16_t value) {
68
-    uuid_base[3] = UUID_TARGET_TEMP;
73
+    uuid_base[3] = UUID_WRITE_SRVC;
74
+    uuid_base2[3] = UUID_TARGET_TEMP;
69 75
 
70 76
     uint8_t buff[4];
71 77
     uint32_t *v = (uint32_t *)buff;
72 78
     *v = value;
73 79
 
74
-    int32_t r = ble_write(uuid_base, buff, 4);
75
-    if (r != 4) {
76
-        debug("ble_write unexpected value %ld", r);
77
-        return -1;
80
+    int8_t r = ble_write(uuid_base, uuid_base2, buff, 4);
81
+    if (r != 0) {
82
+        debug("ble_write unexpected value %d", r);
78 83
     }
79
-    return 0;
84
+    return r;
80 85
 }

Loading…
Cancel
Save