seos_service.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. #include "seos_service.h"
  2. #include "headers/app_common.h"
  3. #include <furi_ble/event_dispatcher.h>
  4. #include <furi_ble/gatt.h>
  5. #include "headers/ble_vs_codes.h"
  6. #include "headers/ble_gatt_aci.h"
  7. #include <furi.h>
  8. #include "seos_service_uuid.inc"
  9. #include <stdint.h>
  10. #define TAG "BtSeosSvc"
  11. static uint8_t select[] =
  12. {0xc0, 0x00, 0xa4, 0x04, 0x00, 0x0a, 0xa0, 0x00, 0x00, 0x04, 0x40, 0x00, 0x01, 0x01, 0x00, 0x01};
  13. typedef enum {
  14. SeosSvcGattCharacteristicRxTx = 0,
  15. SeosSvcGattCharacteristicCount,
  16. } SeosSvcGattCharacteristicId;
  17. typedef struct {
  18. const void* data_ptr;
  19. uint16_t data_len;
  20. } SeosSvcDataWrapper;
  21. static bool
  22. ble_svc_seos_data_callback(const void* context, const uint8_t** data, uint16_t* data_len) {
  23. FURI_LOG_D(TAG, "ble_svc_seos_data_callback");
  24. const SeosSvcDataWrapper* report_data = context;
  25. if(data) {
  26. *data = report_data->data_ptr;
  27. *data_len = report_data->data_len;
  28. } else {
  29. *data_len = BLE_SVC_SEOS_DATA_LEN_MAX;
  30. }
  31. return false;
  32. }
  33. static BleGattCharacteristicParams ble_svc_seos_chars[SeosSvcGattCharacteristicCount] = {
  34. [SeosSvcGattCharacteristicRxTx] =
  35. {.name = "SEOS",
  36. .data_prop_type = FlipperGattCharacteristicDataCallback,
  37. .data.callback.fn = ble_svc_seos_data_callback,
  38. .data.callback.context = NULL,
  39. .uuid.Char_UUID_128 = BLE_SVC_SEOS_READER_CHAR_UUID, // changed before init
  40. .uuid_type = UUID_TYPE_128,
  41. .char_properties = CHAR_PROP_WRITE_WITHOUT_RESP | CHAR_PROP_NOTIFY,
  42. .security_permissions = ATTR_PERMISSION_NONE,
  43. .gatt_evt_mask = GATT_NOTIFY_ATTRIBUTE_WRITE,
  44. .is_variable = CHAR_VALUE_LEN_VARIABLE},
  45. };
  46. struct BleServiceSeos {
  47. uint16_t svc_handle;
  48. BleGattCharacteristicInstance chars[SeosSvcGattCharacteristicCount];
  49. FuriMutex* buff_size_mtx;
  50. uint32_t buff_size;
  51. uint16_t bytes_ready_to_receive;
  52. SeosServiceEventCallback callback;
  53. void* context;
  54. GapSvcEventHandler* event_handler;
  55. FlowMode mode;
  56. };
  57. static BleEventAckStatus ble_svc_seos_event_handler(void* event, void* context) {
  58. BleServiceSeos* seos_svc = (BleServiceSeos*)context;
  59. BleEventAckStatus ret = BleEventNotAck;
  60. hci_event_pckt* event_pckt = (hci_event_pckt*)(((hci_uart_pckt*)event)->data);
  61. evt_blecore_aci* blecore_evt = (evt_blecore_aci*)event_pckt->data;
  62. aci_gatt_attribute_modified_event_rp0* attribute_modified;
  63. if(event_pckt->evt == HCI_LE_META_EVT_CODE) {
  64. } else if(event_pckt->evt == HCI_DISCONNECTION_COMPLETE_EVT_CODE) {
  65. } else if(event_pckt->evt == HCI_VENDOR_SPECIFIC_DEBUG_EVT_CODE) {
  66. if(blecore_evt->ecode == ACI_GATT_ATTRIBUTE_MODIFIED_VSEVT_CODE) {
  67. attribute_modified = (aci_gatt_attribute_modified_event_rp0*)blecore_evt->data;
  68. if(attribute_modified->Attr_Handle ==
  69. seos_svc->chars[SeosSvcGattCharacteristicRxTx].handle + 2) {
  70. // Descriptor handle
  71. ret = BleEventAckFlowEnable;
  72. FURI_LOG_D(TAG, "Descriptor event %d bytes", attribute_modified->Attr_Data_Length);
  73. if(attribute_modified->Attr_Data_Length == 2) {
  74. uint16_t* value = (uint16_t*)attribute_modified->Attr_Data;
  75. if(*value == 1) { // ENABLE_NOTIFICATION_VALUE)
  76. if(seos_svc->mode == FLOW_READER) {
  77. SeosSvcDataWrapper report_data = {
  78. .data_ptr = select, .data_len = sizeof(select)};
  79. ble_gatt_characteristic_update(
  80. seos_svc->svc_handle,
  81. &seos_svc->chars[SeosSvcGattCharacteristicRxTx],
  82. &report_data);
  83. } else if(seos_svc->mode == FLOW_CRED) {
  84. FURI_LOG_D(TAG, "No action for FLOW_CRED after subscribe");
  85. }
  86. }
  87. }
  88. } else if(
  89. attribute_modified->Attr_Handle ==
  90. seos_svc->chars[SeosSvcGattCharacteristicRxTx].handle + 1) {
  91. FURI_LOG_D(TAG, "Received %d bytes", attribute_modified->Attr_Data_Length);
  92. if(seos_svc->callback) {
  93. furi_check(
  94. furi_mutex_acquire(seos_svc->buff_size_mtx, FuriWaitForever) ==
  95. FuriStatusOk);
  96. SeosServiceEvent event = {
  97. .event = SeosServiceEventTypeDataReceived,
  98. .data = {
  99. .buffer = attribute_modified->Attr_Data,
  100. .size = attribute_modified->Attr_Data_Length,
  101. }};
  102. uint32_t buff_free_size = seos_svc->callback(event, seos_svc->context);
  103. FURI_LOG_D(TAG, "Available buff size: %ld", buff_free_size);
  104. furi_check(furi_mutex_release(seos_svc->buff_size_mtx) == FuriStatusOk);
  105. } else {
  106. FURI_LOG_W(TAG, "No seos_cvs->callback defined");
  107. }
  108. ret = BleEventAckFlowEnable;
  109. }
  110. } else if(blecore_evt->ecode == ACI_GATT_SERVER_CONFIRMATION_VSEVT_CODE) {
  111. FURI_LOG_T(TAG, "Ack received");
  112. if(seos_svc->callback) {
  113. SeosServiceEvent event = {
  114. .event = SeosServiceEventTypeDataSent,
  115. };
  116. seos_svc->callback(event, seos_svc->context);
  117. }
  118. ret = BleEventAckFlowEnable;
  119. } else {
  120. FURI_LOG_D(
  121. TAG,
  122. "ble_svc_seos_event_handler unhandled blecore_evt->ecode %d",
  123. blecore_evt->ecode);
  124. }
  125. } else {
  126. FURI_LOG_D(
  127. TAG, "ble_svc_seos_event_handler unhandled event_pckt->evt %d", event_pckt->evt);
  128. }
  129. return ret;
  130. }
  131. BleServiceSeos* ble_svc_seos_start(FlowMode mode) {
  132. BleServiceSeos* seos_svc = malloc(sizeof(BleServiceSeos));
  133. seos_svc->mode = mode;
  134. seos_svc->event_handler =
  135. ble_event_dispatcher_register_svc_handler(ble_svc_seos_event_handler, seos_svc);
  136. if(mode == FLOW_READER) {
  137. if(!ble_gatt_service_add(
  138. UUID_TYPE_128, &reader_service_uuid, PRIMARY_SERVICE, 12, &seos_svc->svc_handle)) {
  139. free(seos_svc);
  140. return NULL;
  141. }
  142. } else if(mode == FLOW_CRED) {
  143. if(!ble_gatt_service_add(
  144. UUID_TYPE_128, &cred_service_uuid, PRIMARY_SERVICE, 12, &seos_svc->svc_handle)) {
  145. free(seos_svc);
  146. return NULL;
  147. }
  148. }
  149. for(uint8_t i = 0; i < SeosSvcGattCharacteristicCount; i++) {
  150. if(i == SeosSvcGattCharacteristicRxTx) {
  151. if(mode == FLOW_READER) {
  152. uint8_t uuid[] = BLE_SVC_SEOS_READER_CHAR_UUID;
  153. memcpy(
  154. ble_svc_seos_chars[SeosSvcGattCharacteristicRxTx].uuid.Char_UUID_128,
  155. uuid,
  156. sizeof(uuid));
  157. } else if(mode == FLOW_CRED) {
  158. uint8_t uuid[] = BLE_SVC_SEOS_CRED_CHAR_UUID;
  159. memcpy(
  160. ble_svc_seos_chars[SeosSvcGattCharacteristicRxTx].uuid.Char_UUID_128,
  161. uuid,
  162. sizeof(uuid));
  163. }
  164. ble_gatt_characteristic_init(
  165. seos_svc->svc_handle, &ble_svc_seos_chars[i], &seos_svc->chars[i]);
  166. }
  167. }
  168. seos_svc->buff_size_mtx = furi_mutex_alloc(FuriMutexTypeNormal);
  169. return seos_svc;
  170. }
  171. void ble_svc_seos_set_callbacks(
  172. BleServiceSeos* seos_svc,
  173. uint16_t buff_size,
  174. SeosServiceEventCallback callback,
  175. void* context) {
  176. furi_check(seos_svc);
  177. seos_svc->callback = callback;
  178. seos_svc->context = context;
  179. seos_svc->buff_size = buff_size;
  180. seos_svc->bytes_ready_to_receive = buff_size;
  181. }
  182. void ble_svc_seos_stop(BleServiceSeos* seos_svc) {
  183. furi_check(seos_svc);
  184. ble_event_dispatcher_unregister_svc_handler(seos_svc->event_handler);
  185. for(uint8_t i = 0; i < SeosSvcGattCharacteristicCount; i++) {
  186. ble_gatt_characteristic_delete(seos_svc->svc_handle, &seos_svc->chars[i]);
  187. }
  188. ble_gatt_service_delete(seos_svc->svc_handle);
  189. furi_mutex_free(seos_svc->buff_size_mtx);
  190. free(seos_svc);
  191. }
  192. bool ble_svc_seos_update_tx(BleServiceSeos* seos_svc, uint8_t* data, uint16_t data_len) {
  193. if(data_len > BLE_SVC_SEOS_DATA_LEN_MAX) {
  194. return false;
  195. }
  196. SeosSvcDataWrapper report_data = {.data_ptr = data, .data_len = data_len};
  197. ble_gatt_characteristic_update(
  198. seos_svc->svc_handle, &seos_svc->chars[SeosSvcGattCharacteristicRxTx], &report_data);
  199. return true;
  200. }