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
 bool ble_is_connected(void);
51
 bool ble_is_connected(void);
52
 void ble_disconnect(void);
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
 #endif // __BLE_H__
58
 #endif // __BLE_H__

+ 252
- 17
src/ble.c View File

27
 #include "ble.h"
27
 #include "ble.h"
28
 
28
 
29
 #define BLE_MAX_SCAN_AGE_MS (10 * 1000)
29
 #define BLE_MAX_SCAN_AGE_MS (10 * 1000)
30
+#define BLE_MAX_SERVICES 8
31
+#define BLE_MAX_CHARACTERISTICS 8
30
 
32
 
31
 enum ble_state {
33
 enum ble_state {
32
     TC_OFF = 0,
34
     TC_OFF = 0,
36
     TC_READY,
38
     TC_READY,
37
     TC_W4_READ,
39
     TC_W4_READ,
38
     TC_READ_COMPLETE,
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
 static btstack_packet_callback_registration_t hci_event_callback_registration;
58
 static btstack_packet_callback_registration_t hci_event_callback_registration;
42
 static hci_con_handle_t connection_handle;
59
 static hci_con_handle_t connection_handle;
43
-
44
 static enum ble_state state = TC_OFF;
60
 static enum ble_state state = TC_OFF;
61
+
45
 static struct ble_scan_result scans[BLE_MAX_SCAN_RESULTS] = {0};
62
 static struct ble_scan_result scans[BLE_MAX_SCAN_RESULTS] = {0};
63
+
46
 static uint16_t read_len = 0;
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
 static void hci_add_scan_result(bd_addr_t addr, bd_addr_type_t type, int8_t rssi) {
71
 static void hci_add_scan_result(bd_addr_t addr, bd_addr_type_t type, int8_t rssi) {
50
     int unused = -1;
72
     int unused = -1;
196
 
218
 
197
     case GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT:
219
     case GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT:
198
         if (state != TC_W4_READ) {
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
             return;
222
             return;
201
         }
223
         }
202
         uint16_t len = gatt_event_characteristic_value_query_result_get_value_length(packet);
224
         uint16_t len = gatt_event_characteristic_value_query_result_get_value_length(packet);
204
             debug("not enough space for value (%d + %d > %d)", read_len, len, BLE_MAX_VALUE_LEN);
226
             debug("not enough space for value (%d + %d > %d)", read_len, len, BLE_MAX_VALUE_LEN);
205
             return;
227
             return;
206
         }
228
         }
207
-        memcpy(read_buff + read_len,
229
+        memcpy(data_buff + read_len,
208
                gatt_event_characteristic_value_query_result_get_value(packet),
230
                gatt_event_characteristic_value_query_result_get_value(packet),
209
                len);
231
                len);
210
         read_len += len;
232
         read_len += len;
211
         break;
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
             return;
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
         break;
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
     default:
288
     default:
222
         //debug("unexpected event 0x%02X", hci_event_packet_get_type(packet));
289
         //debug("unexpected event 0x%02X", hci_event_packet_get_type(packet));
223
         break;
290
         break;
227
 void ble_init(void) {
294
 void ble_init(void) {
228
     cyw43_thread_enter();
295
     cyw43_thread_enter();
229
 
296
 
297
+    state = TC_OFF;
230
     for (uint i = 0; i < BLE_MAX_SCAN_RESULTS; i++) {
298
     for (uint i = 0; i < BLE_MAX_SCAN_RESULTS; i++) {
231
         scans[i].set = false;
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
     cyw43_thread_exit();
308
     cyw43_thread_exit();
236
 
309
 
389
     cyw43_thread_exit();
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
     cyw43_thread_enter();
466
     cyw43_thread_enter();
394
 
467
 
395
     if (state != TC_READY) {
468
     if (state != TC_READY) {
400
 
473
 
401
     uint8_t r = gatt_client_read_value_of_characteristics_by_uuid128(hci_event_handler,
474
     uint8_t r = gatt_client_read_value_of_characteristics_by_uuid128(hci_event_handler,
402
                                                                      connection_handle,
475
                                                                      connection_handle,
403
-                                                                     0x0001, 0xFFFF, uuid);
476
+                                                                     0x0001, 0xFFFF,
477
+                                                                     characteristic);
404
     if (r != ERROR_CODE_SUCCESS) {
478
     if (r != ERROR_CODE_SUCCESS) {
405
         cyw43_thread_exit();
479
         cyw43_thread_exit();
406
         debug("gatt read failed %d", r);
480
         debug("gatt read failed %d", r);
435
         return -3;
509
         return -3;
436
     }
510
     }
437
 
511
 
438
-    memcpy(buff, read_buff, read_len);
512
+    memcpy(buff, data_buff, read_len);
439
 
513
 
440
     cyw43_thread_exit();
514
     cyw43_thread_exit();
441
     return read_len;
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
         println("");
108
         println("");
109
         println("   vrct - Volcano read current temperature");
109
         println("   vrct - Volcano read current temperature");
110
         println("   vrtt - Volcano read target temperature");
110
         println("   vrtt - Volcano read target temperature");
111
+        println(" vwtt X - Volcano write target temperature");
111
         println("");
112
         println("");
112
         println("Press Enter with no input to repeat last command.");
113
         println("Press Enter with no input to repeat last command.");
113
         println("Use repeat to continuously execute last command.");
114
         println("Use repeat to continuously execute last command.");
234
 #ifdef TEST_VOLCANO_AUTO_CONNECT
235
 #ifdef TEST_VOLCANO_AUTO_CONNECT
235
         ble_disconnect();
236
         ble_disconnect();
236
 #endif // TEST_VOLCANO_AUTO_CONNECT
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
     } else {
262
     } else {
238
         println("unknown command \"%s\"", line);
263
         println("unknown command \"%s\"", line);
239
     }
264
     }

+ 11
- 6
src/volcano.c View File

23
 #include "volcano.h"
23
 #include "volcano.h"
24
 
24
 
25
 // Volcano UUIDs are always the same, except for the 4th byte
25
 // Volcano UUIDs are always the same, except for the 4th byte
26
+#define UUID_WRITE_SRVC   0x00
26
 #define UUID_CURRENT_TEMP 0x01
27
 #define UUID_CURRENT_TEMP 0x01
27
 #define UUID_TARGET_TEMP  0x03
28
 #define UUID_TARGET_TEMP  0x03
28
 #define UUID_HEATER_ON    0x0F
29
 #define UUID_HEATER_ON    0x0F
35
     0x10, 0x11, 0x00, 0xFF, 0x53, 0x54, 0x4f, 0x52,
36
     0x10, 0x11, 0x00, 0xFF, 0x53, 0x54, 0x4f, 0x52,
36
     0x5a, 0x26, 0x42, 0x49, 0x43, 0x4b, 0x45, 0x4c,
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
 int16_t volcano_get_current_temp(void) {
44
 int16_t volcano_get_current_temp(void) {
40
     uuid_base[3] = UUID_CURRENT_TEMP;
45
     uuid_base[3] = UUID_CURRENT_TEMP;
65
 }
70
 }
66
 
71
 
67
 int8_t volcano_set_target_temp(uint16_t value) {
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
     uint8_t buff[4];
76
     uint8_t buff[4];
71
     uint32_t *v = (uint32_t *)buff;
77
     uint32_t *v = (uint32_t *)buff;
72
     *v = value;
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