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

[FL-1722] BLE custom serial service (#685)

* 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

Co-authored-by: あく <alleteam@gmail.com>
gornekich 4 лет назад
Родитель
Сommit
9bce160ca6

+ 11 - 0
applications/bt/bt_service/bt.c

@@ -1,4 +1,5 @@
 #include "bt_i.h"
+#include "battery_service.h"
 
 #define BT_SERVICE_TAG "BT"
 
@@ -43,6 +44,12 @@ Bt* bt_alloc() {
     return bt;
 }
 
+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;
+}
+
 int32_t bt_srv() {
     Bt* bt = bt_alloc();
     furi_record_create("bt", bt);
@@ -68,6 +75,10 @@ int32_t bt_srv() {
         if(message.type == BtMessageTypeUpdateStatusbar) {
             // Update statusbar
             view_port_enabled_set(bt->statusbar_view_port, furi_hal_bt_is_alive());
+        } else if(message.type == BtMessageTypeUpdateBatteryLevel) {
+            if(furi_hal_bt_is_alive()) {
+                battery_svc_update_level(message.data.battery_level);
+            }
         }
     }
     return 0;

+ 13 - 0
applications/bt/bt_service/bt.h

@@ -1,3 +1,16 @@
 #pragma once
 
+#include <stdint.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 typedef struct Bt Bt;
+
+bool bt_update_battery_level(Bt* bt, uint8_t battery_level);
+
+#ifdef __cplusplus
+}
+#endif

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

@@ -13,11 +13,16 @@
 
 typedef enum {
     BtMessageTypeUpdateStatusbar,
+    BtMessageTypeUpdateBatteryLevel,
 } BtMessageType;
 
+typedef union {
+    uint8_t battery_level;
+} BtMessageData;
+
 typedef struct {
     BtMessageType type;
-    void* param;
+    BtMessageData data;
 } BtMessage;
 
 struct Bt {

+ 12 - 1
applications/power/power.c

@@ -18,6 +18,7 @@
 #include <stm32wbxx.h>
 
 #include <notification/notification-messages.h>
+#include <applications/bt/bt_service/bt.h>
 
 #define POWER_OFF_TIMEOUT 30
 
@@ -39,6 +40,7 @@ struct Power {
 
     ValueMutex* menu_vm;
     Cli* cli;
+    Bt* bt;
     MenuItem* menu;
 
     PowerState state;
@@ -108,6 +110,8 @@ Power* power_alloc() {
     power->cli = furi_record_open("cli");
     power_cli_init(power->cli, power);
 
+    power->bt = furi_record_open("bt");
+
     power->menu = menu_item_alloc_menu("Power", icon_animation_alloc(&A_Power_14));
     menu_item_subitem_add(
         power->menu, menu_item_alloc_function("Off", NULL, power_menu_off_callback, power));
@@ -206,13 +210,15 @@ int32_t power_srv(void* p) {
         power->menu_vm, (Menu * menu) { menu_item_add(menu, power->menu); });
 
     furi_record_create("power", power);
-
+    uint8_t battery_level = 0;
+    uint8_t battery_level_prev = 0;
     while(1) {
         bool battery_low = false;
 
         with_view_model(
             power->info_view, (PowerInfoModel * model) {
                 model->charge = furi_hal_power_get_pct();
+                battery_level = model->charge;
                 model->health = furi_hal_power_get_bat_health_pct();
                 model->capacity_remaining = furi_hal_power_get_battery_remaining_capacity();
                 model->capacity_full = furi_hal_power_get_battery_full_capacity();
@@ -258,6 +264,11 @@ int32_t power_srv(void* p) {
 
         power_charging_indication_handler(power, notifications);
 
+        if(battery_level_prev != battery_level) {
+            battery_level_prev = battery_level;
+            bt_update_battery_level(power->bt, battery_level);
+        }
+
         view_port_update(power->battery_view_port);
 
         osDelay(1024);

+ 8 - 0
core/furi/common_defines.h

@@ -40,3 +40,11 @@
         y = SWAP;           \
     } while(0)
 #endif
+
+#ifndef PLACE_IN_SECTION
+#define PLACE_IN_SECTION(x) __attribute__((section(x)))
+#endif
+
+#ifndef ALIGN
+#define ALIGN(n) __attribute__((aligned(n)))
+#endif

+ 35 - 66
firmware/targets/f6/ble-glue/app_ble.c

@@ -10,8 +10,9 @@
 #include "cmsis_os.h"
 #include "shci.h"
 #include "otp.h"
-#include "dis_app.h"
-#include "hrs_app.h"
+#include "dev_info_service.h"
+#include "battery_service.h"
+#include "serial_service.h"
 
 #include <furi-hal.h>
 
@@ -123,7 +124,6 @@ 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 Add_Advertisment_Service_UUID( uint16_t servUUID );
 static void Adv_Mgr( void );
 static void AdvUpdateProcess(void *argument);
 static void Adv_Update( void );
@@ -160,6 +160,8 @@ bool APP_BLE_Init() {
   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;
@@ -180,16 +182,18 @@ bool APP_BLE_Start() {
 #endif
 
   // Initialize DIS Application
-  DISAPP_Init();
-  // Initialize HRS Application
-  HRSAPP_Init();
+  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;
 
-  // Make device discoverable
-  BleApplicationContext.BleApplicationContext_legacy.advtServUUID[0] = AD_TYPE_16_BIT_SERV_UUID;
-  BleApplicationContext.BleApplicationContext_legacy.advtServUUIDlen = 1;
-  Add_Advertisment_Service_UUID(HEART_RATE_SERVICE_UUID);
+  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;
@@ -198,6 +202,11 @@ bool APP_BLE_Start() {
   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;
@@ -382,54 +391,21 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification( void *pckt )
   return (SVCCTL_UserEvtFlowEnable);
 }
 
-APP_BLE_ConnStatus_t APP_BLE_Get_Server_Connection_Status() {
-    return BleApplicationContext.Device_Connection_Status;
-}
-
-/* USER CODE BEGIN FD*/
-void APP_BLE_Key_Button1_Action() {
-  tBleStatus ret = BLE_STATUS_INVALID_PARAMS;
-  ret = aci_gap_clear_security_db();
-  if (ret == BLE_STATUS_SUCCESS) {
-    APP_DBG_MSG("Successfully aci_gap_clear_security_db()\r\n");
-  } else {
-    APP_DBG_MSG("aci_gap_clear_security_db() Failed , result: %d \r\n", ret);
-  }
-}
-
-void APP_BLE_Key_Button2_Action() {
-  tBleStatus ret = BLE_STATUS_INVALID_PARAMS;
-  ret = aci_gap_slave_security_req(BleApplicationContext.BleApplicationContext_legacy.connectionHandle); 
-  if (ret == BLE_STATUS_SUCCESS) {
-    APP_DBG_MSG("Successfully aci_gap_slave_security_req()");
-  } else {
-    APP_DBG_MSG("aci_gap_slave_security_req() Failed , result: %d \r\n", ret);
-  }
+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;
 }
-  
-void APP_BLE_Key_Button3_Action() {
-  uint8_t TX_PHY, RX_PHY;
-  tBleStatus ret = BLE_STATUS_INVALID_PARAMS;
-  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");
-    APP_DBG_MSG("PHY Param  TX= %d, RX= %d \r\n", TX_PHY, RX_PHY);
-    if ((TX_PHY == TX_2M) && (RX_PHY == RX_2M)) {
-      APP_DBG_MSG("hci_le_set_phy PHY Param  TX= %d, RX= %d \r\n", TX_1M, RX_1M);
-      ret = hci_le_set_phy(BleApplicationContext.BleApplicationContext_legacy.connectionHandle,ALL_PHYS_PREFERENCE,TX_1M,RX_1M,0);
-    } else {
-      APP_DBG_MSG("hci_le_set_phy PHY Param  TX= %d, RX= %d \r\n", TX_2M_PREFERRED, RX_2M_PREFERRED);
-      ret = hci_le_set_phy(BleApplicationContext.BleApplicationContext_legacy.connectionHandle,ALL_PHYS_PREFERENCE,TX_2M_PREFERRED,RX_2M_PREFERRED,0);
-    } 
-  } else {
-    APP_DBG_MSG("Read conf not succeess \r\n");
-  }
 
-  if (ret == BLE_STATUS_SUCCESS) {
-    APP_DBG_MSG("set PHY cmd ok\r\n");
-  } else {
-    APP_DBG_MSG("set PHY cmd NOK\r\n");
-  }
+APP_BLE_ConnStatus_t APP_BLE_Get_Server_Connection_Status() {
+    return BleApplicationContext.Device_Connection_Status;
 }
 
 static void Ble_Tl_Init( void ) {
@@ -654,6 +630,9 @@ static void Adv_Request(APP_BLE_ConnStatus_t New_Status)
         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);
@@ -712,16 +691,6 @@ const uint8_t* BleGetBdAddress( void ) {
  *SPECIFIC FUNCTIONS
  *
  *************************************************************/
-static void Add_Advertisment_Service_UUID( uint16_t servUUID ) {
-  BleApplicationContext.BleApplicationContext_legacy.advtServUUID[BleApplicationContext.BleApplicationContext_legacy.advtServUUIDlen] =
-      (uint8_t) (servUUID & 0xFF);
-  BleApplicationContext.BleApplicationContext_legacy.advtServUUIDlen++;
-  BleApplicationContext.BleApplicationContext_legacy.advtServUUID[BleApplicationContext.BleApplicationContext_legacy.advtServUUIDlen] =
-      (uint8_t) (servUUID >> 8) & 0xFF;
-  BleApplicationContext.BleApplicationContext_legacy.advtServUUIDlen++;
-
-}
-
 static void Adv_Mgr( void ) {
   /**
    * The code shall be executed in the background as an aci command may be sent

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

@@ -22,10 +22,6 @@ bool APP_BLE_Start();
 
 APP_BLE_ConnStatus_t APP_BLE_Get_Server_Connection_Status();
 
-void APP_BLE_Key_Button1_Action();
-void APP_BLE_Key_Button2_Action();
-void APP_BLE_Key_Button3_Action();
-
 #ifdef __cplusplus
 }
 #endif

+ 3 - 72
firmware/targets/f6/ble-glue/app_common.h

@@ -32,81 +32,12 @@ extern "C"{
 #include <stdlib.h>
 #include <stdarg.h>
 
-#include "app_conf.h"
-
-  /* -------------------------------- *
-   *  Basic definitions               *
-   * -------------------------------- */
-
-#undef NULL
-#define NULL                    0
-
-#undef FALSE
-#define FALSE                   0
-
-#undef TRUE
-#define TRUE                    (!0)
-
-  /* -------------------------------- *
-   *  Critical Section definition     *
-   * -------------------------------- */
-#define BACKUP_PRIMASK()    uint32_t primask_bit= __get_PRIMASK()
-#define DISABLE_IRQ()       __disable_irq()
-#define RESTORE_PRIMASK()   __set_PRIMASK(primask_bit)
-
-  /* -------------------------------- *
-   *  Macro delimiters                *
-   * -------------------------------- */
-
-#define M_BEGIN     do {
-
-#define M_END       } while(0)
-
-  /* -------------------------------- *
-   *  Some useful macro definitions   *
-   * -------------------------------- */
-
-
-#define MODINC( a, m )       M_BEGIN  (a)++;  if ((a)>=(m)) (a)=0;  M_END
-
-#define MODDEC( a, m )       M_BEGIN  if ((a)==0) (a)=(m);  (a)--;  M_END
-
-#define MODADD( a, b, m )    M_BEGIN  (a)+=(b);  if ((a)>=(m)) (a)-=(m);  M_END
+#include <furi/common_defines.h>
 
-#define MODSUB( a, b, m )    MODADD( a, (m)-(b), m )
-
-#define PAUSE( t )           M_BEGIN \
-                               __IO int _i; \
-                               for ( _i = t; _i > 0; _i -- ); \
-                             M_END
-
-#define DIVF( x, y )         ((x)/(y))
+#include "app_conf.h"
 
 #define DIVC( x, y )         (((x)+(y)-1)/(y))
 
 #define DIVR( x, y )         (((x)+((y)/2))/(y))
 
-#define SHRR( x, n )         ((((x)>>((n)-1))+1)>>1)
-
-#define BITN( w, n )         (((w)[(n)/32] >> ((n)%32)) & 1)
-
-#define BITNSET( w, n, b )   M_BEGIN (w)[(n)/32] |= ((U32)(b))<<((n)%32); M_END
-
-  /* -------------------------------- *
-   *  Compiler                         *
-   * -------------------------------- */
-#define PLACE_IN_SECTION( __x__ )  __attribute__((section (__x__)))
-
-#ifdef WIN32
-#define ALIGN(n)
-#else
-#define ALIGN(n)             __attribute__((aligned(n)))
-#endif
-
-#ifdef __cplusplus
-} /* extern "C" */
-#endif
-
-#endif /*APP_COMMON_H */
-
-/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+#endif

+ 0 - 367
firmware/targets/f6/ble-glue/app_debug.c

@@ -1,367 +0,0 @@
-/* USER CODE BEGIN Header */
-/**
- ******************************************************************************
-  * File Name          : app_debug.c
-  * Description        : Debug capabilities source file for STM32WPAN Middleware
- ******************************************************************************
-  * @attention
-  *
-  * <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
-  * All rights reserved.</center></h2>
-  *
-  * This software component is licensed by ST under Ultimate Liberty license
-  * SLA0044, the "License"; You may not use this file except in compliance with
-  * the License. You may obtain a copy of the License at:
-  *                             www.st.com/SLA0044
-  *
- ******************************************************************************
- */
-/* USER CODE END Header */
-
-/* Includes ------------------------------------------------------------------*/
-/* USER CODE BEGIN Includes */
-#include "app_common.h"
-
-#include "app_debug.h"
-#include "utilities_common.h"
-#include "shci.h"
-#include "tl.h"
-#include "dbg_trace.h"
-#include <furi-hal.h>
-/* USER CODE END Includes */
-
-/* Private typedef -----------------------------------------------------------*/
-/* USER CODE BEGIN PTD */
-typedef PACKED_STRUCT
-{
-  GPIO_TypeDef* port;
-  uint16_t pin;
-  uint8_t enable;
-  uint8_t reserved;
-} APPD_GpioConfig_t;
-/* USER CODE END PTD */
-
-/* Private defines -----------------------------------------------------------*/
-/* USER CODE BEGIN PD */
-#define GPIO_NBR_OF_RF_SIGNALS                  9
-#define GPIO_CFG_NBR_OF_FEATURES                34
-#define NBR_OF_TRACES_CONFIG_PARAMETERS         4
-#define NBR_OF_GENERAL_CONFIG_PARAMETERS        4
-
-/**
- * THIS SHALL BE SET TO A VALUE DIFFERENT FROM 0 ONLY ON REQUEST FROM ST SUPPORT
- */
-#define BLE_DTB_CFG     0
-#define SYS_DBG_CFG1  (SHCI_C2_DEBUG_OPTIONS_IPCORE_LP | SHCI_C2_DEBUG_OPTIONS_CPU2_STOP_EN) 
-/* USER CODE END PD */
-
-/* Private variables ---------------------------------------------------------*/
-/* USER CODE BEGIN PV */
-PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static SHCI_C2_DEBUG_TracesConfig_t APPD_TracesConfig={0, 0, 0, 0};
-PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static SHCI_C2_DEBUG_GeneralConfig_t APPD_GeneralConfig={BLE_DTB_CFG, SYS_DBG_CFG1, {0, 0}};
-
-/**
- * THE DEBUG ON GPIO FOR CPU2 IS INTENDED TO BE USED ONLY ON REQUEST FROM ST SUPPORT
- * It provides timing information on the CPU2 activity.
- * All configuration of (port, pin) is supported for each features and can be selected by the user
- * depending on the availability
- */
-static const APPD_GpioConfig_t aGpioConfigList[GPIO_CFG_NBR_OF_FEATURES] =
-{
-    { GPIOA, LL_GPIO_PIN_0, 0, 0},  /* BLE_ISR - Set on Entry / Reset on Exit */
-    { GPIOA, LL_GPIO_PIN_0, 0, 0},  /* BLE_STACK_TICK - Set on Entry / Reset on Exit */
-    { GPIOA, LL_GPIO_PIN_0, 0, 0},  /* BLE_CMD_PROCESS - Set on Entry / Reset on Exit */
-    { GPIOA, LL_GPIO_PIN_0, 0, 0},  /* BLE_ACL_DATA_PROCESS - Set on Entry / Reset on Exit */
-    { GPIOA, LL_GPIO_PIN_0, 0, 0},  /* SYS_CMD_PROCESS - Set on Entry / Reset on Exit */
-    { GPIOA, LL_GPIO_PIN_0, 0, 0},  /* RNG_PROCESS - Set on Entry / Reset on Exit */
-    { GPIOA, LL_GPIO_PIN_0, 0, 0},  /* NVM_PROCESS - Set on Entry / Reset on Exit */
-    { GPIOA, LL_GPIO_PIN_0, 0, 0},  /* IPCC_GENERAL - Set on Entry / Reset on Exit */
-    { GPIOA, LL_GPIO_PIN_0, 0, 0},  /* IPCC_BLE_CMD_RX - Set on Entry / Reset on Exit */
-    { GPIOA, LL_GPIO_PIN_0, 0, 0},  /* IPCC_BLE_EVT_TX - Set on Entry / Reset on Exit */
-    { GPIOA, LL_GPIO_PIN_0, 0, 0},  /* IPCC_BLE_ACL_DATA_RX - Set on Entry / Reset on Exit */
-    { GPIOA, LL_GPIO_PIN_0, 0, 0},  /* IPCC_SYS_CMD_RX - Set on Entry / Reset on Exit */
-    { GPIOA, LL_GPIO_PIN_0, 0, 0},  /* IPCC_SYS_EVT_TX - Set on Entry / Reset on Exit */
-    { GPIOA, LL_GPIO_PIN_0, 0, 0},  /* IPCC_CLI_CMD_RX - Set on Entry / Reset on Exit */
-    { GPIOA, LL_GPIO_PIN_0, 0, 0},  /* IPCC_OT_CMD_RX - Set on Entry / Reset on Exit */
-    { GPIOA, LL_GPIO_PIN_0, 0, 0},  /* IPCC_OT_ACK_TX - Set on Entry / Reset on Exit */
-    { GPIOA, LL_GPIO_PIN_0, 0, 0},  /* IPCC_CLI_ACK_TX - Set on Entry / Reset on Exit */
-    { GPIOA, LL_GPIO_PIN_0, 0, 0},  /* IPCC_MEM_MANAGER_RX - Set on Entry / Reset on Exit */
-    { GPIOA, LL_GPIO_PIN_0, 0, 0},  /* IPCC_TRACES_TX - Set on Entry / Reset on Exit */
-    { GPIOA, LL_GPIO_PIN_0, 0, 0},  /* HARD_FAULT - Set on Entry / Reset on Exit */
-/* From v1.1.1 */
-    { GPIOA, LL_GPIO_PIN_0, 0, 0},  /* IP_CORE_LP_STATUS - Set on Entry / Reset on Exit */
-/* From v1.2.0 */
-    { GPIOA, LL_GPIO_PIN_0, 0, 0},  /* END_OF_CONNECTION_EVENT - Set on Entry / Reset on Exit */
-    { GPIOA, LL_GPIO_PIN_0, 0, 0},  /* TIMER_SERVER_CALLBACK - Toggle on Entry */
-    { GPIOA, LL_GPIO_PIN_0, 0, 0},  /* PES_ACTIVITY - Set on Entry / Reset on Exit */
-    { GPIOA, LL_GPIO_PIN_0, 0, 0},  /* MB_BLE_SEND_EVT - Set on Entry / Reset on Exit */
-/* From v1.3.0 */
-    { GPIOA, LL_GPIO_PIN_0, 0, 0},  /* BLE_NO_DELAY - Set on Entry / Reset on Exit */
-    { GPIOA, LL_GPIO_PIN_0, 0, 0},  /* BLE_STACK_STORE_NVM_CB - Set on Entry / Reset on Exit */
-    { GPIOA, LL_GPIO_PIN_0, 0, 0},  /* NVMA_WRITE_ONGOING - Set on Entry / Reset on Exit */
-    { GPIOA, LL_GPIO_PIN_0, 0, 0},  /* NVMA_WRITE_COMPLETE - Set on Entry / Reset on Exit */
-    { GPIOA, LL_GPIO_PIN_0, 0, 0},  /* NVMA_CLEANUP - Set on Entry / Reset on Exit */
-/* From v1.4.0 */
-    { GPIOA, LL_GPIO_PIN_0, 0, 0},  /* NVMA_START - Set on Entry / Reset on Exit */
-    { GPIOA, LL_GPIO_PIN_0, 0, 0},  /* FLASH_EOP - Set on Entry / Reset on Exit */
-    { GPIOA, LL_GPIO_PIN_0, 0, 0},  /* FLASH_WRITE - Set on Entry / Reset on Exit */
-    { GPIOA, LL_GPIO_PIN_0, 0, 0},  /* FLASH_ERASE - Set on Entry / Reset on Exit */
-};
-
-/**
- * THE DEBUG ON GPIO FOR CPU2 IS INTENDED TO BE USED ONLY ON REQUEST FROM ST SUPPORT
- * This table is relevant only for BLE
- * It provides timing information on BLE RF activity.
- * New signals may be allocated at any location when requested by ST
- * The GPIO allocated to each signal depend on the BLE_DTB_CFG value and cannot be changed
- */
-#if( BLE_DTB_CFG == 7)
-static const APPD_GpioConfig_t aRfConfigList[GPIO_NBR_OF_RF_SIGNALS] =
-{
-    { GPIOB, LL_GPIO_PIN_2, 0, 0},      /* DTB10 - Tx/Rx SPI */
-    { GPIOB, LL_GPIO_PIN_7, 0, 0},      /* DTB11 - Tx/Tx SPI Clk */
-    { GPIOA, LL_GPIO_PIN_8, 0, 0},      /* DTB12 - Tx/Rx Ready & SPI Select */
-    { GPIOA, LL_GPIO_PIN_9, 0, 0},      /* DTB13 - Tx/Rx Start */
-    { GPIOA, LL_GPIO_PIN_10, 0, 0},     /* DTB14 - FSM0 */
-    { GPIOA, LL_GPIO_PIN_11, 0, 0},     /* DTB15 - FSM1 */
-    { GPIOB, LL_GPIO_PIN_8, 0, 0},      /* DTB16 - FSM2 */
-    { GPIOB, LL_GPIO_PIN_11, 0, 0},     /* DTB17 - FSM3 */
-    { GPIOB, LL_GPIO_PIN_10, 0, 0},     /* DTB18 - FSM4 */
-};
-#endif
-/* USER CODE END PV */
-
-/* Global variables ----------------------------------------------------------*/
-/* USER CODE BEGIN GV */
-/* USER CODE END GV */
-
-/* Private function prototypes -----------------------------------------------*/
-/* USER CODE BEGIN PFP */
-static void APPD_SetCPU2GpioConfig( void );
-static void APPD_BleDtbCfg( void );
-/* USER CODE END PFP */
-
-/* Functions Definition ------------------------------------------------------*/
-void APPD_Init( void )
-{
-/* USER CODE BEGIN APPD_Init */
-#if (CFG_DEBUGGER_SUPPORTED == 1)
-  /**
-   * Keep debugger enabled while in any low power mode
-   */
-  HAL_DBGMCU_EnableDBGSleepMode();
-  HAL_DBGMCU_EnableDBGStopMode();
-
-  /***************** ENABLE DEBUGGER *************************************/
-  LL_EXTI_EnableIT_32_63(LL_EXTI_LINE_48);
-
-#else
-  GPIO_InitTypeDef gpio_config = {0};
-
-  gpio_config.Pull = GPIO_NOPULL;
-  gpio_config.Mode = GPIO_MODE_ANALOG;
-
-  gpio_config.Pin = GPIO_PIN_15 | GPIO_PIN_14 | GPIO_PIN_13;
-  __HAL_RCC_GPIOA_CLK_ENABLE();
-  HAL_GPIO_Init(GPIOA, &gpio_config);
-  __HAL_RCC_GPIOA_CLK_DISABLE();
-
-  gpio_config.Pin = GPIO_PIN_4 | GPIO_PIN_3;
-  __HAL_RCC_GPIOB_CLK_ENABLE();
-  HAL_GPIO_Init(GPIOB, &gpio_config);
-  __HAL_RCC_GPIOB_CLK_DISABLE();
-
-  HAL_DBGMCU_DisableDBGSleepMode();
-  HAL_DBGMCU_DisableDBGStopMode();
-  HAL_DBGMCU_DisableDBGStandbyMode();
-
-#endif /* (CFG_DEBUGGER_SUPPORTED == 1) */
-
-#if(CFG_DEBUG_TRACE != 0)
-  DbgTraceInit();
-#endif
-
-  APPD_SetCPU2GpioConfig( );
-  APPD_BleDtbCfg( );
-
-/* USER CODE END APPD_Init */
-  return;
-}
-
-void APPD_EnableCPU2( void )
-{
-/* USER CODE BEGIN APPD_EnableCPU2 */
-  SHCI_C2_DEBUG_Init_Cmd_Packet_t DebugCmdPacket =
-  {
-    {{0,0,0}},                            /**< Does not need to be initialized */
-    {(uint8_t *)aGpioConfigList,
-    (uint8_t *)&APPD_TracesConfig,
-    (uint8_t *)&APPD_GeneralConfig,
-    GPIO_CFG_NBR_OF_FEATURES,
-    NBR_OF_TRACES_CONFIG_PARAMETERS,
-    NBR_OF_GENERAL_CONFIG_PARAMETERS}
-  };
-
-  /**< Traces channel initialization */
-  TL_TRACES_Init( );
-
-  /** GPIO DEBUG Initialization */
-  SHCI_C2_DEBUG_Init( &DebugCmdPacket  );
-
-/* USER CODE END APPD_EnableCPU2 */
-  return;
-}
-
-/*************************************************************
- *
- * LOCAL FUNCTIONS
- *
- *************************************************************/
-static void APPD_SetCPU2GpioConfig( void )
-{
-/* USER CODE BEGIN APPD_SetCPU2GpioConfig */
-  GPIO_InitTypeDef gpio_config = {0};
-  uint8_t local_loop;
-  uint16_t gpioa_pin_list;
-  uint16_t gpiob_pin_list;
-  uint16_t gpioc_pin_list;
-
-  gpioa_pin_list = 0;
-  gpiob_pin_list = 0;
-  gpioc_pin_list = 0;
-
-  for(local_loop = 0 ; local_loop < GPIO_CFG_NBR_OF_FEATURES; local_loop++)
-  {
-    if( aGpioConfigList[local_loop].enable != 0)
-    {
-      switch((uint32_t)aGpioConfigList[local_loop].port)
-      {
-        case (uint32_t)GPIOA:
-            gpioa_pin_list |= aGpioConfigList[local_loop].pin;
-          break;
-
-        case (uint32_t)GPIOB:
-            gpiob_pin_list |= aGpioConfigList[local_loop].pin;
-          break;
-
-        case (uint32_t)GPIOC:
-            gpioc_pin_list |= aGpioConfigList[local_loop].pin;
-          break;
-
-        default:
-          break;
-      }
-    }
-  }
-
-  gpio_config.Pull = GPIO_NOPULL;
-  gpio_config.Mode = GPIO_MODE_OUTPUT_PP;
-  gpio_config.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
-
-  if(gpioa_pin_list != 0)
-  {
-    gpio_config.Pin = gpioa_pin_list;
-    __HAL_RCC_GPIOA_CLK_ENABLE();
-    __HAL_RCC_C2GPIOA_CLK_ENABLE();
-    HAL_GPIO_Init(GPIOA, &gpio_config);
-    HAL_GPIO_WritePin(GPIOA, gpioa_pin_list, GPIO_PIN_RESET);
-  }
-
-  if(gpiob_pin_list != 0)
-  {
-    gpio_config.Pin = gpiob_pin_list;
-    __HAL_RCC_GPIOB_CLK_ENABLE();
-    __HAL_RCC_C2GPIOB_CLK_ENABLE();
-    HAL_GPIO_Init(GPIOB, &gpio_config);
-    HAL_GPIO_WritePin(GPIOB, gpiob_pin_list, GPIO_PIN_RESET);
-  }
-
-  if(gpioc_pin_list != 0)
-  {
-    gpio_config.Pin = gpioc_pin_list;
-    __HAL_RCC_GPIOC_CLK_ENABLE();
-    __HAL_RCC_C2GPIOC_CLK_ENABLE();
-    HAL_GPIO_Init(GPIOC, &gpio_config);
-    HAL_GPIO_WritePin(GPIOC, gpioc_pin_list, GPIO_PIN_RESET);
-  }
-  
-/* USER CODE END APPD_SetCPU2GpioConfig */
-  return;
-}
-
-static void APPD_BleDtbCfg( void )
-{
-/* USER CODE BEGIN APPD_BleDtbCfg */
-#if (BLE_DTB_CFG != 0)
-  GPIO_InitTypeDef gpio_config = {0};
-  uint8_t local_loop;
-  uint16_t gpioa_pin_list;
-  uint16_t gpiob_pin_list;
-
-  gpioa_pin_list = 0;
-  gpiob_pin_list = 0;
-
-  for(local_loop = 0 ; local_loop < GPIO_NBR_OF_RF_SIGNALS; local_loop++)
-  {
-    if( aRfConfigList[local_loop].enable != 0)
-    {
-      switch((uint32_t)aRfConfigList[local_loop].port)
-      {
-        case (uint32_t)GPIOA:
-            gpioa_pin_list |= aRfConfigList[local_loop].pin;
-          break;
-
-        case (uint32_t)GPIOB:
-            gpiob_pin_list |= aRfConfigList[local_loop].pin;
-          break;
-
-        default:
-          break;
-      }
-    }
-  }
-
-  gpio_config.Pull = GPIO_NOPULL;
-  gpio_config.Mode = GPIO_MODE_AF_PP;
-  gpio_config.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
-  gpio_config.Alternate = GPIO_AF6_RF_DTB7;
-
-  if(gpioa_pin_list != 0)
-  {
-    gpio_config.Pin = gpioa_pin_list;
-    __HAL_RCC_GPIOA_CLK_ENABLE();
-    __HAL_RCC_C2GPIOA_CLK_ENABLE();
-    HAL_GPIO_Init(GPIOA, &gpio_config);
-  }
-
-  if(gpiob_pin_list != 0)
-  {
-    gpio_config.Pin = gpiob_pin_list;
-    __HAL_RCC_GPIOB_CLK_ENABLE();
-    __HAL_RCC_C2GPIOB_CLK_ENABLE();
-    HAL_GPIO_Init(GPIOB, &gpio_config);
-  }
-#endif
-
-/* USER CODE END APPD_BleDtbCfg */
-  return;
-}
-
-/*************************************************************
- *
- * WRAP FUNCTIONS
- *
-*************************************************************/
-#if(CFG_DEBUG_TRACE != 0)
-void DbgOutputInit( void )
-{
-}
-
-void DbgOutputTraces(  uint8_t *p_data, uint16_t size, void (*cb)(void) )
-{
-  furi_hal_console_tx(p_data, size);
-  cb();
-}
-#endif
-
-/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 0 - 69
firmware/targets/f6/ble-glue/app_debug.h

@@ -1,69 +0,0 @@
-/* USER CODE BEGIN Header */
-/**
- ******************************************************************************
-  * File Name          : app_debug.h
-  * Description        : Header for app_debug.c module
- ******************************************************************************
-  * @attention
-  *
-  * <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
-  * All rights reserved.</center></h2>
-  *
-  * This software component is licensed by ST under Ultimate Liberty license
-  * SLA0044, the "License"; You may not use this file except in compliance with
-  * the License. You may obtain a copy of the License at:
-  *                             www.st.com/SLA0044
-  *
-  ******************************************************************************
-  */
-/* USER CODE END Header */
-
-/* Define to prevent recursive inclusion -------------------------------------*/
-#ifndef __APP_DEBUG_H
-#define __APP_DEBUG_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Includes ------------------------------------------------------------------*/
-
-/* Private includes ----------------------------------------------------------*/
-/* USER CODE BEGIN Includes */
-
-/* USER CODE END Includes */
-
-  /* Exported types ------------------------------------------------------------*/
-/* USER CODE BEGIN ET */
-
-/* USER CODE END ET */
-
-/* Exported constants --------------------------------------------------------*/
-/* USER CODE BEGIN EC */
-
-/* USER CODE END EC */
-
-/* Exported variables --------------------------------------------------------*/
-/* USER CODE BEGIN EV */
-
-/* USER CODE END EV */
-
-/* Exported macros ------------------------------------------------------------*/
-/* USER CODE BEGIN EM */
-
-/* USER CODE END EM */
-
-/* Exported functions ---------------------------------------------*/
-  void APPD_Init( void );
-  void APPD_EnableCPU2( void );
-/* USER CODE BEGIN EF */
-
-/* USER CODE END EF */
-
-#ifdef __cplusplus
-} /* extern "C" */
-#endif
-
-#endif /*__APP_DEBUG_H */
-
-/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 13 - 1
firmware/targets/f6/ble-glue/app_entry.c

@@ -6,7 +6,6 @@
 #include "tl.h"
 #include "cmsis_os.h"
 #include "shci_tl.h"
-#include "app_debug.h"
 #include <furi-hal.h>
 
 extern RTC_HandleTypeDef hrtc;
@@ -178,3 +177,16 @@ void shci_cmd_resp_wait(uint32_t timeout) {
   UNUSED(timeout);
   osSemaphoreAcquire( SemShciId, osWaitForever );
 }
+
+#if(CFG_DEBUG_TRACE != 0)
+void DbgOutputInit( void )
+{
+}
+
+void DbgOutputTraces(  uint8_t *p_data, uint16_t size, void (*cb)(void) )
+{
+  furi_hal_console_tx(p_data, size);
+  cb();
+}
+#endif
+

+ 55 - 0
firmware/targets/f6/ble-glue/battery_service.c

@@ -0,0 +1,55 @@
+#include "battery_service.h"
+#include "app_common.h"
+#include "ble.h"
+
+#include <furi.h>
+
+#define BATTERY_SERVICE_TAG "battery service"
+
+typedef struct {
+    uint16_t svc_handle;
+    uint16_t char_level_handle;
+} BatterySvc;
+
+static BatterySvc battery_svc;
+
+bool battery_svc_init() {
+    tBleStatus status;
+    const uint16_t service_uuid = BATTERY_SERVICE_UUID;
+    const uint16_t char_battery_level_uuid = BATTERY_LEVEL_CHAR_UUID;
+
+    // Add Battery service
+    status = aci_gatt_add_service(UUID_TYPE_16, (Service_UUID_t*)&service_uuid, PRIMARY_SERVICE, 4, &battery_svc.svc_handle);
+    if(status) {
+        FURI_LOG_E(BATTERY_SERVICE_TAG, "Failed to add Battery service: %d", status);
+    }
+
+    // Add Battery level characteristic
+    status = aci_gatt_add_char(battery_svc.svc_handle,
+                                UUID_TYPE_16,
+                                (Char_UUID_t *) &char_battery_level_uuid,
+                                1,
+                                CHAR_PROP_READ | CHAR_PROP_NOTIFY,
+                                ATTR_PERMISSION_NONE,
+                                GATT_DONT_NOTIFY_EVENTS,
+                                10,
+                                CHAR_VALUE_LEN_CONSTANT,
+                                &battery_svc.char_level_handle);
+    if(status) {
+        FURI_LOG_E(BATTERY_SERVICE_TAG, "Failed to add Battery level characteristic: %d", status);
+    }
+    return status != BLE_STATUS_SUCCESS;
+}
+
+bool battery_svc_update_level(uint8_t battery_charge) {
+    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,
+                                          0,
+                                          1,
+                                          &battery_charge);
+    if(result) {
+        FURI_LOG_E(BATTERY_SERVICE_TAG, "Failed updating RX characteristic: %d", result);
+    }
+    return result != BLE_STATUS_SUCCESS;
+}

+ 16 - 0
firmware/targets/f6/ble-glue/battery_service.h

@@ -0,0 +1,16 @@
+#pragma once
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+bool battery_svc_init();
+
+bool battery_svc_update_level(uint8_t battery_level);
+
+#ifdef __cplusplus
+}
+#endif

+ 1 - 36
firmware/targets/f6/ble-glue/ble_conf.h

@@ -53,47 +53,12 @@
 
 #define BLE_CFG_CLT_MAX_NBR_CB                                                 0
 
-/******************************************************************************
- * Device Information Service (DIS)
- ******************************************************************************/
-/**< Options: Supported(1) or Not Supported(0) */
-#define BLE_CFG_DIS_MANUFACTURER_NAME_STRING                                   1
-#define BLE_CFG_DIS_MODEL_NUMBER_STRING                                        1
-#define BLE_CFG_DIS_SERIAL_NUMBER_STRING                                       0
-#define BLE_CFG_DIS_HARDWARE_REVISION_STRING                                   0
-#define BLE_CFG_DIS_FIRMWARE_REVISION_STRING                                   1
-#define BLE_CFG_DIS_SOFTWARE_REVISION_STRING                                   1
-#define BLE_CFG_DIS_SYSTEM_ID                                                  0
-#define BLE_CFG_DIS_IEEE_CERTIFICATION                                         0
-#define BLE_CFG_DIS_PNP_ID                                                     0
-
-/**
- * device information service characteristic lengths
- */
-#define BLE_CFG_DIS_SYSTEM_ID_LEN_MAX                                        (8)
-#define BLE_CFG_DIS_MODEL_NUMBER_STRING_LEN_MAX                              (32)
-#define BLE_CFG_DIS_SERIAL_NUMBER_STRING_LEN_MAX                             (32)
-#define BLE_CFG_DIS_FIRMWARE_REVISION_STRING_LEN_MAX                         (32)
-#define BLE_CFG_DIS_HARDWARE_REVISION_STRING_LEN_MAX                         (32)
-#define BLE_CFG_DIS_SOFTWARE_REVISION_STRING_LEN_MAX                         (64)
-#define BLE_CFG_DIS_MANUFACTURER_NAME_STRING_LEN_MAX                         (32)
-#define BLE_CFG_DIS_IEEE_CERTIFICATION_LEN_MAX                               (32)
-#define BLE_CFG_DIS_PNP_ID_LEN_MAX                                           (7)
-
-/******************************************************************************
- * Heart Rate Service (HRS)
- ******************************************************************************/
-#define BLE_CFG_HRS_BODY_SENSOR_LOCATION_CHAR               1/**< BODY SENSOR LOCATION CHARACTERISTIC */
-#define BLE_CFG_HRS_ENERGY_EXPENDED_INFO_FLAG               1/**< ENERGY EXTENDED INFO FLAG */
-#define BLE_CFG_HRS_ENERGY_RR_INTERVAL_FLAG                 1/**< Max number of RR interval values - Shall not be greater than 9 */
-
 /******************************************************************************
  * GAP Service - Apprearance
  ******************************************************************************/
 
 #define BLE_CFG_UNKNOWN_APPEARANCE                  (0)
-#define BLE_CFG_HR_SENSOR_APPEARANCE                (832)
-#define BLE_CFG_GAP_APPEARANCE                      (BLE_CFG_HR_SENSOR_APPEARANCE)
+#define BLE_CFG_GAP_APPEARANCE                      (0x0086)
 
 /******************************************************************************
  * Over The Air Feature (OTA) - STM Proprietary

+ 121 - 0
firmware/targets/f6/ble-glue/dev_info_service.c

@@ -0,0 +1,121 @@
+#include "dev_info_service.h"
+#include "app_common.h"
+#include "ble.h"
+
+#include <furi.h>
+
+#define DEV_INFO_SERVICE_TAG "dev info service"
+
+typedef struct {
+    uint16_t service_handle;
+    uint16_t man_name_char_handle;
+    uint16_t serial_num_char_handle;
+    uint16_t firmware_rev_char_handle;
+    uint16_t software_rev_char_handle;
+} DevInfoSvc;
+
+bool dev_info_service_init() {
+    tBleStatus status;
+    DevInfoSvc dev_info_svc;
+
+    // Add Device Information Service
+    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);
+    if(status) {
+        FURI_LOG_E(DEV_INFO_SERVICE_TAG, "Failed to add Device Information Service: %d", status);
+    }
+
+    // Add characteristics
+    uuid = MANUFACTURER_NAME_UUID;
+    status = aci_gatt_add_char(dev_info_svc.service_handle,
+                                UUID_TYPE_16,
+                                (Char_UUID_t*)&uuid,
+                                strlen(DEV_INFO_MANUFACTURER_NAME),
+                                CHAR_PROP_READ,
+                                ATTR_PERMISSION_NONE,
+                                GATT_DONT_NOTIFY_EVENTS,
+                                10,
+                                CHAR_VALUE_LEN_CONSTANT,
+                                &dev_info_svc.man_name_char_handle);
+    if(status) {
+        FURI_LOG_E(DEV_INFO_SERVICE_TAG, "Failed to add manufacturer name char: %d", status);
+
+    }
+    uuid = SERIAL_NUMBER_UUID;
+    status = aci_gatt_add_char(dev_info_svc.service_handle,
+                                UUID_TYPE_16,
+                                (Char_UUID_t*)&uuid,
+                                strlen(DEV_INFO_SERIAL_NUMBER),
+                                CHAR_PROP_READ,
+                                ATTR_PERMISSION_NONE,
+                                GATT_DONT_NOTIFY_EVENTS,
+                                10,
+                                CHAR_VALUE_LEN_CONSTANT,
+                                &dev_info_svc.serial_num_char_handle);
+    if(status) {
+        FURI_LOG_E(DEV_INFO_SERVICE_TAG, "Failed to add serial number char: %d", status);
+    }
+    uuid = FIRMWARE_REVISION_UUID;
+    status = aci_gatt_add_char(dev_info_svc.service_handle,
+                                UUID_TYPE_16,
+                                (Char_UUID_t*)&uuid,
+                                strlen(DEV_INFO_FIRMWARE_REVISION_NUMBER),
+                                CHAR_PROP_READ,
+                                ATTR_PERMISSION_NONE,
+                                GATT_DONT_NOTIFY_EVENTS,
+                                10,
+                                CHAR_VALUE_LEN_CONSTANT,
+                                &dev_info_svc.firmware_rev_char_handle);
+    if(status) {
+        FURI_LOG_E(DEV_INFO_SERVICE_TAG, "Failed to add firmware revision char: %d", status);
+    }
+    uuid = SOFTWARE_REVISION_UUID;
+    status = aci_gatt_add_char(dev_info_svc.service_handle,
+                                UUID_TYPE_16,
+                                (Char_UUID_t*)&uuid,
+                                strlen(DEV_INFO_SOFTWARE_REVISION_NUMBER),
+                                CHAR_PROP_READ,
+                                ATTR_PERMISSION_NONE,
+                                GATT_DONT_NOTIFY_EVENTS,
+                                10,
+                                CHAR_VALUE_LEN_CONSTANT,
+                                &dev_info_svc.software_rev_char_handle);
+    if(status) {
+        FURI_LOG_E(DEV_INFO_SERVICE_TAG, "Failed to add software revision char: %d", status);
+    }
+
+    // Update characteristics
+    status = aci_gatt_update_char_value(dev_info_svc.service_handle,
+                                        dev_info_svc.man_name_char_handle,
+                                        0,
+                                        strlen(DEV_INFO_MANUFACTURER_NAME),
+                                        (uint8_t*)DEV_INFO_MANUFACTURER_NAME);
+    if(status) {
+        FURI_LOG_E(DEV_INFO_SERVICE_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,
+                                        0,
+                                        strlen(DEV_INFO_SERIAL_NUMBER),
+                                        (uint8_t*)DEV_INFO_SERIAL_NUMBER);
+    if(status) {
+        FURI_LOG_E(DEV_INFO_SERVICE_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,
+                                        0,
+                                        strlen(DEV_INFO_FIRMWARE_REVISION_NUMBER),
+                                        (uint8_t*)DEV_INFO_FIRMWARE_REVISION_NUMBER);
+    if(status) {
+        FURI_LOG_E(DEV_INFO_SERVICE_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,
+                                        0,
+                                        strlen(DEV_INFO_SOFTWARE_REVISION_NUMBER),
+                                        (uint8_t*)DEV_INFO_SOFTWARE_REVISION_NUMBER);
+    if(status) {
+        FURI_LOG_E(DEV_INFO_SERVICE_TAG, "Failed to update software revision char: %d", status);
+    }
+    return status != BLE_STATUS_SUCCESS;
+}

+ 20 - 0
firmware/targets/f6/ble-glue/dev_info_service.h

@@ -0,0 +1,20 @@
+#pragma once
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define DEV_INFO_MANUFACTURER_NAME              "Flipper Devices Inc."
+#define DEV_INFO_SERIAL_NUMBER                  "1.0"
+#define DEV_INFO_FIRMWARE_REVISION_NUMBER       TARGET
+#define DEV_INFO_SOFTWARE_REVISION_NUMBER       GIT_COMMIT " " GIT_BRANCH " " GIT_BRANCH_NUM " " BUILD_DATE
+
+
+bool dev_info_service_init();
+
+#ifdef __cplusplus
+}
+#endif

+ 0 - 157
firmware/targets/f6/ble-glue/dis_app.c

@@ -1,157 +0,0 @@
-#include "app_common.h"
-#include "ble.h"
-#include "dis_app.h"
-#include <furi-hal-version.h>
-
-#if ((BLE_CFG_DIS_SYSTEM_ID != 0) || (CFG_MENU_DEVICE_INFORMATION != 0))
-static const uint8_t system_id[BLE_CFG_DIS_SYSTEM_ID_LEN_MAX] = {
-  (uint8_t)((DISAPP_MANUFACTURER_ID & 0xFF0000) >> 16),
-  (uint8_t)((DISAPP_MANUFACTURER_ID & 0x00FF00) >> 8),
-  (uint8_t)(DISAPP_MANUFACTURER_ID & 0x0000FF),
-  0xFE,
-  0xFF,
-  (uint8_t)((DISAPP_OUI & 0xFF0000) >> 16),
-  (uint8_t)((DISAPP_OUI & 0x00FF00) >> 8),
-  (uint8_t)(DISAPP_OUI & 0x0000FF)
-};
-#endif
-
-#if ((BLE_CFG_DIS_IEEE_CERTIFICATION != 0) || (CFG_MENU_DEVICE_INFORMATION != 0))
-static const uint8_t ieee_id[BLE_CFG_DIS_IEEE_CERTIFICATION_LEN_MAX] = {
-  0xFE, 0xCA, 0xFE, 0xCA, 0xFE, 0xCA, 0xFE, 0xCA,
-  0xFE, 0xCA, 0xFE, 0xCA, 0xFE, 0xCA, 0xFE, 0xCA,
-  0xFE, 0xCA, 0xFE, 0xCA, 0xFE, 0xCA, 0xFE, 0xCA,
-  0xFE, 0xCA, 0xFE, 0xCA, 0xFE, 0xCA, 0xFE, 0xCA,
-};
-#endif
-
-#if ((BLE_CFG_DIS_PNP_ID != 0) || (CFG_MENU_DEVICE_INFORMATION != 0))
-static const uint8_t pnp_id[BLE_CFG_DIS_PNP_ID_LEN_MAX] = {
-  0x1,
-  0xAD, 0xDE,
-  0xDE, 0xDA,
-  0x01, 0x00
-};
-#endif
-
-void DISAPP_Init(void) {
-  DIS_Data_t dis_information_data;
-
-#if ((BLE_CFG_DIS_MANUFACTURER_NAME_STRING != 0) || (CFG_MENU_DEVICE_INFORMATION != 0))
-  /**
-   * Update MANUFACTURER NAME Information
-   *
-   * @param UUID
-   * @param pPData
-   * @return
-   */
-  dis_information_data.pPayload = (uint8_t*)DISAPP_MANUFACTURER_NAME;
-  dis_information_data.Length = sizeof(DISAPP_MANUFACTURER_NAME);
-  DIS_UpdateChar(MANUFACTURER_NAME_UUID, &dis_information_data);
-#endif
-
-#if ((BLE_CFG_DIS_MODEL_NUMBER_STRING != 0) || (CFG_MENU_DEVICE_INFORMATION != 0))
-  /**
-   * Update MODEL NUMBERInformation
-   *
-   * @param UUID
-   * @param pPData
-   * @return
-   */
-  const char* name = furi_hal_version_get_device_name_ptr();
-  dis_information_data.pPayload = (uint8_t*)name;
-  dis_information_data.Length = strlen(name) + 1;
-  DIS_UpdateChar(MODEL_NUMBER_UUID, &dis_information_data);
-#endif
-
-#if ((BLE_CFG_DIS_SERIAL_NUMBER_STRING != 0) || (CFG_MENU_DEVICE_INFORMATION != 0))
-  /**
-   * Update SERIAL NUMBERInformation
-   *
-   * @param UUID
-   * @param pPData
-   * @return
-   */
-  dis_information_data.pPayload = (uint8_t*)DISAPP_SERIAL_NUMBER;
-  dis_information_data.Length = sizeof(DISAPP_SERIAL_NUMBER);
-  DIS_UpdateChar(SERIAL_NUMBER_UUID, &dis_information_data);
-#endif
-
-#if ((BLE_CFG_DIS_HARDWARE_REVISION_STRING != 0) || (CFG_MENU_DEVICE_INFORMATION != 0))
-  /**
-   * Update HARDWARE REVISION NUMBERInformation
-   *
-   * @param UUID
-   * @param pPData
-   * @return
-   */
-  dis_information_data.pPayload = (uint8_t*)DISAPP_HARDWARE_REVISION_NUMBER;
-  dis_information_data.Length = sizeof(DISAPP_HARDWARE_REVISION_NUMBER);
-  DIS_UpdateChar(HARDWARE_REVISION_UUID, &dis_information_data);
-#endif
-
-#if ((BLE_CFG_DIS_FIRMWARE_REVISION_STRING != 0) || (CFG_MENU_DEVICE_INFORMATION != 0))
-  /**
-   * Update FIRMWARE REVISION NUMBERInformation
-   *
-   * @param UUID
-   * @param pPData
-   * @return
-   */
-  dis_information_data.pPayload = (uint8_t*)DISAPP_FIRMWARE_REVISION_NUMBER;
-  dis_information_data.Length = sizeof(DISAPP_FIRMWARE_REVISION_NUMBER);
-  DIS_UpdateChar(FIRMWARE_REVISION_UUID, &dis_information_data);
-#endif
-
-#if ((BLE_CFG_DIS_SOFTWARE_REVISION_STRING != 0) || (CFG_MENU_DEVICE_INFORMATION != 0))
-  /**
-   * Update SOFTWARE REVISION NUMBERInformation
-   *
-   * @param UUID
-   * @param pPData
-   * @return
-   */
-  dis_information_data.pPayload = (uint8_t*)DISAPP_SOFTWARE_REVISION_NUMBER;
-  dis_information_data.Length = sizeof(DISAPP_SOFTWARE_REVISION_NUMBER);
-  DIS_UpdateChar(SOFTWARE_REVISION_UUID, &dis_information_data);
-#endif
-
-#if ((BLE_CFG_DIS_SYSTEM_ID != 0) || (CFG_MENU_DEVICE_INFORMATION != 0))
-  /**
-   * Update SYSTEM ID Information
-   *
-   * @param UUID
-   * @param pPData
-   * @return
-   */
-  dis_information_data.pPayload = (uint8_t *)system_id;
-  dis_information_data.Length = BLE_CFG_DIS_SYSTEM_ID_LEN_MAX;
-  DIS_UpdateChar(SYSTEM_ID_UUID, &dis_information_data);
-#endif
-
-#if ((BLE_CFG_DIS_IEEE_CERTIFICATION != 0) || (CFG_MENU_DEVICE_INFORMATION != 0))
-  /**
-   * Update IEEE CERTIFICATION ID Information
-   *
-   * @param UUID
-   * @param pPData
-   * @return
-   */
-  dis_information_data.pPayload = (uint8_t *)ieee_id;
-  dis_information_data.Length = BLE_CFG_DIS_IEEE_CERTIFICATION_LEN_MAX;
-  DIS_UpdateChar(IEEE_CERTIFICATION_UUID, &dis_information_data);
-#endif
-
-#if ((BLE_CFG_DIS_PNP_ID != 0) || (CFG_MENU_DEVICE_INFORMATION != 0))
-  /**
-   * Update PNP ID Information
-   *
-   * @param UUID
-   * @param pPData
-   * @return
-   */
-  dis_information_data.pPayload = (uint8_t *)pnp_id;
-  dis_information_data.Length = BLE_CFG_DIS_PNP_ID_LEN_MAX;
-  DIS_UpdateChar(PNP_ID_UUID, &dis_information_data);
-#endif
-}

+ 0 - 20
firmware/targets/f6/ble-glue/dis_app.h

@@ -1,20 +0,0 @@
-#pragma once
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define DISAPP_MANUFACTURER_NAME              "Flipperdevice Inc."
-//#define DISAPP_MODEL_NUMBER                   "FlipperZero"
-#define DISAPP_SERIAL_NUMBER                  "1.0"
-#define DISAPP_HARDWARE_REVISION_NUMBER       "1.0"
-#define DISAPP_FIRMWARE_REVISION_NUMBER       TARGET
-#define DISAPP_SOFTWARE_REVISION_NUMBER       GIT_COMMIT " " GIT_BRANCH " " GIT_BRANCH_NUM " " BUILD_DATE
-#define DISAPP_OUI                            0x123456
-#define DISAPP_MANUFACTURER_ID                0x9ABCDE
-
-void DISAPP_Init(void);
-
-#ifdef __cplusplus
-}
-#endif

+ 0 - 256
firmware/targets/f6/ble-glue/hrs_app.c

@@ -1,256 +0,0 @@
-/* USER CODE BEGIN Header */
-/**
-  ******************************************************************************
-  * @file    hrs_app.c
-  * @author  MCD Application Team
-  * @brief   Heart Rate Service Application
-  ******************************************************************************
-  * @attention
- *
-  * <h2><center>&copy; Copyright (c) 2019 STMicroelectronics. 
- * All rights reserved.</center></h2>
- *
-  * This software component is licensed by ST under Ultimate Liberty license 
-  * SLA0044, the "License"; You may not use this file except in compliance with 
- * the License. You may obtain a copy of the License at:
- *                             www.st.com/SLA0044
- *
- ******************************************************************************
- */
-/* USER CODE END Header */
-
-/* Includes ------------------------------------------------------------------*/
-#include "app_common.h"
-
-#include "ble.h"
-#include "hrs_app.h"
-#include "cmsis_os.h"
-
-/* Private includes ----------------------------------------------------------*/
-/* USER CODE BEGIN Includes */
-
-/* USER CODE END Includes */
-
-/* Private typedef -----------------------------------------------------------*/
-typedef struct
-{
-  HRS_BodySensorLocation_t BodySensorLocationChar;
-  HRS_MeasVal_t MeasurementvalueChar;
-  uint8_t ResetEnergyExpended;
-  uint8_t TimerMeasurement_Id;
-
-} HRSAPP_Context_t;
-/* USER CODE BEGIN PTD */
-
-/* USER CODE END PTD */
-
-/* Private defines ------------------------------------------------------------*/
-/* USER CODE BEGIN PD */
-
-/* USER CODE END PD */
-
-/* Private macros ------------------------------------------------------------*/
-#define HRSAPP_MEASUREMENT_INTERVAL   (1000000/CFG_TS_TICK_VAL)  /**< 1s */
-/* USER CODE BEGIN PM */
-
-/* USER CODE END PM */
-
-/* Private variables ---------------------------------------------------------*/
-/**
- * START of Section BLE_APP_CONTEXT
- */
-
-PLACE_IN_SECTION("BLE_APP_CONTEXT") static HRSAPP_Context_t HRSAPP_Context;
-
-/**
- * END of Section BLE_APP_CONTEXT
- */
-
-osThreadId_t HrsProcessId;
-
-const osThreadAttr_t HrsProcess_attr = {
-    .name = CFG_HRS_PROCESS_NAME,
-    .attr_bits = CFG_HRS_PROCESS_ATTR_BITS,
-    .cb_mem = CFG_HRS_PROCESS_CB_MEM,
-    .cb_size = CFG_HRS_PROCESS_CB_SIZE,
-    .stack_mem = CFG_HRS_PROCESS_STACK_MEM,
-    .priority = CFG_HRS_PROCESS_PRIORITY,
-    .stack_size = CFG_HRS_PROCESS_STACK_SIZE
-};
-
-/* USER CODE BEGIN PV */
-
-/* USER CODE END PV */
-
-/* Private functions prototypes-----------------------------------------------*/
-static void HrMeas( void );
-static void HrsProcess(void *argument);
-static void HRSAPP_Measurement(void);
-static uint32_t HRSAPP_Read_RTC_SSR_SS ( void );
-/* USER CODE BEGIN PFP */
-
-/* USER CODE END PFP */
-
-/* Functions Definition ------------------------------------------------------*/
-void HRS_Notification(HRS_App_Notification_evt_t *pNotification)
-{
-/* USER CODE BEGIN HRS_Notification_1 */
-
-/* USER CODE END HRS_Notification_1 */
-  switch(pNotification->HRS_Evt_Opcode)
-  {
-/* USER CODE BEGIN HRS_Notification_HRS_Evt_Opcode */
-
-/* USER CODE END HRS_Notification_HRS_Evt_Opcode */
-#if (BLE_CFG_HRS_ENERGY_EXPENDED_INFO_FLAG != 0)
-    case HRS_RESET_ENERGY_EXPENDED_EVT:
-/* USER CODE BEGIN HRS_RESET_ENERGY_EXPENDED_EVT */
-      HRSAPP_Context.MeasurementvalueChar.EnergyExpended = 0;
-      HRSAPP_Context.ResetEnergyExpended = 1;
-/* USER CODE END HRS_RESET_ENERGY_EXPENDED_EVT */
-      break;
-#endif
-
-    case HRS_NOTIFICATION_ENABLED:
-/* USER CODE BEGIN HRS_NOTIFICATION_ENABLED */
-      /**
-       * It could be the enable notification is received twice without the disable notification in between
-       */
-      HW_TS_Stop(HRSAPP_Context.TimerMeasurement_Id);
-      HW_TS_Start(HRSAPP_Context.TimerMeasurement_Id, HRSAPP_MEASUREMENT_INTERVAL);
-/* USER CODE END HRS_NOTIFICATION_ENABLED */
-      break;
-
-    case HRS_NOTIFICATION_DISABLED:
-/* USER CODE BEGIN HRS_NOTIFICATION_DISABLED */
-      HW_TS_Stop(HRSAPP_Context.TimerMeasurement_Id);
-/* USER CODE END HRS_NOTIFICATION_DISABLED */
-      break;
-
-#if (BLE_CFG_OTA_REBOOT_CHAR != 0)
-    case HRS_STM_BOOT_REQUEST_EVT:
-/* USER CODE BEGIN HRS_STM_BOOT_REQUEST_EVT */
-      *(uint32_t*)SRAM1_BASE = *(uint32_t*)pNotification->DataTransfered.pPayload;
-      NVIC_SystemReset();
-/* USER CODE END HRS_STM_BOOT_REQUEST_EVT */
-      break;
-#endif
-
-   default:
-/* USER CODE BEGIN HRS_Notification_Default */
-
-/* USER CODE END HRS_Notification_Default */
-      break;
-  }
-/* USER CODE BEGIN HRS_Notification_2 */
-
-/* USER CODE END HRS_Notification_2 */
-  return;
-}
-
-void HRSAPP_Init(void)
-{
-  HrsProcessId = osThreadNew(HrsProcess, NULL, &HrsProcess_attr);
-/* USER CODE BEGIN HRSAPP_Init */
-  /**
-   * Set Body Sensor Location
-   */
-  HRSAPP_Context.ResetEnergyExpended = 0;
-  HRSAPP_Context.BodySensorLocationChar = HRS_BODY_SENSOR_LOCATION_HAND;
-  HRS_UpdateChar(SENSOR_LOCATION_UUID, (uint8_t *)&HRSAPP_Context.BodySensorLocationChar);
-
-
-  /**
-   * Set Flags for measurement value
-   */
-
-  HRSAPP_Context.MeasurementvalueChar.Flags = ( HRS_HRM_VALUE_FORMAT_UINT16      | 
-                                                  HRS_HRM_SENSOR_CONTACTS_PRESENT   | 
-                                                  HRS_HRM_SENSOR_CONTACTS_SUPPORTED |
-                                                  HRS_HRM_ENERGY_EXPENDED_PRESENT  |
-                                                  HRS_HRM_RR_INTERVAL_PRESENT );
-
-#if (BLE_CFG_HRS_ENERGY_EXPENDED_INFO_FLAG != 0)
-  if(HRSAPP_Context.MeasurementvalueChar.Flags & HRS_HRM_ENERGY_EXPENDED_PRESENT)
-    HRSAPP_Context.MeasurementvalueChar.EnergyExpended = 10;
-#endif
-  
-#if (BLE_CFG_HRS_ENERGY_RR_INTERVAL_FLAG != 0)
-  if(HRSAPP_Context.MeasurementvalueChar.Flags & HRS_HRM_RR_INTERVAL_PRESENT)
-  {
-    uint8_t i;
-    
-    HRSAPP_Context.MeasurementvalueChar.NbreOfValidRRIntervalValues = BLE_CFG_HRS_ENERGY_RR_INTERVAL_FLAG;
-    for(i = 0; i < BLE_CFG_HRS_ENERGY_RR_INTERVAL_FLAG; i++)
-      HRSAPP_Context.MeasurementvalueChar.aRRIntervalValues[i] = 1024;
-  }
-#endif
-  
-  /**
-   * Create timer for Heart Rate Measurement
-   */
-  HW_TS_Create(CFG_TIM_PROC_ID_ISR, &(HRSAPP_Context.TimerMeasurement_Id), hw_ts_Repeated, HrMeas);
-
-/* USER CODE END HRSAPP_Init */
-  return;
-}
-
-static void HrsProcess(void *argument)
-{
-  UNUSED(argument);
-
-  for(;;)
-  {
-    osThreadFlagsWait( 1, osFlagsWaitAny, osWaitForever);
-    HRSAPP_Measurement( );
-  }
-}
-
-static void HRSAPP_Measurement(void)
-{
-/* USER CODE BEGIN HRSAPP_Measurement */
-  uint32_t measurement;
-
-  measurement = ((HRSAPP_Read_RTC_SSR_SS()) & 0x07) + 65;
-
-  HRSAPP_Context.MeasurementvalueChar.MeasurementValue = measurement;
-#if (BLE_CFG_HRS_ENERGY_EXPENDED_INFO_FLAG != 0)
-  if((HRSAPP_Context.MeasurementvalueChar.Flags & HRS_HRM_ENERGY_EXPENDED_PRESENT) &&
-     (HRSAPP_Context.ResetEnergyExpended == 0))
-    HRSAPP_Context.MeasurementvalueChar.EnergyExpended += 5;
-  else if(HRSAPP_Context.ResetEnergyExpended == 1)
-    HRSAPP_Context.ResetEnergyExpended = 0;
-#endif
-
-  HRS_UpdateChar(HEART_RATE_MEASURMENT_UUID, (uint8_t *)&HRSAPP_Context.MeasurementvalueChar);
-
-/* USER CODE END HRSAPP_Measurement */
-  return;
-}
-
-static void HrMeas( void )
-{
-  /**
-   * The code shall be executed in the background as 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( HrsProcessId, 1 );
-
-/* USER CODE BEGIN HrMeas */
-
-/* USER CODE END HrMeas */
-
-  return;
-}
-
-static uint32_t HRSAPP_Read_RTC_SSR_SS ( void )
-{
-  return ((uint32_t)(READ_BIT(RTC->SSR, RTC_SSR_SS)));
-}
-
-/* USER CODE BEGIN FD */
-
-/* USER CODE END FD */
-
-/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 0 - 69
firmware/targets/f6/ble-glue/hrs_app.h

@@ -1,69 +0,0 @@
-/* USER CODE BEGIN Header */
-/**
-  ******************************************************************************
-  * @file    hrs_app.h
-  * @author  MCD Application Team
-  * @brief   Header for hrs_application.c module
-  ******************************************************************************
-  * @attention
-  *
-  * <h2><center>&copy; Copyright (c) 2019 STMicroelectronics. 
-  * All rights reserved.</center></h2>
-  *
-  * This software component is licensed by ST under Ultimate Liberty license 
-  * SLA0044, the "License"; You may not use this file except in compliance with 
-  * the License. You may obtain a copy of the License at:
-  *                             www.st.com/SLA0044
-  *
-  ******************************************************************************
-  */
-/* USER CODE END Header */
-
-/* Define to prevent recursive inclusion -------------------------------------*/
-#ifndef __HRS_APP_H
-#define __HRS_APP_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Includes ------------------------------------------------------------------*/
-
-/* Private includes ----------------------------------------------------------*/
-/* USER CODE BEGIN Includes */
-
-/* USER CODE END Includes */
-
-/* Exported types ------------------------------------------------------------*/
-/* USER CODE BEGIN ET */
-
-/* USER CODE END ET */
-
-/* Exported constants --------------------------------------------------------*/
-/* USER CODE BEGIN EC */
-
-/* USER CODE END EC */
-
-/* External variables --------------------------------------------------------*/
-/* USER CODE BEGIN EV */
-
-/* USER CODE END EV */
-
-/* Exported macros ------------------------------------------------------------*/
-/* USER CODE BEGIN EM */
-
-/* USER CODE END EM */
-
-/* Exported functions ---------------------------------------------*/
-void HRSAPP_Init( void );
-/* USER CODE BEGIN EF */
-
-/* USER CODE END EF */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /*__HRS_APP_H */
-
-/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 102 - 0
firmware/targets/f6/ble-glue/serial_service.c

@@ -0,0 +1,102 @@
+#include "serial_service.h"
+#include "app_common.h"
+#include "ble.h"
+
+#include <furi.h>
+
+#define SERIAL_SERVICE_TAG "serial service"
+
+typedef struct {
+    uint16_t svc_handle;
+    uint16_t rx_char_handle;
+    uint16_t tx_char_handle;
+} SerialSvc;
+
+static SerialSvc serial_svc;
+
+static SVCCTL_EvtAckStatus_t serial_svc_event_handler(void *event) {
+    SVCCTL_EvtAckStatus_t ret = SVCCTL_EvtNotAck;
+    hci_event_pckt* event_pckt = (hci_event_pckt *)(((hci_uart_pckt*)event)->data);
+    evt_blecore_aci* blecore_evt = (evt_blecore_aci*)event_pckt->data;
+    aci_gatt_attribute_modified_event_rp0* attribute_modified;
+    if(event_pckt->evt == HCI_VENDOR_SPECIFIC_DEBUG_EVT_CODE) {
+        if(blecore_evt->ecode == ACI_GATT_ATTRIBUTE_MODIFIED_VSEVT_CODE) {
+            attribute_modified = (aci_gatt_attribute_modified_event_rp0*)blecore_evt->data;
+            if(attribute_modified->Attr_Handle == serial_svc.tx_char_handle + 2) {
+                // Descriptor handle
+                ret = SVCCTL_EvtAckFlowEnable;
+                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");
+                serial_svc_update_rx(attribute_modified->Attr_Data, attribute_modified->Attr_Data_Length);
+                ret = SVCCTL_EvtAckFlowEnable;
+            }
+        } else if(blecore_evt->ecode == ACI_GATT_SERVER_CONFIRMATION_VSEVT_CODE) {
+            FURI_LOG_I(SERIAL_SERVICE_TAG, "Ack received", blecore_evt->ecode);
+            ret = SVCCTL_EvtAckFlowEnable;
+        }
+    }
+    return ret;
+}
+
+bool serial_svc_init() {
+    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};
+
+    // Register event handler
+    SVCCTL_RegisterSvcHandler(serial_svc_event_handler);
+
+    // Add service
+    status = aci_gatt_add_service(UUID_TYPE_128, (Service_UUID_t *)service_uuid, PRIMARY_SERVICE, 6, &serial_svc.svc_handle);
+    if(status) {
+        FURI_LOG_E(SERIAL_SERVICE_TAG, "Failed to add Serial service: %d", status);
+    }
+
+    // Add TX characteristics
+    status = aci_gatt_add_char(serial_svc.svc_handle, UUID_TYPE_128, (const Char_UUID_t*)char_tx_uuid ,
+                                SERIAL_SVC_DATA_LEN_MAX,
+                                CHAR_PROP_WRITE_WITHOUT_RESP | CHAR_PROP_WRITE | CHAR_PROP_READ,
+                                ATTR_PERMISSION_NONE,
+                                GATT_NOTIFY_ATTRIBUTE_WRITE,
+                                10,
+                                CHAR_VALUE_LEN_VARIABLE,
+                                &serial_svc.tx_char_handle);
+    if(status) {
+        FURI_LOG_E(SERIAL_SERVICE_TAG, "Failed to add TX characteristic: %d", status);
+    }
+
+    // Add RX characteristic
+    status = aci_gatt_add_char(serial_svc.svc_handle, UUID_TYPE_128, (const Char_UUID_t*)char_rx_uuid ,
+                                SERIAL_SVC_DATA_LEN_MAX,                                  
+                                CHAR_PROP_READ | CHAR_PROP_INDICATE,
+                                ATTR_PERMISSION_NONE,
+                                GATT_DONT_NOTIFY_EVENTS,
+                                10,
+                                CHAR_VALUE_LEN_VARIABLE,
+                                &serial_svc.rx_char_handle);
+    if(status) {
+        FURI_LOG_E(SERIAL_SERVICE_TAG, "Failed to add RX characteristic: %d", status);
+    }
+
+    return status != BLE_STATUS_SUCCESS;
+}
+
+bool serial_svc_update_rx(uint8_t* data, uint8_t data_len) {
+    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,
+                                          0,
+                                          data_len,
+                                          data);
+    if(result) {
+        FURI_LOG_E(SERIAL_SERVICE_TAG, "Failed updating RX characteristic: %d", result);
+    }
+    return result != BLE_STATUS_SUCCESS;
+}

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

@@ -0,0 +1,22 @@
+#pragma once
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SERIAL_SVC_DATA_LEN_MAX 255
+
+#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();
+
+bool serial_svc_update_rx(uint8_t* data, uint8_t data_len);
+
+#ifdef __cplusplus
+}
+#endif

+ 0 - 2
firmware/targets/f6/target.mk

@@ -108,8 +108,6 @@ C_SOURCES += \
 	$(CUBE_DIR)/Middlewares/ST/STM32_WPAN/utilities/stm_list.c \
 	$(CUBE_DIR)/Middlewares/ST/STM32_WPAN/utilities/dbg_trace.c \
 	$(CUBE_DIR)/Middlewares/ST/STM32_WPAN/ble/svc/Src/svc_ctl.c \
-	$(CUBE_DIR)/Middlewares/ST/STM32_WPAN/ble/svc/Src/dis.c \
-	$(CUBE_DIR)/Middlewares/ST/STM32_WPAN/ble/svc/Src/hrs.c \
 	$(CUBE_DIR)/Middlewares/ST/STM32_WPAN/ble/core/template/osal.c \
 	$(CUBE_DIR)/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_hci_le.c \
 	$(CUBE_DIR)/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_gap_aci.c \