seos_service.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. #include "seos_service.h"
  2. #include "app_common.h"
  3. #include <ble/ble.h>
  4. #include <furi_ble/event_dispatcher.h>
  5. #include <furi_ble/gatt.h>
  6. #include <furi.h>
  7. #include "seos_service_uuid.inc"
  8. #include <stdint.h>
  9. #define TAG "BtSeosSvc"
  10. typedef enum {
  11. SeosSvcGattCharacteristicRx = 0,
  12. SeosSvcGattCharacteristicTx,
  13. SeosSvcGattCharacteristicFlowCtrl,
  14. SeosSvcGattCharacteristicStatus,
  15. SeosSvcGattCharacteristicCount,
  16. } SeosSvcGattCharacteristicId;
  17. static const BleGattCharacteristicParams ble_svc_seos_chars[SeosSvcGattCharacteristicCount] = {
  18. [SeosSvcGattCharacteristicRx] =
  19. {.name = "SEOS",
  20. .data_prop_type = FlipperGattCharacteristicDataFixed,
  21. .data.fixed.length = BLE_SVC_SEOS_DATA_LEN_MAX,
  22. .uuid.Char_UUID_128 = BLE_SVC_SEOS_CHAR_UUID,
  23. .uuid_type = UUID_TYPE_128,
  24. .char_properties = CHAR_PROP_WRITE_WITHOUT_RESP | CHAR_PROP_NOTIFY,
  25. .security_permissions = ATTR_PERMISSION_NONE,
  26. .gatt_evt_mask = GATT_NOTIFY_ATTRIBUTE_WRITE,
  27. .is_variable = CHAR_VALUE_LEN_VARIABLE},
  28. };
  29. struct BleServiceSeos {
  30. uint16_t svc_handle;
  31. BleGattCharacteristicInstance chars[SeosSvcGattCharacteristicCount];
  32. FuriMutex* buff_size_mtx;
  33. uint32_t buff_size;
  34. uint16_t bytes_ready_to_receive;
  35. SeosServiceEventCallback callback;
  36. void* context;
  37. GapSvcEventHandler* event_handler;
  38. };
  39. static BleEventAckStatus ble_svc_seos_event_handler(void* event, void* context) {
  40. BleServiceSeos* seos_svc = (BleServiceSeos*)context;
  41. BleEventAckStatus ret = BleEventNotAck;
  42. hci_event_pckt* event_pckt = (hci_event_pckt*)(((hci_uart_pckt*)event)->data);
  43. evt_blecore_aci* blecore_evt = (evt_blecore_aci*)event_pckt->data;
  44. aci_gatt_attribute_modified_event_rp0* attribute_modified;
  45. if(event_pckt->evt == HCI_VENDOR_SPECIFIC_DEBUG_EVT_CODE) {
  46. if(blecore_evt->ecode == ACI_GATT_ATTRIBUTE_MODIFIED_VSEVT_CODE) {
  47. attribute_modified = (aci_gatt_attribute_modified_event_rp0*)blecore_evt->data;
  48. if(attribute_modified->Attr_Handle ==
  49. seos_svc->chars[SeosSvcGattCharacteristicRx].handle + 2) {
  50. // Descriptor handle
  51. ret = BleEventAckFlowEnable;
  52. FURI_LOG_D(TAG, "RX descriptor event");
  53. } else if(
  54. attribute_modified->Attr_Handle ==
  55. seos_svc->chars[SeosSvcGattCharacteristicRx].handle + 1) {
  56. FURI_LOG_D(TAG, "Received %d bytes", attribute_modified->Attr_Data_Length);
  57. if(seos_svc->callback) {
  58. furi_check(
  59. furi_mutex_acquire(seos_svc->buff_size_mtx, FuriWaitForever) ==
  60. FuriStatusOk);
  61. if(attribute_modified->Attr_Data_Length > seos_svc->bytes_ready_to_receive) {
  62. FURI_LOG_W(
  63. TAG,
  64. "Received %d, while was ready to receive %d bytes. Can lead to buffer overflow!",
  65. attribute_modified->Attr_Data_Length,
  66. seos_svc->bytes_ready_to_receive);
  67. }
  68. seos_svc->bytes_ready_to_receive -= MIN(
  69. seos_svc->bytes_ready_to_receive, attribute_modified->Attr_Data_Length);
  70. SeosServiceEvent event = {
  71. .event = SeosServiceEventTypeDataReceived,
  72. .data = {
  73. .buffer = attribute_modified->Attr_Data,
  74. .size = attribute_modified->Attr_Data_Length,
  75. }};
  76. uint32_t buff_free_size = seos_svc->callback(event, seos_svc->context);
  77. FURI_LOG_D(TAG, "Available buff size: %ld", buff_free_size);
  78. furi_check(furi_mutex_release(seos_svc->buff_size_mtx) == FuriStatusOk);
  79. }
  80. ret = BleEventAckFlowEnable;
  81. } else if(
  82. attribute_modified->Attr_Handle ==
  83. seos_svc->chars[SeosSvcGattCharacteristicStatus].handle + 1) {
  84. bool* rpc_status = (bool*)attribute_modified->Attr_Data;
  85. if(!*rpc_status) {
  86. if(seos_svc->callback) {
  87. SeosServiceEvent event = {
  88. .event = SeosServiceEventTypesBleResetRequest,
  89. };
  90. seos_svc->callback(event, seos_svc->context);
  91. }
  92. }
  93. }
  94. } else if(blecore_evt->ecode == ACI_GATT_SERVER_CONFIRMATION_VSEVT_CODE) {
  95. FURI_LOG_T(TAG, "Ack received");
  96. if(seos_svc->callback) {
  97. SeosServiceEvent event = {
  98. .event = SeosServiceEventTypeDataSent,
  99. };
  100. seos_svc->callback(event, seos_svc->context);
  101. }
  102. ret = BleEventAckFlowEnable;
  103. }
  104. }
  105. return ret;
  106. }
  107. typedef enum {
  108. SeosServiceRpcStatusNotActive = 0UL,
  109. SeosServiceRpcStatusActive = 1UL,
  110. } SeosServiceRpcStatus;
  111. static void
  112. ble_svc_seos_update_rpc_char(BleServiceSeos* seos_svc, SeosServiceRpcStatus status) {
  113. ble_gatt_characteristic_update(
  114. seos_svc->svc_handle, &seos_svc->chars[SeosSvcGattCharacteristicStatus], &status);
  115. }
  116. BleServiceSeos* ble_svc_seos_start(void) {
  117. BleServiceSeos* seos_svc = malloc(sizeof(BleServiceSeos));
  118. seos_svc->event_handler =
  119. ble_event_dispatcher_register_svc_handler(ble_svc_seos_event_handler, seos_svc);
  120. if(!ble_gatt_service_add(
  121. UUID_TYPE_128, &service_uuid, PRIMARY_SERVICE, 12, &seos_svc->svc_handle)) {
  122. free(seos_svc);
  123. return NULL;
  124. }
  125. for(uint8_t i = 0; i < SeosSvcGattCharacteristicCount; i++) {
  126. ble_gatt_characteristic_init(
  127. seos_svc->svc_handle, &ble_svc_seos_chars[i], &seos_svc->chars[i]);
  128. }
  129. ble_svc_seos_update_rpc_char(seos_svc, SeosServiceRpcStatusNotActive);
  130. seos_svc->buff_size_mtx = furi_mutex_alloc(FuriMutexTypeNormal);
  131. return seos_svc;
  132. }
  133. void ble_svc_seos_set_callbacks(
  134. BleServiceSeos* seos_svc,
  135. uint16_t buff_size,
  136. SeosServiceEventCallback callback,
  137. void* context) {
  138. furi_check(seos_svc);
  139. seos_svc->callback = callback;
  140. seos_svc->context = context;
  141. seos_svc->buff_size = buff_size;
  142. seos_svc->bytes_ready_to_receive = buff_size;
  143. uint32_t buff_size_reversed = REVERSE_BYTES_U32(seos_svc->buff_size);
  144. ble_gatt_characteristic_update(
  145. seos_svc->svc_handle,
  146. &seos_svc->chars[SeosSvcGattCharacteristicFlowCtrl],
  147. &buff_size_reversed);
  148. }
  149. void ble_svc_seos_notify_buffer_is_empty(BleServiceSeos* seos_svc) {
  150. furi_check(seos_svc);
  151. furi_check(seos_svc->buff_size_mtx);
  152. furi_check(furi_mutex_acquire(seos_svc->buff_size_mtx, FuriWaitForever) == FuriStatusOk);
  153. if(seos_svc->bytes_ready_to_receive == 0) {
  154. FURI_LOG_D(TAG, "Buffer is empty. Notifying client");
  155. seos_svc->bytes_ready_to_receive = seos_svc->buff_size;
  156. uint32_t buff_size_reversed = REVERSE_BYTES_U32(seos_svc->buff_size);
  157. ble_gatt_characteristic_update(
  158. seos_svc->svc_handle,
  159. &seos_svc->chars[SeosSvcGattCharacteristicFlowCtrl],
  160. &buff_size_reversed);
  161. }
  162. furi_check(furi_mutex_release(seos_svc->buff_size_mtx) == FuriStatusOk);
  163. }
  164. void ble_svc_seos_stop(BleServiceSeos* seos_svc) {
  165. furi_check(seos_svc);
  166. ble_event_dispatcher_unregister_svc_handler(seos_svc->event_handler);
  167. for(uint8_t i = 0; i < SeosSvcGattCharacteristicCount; i++) {
  168. ble_gatt_characteristic_delete(seos_svc->svc_handle, &seos_svc->chars[i]);
  169. }
  170. ble_gatt_service_delete(seos_svc->svc_handle);
  171. furi_mutex_free(seos_svc->buff_size_mtx);
  172. free(seos_svc);
  173. }
  174. bool ble_svc_seos_update_tx(BleServiceSeos* seos_svc, uint8_t* data, uint16_t data_len) {
  175. if(data_len > BLE_SVC_SEOS_DATA_LEN_MAX) {
  176. return false;
  177. }
  178. for(uint16_t remained = data_len; remained > 0;) {
  179. uint8_t value_len = MIN(BLE_SVC_SEOS_CHAR_VALUE_LEN_MAX, remained);
  180. uint16_t value_offset = data_len - remained;
  181. remained -= value_len;
  182. tBleStatus result = aci_gatt_update_char_value_ext(
  183. 0,
  184. seos_svc->svc_handle,
  185. seos_svc->chars[SeosSvcGattCharacteristicTx].handle,
  186. remained ? 0x00 : 0x02,
  187. data_len,
  188. value_offset,
  189. value_len,
  190. data + value_offset);
  191. if(result) {
  192. FURI_LOG_E(TAG, "Failed updating TX characteristic: %d", result);
  193. return false;
  194. }
  195. }
  196. return true;
  197. }
  198. void ble_svc_seos_set_rpc_active(BleServiceSeos* seos_svc, bool active) {
  199. furi_check(seos_svc);
  200. ble_svc_seos_update_rpc_char(
  201. seos_svc, active ? SeosServiceRpcStatusActive : SeosServiceRpcStatusNotActive);
  202. }