diff --git a/applications/bt/bt_service/bt.c b/applications/bt/bt_service/bt.c index ba292021..0c7dac90 100755 --- a/applications/bt/bt_service/bt.c +++ b/applications/bt/bt_service/bt.c @@ -22,6 +22,17 @@ static ViewPort* bt_statusbar_view_port_alloc() { 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 = furi_alloc(sizeof(Bt)); // Load settings @@ -41,13 +52,11 @@ Bt* bt_alloc() { bt->gui = furi_record_open("gui"); 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() { @@ -76,9 +85,13 @@ int32_t bt_srv() { // Update statusbar view_port_enabled_set(bt->statusbar_view_port, furi_hal_bt_is_alive()); } else if(message.type == BtMessageTypeUpdateBatteryLevel) { + // Update battery level if(furi_hal_bt_is_alive()) { 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; diff --git a/applications/bt/bt_service/bt.h b/applications/bt/bt_service/bt.h index 4be69dae..0bde59b8 100644 --- a/applications/bt/bt_service/bt.h +++ b/applications/bt/bt_service/bt.h @@ -9,7 +9,9 @@ extern "C" { 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 } diff --git a/applications/bt/bt_service/bt_api.c b/applications/bt/bt_service/bt_api.c new file mode 100755 index 00000000..a12ac268 --- /dev/null +++ b/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; +} diff --git a/applications/bt/bt_service/bt_i.h b/applications/bt/bt_service/bt_i.h index 6c0c2bf7..fbc0f378 100644 --- a/applications/bt/bt_service/bt_i.h +++ b/applications/bt/bt_service/bt_i.h @@ -9,14 +9,18 @@ #include #include +#include + #include "../bt_settings.h" typedef enum { BtMessageTypeUpdateStatusbar, BtMessageTypeUpdateBatteryLevel, + BtMessageTypePinCodeShow, } BtMessageType; typedef union { + uint32_t pin_code; uint8_t battery_level; } BtMessageData; @@ -31,4 +35,6 @@ struct Bt { osTimerId_t update_status_timer; Gui* gui; ViewPort* statusbar_view_port; + DialogsApp* dialogs; + DialogMessage* dialog_message; }; diff --git a/firmware/targets/f6/ble-glue/app_ble.c b/firmware/targets/f6/ble-glue/app_ble.c index bb80fcea..652c29ef 100644 --- a/firmware/targets/f6/ble-glue/app_ble.c +++ b/firmware/targets/f6/ble-glue/app_ble.c @@ -6,106 +6,20 @@ #include "ble.h" #include "tl.h" #include "app_ble.h" - -#include "cmsis_os.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 -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; -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; osSemaphoreId_t SemHciId; -osThreadId_t AdvUpdateProcessId; 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 = { .name = CFG_HCI_USER_EVT_PROCESS_NAME, .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_StatusNot( HCI_TL_CmdStatus_t status ); 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() { 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); } -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 ) { 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); } -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) { UNUSED(argument); diff --git a/firmware/targets/f6/ble-glue/app_ble.h b/firmware/targets/f6/ble-glue/app_ble.h index 2bbd5165..08c60fe3 100644 --- a/firmware/targets/f6/ble-glue/app_ble.h +++ b/firmware/targets/f6/ble-glue/app_ble.h @@ -7,20 +7,7 @@ extern "C" { #include #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_Start(); - -APP_BLE_ConnStatus_t APP_BLE_Get_Server_Connection_Status(); #ifdef __cplusplus } diff --git a/firmware/targets/f6/ble-glue/app_conf.h b/firmware/targets/f6/ble-glue/app_conf.h index dc22b4ba..381d5ae7 100644 --- a/firmware/targets/f6/ble-glue/app_conf.h +++ b/firmware/targets/f6/ble-glue/app_conf.h @@ -139,7 +139,7 @@ /** * 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 diff --git a/firmware/targets/f6/ble-glue/battery_service.c b/firmware/targets/f6/ble-glue/battery_service.c index bcf54049..654edd53 100644 --- a/firmware/targets/f6/ble-glue/battery_service.c +++ b/firmware/targets/f6/ble-glue/battery_service.c @@ -11,21 +11,22 @@ typedef struct { uint16_t char_level_handle; } 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; - 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); + 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, + status = aci_gatt_add_char(battery_svc->svc_handle, UUID_TYPE_16, (Char_UUID_t *) &char_battery_level_uuid, 1, @@ -34,17 +35,39 @@ bool battery_svc_init() { GATT_DONT_NOTIFY_EVENTS, 10, CHAR_VALUE_LEN_CONSTANT, - &battery_svc.char_level_handle); + &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; +} + +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) { + // 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"); - 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, 1, &battery_charge); diff --git a/firmware/targets/f6/ble-glue/battery_service.h b/firmware/targets/f6/ble-glue/battery_service.h index 82445d2c..a50e607c 100644 --- a/firmware/targets/f6/ble-glue/battery_service.h +++ b/firmware/targets/f6/ble-glue/battery_service.h @@ -7,7 +7,9 @@ extern "C" { #endif -bool battery_svc_init(); +void battery_svc_start(); + +void battery_svc_stop(); bool battery_svc_update_level(uint8_t battery_level); diff --git a/firmware/targets/f6/ble-glue/dev_info_service.c b/firmware/targets/f6/ble-glue/dev_info_service.c index d2b60cfd..db58226b 100644 --- a/firmware/targets/f6/ble-glue/dev_info_service.c +++ b/firmware/targets/f6/ble-glue/dev_info_service.c @@ -4,7 +4,7 @@ #include -#define DEV_INFO_SERVICE_TAG "dev info service" +#define DEV_INFO_SVC_TAG "dev info service" typedef struct { uint16_t service_handle; @@ -14,108 +14,143 @@ typedef struct { uint16_t software_rev_char_handle; } 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; - 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); + 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); + FURI_LOG_E(DEV_INFO_SVC_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, + status = aci_gatt_add_char(dev_info_svc->service_handle, UUID_TYPE_16, (Char_UUID_t*)&uuid, - strlen(DEV_INFO_MANUFACTURER_NAME), + strlen(dev_info_man_name), CHAR_PROP_READ, ATTR_PERMISSION_NONE, GATT_DONT_NOTIFY_EVENTS, 10, CHAR_VALUE_LEN_CONSTANT, - &dev_info_svc.man_name_char_handle); + &dev_info_svc->man_name_char_handle); 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; - status = aci_gatt_add_char(dev_info_svc.service_handle, + status = aci_gatt_add_char(dev_info_svc->service_handle, UUID_TYPE_16, (Char_UUID_t*)&uuid, - strlen(DEV_INFO_SERIAL_NUMBER), + strlen(dev_info_serial_num), CHAR_PROP_READ, ATTR_PERMISSION_NONE, GATT_DONT_NOTIFY_EVENTS, 10, CHAR_VALUE_LEN_CONSTANT, - &dev_info_svc.serial_num_char_handle); + &dev_info_svc->serial_num_char_handle); 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; - status = aci_gatt_add_char(dev_info_svc.service_handle, + status = aci_gatt_add_char(dev_info_svc->service_handle, UUID_TYPE_16, (Char_UUID_t*)&uuid, - strlen(DEV_INFO_FIRMWARE_REVISION_NUMBER), + strlen(dev_info_firmware_rev_num), CHAR_PROP_READ, ATTR_PERMISSION_NONE, GATT_DONT_NOTIFY_EVENTS, 10, CHAR_VALUE_LEN_CONSTANT, - &dev_info_svc.firmware_rev_char_handle); + &dev_info_svc->firmware_rev_char_handle); 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; - status = aci_gatt_add_char(dev_info_svc.service_handle, + status = aci_gatt_add_char(dev_info_svc->service_handle, UUID_TYPE_16, (Char_UUID_t*)&uuid, - strlen(DEV_INFO_SOFTWARE_REVISION_NUMBER), + strlen(dev_info_software_rev_num), CHAR_PROP_READ, ATTR_PERMISSION_NONE, GATT_DONT_NOTIFY_EVENTS, 10, CHAR_VALUE_LEN_CONSTANT, - &dev_info_svc.software_rev_char_handle); + &dev_info_svc->software_rev_char_handle); 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 - 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, - strlen(DEV_INFO_MANUFACTURER_NAME), - (uint8_t*)DEV_INFO_MANUFACTURER_NAME); + strlen(dev_info_man_name), + (uint8_t*)dev_info_man_name); 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, - strlen(DEV_INFO_SERIAL_NUMBER), - (uint8_t*)DEV_INFO_SERIAL_NUMBER); + strlen(dev_info_serial_num), + (uint8_t*)dev_info_serial_num); 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, - 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) { - 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, - 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) { - 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; } diff --git a/firmware/targets/f6/ble-glue/dev_info_service.h b/firmware/targets/f6/ble-glue/dev_info_service.h index b0e08d3f..62eccefa 100644 --- a/firmware/targets/f6/ble-glue/dev_info_service.h +++ b/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_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 } diff --git a/firmware/targets/f6/ble-glue/gap.c b/firmware/targets/f6/ble-glue/gap.c new file mode 100644 index 00000000..19d1b5f1 --- /dev/null +++ b/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 +#include + +#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); + } +} diff --git a/firmware/targets/f6/ble-glue/gap.h b/firmware/targets/f6/ble-glue/gap.h new file mode 100644 index 00000000..3fc2cf4c --- /dev/null +++ b/firmware/targets/f6/ble-glue/gap.h @@ -0,0 +1,22 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + GapStateIdle, + GapStateAdvFast, + GapStateAdvLowPower, + GapStateConnected, +} GapState; + +bool gap_init(); + +GapState gap_get_status(); + +#ifdef __cplusplus +} +#endif diff --git a/firmware/targets/f6/ble-glue/serial_service.c b/firmware/targets/f6/ble-glue/serial_service.c index 4b0ad402..eae2c275 100644 --- a/firmware/targets/f6/ble-glue/serial_service.c +++ b/firmware/targets/f6/ble-glue/serial_service.c @@ -6,13 +6,19 @@ #define SERIAL_SERVICE_TAG "serial service" +#define SERIAL_SVC_DATA_LEN_MAX 245 + typedef struct { uint16_t svc_handle; uint16_t rx_char_handle; uint16_t tx_char_handle; } 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) { 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(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) { + 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"); + } 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); 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); + FURI_LOG_D(SERIAL_SERVICE_TAG, "Ack received", blecore_evt->ecode); ret = SVCCTL_EvtAckFlowEnable; } } return ret; } -bool serial_svc_init() { +void serial_svc_start() { 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 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); + 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 , + 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); + &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 , + 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); + &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; } +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) { 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, data_len, data); diff --git a/firmware/targets/f6/ble-glue/serial_service.h b/firmware/targets/f6/ble-glue/serial_service.h index 92b943a0..9d3d6217 100644 --- a/firmware/targets/f6/ble-glue/serial_service.h +++ b/firmware/targets/f6/ble-glue/serial_service.h @@ -7,13 +7,9 @@ extern "C" { #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); diff --git a/firmware/targets/f6/furi-hal/furi-hal-bt.c b/firmware/targets/f6/furi-hal/furi-hal-bt.c index f40f9601..36bd1fa2 100644 --- a/firmware/targets/f6/furi-hal/furi-hal-bt.c +++ b/firmware/targets/f6/furi-hal/furi-hal-bt.c @@ -5,6 +5,7 @@ #include #include #include +#include void furi_hal_bt_init() { // 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() { - return APP_BLE_Start(); + return gap_init(); } void furi_hal_bt_dump_state(string_t buffer) { diff --git a/firmware/targets/f7/ble-glue/app_ble.c b/firmware/targets/f7/ble-glue/app_ble.c index bb80fcea..652c29ef 100644 --- a/firmware/targets/f7/ble-glue/app_ble.c +++ b/firmware/targets/f7/ble-glue/app_ble.c @@ -6,106 +6,20 @@ #include "ble.h" #include "tl.h" #include "app_ble.h" - -#include "cmsis_os.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 -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; -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; osSemaphoreId_t SemHciId; -osThreadId_t AdvUpdateProcessId; 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 = { .name = CFG_HCI_USER_EVT_PROCESS_NAME, .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_StatusNot( HCI_TL_CmdStatus_t status ); 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() { 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); } -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 ) { 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); } -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) { UNUSED(argument); diff --git a/firmware/targets/f7/ble-glue/app_ble.h b/firmware/targets/f7/ble-glue/app_ble.h index 2bbd5165..08c60fe3 100644 --- a/firmware/targets/f7/ble-glue/app_ble.h +++ b/firmware/targets/f7/ble-glue/app_ble.h @@ -7,20 +7,7 @@ extern "C" { #include #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_Start(); - -APP_BLE_ConnStatus_t APP_BLE_Get_Server_Connection_Status(); #ifdef __cplusplus } diff --git a/firmware/targets/f7/ble-glue/app_conf.h b/firmware/targets/f7/ble-glue/app_conf.h index dc22b4ba..381d5ae7 100644 --- a/firmware/targets/f7/ble-glue/app_conf.h +++ b/firmware/targets/f7/ble-glue/app_conf.h @@ -139,7 +139,7 @@ /** * 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 diff --git a/firmware/targets/f7/ble-glue/battery_service.c b/firmware/targets/f7/ble-glue/battery_service.c index bcf54049..654edd53 100644 --- a/firmware/targets/f7/ble-glue/battery_service.c +++ b/firmware/targets/f7/ble-glue/battery_service.c @@ -11,21 +11,22 @@ typedef struct { uint16_t char_level_handle; } 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; - 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); + 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, + status = aci_gatt_add_char(battery_svc->svc_handle, UUID_TYPE_16, (Char_UUID_t *) &char_battery_level_uuid, 1, @@ -34,17 +35,39 @@ bool battery_svc_init() { GATT_DONT_NOTIFY_EVENTS, 10, CHAR_VALUE_LEN_CONSTANT, - &battery_svc.char_level_handle); + &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; +} + +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) { + // 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"); - 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, 1, &battery_charge); diff --git a/firmware/targets/f7/ble-glue/battery_service.h b/firmware/targets/f7/ble-glue/battery_service.h index 82445d2c..a50e607c 100644 --- a/firmware/targets/f7/ble-glue/battery_service.h +++ b/firmware/targets/f7/ble-glue/battery_service.h @@ -7,7 +7,9 @@ extern "C" { #endif -bool battery_svc_init(); +void battery_svc_start(); + +void battery_svc_stop(); bool battery_svc_update_level(uint8_t battery_level); diff --git a/firmware/targets/f7/ble-glue/dev_info_service.c b/firmware/targets/f7/ble-glue/dev_info_service.c index d2b60cfd..db58226b 100644 --- a/firmware/targets/f7/ble-glue/dev_info_service.c +++ b/firmware/targets/f7/ble-glue/dev_info_service.c @@ -4,7 +4,7 @@ #include -#define DEV_INFO_SERVICE_TAG "dev info service" +#define DEV_INFO_SVC_TAG "dev info service" typedef struct { uint16_t service_handle; @@ -14,108 +14,143 @@ typedef struct { uint16_t software_rev_char_handle; } 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; - 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); + 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); + FURI_LOG_E(DEV_INFO_SVC_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, + status = aci_gatt_add_char(dev_info_svc->service_handle, UUID_TYPE_16, (Char_UUID_t*)&uuid, - strlen(DEV_INFO_MANUFACTURER_NAME), + strlen(dev_info_man_name), CHAR_PROP_READ, ATTR_PERMISSION_NONE, GATT_DONT_NOTIFY_EVENTS, 10, CHAR_VALUE_LEN_CONSTANT, - &dev_info_svc.man_name_char_handle); + &dev_info_svc->man_name_char_handle); 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; - status = aci_gatt_add_char(dev_info_svc.service_handle, + status = aci_gatt_add_char(dev_info_svc->service_handle, UUID_TYPE_16, (Char_UUID_t*)&uuid, - strlen(DEV_INFO_SERIAL_NUMBER), + strlen(dev_info_serial_num), CHAR_PROP_READ, ATTR_PERMISSION_NONE, GATT_DONT_NOTIFY_EVENTS, 10, CHAR_VALUE_LEN_CONSTANT, - &dev_info_svc.serial_num_char_handle); + &dev_info_svc->serial_num_char_handle); 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; - status = aci_gatt_add_char(dev_info_svc.service_handle, + status = aci_gatt_add_char(dev_info_svc->service_handle, UUID_TYPE_16, (Char_UUID_t*)&uuid, - strlen(DEV_INFO_FIRMWARE_REVISION_NUMBER), + strlen(dev_info_firmware_rev_num), CHAR_PROP_READ, ATTR_PERMISSION_NONE, GATT_DONT_NOTIFY_EVENTS, 10, CHAR_VALUE_LEN_CONSTANT, - &dev_info_svc.firmware_rev_char_handle); + &dev_info_svc->firmware_rev_char_handle); 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; - status = aci_gatt_add_char(dev_info_svc.service_handle, + status = aci_gatt_add_char(dev_info_svc->service_handle, UUID_TYPE_16, (Char_UUID_t*)&uuid, - strlen(DEV_INFO_SOFTWARE_REVISION_NUMBER), + strlen(dev_info_software_rev_num), CHAR_PROP_READ, ATTR_PERMISSION_NONE, GATT_DONT_NOTIFY_EVENTS, 10, CHAR_VALUE_LEN_CONSTANT, - &dev_info_svc.software_rev_char_handle); + &dev_info_svc->software_rev_char_handle); 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 - 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, - strlen(DEV_INFO_MANUFACTURER_NAME), - (uint8_t*)DEV_INFO_MANUFACTURER_NAME); + strlen(dev_info_man_name), + (uint8_t*)dev_info_man_name); 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, - strlen(DEV_INFO_SERIAL_NUMBER), - (uint8_t*)DEV_INFO_SERIAL_NUMBER); + strlen(dev_info_serial_num), + (uint8_t*)dev_info_serial_num); 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, - 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) { - 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, - 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) { - 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; } diff --git a/firmware/targets/f7/ble-glue/dev_info_service.h b/firmware/targets/f7/ble-glue/dev_info_service.h index b0e08d3f..62eccefa 100644 --- a/firmware/targets/f7/ble-glue/dev_info_service.h +++ b/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_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 } diff --git a/firmware/targets/f7/ble-glue/gap.c b/firmware/targets/f7/ble-glue/gap.c new file mode 100644 index 00000000..19d1b5f1 --- /dev/null +++ b/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 +#include + +#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); + } +} diff --git a/firmware/targets/f7/ble-glue/gap.h b/firmware/targets/f7/ble-glue/gap.h new file mode 100644 index 00000000..3fc2cf4c --- /dev/null +++ b/firmware/targets/f7/ble-glue/gap.h @@ -0,0 +1,22 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + GapStateIdle, + GapStateAdvFast, + GapStateAdvLowPower, + GapStateConnected, +} GapState; + +bool gap_init(); + +GapState gap_get_status(); + +#ifdef __cplusplus +} +#endif diff --git a/firmware/targets/f7/ble-glue/serial_service.c b/firmware/targets/f7/ble-glue/serial_service.c index 4b0ad402..eae2c275 100644 --- a/firmware/targets/f7/ble-glue/serial_service.c +++ b/firmware/targets/f7/ble-glue/serial_service.c @@ -6,13 +6,19 @@ #define SERIAL_SERVICE_TAG "serial service" +#define SERIAL_SVC_DATA_LEN_MAX 245 + typedef struct { uint16_t svc_handle; uint16_t rx_char_handle; uint16_t tx_char_handle; } 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) { 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(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) { + 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"); + } 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); 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); + FURI_LOG_D(SERIAL_SERVICE_TAG, "Ack received", blecore_evt->ecode); ret = SVCCTL_EvtAckFlowEnable; } } return ret; } -bool serial_svc_init() { +void serial_svc_start() { 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 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); + 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 , + 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); + &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 , + 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); + &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; } +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) { 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, data_len, data); diff --git a/firmware/targets/f7/ble-glue/serial_service.h b/firmware/targets/f7/ble-glue/serial_service.h index 92b943a0..9d3d6217 100644 --- a/firmware/targets/f7/ble-glue/serial_service.h +++ b/firmware/targets/f7/ble-glue/serial_service.h @@ -7,13 +7,9 @@ extern "C" { #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); diff --git a/firmware/targets/f7/furi-hal/furi-hal-bt.c b/firmware/targets/f7/furi-hal/furi-hal-bt.c index f40f9601..36bd1fa2 100644 --- a/firmware/targets/f7/furi-hal/furi-hal-bt.c +++ b/firmware/targets/f7/furi-hal/furi-hal-bt.c @@ -5,6 +5,7 @@ #include #include #include +#include void furi_hal_bt_init() { // 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() { - return APP_BLE_Start(); + return gap_init(); } void furi_hal_bt_dump_state(string_t buffer) {