Просмотр исходного кода

[FL-1795] BLE GAP refactoring (#694)

* ble: remove heart rate profile
* ble-glue: delete dead code
* ble-glue: dis refactoring
* ble-glue: add battery service
* broken ble_common refactoring
* ble-glue: advertise 128 bit service uid
* ble-glue: remove dead code
* ble: advertise service 16 bit uid depending on flipper color
* ble-glue: remove debug
* ble: intriduce serial service
* ble: serial over ble
* bt: serial echo server
* bt: serial service process indicate acknowledge
* bt: serial service event handler update
* bt: refactore battery service
* bt: add battery level apdate API
* power: update battery level on change
* bt: refactore device information service
* app_ble: pairing configuration
* bt: display pin code
* bt: refactor battery service
* bt: refactor device info service
* bt: change advertise timer to freertos one
* bt: separate app_ble to hci and gap
* bt: increase max ble packet size
* gap: refactoring
* bt: refactor serial service
* bt: support f7 target
* bt: not blocking pin code show request

Co-authored-by: Anna Prosvetova <anna@prosvetova.me>
Co-authored-by: あく <alleteam@gmail.com>
gornekich 4 лет назад
Родитель
Сommit
95d9140d24
28 измененных файлов с 1195 добавлено и 1483 удалено
  1. 19 6
      applications/bt/bt_service/bt.c
  2. 3 1
      applications/bt/bt_service/bt.h
  3. 15 0
      applications/bt/bt_service/bt_api.c
  4. 6 0
      applications/bt/bt_service/bt_i.h
  5. 3 639
      firmware/targets/f6/ble-glue/app_ble.c
  6. 0 13
      firmware/targets/f6/ble-glue/app_ble.h
  7. 1 1
      firmware/targets/f6/ble-glue/app_conf.h
  8. 34 11
      firmware/targets/f6/ble-glue/battery_service.c
  9. 3 1
      firmware/targets/f6/ble-glue/battery_service.h
  10. 78 43
      firmware/targets/f6/ble-glue/dev_info_service.c
  11. 2 1
      firmware/targets/f6/ble-glue/dev_info_service.h
  12. 387 0
      firmware/targets/f6/ble-glue/gap.c
  13. 22 0
      firmware/targets/f6/ble-glue/gap.h
  14. 42 22
      firmware/targets/f6/ble-glue/serial_service.c
  15. 2 6
      firmware/targets/f6/ble-glue/serial_service.h
  16. 2 1
      firmware/targets/f6/furi-hal/furi-hal-bt.c
  17. 3 639
      firmware/targets/f7/ble-glue/app_ble.c
  18. 0 13
      firmware/targets/f7/ble-glue/app_ble.h
  19. 1 1
      firmware/targets/f7/ble-glue/app_conf.h
  20. 34 11
      firmware/targets/f7/ble-glue/battery_service.c
  21. 3 1
      firmware/targets/f7/ble-glue/battery_service.h
  22. 78 43
      firmware/targets/f7/ble-glue/dev_info_service.c
  23. 2 1
      firmware/targets/f7/ble-glue/dev_info_service.h
  24. 387 0
      firmware/targets/f7/ble-glue/gap.c
  25. 22 0
      firmware/targets/f7/ble-glue/gap.h
  26. 42 22
      firmware/targets/f7/ble-glue/serial_service.c
  27. 2 6
      firmware/targets/f7/ble-glue/serial_service.h
  28. 2 1
      firmware/targets/f7/furi-hal/furi-hal-bt.c

+ 19 - 6
applications/bt/bt_service/bt.c

@@ -22,6 +22,17 @@ static ViewPort* bt_statusbar_view_port_alloc() {
     return statusbar_view_port;
     return statusbar_view_port;
 }
 }
 
 
+static void bt_pin_code_show_event_handler(Bt* bt, uint32_t pin) {
+    furi_assert(bt);
+    string_t pin_str;
+    string_init_printf(pin_str, "%06d", pin);
+    dialog_message_set_text(
+        bt->dialog_message, string_get_cstr(pin_str), 64, 32, AlignCenter, AlignCenter);
+    dialog_message_set_buttons(bt->dialog_message, "Back", NULL, NULL);
+    dialog_message_show(bt->dialogs, bt->dialog_message);
+    string_clear(pin_str);
+}
+
 Bt* bt_alloc() {
 Bt* bt_alloc() {
     Bt* bt = furi_alloc(sizeof(Bt));
     Bt* bt = furi_alloc(sizeof(Bt));
     // Load settings
     // Load settings
@@ -41,13 +52,11 @@ Bt* bt_alloc() {
     bt->gui = furi_record_open("gui");
     bt->gui = furi_record_open("gui");
     gui_add_view_port(bt->gui, bt->statusbar_view_port, GuiLayerStatusBarLeft);
     gui_add_view_port(bt->gui, bt->statusbar_view_port, GuiLayerStatusBarLeft);
 
 
-    return bt;
-}
+    // Dialogs
+    bt->dialogs = furi_record_open("dialogs");
+    bt->dialog_message = dialog_message_alloc();
 
 
-bool bt_update_battery_level(Bt* bt, uint8_t battery_level) {
-    BtMessage message = {
-        .type = BtMessageTypeUpdateBatteryLevel, .data.battery_level = battery_level};
-    return osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK;
+    return bt;
 }
 }
 
 
 int32_t bt_srv() {
 int32_t bt_srv() {
@@ -76,9 +85,13 @@ int32_t bt_srv() {
             // Update statusbar
             // Update statusbar
             view_port_enabled_set(bt->statusbar_view_port, furi_hal_bt_is_alive());
             view_port_enabled_set(bt->statusbar_view_port, furi_hal_bt_is_alive());
         } else if(message.type == BtMessageTypeUpdateBatteryLevel) {
         } else if(message.type == BtMessageTypeUpdateBatteryLevel) {
+            // Update battery level
             if(furi_hal_bt_is_alive()) {
             if(furi_hal_bt_is_alive()) {
                 battery_svc_update_level(message.data.battery_level);
                 battery_svc_update_level(message.data.battery_level);
             }
             }
+        } else if(message.type == BtMessageTypePinCodeShow) {
+            // Display PIN code
+            bt_pin_code_show_event_handler(bt, message.data.pin_code);
         }
         }
     }
     }
     return 0;
     return 0;

+ 3 - 1
applications/bt/bt_service/bt.h

@@ -9,7 +9,9 @@ extern "C" {
 
 
 typedef struct Bt Bt;
 typedef struct Bt Bt;
 
 
-bool bt_update_battery_level(Bt* bt, uint8_t battery_level);
+void bt_update_battery_level(Bt* bt, uint8_t battery_level);
+
+bool bt_pin_code_show(Bt* bt, uint32_t pin_code);
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 }
 }

+ 15 - 0
applications/bt/bt_service/bt_api.c

@@ -0,0 +1,15 @@
+#include "bt.h"
+#include "bt_i.h"
+
+void bt_update_battery_level(Bt* bt, uint8_t battery_level) {
+    furi_assert(bt);
+    BtMessage message = {
+        .type = BtMessageTypeUpdateBatteryLevel, .data.battery_level = battery_level};
+    furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK);
+}
+
+bool bt_pin_code_show(Bt* bt, uint32_t pin_code) {
+    furi_assert(bt);
+    BtMessage message = {.type = BtMessageTypePinCodeShow, .data.pin_code = pin_code};
+    return osMessageQueuePut(bt->message_queue, &message, 0, 0) == osOK;
+}

+ 6 - 0
applications/bt/bt_service/bt_i.h

@@ -9,14 +9,18 @@
 #include <gui/view_port.h>
 #include <gui/view_port.h>
 #include <gui/view.h>
 #include <gui/view.h>
 
 
+#include <applications/dialogs/dialogs.h>
+
 #include "../bt_settings.h"
 #include "../bt_settings.h"
 
 
 typedef enum {
 typedef enum {
     BtMessageTypeUpdateStatusbar,
     BtMessageTypeUpdateStatusbar,
     BtMessageTypeUpdateBatteryLevel,
     BtMessageTypeUpdateBatteryLevel,
+    BtMessageTypePinCodeShow,
 } BtMessageType;
 } BtMessageType;
 
 
 typedef union {
 typedef union {
+    uint32_t pin_code;
     uint8_t battery_level;
     uint8_t battery_level;
 } BtMessageData;
 } BtMessageData;
 
 
@@ -31,4 +35,6 @@ struct Bt {
     osTimerId_t update_status_timer;
     osTimerId_t update_status_timer;
     Gui* gui;
     Gui* gui;
     ViewPort* statusbar_view_port;
     ViewPort* statusbar_view_port;
+    DialogsApp* dialogs;
+    DialogMessage* dialog_message;
 };
 };

+ 3 - 639
firmware/targets/f6/ble-glue/app_ble.c

@@ -6,106 +6,20 @@
 #include "ble.h"
 #include "ble.h"
 #include "tl.h"
 #include "tl.h"
 #include "app_ble.h"
 #include "app_ble.h"
-
-#include "cmsis_os.h"
 #include "shci.h"
 #include "shci.h"
-#include "otp.h"
-#include "dev_info_service.h"
-#include "battery_service.h"
-#include "serial_service.h"
+#include "cmsis_os.h"
 
 
 #include <furi-hal.h>
 #include <furi-hal.h>
 
 
-typedef struct _tSecurityParams {
-  uint8_t ioCapability;
-  uint8_t mitm_mode;
-  uint8_t bonding_mode;
-  uint8_t Use_Fixed_Pin;
-  uint8_t encryptionKeySizeMin;
-  uint8_t encryptionKeySizeMax;
-  uint32_t Fixed_Pin;
-  uint8_t initiateSecurity;
-} tSecurityParams;
-
-typedef struct _tBLEProfileGlobalContext {
-  tSecurityParams bleSecurityParam;
-  uint16_t gapServiceHandle;
-  uint16_t devNameCharHandle;
-  uint16_t appearanceCharHandle;
-  uint16_t connectionHandle;
-  uint8_t advtServUUIDlen;
-  uint8_t advtServUUID[100];
-} BleGlobalContext_t;
-
-typedef struct {
-  BleGlobalContext_t BleApplicationContext_legacy;
-  APP_BLE_ConnStatus_t Device_Connection_Status;
-  uint8_t Advertising_mgr_timer_Id;
-} BleApplicationContext_t;
-
-
-#define FAST_ADV_TIMEOUT               (30*1000*1000/CFG_TS_TICK_VAL) /**< 30s */
-#define INITIAL_ADV_TIMEOUT            (60*1000*1000/CFG_TS_TICK_VAL) /**< 60s */
-
-#define BD_ADDR_SIZE_LOCAL    6
-
-#define LED_ON_TIMEOUT                 (0.005*1000*1000/CFG_TS_TICK_VAL) /**< 5ms */
-
 PLACE_IN_SECTION("MB_MEM1") ALIGN(4) static TL_CmdPacket_t BleCmdBuffer;
 PLACE_IN_SECTION("MB_MEM1") ALIGN(4) static TL_CmdPacket_t BleCmdBuffer;
 
 
-static const uint8_t M_bd_addr[BD_ADDR_SIZE_LOCAL] =
-    {
-        (uint8_t)((CFG_ADV_BD_ADDRESS & 0x0000000000FF)),
-        (uint8_t)((CFG_ADV_BD_ADDRESS & 0x00000000FF00) >> 8),
-        (uint8_t)((CFG_ADV_BD_ADDRESS & 0x000000FF0000) >> 16),
-        (uint8_t)((CFG_ADV_BD_ADDRESS & 0x0000FF000000) >> 24),
-        (uint8_t)((CFG_ADV_BD_ADDRESS & 0x00FF00000000) >> 32),
-        (uint8_t)((CFG_ADV_BD_ADDRESS & 0xFF0000000000) >> 40)
-    };
-
-static uint8_t bd_addr_udn[BD_ADDR_SIZE_LOCAL];
-
-static const uint8_t BLE_CFG_IR_VALUE[16] = CFG_BLE_IRK;
-static const uint8_t BLE_CFG_ER_VALUE[16] = CFG_BLE_ERK;
-
-PLACE_IN_SECTION("TAG_OTA_END") const uint32_t MagicKeywordValue = 0x94448A29 ;
-PLACE_IN_SECTION("TAG_OTA_START") const uint32_t MagicKeywordAddress = (uint32_t)&MagicKeywordValue;
-
-PLACE_IN_SECTION("BLE_APP_CONTEXT") static BleApplicationContext_t BleApplicationContext;
-PLACE_IN_SECTION("BLE_APP_CONTEXT") static uint16_t AdvIntervalMin, AdvIntervalMax;
-
-uint8_t  manuf_data[14] = {
-    sizeof(manuf_data)-1, AD_TYPE_MANUFACTURER_SPECIFIC_DATA,
-    0x01/*SKD version */,
-    0x00 /* Generic*/,
-    0x00 /* GROUP A Feature  */,
-    0x00 /* GROUP A Feature */,
-    0x00 /* GROUP B Feature */,
-    0x00 /* GROUP B Feature */,
-    0x00, /* BLE MAC start -MSB */
-    0x00,
-    0x00,
-    0x00,
-    0x00,
-    0x00, /* BLE MAC stop */
-
-};
+// PLACE_IN_SECTION("TAG_OTA_END") const uint32_t MagicKeywordValue = 0x94448A29 ;
+// PLACE_IN_SECTION("TAG_OTA_START") const uint32_t MagicKeywordAddress = (uint32_t)&MagicKeywordValue;
 
 
 osMutexId_t MtxHciId;
 osMutexId_t MtxHciId;
 osSemaphoreId_t SemHciId;
 osSemaphoreId_t SemHciId;
-osThreadId_t AdvUpdateProcessId;
 osThreadId_t HciUserEvtProcessId;
 osThreadId_t HciUserEvtProcessId;
 
 
-const osThreadAttr_t AdvUpdateProcess_attr = {
-    .name = CFG_ADV_UPDATE_PROCESS_NAME,
-    .attr_bits = CFG_ADV_UPDATE_PROCESS_ATTR_BITS,
-    .cb_mem = CFG_ADV_UPDATE_PROCESS_CB_MEM,
-    .cb_size = CFG_ADV_UPDATE_PROCESS_CB_SIZE,
-    .stack_mem = CFG_ADV_UPDATE_PROCESS_STACK_MEM,
-    .priority = CFG_ADV_UPDATE_PROCESS_PRIORITY,
-    .stack_size = CFG_ADV_UPDATE_PROCESS_STACK_SIZE
-};
-
 const osThreadAttr_t HciUserEvtProcess_attr = {
 const osThreadAttr_t HciUserEvtProcess_attr = {
     .name = CFG_HCI_USER_EVT_PROCESS_NAME,
     .name = CFG_HCI_USER_EVT_PROCESS_NAME,
     .attr_bits = CFG_HCI_USER_EVT_PROCESS_ATTR_BITS,
     .attr_bits = CFG_HCI_USER_EVT_PROCESS_ATTR_BITS,
@@ -121,13 +35,6 @@ static void HciUserEvtProcess(void *argument);
 static void BLE_UserEvtRx( void * pPayload );
 static void BLE_UserEvtRx( void * pPayload );
 static void BLE_StatusNot( HCI_TL_CmdStatus_t status );
 static void BLE_StatusNot( HCI_TL_CmdStatus_t status );
 static void Ble_Tl_Init( void );
 static void Ble_Tl_Init( void );
-static void Ble_Hci_Gap_Gatt_Init();
-static const uint8_t* BleGetBdAddress( void );
-static void Adv_Request( APP_BLE_ConnStatus_t New_Status );
-static void Adv_Mgr( void );
-static void AdvUpdateProcess(void *argument);
-static void Adv_Update( void );
-
 
 
 bool APP_BLE_Init() {
 bool APP_BLE_Init() {
   SHCI_C2_Ble_Init_Cmd_Packet_t ble_init_cmd_packet = {
   SHCI_C2_Ble_Init_Cmd_Packet_t ble_init_cmd_packet = {
@@ -160,254 +67,6 @@ bool APP_BLE_Init() {
   return (SHCI_C2_BLE_Init( &ble_init_cmd_packet ) == SHCI_Success);
   return (SHCI_C2_BLE_Init( &ble_init_cmd_packet ) == SHCI_Success);
 }
 }
 
 
-static void set_advertisment_service_uid(uint8_t* uid, uint8_t uin_len);
-
-bool APP_BLE_Start() {
-  if (APPE_Status() != BleGlueStatusStarted) {
-    return false;
-  }
-  // Initialization of HCI & GATT & GAP layer
-  Ble_Hci_Gap_Gatt_Init();
-  // Initialization of the BLE Services
-  SVCCTL_Init();
-  // Initialization of the BLE App Context
-  BleApplicationContext.Device_Connection_Status = APP_BLE_IDLE;
-  BleApplicationContext.BleApplicationContext_legacy.connectionHandle = 0xFFFF;
-  // From here, all initialization are BLE application specific
-  AdvUpdateProcessId = osThreadNew(AdvUpdateProcess, NULL, &AdvUpdateProcess_attr);
-
-  // Initialization of ADV - Ad Manufacturer Element - Support OTA Bit Masks
-#if(BLE_CFG_OTA_REBOOT_CHAR != 0)
-  manuf_data[sizeof(manuf_data)-8] = CFG_FEATURE_OTA_REBOOT;
-#endif
-
-  // Initialize DIS Application
-  dev_info_service_init();
-  // Initialize BAS Application
-  battery_svc_init();
-  // Initialize Serial application
-  serial_svc_init();
-  // Create timer to handle the connection state machine
-  HW_TS_Create(CFG_TIM_PROC_ID_ISR, &(BleApplicationContext.Advertising_mgr_timer_Id), hw_ts_SingleShot, Adv_Mgr);
-  uint8_t adv_service_uid[2];
-  adv_service_uid[0] = 0x80 | furi_hal_version_get_hw_color();
-  adv_service_uid[1] = 0x30;
-
-  set_advertisment_service_uid(adv_service_uid, sizeof(adv_service_uid));
-  /* Initialize intervals for reconnexion without intervals update */
-  AdvIntervalMin = CFG_FAST_CONN_ADV_INTERVAL_MIN;
-  AdvIntervalMax = CFG_FAST_CONN_ADV_INTERVAL_MAX;
-
-  Adv_Request(APP_BLE_FAST_ADV);
-  return true;
-}
-
-void SVCCTL_SvcInit() {
-    // Dummy function to prevent unused services initialization
-    // TODO refactore
-}
-
-SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification( void *pckt )
-{
-  hci_event_pckt *event_pckt;
-  evt_le_meta_event *meta_evt;
-  evt_blue_aci *blue_evt;
-  hci_le_phy_update_complete_event_rp0 *evt_le_phy_update_complete;
-  uint8_t TX_PHY, RX_PHY;
-  tBleStatus ret = BLE_STATUS_INVALID_PARAMS;
-
-  event_pckt = (hci_event_pckt*) ((hci_uart_pckt *) pckt)->data;
-
-  switch (event_pckt->evt) {
-    case EVT_DISCONN_COMPLETE:
-    {
-      hci_disconnection_complete_event_rp0 *disconnection_complete_event;
-      disconnection_complete_event = (hci_disconnection_complete_event_rp0 *) event_pckt->data;
-
-      if (disconnection_complete_event->Connection_Handle == BleApplicationContext.BleApplicationContext_legacy.connectionHandle) {
-        BleApplicationContext.BleApplicationContext_legacy.connectionHandle = 0;
-        BleApplicationContext.Device_Connection_Status = APP_BLE_IDLE;
-        APP_DBG_MSG("\r\n\r** DISCONNECTION EVENT WITH CLIENT \r\n");
-      }
-      /* restart advertising */
-      Adv_Request(APP_BLE_FAST_ADV);
-      furi_hal_power_insomnia_exit();
-    }
-    break; /* EVT_DISCONN_COMPLETE */
-
-    case EVT_LE_META_EVENT:
-    {
-      meta_evt = (evt_le_meta_event*) event_pckt->data;
-      switch (meta_evt->subevent)
-      {
-        case EVT_LE_CONN_UPDATE_COMPLETE:
-          APP_DBG_MSG("\r\n\r** CONNECTION UPDATE EVENT WITH CLIENT \r\n");
-
-          /* USER CODE BEGIN EVT_LE_CONN_UPDATE_COMPLETE */
-
-          /* USER CODE END EVT_LE_CONN_UPDATE_COMPLETE */
-          break;
-        case EVT_LE_PHY_UPDATE_COMPLETE:
-          APP_DBG_MSG("EVT_UPDATE_PHY_COMPLETE \r\n");
-          evt_le_phy_update_complete = (hci_le_phy_update_complete_event_rp0*)meta_evt->data;
-          if (evt_le_phy_update_complete->Status == 0)
-          {
-            APP_DBG_MSG("EVT_UPDATE_PHY_COMPLETE, status ok \r\n");
-          }
-          else
-          {
-            APP_DBG_MSG("EVT_UPDATE_PHY_COMPLETE, status nok \r\n");
-          }
-
-          ret = hci_le_read_phy(BleApplicationContext.BleApplicationContext_legacy.connectionHandle,&TX_PHY,&RX_PHY);
-          if (ret == BLE_STATUS_SUCCESS)
-          {
-            APP_DBG_MSG("Read_PHY success \r\n");
-
-            if ((TX_PHY == TX_2M) && (RX_PHY == RX_2M))
-            {
-              APP_DBG_MSG("PHY Param  TX= %d, RX= %d \r\n", TX_PHY, RX_PHY);
-            }
-            else
-            {
-              APP_DBG_MSG("PHY Param  TX= %d, RX= %d \r\n", TX_PHY, RX_PHY);
-            }
-          }
-          else
-          {
-            APP_DBG_MSG("Read conf not succeess \r\n");
-          }
-          break;
-        case EVT_LE_CONN_COMPLETE:
-        {
-          furi_hal_power_insomnia_enter();
-          hci_le_connection_complete_event_rp0 *connection_complete_event;
-
-          /**
-           * The connection is done, there is no need anymore to schedule the LP ADV
-           */
-          connection_complete_event = (hci_le_connection_complete_event_rp0 *) meta_evt->data;
-
-          HW_TS_Stop(BleApplicationContext.Advertising_mgr_timer_Id);
-
-          APP_DBG_MSG("EVT_LE_CONN_COMPLETE for connection handle 0x%x\r\n", connection_complete_event->Connection_Handle);
-          if (BleApplicationContext.Device_Connection_Status == APP_BLE_LP_CONNECTING)
-          {
-            /* Connection as client */
-            BleApplicationContext.Device_Connection_Status = APP_BLE_CONNECTED_CLIENT;
-          }
-          else
-          {
-            /* Connection as server */
-            BleApplicationContext.Device_Connection_Status = APP_BLE_CONNECTED_SERVER;
-          }
-          BleApplicationContext.BleApplicationContext_legacy.connectionHandle = connection_complete_event->Connection_Handle;
-        }
-        break; /* HCI_EVT_LE_CONN_COMPLETE */
-        default:
-          break;
-      }
-    }
-    break; /* HCI_EVT_LE_META_EVENT */
-
-    case EVT_VENDOR:
-      blue_evt = (evt_blue_aci*) event_pckt->data;
-      switch (blue_evt->ecode) {
-        aci_gap_pairing_complete_event_rp0 *pairing_complete;
-
-      case EVT_BLUE_GAP_LIMITED_DISCOVERABLE: 
-        APP_DBG_MSG("\r\n\r** EVT_BLUE_GAP_LIMITED_DISCOVERABLE \r\n");
-          break; /* EVT_BLUE_GAP_LIMITED_DISCOVERABLE */
-          
-      case EVT_BLUE_GAP_PASS_KEY_REQUEST:  
-        APP_DBG_MSG("\r\n\r** EVT_BLUE_GAP_PASS_KEY_REQUEST \r\n");
-
-        aci_gap_pass_key_resp(BleApplicationContext.BleApplicationContext_legacy.connectionHandle,123456);
-
-        APP_DBG_MSG("\r\n\r** aci_gap_pass_key_resp \r\n");
-          break; /* EVT_BLUE_GAP_PASS_KEY_REQUEST */
-
-      case EVT_BLUE_GAP_AUTHORIZATION_REQUEST:    
-        APP_DBG_MSG("\r\n\r** EVT_BLUE_GAP_AUTHORIZATION_REQUEST \r\n");
-          break; /* EVT_BLUE_GAP_AUTHORIZATION_REQUEST */
-
-      case EVT_BLUE_GAP_SLAVE_SECURITY_INITIATED:   
-        APP_DBG_MSG("\r\n\r** EVT_BLUE_GAP_SLAVE_SECURITY_INITIATED \r\n");
-          break; /* EVT_BLUE_GAP_SLAVE_SECURITY_INITIATED */
-
-      case EVT_BLUE_GAP_BOND_LOST:    
-        APP_DBG_MSG("\r\n\r** EVT_BLUE_GAP_BOND_LOST \r\n");
-          aci_gap_allow_rebond(BleApplicationContext.BleApplicationContext_legacy.connectionHandle);
-        APP_DBG_MSG("\r\n\r** Send allow rebond \r\n");
-          break; /* EVT_BLUE_GAP_BOND_LOST */
-
-      case EVT_BLUE_GAP_DEVICE_FOUND:  
-        APP_DBG_MSG("\r\n\r** EVT_BLUE_GAP_DEVICE_FOUND \r\n");
-          break; /* EVT_BLUE_GAP_DEVICE_FOUND */
-
-      case EVT_BLUE_GAP_ADDR_NOT_RESOLVED:
-         APP_DBG_MSG("\r\n\r** EVT_BLUE_GAP_DEVICE_FOUND \r\n");
-          break; /* EVT_BLUE_GAP_DEVICE_FOUND */
-      
-      case (EVT_BLUE_GAP_KEYPRESS_NOTIFICATION):
-         APP_DBG_MSG("\r\n\r** EVT_BLUE_GAP_KEYPRESS_NOTIFICATION \r\n");
-          break; /* EVT_BLUE_GAP_KEY_PRESS_NOTIFICATION */    
-
-       case (EVT_BLUE_GAP_NUMERIC_COMPARISON_VALUE):
-          APP_DBG_MSG("numeric_value = %ld\r\n",
-                      ((aci_gap_numeric_comparison_value_event_rp0 *)(blue_evt->data))->Numeric_Value);
-
-          APP_DBG_MSG("Hex_value = %lx\r\n",
-                      ((aci_gap_numeric_comparison_value_event_rp0 *)(blue_evt->data))->Numeric_Value);
-
-          aci_gap_numeric_comparison_value_confirm_yesno(BleApplicationContext.BleApplicationContext_legacy.connectionHandle, 1); /* CONFIRM_YES = 1 */
-
-          APP_DBG_MSG("\r\n\r** aci_gap_numeric_comparison_value_confirm_yesno-->YES \r\n");
-          break;
-
-        case (EVT_BLUE_GAP_PAIRING_CMPLT):
-          {
-            pairing_complete = (aci_gap_pairing_complete_event_rp0*)blue_evt->data;
-
-            APP_DBG_MSG("BLE_CTRL_App_Notification: EVT_BLUE_GAP_PAIRING_CMPLT, pairing_complete->Status = %d\r\n",pairing_complete->Status);
-            if (pairing_complete->Status == 0) {
-              APP_DBG_MSG("\r\n\r** Pairing OK \r\n");
-            } else {
-              APP_DBG_MSG("\r\n\r** Pairing KO \r\n");
-            }
-          }
-          break;
-
-      /* USER CODE END ecode */
-        case EVT_BLUE_GAP_PROCEDURE_COMPLETE:
-          APP_DBG_MSG("\r\n\r** EVT_BLUE_GAP_PROCEDURE_COMPLETE \r\n");
-          break;
-      }
-      break; /* EVT_VENDOR */
-      default:
-        break;
-  }
-
-  return (SVCCTL_UserEvtFlowEnable);
-}
-
-static void set_advertisment_service_uid(uint8_t* uid, uint8_t uid_len) {
-    BleApplicationContext.BleApplicationContext_legacy.advtServUUIDlen = 1;
-    if(uid_len == 2) {
-        BleApplicationContext.BleApplicationContext_legacy.advtServUUID[0] = AD_TYPE_16_BIT_SERV_UUID;
-    } else if (uid_len == 4) {
-        BleApplicationContext.BleApplicationContext_legacy.advtServUUID[0] = AD_TYPE_32_BIT_SERV_UUID;
-    } else if(uid_len == 16) {
-        BleApplicationContext.BleApplicationContext_legacy.advtServUUID[0] = AD_TYPE_128_BIT_SERV_UUID_CMPLT_LIST;
-    }
-    memcpy(&BleApplicationContext.BleApplicationContext_legacy.advtServUUID[1], uid, uid_len);
-    BleApplicationContext.BleApplicationContext_legacy.advtServUUIDlen += uid_len;
-}
-
-APP_BLE_ConnStatus_t APP_BLE_Get_Server_Connection_Status() {
-    return BleApplicationContext.Device_Connection_Status;
-}
-
 static void Ble_Tl_Init( void ) {
 static void Ble_Tl_Init( void ) {
   HCI_TL_HciInitConf_t Hci_Tl_Init_Conf;
   HCI_TL_HciInitConf_t Hci_Tl_Init_Conf;
 
 
@@ -419,301 +78,6 @@ static void Ble_Tl_Init( void ) {
   hci_init(BLE_UserEvtRx, (void*) &Hci_Tl_Init_Conf);
   hci_init(BLE_UserEvtRx, (void*) &Hci_Tl_Init_Conf);
 }
 }
 
 
-static void Ble_Hci_Gap_Gatt_Init() {
-  uint8_t role;
-  uint16_t gap_service_handle, gap_dev_name_char_handle, gap_appearance_char_handle;
-  const uint8_t *bd_addr;
-  uint32_t srd_bd_addr[2];
-  uint16_t appearance[1] = { BLE_CFG_GAP_APPEARANCE };
-
-  /*HCI Reset to synchronise BLE Stack*/
-  hci_reset();
-
-  /**
-   * Write the BD Address
-   */
-  bd_addr = BleGetBdAddress();
-  aci_hal_write_config_data(CONFIG_DATA_PUBADDR_OFFSET,
-                            CONFIG_DATA_PUBADDR_LEN,
-                            (uint8_t*) bd_addr);
-
-  /* BLE MAC in ADV Packet */
-  manuf_data[ sizeof(manuf_data)-6] = bd_addr[5];
-  manuf_data[ sizeof(manuf_data)-5] = bd_addr[4];
-  manuf_data[ sizeof(manuf_data)-4] = bd_addr[3];
-  manuf_data[ sizeof(manuf_data)-3] = bd_addr[2];
-  manuf_data[ sizeof(manuf_data)-2] = bd_addr[1];
-  manuf_data[ sizeof(manuf_data)-1] = bd_addr[0];
-
-  /**
-   * Write Identity root key used to derive LTK and CSRK
-   */
-    aci_hal_write_config_data(CONFIG_DATA_IR_OFFSET,
-    CONFIG_DATA_IR_LEN,
-                            (uint8_t*) BLE_CFG_IR_VALUE);
-
-   /**
-   * Write Encryption root key used to derive LTK and CSRK
-   */
-    aci_hal_write_config_data(CONFIG_DATA_ER_OFFSET,
-    CONFIG_DATA_ER_LEN,
-                            (uint8_t*) BLE_CFG_ER_VALUE);
-
-   /**
-   * Write random bd_address
-   */
-   /* random_bd_address = R_bd_address;
-    aci_hal_write_config_data(CONFIG_DATA_RANDOM_ADDRESS_WR,
-    CONFIG_DATA_RANDOM_ADDRESS_LEN,
-                            (uint8_t*) random_bd_address);
-  */
-
-  /**
-   * Static random Address
-   * The two upper bits shall be set to 1
-   * The lowest 32bits is read from the UDN to differentiate between devices
-   * The RNG may be used to provide a random number on each power on
-   */
-  srd_bd_addr[1] =  0x0000ED6E;
-  srd_bd_addr[0] =  LL_FLASH_GetUDN( );
-  aci_hal_write_config_data( CONFIG_DATA_RANDOM_ADDRESS_OFFSET, CONFIG_DATA_RANDOM_ADDRESS_LEN, (uint8_t*)srd_bd_addr );
-
-  /**
-   * Write Identity root key used to derive LTK and CSRK
-   */
-    aci_hal_write_config_data( CONFIG_DATA_IR_OFFSET, CONFIG_DATA_IR_LEN, (uint8_t*)BLE_CFG_IR_VALUE );
-
-   /**
-   * Write Encryption root key used to derive LTK and CSRK
-   */
-    aci_hal_write_config_data( CONFIG_DATA_ER_OFFSET, CONFIG_DATA_ER_LEN, (uint8_t*)BLE_CFG_ER_VALUE );
-
-  /**
-   * Set TX Power to 0dBm.
-   */
-  aci_hal_set_tx_power_level(1, CFG_TX_POWER);
-
-  /**
-   * Initialize GATT interface
-   */
-  aci_gatt_init();
-
-  /**
-   * Initialize GAP interface
-   */
-  role = 0;
-
-#if (BLE_CFG_PERIPHERAL == 1)
-  role |= GAP_PERIPHERAL_ROLE;
-#endif
-
-#if (BLE_CFG_CENTRAL == 1)
-  role |= GAP_CENTRAL_ROLE;
-#endif
-
-  if (role > 0)
-  {
-    const char *name = furi_hal_version_get_device_name_ptr();
-    aci_gap_init(role, 0,
-                 strlen(name),
-                 &gap_service_handle, &gap_dev_name_char_handle, &gap_appearance_char_handle);
-
-    if (aci_gatt_update_char_value(gap_service_handle, gap_dev_name_char_handle, 0, strlen(name), (uint8_t *) name))
-    {
-      BLE_DBG_SVCCTL_MSG("Device Name aci_gatt_update_char_value failed.\r\n");
-    }
-  }
-
-  if(aci_gatt_update_char_value(gap_service_handle,
-                                gap_appearance_char_handle,
-                                0,
-                                2,
-                                (uint8_t *)&appearance))
-  {
-    BLE_DBG_SVCCTL_MSG("Appearance aci_gatt_update_char_value failed.\r\n");
-  }
-  /**
-   * Initialize Default PHY
-   */
-  hci_le_set_default_phy(ALL_PHYS_PREFERENCE,TX_2M_PREFERRED,RX_2M_PREFERRED);
-
-  /**
-   * Initialize IO capability
-   */
-  BleApplicationContext.BleApplicationContext_legacy.bleSecurityParam.ioCapability = CFG_IO_CAPABILITY;
-  aci_gap_set_io_capability(BleApplicationContext.BleApplicationContext_legacy.bleSecurityParam.ioCapability);
-
-  /**
-   * Initialize authentication
-   */
-  BleApplicationContext.BleApplicationContext_legacy.bleSecurityParam.mitm_mode = CFG_MITM_PROTECTION;
-  BleApplicationContext.BleApplicationContext_legacy.bleSecurityParam.encryptionKeySizeMin = CFG_ENCRYPTION_KEY_SIZE_MIN;
-  BleApplicationContext.BleApplicationContext_legacy.bleSecurityParam.encryptionKeySizeMax = CFG_ENCRYPTION_KEY_SIZE_MAX;
-  BleApplicationContext.BleApplicationContext_legacy.bleSecurityParam.Use_Fixed_Pin = CFG_USED_FIXED_PIN;
-  BleApplicationContext.BleApplicationContext_legacy.bleSecurityParam.Fixed_Pin = CFG_FIXED_PIN;
-  BleApplicationContext.BleApplicationContext_legacy.bleSecurityParam.bonding_mode = CFG_BONDING_MODE;
-
-  aci_gap_set_authentication_requirement(BleApplicationContext.BleApplicationContext_legacy.bleSecurityParam.bonding_mode,
-                                         BleApplicationContext.BleApplicationContext_legacy.bleSecurityParam.mitm_mode,
-                                         CFG_SC_SUPPORT,
-                                         CFG_KEYPRESS_NOTIFICATION_SUPPORT,
-                                         BleApplicationContext.BleApplicationContext_legacy.bleSecurityParam.encryptionKeySizeMin,
-                                         BleApplicationContext.BleApplicationContext_legacy.bleSecurityParam.encryptionKeySizeMax,
-                                         BleApplicationContext.BleApplicationContext_legacy.bleSecurityParam.Use_Fixed_Pin,
-                                         BleApplicationContext.BleApplicationContext_legacy.bleSecurityParam.Fixed_Pin,
-                                         PUBLIC_ADDR
-                                         );
-
-  /**
-   * Initialize whitelist
-   */
-   if (BleApplicationContext.BleApplicationContext_legacy.bleSecurityParam.bonding_mode)
-   {
-     aci_gap_configure_whitelist();
-   }
-}
-
-static void Adv_Request(APP_BLE_ConnStatus_t New_Status)
-{
-  tBleStatus ret = BLE_STATUS_INVALID_PARAMS;
-  uint16_t Min_Inter, Max_Inter;
-
-  if (New_Status == APP_BLE_FAST_ADV)
-  {
-    Min_Inter = AdvIntervalMin;
-    Max_Inter = AdvIntervalMax;
-  }
-  else
-  {
-    Min_Inter = CFG_LP_CONN_ADV_INTERVAL_MIN;
-    Max_Inter = CFG_LP_CONN_ADV_INTERVAL_MAX;
-  }
-
-    /**
-     * Stop the timer, it will be restarted for a new shot
-     * It does not hurt if the timer was not running
-     */
-    HW_TS_Stop(BleApplicationContext.Advertising_mgr_timer_Id);
-
-    APP_DBG_MSG("First index in %d state \r\n", BleApplicationContext.Device_Connection_Status);
-
-    if ((New_Status == APP_BLE_LP_ADV)
-        && ((BleApplicationContext.Device_Connection_Status == APP_BLE_FAST_ADV)
-            || (BleApplicationContext.Device_Connection_Status == APP_BLE_LP_ADV)))
-    {
-      /* Connection in ADVERTISE mode have to stop the current advertising */
-      ret = aci_gap_set_non_discoverable();
-      if (ret == BLE_STATUS_SUCCESS)
-      {
-        APP_DBG_MSG("Successfully Stopped Advertising \r\n");
-      }
-      else
-      {
-        APP_DBG_MSG("Stop Advertising Failed , result: %d \r\n", ret);
-      }
-    }
-
-    BleApplicationContext.Device_Connection_Status = New_Status;
-
-    const char* name = furi_hal_version_get_ble_local_device_name_ptr();
-
-    /* Start Fast or Low Power Advertising */
-    ret = aci_gap_set_discoverable(
-        ADV_IND,
-        Min_Inter,
-        Max_Inter,
-        PUBLIC_ADDR,
-        NO_WHITE_LIST_USE, /* use white list */
-        strlen(name),
-        (uint8_t*)name,
-        BleApplicationContext.BleApplicationContext_legacy.advtServUUIDlen,
-        BleApplicationContext.BleApplicationContext_legacy.advtServUUID,
-        0,
-        0);
-    if(ret) {
-      FURI_LOG_E("APP ble", "Set discoverable err: %d", ret);
-    }
-
-    /* Update Advertising data */
-    ret = aci_gap_update_adv_data(sizeof(manuf_data), (uint8_t*) manuf_data);
-    if (ret == BLE_STATUS_SUCCESS) {
-      if (New_Status == APP_BLE_FAST_ADV) {
-        APP_DBG_MSG("Successfully Start Fast Advertising \r\n" );
-        /* Start Timer to STOP ADV - TIMEOUT */
-        HW_TS_Start(BleApplicationContext.Advertising_mgr_timer_Id, INITIAL_ADV_TIMEOUT);
-      } else {
-        APP_DBG_MSG("Successfully Start Low Power Advertising \r\n");
-      }
-    } else {
-      if (New_Status == APP_BLE_FAST_ADV) {
-        APP_DBG_MSG("Start Fast Advertising Failed , result: %d \r\n", ret);
-      } else {
-        APP_DBG_MSG("Start Low Power Advertising Failed , result: %d \r\n", ret);
-      }
-    }
-}
-
-const uint8_t* BleGetBdAddress( void ) {
-  uint8_t *otp_addr;
-  const uint8_t *bd_addr;
-  uint32_t udn;
-  uint32_t company_id;
-  uint32_t device_id;
-
-  udn = LL_FLASH_GetUDN();
-
-  if(udn != 0xFFFFFFFF) {
-    company_id = LL_FLASH_GetSTCompanyID();
-    device_id = LL_FLASH_GetDeviceID();
-
-    bd_addr_udn[0] = (uint8_t)(udn & 0x000000FF);
-    bd_addr_udn[1] = (uint8_t)( (udn & 0x0000FF00) >> 8 );
-    bd_addr_udn[2] = (uint8_t)( (udn & 0x00FF0000) >> 16 );
-    bd_addr_udn[3] = (uint8_t)device_id;
-    bd_addr_udn[4] = (uint8_t)(company_id & 0x000000FF);;
-    bd_addr_udn[5] = (uint8_t)( (company_id & 0x0000FF00) >> 8 );
-
-    bd_addr = (const uint8_t *)bd_addr_udn;
-  } else {
-    otp_addr = OTP_Read(0);
-    if(otp_addr) {
-      bd_addr = ((OTP_ID0_t*)otp_addr)->bd_address;
-    } else {
-      bd_addr = M_bd_addr;
-    }
-  }
-
-  return bd_addr;
-}
-
-/*************************************************************
- *
- *SPECIFIC FUNCTIONS
- *
- *************************************************************/
-static void Adv_Mgr( void ) {
-  /**
-   * The code shall be executed in the background as an aci command may be sent
-   * The background is the only place where the application can make sure a new aci command
-   * is not sent if there is a pending one
-   */
-  osThreadFlagsSet( AdvUpdateProcessId, 1 );
-}
-
-static void AdvUpdateProcess(void *argument) {
-  UNUSED(argument);
-
-  for(;;) {
-    osThreadFlagsWait( 1, osFlagsWaitAny, osWaitForever);
-    Adv_Update( );
-  }
-}
-
-static void Adv_Update( void ) {
-  Adv_Request(APP_BLE_LP_ADV);
-
-}
-
 static void HciUserEvtProcess(void *argument) {
 static void HciUserEvtProcess(void *argument) {
   UNUSED(argument);
   UNUSED(argument);
 
 

+ 0 - 13
firmware/targets/f6/ble-glue/app_ble.h

@@ -7,20 +7,7 @@ extern "C" {
 #include <stdbool.h>
 #include <stdbool.h>
 #include "hci_tl.h"
 #include "hci_tl.h"
 
 
-typedef enum {
-    APP_BLE_IDLE,
-    APP_BLE_FAST_ADV,
-    APP_BLE_LP_ADV,
-    APP_BLE_SCAN,
-    APP_BLE_LP_CONNECTING,
-    APP_BLE_CONNECTED_SERVER,
-    APP_BLE_CONNECTED_CLIENT
-} APP_BLE_ConnStatus_t;
-
 bool APP_BLE_Init();
 bool APP_BLE_Init();
-bool APP_BLE_Start();
-
-APP_BLE_ConnStatus_t APP_BLE_Get_Server_Connection_Status();
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 }
 }

+ 1 - 1
firmware/targets/f6/ble-glue/app_conf.h

@@ -139,7 +139,7 @@
 /**
 /**
  * Maximum supported ATT_MTU size
  * Maximum supported ATT_MTU size
  */
  */
-#define CFG_BLE_MAX_ATT_MTU             (156)
+#define CFG_BLE_MAX_ATT_MTU             (251)
 
 
 /**
 /**
  * Size of the storage area for Attribute values
  * Size of the storage area for Attribute values

+ 34 - 11
firmware/targets/f6/ble-glue/battery_service.c

@@ -11,21 +11,22 @@ typedef struct {
     uint16_t char_level_handle;
     uint16_t char_level_handle;
 } BatterySvc;
 } BatterySvc;
 
 
-static BatterySvc battery_svc;
+static BatterySvc* battery_svc = NULL;
 
 
-bool battery_svc_init() {
+static const uint16_t service_uuid = BATTERY_SERVICE_UUID;
+static const uint16_t char_battery_level_uuid = BATTERY_LEVEL_CHAR_UUID;
+
+void battery_svc_start() {
+    battery_svc = furi_alloc(sizeof(BatterySvc));
     tBleStatus status;
     tBleStatus status;
-    const uint16_t service_uuid = BATTERY_SERVICE_UUID;
-    const uint16_t char_battery_level_uuid = BATTERY_LEVEL_CHAR_UUID;
 
 
     // Add Battery service
     // Add Battery service
-    status = aci_gatt_add_service(UUID_TYPE_16, (Service_UUID_t*)&service_uuid, PRIMARY_SERVICE, 4, &battery_svc.svc_handle);
+    status = aci_gatt_add_service(UUID_TYPE_16, (Service_UUID_t*)&service_uuid, PRIMARY_SERVICE, 4, &battery_svc->svc_handle);
     if(status) {
     if(status) {
         FURI_LOG_E(BATTERY_SERVICE_TAG, "Failed to add Battery service: %d", status);
         FURI_LOG_E(BATTERY_SERVICE_TAG, "Failed to add Battery service: %d", status);
     }
     }
-
     // Add Battery level characteristic
     // Add Battery level characteristic
-    status = aci_gatt_add_char(battery_svc.svc_handle,
+    status = aci_gatt_add_char(battery_svc->svc_handle,
                                 UUID_TYPE_16,
                                 UUID_TYPE_16,
                                 (Char_UUID_t *) &char_battery_level_uuid,
                                 (Char_UUID_t *) &char_battery_level_uuid,
                                 1,
                                 1,
@@ -34,17 +35,39 @@ bool battery_svc_init() {
                                 GATT_DONT_NOTIFY_EVENTS,
                                 GATT_DONT_NOTIFY_EVENTS,
                                 10,
                                 10,
                                 CHAR_VALUE_LEN_CONSTANT,
                                 CHAR_VALUE_LEN_CONSTANT,
-                                &battery_svc.char_level_handle);
+                                &battery_svc->char_level_handle);
     if(status) {
     if(status) {
         FURI_LOG_E(BATTERY_SERVICE_TAG, "Failed to add Battery level characteristic: %d", status);
         FURI_LOG_E(BATTERY_SERVICE_TAG, "Failed to add Battery level characteristic: %d", status);
     }
     }
-    return status != BLE_STATUS_SUCCESS;
+}
+
+void battery_svc_stop() {
+    tBleStatus status;
+    if(battery_svc) {
+        // Delete Battery level characteristic
+        status = aci_gatt_del_char(battery_svc->svc_handle, battery_svc->char_level_handle);
+        if(status) {
+            FURI_LOG_E(BATTERY_SERVICE_TAG, "Failed to delete Battery level characteristic: %d", status);
+        }
+        // Delete Battery service
+        status = aci_gatt_del_service(battery_svc->svc_handle);
+        if(status) {
+            FURI_LOG_E(BATTERY_SERVICE_TAG, "Failed to delete Battery service: %d", status);
+        }
+        free(battery_svc);
+        battery_svc = NULL;
+    }
 }
 }
 
 
 bool battery_svc_update_level(uint8_t battery_charge) {
 bool battery_svc_update_level(uint8_t battery_charge) {
+    // Check if service was started
+    if(battery_svc == NULL) {
+        return false;
+    }
+    // Update battery level characteristic
     FURI_LOG_I(BATTERY_SERVICE_TAG, "Updating battery level characteristic");
     FURI_LOG_I(BATTERY_SERVICE_TAG, "Updating battery level characteristic");
-    tBleStatus result = aci_gatt_update_char_value(battery_svc.svc_handle,
-                                          battery_svc.char_level_handle,
+    tBleStatus result = aci_gatt_update_char_value(battery_svc->svc_handle,
+                                          battery_svc->char_level_handle,
                                           0,
                                           0,
                                           1,
                                           1,
                                           &battery_charge);
                                           &battery_charge);

+ 3 - 1
firmware/targets/f6/ble-glue/battery_service.h

@@ -7,7 +7,9 @@
 extern "C" {
 extern "C" {
 #endif
 #endif
 
 
-bool battery_svc_init();
+void battery_svc_start();
+
+void battery_svc_stop();
 
 
 bool battery_svc_update_level(uint8_t battery_level);
 bool battery_svc_update_level(uint8_t battery_level);
 
 

+ 78 - 43
firmware/targets/f6/ble-glue/dev_info_service.c

@@ -4,7 +4,7 @@
 
 
 #include <furi.h>
 #include <furi.h>
 
 
-#define DEV_INFO_SERVICE_TAG "dev info service"
+#define DEV_INFO_SVC_TAG "dev info service"
 
 
 typedef struct {
 typedef struct {
     uint16_t service_handle;
     uint16_t service_handle;
@@ -14,108 +14,143 @@ typedef struct {
     uint16_t software_rev_char_handle;
     uint16_t software_rev_char_handle;
 } DevInfoSvc;
 } DevInfoSvc;
 
 
-bool dev_info_service_init() {
+static DevInfoSvc* dev_info_svc = NULL;
+
+static const char dev_info_man_name[] = "Flipper Devices Inc.";
+static const char dev_info_serial_num[] = "1.0";
+static const char dev_info_firmware_rev_num[] = TARGET;
+static const char dev_info_software_rev_num[] = GIT_COMMIT " " GIT_BRANCH " " GIT_BRANCH_NUM " " BUILD_DATE;
+
+void dev_info_svc_start() {
+    dev_info_svc = furi_alloc(sizeof(DevInfoSvc));
     tBleStatus status;
     tBleStatus status;
-    DevInfoSvc dev_info_svc;
 
 
     // Add Device Information Service
     // Add Device Information Service
     uint16_t uuid = DEVICE_INFORMATION_SERVICE_UUID;
     uint16_t uuid = DEVICE_INFORMATION_SERVICE_UUID;
-    status = aci_gatt_add_service(UUID_TYPE_16, (Service_UUID_t*)&uuid, PRIMARY_SERVICE, 9, &dev_info_svc.service_handle);
+    status = aci_gatt_add_service(UUID_TYPE_16, (Service_UUID_t*)&uuid, PRIMARY_SERVICE, 9, &dev_info_svc->service_handle);
     if(status) {
     if(status) {
-        FURI_LOG_E(DEV_INFO_SERVICE_TAG, "Failed to add Device Information Service: %d", status);
+        FURI_LOG_E(DEV_INFO_SVC_TAG, "Failed to add Device Information Service: %d", status);
     }
     }
 
 
     // Add characteristics
     // Add characteristics
     uuid = MANUFACTURER_NAME_UUID;
     uuid = MANUFACTURER_NAME_UUID;
-    status = aci_gatt_add_char(dev_info_svc.service_handle,
+    status = aci_gatt_add_char(dev_info_svc->service_handle,
                                 UUID_TYPE_16,
                                 UUID_TYPE_16,
                                 (Char_UUID_t*)&uuid,
                                 (Char_UUID_t*)&uuid,
-                                strlen(DEV_INFO_MANUFACTURER_NAME),
+                                strlen(dev_info_man_name),
                                 CHAR_PROP_READ,
                                 CHAR_PROP_READ,
                                 ATTR_PERMISSION_NONE,
                                 ATTR_PERMISSION_NONE,
                                 GATT_DONT_NOTIFY_EVENTS,
                                 GATT_DONT_NOTIFY_EVENTS,
                                 10,
                                 10,
                                 CHAR_VALUE_LEN_CONSTANT,
                                 CHAR_VALUE_LEN_CONSTANT,
-                                &dev_info_svc.man_name_char_handle);
+                                &dev_info_svc->man_name_char_handle);
     if(status) {
     if(status) {
-        FURI_LOG_E(DEV_INFO_SERVICE_TAG, "Failed to add manufacturer name char: %d", status);
-
+        FURI_LOG_E(DEV_INFO_SVC_TAG, "Failed to add manufacturer name char: %d", status);
     }
     }
     uuid = SERIAL_NUMBER_UUID;
     uuid = SERIAL_NUMBER_UUID;
-    status = aci_gatt_add_char(dev_info_svc.service_handle,
+    status = aci_gatt_add_char(dev_info_svc->service_handle,
                                 UUID_TYPE_16,
                                 UUID_TYPE_16,
                                 (Char_UUID_t*)&uuid,
                                 (Char_UUID_t*)&uuid,
-                                strlen(DEV_INFO_SERIAL_NUMBER),
+                                strlen(dev_info_serial_num),
                                 CHAR_PROP_READ,
                                 CHAR_PROP_READ,
                                 ATTR_PERMISSION_NONE,
                                 ATTR_PERMISSION_NONE,
                                 GATT_DONT_NOTIFY_EVENTS,
                                 GATT_DONT_NOTIFY_EVENTS,
                                 10,
                                 10,
                                 CHAR_VALUE_LEN_CONSTANT,
                                 CHAR_VALUE_LEN_CONSTANT,
-                                &dev_info_svc.serial_num_char_handle);
+                                &dev_info_svc->serial_num_char_handle);
     if(status) {
     if(status) {
-        FURI_LOG_E(DEV_INFO_SERVICE_TAG, "Failed to add serial number char: %d", status);
+        FURI_LOG_E(DEV_INFO_SVC_TAG, "Failed to add serial number char: %d", status);
     }
     }
     uuid = FIRMWARE_REVISION_UUID;
     uuid = FIRMWARE_REVISION_UUID;
-    status = aci_gatt_add_char(dev_info_svc.service_handle,
+    status = aci_gatt_add_char(dev_info_svc->service_handle,
                                 UUID_TYPE_16,
                                 UUID_TYPE_16,
                                 (Char_UUID_t*)&uuid,
                                 (Char_UUID_t*)&uuid,
-                                strlen(DEV_INFO_FIRMWARE_REVISION_NUMBER),
+                                strlen(dev_info_firmware_rev_num),
                                 CHAR_PROP_READ,
                                 CHAR_PROP_READ,
                                 ATTR_PERMISSION_NONE,
                                 ATTR_PERMISSION_NONE,
                                 GATT_DONT_NOTIFY_EVENTS,
                                 GATT_DONT_NOTIFY_EVENTS,
                                 10,
                                 10,
                                 CHAR_VALUE_LEN_CONSTANT,
                                 CHAR_VALUE_LEN_CONSTANT,
-                                &dev_info_svc.firmware_rev_char_handle);
+                                &dev_info_svc->firmware_rev_char_handle);
     if(status) {
     if(status) {
-        FURI_LOG_E(DEV_INFO_SERVICE_TAG, "Failed to add firmware revision char: %d", status);
+        FURI_LOG_E(DEV_INFO_SVC_TAG, "Failed to add firmware revision char: %d", status);
     }
     }
     uuid = SOFTWARE_REVISION_UUID;
     uuid = SOFTWARE_REVISION_UUID;
-    status = aci_gatt_add_char(dev_info_svc.service_handle,
+    status = aci_gatt_add_char(dev_info_svc->service_handle,
                                 UUID_TYPE_16,
                                 UUID_TYPE_16,
                                 (Char_UUID_t*)&uuid,
                                 (Char_UUID_t*)&uuid,
-                                strlen(DEV_INFO_SOFTWARE_REVISION_NUMBER),
+                                strlen(dev_info_software_rev_num),
                                 CHAR_PROP_READ,
                                 CHAR_PROP_READ,
                                 ATTR_PERMISSION_NONE,
                                 ATTR_PERMISSION_NONE,
                                 GATT_DONT_NOTIFY_EVENTS,
                                 GATT_DONT_NOTIFY_EVENTS,
                                 10,
                                 10,
                                 CHAR_VALUE_LEN_CONSTANT,
                                 CHAR_VALUE_LEN_CONSTANT,
-                                &dev_info_svc.software_rev_char_handle);
+                                &dev_info_svc->software_rev_char_handle);
     if(status) {
     if(status) {
-        FURI_LOG_E(DEV_INFO_SERVICE_TAG, "Failed to add software revision char: %d", status);
+        FURI_LOG_E(DEV_INFO_SVC_TAG, "Failed to add software revision char: %d", status);
     }
     }
 
 
     // Update characteristics
     // Update characteristics
-    status = aci_gatt_update_char_value(dev_info_svc.service_handle,
-                                        dev_info_svc.man_name_char_handle,
+    status = aci_gatt_update_char_value(dev_info_svc->service_handle,
+                                        dev_info_svc->man_name_char_handle,
                                         0,
                                         0,
-                                        strlen(DEV_INFO_MANUFACTURER_NAME),
-                                        (uint8_t*)DEV_INFO_MANUFACTURER_NAME);
+                                        strlen(dev_info_man_name),
+                                        (uint8_t*)dev_info_man_name);
     if(status) {
     if(status) {
-        FURI_LOG_E(DEV_INFO_SERVICE_TAG, "Failed to update manufacturer name char: %d", status);
+        FURI_LOG_E(DEV_INFO_SVC_TAG, "Failed to update manufacturer name char: %d", status);
     }
     }
-    status = aci_gatt_update_char_value(dev_info_svc.service_handle,
-                                        dev_info_svc.serial_num_char_handle,
+    status = aci_gatt_update_char_value(dev_info_svc->service_handle,
+                                        dev_info_svc->serial_num_char_handle,
                                         0,
                                         0,
-                                        strlen(DEV_INFO_SERIAL_NUMBER),
-                                        (uint8_t*)DEV_INFO_SERIAL_NUMBER);
+                                        strlen(dev_info_serial_num),
+                                        (uint8_t*)dev_info_serial_num);
     if(status) {
     if(status) {
-        FURI_LOG_E(DEV_INFO_SERVICE_TAG, "Failed to update serial number char: %d", status);
+        FURI_LOG_E(DEV_INFO_SVC_TAG, "Failed to update serial number char: %d", status);
     }
     }
-    status = aci_gatt_update_char_value(dev_info_svc.service_handle,
-                                        dev_info_svc.firmware_rev_char_handle,
+    status = aci_gatt_update_char_value(dev_info_svc->service_handle,
+                                        dev_info_svc->firmware_rev_char_handle,
                                         0,
                                         0,
-                                        strlen(DEV_INFO_FIRMWARE_REVISION_NUMBER),
-                                        (uint8_t*)DEV_INFO_FIRMWARE_REVISION_NUMBER);
+                                        strlen(dev_info_firmware_rev_num),
+                                        (uint8_t*)dev_info_firmware_rev_num);
     if(status) {
     if(status) {
-        FURI_LOG_E(DEV_INFO_SERVICE_TAG, "Failed to update firmware revision char: %d", status);
+        FURI_LOG_E(DEV_INFO_SVC_TAG, "Failed to update firmware revision char: %d", status);
     }
     }
-    status = aci_gatt_update_char_value(dev_info_svc.service_handle,
-                                        dev_info_svc.software_rev_char_handle,
+    status = aci_gatt_update_char_value(dev_info_svc->service_handle,
+                                        dev_info_svc->software_rev_char_handle,
                                         0,
                                         0,
-                                        strlen(DEV_INFO_SOFTWARE_REVISION_NUMBER),
-                                        (uint8_t*)DEV_INFO_SOFTWARE_REVISION_NUMBER);
+                                        strlen(dev_info_software_rev_num),
+                                        (uint8_t*)dev_info_software_rev_num);
     if(status) {
     if(status) {
-        FURI_LOG_E(DEV_INFO_SERVICE_TAG, "Failed to update software revision char: %d", status);
+        FURI_LOG_E(DEV_INFO_SVC_TAG, "Failed to update software revision char: %d", status);
+    }
+}
+
+void dev_info_svc_stop() {
+    tBleStatus status;
+    if(dev_info_svc) {
+        // Delete service characteristics
+        status = aci_gatt_del_char(dev_info_svc->service_handle, dev_info_svc->man_name_char_handle);
+        if(status) {
+            FURI_LOG_E(DEV_INFO_SVC_TAG, "Failed to delete manufacturer name char: %d", status);
+        }
+        status = aci_gatt_del_char(dev_info_svc->service_handle, dev_info_svc->serial_num_char_handle);
+        if(status) {
+            FURI_LOG_E(DEV_INFO_SVC_TAG, "Failed to delete serial number char: %d", status);
+        }
+        status = aci_gatt_del_char(dev_info_svc->service_handle, dev_info_svc->firmware_rev_char_handle);
+        if(status) {
+            FURI_LOG_E(DEV_INFO_SVC_TAG, "Failed to delete firmware revision char: %d", status);
+        }
+        status = aci_gatt_del_char(dev_info_svc->service_handle, dev_info_svc->software_rev_char_handle);
+        if(status) {
+            FURI_LOG_E(DEV_INFO_SVC_TAG, "Failed to delete software revision char: %d", status);
+        }
+        // Delete service
+        status = aci_gatt_del_service(dev_info_svc->service_handle);
+        if(status) {
+            FURI_LOG_E(DEV_INFO_SVC_TAG, "Failed to delete device info service: %d", status);
+        }
+        free(dev_info_svc);
+        dev_info_svc = NULL;
     }
     }
-    return status != BLE_STATUS_SUCCESS;
 }
 }

+ 2 - 1
firmware/targets/f6/ble-glue/dev_info_service.h

@@ -12,8 +12,9 @@ extern "C" {
 #define DEV_INFO_FIRMWARE_REVISION_NUMBER       TARGET
 #define DEV_INFO_FIRMWARE_REVISION_NUMBER       TARGET
 #define DEV_INFO_SOFTWARE_REVISION_NUMBER       GIT_COMMIT " " GIT_BRANCH " " GIT_BRANCH_NUM " " BUILD_DATE
 #define DEV_INFO_SOFTWARE_REVISION_NUMBER       GIT_COMMIT " " GIT_BRANCH " " GIT_BRANCH_NUM " " BUILD_DATE
 
 
+void dev_info_svc_start();
 
 
-bool dev_info_service_init();
+void dev_info_svc_stop();
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 }
 }

+ 387 - 0
firmware/targets/f6/ble-glue/gap.c

@@ -0,0 +1,387 @@
+#include "gap.h"
+
+#include "app_entry.h"
+#include "ble.h"
+
+#include "cmsis_os.h"
+#include "otp.h"
+#include "dev_info_service.h"
+#include "battery_service.h"
+#include "serial_service.h"
+
+#include <applications/bt/bt_service/bt.h>
+#include <furi-hal.h>
+
+#define GAP_TAG "BLE"
+
+#define FAST_ADV_TIMEOUT 30000
+#define INITIAL_ADV_TIMEOUT 60000
+
+#define BD_ADDR_SIZE_LOCAL 6
+
+typedef struct {
+  uint16_t gap_svc_handle;
+  uint16_t dev_name_char_handle;
+  uint16_t appearance_char_handle;
+  uint16_t connection_handle;
+  uint8_t adv_svc_uuid_len;
+  uint8_t adv_svc_uuid[20];
+} GapSvc;
+
+typedef struct {
+  GapSvc gap_svc;
+  GapState state;
+  uint8_t mac_address[BD_ADDR_SIZE_LOCAL];
+  Bt* bt;
+  osTimerId advertise_timer;
+  osThreadAttr_t thread_attr;
+  osThreadId_t thread_id;
+} Gap;
+
+// Identity root key
+static const uint8_t gap_irk[16] = {0x12,0x34,0x56,0x78,0x9a,0xbc,0xde,0xf0,0x12,0x34,0x56,0x78,0x9a,0xbc,0xde,0xf0};
+// Encryption root key
+static const uint8_t gap_erk[16] = {0xfe,0xdc,0xba,0x09,0x87,0x65,0x43,0x21,0xfe,0xdc,0xba,0x09,0x87,0x65,0x43,0x21};
+// Appearence characteristic UUID
+static const uint8_t gap_appearence_char_uuid[] = {0x00, 0x86};
+// Default MAC address
+static const uint8_t gap_default_mac_addr[] = {0x6c, 0x7a, 0xd8, 0xac, 0x57, 0x72};
+
+static Gap* gap = NULL;
+
+static void gap_advertise(GapState new_state);
+static void gap_app(void *arg);
+
+SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification( void *pckt )
+{
+  hci_event_pckt *event_pckt;
+  evt_le_meta_event *meta_evt;
+  evt_blue_aci *blue_evt;
+  hci_le_phy_update_complete_event_rp0 *evt_le_phy_update_complete;
+  uint8_t tx_phy;
+  uint8_t rx_phy;
+  tBleStatus ret = BLE_STATUS_INVALID_PARAMS;
+
+  event_pckt = (hci_event_pckt*) ((hci_uart_pckt *) pckt)->data;
+
+  switch (event_pckt->evt) {
+    case EVT_DISCONN_COMPLETE:
+    {
+        hci_disconnection_complete_event_rp0 *disconnection_complete_event = (hci_disconnection_complete_event_rp0 *) event_pckt->data;
+        if (disconnection_complete_event->Connection_Handle == gap->gap_svc.connection_handle) {
+            gap->gap_svc.connection_handle = 0;
+            gap->state = GapStateIdle;
+            FURI_LOG_I(GAP_TAG, "Disconnect from client");
+        }
+        // Restart advertising
+        gap_advertise(GapStateAdvFast);
+        furi_hal_power_insomnia_exit();
+    }
+    break;
+
+    case EVT_LE_META_EVENT:
+        meta_evt = (evt_le_meta_event*) event_pckt->data;
+        switch (meta_evt->subevent) {
+            case EVT_LE_CONN_UPDATE_COMPLETE:
+            FURI_LOG_D(GAP_TAG, "Connection update event");
+            break;
+
+            case EVT_LE_PHY_UPDATE_COMPLETE:
+            evt_le_phy_update_complete = (hci_le_phy_update_complete_event_rp0*)meta_evt->data;
+            if(evt_le_phy_update_complete->Status) {
+                FURI_LOG_E(GAP_TAG, "Update PHY failed, status %d", evt_le_phy_update_complete->Status);
+            } else {
+                FURI_LOG_I(GAP_TAG, "Update PHY succeed");
+            }
+            ret = hci_le_read_phy(gap->gap_svc.connection_handle,&tx_phy,&rx_phy);
+            if(ret) {
+                FURI_LOG_E(GAP_TAG, "Read PHY failed, status: %d", ret);
+            } else {
+                FURI_LOG_I(GAP_TAG, "PHY Params TX= %d, RX= %d ", tx_phy, rx_phy);
+            }
+            break;
+
+            case EVT_LE_CONN_COMPLETE:
+            furi_hal_power_insomnia_enter();
+            hci_le_connection_complete_event_rp0* connection_complete_event = (hci_le_connection_complete_event_rp0 *) meta_evt->data;
+            FURI_LOG_I(GAP_TAG, "Connection complete for connection handle 0x%x", connection_complete_event->Connection_Handle);
+
+            // Stop advertising as connection completed
+            osTimerStop(gap->advertise_timer);
+
+            // Update connection status and handle
+            gap->state = GapStateConnected;
+            gap->gap_svc.connection_handle = connection_complete_event->Connection_Handle;
+
+            // Start pairing by sending security request
+            aci_gap_slave_security_req(connection_complete_event->Connection_Handle);
+            break;
+
+            default:
+            break;
+        }
+    break;
+
+    case EVT_VENDOR:
+        blue_evt = (evt_blue_aci*) event_pckt->data;
+        switch (blue_evt->ecode) {
+            aci_gap_pairing_complete_event_rp0 *pairing_complete;
+
+        case EVT_BLUE_GAP_LIMITED_DISCOVERABLE:
+            FURI_LOG_I(GAP_TAG, "Limited discoverable event");
+            break;
+
+        case EVT_BLUE_GAP_PASS_KEY_REQUEST:
+        {
+            // Generate random PIN code
+            uint32_t pin = rand() % 999999;
+            aci_gap_pass_key_resp(gap->gap_svc.connection_handle, pin);
+            FURI_LOG_I(GAP_TAG, "Pass key request event. Pin: %d", pin);
+            bt_pin_code_show(gap->bt, pin);
+        }
+            break;
+
+        case EVT_BLUE_GAP_AUTHORIZATION_REQUEST:
+            FURI_LOG_I(GAP_TAG, "Authorization request event");
+            break;
+
+        case EVT_BLUE_GAP_SLAVE_SECURITY_INITIATED:
+            FURI_LOG_I(GAP_TAG, "Slave security initiated");
+            break;
+
+        case EVT_BLUE_GAP_BOND_LOST:
+            FURI_LOG_I(GAP_TAG, "Bond lost event. Start rebonding");
+            aci_gap_allow_rebond(gap->gap_svc.connection_handle);
+            break;
+
+        case EVT_BLUE_GAP_DEVICE_FOUND:
+            FURI_LOG_I(GAP_TAG, "Device found event");
+            break;
+
+        case EVT_BLUE_GAP_ADDR_NOT_RESOLVED:
+            FURI_LOG_I(GAP_TAG, "Address not resolved event");
+            break;
+
+        case EVT_BLUE_GAP_KEYPRESS_NOTIFICATION:
+            FURI_LOG_I(GAP_TAG, "Key press notification event");
+            break;
+
+        case EVT_BLUE_GAP_NUMERIC_COMPARISON_VALUE:
+            FURI_LOG_I(GAP_TAG, "Hex_value = %lx",
+                        ((aci_gap_numeric_comparison_value_event_rp0 *)(blue_evt->data))->Numeric_Value);
+            aci_gap_numeric_comparison_value_confirm_yesno(gap->gap_svc.connection_handle, 1);
+            break;
+
+        case (EVT_BLUE_GAP_PAIRING_CMPLT):
+        {
+            pairing_complete = (aci_gap_pairing_complete_event_rp0*)blue_evt->data;
+            if (pairing_complete->Status) {
+            FURI_LOG_E(GAP_TAG, "Pairing failed with status: %d. Terminating connection", pairing_complete->Status);
+            aci_gap_terminate(gap->gap_svc.connection_handle, 5);
+            } else {
+            FURI_LOG_I(GAP_TAG, "Pairing complete");
+            }
+        }
+            break;
+
+        case EVT_BLUE_GAP_PROCEDURE_COMPLETE:
+            FURI_LOG_I(GAP_TAG, "Procedure complete event");
+            break;
+        }
+        default:
+            break;
+  }
+
+  return SVCCTL_UserEvtFlowEnable;
+}
+
+void SVCCTL_SvcInit() {
+    // Dummy function to prevent unused services initialization
+    // TODO refactor (disable all services in WPAN config)
+}
+
+static void set_advertisment_service_uid(uint8_t* uid, uint8_t uid_len) {
+    gap->gap_svc.adv_svc_uuid_len = 1;
+    if(uid_len == 2) {
+        gap->gap_svc.adv_svc_uuid[0] = AD_TYPE_16_BIT_SERV_UUID;
+    } else if (uid_len == 4) {
+        gap->gap_svc.adv_svc_uuid[0] = AD_TYPE_32_BIT_SERV_UUID;
+    } else if(uid_len == 16) {
+        gap->gap_svc.adv_svc_uuid[0] = AD_TYPE_128_BIT_SERV_UUID_CMPLT_LIST;
+    }
+    memcpy(&gap->gap_svc.adv_svc_uuid[1], uid, uid_len);
+    gap->gap_svc.adv_svc_uuid_len += uid_len;
+}
+
+GapState gap_get_status() {
+    return gap->state;
+}
+
+void gap_init_mac_address(Gap* gap) {
+    uint8_t *otp_addr;
+    uint32_t udn;
+    uint32_t company_id;
+    uint32_t device_id;
+
+    udn = LL_FLASH_GetUDN();
+    if(udn != 0xFFFFFFFF) {
+        company_id = LL_FLASH_GetSTCompanyID();
+        device_id = LL_FLASH_GetDeviceID();
+        gap->mac_address[0] = (uint8_t)(udn & 0x000000FF);
+        gap->mac_address[1] = (uint8_t)( (udn & 0x0000FF00) >> 8 );
+        gap->mac_address[2] = (uint8_t)( (udn & 0x00FF0000) >> 16 );
+        gap->mac_address[3] = (uint8_t)device_id;
+        gap->mac_address[4] = (uint8_t)(company_id & 0x000000FF);;
+        gap->mac_address[5] = (uint8_t)( (company_id & 0x0000FF00) >> 8 );
+    } else {
+        otp_addr = OTP_Read(0);
+        if(otp_addr) {
+            memcpy(gap->mac_address, ((OTP_ID0_t*)otp_addr)->bd_address, sizeof(gap->mac_address));
+        } else {
+            memcpy(gap->mac_address, gap_default_mac_addr, sizeof(gap->mac_address));
+        }
+    }
+}
+
+static void gap_init_svc(Gap* gap) {
+    tBleStatus status;
+    uint32_t srd_bd_addr[2];
+
+    //HCI Reset to synchronise BLE Stack*/
+    hci_reset();
+    // Configure mac address
+    gap_init_mac_address(gap);
+    aci_hal_write_config_data(CONFIG_DATA_PUBADDR_OFFSET, CONFIG_DATA_PUBADDR_LEN, (uint8_t*)gap->mac_address);
+
+    /* Static random Address
+     * The two upper bits shall be set to 1
+     * The lowest 32bits is read from the UDN to differentiate between devices
+     * The RNG may be used to provide a random number on each power on
+     */
+    srd_bd_addr[1] = 0x0000ED6E;
+    srd_bd_addr[0] = LL_FLASH_GetUDN();
+    aci_hal_write_config_data( CONFIG_DATA_RANDOM_ADDRESS_OFFSET, CONFIG_DATA_RANDOM_ADDRESS_LEN, (uint8_t*)srd_bd_addr );
+    // Set Identity root key used to derive LTK and CSRK
+    aci_hal_write_config_data( CONFIG_DATA_IR_OFFSET, CONFIG_DATA_IR_LEN, (uint8_t*)gap_irk );
+    // Set Encryption root key used to derive LTK and CSRK
+    aci_hal_write_config_data( CONFIG_DATA_ER_OFFSET, CONFIG_DATA_ER_LEN, (uint8_t*)gap_erk );
+    // Set TX Power to 0 dBm
+    aci_hal_set_tx_power_level(1, 0x19);
+    // Initialize GATT interface
+    aci_gatt_init();
+    // Initialize GAP interface
+    const char *name = furi_hal_version_get_device_name_ptr();
+    aci_gap_init(GAP_PERIPHERAL_ROLE, 0, strlen(name),
+                &gap->gap_svc.gap_svc_handle, &gap->gap_svc.dev_name_char_handle, &gap->gap_svc.appearance_char_handle);
+
+    // Set GAP characteristics
+    status = aci_gatt_update_char_value(gap->gap_svc.gap_svc_handle, gap->gap_svc.dev_name_char_handle, 0, strlen(name), (uint8_t *) name);
+    if (status) {
+        FURI_LOG_E(GAP_TAG, "Failed updating name characteristic: %d", status);
+    }
+    status = aci_gatt_update_char_value(gap->gap_svc.gap_svc_handle, gap->gap_svc.appearance_char_handle, 0, 2, gap_appearence_char_uuid);
+    if(status) {
+        FURI_LOG_E(GAP_TAG, "Failed updating appearence characteristic: %d", status);
+    }
+    // Set default PHY
+    hci_le_set_default_phy(ALL_PHYS_PREFERENCE, TX_2M_PREFERRED, RX_2M_PREFERRED);
+    // Set I/O capability
+    aci_gap_set_io_capability(IO_CAP_DISPLAY_ONLY);
+    // Setup  authentication
+    aci_gap_set_authentication_requirement(1, 1, 1, 0, 8, 16, 1, 0, PUBLIC_ADDR);
+    // Configure whitelist
+    aci_gap_configure_whitelist();
+}
+
+static void gap_advertise(GapState new_state)
+{
+    tBleStatus status;
+    uint16_t min_interval;
+    uint16_t max_interval;
+
+    if (new_state == GapStateAdvFast) {
+        min_interval = 0x80; // 80 ms
+        max_interval = 0xa0; // 100 ms
+    } else {
+        min_interval = 0x0640; // 1 s
+        max_interval = 0x0fa0; // 2.5 s
+    }
+    // Stop advertising timer
+    osTimerStop(gap->advertise_timer);
+
+    if ((new_state == GapStateAdvLowPower) && ((gap->state == GapStateAdvFast) || (gap->state == GapStateAdvLowPower))) {
+        // Stop advertising
+        status = aci_gap_set_non_discoverable();
+        if (status) {
+            FURI_LOG_E(GAP_TAG, "Stop Advertising Failed, result: %d", status);
+        }
+    }
+    // Configure advertising
+    gap->state = new_state;
+    const char* name = furi_hal_version_get_ble_local_device_name_ptr();
+    status = aci_gap_set_discoverable(ADV_IND, min_interval, max_interval, PUBLIC_ADDR, 0,
+                                        strlen(name), (uint8_t*)name,
+                                        gap->gap_svc.adv_svc_uuid_len, gap->gap_svc.adv_svc_uuid, 0, 0);
+    if(status) {
+        FURI_LOG_E(GAP_TAG, "Set discoverable err: %d", status);
+    }
+    osTimerStart(gap->advertise_timer, INITIAL_ADV_TIMEOUT);
+}
+
+static void gap_advertise_request(Gap* gap) {
+    osThreadFlagsSet(gap->thread_id, 1);
+}
+
+static void gap_advetise_timer_callback(void* context) {
+    furi_assert(context);
+    Gap* gap = context;
+    gap_advertise_request(gap);
+}
+
+bool gap_init() {
+    if (APPE_Status() != BleGlueStatusStarted) {
+        return false;
+    }
+
+    gap = furi_alloc(sizeof(Gap));
+    srand(DWT->CYCCNT);
+    // Open Bt record
+    gap->bt = furi_record_open("bt");
+    // Create advertising timer
+    gap->advertise_timer = osTimerNew(gap_advetise_timer_callback, osTimerOnce, &gap, NULL);
+    // Initialization of HCI & GATT & GAP layer
+    gap_init_svc(gap);
+    // Initialization of the BLE Services
+    SVCCTL_Init();
+    // Initialization of the BLE App Context
+    gap->state = GapStateIdle;
+    gap->gap_svc.connection_handle = 0xFFFF;
+
+    // Thread configuration
+    gap->thread_attr.name = "BLE advertising";
+    gap->thread_attr.stack_size = 512;
+    gap->thread_id = osThreadNew(gap_app, NULL, &gap->thread_attr);
+
+    // Start Device Information service
+    dev_info_svc_start();
+    // Start Battery service
+    battery_svc_start();
+    // Start Serial application
+    serial_svc_start();
+    // Configure advirtise service UUID
+    uint8_t adv_service_uid[2];
+    adv_service_uid[0] = 0x80 | furi_hal_version_get_hw_color();
+    adv_service_uid[1] = 0x30;
+
+    set_advertisment_service_uid(adv_service_uid, sizeof(adv_service_uid));
+    gap_advertise(GapStateAdvFast);
+    return true;
+}
+
+static void gap_app(void *arg) {
+    // TODO Exit from app, stop service, clean memory
+    while(1) {
+        osThreadFlagsWait(1, osFlagsWaitAny, osWaitForever);
+        gap_advertise(GapStateAdvLowPower);
+    }
+}

+ 22 - 0
firmware/targets/f6/ble-glue/gap.h

@@ -0,0 +1,22 @@
+#pragma once
+
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+    GapStateIdle,
+    GapStateAdvFast,
+    GapStateAdvLowPower,
+    GapStateConnected,
+} GapState;
+
+bool gap_init();
+
+GapState gap_get_status();
+
+#ifdef __cplusplus
+}
+#endif

+ 42 - 22
firmware/targets/f6/ble-glue/serial_service.c

@@ -6,13 +6,19 @@
 
 
 #define SERIAL_SERVICE_TAG "serial service"
 #define SERIAL_SERVICE_TAG "serial service"
 
 
+#define SERIAL_SVC_DATA_LEN_MAX 245
+
 typedef struct {
 typedef struct {
     uint16_t svc_handle;
     uint16_t svc_handle;
     uint16_t rx_char_handle;
     uint16_t rx_char_handle;
     uint16_t tx_char_handle;
     uint16_t tx_char_handle;
 } SerialSvc;
 } SerialSvc;
 
 
-static SerialSvc serial_svc;
+static SerialSvc* serial_svc;
+
+static const uint8_t service_uuid[] = {0x00, 0x00, 0xfe, 0x60, 0xcc, 0x7a, 0x48, 0x2a, 0x98, 0x4a, 0x7f, 0x2e, 0xd5, 0xb3, 0xe5, 0x8f};
+static const uint8_t char_rx_uuid[] = {0x00, 0x00, 0xfe, 0x61, 0x8e, 0x22, 0x45, 0x41, 0x9d, 0x4c, 0x21, 0xed, 0xae, 0x82, 0xed, 0x19};
+static const uint8_t char_tx_uuid[] = {0x00, 0x00, 0xfe, 0x62, 0x8e, 0x22, 0x45, 0x41, 0x9d, 0x4c, 0x21, 0xed, 0xae, 0x82, 0xed, 0x19};
 
 
 static SVCCTL_EvtAckStatus_t serial_svc_event_handler(void *event) {
 static SVCCTL_EvtAckStatus_t serial_svc_event_handler(void *event) {
     SVCCTL_EvtAckStatus_t ret = SVCCTL_EvtNotAck;
     SVCCTL_EvtAckStatus_t ret = SVCCTL_EvtNotAck;
@@ -22,76 +28,90 @@ static SVCCTL_EvtAckStatus_t serial_svc_event_handler(void *event) {
     if(event_pckt->evt == HCI_VENDOR_SPECIFIC_DEBUG_EVT_CODE) {
     if(event_pckt->evt == HCI_VENDOR_SPECIFIC_DEBUG_EVT_CODE) {
         if(blecore_evt->ecode == ACI_GATT_ATTRIBUTE_MODIFIED_VSEVT_CODE) {
         if(blecore_evt->ecode == ACI_GATT_ATTRIBUTE_MODIFIED_VSEVT_CODE) {
             attribute_modified = (aci_gatt_attribute_modified_event_rp0*)blecore_evt->data;
             attribute_modified = (aci_gatt_attribute_modified_event_rp0*)blecore_evt->data;
-            if(attribute_modified->Attr_Handle == serial_svc.tx_char_handle + 2) {
+            if(attribute_modified->Attr_Handle == serial_svc->tx_char_handle + 2) {
                 // Descriptor handle
                 // Descriptor handle
                 ret = SVCCTL_EvtAckFlowEnable;
                 ret = SVCCTL_EvtAckFlowEnable;
                 FURI_LOG_D(SERIAL_SERVICE_TAG, "TX descriptor event");
                 FURI_LOG_D(SERIAL_SERVICE_TAG, "TX descriptor event");
-            } else if(attribute_modified->Attr_Handle == serial_svc.tx_char_handle + 1) {
-                FURI_LOG_I(SERIAL_SERVICE_TAG, "Data len: %d", attribute_modified->Attr_Data_Length);
-                for(uint8_t i = 0; i < attribute_modified->Attr_Data_Length; i++) {
-                    printf("%02X ", attribute_modified->Attr_Data[i]);
-                }
-                printf("\r\n");
+            } else if(attribute_modified->Attr_Handle == serial_svc->tx_char_handle + 1) {
+                FURI_LOG_D(SERIAL_SERVICE_TAG, "Received %d bytes", attribute_modified->Attr_Data_Length);
                 serial_svc_update_rx(attribute_modified->Attr_Data, attribute_modified->Attr_Data_Length);
                 serial_svc_update_rx(attribute_modified->Attr_Data, attribute_modified->Attr_Data_Length);
                 ret = SVCCTL_EvtAckFlowEnable;
                 ret = SVCCTL_EvtAckFlowEnable;
             }
             }
         } else if(blecore_evt->ecode == ACI_GATT_SERVER_CONFIRMATION_VSEVT_CODE) {
         } else if(blecore_evt->ecode == ACI_GATT_SERVER_CONFIRMATION_VSEVT_CODE) {
-            FURI_LOG_I(SERIAL_SERVICE_TAG, "Ack received", blecore_evt->ecode);
+            FURI_LOG_D(SERIAL_SERVICE_TAG, "Ack received", blecore_evt->ecode);
             ret = SVCCTL_EvtAckFlowEnable;
             ret = SVCCTL_EvtAckFlowEnable;
         }
         }
     }
     }
     return ret;
     return ret;
 }
 }
 
 
-bool serial_svc_init() {
+void serial_svc_start() {
     tBleStatus status;
     tBleStatus status;
-    const uint8_t service_uuid[] = {SERIAL_SVC_UUID_128};
-    const uint8_t char_rx_uuid[] = {SERIAL_CHAR_RX_UUID_128};
-    const uint8_t char_tx_uuid[] = {SERIAL_CHAR_TX_UUID_128};
-
+    serial_svc = furi_alloc(sizeof(SerialSvc));
     // Register event handler
     // Register event handler
     SVCCTL_RegisterSvcHandler(serial_svc_event_handler);
     SVCCTL_RegisterSvcHandler(serial_svc_event_handler);
 
 
     // Add service
     // Add service
-    status = aci_gatt_add_service(UUID_TYPE_128, (Service_UUID_t *)service_uuid, PRIMARY_SERVICE, 6, &serial_svc.svc_handle);
+    status = aci_gatt_add_service(UUID_TYPE_128, (Service_UUID_t *)service_uuid, PRIMARY_SERVICE, 6, &serial_svc->svc_handle);
     if(status) {
     if(status) {
         FURI_LOG_E(SERIAL_SERVICE_TAG, "Failed to add Serial service: %d", status);
         FURI_LOG_E(SERIAL_SERVICE_TAG, "Failed to add Serial service: %d", status);
     }
     }
 
 
     // Add TX characteristics
     // Add TX characteristics
-    status = aci_gatt_add_char(serial_svc.svc_handle, UUID_TYPE_128, (const Char_UUID_t*)char_tx_uuid ,
+    status = aci_gatt_add_char(serial_svc->svc_handle, UUID_TYPE_128, (const Char_UUID_t*)char_tx_uuid,
                                 SERIAL_SVC_DATA_LEN_MAX,
                                 SERIAL_SVC_DATA_LEN_MAX,
                                 CHAR_PROP_WRITE_WITHOUT_RESP | CHAR_PROP_WRITE | CHAR_PROP_READ,
                                 CHAR_PROP_WRITE_WITHOUT_RESP | CHAR_PROP_WRITE | CHAR_PROP_READ,
                                 ATTR_PERMISSION_NONE,
                                 ATTR_PERMISSION_NONE,
                                 GATT_NOTIFY_ATTRIBUTE_WRITE,
                                 GATT_NOTIFY_ATTRIBUTE_WRITE,
                                 10,
                                 10,
                                 CHAR_VALUE_LEN_VARIABLE,
                                 CHAR_VALUE_LEN_VARIABLE,
-                                &serial_svc.tx_char_handle);
+                                &serial_svc->tx_char_handle);
     if(status) {
     if(status) {
         FURI_LOG_E(SERIAL_SERVICE_TAG, "Failed to add TX characteristic: %d", status);
         FURI_LOG_E(SERIAL_SERVICE_TAG, "Failed to add TX characteristic: %d", status);
     }
     }
 
 
     // Add RX characteristic
     // Add RX characteristic
-    status = aci_gatt_add_char(serial_svc.svc_handle, UUID_TYPE_128, (const Char_UUID_t*)char_rx_uuid ,
+    status = aci_gatt_add_char(serial_svc->svc_handle, UUID_TYPE_128, (const Char_UUID_t*)char_rx_uuid,
                                 SERIAL_SVC_DATA_LEN_MAX,                                  
                                 SERIAL_SVC_DATA_LEN_MAX,                                  
                                 CHAR_PROP_READ | CHAR_PROP_INDICATE,
                                 CHAR_PROP_READ | CHAR_PROP_INDICATE,
                                 ATTR_PERMISSION_NONE,
                                 ATTR_PERMISSION_NONE,
                                 GATT_DONT_NOTIFY_EVENTS,
                                 GATT_DONT_NOTIFY_EVENTS,
                                 10,
                                 10,
                                 CHAR_VALUE_LEN_VARIABLE,
                                 CHAR_VALUE_LEN_VARIABLE,
-                                &serial_svc.rx_char_handle);
+                                &serial_svc->rx_char_handle);
     if(status) {
     if(status) {
         FURI_LOG_E(SERIAL_SERVICE_TAG, "Failed to add RX characteristic: %d", status);
         FURI_LOG_E(SERIAL_SERVICE_TAG, "Failed to add RX characteristic: %d", status);
     }
     }
+}
 
 
-    return status != BLE_STATUS_SUCCESS;
+void serial_svc_stop() {
+    tBleStatus status;
+    if(serial_svc) {
+        // Delete characteristics
+        status = aci_gatt_del_char(serial_svc->svc_handle, serial_svc->tx_char_handle);
+        if(status) {
+            FURI_LOG_E(SERIAL_SERVICE_TAG, "Failed to delete TX characteristic: %d", status);
+        }
+        status = aci_gatt_del_char(serial_svc->svc_handle, serial_svc->rx_char_handle);
+        if(status) {
+            FURI_LOG_E(SERIAL_SERVICE_TAG, "Failed to delete RX characteristic: %d", status);
+        }
+        // Delete service
+        status = aci_gatt_del_service(serial_svc->svc_handle);
+        if(status) {
+            FURI_LOG_E(SERIAL_SERVICE_TAG, "Failed to delete Serial service: %d", status);
+        }
+        free(serial_svc);
+        serial_svc = NULL;
+    }
 }
 }
 
 
+
 bool serial_svc_update_rx(uint8_t* data, uint8_t data_len) {
 bool serial_svc_update_rx(uint8_t* data, uint8_t data_len) {
     furi_assert(data_len < SERIAL_SVC_DATA_LEN_MAX);
     furi_assert(data_len < SERIAL_SVC_DATA_LEN_MAX);
 
 
-    tBleStatus result = aci_gatt_update_char_value(serial_svc.svc_handle,
-                                          serial_svc.rx_char_handle,
+    tBleStatus result = aci_gatt_update_char_value(serial_svc->svc_handle,
+                                          serial_svc->rx_char_handle,
                                           0,
                                           0,
                                           data_len,
                                           data_len,
                                           data);
                                           data);

+ 2 - 6
firmware/targets/f6/ble-glue/serial_service.h

@@ -7,13 +7,9 @@
 extern "C" {
 extern "C" {
 #endif
 #endif
 
 
-#define SERIAL_SVC_DATA_LEN_MAX 255
+void serial_svc_start();
 
 
-#define SERIAL_SVC_UUID_128 0x00, 0x00, 0xfe, 0x60, 0xcc, 0x7a, 0x48, 0x2a, 0x98, 0x4a, 0x7f, 0x2e, 0xd5, 0xb3, 0xe5, 0x8f
-#define SERIAL_CHAR_RX_UUID_128 0x00, 0x00, 0xfe, 0x61, 0x8e, 0x22, 0x45, 0x41, 0x9d, 0x4c, 0x21, 0xed, 0xae, 0x82, 0xed, 0x19
-#define SERIAL_CHAR_TX_UUID_128 0x00, 0x00, 0xfe, 0x62, 0x8e, 0x22, 0x45, 0x41, 0x9d, 0x4c, 0x21, 0xed, 0xae, 0x82, 0xed, 0x19
-
-bool serial_svc_init();
+void serial_svc_stop();
 
 
 bool serial_svc_update_rx(uint8_t* data, uint8_t data_len);
 bool serial_svc_update_rx(uint8_t* data, uint8_t data_len);
 
 

+ 2 - 1
firmware/targets/f6/furi-hal/furi-hal-bt.c

@@ -5,6 +5,7 @@
 #include <shci.h>
 #include <shci.h>
 #include <cmsis_os2.h>
 #include <cmsis_os2.h>
 #include <app_ble.h>
 #include <app_ble.h>
+#include <gap.h>
 
 
 void furi_hal_bt_init() {
 void furi_hal_bt_init() {
     // Explicitly tell that we are in charge of CLK48 domain
     // Explicitly tell that we are in charge of CLK48 domain
@@ -14,7 +15,7 @@ void furi_hal_bt_init() {
 }
 }
 
 
 bool furi_hal_bt_start_app() {
 bool furi_hal_bt_start_app() {
-    return APP_BLE_Start();
+    return gap_init();
 }
 }
 
 
 void furi_hal_bt_dump_state(string_t buffer) {
 void furi_hal_bt_dump_state(string_t buffer) {

+ 3 - 639
firmware/targets/f7/ble-glue/app_ble.c

@@ -6,106 +6,20 @@
 #include "ble.h"
 #include "ble.h"
 #include "tl.h"
 #include "tl.h"
 #include "app_ble.h"
 #include "app_ble.h"
-
-#include "cmsis_os.h"
 #include "shci.h"
 #include "shci.h"
-#include "otp.h"
-#include "dev_info_service.h"
-#include "battery_service.h"
-#include "serial_service.h"
+#include "cmsis_os.h"
 
 
 #include <furi-hal.h>
 #include <furi-hal.h>
 
 
-typedef struct _tSecurityParams {
-  uint8_t ioCapability;
-  uint8_t mitm_mode;
-  uint8_t bonding_mode;
-  uint8_t Use_Fixed_Pin;
-  uint8_t encryptionKeySizeMin;
-  uint8_t encryptionKeySizeMax;
-  uint32_t Fixed_Pin;
-  uint8_t initiateSecurity;
-} tSecurityParams;
-
-typedef struct _tBLEProfileGlobalContext {
-  tSecurityParams bleSecurityParam;
-  uint16_t gapServiceHandle;
-  uint16_t devNameCharHandle;
-  uint16_t appearanceCharHandle;
-  uint16_t connectionHandle;
-  uint8_t advtServUUIDlen;
-  uint8_t advtServUUID[100];
-} BleGlobalContext_t;
-
-typedef struct {
-  BleGlobalContext_t BleApplicationContext_legacy;
-  APP_BLE_ConnStatus_t Device_Connection_Status;
-  uint8_t Advertising_mgr_timer_Id;
-} BleApplicationContext_t;
-
-
-#define FAST_ADV_TIMEOUT               (30*1000*1000/CFG_TS_TICK_VAL) /**< 30s */
-#define INITIAL_ADV_TIMEOUT            (60*1000*1000/CFG_TS_TICK_VAL) /**< 60s */
-
-#define BD_ADDR_SIZE_LOCAL    6
-
-#define LED_ON_TIMEOUT                 (0.005*1000*1000/CFG_TS_TICK_VAL) /**< 5ms */
-
 PLACE_IN_SECTION("MB_MEM1") ALIGN(4) static TL_CmdPacket_t BleCmdBuffer;
 PLACE_IN_SECTION("MB_MEM1") ALIGN(4) static TL_CmdPacket_t BleCmdBuffer;
 
 
-static const uint8_t M_bd_addr[BD_ADDR_SIZE_LOCAL] =
-    {
-        (uint8_t)((CFG_ADV_BD_ADDRESS & 0x0000000000FF)),
-        (uint8_t)((CFG_ADV_BD_ADDRESS & 0x00000000FF00) >> 8),
-        (uint8_t)((CFG_ADV_BD_ADDRESS & 0x000000FF0000) >> 16),
-        (uint8_t)((CFG_ADV_BD_ADDRESS & 0x0000FF000000) >> 24),
-        (uint8_t)((CFG_ADV_BD_ADDRESS & 0x00FF00000000) >> 32),
-        (uint8_t)((CFG_ADV_BD_ADDRESS & 0xFF0000000000) >> 40)
-    };
-
-static uint8_t bd_addr_udn[BD_ADDR_SIZE_LOCAL];
-
-static const uint8_t BLE_CFG_IR_VALUE[16] = CFG_BLE_IRK;
-static const uint8_t BLE_CFG_ER_VALUE[16] = CFG_BLE_ERK;
-
-PLACE_IN_SECTION("TAG_OTA_END") const uint32_t MagicKeywordValue = 0x94448A29 ;
-PLACE_IN_SECTION("TAG_OTA_START") const uint32_t MagicKeywordAddress = (uint32_t)&MagicKeywordValue;
-
-PLACE_IN_SECTION("BLE_APP_CONTEXT") static BleApplicationContext_t BleApplicationContext;
-PLACE_IN_SECTION("BLE_APP_CONTEXT") static uint16_t AdvIntervalMin, AdvIntervalMax;
-
-uint8_t  manuf_data[14] = {
-    sizeof(manuf_data)-1, AD_TYPE_MANUFACTURER_SPECIFIC_DATA,
-    0x01/*SKD version */,
-    0x00 /* Generic*/,
-    0x00 /* GROUP A Feature  */,
-    0x00 /* GROUP A Feature */,
-    0x00 /* GROUP B Feature */,
-    0x00 /* GROUP B Feature */,
-    0x00, /* BLE MAC start -MSB */
-    0x00,
-    0x00,
-    0x00,
-    0x00,
-    0x00, /* BLE MAC stop */
-
-};
+// PLACE_IN_SECTION("TAG_OTA_END") const uint32_t MagicKeywordValue = 0x94448A29 ;
+// PLACE_IN_SECTION("TAG_OTA_START") const uint32_t MagicKeywordAddress = (uint32_t)&MagicKeywordValue;
 
 
 osMutexId_t MtxHciId;
 osMutexId_t MtxHciId;
 osSemaphoreId_t SemHciId;
 osSemaphoreId_t SemHciId;
-osThreadId_t AdvUpdateProcessId;
 osThreadId_t HciUserEvtProcessId;
 osThreadId_t HciUserEvtProcessId;
 
 
-const osThreadAttr_t AdvUpdateProcess_attr = {
-    .name = CFG_ADV_UPDATE_PROCESS_NAME,
-    .attr_bits = CFG_ADV_UPDATE_PROCESS_ATTR_BITS,
-    .cb_mem = CFG_ADV_UPDATE_PROCESS_CB_MEM,
-    .cb_size = CFG_ADV_UPDATE_PROCESS_CB_SIZE,
-    .stack_mem = CFG_ADV_UPDATE_PROCESS_STACK_MEM,
-    .priority = CFG_ADV_UPDATE_PROCESS_PRIORITY,
-    .stack_size = CFG_ADV_UPDATE_PROCESS_STACK_SIZE
-};
-
 const osThreadAttr_t HciUserEvtProcess_attr = {
 const osThreadAttr_t HciUserEvtProcess_attr = {
     .name = CFG_HCI_USER_EVT_PROCESS_NAME,
     .name = CFG_HCI_USER_EVT_PROCESS_NAME,
     .attr_bits = CFG_HCI_USER_EVT_PROCESS_ATTR_BITS,
     .attr_bits = CFG_HCI_USER_EVT_PROCESS_ATTR_BITS,
@@ -121,13 +35,6 @@ static void HciUserEvtProcess(void *argument);
 static void BLE_UserEvtRx( void * pPayload );
 static void BLE_UserEvtRx( void * pPayload );
 static void BLE_StatusNot( HCI_TL_CmdStatus_t status );
 static void BLE_StatusNot( HCI_TL_CmdStatus_t status );
 static void Ble_Tl_Init( void );
 static void Ble_Tl_Init( void );
-static void Ble_Hci_Gap_Gatt_Init();
-static const uint8_t* BleGetBdAddress( void );
-static void Adv_Request( APP_BLE_ConnStatus_t New_Status );
-static void Adv_Mgr( void );
-static void AdvUpdateProcess(void *argument);
-static void Adv_Update( void );
-
 
 
 bool APP_BLE_Init() {
 bool APP_BLE_Init() {
   SHCI_C2_Ble_Init_Cmd_Packet_t ble_init_cmd_packet = {
   SHCI_C2_Ble_Init_Cmd_Packet_t ble_init_cmd_packet = {
@@ -160,254 +67,6 @@ bool APP_BLE_Init() {
   return (SHCI_C2_BLE_Init( &ble_init_cmd_packet ) == SHCI_Success);
   return (SHCI_C2_BLE_Init( &ble_init_cmd_packet ) == SHCI_Success);
 }
 }
 
 
-static void set_advertisment_service_uid(uint8_t* uid, uint8_t uin_len);
-
-bool APP_BLE_Start() {
-  if (APPE_Status() != BleGlueStatusStarted) {
-    return false;
-  }
-  // Initialization of HCI & GATT & GAP layer
-  Ble_Hci_Gap_Gatt_Init();
-  // Initialization of the BLE Services
-  SVCCTL_Init();
-  // Initialization of the BLE App Context
-  BleApplicationContext.Device_Connection_Status = APP_BLE_IDLE;
-  BleApplicationContext.BleApplicationContext_legacy.connectionHandle = 0xFFFF;
-  // From here, all initialization are BLE application specific
-  AdvUpdateProcessId = osThreadNew(AdvUpdateProcess, NULL, &AdvUpdateProcess_attr);
-
-  // Initialization of ADV - Ad Manufacturer Element - Support OTA Bit Masks
-#if(BLE_CFG_OTA_REBOOT_CHAR != 0)
-  manuf_data[sizeof(manuf_data)-8] = CFG_FEATURE_OTA_REBOOT;
-#endif
-
-  // Initialize DIS Application
-  dev_info_service_init();
-  // Initialize BAS Application
-  battery_svc_init();
-  // Initialize Serial application
-  serial_svc_init();
-  // Create timer to handle the connection state machine
-  HW_TS_Create(CFG_TIM_PROC_ID_ISR, &(BleApplicationContext.Advertising_mgr_timer_Id), hw_ts_SingleShot, Adv_Mgr);
-  uint8_t adv_service_uid[2];
-  adv_service_uid[0] = 0x80 | furi_hal_version_get_hw_color();
-  adv_service_uid[1] = 0x30;
-
-  set_advertisment_service_uid(adv_service_uid, sizeof(adv_service_uid));
-  /* Initialize intervals for reconnexion without intervals update */
-  AdvIntervalMin = CFG_FAST_CONN_ADV_INTERVAL_MIN;
-  AdvIntervalMax = CFG_FAST_CONN_ADV_INTERVAL_MAX;
-
-  Adv_Request(APP_BLE_FAST_ADV);
-  return true;
-}
-
-void SVCCTL_SvcInit() {
-    // Dummy function to prevent unused services initialization
-    // TODO refactore
-}
-
-SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification( void *pckt )
-{
-  hci_event_pckt *event_pckt;
-  evt_le_meta_event *meta_evt;
-  evt_blue_aci *blue_evt;
-  hci_le_phy_update_complete_event_rp0 *evt_le_phy_update_complete;
-  uint8_t TX_PHY, RX_PHY;
-  tBleStatus ret = BLE_STATUS_INVALID_PARAMS;
-
-  event_pckt = (hci_event_pckt*) ((hci_uart_pckt *) pckt)->data;
-
-  switch (event_pckt->evt) {
-    case EVT_DISCONN_COMPLETE:
-    {
-      hci_disconnection_complete_event_rp0 *disconnection_complete_event;
-      disconnection_complete_event = (hci_disconnection_complete_event_rp0 *) event_pckt->data;
-
-      if (disconnection_complete_event->Connection_Handle == BleApplicationContext.BleApplicationContext_legacy.connectionHandle) {
-        BleApplicationContext.BleApplicationContext_legacy.connectionHandle = 0;
-        BleApplicationContext.Device_Connection_Status = APP_BLE_IDLE;
-        APP_DBG_MSG("\r\n\r** DISCONNECTION EVENT WITH CLIENT \r\n");
-      }
-      /* restart advertising */
-      Adv_Request(APP_BLE_FAST_ADV);
-      furi_hal_power_insomnia_exit();
-    }
-    break; /* EVT_DISCONN_COMPLETE */
-
-    case EVT_LE_META_EVENT:
-    {
-      meta_evt = (evt_le_meta_event*) event_pckt->data;
-      switch (meta_evt->subevent)
-      {
-        case EVT_LE_CONN_UPDATE_COMPLETE:
-          APP_DBG_MSG("\r\n\r** CONNECTION UPDATE EVENT WITH CLIENT \r\n");
-
-          /* USER CODE BEGIN EVT_LE_CONN_UPDATE_COMPLETE */
-
-          /* USER CODE END EVT_LE_CONN_UPDATE_COMPLETE */
-          break;
-        case EVT_LE_PHY_UPDATE_COMPLETE:
-          APP_DBG_MSG("EVT_UPDATE_PHY_COMPLETE \r\n");
-          evt_le_phy_update_complete = (hci_le_phy_update_complete_event_rp0*)meta_evt->data;
-          if (evt_le_phy_update_complete->Status == 0)
-          {
-            APP_DBG_MSG("EVT_UPDATE_PHY_COMPLETE, status ok \r\n");
-          }
-          else
-          {
-            APP_DBG_MSG("EVT_UPDATE_PHY_COMPLETE, status nok \r\n");
-          }
-
-          ret = hci_le_read_phy(BleApplicationContext.BleApplicationContext_legacy.connectionHandle,&TX_PHY,&RX_PHY);
-          if (ret == BLE_STATUS_SUCCESS)
-          {
-            APP_DBG_MSG("Read_PHY success \r\n");
-
-            if ((TX_PHY == TX_2M) && (RX_PHY == RX_2M))
-            {
-              APP_DBG_MSG("PHY Param  TX= %d, RX= %d \r\n", TX_PHY, RX_PHY);
-            }
-            else
-            {
-              APP_DBG_MSG("PHY Param  TX= %d, RX= %d \r\n", TX_PHY, RX_PHY);
-            }
-          }
-          else
-          {
-            APP_DBG_MSG("Read conf not succeess \r\n");
-          }
-          break;
-        case EVT_LE_CONN_COMPLETE:
-        {
-          furi_hal_power_insomnia_enter();
-          hci_le_connection_complete_event_rp0 *connection_complete_event;
-
-          /**
-           * The connection is done, there is no need anymore to schedule the LP ADV
-           */
-          connection_complete_event = (hci_le_connection_complete_event_rp0 *) meta_evt->data;
-
-          HW_TS_Stop(BleApplicationContext.Advertising_mgr_timer_Id);
-
-          APP_DBG_MSG("EVT_LE_CONN_COMPLETE for connection handle 0x%x\r\n", connection_complete_event->Connection_Handle);
-          if (BleApplicationContext.Device_Connection_Status == APP_BLE_LP_CONNECTING)
-          {
-            /* Connection as client */
-            BleApplicationContext.Device_Connection_Status = APP_BLE_CONNECTED_CLIENT;
-          }
-          else
-          {
-            /* Connection as server */
-            BleApplicationContext.Device_Connection_Status = APP_BLE_CONNECTED_SERVER;
-          }
-          BleApplicationContext.BleApplicationContext_legacy.connectionHandle = connection_complete_event->Connection_Handle;
-        }
-        break; /* HCI_EVT_LE_CONN_COMPLETE */
-        default:
-          break;
-      }
-    }
-    break; /* HCI_EVT_LE_META_EVENT */
-
-    case EVT_VENDOR:
-      blue_evt = (evt_blue_aci*) event_pckt->data;
-      switch (blue_evt->ecode) {
-        aci_gap_pairing_complete_event_rp0 *pairing_complete;
-
-      case EVT_BLUE_GAP_LIMITED_DISCOVERABLE: 
-        APP_DBG_MSG("\r\n\r** EVT_BLUE_GAP_LIMITED_DISCOVERABLE \r\n");
-          break; /* EVT_BLUE_GAP_LIMITED_DISCOVERABLE */
-          
-      case EVT_BLUE_GAP_PASS_KEY_REQUEST:  
-        APP_DBG_MSG("\r\n\r** EVT_BLUE_GAP_PASS_KEY_REQUEST \r\n");
-
-        aci_gap_pass_key_resp(BleApplicationContext.BleApplicationContext_legacy.connectionHandle,123456);
-
-        APP_DBG_MSG("\r\n\r** aci_gap_pass_key_resp \r\n");
-          break; /* EVT_BLUE_GAP_PASS_KEY_REQUEST */
-
-      case EVT_BLUE_GAP_AUTHORIZATION_REQUEST:    
-        APP_DBG_MSG("\r\n\r** EVT_BLUE_GAP_AUTHORIZATION_REQUEST \r\n");
-          break; /* EVT_BLUE_GAP_AUTHORIZATION_REQUEST */
-
-      case EVT_BLUE_GAP_SLAVE_SECURITY_INITIATED:   
-        APP_DBG_MSG("\r\n\r** EVT_BLUE_GAP_SLAVE_SECURITY_INITIATED \r\n");
-          break; /* EVT_BLUE_GAP_SLAVE_SECURITY_INITIATED */
-
-      case EVT_BLUE_GAP_BOND_LOST:    
-        APP_DBG_MSG("\r\n\r** EVT_BLUE_GAP_BOND_LOST \r\n");
-          aci_gap_allow_rebond(BleApplicationContext.BleApplicationContext_legacy.connectionHandle);
-        APP_DBG_MSG("\r\n\r** Send allow rebond \r\n");
-          break; /* EVT_BLUE_GAP_BOND_LOST */
-
-      case EVT_BLUE_GAP_DEVICE_FOUND:  
-        APP_DBG_MSG("\r\n\r** EVT_BLUE_GAP_DEVICE_FOUND \r\n");
-          break; /* EVT_BLUE_GAP_DEVICE_FOUND */
-
-      case EVT_BLUE_GAP_ADDR_NOT_RESOLVED:
-         APP_DBG_MSG("\r\n\r** EVT_BLUE_GAP_DEVICE_FOUND \r\n");
-          break; /* EVT_BLUE_GAP_DEVICE_FOUND */
-      
-      case (EVT_BLUE_GAP_KEYPRESS_NOTIFICATION):
-         APP_DBG_MSG("\r\n\r** EVT_BLUE_GAP_KEYPRESS_NOTIFICATION \r\n");
-          break; /* EVT_BLUE_GAP_KEY_PRESS_NOTIFICATION */    
-
-       case (EVT_BLUE_GAP_NUMERIC_COMPARISON_VALUE):
-          APP_DBG_MSG("numeric_value = %ld\r\n",
-                      ((aci_gap_numeric_comparison_value_event_rp0 *)(blue_evt->data))->Numeric_Value);
-
-          APP_DBG_MSG("Hex_value = %lx\r\n",
-                      ((aci_gap_numeric_comparison_value_event_rp0 *)(blue_evt->data))->Numeric_Value);
-
-          aci_gap_numeric_comparison_value_confirm_yesno(BleApplicationContext.BleApplicationContext_legacy.connectionHandle, 1); /* CONFIRM_YES = 1 */
-
-          APP_DBG_MSG("\r\n\r** aci_gap_numeric_comparison_value_confirm_yesno-->YES \r\n");
-          break;
-
-        case (EVT_BLUE_GAP_PAIRING_CMPLT):
-          {
-            pairing_complete = (aci_gap_pairing_complete_event_rp0*)blue_evt->data;
-
-            APP_DBG_MSG("BLE_CTRL_App_Notification: EVT_BLUE_GAP_PAIRING_CMPLT, pairing_complete->Status = %d\r\n",pairing_complete->Status);
-            if (pairing_complete->Status == 0) {
-              APP_DBG_MSG("\r\n\r** Pairing OK \r\n");
-            } else {
-              APP_DBG_MSG("\r\n\r** Pairing KO \r\n");
-            }
-          }
-          break;
-
-      /* USER CODE END ecode */
-        case EVT_BLUE_GAP_PROCEDURE_COMPLETE:
-          APP_DBG_MSG("\r\n\r** EVT_BLUE_GAP_PROCEDURE_COMPLETE \r\n");
-          break;
-      }
-      break; /* EVT_VENDOR */
-      default:
-        break;
-  }
-
-  return (SVCCTL_UserEvtFlowEnable);
-}
-
-static void set_advertisment_service_uid(uint8_t* uid, uint8_t uid_len) {
-    BleApplicationContext.BleApplicationContext_legacy.advtServUUIDlen = 1;
-    if(uid_len == 2) {
-        BleApplicationContext.BleApplicationContext_legacy.advtServUUID[0] = AD_TYPE_16_BIT_SERV_UUID;
-    } else if (uid_len == 4) {
-        BleApplicationContext.BleApplicationContext_legacy.advtServUUID[0] = AD_TYPE_32_BIT_SERV_UUID;
-    } else if(uid_len == 16) {
-        BleApplicationContext.BleApplicationContext_legacy.advtServUUID[0] = AD_TYPE_128_BIT_SERV_UUID_CMPLT_LIST;
-    }
-    memcpy(&BleApplicationContext.BleApplicationContext_legacy.advtServUUID[1], uid, uid_len);
-    BleApplicationContext.BleApplicationContext_legacy.advtServUUIDlen += uid_len;
-}
-
-APP_BLE_ConnStatus_t APP_BLE_Get_Server_Connection_Status() {
-    return BleApplicationContext.Device_Connection_Status;
-}
-
 static void Ble_Tl_Init( void ) {
 static void Ble_Tl_Init( void ) {
   HCI_TL_HciInitConf_t Hci_Tl_Init_Conf;
   HCI_TL_HciInitConf_t Hci_Tl_Init_Conf;
 
 
@@ -419,301 +78,6 @@ static void Ble_Tl_Init( void ) {
   hci_init(BLE_UserEvtRx, (void*) &Hci_Tl_Init_Conf);
   hci_init(BLE_UserEvtRx, (void*) &Hci_Tl_Init_Conf);
 }
 }
 
 
-static void Ble_Hci_Gap_Gatt_Init() {
-  uint8_t role;
-  uint16_t gap_service_handle, gap_dev_name_char_handle, gap_appearance_char_handle;
-  const uint8_t *bd_addr;
-  uint32_t srd_bd_addr[2];
-  uint16_t appearance[1] = { BLE_CFG_GAP_APPEARANCE };
-
-  /*HCI Reset to synchronise BLE Stack*/
-  hci_reset();
-
-  /**
-   * Write the BD Address
-   */
-  bd_addr = BleGetBdAddress();
-  aci_hal_write_config_data(CONFIG_DATA_PUBADDR_OFFSET,
-                            CONFIG_DATA_PUBADDR_LEN,
-                            (uint8_t*) bd_addr);
-
-  /* BLE MAC in ADV Packet */
-  manuf_data[ sizeof(manuf_data)-6] = bd_addr[5];
-  manuf_data[ sizeof(manuf_data)-5] = bd_addr[4];
-  manuf_data[ sizeof(manuf_data)-4] = bd_addr[3];
-  manuf_data[ sizeof(manuf_data)-3] = bd_addr[2];
-  manuf_data[ sizeof(manuf_data)-2] = bd_addr[1];
-  manuf_data[ sizeof(manuf_data)-1] = bd_addr[0];
-
-  /**
-   * Write Identity root key used to derive LTK and CSRK
-   */
-    aci_hal_write_config_data(CONFIG_DATA_IR_OFFSET,
-    CONFIG_DATA_IR_LEN,
-                            (uint8_t*) BLE_CFG_IR_VALUE);
-
-   /**
-   * Write Encryption root key used to derive LTK and CSRK
-   */
-    aci_hal_write_config_data(CONFIG_DATA_ER_OFFSET,
-    CONFIG_DATA_ER_LEN,
-                            (uint8_t*) BLE_CFG_ER_VALUE);
-
-   /**
-   * Write random bd_address
-   */
-   /* random_bd_address = R_bd_address;
-    aci_hal_write_config_data(CONFIG_DATA_RANDOM_ADDRESS_WR,
-    CONFIG_DATA_RANDOM_ADDRESS_LEN,
-                            (uint8_t*) random_bd_address);
-  */
-
-  /**
-   * Static random Address
-   * The two upper bits shall be set to 1
-   * The lowest 32bits is read from the UDN to differentiate between devices
-   * The RNG may be used to provide a random number on each power on
-   */
-  srd_bd_addr[1] =  0x0000ED6E;
-  srd_bd_addr[0] =  LL_FLASH_GetUDN( );
-  aci_hal_write_config_data( CONFIG_DATA_RANDOM_ADDRESS_OFFSET, CONFIG_DATA_RANDOM_ADDRESS_LEN, (uint8_t*)srd_bd_addr );
-
-  /**
-   * Write Identity root key used to derive LTK and CSRK
-   */
-    aci_hal_write_config_data( CONFIG_DATA_IR_OFFSET, CONFIG_DATA_IR_LEN, (uint8_t*)BLE_CFG_IR_VALUE );
-
-   /**
-   * Write Encryption root key used to derive LTK and CSRK
-   */
-    aci_hal_write_config_data( CONFIG_DATA_ER_OFFSET, CONFIG_DATA_ER_LEN, (uint8_t*)BLE_CFG_ER_VALUE );
-
-  /**
-   * Set TX Power to 0dBm.
-   */
-  aci_hal_set_tx_power_level(1, CFG_TX_POWER);
-
-  /**
-   * Initialize GATT interface
-   */
-  aci_gatt_init();
-
-  /**
-   * Initialize GAP interface
-   */
-  role = 0;
-
-#if (BLE_CFG_PERIPHERAL == 1)
-  role |= GAP_PERIPHERAL_ROLE;
-#endif
-
-#if (BLE_CFG_CENTRAL == 1)
-  role |= GAP_CENTRAL_ROLE;
-#endif
-
-  if (role > 0)
-  {
-    const char *name = furi_hal_version_get_device_name_ptr();
-    aci_gap_init(role, 0,
-                 strlen(name),
-                 &gap_service_handle, &gap_dev_name_char_handle, &gap_appearance_char_handle);
-
-    if (aci_gatt_update_char_value(gap_service_handle, gap_dev_name_char_handle, 0, strlen(name), (uint8_t *) name))
-    {
-      BLE_DBG_SVCCTL_MSG("Device Name aci_gatt_update_char_value failed.\r\n");
-    }
-  }
-
-  if(aci_gatt_update_char_value(gap_service_handle,
-                                gap_appearance_char_handle,
-                                0,
-                                2,
-                                (uint8_t *)&appearance))
-  {
-    BLE_DBG_SVCCTL_MSG("Appearance aci_gatt_update_char_value failed.\r\n");
-  }
-  /**
-   * Initialize Default PHY
-   */
-  hci_le_set_default_phy(ALL_PHYS_PREFERENCE,TX_2M_PREFERRED,RX_2M_PREFERRED);
-
-  /**
-   * Initialize IO capability
-   */
-  BleApplicationContext.BleApplicationContext_legacy.bleSecurityParam.ioCapability = CFG_IO_CAPABILITY;
-  aci_gap_set_io_capability(BleApplicationContext.BleApplicationContext_legacy.bleSecurityParam.ioCapability);
-
-  /**
-   * Initialize authentication
-   */
-  BleApplicationContext.BleApplicationContext_legacy.bleSecurityParam.mitm_mode = CFG_MITM_PROTECTION;
-  BleApplicationContext.BleApplicationContext_legacy.bleSecurityParam.encryptionKeySizeMin = CFG_ENCRYPTION_KEY_SIZE_MIN;
-  BleApplicationContext.BleApplicationContext_legacy.bleSecurityParam.encryptionKeySizeMax = CFG_ENCRYPTION_KEY_SIZE_MAX;
-  BleApplicationContext.BleApplicationContext_legacy.bleSecurityParam.Use_Fixed_Pin = CFG_USED_FIXED_PIN;
-  BleApplicationContext.BleApplicationContext_legacy.bleSecurityParam.Fixed_Pin = CFG_FIXED_PIN;
-  BleApplicationContext.BleApplicationContext_legacy.bleSecurityParam.bonding_mode = CFG_BONDING_MODE;
-
-  aci_gap_set_authentication_requirement(BleApplicationContext.BleApplicationContext_legacy.bleSecurityParam.bonding_mode,
-                                         BleApplicationContext.BleApplicationContext_legacy.bleSecurityParam.mitm_mode,
-                                         CFG_SC_SUPPORT,
-                                         CFG_KEYPRESS_NOTIFICATION_SUPPORT,
-                                         BleApplicationContext.BleApplicationContext_legacy.bleSecurityParam.encryptionKeySizeMin,
-                                         BleApplicationContext.BleApplicationContext_legacy.bleSecurityParam.encryptionKeySizeMax,
-                                         BleApplicationContext.BleApplicationContext_legacy.bleSecurityParam.Use_Fixed_Pin,
-                                         BleApplicationContext.BleApplicationContext_legacy.bleSecurityParam.Fixed_Pin,
-                                         PUBLIC_ADDR
-                                         );
-
-  /**
-   * Initialize whitelist
-   */
-   if (BleApplicationContext.BleApplicationContext_legacy.bleSecurityParam.bonding_mode)
-   {
-     aci_gap_configure_whitelist();
-   }
-}
-
-static void Adv_Request(APP_BLE_ConnStatus_t New_Status)
-{
-  tBleStatus ret = BLE_STATUS_INVALID_PARAMS;
-  uint16_t Min_Inter, Max_Inter;
-
-  if (New_Status == APP_BLE_FAST_ADV)
-  {
-    Min_Inter = AdvIntervalMin;
-    Max_Inter = AdvIntervalMax;
-  }
-  else
-  {
-    Min_Inter = CFG_LP_CONN_ADV_INTERVAL_MIN;
-    Max_Inter = CFG_LP_CONN_ADV_INTERVAL_MAX;
-  }
-
-    /**
-     * Stop the timer, it will be restarted for a new shot
-     * It does not hurt if the timer was not running
-     */
-    HW_TS_Stop(BleApplicationContext.Advertising_mgr_timer_Id);
-
-    APP_DBG_MSG("First index in %d state \r\n", BleApplicationContext.Device_Connection_Status);
-
-    if ((New_Status == APP_BLE_LP_ADV)
-        && ((BleApplicationContext.Device_Connection_Status == APP_BLE_FAST_ADV)
-            || (BleApplicationContext.Device_Connection_Status == APP_BLE_LP_ADV)))
-    {
-      /* Connection in ADVERTISE mode have to stop the current advertising */
-      ret = aci_gap_set_non_discoverable();
-      if (ret == BLE_STATUS_SUCCESS)
-      {
-        APP_DBG_MSG("Successfully Stopped Advertising \r\n");
-      }
-      else
-      {
-        APP_DBG_MSG("Stop Advertising Failed , result: %d \r\n", ret);
-      }
-    }
-
-    BleApplicationContext.Device_Connection_Status = New_Status;
-
-    const char* name = furi_hal_version_get_ble_local_device_name_ptr();
-
-    /* Start Fast or Low Power Advertising */
-    ret = aci_gap_set_discoverable(
-        ADV_IND,
-        Min_Inter,
-        Max_Inter,
-        PUBLIC_ADDR,
-        NO_WHITE_LIST_USE, /* use white list */
-        strlen(name),
-        (uint8_t*)name,
-        BleApplicationContext.BleApplicationContext_legacy.advtServUUIDlen,
-        BleApplicationContext.BleApplicationContext_legacy.advtServUUID,
-        0,
-        0);
-    if(ret) {
-      FURI_LOG_E("APP ble", "Set discoverable err: %d", ret);
-    }
-
-    /* Update Advertising data */
-    ret = aci_gap_update_adv_data(sizeof(manuf_data), (uint8_t*) manuf_data);
-    if (ret == BLE_STATUS_SUCCESS) {
-      if (New_Status == APP_BLE_FAST_ADV) {
-        APP_DBG_MSG("Successfully Start Fast Advertising \r\n" );
-        /* Start Timer to STOP ADV - TIMEOUT */
-        HW_TS_Start(BleApplicationContext.Advertising_mgr_timer_Id, INITIAL_ADV_TIMEOUT);
-      } else {
-        APP_DBG_MSG("Successfully Start Low Power Advertising \r\n");
-      }
-    } else {
-      if (New_Status == APP_BLE_FAST_ADV) {
-        APP_DBG_MSG("Start Fast Advertising Failed , result: %d \r\n", ret);
-      } else {
-        APP_DBG_MSG("Start Low Power Advertising Failed , result: %d \r\n", ret);
-      }
-    }
-}
-
-const uint8_t* BleGetBdAddress( void ) {
-  uint8_t *otp_addr;
-  const uint8_t *bd_addr;
-  uint32_t udn;
-  uint32_t company_id;
-  uint32_t device_id;
-
-  udn = LL_FLASH_GetUDN();
-
-  if(udn != 0xFFFFFFFF) {
-    company_id = LL_FLASH_GetSTCompanyID();
-    device_id = LL_FLASH_GetDeviceID();
-
-    bd_addr_udn[0] = (uint8_t)(udn & 0x000000FF);
-    bd_addr_udn[1] = (uint8_t)( (udn & 0x0000FF00) >> 8 );
-    bd_addr_udn[2] = (uint8_t)( (udn & 0x00FF0000) >> 16 );
-    bd_addr_udn[3] = (uint8_t)device_id;
-    bd_addr_udn[4] = (uint8_t)(company_id & 0x000000FF);;
-    bd_addr_udn[5] = (uint8_t)( (company_id & 0x0000FF00) >> 8 );
-
-    bd_addr = (const uint8_t *)bd_addr_udn;
-  } else {
-    otp_addr = OTP_Read(0);
-    if(otp_addr) {
-      bd_addr = ((OTP_ID0_t*)otp_addr)->bd_address;
-    } else {
-      bd_addr = M_bd_addr;
-    }
-  }
-
-  return bd_addr;
-}
-
-/*************************************************************
- *
- *SPECIFIC FUNCTIONS
- *
- *************************************************************/
-static void Adv_Mgr( void ) {
-  /**
-   * The code shall be executed in the background as an aci command may be sent
-   * The background is the only place where the application can make sure a new aci command
-   * is not sent if there is a pending one
-   */
-  osThreadFlagsSet( AdvUpdateProcessId, 1 );
-}
-
-static void AdvUpdateProcess(void *argument) {
-  UNUSED(argument);
-
-  for(;;) {
-    osThreadFlagsWait( 1, osFlagsWaitAny, osWaitForever);
-    Adv_Update( );
-  }
-}
-
-static void Adv_Update( void ) {
-  Adv_Request(APP_BLE_LP_ADV);
-
-}
-
 static void HciUserEvtProcess(void *argument) {
 static void HciUserEvtProcess(void *argument) {
   UNUSED(argument);
   UNUSED(argument);
 
 

+ 0 - 13
firmware/targets/f7/ble-glue/app_ble.h

@@ -7,20 +7,7 @@ extern "C" {
 #include <stdbool.h>
 #include <stdbool.h>
 #include "hci_tl.h"
 #include "hci_tl.h"
 
 
-typedef enum {
-    APP_BLE_IDLE,
-    APP_BLE_FAST_ADV,
-    APP_BLE_LP_ADV,
-    APP_BLE_SCAN,
-    APP_BLE_LP_CONNECTING,
-    APP_BLE_CONNECTED_SERVER,
-    APP_BLE_CONNECTED_CLIENT
-} APP_BLE_ConnStatus_t;
-
 bool APP_BLE_Init();
 bool APP_BLE_Init();
-bool APP_BLE_Start();
-
-APP_BLE_ConnStatus_t APP_BLE_Get_Server_Connection_Status();
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 }
 }

+ 1 - 1
firmware/targets/f7/ble-glue/app_conf.h

@@ -139,7 +139,7 @@
 /**
 /**
  * Maximum supported ATT_MTU size
  * Maximum supported ATT_MTU size
  */
  */
-#define CFG_BLE_MAX_ATT_MTU             (156)
+#define CFG_BLE_MAX_ATT_MTU             (251)
 
 
 /**
 /**
  * Size of the storage area for Attribute values
  * Size of the storage area for Attribute values

+ 34 - 11
firmware/targets/f7/ble-glue/battery_service.c

@@ -11,21 +11,22 @@ typedef struct {
     uint16_t char_level_handle;
     uint16_t char_level_handle;
 } BatterySvc;
 } BatterySvc;
 
 
-static BatterySvc battery_svc;
+static BatterySvc* battery_svc = NULL;
 
 
-bool battery_svc_init() {
+static const uint16_t service_uuid = BATTERY_SERVICE_UUID;
+static const uint16_t char_battery_level_uuid = BATTERY_LEVEL_CHAR_UUID;
+
+void battery_svc_start() {
+    battery_svc = furi_alloc(sizeof(BatterySvc));
     tBleStatus status;
     tBleStatus status;
-    const uint16_t service_uuid = BATTERY_SERVICE_UUID;
-    const uint16_t char_battery_level_uuid = BATTERY_LEVEL_CHAR_UUID;
 
 
     // Add Battery service
     // Add Battery service
-    status = aci_gatt_add_service(UUID_TYPE_16, (Service_UUID_t*)&service_uuid, PRIMARY_SERVICE, 4, &battery_svc.svc_handle);
+    status = aci_gatt_add_service(UUID_TYPE_16, (Service_UUID_t*)&service_uuid, PRIMARY_SERVICE, 4, &battery_svc->svc_handle);
     if(status) {
     if(status) {
         FURI_LOG_E(BATTERY_SERVICE_TAG, "Failed to add Battery service: %d", status);
         FURI_LOG_E(BATTERY_SERVICE_TAG, "Failed to add Battery service: %d", status);
     }
     }
-
     // Add Battery level characteristic
     // Add Battery level characteristic
-    status = aci_gatt_add_char(battery_svc.svc_handle,
+    status = aci_gatt_add_char(battery_svc->svc_handle,
                                 UUID_TYPE_16,
                                 UUID_TYPE_16,
                                 (Char_UUID_t *) &char_battery_level_uuid,
                                 (Char_UUID_t *) &char_battery_level_uuid,
                                 1,
                                 1,
@@ -34,17 +35,39 @@ bool battery_svc_init() {
                                 GATT_DONT_NOTIFY_EVENTS,
                                 GATT_DONT_NOTIFY_EVENTS,
                                 10,
                                 10,
                                 CHAR_VALUE_LEN_CONSTANT,
                                 CHAR_VALUE_LEN_CONSTANT,
-                                &battery_svc.char_level_handle);
+                                &battery_svc->char_level_handle);
     if(status) {
     if(status) {
         FURI_LOG_E(BATTERY_SERVICE_TAG, "Failed to add Battery level characteristic: %d", status);
         FURI_LOG_E(BATTERY_SERVICE_TAG, "Failed to add Battery level characteristic: %d", status);
     }
     }
-    return status != BLE_STATUS_SUCCESS;
+}
+
+void battery_svc_stop() {
+    tBleStatus status;
+    if(battery_svc) {
+        // Delete Battery level characteristic
+        status = aci_gatt_del_char(battery_svc->svc_handle, battery_svc->char_level_handle);
+        if(status) {
+            FURI_LOG_E(BATTERY_SERVICE_TAG, "Failed to delete Battery level characteristic: %d", status);
+        }
+        // Delete Battery service
+        status = aci_gatt_del_service(battery_svc->svc_handle);
+        if(status) {
+            FURI_LOG_E(BATTERY_SERVICE_TAG, "Failed to delete Battery service: %d", status);
+        }
+        free(battery_svc);
+        battery_svc = NULL;
+    }
 }
 }
 
 
 bool battery_svc_update_level(uint8_t battery_charge) {
 bool battery_svc_update_level(uint8_t battery_charge) {
+    // Check if service was started
+    if(battery_svc == NULL) {
+        return false;
+    }
+    // Update battery level characteristic
     FURI_LOG_I(BATTERY_SERVICE_TAG, "Updating battery level characteristic");
     FURI_LOG_I(BATTERY_SERVICE_TAG, "Updating battery level characteristic");
-    tBleStatus result = aci_gatt_update_char_value(battery_svc.svc_handle,
-                                          battery_svc.char_level_handle,
+    tBleStatus result = aci_gatt_update_char_value(battery_svc->svc_handle,
+                                          battery_svc->char_level_handle,
                                           0,
                                           0,
                                           1,
                                           1,
                                           &battery_charge);
                                           &battery_charge);

+ 3 - 1
firmware/targets/f7/ble-glue/battery_service.h

@@ -7,7 +7,9 @@
 extern "C" {
 extern "C" {
 #endif
 #endif
 
 
-bool battery_svc_init();
+void battery_svc_start();
+
+void battery_svc_stop();
 
 
 bool battery_svc_update_level(uint8_t battery_level);
 bool battery_svc_update_level(uint8_t battery_level);
 
 

+ 78 - 43
firmware/targets/f7/ble-glue/dev_info_service.c

@@ -4,7 +4,7 @@
 
 
 #include <furi.h>
 #include <furi.h>
 
 
-#define DEV_INFO_SERVICE_TAG "dev info service"
+#define DEV_INFO_SVC_TAG "dev info service"
 
 
 typedef struct {
 typedef struct {
     uint16_t service_handle;
     uint16_t service_handle;
@@ -14,108 +14,143 @@ typedef struct {
     uint16_t software_rev_char_handle;
     uint16_t software_rev_char_handle;
 } DevInfoSvc;
 } DevInfoSvc;
 
 
-bool dev_info_service_init() {
+static DevInfoSvc* dev_info_svc = NULL;
+
+static const char dev_info_man_name[] = "Flipper Devices Inc.";
+static const char dev_info_serial_num[] = "1.0";
+static const char dev_info_firmware_rev_num[] = TARGET;
+static const char dev_info_software_rev_num[] = GIT_COMMIT " " GIT_BRANCH " " GIT_BRANCH_NUM " " BUILD_DATE;
+
+void dev_info_svc_start() {
+    dev_info_svc = furi_alloc(sizeof(DevInfoSvc));
     tBleStatus status;
     tBleStatus status;
-    DevInfoSvc dev_info_svc;
 
 
     // Add Device Information Service
     // Add Device Information Service
     uint16_t uuid = DEVICE_INFORMATION_SERVICE_UUID;
     uint16_t uuid = DEVICE_INFORMATION_SERVICE_UUID;
-    status = aci_gatt_add_service(UUID_TYPE_16, (Service_UUID_t*)&uuid, PRIMARY_SERVICE, 9, &dev_info_svc.service_handle);
+    status = aci_gatt_add_service(UUID_TYPE_16, (Service_UUID_t*)&uuid, PRIMARY_SERVICE, 9, &dev_info_svc->service_handle);
     if(status) {
     if(status) {
-        FURI_LOG_E(DEV_INFO_SERVICE_TAG, "Failed to add Device Information Service: %d", status);
+        FURI_LOG_E(DEV_INFO_SVC_TAG, "Failed to add Device Information Service: %d", status);
     }
     }
 
 
     // Add characteristics
     // Add characteristics
     uuid = MANUFACTURER_NAME_UUID;
     uuid = MANUFACTURER_NAME_UUID;
-    status = aci_gatt_add_char(dev_info_svc.service_handle,
+    status = aci_gatt_add_char(dev_info_svc->service_handle,
                                 UUID_TYPE_16,
                                 UUID_TYPE_16,
                                 (Char_UUID_t*)&uuid,
                                 (Char_UUID_t*)&uuid,
-                                strlen(DEV_INFO_MANUFACTURER_NAME),
+                                strlen(dev_info_man_name),
                                 CHAR_PROP_READ,
                                 CHAR_PROP_READ,
                                 ATTR_PERMISSION_NONE,
                                 ATTR_PERMISSION_NONE,
                                 GATT_DONT_NOTIFY_EVENTS,
                                 GATT_DONT_NOTIFY_EVENTS,
                                 10,
                                 10,
                                 CHAR_VALUE_LEN_CONSTANT,
                                 CHAR_VALUE_LEN_CONSTANT,
-                                &dev_info_svc.man_name_char_handle);
+                                &dev_info_svc->man_name_char_handle);
     if(status) {
     if(status) {
-        FURI_LOG_E(DEV_INFO_SERVICE_TAG, "Failed to add manufacturer name char: %d", status);
-
+        FURI_LOG_E(DEV_INFO_SVC_TAG, "Failed to add manufacturer name char: %d", status);
     }
     }
     uuid = SERIAL_NUMBER_UUID;
     uuid = SERIAL_NUMBER_UUID;
-    status = aci_gatt_add_char(dev_info_svc.service_handle,
+    status = aci_gatt_add_char(dev_info_svc->service_handle,
                                 UUID_TYPE_16,
                                 UUID_TYPE_16,
                                 (Char_UUID_t*)&uuid,
                                 (Char_UUID_t*)&uuid,
-                                strlen(DEV_INFO_SERIAL_NUMBER),
+                                strlen(dev_info_serial_num),
                                 CHAR_PROP_READ,
                                 CHAR_PROP_READ,
                                 ATTR_PERMISSION_NONE,
                                 ATTR_PERMISSION_NONE,
                                 GATT_DONT_NOTIFY_EVENTS,
                                 GATT_DONT_NOTIFY_EVENTS,
                                 10,
                                 10,
                                 CHAR_VALUE_LEN_CONSTANT,
                                 CHAR_VALUE_LEN_CONSTANT,
-                                &dev_info_svc.serial_num_char_handle);
+                                &dev_info_svc->serial_num_char_handle);
     if(status) {
     if(status) {
-        FURI_LOG_E(DEV_INFO_SERVICE_TAG, "Failed to add serial number char: %d", status);
+        FURI_LOG_E(DEV_INFO_SVC_TAG, "Failed to add serial number char: %d", status);
     }
     }
     uuid = FIRMWARE_REVISION_UUID;
     uuid = FIRMWARE_REVISION_UUID;
-    status = aci_gatt_add_char(dev_info_svc.service_handle,
+    status = aci_gatt_add_char(dev_info_svc->service_handle,
                                 UUID_TYPE_16,
                                 UUID_TYPE_16,
                                 (Char_UUID_t*)&uuid,
                                 (Char_UUID_t*)&uuid,
-                                strlen(DEV_INFO_FIRMWARE_REVISION_NUMBER),
+                                strlen(dev_info_firmware_rev_num),
                                 CHAR_PROP_READ,
                                 CHAR_PROP_READ,
                                 ATTR_PERMISSION_NONE,
                                 ATTR_PERMISSION_NONE,
                                 GATT_DONT_NOTIFY_EVENTS,
                                 GATT_DONT_NOTIFY_EVENTS,
                                 10,
                                 10,
                                 CHAR_VALUE_LEN_CONSTANT,
                                 CHAR_VALUE_LEN_CONSTANT,
-                                &dev_info_svc.firmware_rev_char_handle);
+                                &dev_info_svc->firmware_rev_char_handle);
     if(status) {
     if(status) {
-        FURI_LOG_E(DEV_INFO_SERVICE_TAG, "Failed to add firmware revision char: %d", status);
+        FURI_LOG_E(DEV_INFO_SVC_TAG, "Failed to add firmware revision char: %d", status);
     }
     }
     uuid = SOFTWARE_REVISION_UUID;
     uuid = SOFTWARE_REVISION_UUID;
-    status = aci_gatt_add_char(dev_info_svc.service_handle,
+    status = aci_gatt_add_char(dev_info_svc->service_handle,
                                 UUID_TYPE_16,
                                 UUID_TYPE_16,
                                 (Char_UUID_t*)&uuid,
                                 (Char_UUID_t*)&uuid,
-                                strlen(DEV_INFO_SOFTWARE_REVISION_NUMBER),
+                                strlen(dev_info_software_rev_num),
                                 CHAR_PROP_READ,
                                 CHAR_PROP_READ,
                                 ATTR_PERMISSION_NONE,
                                 ATTR_PERMISSION_NONE,
                                 GATT_DONT_NOTIFY_EVENTS,
                                 GATT_DONT_NOTIFY_EVENTS,
                                 10,
                                 10,
                                 CHAR_VALUE_LEN_CONSTANT,
                                 CHAR_VALUE_LEN_CONSTANT,
-                                &dev_info_svc.software_rev_char_handle);
+                                &dev_info_svc->software_rev_char_handle);
     if(status) {
     if(status) {
-        FURI_LOG_E(DEV_INFO_SERVICE_TAG, "Failed to add software revision char: %d", status);
+        FURI_LOG_E(DEV_INFO_SVC_TAG, "Failed to add software revision char: %d", status);
     }
     }
 
 
     // Update characteristics
     // Update characteristics
-    status = aci_gatt_update_char_value(dev_info_svc.service_handle,
-                                        dev_info_svc.man_name_char_handle,
+    status = aci_gatt_update_char_value(dev_info_svc->service_handle,
+                                        dev_info_svc->man_name_char_handle,
                                         0,
                                         0,
-                                        strlen(DEV_INFO_MANUFACTURER_NAME),
-                                        (uint8_t*)DEV_INFO_MANUFACTURER_NAME);
+                                        strlen(dev_info_man_name),
+                                        (uint8_t*)dev_info_man_name);
     if(status) {
     if(status) {
-        FURI_LOG_E(DEV_INFO_SERVICE_TAG, "Failed to update manufacturer name char: %d", status);
+        FURI_LOG_E(DEV_INFO_SVC_TAG, "Failed to update manufacturer name char: %d", status);
     }
     }
-    status = aci_gatt_update_char_value(dev_info_svc.service_handle,
-                                        dev_info_svc.serial_num_char_handle,
+    status = aci_gatt_update_char_value(dev_info_svc->service_handle,
+                                        dev_info_svc->serial_num_char_handle,
                                         0,
                                         0,
-                                        strlen(DEV_INFO_SERIAL_NUMBER),
-                                        (uint8_t*)DEV_INFO_SERIAL_NUMBER);
+                                        strlen(dev_info_serial_num),
+                                        (uint8_t*)dev_info_serial_num);
     if(status) {
     if(status) {
-        FURI_LOG_E(DEV_INFO_SERVICE_TAG, "Failed to update serial number char: %d", status);
+        FURI_LOG_E(DEV_INFO_SVC_TAG, "Failed to update serial number char: %d", status);
     }
     }
-    status = aci_gatt_update_char_value(dev_info_svc.service_handle,
-                                        dev_info_svc.firmware_rev_char_handle,
+    status = aci_gatt_update_char_value(dev_info_svc->service_handle,
+                                        dev_info_svc->firmware_rev_char_handle,
                                         0,
                                         0,
-                                        strlen(DEV_INFO_FIRMWARE_REVISION_NUMBER),
-                                        (uint8_t*)DEV_INFO_FIRMWARE_REVISION_NUMBER);
+                                        strlen(dev_info_firmware_rev_num),
+                                        (uint8_t*)dev_info_firmware_rev_num);
     if(status) {
     if(status) {
-        FURI_LOG_E(DEV_INFO_SERVICE_TAG, "Failed to update firmware revision char: %d", status);
+        FURI_LOG_E(DEV_INFO_SVC_TAG, "Failed to update firmware revision char: %d", status);
     }
     }
-    status = aci_gatt_update_char_value(dev_info_svc.service_handle,
-                                        dev_info_svc.software_rev_char_handle,
+    status = aci_gatt_update_char_value(dev_info_svc->service_handle,
+                                        dev_info_svc->software_rev_char_handle,
                                         0,
                                         0,
-                                        strlen(DEV_INFO_SOFTWARE_REVISION_NUMBER),
-                                        (uint8_t*)DEV_INFO_SOFTWARE_REVISION_NUMBER);
+                                        strlen(dev_info_software_rev_num),
+                                        (uint8_t*)dev_info_software_rev_num);
     if(status) {
     if(status) {
-        FURI_LOG_E(DEV_INFO_SERVICE_TAG, "Failed to update software revision char: %d", status);
+        FURI_LOG_E(DEV_INFO_SVC_TAG, "Failed to update software revision char: %d", status);
+    }
+}
+
+void dev_info_svc_stop() {
+    tBleStatus status;
+    if(dev_info_svc) {
+        // Delete service characteristics
+        status = aci_gatt_del_char(dev_info_svc->service_handle, dev_info_svc->man_name_char_handle);
+        if(status) {
+            FURI_LOG_E(DEV_INFO_SVC_TAG, "Failed to delete manufacturer name char: %d", status);
+        }
+        status = aci_gatt_del_char(dev_info_svc->service_handle, dev_info_svc->serial_num_char_handle);
+        if(status) {
+            FURI_LOG_E(DEV_INFO_SVC_TAG, "Failed to delete serial number char: %d", status);
+        }
+        status = aci_gatt_del_char(dev_info_svc->service_handle, dev_info_svc->firmware_rev_char_handle);
+        if(status) {
+            FURI_LOG_E(DEV_INFO_SVC_TAG, "Failed to delete firmware revision char: %d", status);
+        }
+        status = aci_gatt_del_char(dev_info_svc->service_handle, dev_info_svc->software_rev_char_handle);
+        if(status) {
+            FURI_LOG_E(DEV_INFO_SVC_TAG, "Failed to delete software revision char: %d", status);
+        }
+        // Delete service
+        status = aci_gatt_del_service(dev_info_svc->service_handle);
+        if(status) {
+            FURI_LOG_E(DEV_INFO_SVC_TAG, "Failed to delete device info service: %d", status);
+        }
+        free(dev_info_svc);
+        dev_info_svc = NULL;
     }
     }
-    return status != BLE_STATUS_SUCCESS;
 }
 }

+ 2 - 1
firmware/targets/f7/ble-glue/dev_info_service.h

@@ -12,8 +12,9 @@ extern "C" {
 #define DEV_INFO_FIRMWARE_REVISION_NUMBER       TARGET
 #define DEV_INFO_FIRMWARE_REVISION_NUMBER       TARGET
 #define DEV_INFO_SOFTWARE_REVISION_NUMBER       GIT_COMMIT " " GIT_BRANCH " " GIT_BRANCH_NUM " " BUILD_DATE
 #define DEV_INFO_SOFTWARE_REVISION_NUMBER       GIT_COMMIT " " GIT_BRANCH " " GIT_BRANCH_NUM " " BUILD_DATE
 
 
+void dev_info_svc_start();
 
 
-bool dev_info_service_init();
+void dev_info_svc_stop();
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 }
 }

+ 387 - 0
firmware/targets/f7/ble-glue/gap.c

@@ -0,0 +1,387 @@
+#include "gap.h"
+
+#include "app_entry.h"
+#include "ble.h"
+
+#include "cmsis_os.h"
+#include "otp.h"
+#include "dev_info_service.h"
+#include "battery_service.h"
+#include "serial_service.h"
+
+#include <applications/bt/bt_service/bt.h>
+#include <furi-hal.h>
+
+#define GAP_TAG "BLE"
+
+#define FAST_ADV_TIMEOUT 30000
+#define INITIAL_ADV_TIMEOUT 60000
+
+#define BD_ADDR_SIZE_LOCAL 6
+
+typedef struct {
+  uint16_t gap_svc_handle;
+  uint16_t dev_name_char_handle;
+  uint16_t appearance_char_handle;
+  uint16_t connection_handle;
+  uint8_t adv_svc_uuid_len;
+  uint8_t adv_svc_uuid[20];
+} GapSvc;
+
+typedef struct {
+  GapSvc gap_svc;
+  GapState state;
+  uint8_t mac_address[BD_ADDR_SIZE_LOCAL];
+  Bt* bt;
+  osTimerId advertise_timer;
+  osThreadAttr_t thread_attr;
+  osThreadId_t thread_id;
+} Gap;
+
+// Identity root key
+static const uint8_t gap_irk[16] = {0x12,0x34,0x56,0x78,0x9a,0xbc,0xde,0xf0,0x12,0x34,0x56,0x78,0x9a,0xbc,0xde,0xf0};
+// Encryption root key
+static const uint8_t gap_erk[16] = {0xfe,0xdc,0xba,0x09,0x87,0x65,0x43,0x21,0xfe,0xdc,0xba,0x09,0x87,0x65,0x43,0x21};
+// Appearence characteristic UUID
+static const uint8_t gap_appearence_char_uuid[] = {0x00, 0x86};
+// Default MAC address
+static const uint8_t gap_default_mac_addr[] = {0x6c, 0x7a, 0xd8, 0xac, 0x57, 0x72};
+
+static Gap* gap = NULL;
+
+static void gap_advertise(GapState new_state);
+static void gap_app(void *arg);
+
+SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification( void *pckt )
+{
+  hci_event_pckt *event_pckt;
+  evt_le_meta_event *meta_evt;
+  evt_blue_aci *blue_evt;
+  hci_le_phy_update_complete_event_rp0 *evt_le_phy_update_complete;
+  uint8_t tx_phy;
+  uint8_t rx_phy;
+  tBleStatus ret = BLE_STATUS_INVALID_PARAMS;
+
+  event_pckt = (hci_event_pckt*) ((hci_uart_pckt *) pckt)->data;
+
+  switch (event_pckt->evt) {
+    case EVT_DISCONN_COMPLETE:
+    {
+        hci_disconnection_complete_event_rp0 *disconnection_complete_event = (hci_disconnection_complete_event_rp0 *) event_pckt->data;
+        if (disconnection_complete_event->Connection_Handle == gap->gap_svc.connection_handle) {
+            gap->gap_svc.connection_handle = 0;
+            gap->state = GapStateIdle;
+            FURI_LOG_I(GAP_TAG, "Disconnect from client");
+        }
+        // Restart advertising
+        gap_advertise(GapStateAdvFast);
+        furi_hal_power_insomnia_exit();
+    }
+    break;
+
+    case EVT_LE_META_EVENT:
+        meta_evt = (evt_le_meta_event*) event_pckt->data;
+        switch (meta_evt->subevent) {
+            case EVT_LE_CONN_UPDATE_COMPLETE:
+            FURI_LOG_D(GAP_TAG, "Connection update event");
+            break;
+
+            case EVT_LE_PHY_UPDATE_COMPLETE:
+            evt_le_phy_update_complete = (hci_le_phy_update_complete_event_rp0*)meta_evt->data;
+            if(evt_le_phy_update_complete->Status) {
+                FURI_LOG_E(GAP_TAG, "Update PHY failed, status %d", evt_le_phy_update_complete->Status);
+            } else {
+                FURI_LOG_I(GAP_TAG, "Update PHY succeed");
+            }
+            ret = hci_le_read_phy(gap->gap_svc.connection_handle,&tx_phy,&rx_phy);
+            if(ret) {
+                FURI_LOG_E(GAP_TAG, "Read PHY failed, status: %d", ret);
+            } else {
+                FURI_LOG_I(GAP_TAG, "PHY Params TX= %d, RX= %d ", tx_phy, rx_phy);
+            }
+            break;
+
+            case EVT_LE_CONN_COMPLETE:
+            furi_hal_power_insomnia_enter();
+            hci_le_connection_complete_event_rp0* connection_complete_event = (hci_le_connection_complete_event_rp0 *) meta_evt->data;
+            FURI_LOG_I(GAP_TAG, "Connection complete for connection handle 0x%x", connection_complete_event->Connection_Handle);
+
+            // Stop advertising as connection completed
+            osTimerStop(gap->advertise_timer);
+
+            // Update connection status and handle
+            gap->state = GapStateConnected;
+            gap->gap_svc.connection_handle = connection_complete_event->Connection_Handle;
+
+            // Start pairing by sending security request
+            aci_gap_slave_security_req(connection_complete_event->Connection_Handle);
+            break;
+
+            default:
+            break;
+        }
+    break;
+
+    case EVT_VENDOR:
+        blue_evt = (evt_blue_aci*) event_pckt->data;
+        switch (blue_evt->ecode) {
+            aci_gap_pairing_complete_event_rp0 *pairing_complete;
+
+        case EVT_BLUE_GAP_LIMITED_DISCOVERABLE:
+            FURI_LOG_I(GAP_TAG, "Limited discoverable event");
+            break;
+
+        case EVT_BLUE_GAP_PASS_KEY_REQUEST:
+        {
+            // Generate random PIN code
+            uint32_t pin = rand() % 999999;
+            aci_gap_pass_key_resp(gap->gap_svc.connection_handle, pin);
+            FURI_LOG_I(GAP_TAG, "Pass key request event. Pin: %d", pin);
+            bt_pin_code_show(gap->bt, pin);
+        }
+            break;
+
+        case EVT_BLUE_GAP_AUTHORIZATION_REQUEST:
+            FURI_LOG_I(GAP_TAG, "Authorization request event");
+            break;
+
+        case EVT_BLUE_GAP_SLAVE_SECURITY_INITIATED:
+            FURI_LOG_I(GAP_TAG, "Slave security initiated");
+            break;
+
+        case EVT_BLUE_GAP_BOND_LOST:
+            FURI_LOG_I(GAP_TAG, "Bond lost event. Start rebonding");
+            aci_gap_allow_rebond(gap->gap_svc.connection_handle);
+            break;
+
+        case EVT_BLUE_GAP_DEVICE_FOUND:
+            FURI_LOG_I(GAP_TAG, "Device found event");
+            break;
+
+        case EVT_BLUE_GAP_ADDR_NOT_RESOLVED:
+            FURI_LOG_I(GAP_TAG, "Address not resolved event");
+            break;
+
+        case EVT_BLUE_GAP_KEYPRESS_NOTIFICATION:
+            FURI_LOG_I(GAP_TAG, "Key press notification event");
+            break;
+
+        case EVT_BLUE_GAP_NUMERIC_COMPARISON_VALUE:
+            FURI_LOG_I(GAP_TAG, "Hex_value = %lx",
+                        ((aci_gap_numeric_comparison_value_event_rp0 *)(blue_evt->data))->Numeric_Value);
+            aci_gap_numeric_comparison_value_confirm_yesno(gap->gap_svc.connection_handle, 1);
+            break;
+
+        case (EVT_BLUE_GAP_PAIRING_CMPLT):
+        {
+            pairing_complete = (aci_gap_pairing_complete_event_rp0*)blue_evt->data;
+            if (pairing_complete->Status) {
+            FURI_LOG_E(GAP_TAG, "Pairing failed with status: %d. Terminating connection", pairing_complete->Status);
+            aci_gap_terminate(gap->gap_svc.connection_handle, 5);
+            } else {
+            FURI_LOG_I(GAP_TAG, "Pairing complete");
+            }
+        }
+            break;
+
+        case EVT_BLUE_GAP_PROCEDURE_COMPLETE:
+            FURI_LOG_I(GAP_TAG, "Procedure complete event");
+            break;
+        }
+        default:
+            break;
+  }
+
+  return SVCCTL_UserEvtFlowEnable;
+}
+
+void SVCCTL_SvcInit() {
+    // Dummy function to prevent unused services initialization
+    // TODO refactor (disable all services in WPAN config)
+}
+
+static void set_advertisment_service_uid(uint8_t* uid, uint8_t uid_len) {
+    gap->gap_svc.adv_svc_uuid_len = 1;
+    if(uid_len == 2) {
+        gap->gap_svc.adv_svc_uuid[0] = AD_TYPE_16_BIT_SERV_UUID;
+    } else if (uid_len == 4) {
+        gap->gap_svc.adv_svc_uuid[0] = AD_TYPE_32_BIT_SERV_UUID;
+    } else if(uid_len == 16) {
+        gap->gap_svc.adv_svc_uuid[0] = AD_TYPE_128_BIT_SERV_UUID_CMPLT_LIST;
+    }
+    memcpy(&gap->gap_svc.adv_svc_uuid[1], uid, uid_len);
+    gap->gap_svc.adv_svc_uuid_len += uid_len;
+}
+
+GapState gap_get_status() {
+    return gap->state;
+}
+
+void gap_init_mac_address(Gap* gap) {
+    uint8_t *otp_addr;
+    uint32_t udn;
+    uint32_t company_id;
+    uint32_t device_id;
+
+    udn = LL_FLASH_GetUDN();
+    if(udn != 0xFFFFFFFF) {
+        company_id = LL_FLASH_GetSTCompanyID();
+        device_id = LL_FLASH_GetDeviceID();
+        gap->mac_address[0] = (uint8_t)(udn & 0x000000FF);
+        gap->mac_address[1] = (uint8_t)( (udn & 0x0000FF00) >> 8 );
+        gap->mac_address[2] = (uint8_t)( (udn & 0x00FF0000) >> 16 );
+        gap->mac_address[3] = (uint8_t)device_id;
+        gap->mac_address[4] = (uint8_t)(company_id & 0x000000FF);;
+        gap->mac_address[5] = (uint8_t)( (company_id & 0x0000FF00) >> 8 );
+    } else {
+        otp_addr = OTP_Read(0);
+        if(otp_addr) {
+            memcpy(gap->mac_address, ((OTP_ID0_t*)otp_addr)->bd_address, sizeof(gap->mac_address));
+        } else {
+            memcpy(gap->mac_address, gap_default_mac_addr, sizeof(gap->mac_address));
+        }
+    }
+}
+
+static void gap_init_svc(Gap* gap) {
+    tBleStatus status;
+    uint32_t srd_bd_addr[2];
+
+    //HCI Reset to synchronise BLE Stack*/
+    hci_reset();
+    // Configure mac address
+    gap_init_mac_address(gap);
+    aci_hal_write_config_data(CONFIG_DATA_PUBADDR_OFFSET, CONFIG_DATA_PUBADDR_LEN, (uint8_t*)gap->mac_address);
+
+    /* Static random Address
+     * The two upper bits shall be set to 1
+     * The lowest 32bits is read from the UDN to differentiate between devices
+     * The RNG may be used to provide a random number on each power on
+     */
+    srd_bd_addr[1] = 0x0000ED6E;
+    srd_bd_addr[0] = LL_FLASH_GetUDN();
+    aci_hal_write_config_data( CONFIG_DATA_RANDOM_ADDRESS_OFFSET, CONFIG_DATA_RANDOM_ADDRESS_LEN, (uint8_t*)srd_bd_addr );
+    // Set Identity root key used to derive LTK and CSRK
+    aci_hal_write_config_data( CONFIG_DATA_IR_OFFSET, CONFIG_DATA_IR_LEN, (uint8_t*)gap_irk );
+    // Set Encryption root key used to derive LTK and CSRK
+    aci_hal_write_config_data( CONFIG_DATA_ER_OFFSET, CONFIG_DATA_ER_LEN, (uint8_t*)gap_erk );
+    // Set TX Power to 0 dBm
+    aci_hal_set_tx_power_level(1, 0x19);
+    // Initialize GATT interface
+    aci_gatt_init();
+    // Initialize GAP interface
+    const char *name = furi_hal_version_get_device_name_ptr();
+    aci_gap_init(GAP_PERIPHERAL_ROLE, 0, strlen(name),
+                &gap->gap_svc.gap_svc_handle, &gap->gap_svc.dev_name_char_handle, &gap->gap_svc.appearance_char_handle);
+
+    // Set GAP characteristics
+    status = aci_gatt_update_char_value(gap->gap_svc.gap_svc_handle, gap->gap_svc.dev_name_char_handle, 0, strlen(name), (uint8_t *) name);
+    if (status) {
+        FURI_LOG_E(GAP_TAG, "Failed updating name characteristic: %d", status);
+    }
+    status = aci_gatt_update_char_value(gap->gap_svc.gap_svc_handle, gap->gap_svc.appearance_char_handle, 0, 2, gap_appearence_char_uuid);
+    if(status) {
+        FURI_LOG_E(GAP_TAG, "Failed updating appearence characteristic: %d", status);
+    }
+    // Set default PHY
+    hci_le_set_default_phy(ALL_PHYS_PREFERENCE, TX_2M_PREFERRED, RX_2M_PREFERRED);
+    // Set I/O capability
+    aci_gap_set_io_capability(IO_CAP_DISPLAY_ONLY);
+    // Setup  authentication
+    aci_gap_set_authentication_requirement(1, 1, 1, 0, 8, 16, 1, 0, PUBLIC_ADDR);
+    // Configure whitelist
+    aci_gap_configure_whitelist();
+}
+
+static void gap_advertise(GapState new_state)
+{
+    tBleStatus status;
+    uint16_t min_interval;
+    uint16_t max_interval;
+
+    if (new_state == GapStateAdvFast) {
+        min_interval = 0x80; // 80 ms
+        max_interval = 0xa0; // 100 ms
+    } else {
+        min_interval = 0x0640; // 1 s
+        max_interval = 0x0fa0; // 2.5 s
+    }
+    // Stop advertising timer
+    osTimerStop(gap->advertise_timer);
+
+    if ((new_state == GapStateAdvLowPower) && ((gap->state == GapStateAdvFast) || (gap->state == GapStateAdvLowPower))) {
+        // Stop advertising
+        status = aci_gap_set_non_discoverable();
+        if (status) {
+            FURI_LOG_E(GAP_TAG, "Stop Advertising Failed, result: %d", status);
+        }
+    }
+    // Configure advertising
+    gap->state = new_state;
+    const char* name = furi_hal_version_get_ble_local_device_name_ptr();
+    status = aci_gap_set_discoverable(ADV_IND, min_interval, max_interval, PUBLIC_ADDR, 0,
+                                        strlen(name), (uint8_t*)name,
+                                        gap->gap_svc.adv_svc_uuid_len, gap->gap_svc.adv_svc_uuid, 0, 0);
+    if(status) {
+        FURI_LOG_E(GAP_TAG, "Set discoverable err: %d", status);
+    }
+    osTimerStart(gap->advertise_timer, INITIAL_ADV_TIMEOUT);
+}
+
+static void gap_advertise_request(Gap* gap) {
+    osThreadFlagsSet(gap->thread_id, 1);
+}
+
+static void gap_advetise_timer_callback(void* context) {
+    furi_assert(context);
+    Gap* gap = context;
+    gap_advertise_request(gap);
+}
+
+bool gap_init() {
+    if (APPE_Status() != BleGlueStatusStarted) {
+        return false;
+    }
+
+    gap = furi_alloc(sizeof(Gap));
+    srand(DWT->CYCCNT);
+    // Open Bt record
+    gap->bt = furi_record_open("bt");
+    // Create advertising timer
+    gap->advertise_timer = osTimerNew(gap_advetise_timer_callback, osTimerOnce, &gap, NULL);
+    // Initialization of HCI & GATT & GAP layer
+    gap_init_svc(gap);
+    // Initialization of the BLE Services
+    SVCCTL_Init();
+    // Initialization of the BLE App Context
+    gap->state = GapStateIdle;
+    gap->gap_svc.connection_handle = 0xFFFF;
+
+    // Thread configuration
+    gap->thread_attr.name = "BLE advertising";
+    gap->thread_attr.stack_size = 512;
+    gap->thread_id = osThreadNew(gap_app, NULL, &gap->thread_attr);
+
+    // Start Device Information service
+    dev_info_svc_start();
+    // Start Battery service
+    battery_svc_start();
+    // Start Serial application
+    serial_svc_start();
+    // Configure advirtise service UUID
+    uint8_t adv_service_uid[2];
+    adv_service_uid[0] = 0x80 | furi_hal_version_get_hw_color();
+    adv_service_uid[1] = 0x30;
+
+    set_advertisment_service_uid(adv_service_uid, sizeof(adv_service_uid));
+    gap_advertise(GapStateAdvFast);
+    return true;
+}
+
+static void gap_app(void *arg) {
+    // TODO Exit from app, stop service, clean memory
+    while(1) {
+        osThreadFlagsWait(1, osFlagsWaitAny, osWaitForever);
+        gap_advertise(GapStateAdvLowPower);
+    }
+}

+ 22 - 0
firmware/targets/f7/ble-glue/gap.h

@@ -0,0 +1,22 @@
+#pragma once
+
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+    GapStateIdle,
+    GapStateAdvFast,
+    GapStateAdvLowPower,
+    GapStateConnected,
+} GapState;
+
+bool gap_init();
+
+GapState gap_get_status();
+
+#ifdef __cplusplus
+}
+#endif

+ 42 - 22
firmware/targets/f7/ble-glue/serial_service.c

@@ -6,13 +6,19 @@
 
 
 #define SERIAL_SERVICE_TAG "serial service"
 #define SERIAL_SERVICE_TAG "serial service"
 
 
+#define SERIAL_SVC_DATA_LEN_MAX 245
+
 typedef struct {
 typedef struct {
     uint16_t svc_handle;
     uint16_t svc_handle;
     uint16_t rx_char_handle;
     uint16_t rx_char_handle;
     uint16_t tx_char_handle;
     uint16_t tx_char_handle;
 } SerialSvc;
 } SerialSvc;
 
 
-static SerialSvc serial_svc;
+static SerialSvc* serial_svc;
+
+static const uint8_t service_uuid[] = {0x00, 0x00, 0xfe, 0x60, 0xcc, 0x7a, 0x48, 0x2a, 0x98, 0x4a, 0x7f, 0x2e, 0xd5, 0xb3, 0xe5, 0x8f};
+static const uint8_t char_rx_uuid[] = {0x00, 0x00, 0xfe, 0x61, 0x8e, 0x22, 0x45, 0x41, 0x9d, 0x4c, 0x21, 0xed, 0xae, 0x82, 0xed, 0x19};
+static const uint8_t char_tx_uuid[] = {0x00, 0x00, 0xfe, 0x62, 0x8e, 0x22, 0x45, 0x41, 0x9d, 0x4c, 0x21, 0xed, 0xae, 0x82, 0xed, 0x19};
 
 
 static SVCCTL_EvtAckStatus_t serial_svc_event_handler(void *event) {
 static SVCCTL_EvtAckStatus_t serial_svc_event_handler(void *event) {
     SVCCTL_EvtAckStatus_t ret = SVCCTL_EvtNotAck;
     SVCCTL_EvtAckStatus_t ret = SVCCTL_EvtNotAck;
@@ -22,76 +28,90 @@ static SVCCTL_EvtAckStatus_t serial_svc_event_handler(void *event) {
     if(event_pckt->evt == HCI_VENDOR_SPECIFIC_DEBUG_EVT_CODE) {
     if(event_pckt->evt == HCI_VENDOR_SPECIFIC_DEBUG_EVT_CODE) {
         if(blecore_evt->ecode == ACI_GATT_ATTRIBUTE_MODIFIED_VSEVT_CODE) {
         if(blecore_evt->ecode == ACI_GATT_ATTRIBUTE_MODIFIED_VSEVT_CODE) {
             attribute_modified = (aci_gatt_attribute_modified_event_rp0*)blecore_evt->data;
             attribute_modified = (aci_gatt_attribute_modified_event_rp0*)blecore_evt->data;
-            if(attribute_modified->Attr_Handle == serial_svc.tx_char_handle + 2) {
+            if(attribute_modified->Attr_Handle == serial_svc->tx_char_handle + 2) {
                 // Descriptor handle
                 // Descriptor handle
                 ret = SVCCTL_EvtAckFlowEnable;
                 ret = SVCCTL_EvtAckFlowEnable;
                 FURI_LOG_D(SERIAL_SERVICE_TAG, "TX descriptor event");
                 FURI_LOG_D(SERIAL_SERVICE_TAG, "TX descriptor event");
-            } else if(attribute_modified->Attr_Handle == serial_svc.tx_char_handle + 1) {
-                FURI_LOG_I(SERIAL_SERVICE_TAG, "Data len: %d", attribute_modified->Attr_Data_Length);
-                for(uint8_t i = 0; i < attribute_modified->Attr_Data_Length; i++) {
-                    printf("%02X ", attribute_modified->Attr_Data[i]);
-                }
-                printf("\r\n");
+            } else if(attribute_modified->Attr_Handle == serial_svc->tx_char_handle + 1) {
+                FURI_LOG_D(SERIAL_SERVICE_TAG, "Received %d bytes", attribute_modified->Attr_Data_Length);
                 serial_svc_update_rx(attribute_modified->Attr_Data, attribute_modified->Attr_Data_Length);
                 serial_svc_update_rx(attribute_modified->Attr_Data, attribute_modified->Attr_Data_Length);
                 ret = SVCCTL_EvtAckFlowEnable;
                 ret = SVCCTL_EvtAckFlowEnable;
             }
             }
         } else if(blecore_evt->ecode == ACI_GATT_SERVER_CONFIRMATION_VSEVT_CODE) {
         } else if(blecore_evt->ecode == ACI_GATT_SERVER_CONFIRMATION_VSEVT_CODE) {
-            FURI_LOG_I(SERIAL_SERVICE_TAG, "Ack received", blecore_evt->ecode);
+            FURI_LOG_D(SERIAL_SERVICE_TAG, "Ack received", blecore_evt->ecode);
             ret = SVCCTL_EvtAckFlowEnable;
             ret = SVCCTL_EvtAckFlowEnable;
         }
         }
     }
     }
     return ret;
     return ret;
 }
 }
 
 
-bool serial_svc_init() {
+void serial_svc_start() {
     tBleStatus status;
     tBleStatus status;
-    const uint8_t service_uuid[] = {SERIAL_SVC_UUID_128};
-    const uint8_t char_rx_uuid[] = {SERIAL_CHAR_RX_UUID_128};
-    const uint8_t char_tx_uuid[] = {SERIAL_CHAR_TX_UUID_128};
-
+    serial_svc = furi_alloc(sizeof(SerialSvc));
     // Register event handler
     // Register event handler
     SVCCTL_RegisterSvcHandler(serial_svc_event_handler);
     SVCCTL_RegisterSvcHandler(serial_svc_event_handler);
 
 
     // Add service
     // Add service
-    status = aci_gatt_add_service(UUID_TYPE_128, (Service_UUID_t *)service_uuid, PRIMARY_SERVICE, 6, &serial_svc.svc_handle);
+    status = aci_gatt_add_service(UUID_TYPE_128, (Service_UUID_t *)service_uuid, PRIMARY_SERVICE, 6, &serial_svc->svc_handle);
     if(status) {
     if(status) {
         FURI_LOG_E(SERIAL_SERVICE_TAG, "Failed to add Serial service: %d", status);
         FURI_LOG_E(SERIAL_SERVICE_TAG, "Failed to add Serial service: %d", status);
     }
     }
 
 
     // Add TX characteristics
     // Add TX characteristics
-    status = aci_gatt_add_char(serial_svc.svc_handle, UUID_TYPE_128, (const Char_UUID_t*)char_tx_uuid ,
+    status = aci_gatt_add_char(serial_svc->svc_handle, UUID_TYPE_128, (const Char_UUID_t*)char_tx_uuid,
                                 SERIAL_SVC_DATA_LEN_MAX,
                                 SERIAL_SVC_DATA_LEN_MAX,
                                 CHAR_PROP_WRITE_WITHOUT_RESP | CHAR_PROP_WRITE | CHAR_PROP_READ,
                                 CHAR_PROP_WRITE_WITHOUT_RESP | CHAR_PROP_WRITE | CHAR_PROP_READ,
                                 ATTR_PERMISSION_NONE,
                                 ATTR_PERMISSION_NONE,
                                 GATT_NOTIFY_ATTRIBUTE_WRITE,
                                 GATT_NOTIFY_ATTRIBUTE_WRITE,
                                 10,
                                 10,
                                 CHAR_VALUE_LEN_VARIABLE,
                                 CHAR_VALUE_LEN_VARIABLE,
-                                &serial_svc.tx_char_handle);
+                                &serial_svc->tx_char_handle);
     if(status) {
     if(status) {
         FURI_LOG_E(SERIAL_SERVICE_TAG, "Failed to add TX characteristic: %d", status);
         FURI_LOG_E(SERIAL_SERVICE_TAG, "Failed to add TX characteristic: %d", status);
     }
     }
 
 
     // Add RX characteristic
     // Add RX characteristic
-    status = aci_gatt_add_char(serial_svc.svc_handle, UUID_TYPE_128, (const Char_UUID_t*)char_rx_uuid ,
+    status = aci_gatt_add_char(serial_svc->svc_handle, UUID_TYPE_128, (const Char_UUID_t*)char_rx_uuid,
                                 SERIAL_SVC_DATA_LEN_MAX,                                  
                                 SERIAL_SVC_DATA_LEN_MAX,                                  
                                 CHAR_PROP_READ | CHAR_PROP_INDICATE,
                                 CHAR_PROP_READ | CHAR_PROP_INDICATE,
                                 ATTR_PERMISSION_NONE,
                                 ATTR_PERMISSION_NONE,
                                 GATT_DONT_NOTIFY_EVENTS,
                                 GATT_DONT_NOTIFY_EVENTS,
                                 10,
                                 10,
                                 CHAR_VALUE_LEN_VARIABLE,
                                 CHAR_VALUE_LEN_VARIABLE,
-                                &serial_svc.rx_char_handle);
+                                &serial_svc->rx_char_handle);
     if(status) {
     if(status) {
         FURI_LOG_E(SERIAL_SERVICE_TAG, "Failed to add RX characteristic: %d", status);
         FURI_LOG_E(SERIAL_SERVICE_TAG, "Failed to add RX characteristic: %d", status);
     }
     }
+}
 
 
-    return status != BLE_STATUS_SUCCESS;
+void serial_svc_stop() {
+    tBleStatus status;
+    if(serial_svc) {
+        // Delete characteristics
+        status = aci_gatt_del_char(serial_svc->svc_handle, serial_svc->tx_char_handle);
+        if(status) {
+            FURI_LOG_E(SERIAL_SERVICE_TAG, "Failed to delete TX characteristic: %d", status);
+        }
+        status = aci_gatt_del_char(serial_svc->svc_handle, serial_svc->rx_char_handle);
+        if(status) {
+            FURI_LOG_E(SERIAL_SERVICE_TAG, "Failed to delete RX characteristic: %d", status);
+        }
+        // Delete service
+        status = aci_gatt_del_service(serial_svc->svc_handle);
+        if(status) {
+            FURI_LOG_E(SERIAL_SERVICE_TAG, "Failed to delete Serial service: %d", status);
+        }
+        free(serial_svc);
+        serial_svc = NULL;
+    }
 }
 }
 
 
+
 bool serial_svc_update_rx(uint8_t* data, uint8_t data_len) {
 bool serial_svc_update_rx(uint8_t* data, uint8_t data_len) {
     furi_assert(data_len < SERIAL_SVC_DATA_LEN_MAX);
     furi_assert(data_len < SERIAL_SVC_DATA_LEN_MAX);
 
 
-    tBleStatus result = aci_gatt_update_char_value(serial_svc.svc_handle,
-                                          serial_svc.rx_char_handle,
+    tBleStatus result = aci_gatt_update_char_value(serial_svc->svc_handle,
+                                          serial_svc->rx_char_handle,
                                           0,
                                           0,
                                           data_len,
                                           data_len,
                                           data);
                                           data);

+ 2 - 6
firmware/targets/f7/ble-glue/serial_service.h

@@ -7,13 +7,9 @@
 extern "C" {
 extern "C" {
 #endif
 #endif
 
 
-#define SERIAL_SVC_DATA_LEN_MAX 255
+void serial_svc_start();
 
 
-#define SERIAL_SVC_UUID_128 0x00, 0x00, 0xfe, 0x60, 0xcc, 0x7a, 0x48, 0x2a, 0x98, 0x4a, 0x7f, 0x2e, 0xd5, 0xb3, 0xe5, 0x8f
-#define SERIAL_CHAR_RX_UUID_128 0x00, 0x00, 0xfe, 0x61, 0x8e, 0x22, 0x45, 0x41, 0x9d, 0x4c, 0x21, 0xed, 0xae, 0x82, 0xed, 0x19
-#define SERIAL_CHAR_TX_UUID_128 0x00, 0x00, 0xfe, 0x62, 0x8e, 0x22, 0x45, 0x41, 0x9d, 0x4c, 0x21, 0xed, 0xae, 0x82, 0xed, 0x19
-
-bool serial_svc_init();
+void serial_svc_stop();
 
 
 bool serial_svc_update_rx(uint8_t* data, uint8_t data_len);
 bool serial_svc_update_rx(uint8_t* data, uint8_t data_len);
 
 

+ 2 - 1
firmware/targets/f7/furi-hal/furi-hal-bt.c

@@ -5,6 +5,7 @@
 #include <shci.h>
 #include <shci.h>
 #include <cmsis_os2.h>
 #include <cmsis_os2.h>
 #include <app_ble.h>
 #include <app_ble.h>
+#include <gap.h>
 
 
 void furi_hal_bt_init() {
 void furi_hal_bt_init() {
     // Explicitly tell that we are in charge of CLK48 domain
     // Explicitly tell that we are in charge of CLK48 domain
@@ -14,7 +15,7 @@ void furi_hal_bt_init() {
 }
 }
 
 
 bool furi_hal_bt_start_app() {
 bool furi_hal_bt_start_app() {
-    return APP_BLE_Start();
+    return gap_init();
 }
 }
 
 
 void furi_hal_bt_dump_state(string_t buffer) {
 void furi_hal_bt_dump_state(string_t buffer) {