|
@@ -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
|
+}
|