Procházet zdrojové kódy

[FL-2623] Add BLE disconnect request #1686

Co-authored-by: LionZXY <nikita@kulikof.ru>
Co-authored-by: あく <alleteam@gmail.com>
gornekich před 3 roky
rodič
revize
ead9f134f4

+ 16 - 3
applications/services/bt/bt_service/bt.c

@@ -165,6 +165,11 @@ static uint16_t bt_serial_event_callback(SerialServiceEvent event, void* context
         ret = rpc_session_get_available_size(bt->rpc_session);
     } else if(event.event == SerialServiceEventTypeDataSent) {
         furi_event_flag_set(bt->rpc_event, BT_RPC_EVENT_BUFF_SENT);
+    } else if(event.event == SerialServiceEventTypesBleResetRequest) {
+        FURI_LOG_I(TAG, "BLE restart request received");
+        BtMessage message = {.type = BtMessageTypeSetProfile, .data.profile = BtProfileSerial};
+        furi_check(
+            furi_message_queue_put(bt->message_queue, &message, FuriWaitForever) == FuriStatusOk);
     }
     return ret;
 }
@@ -226,6 +231,7 @@ static bool bt_on_gap_event_callback(GapEvent event, void* context) {
                 rpc_session_set_context(bt->rpc_session, bt);
                 furi_hal_bt_serial_set_event_callback(
                     RPC_BUFFER_SIZE, bt_serial_event_callback, bt);
+                furi_hal_bt_serial_set_rpc_status(FuriHalBtSerialRpcStatusActive);
             } else {
                 FURI_LOG_W(TAG, "RPC is busy, failed to open new session");
             }
@@ -241,6 +247,7 @@ static bool bt_on_gap_event_callback(GapEvent event, void* context) {
     } else if(event.type == GapEventTypeDisconnected) {
         if(bt->profile == BtProfileSerial && bt->rpc_session) {
             FURI_LOG_I(TAG, "Close RPC connection");
+            furi_hal_bt_serial_set_rpc_status(FuriHalBtSerialRpcStatusNotActive);
             furi_event_flag_set(bt->rpc_event, BT_RPC_EVENT_DISCONNECTED);
             rpc_session_close(bt->rpc_session);
             furi_hal_bt_serial_set_event_callback(0, NULL, NULL);
@@ -330,14 +337,20 @@ static void bt_change_profile(Bt* bt, BtMessage* message) {
             }
             furi_hal_bt_set_key_storage_change_callback(bt_on_key_storage_change_callback, bt);
             bt->profile = message->data.profile;
-            *message->result = true;
+            if(message->result) {
+                *message->result = true;
+            }
         } else {
             FURI_LOG_E(TAG, "Failed to start Bt App");
-            *message->result = false;
+            if(message->result) {
+                *message->result = false;
+            }
         }
     } else {
         bt_show_warning(bt, "Radio stack doesn't support this app");
-        *message->result = false;
+        if(message->result) {
+            *message->result = false;
+        }
     }
     furi_event_flag_set(bt->api_event, BT_API_UNLOCK_EVENT);
 }

+ 52 - 1
firmware/targets/f7/ble_glue/serial_service.c

@@ -11,6 +11,7 @@ typedef struct {
     uint16_t rx_char_handle;
     uint16_t tx_char_handle;
     uint16_t flow_ctrl_char_handle;
+    uint16_t rpc_status_char_handle;
     FuriMutex* buff_size_mtx;
     uint32_t buff_size;
     uint16_t bytes_ready_to_receive;
@@ -28,6 +29,8 @@ static const uint8_t char_rx_uuid[] =
     {0x00, 0x00, 0xfe, 0x62, 0x8e, 0x22, 0x45, 0x41, 0x9d, 0x4c, 0x21, 0xed, 0xae, 0x82, 0xed, 0x19};
 static const uint8_t flow_ctrl_uuid[] =
     {0x00, 0x00, 0xfe, 0x63, 0x8e, 0x22, 0x45, 0x41, 0x9d, 0x4c, 0x21, 0xed, 0xae, 0x82, 0xed, 0x19};
+static const uint8_t rpc_status_uuid[] =
+    {0x00, 0x00, 0xfe, 0x64, 0x8e, 0x22, 0x45, 0x41, 0x9d, 0x4c, 0x21, 0xed, 0xae, 0x82, 0xed, 0x19};
 
 static SVCCTL_EvtAckStatus_t serial_svc_event_handler(void* event) {
     SVCCTL_EvtAckStatus_t ret = SVCCTL_EvtNotAck;
@@ -67,6 +70,17 @@ static SVCCTL_EvtAckStatus_t serial_svc_event_handler(void* event) {
                     furi_check(furi_mutex_release(serial_svc->buff_size_mtx) == FuriStatusOk);
                 }
                 ret = SVCCTL_EvtAckFlowEnable;
+            } else if(attribute_modified->Attr_Handle == serial_svc->rpc_status_char_handle + 1) {
+                SerialServiceRpcStatus* rpc_status =
+                    (SerialServiceRpcStatus*)attribute_modified->Attr_Data;
+                if(*rpc_status == SerialServiceRpcStatusNotActive) {
+                    if(serial_svc->callback) {
+                        SerialServiceEvent event = {
+                            .event = SerialServiceEventTypesBleResetRequest,
+                        };
+                        serial_svc->callback(event, serial_svc->context);
+                    }
+                }
             }
         } else if(blecore_evt->ecode == ACI_GATT_SERVER_CONFIRMATION_VSEVT_CODE) {
             FURI_LOG_T(TAG, "Ack received");
@@ -82,6 +96,18 @@ static SVCCTL_EvtAckStatus_t serial_svc_event_handler(void* event) {
     return ret;
 }
 
+static void serial_svc_update_rpc_char(SerialServiceRpcStatus status) {
+    tBleStatus ble_status = aci_gatt_update_char_value(
+        serial_svc->svc_handle,
+        serial_svc->rpc_status_char_handle,
+        0,
+        sizeof(SerialServiceRpcStatus),
+        (uint8_t*)&status);
+    if(ble_status) {
+        FURI_LOG_E(TAG, "Failed to update RPC status char: %d", ble_status);
+    }
+}
+
 void serial_svc_start() {
     tBleStatus status;
     serial_svc = malloc(sizeof(SerialSvc));
@@ -90,7 +116,7 @@ void serial_svc_start() {
 
     // Add service
     status = aci_gatt_add_service(
-        UUID_TYPE_128, (Service_UUID_t*)service_uuid, PRIMARY_SERVICE, 10, &serial_svc->svc_handle);
+        UUID_TYPE_128, (Service_UUID_t*)service_uuid, PRIMARY_SERVICE, 12, &serial_svc->svc_handle);
     if(status) {
         FURI_LOG_E(TAG, "Failed to add Serial service: %d", status);
     }
@@ -141,6 +167,22 @@ void serial_svc_start() {
     if(status) {
         FURI_LOG_E(TAG, "Failed to add Flow Control characteristic: %d", status);
     }
+    // Add RPC status characteristic
+    status = aci_gatt_add_char(
+        serial_svc->svc_handle,
+        UUID_TYPE_128,
+        (const Char_UUID_t*)rpc_status_uuid,
+        sizeof(SerialServiceRpcStatus),
+        CHAR_PROP_READ | CHAR_PROP_WRITE | CHAR_PROP_NOTIFY,
+        ATTR_PERMISSION_AUTHEN_READ | ATTR_PERMISSION_AUTHEN_WRITE,
+        GATT_NOTIFY_ATTRIBUTE_WRITE,
+        10,
+        CHAR_VALUE_LEN_CONSTANT,
+        &serial_svc->rpc_status_char_handle);
+    if(status) {
+        FURI_LOG_E(TAG, "Failed to add RPC status characteristic: %d", status);
+    }
+    serial_svc_update_rpc_char(SerialServiceRpcStatusNotActive);
     // Allocate buffer size mutex
     serial_svc->buff_size_mtx = furi_mutex_alloc(FuriMutexTypeNormal);
 }
@@ -198,6 +240,10 @@ void serial_svc_stop() {
         if(status) {
             FURI_LOG_E(TAG, "Failed to delete Flow Control characteristic: %d", status);
         }
+        status = aci_gatt_del_char(serial_svc->svc_handle, serial_svc->rpc_status_char_handle);
+        if(status) {
+            FURI_LOG_E(TAG, "Failed to delete RPC Status characteristic: %d", status);
+        }
         // Delete service
         status = aci_gatt_del_service(serial_svc->svc_handle);
         if(status) {
@@ -242,3 +288,8 @@ bool serial_svc_update_tx(uint8_t* data, uint16_t data_len) {
 
     return true;
 }
+
+void serial_svc_set_rpc_status(SerialServiceRpcStatus status) {
+    furi_assert(serial_svc);
+    serial_svc_update_rpc_char(status);
+}

+ 8 - 0
firmware/targets/f7/ble_glue/serial_service.h

@@ -10,9 +10,15 @@
 extern "C" {
 #endif
 
+typedef enum {
+    SerialServiceRpcStatusNotActive = 0UL,
+    SerialServiceRpcStatusActive = 1UL,
+} SerialServiceRpcStatus;
+
 typedef enum {
     SerialServiceEventTypeDataReceived,
     SerialServiceEventTypeDataSent,
+    SerialServiceEventTypesBleResetRequest,
 } SerialServiceEventType;
 
 typedef struct {
@@ -34,6 +40,8 @@ void serial_svc_set_callbacks(
     SerialServiceEventCallback callback,
     void* context);
 
+void serial_svc_set_rpc_status(SerialServiceRpcStatus status);
+
 void serial_svc_notify_buffer_is_empty();
 
 void serial_svc_stop();

+ 10 - 0
firmware/targets/f7/furi_hal/furi_hal_bt_serial.c

@@ -31,6 +31,16 @@ void furi_hal_bt_serial_notify_buffer_is_empty() {
     serial_svc_notify_buffer_is_empty();
 }
 
+void furi_hal_bt_serial_set_rpc_status(FuriHalBtSerialRpcStatus status) {
+    SerialServiceRpcStatus st;
+    if(status == FuriHalBtSerialRpcStatusActive) {
+        st = SerialServiceRpcStatusActive;
+    } else {
+        st = SerialServiceRpcStatusNotActive;
+    }
+    serial_svc_set_rpc_status(st);
+}
+
 bool furi_hal_bt_serial_tx(uint8_t* data, uint16_t size) {
     if(size > FURI_HAL_BT_SERIAL_PACKET_SIZE_MAX) {
         return false;

+ 11 - 0
firmware/targets/furi_hal_include/furi_hal_bt_serial.h

@@ -8,6 +8,11 @@ extern "C" {
 
 #define FURI_HAL_BT_SERIAL_PACKET_SIZE_MAX SERIAL_SVC_DATA_LEN_MAX
 
+typedef enum {
+    FuriHalBtSerialRpcStatusNotActive,
+    FuriHalBtSerialRpcStatusActive,
+} FuriHalBtSerialRpcStatus;
+
 /** Serial service callback type */
 typedef SerialServiceEventCallback FuriHalBtSerialCallback;
 
@@ -30,6 +35,12 @@ void furi_hal_bt_serial_set_event_callback(
     FuriHalBtSerialCallback callback,
     void* context);
 
+/** Set BLE RPC status
+ *
+ * @param status        FuriHalBtSerialRpcStatus instance
+ */
+void furi_hal_bt_serial_set_rpc_status(FuriHalBtSerialRpcStatus status);
+
 /** Notify that application buffer is empty
  */
 void furi_hal_bt_serial_notify_buffer_is_empty();