seos_service.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. #include "seos_service.h"
  2. #include "app_common.h"
  3. #include <furi_ble/event_dispatcher.h>
  4. #include <furi_ble/gatt.h>
  5. #include "ble_vs_codes.h"
  6. #include "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. };
  56. static BleEventAckStatus ble_svc_seos_event_handler(void* event, void* context) {
  57. BleServiceSeos* seos_svc = (BleServiceSeos*)context;
  58. BleEventAckStatus ret = BleEventNotAck;
  59. hci_event_pckt* event_pckt = (hci_event_pckt*)(((hci_uart_pckt*)event)->data);
  60. evt_blecore_aci* blecore_evt = (evt_blecore_aci*)event_pckt->data;
  61. aci_gatt_attribute_modified_event_rp0* attribute_modified;
  62. if(event_pckt->evt == HCI_LE_META_EVT_CODE) {
  63. } else if(event_pckt->evt == HCI_DISCONNECTION_COMPLETE_EVT_CODE) {
  64. } else if(event_pckt->evt == HCI_VENDOR_SPECIFIC_DEBUG_EVT_CODE) {
  65. if(blecore_evt->ecode == ACI_GATT_ATTRIBUTE_MODIFIED_VSEVT_CODE) {
  66. attribute_modified = (aci_gatt_attribute_modified_event_rp0*)blecore_evt->data;
  67. if(attribute_modified->Attr_Handle ==
  68. seos_svc->chars[SeosSvcGattCharacteristicRxTx].handle + 2) {
  69. // Descriptor handle
  70. ret = BleEventAckFlowEnable;
  71. if(attribute_modified->Attr_Data_Length == 2) {
  72. uint16_t* value = (uint16_t*)attribute_modified->Attr_Data;
  73. if(*value == 1) { // ENABLE_NOTIFICATION_VALUE)
  74. SeosSvcDataWrapper report_data = {
  75. .data_ptr = select, .data_len = sizeof(select)};
  76. ble_gatt_characteristic_update(
  77. seos_svc->svc_handle,
  78. &seos_svc->chars[SeosSvcGattCharacteristicRxTx],
  79. &report_data);
  80. }
  81. } else {
  82. FURI_LOG_D(
  83. TAG, "descriptor event %d bytes", attribute_modified->Attr_Data_Length);
  84. }
  85. } else if(
  86. attribute_modified->Attr_Handle ==
  87. seos_svc->chars[SeosSvcGattCharacteristicRxTx].handle + 1) {
  88. FURI_LOG_D(TAG, "Received %d bytes", attribute_modified->Attr_Data_Length);
  89. if(seos_svc->callback) {
  90. furi_check(
  91. furi_mutex_acquire(seos_svc->buff_size_mtx, FuriWaitForever) ==
  92. FuriStatusOk);
  93. SeosServiceEvent event = {
  94. .event = SeosServiceEventTypeDataReceived,
  95. .data = {
  96. .buffer = attribute_modified->Attr_Data,
  97. .size = attribute_modified->Attr_Data_Length,
  98. }};
  99. uint32_t buff_free_size = seos_svc->callback(event, seos_svc->context);
  100. FURI_LOG_D(TAG, "Available buff size: %ld", buff_free_size);
  101. furi_check(furi_mutex_release(seos_svc->buff_size_mtx) == FuriStatusOk);
  102. } else {
  103. FURI_LOG_W(TAG, "No seos_cvs->callback defined");
  104. }
  105. ret = BleEventAckFlowEnable;
  106. }
  107. } else if(blecore_evt->ecode == ACI_GATT_SERVER_CONFIRMATION_VSEVT_CODE) {
  108. FURI_LOG_T(TAG, "Ack received");
  109. if(seos_svc->callback) {
  110. SeosServiceEvent event = {
  111. .event = SeosServiceEventTypeDataSent,
  112. };
  113. seos_svc->callback(event, seos_svc->context);
  114. }
  115. ret = BleEventAckFlowEnable;
  116. } else {
  117. FURI_LOG_D(
  118. TAG,
  119. "ble_svc_seos_event_handler unhandled blecore_evt->ecode %d",
  120. blecore_evt->ecode);
  121. }
  122. } else {
  123. FURI_LOG_D(
  124. TAG, "ble_svc_seos_event_handler unhandled event_pckt->evt %d", event_pckt->evt);
  125. }
  126. return ret;
  127. }
  128. BleServiceSeos* ble_svc_seos_start(FlowMode mode) {
  129. BleServiceSeos* seos_svc = malloc(sizeof(BleServiceSeos));
  130. seos_svc->event_handler =
  131. ble_event_dispatcher_register_svc_handler(ble_svc_seos_event_handler, seos_svc);
  132. if(mode == FLOW_READER) {
  133. if(!ble_gatt_service_add(
  134. UUID_TYPE_128, &reader_service_uuid, PRIMARY_SERVICE, 12, &seos_svc->svc_handle)) {
  135. free(seos_svc);
  136. return NULL;
  137. }
  138. } else if(mode == FLOW_CRED) {
  139. if(!ble_gatt_service_add(
  140. UUID_TYPE_128, &cred_service_uuid, PRIMARY_SERVICE, 12, &seos_svc->svc_handle)) {
  141. free(seos_svc);
  142. return NULL;
  143. }
  144. }
  145. for(uint8_t i = 0; i < SeosSvcGattCharacteristicCount; i++) {
  146. if(i == SeosSvcGattCharacteristicRxTx) {
  147. if(mode == FLOW_READER) {
  148. uint8_t uuid[] = BLE_SVC_SEOS_READER_CHAR_UUID;
  149. memcpy(
  150. ble_svc_seos_chars[SeosSvcGattCharacteristicRxTx].uuid.Char_UUID_128,
  151. uuid,
  152. sizeof(uuid));
  153. } else if(mode == FLOW_CRED) {
  154. uint8_t uuid[] = BLE_SVC_SEOS_CRED_CHAR_UUID;
  155. memcpy(
  156. ble_svc_seos_chars[SeosSvcGattCharacteristicRxTx].uuid.Char_UUID_128,
  157. uuid,
  158. sizeof(uuid));
  159. }
  160. ble_gatt_characteristic_init(
  161. seos_svc->svc_handle, &ble_svc_seos_chars[i], &seos_svc->chars[i]);
  162. }
  163. }
  164. seos_svc->buff_size_mtx = furi_mutex_alloc(FuriMutexTypeNormal);
  165. return seos_svc;
  166. }
  167. void ble_svc_seos_set_callbacks(
  168. BleServiceSeos* seos_svc,
  169. uint16_t buff_size,
  170. SeosServiceEventCallback callback,
  171. void* context) {
  172. furi_check(seos_svc);
  173. seos_svc->callback = callback;
  174. seos_svc->context = context;
  175. seos_svc->buff_size = buff_size;
  176. seos_svc->bytes_ready_to_receive = buff_size;
  177. }
  178. void ble_svc_seos_stop(BleServiceSeos* seos_svc) {
  179. furi_check(seos_svc);
  180. ble_event_dispatcher_unregister_svc_handler(seos_svc->event_handler);
  181. for(uint8_t i = 0; i < SeosSvcGattCharacteristicCount; i++) {
  182. ble_gatt_characteristic_delete(seos_svc->svc_handle, &seos_svc->chars[i]);
  183. }
  184. ble_gatt_service_delete(seos_svc->svc_handle);
  185. furi_mutex_free(seos_svc->buff_size_mtx);
  186. free(seos_svc);
  187. }
  188. bool ble_svc_seos_update_tx(BleServiceSeos* seos_svc, uint8_t* data, uint16_t data_len) {
  189. if(data_len > BLE_SVC_SEOS_DATA_LEN_MAX) {
  190. return false;
  191. }
  192. SeosSvcDataWrapper report_data = {.data_ptr = data, .data_len = data_len};
  193. ble_gatt_characteristic_update(
  194. seos_svc->svc_handle, &seos_svc->chars[SeosSvcGattCharacteristicRxTx], &report_data);
  195. return true;
  196. }