Browse Source

implement ble read

Thomas Buck 1 year ago
parent
commit
1b3e3e286b
7 changed files with 236 additions and 7 deletions
  1. 1
    0
      CMakeLists.txt
  2. 8
    1
      include/ble.h
  3. 29
    0
      include/volcano.h
  4. 105
    4
      src/ble.c
  5. 11
    1
      src/console.c
  6. 1
    1
      src/main.c
  7. 81
    0
      src/volcano.c

+ 1
- 0
CMakeLists.txt View File

60
     src/text.c
60
     src/text.c
61
     src/image.c
61
     src/image.c
62
     src/state.c
62
     src/state.c
63
+    src/volcano.c
63
 
64
 
64
     ${CMAKE_CURRENT_BINARY_DIR}/fatfs/ff.c
65
     ${CMAKE_CURRENT_BINARY_DIR}/fatfs/ff.c
65
     ${CMAKE_CURRENT_BINARY_DIR}/fatfs/ffunicode.c
66
     ${CMAKE_CURRENT_BINARY_DIR}/fatfs/ffunicode.c

+ 8
- 1
include/ble.h View File

23
 
23
 
24
 #define BLE_MAX_NAME_LENGTH 32
24
 #define BLE_MAX_NAME_LENGTH 32
25
 #define BLE_MAX_SCAN_RESULTS 32
25
 #define BLE_MAX_SCAN_RESULTS 32
26
+#define BLE_MAX_VALUE_LEN 64
26
 
27
 
27
 enum ble_scan_mode {
28
 enum ble_scan_mode {
28
     BLE_SCAN_OFF    = 0,
29
     BLE_SCAN_OFF    = 0,
42
 
43
 
43
 void ble_init(void);
44
 void ble_init(void);
44
 bool ble_is_ready(void);
45
 bool ble_is_ready(void);
46
+
45
 void ble_scan(enum ble_scan_mode mode);
47
 void ble_scan(enum ble_scan_mode mode);
46
-int ble_get_scan_results(struct ble_scan_result *buf, uint len);
48
+int32_t ble_get_scan_results(struct ble_scan_result *buf, uint16_t len);
49
+
47
 void ble_connect(bd_addr_t addr, bd_addr_type_t type);
50
 void ble_connect(bd_addr_t addr, bd_addr_type_t type);
51
+bool ble_is_connected(void);
48
 void ble_disconnect(void);
52
 void ble_disconnect(void);
49
 
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);
56
+
50
 #endif // __BLE_H__
57
 #endif // __BLE_H__

+ 29
- 0
include/volcano.h View File

1
+/*
2
+ * volcano.h
3
+ *
4
+ * Copyright (c) 2023 Thomas Buck (thomas@xythobuz.de)
5
+ *
6
+ * This program is free software: you can redistribute it and/or modify
7
+ * it under the terms of the GNU General Public License as published by
8
+ * the Free Software Foundation, either version 3 of the License, or
9
+ * (at your option) any later version.
10
+ *
11
+ * This program is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
+ * GNU General Public License for more details.
15
+ *
16
+ * See <http://www.gnu.org/licenses/>.
17
+ */
18
+
19
+#ifndef __VOLCANO_H__
20
+#define __VOLCANO_H__
21
+
22
+// in 1/10th degrees C, or < 0 on error
23
+int16_t volcano_get_current_temp(void);
24
+int16_t volcano_get_target_temp(void);
25
+
26
+// v in 1/10th degrees C, returns < 0 on error
27
+int8_t volcano_set_target_temp(uint16_t v);
28
+
29
+#endif // __VOLCANO_H__

+ 105
- 4
src/ble.c View File

33
     TC_IDLE,
33
     TC_IDLE,
34
     TC_W4_SCAN,
34
     TC_W4_SCAN,
35
     TC_W4_CONNECT,
35
     TC_W4_CONNECT,
36
-    TC_READY
36
+    TC_READY,
37
+    TC_W4_READ,
38
+    TC_READ_COMPLETE,
37
 };
39
 };
38
 
40
 
39
 static btstack_packet_callback_registration_t hci_event_callback_registration;
41
 static btstack_packet_callback_registration_t hci_event_callback_registration;
41
 
43
 
42
 static enum ble_state state = TC_OFF;
44
 static enum ble_state state = TC_OFF;
43
 static struct ble_scan_result scans[BLE_MAX_SCAN_RESULTS] = {0};
45
 static struct ble_scan_result scans[BLE_MAX_SCAN_RESULTS] = {0};
46
+static uint16_t read_len = 0;
47
+static uint8_t read_buff[BLE_MAX_VALUE_LEN] = {0};
44
 
48
 
45
 static void hci_add_scan_result(bd_addr_t addr, bd_addr_type_t type, int8_t rssi) {
49
 static void hci_add_scan_result(bd_addr_t addr, bd_addr_type_t type, int8_t rssi) {
46
     int unused = -1;
50
     int unused = -1;
101
     UNUSED(size);
105
     UNUSED(size);
102
     UNUSED(channel);
106
     UNUSED(channel);
103
 
107
 
108
+    //debug("type=0x%02X size=%d", packet_type, size);
109
+    //hexdump(packet, size);
110
+
104
     if (packet_type != HCI_EVENT_PACKET) {
111
     if (packet_type != HCI_EVENT_PACKET) {
105
         //debug("unexpected packet 0x%02X", packet_type);
112
         //debug("unexpected packet 0x%02X", packet_type);
106
         return;
113
         return;
187
         state = TC_IDLE;
194
         state = TC_IDLE;
188
         break;
195
         break;
189
 
196
 
197
+    case GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT:
198
+        if (state != TC_W4_READ) {
199
+            debug("gatt query result in invalid state %d", state);
200
+            return;
201
+        }
202
+        uint16_t len = gatt_event_characteristic_value_query_result_get_value_length(packet);
203
+        if ((read_len + len) > BLE_MAX_VALUE_LEN) {
204
+            debug("not enough space for value (%d + %d > %d)", read_len, len, BLE_MAX_VALUE_LEN);
205
+            return;
206
+        }
207
+        memcpy(read_buff + read_len,
208
+               gatt_event_characteristic_value_query_result_get_value(packet),
209
+               len);
210
+        read_len += len;
211
+        break;
212
+
213
+    case GATT_EVENT_QUERY_COMPLETE:
214
+        if (state != TC_W4_READ) {
215
+            debug("gatt query complete in invalid state %d", state);
216
+            return;
217
+        }
218
+        state = TC_READ_COMPLETE;
219
+        break;
220
+
190
     default:
221
     default:
191
         //debug("unexpected event 0x%02X", hci_event_packet_get_type(packet));
222
         //debug("unexpected event 0x%02X", hci_event_packet_get_type(packet));
192
         break;
223
         break;
272
     cyw43_thread_exit();
303
     cyw43_thread_exit();
273
 }
304
 }
274
 
305
 
275
-int ble_get_scan_results(struct ble_scan_result *buf, uint len) {
306
+int32_t ble_get_scan_results(struct ble_scan_result *buf, uint16_t len) {
276
     if (!buf || (len <= 0)) {
307
     if (!buf || (len <= 0)) {
277
         return -1;
308
         return -1;
278
     }
309
     }
284
         return -1;
315
         return -1;
285
     }
316
     }
286
 
317
 
287
-    uint pos = 0;
288
-    for (uint i = 0; i < BLE_MAX_SCAN_RESULTS; i++) {
318
+    uint16_t pos = 0;
319
+    for (uint16_t i = 0; i < BLE_MAX_SCAN_RESULTS; i++) {
289
         if (!scans[i].set) {
320
         if (!scans[i].set) {
290
             continue;
321
             continue;
291
         }
322
         }
337
     cyw43_thread_exit();
368
     cyw43_thread_exit();
338
 }
369
 }
339
 
370
 
371
+bool ble_is_connected(void) {
372
+    cyw43_thread_enter();
373
+
374
+    bool v = (state == TC_READY)
375
+             || (state == TC_W4_READ)
376
+             || (state == TC_READ_COMPLETE);
377
+
378
+    cyw43_thread_exit();
379
+    return v;
380
+}
381
+
340
 void ble_disconnect(void) {
382
 void ble_disconnect(void) {
341
     cyw43_thread_enter();
383
     cyw43_thread_enter();
342
 
384
 
346
 
388
 
347
     cyw43_thread_exit();
389
     cyw43_thread_exit();
348
 }
390
 }
391
+
392
+int32_t ble_read(const uint8_t *uuid, uint8_t *buff, uint16_t buff_len) {
393
+    cyw43_thread_enter();
394
+
395
+    if (state != TC_READY) {
396
+        cyw43_thread_exit();
397
+        debug("invalid state for read (%d)", state);
398
+        return -1;
399
+    }
400
+
401
+    uint8_t r = gatt_client_read_value_of_characteristics_by_uuid128(hci_event_handler,
402
+                                                                     connection_handle,
403
+                                                                     0x0001, 0xFFFF, uuid);
404
+    if (r != ERROR_CODE_SUCCESS) {
405
+        cyw43_thread_exit();
406
+        debug("gatt read failed %d", r);
407
+        return -2;
408
+    }
409
+
410
+    state = TC_W4_READ;
411
+    read_len = 0;
412
+    cyw43_thread_exit();
413
+
414
+    while (1) {
415
+        sleep_ms(1);
416
+
417
+        // TODO timeout
418
+
419
+        cyw43_thread_enter();
420
+        enum ble_state state_cached = state;
421
+        cyw43_thread_exit();
422
+
423
+        if (state_cached == TC_READ_COMPLETE) {
424
+            break;
425
+        }
426
+    }
427
+
428
+    cyw43_thread_enter();
429
+
430
+    state = TC_READY;
431
+
432
+    if (read_len > buff_len) {
433
+        debug("buffer too short (%d < %d)", buff_len, read_len);
434
+        cyw43_thread_exit();
435
+        return -3;
436
+    }
437
+
438
+    memcpy(buff, read_buff, read_len);
439
+
440
+    cyw43_thread_exit();
441
+    return read_len;
442
+}
443
+
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;
449
+}

+ 11
- 1
src/console.c View File

34
 #include "text.h"
34
 #include "text.h"
35
 #include "lcd.h"
35
 #include "lcd.h"
36
 #include "image.h"
36
 #include "image.h"
37
+#include "volcano.h"
37
 
38
 
38
 #define CNSL_BUFF_SIZE 1024
39
 #define CNSL_BUFF_SIZE 1024
39
 #define CNSL_REPEAT_MS 500
40
 #define CNSL_REPEAT_MS 500
89
         println("   text - draw text on screen");
90
         println("   text - draw text on screen");
90
         println("    bat - draw battery indicator");
91
         println("    bat - draw battery indicator");
91
         println("");
92
         println("");
93
+        println("   vrct - Volcano read current temperature");
94
+        println("   vrtt - Volcano read target temperature");
95
+        println("");
92
         println("Press Enter with no input to repeat last command.");
96
         println("Press Enter with no input to repeat last command.");
93
         println("Use repeat to continuously execute last command.");
97
         println("Use repeat to continuously execute last command.");
94
         println("Stop this by calling repeat again.");
98
         println("Stop this by calling repeat again.");
106
                 volt, lipo_percentage(volt),
110
                 volt, lipo_percentage(volt),
107
                 lipo_charging() ? "charging" : "draining");
111
                 lipo_charging() ? "charging" : "draining");
108
     } else if (strcmp(line, "scan") == 0) {
112
     } else if (strcmp(line, "scan") == 0) {
109
-        ble_scan(2);
113
+        ble_scan(BLE_SCAN_TOGGLE);
110
     } else if (strcmp(line, "scanres") == 0) {
114
     } else if (strcmp(line, "scanres") == 0) {
111
         struct ble_scan_result results[BLE_MAX_SCAN_RESULTS] = {0};
115
         struct ble_scan_result results[BLE_MAX_SCAN_RESULTS] = {0};
112
         int n = ble_get_scan_results(results, BLE_MAX_SCAN_RESULTS);
116
         int n = ble_get_scan_results(results, BLE_MAX_SCAN_RESULTS);
192
         }
196
         }
193
     } else if (strcmp(line, "bat") == 0) {
197
     } else if (strcmp(line, "bat") == 0) {
194
         draw_battery_indicator();
198
         draw_battery_indicator();
199
+    } else if (strcmp(line, "vrct") == 0) {
200
+        int16_t r = volcano_get_current_temp();
201
+        println("volcano current temp: %.1f", r / 10.0);
202
+    } else if (strcmp(line, "vrtt") == 0) {
203
+        int16_t r = volcano_get_target_temp();
204
+        println("volcano target temp: %.1f", r / 10.0);
195
     } else {
205
     } else {
196
         println("unknown command \"%s\"", line);
206
         println("unknown command \"%s\"", line);
197
     }
207
     }

+ 1
- 1
src/main.c View File

78
 
78
 
79
     // wait for BLE stack to be ready before using it
79
     // wait for BLE stack to be ready before using it
80
     while (!ble_is_ready()) {
80
     while (!ble_is_ready()) {
81
-        sleep_ms(10);
81
+        sleep_ms(1);
82
     }
82
     }
83
 
83
 
84
     debug("starting app");
84
     debug("starting app");

+ 81
- 0
src/volcano.c View File

1
+/*
2
+ * volcano.c
3
+ *
4
+ * Copyright (c) 2023 Thomas Buck (thomas@xythobuz.de)
5
+ *
6
+ * This program is free software: you can redistribute it and/or modify
7
+ * it under the terms of the GNU General Public License as published by
8
+ * the Free Software Foundation, either version 3 of the License, or
9
+ * (at your option) any later version.
10
+ *
11
+ * This program is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
+ * GNU General Public License for more details.
15
+ *
16
+ * See <http://www.gnu.org/licenses/>.
17
+ */
18
+
19
+#include "config.h"
20
+#include "log.h"
21
+#include "util.h"
22
+#include "ble.h"
23
+#include "volcano.h"
24
+
25
+// Volcano UUIDs are always the same, except for the 4th byte
26
+
27
+#define UUID_CURRENT_TEMP 0x01
28
+#define UUID_TARGET_TEMP  0x03
29
+#define UUID_HEATER_ON    0x0F
30
+#define UUID_HEATER_OFF   0x10
31
+#define UUID_PUMP_ON      0x13
32
+#define UUID_PUMP_OFF     0x14
33
+
34
+// "101100FF-5354-4f52-5a26-4249434b454c"
35
+static uint8_t uuid_base[16] = {
36
+    0x10, 0x11, 0x00, 0xFF, 0x53, 0x54, 0x4f, 0x52,
37
+    0x5a, 0x26, 0x42, 0x49, 0x43, 0x4b, 0x45, 0x4c,
38
+};
39
+
40
+int16_t volcano_get_current_temp(void) {
41
+    uuid_base[3] = UUID_CURRENT_TEMP;
42
+
43
+    uint8_t buff[4];
44
+    int32_t r = ble_read(uuid_base, buff, 4);
45
+    if (r != 4) {
46
+        debug("ble_read unexpected value %ld", r);
47
+        return -1;
48
+    }
49
+
50
+    uint32_t *v = (uint32_t *)buff;
51
+    return *v;
52
+}
53
+
54
+int16_t volcano_get_target_temp(void) {
55
+    uuid_base[3] = UUID_TARGET_TEMP;
56
+
57
+    uint8_t buff[4];
58
+    int32_t r = ble_read(uuid_base, buff, 4);
59
+    if (r != 4) {
60
+        debug("ble_read unexpected value %ld", r);
61
+        return -1;
62
+    }
63
+
64
+    uint32_t *v = (uint32_t *)buff;
65
+    return *v;
66
+}
67
+
68
+int8_t volcano_set_target_temp(uint16_t value) {
69
+    uuid_base[3] = UUID_TARGET_TEMP;
70
+
71
+    uint8_t buff[4];
72
+    uint32_t *v = (uint32_t *)buff;
73
+    *v = value;
74
+
75
+    int32_t r = ble_write(uuid_base, buff, 4);
76
+    if (r != 4) {
77
+        debug("ble_write unexpected value %ld", r);
78
+        return -1;
79
+    }
80
+    return 0;
81
+}

Loading…
Cancel
Save