Browse Source

basic ble notification support

Thomas Buck 1 year ago
parent
commit
944f87e56b
2 changed files with 167 additions and 1 deletions
  1. 5
    0
      include/ble.h
  2. 162
    1
      src/ble.c

+ 5
- 0
include/ble.h View File

@@ -60,4 +60,9 @@ int32_t ble_read(const uint8_t *characteristic, uint8_t *buff, uint16_t buff_len
60 60
 int8_t ble_write(const uint8_t *service, const uint8_t *characteristic,
61 61
                  const uint8_t *buff, uint16_t buff_len);
62 62
 
63
+int8_t ble_notification_disable(const uint8_t *service, const uint8_t *characteristic);
64
+int8_t ble_notification_enable(const uint8_t *service, const uint8_t *characteristic);
65
+bool ble_notification_ready(void);
66
+uint16_t ble_notification_get(uint8_t *buff, uint16_t buff_len);
67
+
63 68
 #endif // __BLE_H__

+ 162
- 1
src/ble.c View File

@@ -32,6 +32,7 @@
32 32
 #define BLE_SRVC_TIMEOUT_MS (3 * 500)
33 33
 #define BLE_CHAR_TIMEOUT_MS (3 * 2000)
34 34
 #define BLE_WRTE_TIMEOUT_MS (3 * 500)
35
+#define BLE_NOTY_TIMEOUT_MS (3 * 500)
35 36
 #define BLE_MAX_SCAN_AGE_MS (10 * 1000)
36 37
 #define BLE_MAX_SERVICES 8
37 38
 #define BLE_MAX_CHARACTERISTICS 8
@@ -48,11 +49,14 @@ enum ble_state {
48 49
     TC_W4_CHARACTERISTIC,
49 50
     TC_W4_WRITE,
50 51
     TC_WRITE_COMPLETE,
52
+    TC_W4_NOTIFY_ENABLE,
53
+    TC_NOTIFY_ENABLED,
51 54
 };
52 55
 
53 56
 struct ble_characteristic {
54 57
     bool set;
55 58
     gatt_client_characteristic_t c;
59
+    gatt_client_notification_t n;
56 60
 };
57 61
 
58 62
 struct ble_service {
@@ -319,6 +323,11 @@ static void hci_event_handler(uint8_t packet_type, uint16_t channel, uint8_t *pa
319 323
             state = TC_WRITE_COMPLETE;
320 324
             break;
321 325
 
326
+        case TC_W4_NOTIFY_ENABLE:
327
+            //debug("notify enable complete");
328
+            state = TC_NOTIFY_ENABLED;
329
+            break;
330
+
322 331
         default:
323 332
             debug("gatt query complete in invalid state %d", state);
324 333
             break;
@@ -326,6 +335,22 @@ static void hci_event_handler(uint8_t packet_type, uint16_t channel, uint8_t *pa
326 335
         break;
327 336
     }
328 337
 
338
+    case GATT_EVENT_NOTIFICATION: {
339
+        if ((state != TC_READY) && (state != TC_WRITE_COMPLETE)) {
340
+            debug("gatt notification in invalid state %d", state);
341
+            return;
342
+        }
343
+
344
+        uint16_t value_length = gatt_event_notification_get_value_length(packet);
345
+        const uint8_t *value = gatt_event_notification_get_value(packet);
346
+        if ((read_len + value_length) <= BLE_MAX_VALUE_LEN) {
347
+            memcpy(data_buff + read_len, value, value_length);
348
+            read_len += value_length;
349
+        }
350
+
351
+        break;
352
+    }
353
+
329 354
     default:
330 355
         //debug("unexpected event 0x%02X", hci_event_packet_get_type(packet));
331 356
         break;
@@ -572,8 +597,11 @@ int32_t ble_read(const uint8_t *characteristic, uint8_t *buff, uint16_t buff_len
572 597
 
573 598
     memcpy(buff, data_buff, read_len);
574 599
 
600
+    uint16_t tmp = read_len;
601
+    read_len = 0;
602
+
575 603
     cyw43_thread_exit();
576
-    return read_len;
604
+    return tmp;
577 605
 }
578 606
 
579 607
 static int discover_service(const uint8_t *service) {
@@ -813,3 +841,136 @@ int8_t ble_discover(const uint8_t *service, const uint8_t *characteristic) {
813 841
     cyw43_thread_exit();
814 842
     return 0;
815 843
 }
844
+
845
+int8_t ble_notification_disable(const uint8_t *service, const uint8_t *characteristic) {
846
+    cyw43_thread_enter();
847
+
848
+    if (state != TC_READY) {
849
+        cyw43_thread_exit();
850
+        debug("invalid state for notify (%d)", state);
851
+        return -1;
852
+    }
853
+
854
+    int srvc = discover_service(service);
855
+    if (srvc < 0) {
856
+        debug("error discovering service (%d)", srvc);
857
+        return srvc;
858
+    }
859
+
860
+    int ch = discover_characteristic(srvc, characteristic);
861
+    if (ch < 0) {
862
+        debug("error discovering characteristic (%d)", ch);
863
+        return ch;
864
+    }
865
+
866
+    gatt_client_stop_listening_for_characteristic_value_updates(&services[srvc].chars[ch].n);
867
+
868
+    cyw43_thread_exit();
869
+    return 0;
870
+}
871
+
872
+int8_t ble_notification_enable(const uint8_t *service, const uint8_t *characteristic) {
873
+    cyw43_thread_enter();
874
+
875
+    if (state != TC_READY) {
876
+        cyw43_thread_exit();
877
+        debug("invalid state for notify (%d)", state);
878
+        return -1;
879
+    }
880
+
881
+    int srvc = discover_service(service);
882
+    if (srvc < 0) {
883
+        debug("error discovering service (%d)", srvc);
884
+        return srvc;
885
+    }
886
+
887
+    int ch = discover_characteristic(srvc, characteristic);
888
+    if (ch < 0) {
889
+        debug("error discovering characteristic (%d)", ch);
890
+        return ch;
891
+    }
892
+
893
+    gatt_client_listen_for_characteristic_value_updates(&services[srvc].chars[ch].n,
894
+                                                        hci_event_handler,
895
+                                                        connection_handle,
896
+                                                        &services[srvc].chars[ch].c);
897
+
898
+    gatt_client_write_client_characteristic_configuration(hci_event_handler,
899
+                                                          connection_handle,
900
+                                                          &services[srvc].chars[ch].c,
901
+                                                          GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION);
902
+
903
+    state = TC_W4_NOTIFY_ENABLE;
904
+    cyw43_thread_exit();
905
+
906
+    uint32_t start_time = to_ms_since_boot(get_absolute_time());
907
+    while (1) {
908
+        sleep_ms(1);
909
+        main_loop_hw();
910
+
911
+        uint32_t now = to_ms_since_boot(get_absolute_time());
912
+        if ((now - start_time) >= BLE_NOTY_TIMEOUT_MS) {
913
+            debug("timeout waiting for notify enable");
914
+            cyw43_thread_enter();
915
+            state = TC_READY;
916
+            cyw43_thread_exit();
917
+            return -6;
918
+        }
919
+
920
+        cyw43_thread_enter();
921
+        enum ble_state state_cached = state;
922
+        cyw43_thread_exit();
923
+
924
+        if ((state_cached == TC_NOTIFY_ENABLED) || (state_cached == TC_READY)) {
925
+            break;
926
+        }
927
+    }
928
+
929
+    cyw43_thread_enter();
930
+
931
+    int8_t ret = (state == TC_NOTIFY_ENABLED) ? 0 : -7;
932
+    state = TC_READY;
933
+
934
+    cyw43_thread_exit();
935
+    return ret;
936
+}
937
+
938
+bool ble_notification_ready(void) {
939
+    cyw43_thread_enter();
940
+
941
+    if (state != TC_READY) {
942
+        cyw43_thread_exit();
943
+        debug("invalid state for notify (%d)", state);
944
+        return -1;
945
+    }
946
+
947
+    uint16_t tmp = read_len;
948
+
949
+    cyw43_thread_exit();
950
+    return (tmp > 0);
951
+
952
+}
953
+
954
+uint16_t ble_notification_get(uint8_t *buff, uint16_t buff_len) {
955
+    cyw43_thread_enter();
956
+
957
+    if (state != TC_READY) {
958
+        cyw43_thread_exit();
959
+        debug("invalid state for notify (%d)", state);
960
+        return -1;
961
+    }
962
+
963
+    if (read_len > buff_len) {
964
+        debug("buffer too short (%d < %d)", buff_len, read_len);
965
+        cyw43_thread_exit();
966
+        return -2;
967
+    }
968
+
969
+    memcpy(buff, data_buff, read_len);
970
+
971
+    uint16_t tmp = read_len;
972
+    read_len = 0;
973
+
974
+    cyw43_thread_exit();
975
+    return tmp;
976
+}

Loading…
Cancel
Save