seos_service.c 8.7 KB

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