From 710f33981a39d77d94d4313b67a58284eefa4a9d Mon Sep 17 00:00:00 2001 From: Pavel Kulyov Date: Thu, 9 Sep 2021 09:54:30 -0700 Subject: [PATCH 01/13] ReadMe: fix typo (#692) --- ReadMe.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ReadMe.md b/ReadMe.md index 5e0fd381..d5d54baf 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -14,7 +14,7 @@ Our goal is to create nice and clean code with good documentation, to make it a Flipper Zero's firmware consists of three components: -- Core2 firmware set - proprietary componenets by ST: FUS + radio stack. +- Core2 firmware set - proprietary components by ST: FUS + radio stack. - Core1 Bootloader - controls basic hardware initialization and loads firmware - Core1 Firmware - HAL + OS + Drivers + Applications From 9bce160ca6aff2b139cd230aad2709e192be8117 Mon Sep 17 00:00:00 2001 From: gornekich Date: Fri, 10 Sep 2021 00:11:32 +0300 Subject: [PATCH 02/13] [FL-1722] BLE custom serial service (#685) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ble: remove heart rate profile * ble-glue: delete dead code * ble-glue: dis refactoring * ble-glue: add battery service * broken ble_common refactoring * ble-glue: advertise 128 bit service uid * ble-glue: remove dead code * ble: advertise service 16 bit uid depending on flipper color * ble-glue: remove debug * ble: intriduce serial service * ble: serial over ble * bt: serial echo server * bt: serial service process indicate acknowledge * bt: serial service event handler update * bt: refactore battery service * bt: add battery level apdate API * power: update battery level on change * bt: refactore device information service Co-authored-by: あく --- applications/bt/bt_service/bt.c | 11 + applications/bt/bt_service/bt.h | 13 + applications/bt/bt_service/bt_i.h | 7 +- applications/power/power.c | 13 +- core/furi/common_defines.h | 8 + firmware/targets/f6/ble-glue/app_ble.c | 101 ++--- firmware/targets/f6/ble-glue/app_ble.h | 4 - firmware/targets/f6/ble-glue/app_common.h | 75 +--- firmware/targets/f6/ble-glue/app_debug.c | 367 ------------------ firmware/targets/f6/ble-glue/app_debug.h | 69 ---- firmware/targets/f6/ble-glue/app_entry.c | 14 +- .../targets/f6/ble-glue/battery_service.c | 55 +++ .../targets/f6/ble-glue/battery_service.h | 16 + firmware/targets/f6/ble-glue/ble_conf.h | 37 +- .../targets/f6/ble-glue/dev_info_service.c | 121 ++++++ .../targets/f6/ble-glue/dev_info_service.h | 20 + firmware/targets/f6/ble-glue/dis_app.c | 157 -------- firmware/targets/f6/ble-glue/dis_app.h | 20 - firmware/targets/f6/ble-glue/hrs_app.c | 256 ------------ firmware/targets/f6/ble-glue/hrs_app.h | 69 ---- firmware/targets/f6/ble-glue/serial_service.c | 102 +++++ firmware/targets/f6/ble-glue/serial_service.h | 22 ++ firmware/targets/f6/target.mk | 2 - 23 files changed, 438 insertions(+), 1121 deletions(-) mode change 100644 => 100755 applications/bt/bt_service/bt.c delete mode 100644 firmware/targets/f6/ble-glue/app_debug.c delete mode 100644 firmware/targets/f6/ble-glue/app_debug.h create mode 100644 firmware/targets/f6/ble-glue/battery_service.c create mode 100644 firmware/targets/f6/ble-glue/battery_service.h create mode 100644 firmware/targets/f6/ble-glue/dev_info_service.c create mode 100644 firmware/targets/f6/ble-glue/dev_info_service.h delete mode 100644 firmware/targets/f6/ble-glue/dis_app.c delete mode 100644 firmware/targets/f6/ble-glue/dis_app.h delete mode 100644 firmware/targets/f6/ble-glue/hrs_app.c delete mode 100644 firmware/targets/f6/ble-glue/hrs_app.h create mode 100644 firmware/targets/f6/ble-glue/serial_service.c create mode 100644 firmware/targets/f6/ble-glue/serial_service.h diff --git a/applications/bt/bt_service/bt.c b/applications/bt/bt_service/bt.c old mode 100644 new mode 100755 index 785573f2..ba292021 --- a/applications/bt/bt_service/bt.c +++ b/applications/bt/bt_service/bt.c @@ -1,4 +1,5 @@ #include "bt_i.h" +#include "battery_service.h" #define BT_SERVICE_TAG "BT" @@ -43,6 +44,12 @@ Bt* bt_alloc() { return bt; } +bool bt_update_battery_level(Bt* bt, uint8_t battery_level) { + BtMessage message = { + .type = BtMessageTypeUpdateBatteryLevel, .data.battery_level = battery_level}; + return osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK; +} + int32_t bt_srv() { Bt* bt = bt_alloc(); furi_record_create("bt", bt); @@ -68,6 +75,10 @@ int32_t bt_srv() { if(message.type == BtMessageTypeUpdateStatusbar) { // Update statusbar view_port_enabled_set(bt->statusbar_view_port, furi_hal_bt_is_alive()); + } else if(message.type == BtMessageTypeUpdateBatteryLevel) { + if(furi_hal_bt_is_alive()) { + battery_svc_update_level(message.data.battery_level); + } } } return 0; diff --git a/applications/bt/bt_service/bt.h b/applications/bt/bt_service/bt.h index b163fa69..4be69dae 100644 --- a/applications/bt/bt_service/bt.h +++ b/applications/bt/bt_service/bt.h @@ -1,3 +1,16 @@ #pragma once +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + typedef struct Bt Bt; + +bool bt_update_battery_level(Bt* bt, uint8_t battery_level); + +#ifdef __cplusplus +} +#endif diff --git a/applications/bt/bt_service/bt_i.h b/applications/bt/bt_service/bt_i.h index b498e048..6c0c2bf7 100644 --- a/applications/bt/bt_service/bt_i.h +++ b/applications/bt/bt_service/bt_i.h @@ -13,11 +13,16 @@ typedef enum { BtMessageTypeUpdateStatusbar, + BtMessageTypeUpdateBatteryLevel, } BtMessageType; +typedef union { + uint8_t battery_level; +} BtMessageData; + typedef struct { BtMessageType type; - void* param; + BtMessageData data; } BtMessage; struct Bt { diff --git a/applications/power/power.c b/applications/power/power.c index b083f6ea..6fc4077a 100644 --- a/applications/power/power.c +++ b/applications/power/power.c @@ -18,6 +18,7 @@ #include #include +#include #define POWER_OFF_TIMEOUT 30 @@ -39,6 +40,7 @@ struct Power { ValueMutex* menu_vm; Cli* cli; + Bt* bt; MenuItem* menu; PowerState state; @@ -108,6 +110,8 @@ Power* power_alloc() { power->cli = furi_record_open("cli"); power_cli_init(power->cli, power); + power->bt = furi_record_open("bt"); + power->menu = menu_item_alloc_menu("Power", icon_animation_alloc(&A_Power_14)); menu_item_subitem_add( power->menu, menu_item_alloc_function("Off", NULL, power_menu_off_callback, power)); @@ -206,13 +210,15 @@ int32_t power_srv(void* p) { power->menu_vm, (Menu * menu) { menu_item_add(menu, power->menu); }); furi_record_create("power", power); - + uint8_t battery_level = 0; + uint8_t battery_level_prev = 0; while(1) { bool battery_low = false; with_view_model( power->info_view, (PowerInfoModel * model) { model->charge = furi_hal_power_get_pct(); + battery_level = model->charge; model->health = furi_hal_power_get_bat_health_pct(); model->capacity_remaining = furi_hal_power_get_battery_remaining_capacity(); model->capacity_full = furi_hal_power_get_battery_full_capacity(); @@ -258,6 +264,11 @@ int32_t power_srv(void* p) { power_charging_indication_handler(power, notifications); + if(battery_level_prev != battery_level) { + battery_level_prev = battery_level; + bt_update_battery_level(power->bt, battery_level); + } + view_port_update(power->battery_view_port); osDelay(1024); diff --git a/core/furi/common_defines.h b/core/furi/common_defines.h index 011af99e..7d514660 100644 --- a/core/furi/common_defines.h +++ b/core/furi/common_defines.h @@ -40,3 +40,11 @@ y = SWAP; \ } while(0) #endif + +#ifndef PLACE_IN_SECTION +#define PLACE_IN_SECTION(x) __attribute__((section(x))) +#endif + +#ifndef ALIGN +#define ALIGN(n) __attribute__((aligned(n))) +#endif diff --git a/firmware/targets/f6/ble-glue/app_ble.c b/firmware/targets/f6/ble-glue/app_ble.c index 042000b5..bb80fcea 100644 --- a/firmware/targets/f6/ble-glue/app_ble.c +++ b/firmware/targets/f6/ble-glue/app_ble.c @@ -10,8 +10,9 @@ #include "cmsis_os.h" #include "shci.h" #include "otp.h" -#include "dis_app.h" -#include "hrs_app.h" +#include "dev_info_service.h" +#include "battery_service.h" +#include "serial_service.h" #include @@ -123,7 +124,6 @@ static void Ble_Tl_Init( void ); static void Ble_Hci_Gap_Gatt_Init(); static const uint8_t* BleGetBdAddress( void ); static void Adv_Request( APP_BLE_ConnStatus_t New_Status ); -static void Add_Advertisment_Service_UUID( uint16_t servUUID ); static void Adv_Mgr( void ); static void AdvUpdateProcess(void *argument); static void Adv_Update( void ); @@ -160,6 +160,8 @@ bool APP_BLE_Init() { return (SHCI_C2_BLE_Init( &ble_init_cmd_packet ) == SHCI_Success); } +static void set_advertisment_service_uid(uint8_t* uid, uint8_t uin_len); + bool APP_BLE_Start() { if (APPE_Status() != BleGlueStatusStarted) { return false; @@ -180,16 +182,18 @@ bool APP_BLE_Start() { #endif // Initialize DIS Application - DISAPP_Init(); - // Initialize HRS Application - HRSAPP_Init(); + dev_info_service_init(); + // Initialize BAS Application + battery_svc_init(); + // Initialize Serial application + serial_svc_init(); // Create timer to handle the connection state machine HW_TS_Create(CFG_TIM_PROC_ID_ISR, &(BleApplicationContext.Advertising_mgr_timer_Id), hw_ts_SingleShot, Adv_Mgr); + uint8_t adv_service_uid[2]; + adv_service_uid[0] = 0x80 | furi_hal_version_get_hw_color(); + adv_service_uid[1] = 0x30; - // Make device discoverable - BleApplicationContext.BleApplicationContext_legacy.advtServUUID[0] = AD_TYPE_16_BIT_SERV_UUID; - BleApplicationContext.BleApplicationContext_legacy.advtServUUIDlen = 1; - Add_Advertisment_Service_UUID(HEART_RATE_SERVICE_UUID); + set_advertisment_service_uid(adv_service_uid, sizeof(adv_service_uid)); /* Initialize intervals for reconnexion without intervals update */ AdvIntervalMin = CFG_FAST_CONN_ADV_INTERVAL_MIN; AdvIntervalMax = CFG_FAST_CONN_ADV_INTERVAL_MAX; @@ -198,6 +202,11 @@ bool APP_BLE_Start() { return true; } +void SVCCTL_SvcInit() { + // Dummy function to prevent unused services initialization + // TODO refactore +} + SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification( void *pckt ) { hci_event_pckt *event_pckt; @@ -382,56 +391,23 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification( void *pckt ) 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; } -/* USER CODE BEGIN FD*/ -void APP_BLE_Key_Button1_Action() { - tBleStatus ret = BLE_STATUS_INVALID_PARAMS; - ret = aci_gap_clear_security_db(); - if (ret == BLE_STATUS_SUCCESS) { - APP_DBG_MSG("Successfully aci_gap_clear_security_db()\r\n"); - } else { - APP_DBG_MSG("aci_gap_clear_security_db() Failed , result: %d \r\n", ret); - } -} - -void APP_BLE_Key_Button2_Action() { - tBleStatus ret = BLE_STATUS_INVALID_PARAMS; - ret = aci_gap_slave_security_req(BleApplicationContext.BleApplicationContext_legacy.connectionHandle); - if (ret == BLE_STATUS_SUCCESS) { - APP_DBG_MSG("Successfully aci_gap_slave_security_req()"); - } else { - APP_DBG_MSG("aci_gap_slave_security_req() Failed , result: %d \r\n", ret); - } -} - -void APP_BLE_Key_Button3_Action() { - uint8_t TX_PHY, RX_PHY; - tBleStatus ret = BLE_STATUS_INVALID_PARAMS; - ret = hci_le_read_phy(BleApplicationContext.BleApplicationContext_legacy.connectionHandle,&TX_PHY,&RX_PHY); - if (ret == BLE_STATUS_SUCCESS) { - APP_DBG_MSG("Read_PHY success \r\n"); - APP_DBG_MSG("PHY Param TX= %d, RX= %d \r\n", TX_PHY, RX_PHY); - if ((TX_PHY == TX_2M) && (RX_PHY == RX_2M)) { - APP_DBG_MSG("hci_le_set_phy PHY Param TX= %d, RX= %d \r\n", TX_1M, RX_1M); - ret = hci_le_set_phy(BleApplicationContext.BleApplicationContext_legacy.connectionHandle,ALL_PHYS_PREFERENCE,TX_1M,RX_1M,0); - } else { - APP_DBG_MSG("hci_le_set_phy PHY Param TX= %d, RX= %d \r\n", TX_2M_PREFERRED, RX_2M_PREFERRED); - ret = hci_le_set_phy(BleApplicationContext.BleApplicationContext_legacy.connectionHandle,ALL_PHYS_PREFERENCE,TX_2M_PREFERRED,RX_2M_PREFERRED,0); - } - } else { - APP_DBG_MSG("Read conf not succeess \r\n"); - } - - if (ret == BLE_STATUS_SUCCESS) { - APP_DBG_MSG("set PHY cmd ok\r\n"); - } else { - APP_DBG_MSG("set PHY cmd NOK\r\n"); - } -} - static void Ble_Tl_Init( void ) { HCI_TL_HciInitConf_t Hci_Tl_Init_Conf; @@ -654,6 +630,9 @@ static void Adv_Request(APP_BLE_ConnStatus_t New_Status) BleApplicationContext.BleApplicationContext_legacy.advtServUUID, 0, 0); + if(ret) { + FURI_LOG_E("APP ble", "Set discoverable err: %d", ret); + } /* Update Advertising data */ ret = aci_gap_update_adv_data(sizeof(manuf_data), (uint8_t*) manuf_data); @@ -712,16 +691,6 @@ const uint8_t* BleGetBdAddress( void ) { *SPECIFIC FUNCTIONS * *************************************************************/ -static void Add_Advertisment_Service_UUID( uint16_t servUUID ) { - BleApplicationContext.BleApplicationContext_legacy.advtServUUID[BleApplicationContext.BleApplicationContext_legacy.advtServUUIDlen] = - (uint8_t) (servUUID & 0xFF); - BleApplicationContext.BleApplicationContext_legacy.advtServUUIDlen++; - BleApplicationContext.BleApplicationContext_legacy.advtServUUID[BleApplicationContext.BleApplicationContext_legacy.advtServUUIDlen] = - (uint8_t) (servUUID >> 8) & 0xFF; - BleApplicationContext.BleApplicationContext_legacy.advtServUUIDlen++; - -} - static void Adv_Mgr( void ) { /** * The code shall be executed in the background as an aci command may be sent diff --git a/firmware/targets/f6/ble-glue/app_ble.h b/firmware/targets/f6/ble-glue/app_ble.h index 4d3ba876..2bbd5165 100644 --- a/firmware/targets/f6/ble-glue/app_ble.h +++ b/firmware/targets/f6/ble-glue/app_ble.h @@ -22,10 +22,6 @@ bool APP_BLE_Start(); APP_BLE_ConnStatus_t APP_BLE_Get_Server_Connection_Status(); -void APP_BLE_Key_Button1_Action(); -void APP_BLE_Key_Button2_Action(); -void APP_BLE_Key_Button3_Action(); - #ifdef __cplusplus } #endif diff --git a/firmware/targets/f6/ble-glue/app_common.h b/firmware/targets/f6/ble-glue/app_common.h index 9248c529..d21860f6 100644 --- a/firmware/targets/f6/ble-glue/app_common.h +++ b/firmware/targets/f6/ble-glue/app_common.h @@ -32,81 +32,12 @@ extern "C"{ #include #include +#include + #include "app_conf.h" - /* -------------------------------- * - * Basic definitions * - * -------------------------------- */ - -#undef NULL -#define NULL 0 - -#undef FALSE -#define FALSE 0 - -#undef TRUE -#define TRUE (!0) - - /* -------------------------------- * - * Critical Section definition * - * -------------------------------- */ -#define BACKUP_PRIMASK() uint32_t primask_bit= __get_PRIMASK() -#define DISABLE_IRQ() __disable_irq() -#define RESTORE_PRIMASK() __set_PRIMASK(primask_bit) - - /* -------------------------------- * - * Macro delimiters * - * -------------------------------- */ - -#define M_BEGIN do { - -#define M_END } while(0) - - /* -------------------------------- * - * Some useful macro definitions * - * -------------------------------- */ - - -#define MODINC( a, m ) M_BEGIN (a)++; if ((a)>=(m)) (a)=0; M_END - -#define MODDEC( a, m ) M_BEGIN if ((a)==0) (a)=(m); (a)--; M_END - -#define MODADD( a, b, m ) M_BEGIN (a)+=(b); if ((a)>=(m)) (a)-=(m); M_END - -#define MODSUB( a, b, m ) MODADD( a, (m)-(b), m ) - -#define PAUSE( t ) M_BEGIN \ - __IO int _i; \ - for ( _i = t; _i > 0; _i -- ); \ - M_END - -#define DIVF( x, y ) ((x)/(y)) - #define DIVC( x, y ) (((x)+(y)-1)/(y)) #define DIVR( x, y ) (((x)+((y)/2))/(y)) -#define SHRR( x, n ) ((((x)>>((n)-1))+1)>>1) - -#define BITN( w, n ) (((w)[(n)/32] >> ((n)%32)) & 1) - -#define BITNSET( w, n, b ) M_BEGIN (w)[(n)/32] |= ((U32)(b))<<((n)%32); M_END - - /* -------------------------------- * - * Compiler * - * -------------------------------- */ -#define PLACE_IN_SECTION( __x__ ) __attribute__((section (__x__))) - -#ifdef WIN32 -#define ALIGN(n) -#else -#define ALIGN(n) __attribute__((aligned(n))) -#endif - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /*APP_COMMON_H */ - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +#endif \ No newline at end of file diff --git a/firmware/targets/f6/ble-glue/app_debug.c b/firmware/targets/f6/ble-glue/app_debug.c deleted file mode 100644 index e1c29b46..00000000 --- a/firmware/targets/f6/ble-glue/app_debug.c +++ /dev/null @@ -1,367 +0,0 @@ -/* USER CODE BEGIN Header */ -/** - ****************************************************************************** - * File Name : app_debug.c - * Description : Debug capabilities source file for STM32WPAN Middleware - ****************************************************************************** - * @attention - * - *

© Copyright (c) 2020 STMicroelectronics. - * All rights reserved.

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

© Copyright (c) 2020 STMicroelectronics. - * All rights reserved.

- * - * This software component is licensed by ST under Ultimate Liberty license - * SLA0044, the "License"; You may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * www.st.com/SLA0044 - * - ****************************************************************************** - */ -/* USER CODE END Header */ - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __APP_DEBUG_H -#define __APP_DEBUG_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* Includes ------------------------------------------------------------------*/ - -/* Private includes ----------------------------------------------------------*/ -/* USER CODE BEGIN Includes */ - -/* USER CODE END Includes */ - - /* Exported types ------------------------------------------------------------*/ -/* USER CODE BEGIN ET */ - -/* USER CODE END ET */ - -/* Exported constants --------------------------------------------------------*/ -/* USER CODE BEGIN EC */ - -/* USER CODE END EC */ - -/* Exported variables --------------------------------------------------------*/ -/* USER CODE BEGIN EV */ - -/* USER CODE END EV */ - -/* Exported macros ------------------------------------------------------------*/ -/* USER CODE BEGIN EM */ - -/* USER CODE END EM */ - -/* Exported functions ---------------------------------------------*/ - void APPD_Init( void ); - void APPD_EnableCPU2( void ); -/* USER CODE BEGIN EF */ - -/* USER CODE END EF */ - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /*__APP_DEBUG_H */ - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f6/ble-glue/app_entry.c b/firmware/targets/f6/ble-glue/app_entry.c index 93b528c9..f2367263 100644 --- a/firmware/targets/f6/ble-glue/app_entry.c +++ b/firmware/targets/f6/ble-glue/app_entry.c @@ -6,7 +6,6 @@ #include "tl.h" #include "cmsis_os.h" #include "shci_tl.h" -#include "app_debug.h" #include extern RTC_HandleTypeDef hrtc; @@ -178,3 +177,16 @@ void shci_cmd_resp_wait(uint32_t timeout) { UNUSED(timeout); osSemaphoreAcquire( SemShciId, osWaitForever ); } + +#if(CFG_DEBUG_TRACE != 0) +void DbgOutputInit( void ) +{ +} + +void DbgOutputTraces( uint8_t *p_data, uint16_t size, void (*cb)(void) ) +{ + furi_hal_console_tx(p_data, size); + cb(); +} +#endif + diff --git a/firmware/targets/f6/ble-glue/battery_service.c b/firmware/targets/f6/ble-glue/battery_service.c new file mode 100644 index 00000000..bcf54049 --- /dev/null +++ b/firmware/targets/f6/ble-glue/battery_service.c @@ -0,0 +1,55 @@ +#include "battery_service.h" +#include "app_common.h" +#include "ble.h" + +#include + +#define BATTERY_SERVICE_TAG "battery service" + +typedef struct { + uint16_t svc_handle; + uint16_t char_level_handle; +} BatterySvc; + +static BatterySvc battery_svc; + +bool battery_svc_init() { + tBleStatus status; + const uint16_t service_uuid = BATTERY_SERVICE_UUID; + const uint16_t char_battery_level_uuid = BATTERY_LEVEL_CHAR_UUID; + + // Add Battery service + status = aci_gatt_add_service(UUID_TYPE_16, (Service_UUID_t*)&service_uuid, PRIMARY_SERVICE, 4, &battery_svc.svc_handle); + if(status) { + FURI_LOG_E(BATTERY_SERVICE_TAG, "Failed to add Battery service: %d", status); + } + + // Add Battery level characteristic + status = aci_gatt_add_char(battery_svc.svc_handle, + UUID_TYPE_16, + (Char_UUID_t *) &char_battery_level_uuid, + 1, + CHAR_PROP_READ | CHAR_PROP_NOTIFY, + ATTR_PERMISSION_NONE, + GATT_DONT_NOTIFY_EVENTS, + 10, + CHAR_VALUE_LEN_CONSTANT, + &battery_svc.char_level_handle); + if(status) { + FURI_LOG_E(BATTERY_SERVICE_TAG, "Failed to add Battery level characteristic: %d", status); + } + return status != BLE_STATUS_SUCCESS; +} + +bool battery_svc_update_level(uint8_t battery_charge) { + FURI_LOG_I(BATTERY_SERVICE_TAG, "Updating battery level characteristic"); + tBleStatus result = aci_gatt_update_char_value(battery_svc.svc_handle, + battery_svc.char_level_handle, + 0, + 1, + &battery_charge); + if(result) { + FURI_LOG_E(BATTERY_SERVICE_TAG, "Failed updating RX characteristic: %d", result); + } + return result != BLE_STATUS_SUCCESS; +} diff --git a/firmware/targets/f6/ble-glue/battery_service.h b/firmware/targets/f6/ble-glue/battery_service.h new file mode 100644 index 00000000..82445d2c --- /dev/null +++ b/firmware/targets/f6/ble-glue/battery_service.h @@ -0,0 +1,16 @@ +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +bool battery_svc_init(); + +bool battery_svc_update_level(uint8_t battery_level); + +#ifdef __cplusplus +} +#endif diff --git a/firmware/targets/f6/ble-glue/ble_conf.h b/firmware/targets/f6/ble-glue/ble_conf.h index eb034e35..0acd8860 100644 --- a/firmware/targets/f6/ble-glue/ble_conf.h +++ b/firmware/targets/f6/ble-glue/ble_conf.h @@ -53,47 +53,12 @@ #define BLE_CFG_CLT_MAX_NBR_CB 0 -/****************************************************************************** - * Device Information Service (DIS) - ******************************************************************************/ -/**< Options: Supported(1) or Not Supported(0) */ -#define BLE_CFG_DIS_MANUFACTURER_NAME_STRING 1 -#define BLE_CFG_DIS_MODEL_NUMBER_STRING 1 -#define BLE_CFG_DIS_SERIAL_NUMBER_STRING 0 -#define BLE_CFG_DIS_HARDWARE_REVISION_STRING 0 -#define BLE_CFG_DIS_FIRMWARE_REVISION_STRING 1 -#define BLE_CFG_DIS_SOFTWARE_REVISION_STRING 1 -#define BLE_CFG_DIS_SYSTEM_ID 0 -#define BLE_CFG_DIS_IEEE_CERTIFICATION 0 -#define BLE_CFG_DIS_PNP_ID 0 - -/** - * device information service characteristic lengths - */ -#define BLE_CFG_DIS_SYSTEM_ID_LEN_MAX (8) -#define BLE_CFG_DIS_MODEL_NUMBER_STRING_LEN_MAX (32) -#define BLE_CFG_DIS_SERIAL_NUMBER_STRING_LEN_MAX (32) -#define BLE_CFG_DIS_FIRMWARE_REVISION_STRING_LEN_MAX (32) -#define BLE_CFG_DIS_HARDWARE_REVISION_STRING_LEN_MAX (32) -#define BLE_CFG_DIS_SOFTWARE_REVISION_STRING_LEN_MAX (64) -#define BLE_CFG_DIS_MANUFACTURER_NAME_STRING_LEN_MAX (32) -#define BLE_CFG_DIS_IEEE_CERTIFICATION_LEN_MAX (32) -#define BLE_CFG_DIS_PNP_ID_LEN_MAX (7) - -/****************************************************************************** - * Heart Rate Service (HRS) - ******************************************************************************/ -#define BLE_CFG_HRS_BODY_SENSOR_LOCATION_CHAR 1/**< BODY SENSOR LOCATION CHARACTERISTIC */ -#define BLE_CFG_HRS_ENERGY_EXPENDED_INFO_FLAG 1/**< ENERGY EXTENDED INFO FLAG */ -#define BLE_CFG_HRS_ENERGY_RR_INTERVAL_FLAG 1/**< Max number of RR interval values - Shall not be greater than 9 */ - /****************************************************************************** * GAP Service - Apprearance ******************************************************************************/ #define BLE_CFG_UNKNOWN_APPEARANCE (0) -#define BLE_CFG_HR_SENSOR_APPEARANCE (832) -#define BLE_CFG_GAP_APPEARANCE (BLE_CFG_HR_SENSOR_APPEARANCE) +#define BLE_CFG_GAP_APPEARANCE (0x0086) /****************************************************************************** * Over The Air Feature (OTA) - STM Proprietary diff --git a/firmware/targets/f6/ble-glue/dev_info_service.c b/firmware/targets/f6/ble-glue/dev_info_service.c new file mode 100644 index 00000000..d2b60cfd --- /dev/null +++ b/firmware/targets/f6/ble-glue/dev_info_service.c @@ -0,0 +1,121 @@ +#include "dev_info_service.h" +#include "app_common.h" +#include "ble.h" + +#include + +#define DEV_INFO_SERVICE_TAG "dev info service" + +typedef struct { + uint16_t service_handle; + uint16_t man_name_char_handle; + uint16_t serial_num_char_handle; + uint16_t firmware_rev_char_handle; + uint16_t software_rev_char_handle; +} DevInfoSvc; + +bool dev_info_service_init() { + tBleStatus status; + DevInfoSvc dev_info_svc; + + // Add Device Information Service + uint16_t uuid = DEVICE_INFORMATION_SERVICE_UUID; + status = aci_gatt_add_service(UUID_TYPE_16, (Service_UUID_t*)&uuid, PRIMARY_SERVICE, 9, &dev_info_svc.service_handle); + if(status) { + FURI_LOG_E(DEV_INFO_SERVICE_TAG, "Failed to add Device Information Service: %d", status); + } + + // Add characteristics + uuid = MANUFACTURER_NAME_UUID; + status = aci_gatt_add_char(dev_info_svc.service_handle, + UUID_TYPE_16, + (Char_UUID_t*)&uuid, + strlen(DEV_INFO_MANUFACTURER_NAME), + CHAR_PROP_READ, + ATTR_PERMISSION_NONE, + GATT_DONT_NOTIFY_EVENTS, + 10, + CHAR_VALUE_LEN_CONSTANT, + &dev_info_svc.man_name_char_handle); + if(status) { + FURI_LOG_E(DEV_INFO_SERVICE_TAG, "Failed to add manufacturer name char: %d", status); + + } + uuid = SERIAL_NUMBER_UUID; + status = aci_gatt_add_char(dev_info_svc.service_handle, + UUID_TYPE_16, + (Char_UUID_t*)&uuid, + strlen(DEV_INFO_SERIAL_NUMBER), + CHAR_PROP_READ, + ATTR_PERMISSION_NONE, + GATT_DONT_NOTIFY_EVENTS, + 10, + CHAR_VALUE_LEN_CONSTANT, + &dev_info_svc.serial_num_char_handle); + if(status) { + FURI_LOG_E(DEV_INFO_SERVICE_TAG, "Failed to add serial number char: %d", status); + } + uuid = FIRMWARE_REVISION_UUID; + status = aci_gatt_add_char(dev_info_svc.service_handle, + UUID_TYPE_16, + (Char_UUID_t*)&uuid, + strlen(DEV_INFO_FIRMWARE_REVISION_NUMBER), + CHAR_PROP_READ, + ATTR_PERMISSION_NONE, + GATT_DONT_NOTIFY_EVENTS, + 10, + CHAR_VALUE_LEN_CONSTANT, + &dev_info_svc.firmware_rev_char_handle); + if(status) { + FURI_LOG_E(DEV_INFO_SERVICE_TAG, "Failed to add firmware revision char: %d", status); + } + uuid = SOFTWARE_REVISION_UUID; + status = aci_gatt_add_char(dev_info_svc.service_handle, + UUID_TYPE_16, + (Char_UUID_t*)&uuid, + strlen(DEV_INFO_SOFTWARE_REVISION_NUMBER), + CHAR_PROP_READ, + ATTR_PERMISSION_NONE, + GATT_DONT_NOTIFY_EVENTS, + 10, + CHAR_VALUE_LEN_CONSTANT, + &dev_info_svc.software_rev_char_handle); + if(status) { + FURI_LOG_E(DEV_INFO_SERVICE_TAG, "Failed to add software revision char: %d", status); + } + + // Update characteristics + status = aci_gatt_update_char_value(dev_info_svc.service_handle, + dev_info_svc.man_name_char_handle, + 0, + strlen(DEV_INFO_MANUFACTURER_NAME), + (uint8_t*)DEV_INFO_MANUFACTURER_NAME); + if(status) { + FURI_LOG_E(DEV_INFO_SERVICE_TAG, "Failed to update manufacturer name char: %d", status); + } + status = aci_gatt_update_char_value(dev_info_svc.service_handle, + dev_info_svc.serial_num_char_handle, + 0, + strlen(DEV_INFO_SERIAL_NUMBER), + (uint8_t*)DEV_INFO_SERIAL_NUMBER); + if(status) { + FURI_LOG_E(DEV_INFO_SERVICE_TAG, "Failed to update serial number char: %d", status); + } + status = aci_gatt_update_char_value(dev_info_svc.service_handle, + dev_info_svc.firmware_rev_char_handle, + 0, + strlen(DEV_INFO_FIRMWARE_REVISION_NUMBER), + (uint8_t*)DEV_INFO_FIRMWARE_REVISION_NUMBER); + if(status) { + FURI_LOG_E(DEV_INFO_SERVICE_TAG, "Failed to update firmware revision char: %d", status); + } + status = aci_gatt_update_char_value(dev_info_svc.service_handle, + dev_info_svc.software_rev_char_handle, + 0, + strlen(DEV_INFO_SOFTWARE_REVISION_NUMBER), + (uint8_t*)DEV_INFO_SOFTWARE_REVISION_NUMBER); + if(status) { + FURI_LOG_E(DEV_INFO_SERVICE_TAG, "Failed to update software revision char: %d", status); + } + return status != BLE_STATUS_SUCCESS; +} diff --git a/firmware/targets/f6/ble-glue/dev_info_service.h b/firmware/targets/f6/ble-glue/dev_info_service.h new file mode 100644 index 00000000..b0e08d3f --- /dev/null +++ b/firmware/targets/f6/ble-glue/dev_info_service.h @@ -0,0 +1,20 @@ +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define DEV_INFO_MANUFACTURER_NAME "Flipper Devices Inc." +#define DEV_INFO_SERIAL_NUMBER "1.0" +#define DEV_INFO_FIRMWARE_REVISION_NUMBER TARGET +#define DEV_INFO_SOFTWARE_REVISION_NUMBER GIT_COMMIT " " GIT_BRANCH " " GIT_BRANCH_NUM " " BUILD_DATE + + +bool dev_info_service_init(); + +#ifdef __cplusplus +} +#endif diff --git a/firmware/targets/f6/ble-glue/dis_app.c b/firmware/targets/f6/ble-glue/dis_app.c deleted file mode 100644 index 0bf6d4c0..00000000 --- a/firmware/targets/f6/ble-glue/dis_app.c +++ /dev/null @@ -1,157 +0,0 @@ -#include "app_common.h" -#include "ble.h" -#include "dis_app.h" -#include - -#if ((BLE_CFG_DIS_SYSTEM_ID != 0) || (CFG_MENU_DEVICE_INFORMATION != 0)) -static const uint8_t system_id[BLE_CFG_DIS_SYSTEM_ID_LEN_MAX] = { - (uint8_t)((DISAPP_MANUFACTURER_ID & 0xFF0000) >> 16), - (uint8_t)((DISAPP_MANUFACTURER_ID & 0x00FF00) >> 8), - (uint8_t)(DISAPP_MANUFACTURER_ID & 0x0000FF), - 0xFE, - 0xFF, - (uint8_t)((DISAPP_OUI & 0xFF0000) >> 16), - (uint8_t)((DISAPP_OUI & 0x00FF00) >> 8), - (uint8_t)(DISAPP_OUI & 0x0000FF) -}; -#endif - -#if ((BLE_CFG_DIS_IEEE_CERTIFICATION != 0) || (CFG_MENU_DEVICE_INFORMATION != 0)) -static const uint8_t ieee_id[BLE_CFG_DIS_IEEE_CERTIFICATION_LEN_MAX] = { - 0xFE, 0xCA, 0xFE, 0xCA, 0xFE, 0xCA, 0xFE, 0xCA, - 0xFE, 0xCA, 0xFE, 0xCA, 0xFE, 0xCA, 0xFE, 0xCA, - 0xFE, 0xCA, 0xFE, 0xCA, 0xFE, 0xCA, 0xFE, 0xCA, - 0xFE, 0xCA, 0xFE, 0xCA, 0xFE, 0xCA, 0xFE, 0xCA, -}; -#endif - -#if ((BLE_CFG_DIS_PNP_ID != 0) || (CFG_MENU_DEVICE_INFORMATION != 0)) -static const uint8_t pnp_id[BLE_CFG_DIS_PNP_ID_LEN_MAX] = { - 0x1, - 0xAD, 0xDE, - 0xDE, 0xDA, - 0x01, 0x00 -}; -#endif - -void DISAPP_Init(void) { - DIS_Data_t dis_information_data; - -#if ((BLE_CFG_DIS_MANUFACTURER_NAME_STRING != 0) || (CFG_MENU_DEVICE_INFORMATION != 0)) - /** - * Update MANUFACTURER NAME Information - * - * @param UUID - * @param pPData - * @return - */ - dis_information_data.pPayload = (uint8_t*)DISAPP_MANUFACTURER_NAME; - dis_information_data.Length = sizeof(DISAPP_MANUFACTURER_NAME); - DIS_UpdateChar(MANUFACTURER_NAME_UUID, &dis_information_data); -#endif - -#if ((BLE_CFG_DIS_MODEL_NUMBER_STRING != 0) || (CFG_MENU_DEVICE_INFORMATION != 0)) - /** - * Update MODEL NUMBERInformation - * - * @param UUID - * @param pPData - * @return - */ - const char* name = furi_hal_version_get_device_name_ptr(); - dis_information_data.pPayload = (uint8_t*)name; - dis_information_data.Length = strlen(name) + 1; - DIS_UpdateChar(MODEL_NUMBER_UUID, &dis_information_data); -#endif - -#if ((BLE_CFG_DIS_SERIAL_NUMBER_STRING != 0) || (CFG_MENU_DEVICE_INFORMATION != 0)) - /** - * Update SERIAL NUMBERInformation - * - * @param UUID - * @param pPData - * @return - */ - dis_information_data.pPayload = (uint8_t*)DISAPP_SERIAL_NUMBER; - dis_information_data.Length = sizeof(DISAPP_SERIAL_NUMBER); - DIS_UpdateChar(SERIAL_NUMBER_UUID, &dis_information_data); -#endif - -#if ((BLE_CFG_DIS_HARDWARE_REVISION_STRING != 0) || (CFG_MENU_DEVICE_INFORMATION != 0)) - /** - * Update HARDWARE REVISION NUMBERInformation - * - * @param UUID - * @param pPData - * @return - */ - dis_information_data.pPayload = (uint8_t*)DISAPP_HARDWARE_REVISION_NUMBER; - dis_information_data.Length = sizeof(DISAPP_HARDWARE_REVISION_NUMBER); - DIS_UpdateChar(HARDWARE_REVISION_UUID, &dis_information_data); -#endif - -#if ((BLE_CFG_DIS_FIRMWARE_REVISION_STRING != 0) || (CFG_MENU_DEVICE_INFORMATION != 0)) - /** - * Update FIRMWARE REVISION NUMBERInformation - * - * @param UUID - * @param pPData - * @return - */ - dis_information_data.pPayload = (uint8_t*)DISAPP_FIRMWARE_REVISION_NUMBER; - dis_information_data.Length = sizeof(DISAPP_FIRMWARE_REVISION_NUMBER); - DIS_UpdateChar(FIRMWARE_REVISION_UUID, &dis_information_data); -#endif - -#if ((BLE_CFG_DIS_SOFTWARE_REVISION_STRING != 0) || (CFG_MENU_DEVICE_INFORMATION != 0)) - /** - * Update SOFTWARE REVISION NUMBERInformation - * - * @param UUID - * @param pPData - * @return - */ - dis_information_data.pPayload = (uint8_t*)DISAPP_SOFTWARE_REVISION_NUMBER; - dis_information_data.Length = sizeof(DISAPP_SOFTWARE_REVISION_NUMBER); - DIS_UpdateChar(SOFTWARE_REVISION_UUID, &dis_information_data); -#endif - -#if ((BLE_CFG_DIS_SYSTEM_ID != 0) || (CFG_MENU_DEVICE_INFORMATION != 0)) - /** - * Update SYSTEM ID Information - * - * @param UUID - * @param pPData - * @return - */ - dis_information_data.pPayload = (uint8_t *)system_id; - dis_information_data.Length = BLE_CFG_DIS_SYSTEM_ID_LEN_MAX; - DIS_UpdateChar(SYSTEM_ID_UUID, &dis_information_data); -#endif - -#if ((BLE_CFG_DIS_IEEE_CERTIFICATION != 0) || (CFG_MENU_DEVICE_INFORMATION != 0)) - /** - * Update IEEE CERTIFICATION ID Information - * - * @param UUID - * @param pPData - * @return - */ - dis_information_data.pPayload = (uint8_t *)ieee_id; - dis_information_data.Length = BLE_CFG_DIS_IEEE_CERTIFICATION_LEN_MAX; - DIS_UpdateChar(IEEE_CERTIFICATION_UUID, &dis_information_data); -#endif - -#if ((BLE_CFG_DIS_PNP_ID != 0) || (CFG_MENU_DEVICE_INFORMATION != 0)) - /** - * Update PNP ID Information - * - * @param UUID - * @param pPData - * @return - */ - dis_information_data.pPayload = (uint8_t *)pnp_id; - dis_information_data.Length = BLE_CFG_DIS_PNP_ID_LEN_MAX; - DIS_UpdateChar(PNP_ID_UUID, &dis_information_data); -#endif -} diff --git a/firmware/targets/f6/ble-glue/dis_app.h b/firmware/targets/f6/ble-glue/dis_app.h deleted file mode 100644 index ecc7800f..00000000 --- a/firmware/targets/f6/ble-glue/dis_app.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -#define DISAPP_MANUFACTURER_NAME "Flipperdevice Inc." -//#define DISAPP_MODEL_NUMBER "FlipperZero" -#define DISAPP_SERIAL_NUMBER "1.0" -#define DISAPP_HARDWARE_REVISION_NUMBER "1.0" -#define DISAPP_FIRMWARE_REVISION_NUMBER TARGET -#define DISAPP_SOFTWARE_REVISION_NUMBER GIT_COMMIT " " GIT_BRANCH " " GIT_BRANCH_NUM " " BUILD_DATE -#define DISAPP_OUI 0x123456 -#define DISAPP_MANUFACTURER_ID 0x9ABCDE - -void DISAPP_Init(void); - -#ifdef __cplusplus -} -#endif diff --git a/firmware/targets/f6/ble-glue/hrs_app.c b/firmware/targets/f6/ble-glue/hrs_app.c deleted file mode 100644 index 08cff558..00000000 --- a/firmware/targets/f6/ble-glue/hrs_app.c +++ /dev/null @@ -1,256 +0,0 @@ -/* USER CODE BEGIN Header */ -/** - ****************************************************************************** - * @file hrs_app.c - * @author MCD Application Team - * @brief Heart Rate Service Application - ****************************************************************************** - * @attention - * - *

© Copyright (c) 2019 STMicroelectronics. - * All rights reserved.

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

© Copyright (c) 2019 STMicroelectronics. - * All rights reserved.

- * - * This software component is licensed by ST under Ultimate Liberty license - * SLA0044, the "License"; You may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * www.st.com/SLA0044 - * - ****************************************************************************** - */ -/* USER CODE END Header */ - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __HRS_APP_H -#define __HRS_APP_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* Includes ------------------------------------------------------------------*/ - -/* Private includes ----------------------------------------------------------*/ -/* USER CODE BEGIN Includes */ - -/* USER CODE END Includes */ - -/* Exported types ------------------------------------------------------------*/ -/* USER CODE BEGIN ET */ - -/* USER CODE END ET */ - -/* Exported constants --------------------------------------------------------*/ -/* USER CODE BEGIN EC */ - -/* USER CODE END EC */ - -/* External variables --------------------------------------------------------*/ -/* USER CODE BEGIN EV */ - -/* USER CODE END EV */ - -/* Exported macros ------------------------------------------------------------*/ -/* USER CODE BEGIN EM */ - -/* USER CODE END EM */ - -/* Exported functions ---------------------------------------------*/ -void HRSAPP_Init( void ); -/* USER CODE BEGIN EF */ - -/* USER CODE END EF */ - -#ifdef __cplusplus -} -#endif - -#endif /*__HRS_APP_H */ - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f6/ble-glue/serial_service.c b/firmware/targets/f6/ble-glue/serial_service.c new file mode 100644 index 00000000..4b0ad402 --- /dev/null +++ b/firmware/targets/f6/ble-glue/serial_service.c @@ -0,0 +1,102 @@ +#include "serial_service.h" +#include "app_common.h" +#include "ble.h" + +#include + +#define SERIAL_SERVICE_TAG "serial service" + +typedef struct { + uint16_t svc_handle; + uint16_t rx_char_handle; + uint16_t tx_char_handle; +} SerialSvc; + +static SerialSvc serial_svc; + +static SVCCTL_EvtAckStatus_t serial_svc_event_handler(void *event) { + SVCCTL_EvtAckStatus_t ret = SVCCTL_EvtNotAck; + hci_event_pckt* event_pckt = (hci_event_pckt *)(((hci_uart_pckt*)event)->data); + evt_blecore_aci* blecore_evt = (evt_blecore_aci*)event_pckt->data; + aci_gatt_attribute_modified_event_rp0* attribute_modified; + if(event_pckt->evt == HCI_VENDOR_SPECIFIC_DEBUG_EVT_CODE) { + if(blecore_evt->ecode == ACI_GATT_ATTRIBUTE_MODIFIED_VSEVT_CODE) { + attribute_modified = (aci_gatt_attribute_modified_event_rp0*)blecore_evt->data; + if(attribute_modified->Attr_Handle == serial_svc.tx_char_handle + 2) { + // Descriptor handle + ret = SVCCTL_EvtAckFlowEnable; + FURI_LOG_D(SERIAL_SERVICE_TAG, "TX descriptor event"); + } else if(attribute_modified->Attr_Handle == serial_svc.tx_char_handle + 1) { + FURI_LOG_I(SERIAL_SERVICE_TAG, "Data len: %d", attribute_modified->Attr_Data_Length); + for(uint8_t i = 0; i < attribute_modified->Attr_Data_Length; i++) { + printf("%02X ", attribute_modified->Attr_Data[i]); + } + printf("\r\n"); + serial_svc_update_rx(attribute_modified->Attr_Data, attribute_modified->Attr_Data_Length); + ret = SVCCTL_EvtAckFlowEnable; + } + } else if(blecore_evt->ecode == ACI_GATT_SERVER_CONFIRMATION_VSEVT_CODE) { + FURI_LOG_I(SERIAL_SERVICE_TAG, "Ack received", blecore_evt->ecode); + ret = SVCCTL_EvtAckFlowEnable; + } + } + return ret; +} + +bool serial_svc_init() { + tBleStatus status; + const uint8_t service_uuid[] = {SERIAL_SVC_UUID_128}; + const uint8_t char_rx_uuid[] = {SERIAL_CHAR_RX_UUID_128}; + const uint8_t char_tx_uuid[] = {SERIAL_CHAR_TX_UUID_128}; + + // Register event handler + SVCCTL_RegisterSvcHandler(serial_svc_event_handler); + + // Add service + status = aci_gatt_add_service(UUID_TYPE_128, (Service_UUID_t *)service_uuid, PRIMARY_SERVICE, 6, &serial_svc.svc_handle); + if(status) { + FURI_LOG_E(SERIAL_SERVICE_TAG, "Failed to add Serial service: %d", status); + } + + // Add TX characteristics + status = aci_gatt_add_char(serial_svc.svc_handle, UUID_TYPE_128, (const Char_UUID_t*)char_tx_uuid , + SERIAL_SVC_DATA_LEN_MAX, + CHAR_PROP_WRITE_WITHOUT_RESP | CHAR_PROP_WRITE | CHAR_PROP_READ, + ATTR_PERMISSION_NONE, + GATT_NOTIFY_ATTRIBUTE_WRITE, + 10, + CHAR_VALUE_LEN_VARIABLE, + &serial_svc.tx_char_handle); + if(status) { + FURI_LOG_E(SERIAL_SERVICE_TAG, "Failed to add TX characteristic: %d", status); + } + + // Add RX characteristic + status = aci_gatt_add_char(serial_svc.svc_handle, UUID_TYPE_128, (const Char_UUID_t*)char_rx_uuid , + SERIAL_SVC_DATA_LEN_MAX, + CHAR_PROP_READ | CHAR_PROP_INDICATE, + ATTR_PERMISSION_NONE, + GATT_DONT_NOTIFY_EVENTS, + 10, + CHAR_VALUE_LEN_VARIABLE, + &serial_svc.rx_char_handle); + if(status) { + FURI_LOG_E(SERIAL_SERVICE_TAG, "Failed to add RX characteristic: %d", status); + } + + return status != BLE_STATUS_SUCCESS; +} + +bool serial_svc_update_rx(uint8_t* data, uint8_t data_len) { + furi_assert(data_len < SERIAL_SVC_DATA_LEN_MAX); + + tBleStatus result = aci_gatt_update_char_value(serial_svc.svc_handle, + serial_svc.rx_char_handle, + 0, + data_len, + data); + if(result) { + FURI_LOG_E(SERIAL_SERVICE_TAG, "Failed updating RX characteristic: %d", result); + } + return result != BLE_STATUS_SUCCESS; +} diff --git a/firmware/targets/f6/ble-glue/serial_service.h b/firmware/targets/f6/ble-glue/serial_service.h new file mode 100644 index 00000000..92b943a0 --- /dev/null +++ b/firmware/targets/f6/ble-glue/serial_service.h @@ -0,0 +1,22 @@ +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define SERIAL_SVC_DATA_LEN_MAX 255 + +#define SERIAL_SVC_UUID_128 0x00, 0x00, 0xfe, 0x60, 0xcc, 0x7a, 0x48, 0x2a, 0x98, 0x4a, 0x7f, 0x2e, 0xd5, 0xb3, 0xe5, 0x8f +#define SERIAL_CHAR_RX_UUID_128 0x00, 0x00, 0xfe, 0x61, 0x8e, 0x22, 0x45, 0x41, 0x9d, 0x4c, 0x21, 0xed, 0xae, 0x82, 0xed, 0x19 +#define SERIAL_CHAR_TX_UUID_128 0x00, 0x00, 0xfe, 0x62, 0x8e, 0x22, 0x45, 0x41, 0x9d, 0x4c, 0x21, 0xed, 0xae, 0x82, 0xed, 0x19 + +bool serial_svc_init(); + +bool serial_svc_update_rx(uint8_t* data, uint8_t data_len); + +#ifdef __cplusplus +} +#endif diff --git a/firmware/targets/f6/target.mk b/firmware/targets/f6/target.mk index 558074c3..d020c155 100644 --- a/firmware/targets/f6/target.mk +++ b/firmware/targets/f6/target.mk @@ -108,8 +108,6 @@ C_SOURCES += \ $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/utilities/stm_list.c \ $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/utilities/dbg_trace.c \ $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/ble/svc/Src/svc_ctl.c \ - $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/ble/svc/Src/dis.c \ - $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/ble/svc/Src/hrs.c \ $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/ble/core/template/osal.c \ $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_hci_le.c \ $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_gap_aci.c \ From fbccb9fbafd543c2f7683be6de8ac9393250e9cd Mon Sep 17 00:00:00 2001 From: Albert Kharisov Date: Fri, 10 Sep 2021 00:37:32 +0300 Subject: [PATCH 03/13] [FL-1684] IRDA Add SIRC protocol (#693) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * IRDA HAL: Fill buffer refactoring * IRDA: Add SIRC protocol * IRDA: correct adr/cmd bit length * Disable Unit tests Co-authored-by: あく --- applications/irda/cli/irda-cli.cpp | 18 +- applications/irda/irda-app-file-parser.cpp | 12 +- .../irda/scene/irda-app-scene-edit-delete.cpp | 4 +- .../scene/irda-app-scene-learn-enter-name.cpp | 2 +- .../scene/irda-app-scene-learn-success.cpp | 4 +- applications/irda_monitor/irda_monitor.c | 8 +- .../irda_decoder_encoder_test.c | 135 +++-- .../test_data/irda_nec_test_data.srcdata | 2 +- .../test_data/irda_necext_test_data.srcdata | 2 +- .../test_data/irda_rc5_test_data.srcdata | 2 +- .../test_data/irda_rc6_test_data.srcdata | 2 +- .../test_data/irda_samsung_test_data.srcdata | 2 +- .../test_data/irda_sirc_test_data.srcdata | 485 ++++++++++++++++++ core/furi/common_defines.h | 9 + firmware/targets/f6/furi-hal/furi-hal-irda.c | 10 +- .../common/irda_common_decoder.c | 153 ++++-- .../common/irda_common_encoder.c | 27 +- .../encoder_decoder/common/irda_common_i.h | 37 +- .../common/irda_common_protocol_defs.c | 39 +- lib/irda/encoder_decoder/irda.c | 69 ++- lib/irda/encoder_decoder/irda.h | 28 +- lib/irda/encoder_decoder/irda_i.h | 9 +- .../encoder_decoder/irda_protocol_defs_i.h | 90 +++- .../encoder_decoder/nec/irda_decoder_nec.c | 6 +- .../encoder_decoder/nec/irda_encoder_nec.c | 9 +- lib/irda/encoder_decoder/nec/irda_nec_spec.c | 8 +- .../encoder_decoder/rc5/irda_decoder_rc5.c | 2 +- lib/irda/encoder_decoder/rc5/irda_rc5_spec.c | 8 +- .../encoder_decoder/rc6/irda_decoder_rc6.c | 8 +- lib/irda/encoder_decoder/rc6/irda_rc6_spec.c | 4 +- .../samsung/irda_decoder_samsung.c | 10 +- .../samsung/irda_samsung_spec.c | 4 +- .../encoder_decoder/sirc/irda_decoder_sirc.c | 92 ++++ .../encoder_decoder/sirc/irda_encoder_sirc.c | 89 ++++ .../encoder_decoder/sirc/irda_sirc_spec.c | 38 ++ lib/irda/worker/irda_worker.c | 12 +- 36 files changed, 1216 insertions(+), 223 deletions(-) create mode 100644 applications/tests/irda_decoder_encoder/test_data/irda_sirc_test_data.srcdata create mode 100644 lib/irda/encoder_decoder/sirc/irda_decoder_sirc.c create mode 100644 lib/irda/encoder_decoder/sirc/irda_encoder_sirc.c create mode 100644 lib/irda/encoder_decoder/sirc/irda_sirc_spec.c diff --git a/applications/irda/cli/irda-cli.cpp b/applications/irda/cli/irda-cli.cpp index 1becdfbb..f9906b5c 100644 --- a/applications/irda/cli/irda-cli.cpp +++ b/applications/irda/cli/irda-cli.cpp @@ -25,9 +25,9 @@ static void signal_received_callback(void* context, IrdaWorkerSignal* received_s sizeof(buf), "%s, A:0x%0*lX, C:0x%0*lX%s\r\n", irda_get_protocol_name(message->protocol), - irda_get_protocol_address_length(message->protocol), + ROUND_UP_TO(irda_get_protocol_address_length(message->protocol), 4), message->address, - irda_get_protocol_command_length(message->protocol), + ROUND_UP_TO(irda_get_protocol_command_length(message->protocol), 4), message->command, message->repeat ? " R" : ""); cli_write(cli, (uint8_t*)buf, buf_cnt); @@ -98,6 +98,20 @@ static bool parse_message(const char* str, IrdaMessage* message) { return false; } + uint32_t address_length = irda_get_protocol_address_length(protocol); + uint32_t address_mask = (1LU << address_length) - 1; + if(address != (address & address_mask)) { + printf("Address out of range (mask 0x%08lX): 0x%lX\r\n", address_mask, address); + return false; + } + + uint32_t command_length = irda_get_protocol_command_length(protocol); + uint32_t command_mask = (1LU << command_length) - 1; + if(command != (command & command_mask)) { + printf("Command out of range (mask 0x%08lX): 0x%lX\r\n", command_mask, command); + return false; + } + message->protocol = protocol; message->address = address; message->command = command; diff --git a/applications/irda/irda-app-file-parser.cpp b/applications/irda/irda-app-file-parser.cpp index f462919e..3ab14fc0 100644 --- a/applications/irda/irda-app-file-parser.cpp +++ b/applications/irda/irda-app-file-parser.cpp @@ -45,9 +45,9 @@ size_t IrdaAppFileParser::stringify_message( "%.31s %.31s A:%0*lX C:%0*lX\n", name, irda_get_protocol_name(protocol), - irda_get_protocol_address_length(protocol), + ROUND_UP_TO(irda_get_protocol_address_length(protocol), 4), message.address, - irda_get_protocol_command_length(protocol), + ROUND_UP_TO(irda_get_protocol_command_length(protocol), 4), message.command); furi_assert(written < buf_size); @@ -162,8 +162,8 @@ std::unique_ptr return nullptr; } - int address_length = irda_get_protocol_address_length(protocol); - uint32_t address_mask = (1LU << (4 * address_length)) - 1; + uint32_t address_length = irda_get_protocol_address_length(protocol); + uint32_t address_mask = (1LU << address_length) - 1; if(address != (address & address_mask)) { size_t end_of_str = MIN(str.find_last_not_of(" \t\r\n") + 1, (size_t)30); FURI_LOG_E( @@ -176,8 +176,8 @@ std::unique_ptr return nullptr; } - int command_length = irda_get_protocol_command_length(protocol); - uint32_t command_mask = (1LU << (4 * command_length)) - 1; + uint32_t command_length = irda_get_protocol_command_length(protocol); + uint32_t command_mask = (1LU << command_length) - 1; if(command != (command & command_mask)) { size_t end_of_str = MIN(str.find_last_not_of(" \t\r\n") + 1, (size_t)30); FURI_LOG_E( diff --git a/applications/irda/scene/irda-app-scene-edit-delete.cpp b/applications/irda/scene/irda-app-scene-edit-delete.cpp index c5d1cdd7..ff11cc19 100644 --- a/applications/irda/scene/irda-app-scene-edit-delete.cpp +++ b/applications/irda/scene/irda-app-scene-edit-delete.cpp @@ -29,9 +29,9 @@ void IrdaAppSceneEditDelete::on_enter(IrdaApp* app) { "%s\n%s\nA=0x%0*lX C=0x%0*lX", remote_manager->get_button_name(app->get_current_button()).c_str(), irda_get_protocol_name(message->protocol), - irda_get_protocol_address_length(message->protocol), + ROUND_UP_TO(irda_get_protocol_address_length(message->protocol), 4), message->address, - irda_get_protocol_command_length(message->protocol), + ROUND_UP_TO(irda_get_protocol_command_length(message->protocol), 4), message->command); } else { app->set_text_store( diff --git a/applications/irda/scene/irda-app-scene-learn-enter-name.cpp b/applications/irda/scene/irda-app-scene-learn-enter-name.cpp index aa22d620..821ae9de 100644 --- a/applications/irda/scene/irda-app-scene-learn-enter-name.cpp +++ b/applications/irda/scene/irda-app-scene-learn-enter-name.cpp @@ -13,7 +13,7 @@ void IrdaAppSceneLearnEnterName::on_enter(IrdaApp* app) { 0, "%.4s_%0*lX", irda_get_protocol_name(message->protocol), - irda_get_protocol_command_length(message->protocol), + ROUND_UP_TO(irda_get_protocol_command_length(message->protocol), 4), message->command); } else { auto raw_signal = signal.get_raw_signal(); diff --git a/applications/irda/scene/irda-app-scene-learn-success.cpp b/applications/irda/scene/irda-app-scene-learn-success.cpp index 8fa0c87b..030ca0e3 100644 --- a/applications/irda/scene/irda-app-scene-learn-success.cpp +++ b/applications/irda/scene/irda-app-scene-learn-success.cpp @@ -27,9 +27,9 @@ void IrdaAppSceneLearnSuccess::on_enter(IrdaApp* app) { app->set_text_store( 1, "A: 0x%0*lX\nC: 0x%0*lX\n", - irda_get_protocol_address_length(message->protocol), + ROUND_UP_TO(irda_get_protocol_address_length(message->protocol), 4), message->address, - irda_get_protocol_command_length(message->protocol), + ROUND_UP_TO(irda_get_protocol_command_length(message->protocol), 4), message->command); dialog_ex_set_header(dialog_ex, app->get_text_store(0), 95, 10, AlignCenter, AlignCenter); dialog_ex_set_text(dialog_ex, app->get_text_store(1), 75, 23, AlignLeft, AlignTop); diff --git a/applications/irda_monitor/irda_monitor.c b/applications/irda_monitor/irda_monitor.c index 3a0a342a..8057a74d 100644 --- a/applications/irda_monitor/irda_monitor.c +++ b/applications/irda_monitor/irda_monitor.c @@ -64,18 +64,18 @@ static void signal_received_callback(void* context, IrdaWorkerSignal* received_s sizeof(irda_monitor->display_text), "%s\nA:0x%0*lX\nC:0x%0*lX\n%s\n", irda_get_protocol_name(message->protocol), - irda_get_protocol_address_length(message->protocol), + ROUND_UP_TO(irda_get_protocol_address_length(message->protocol), 4), message->address, - irda_get_protocol_command_length(message->protocol), + ROUND_UP_TO(irda_get_protocol_command_length(message->protocol), 4), message->command, message->repeat ? " R" : ""); view_port_update(irda_monitor->view_port); printf( "== %s, A:0x%0*lX, C:0x%0*lX%s ==\r\n", irda_get_protocol_name(message->protocol), - irda_get_protocol_address_length(message->protocol), + ROUND_UP_TO(irda_get_protocol_address_length(message->protocol), 4), message->address, - irda_get_protocol_command_length(message->protocol), + ROUND_UP_TO(irda_get_protocol_command_length(message->protocol), 4), message->command, message->repeat ? " R" : ""); } else { diff --git a/applications/tests/irda_decoder_encoder/irda_decoder_encoder_test.c b/applications/tests/irda_decoder_encoder/irda_decoder_encoder_test.c index 66ec689d..55403b95 100644 --- a/applications/tests/irda_decoder_encoder/irda_decoder_encoder_test.c +++ b/applications/tests/irda_decoder_encoder/irda_decoder_encoder_test.c @@ -7,6 +7,7 @@ #include "test_data/irda_samsung_test_data.srcdata" #include "test_data/irda_rc6_test_data.srcdata" #include "test_data/irda_rc5_test_data.srcdata" +#include "test_data/irda_sirc_test_data.srcdata" #define RUN_ENCODER(data, expected) \ run_encoder((data), COUNT_OF(data), (expected), COUNT_OF(expected)) @@ -14,6 +15,8 @@ #define RUN_DECODER(data, expected) \ run_decoder((data), COUNT_OF(data), (expected), COUNT_OF(expected)) +#define RUN_ENCODER_DECODER(data) run_encoder_decoder((data), COUNT_OF(data)) + static IrdaDecoderHandler* decoder_handler; static IrdaEncoderHandler* encoder_handler; @@ -33,27 +36,44 @@ static void compare_message_results( mu_check(message_decoded->protocol == message_expected->protocol); mu_check(message_decoded->command == message_expected->command); mu_check(message_decoded->address == message_expected->address); - mu_check(message_decoded->repeat == message_expected->repeat); + if((message_expected->protocol == IrdaProtocolSIRC) || + (message_expected->protocol == IrdaProtocolSIRC15) || + (message_expected->protocol == IrdaProtocolSIRC20)) { + mu_check(message_decoded->repeat == false); + } else { + mu_check(message_decoded->repeat == message_expected->repeat); + } } -static void - run_encoder_fill_array(IrdaEncoderHandler* handler, uint32_t* timings, uint32_t* timings_len) { +/* Encodes signal and merges same levels (high+high, low+low) */ +static void run_encoder_fill_array( + IrdaEncoderHandler* handler, + uint32_t* timings, + uint32_t* timings_len, + bool* start_level) { uint32_t duration = 0; - bool level = false; // start from space + bool level = false; bool level_read; IrdaStatus status = IrdaStatusError; int i = 0; + bool first = true; while(1) { status = irda_encode(handler, &duration, &level_read); - if(level_read != level) { - level = level_read; + if(first) { + if(start_level) *start_level = level_read; + first = false; + timings[0] = 0; + } else if(level_read != level) { ++i; + furi_assert(i < *timings_len); + timings[i] = 0; } + level = level_read; timings[i] += duration; + furi_assert((status == IrdaStatusOk) || (status == IrdaStatusDone)); if(status == IrdaStatusDone) break; - furi_assert(i < *timings_len); } *timings_len = i + 1; @@ -66,8 +86,9 @@ static void run_encoder( const uint32_t expected_timings[], uint32_t expected_timings_len) { uint32_t* timings = 0; - uint32_t timings_len = 0; + uint32_t timings_len = 200; uint32_t j = 0; + timings = furi_alloc(sizeof(uint32_t) * timings_len); for(uint32_t message_counter = 0; message_counter < input_messages_len; ++message_counter) { const IrdaMessage* message = &input_messages[message_counter]; @@ -76,44 +97,51 @@ static void run_encoder( } timings_len = 200; - timings = furi_alloc(sizeof(uint32_t) * timings_len); - run_encoder_fill_array(encoder_handler, timings, &timings_len); + run_encoder_fill_array(encoder_handler, timings, &timings_len, NULL); furi_assert(timings_len <= 200); for(int i = 0; i < timings_len; ++i, ++j) { - mu_check(MATCH_BIT_TIMING(timings[i], expected_timings[j], 120)); + mu_check(MATCH_TIMING(timings[i], expected_timings[j], 120)); mu_assert(j < expected_timings_len, "encoded more timings than expected"); } - - free(timings); } + free(timings); mu_assert(j == expected_timings_len, "encoded less timings than expected"); } static void run_encoder_decoder(const IrdaMessage input_messages[], uint32_t input_messages_len) { uint32_t* timings = 0; - uint32_t timings_len = 0; + uint32_t timings_len = 200; bool level = false; + timings = furi_alloc(sizeof(uint32_t) * timings_len); for(uint32_t message_counter = 0; message_counter < input_messages_len; ++message_counter) { const IrdaMessage* message_encoded = &input_messages[message_counter]; if(!message_encoded->repeat) { irda_reset_encoder(encoder_handler, message_encoded); - level = false; } timings_len = 200; - timings = furi_alloc(sizeof(uint32_t) * timings_len); - run_encoder_fill_array(encoder_handler, timings, &timings_len); + run_encoder_fill_array(encoder_handler, timings, &timings_len, &level); furi_assert(timings_len <= 200); const IrdaMessage* message_decoded = 0; for(int i = 0; i < timings_len; ++i) { message_decoded = irda_decode(decoder_handler, level, timings[i]); - if(i < timings_len - 1) + if((i == timings_len - 2) && level && message_decoded) { + /* In case we end with space timing - message can be decoded at last mark. + * Exception - SIRC protocol, which has variable message length (12/15/20), + * and decoder recognizes protocol by silence time before next message + * or by timeout (irda_check_decoder_ready()). */ + break; + } else if(i < timings_len - 1) { mu_check(!message_decoded); - else + } else { + if(!message_decoded) { + message_decoded = irda_check_decoder_ready(decoder_handler); + } mu_check(message_decoded); + } level = !level; } if(message_decoded) { @@ -121,9 +149,8 @@ static void run_encoder_decoder(const IrdaMessage input_messages[], uint32_t inp } else { mu_check(0); } - - free(timings); } + free(timings); } static void run_decoder( @@ -131,21 +158,49 @@ static void run_decoder( uint32_t input_delays_len, const IrdaMessage* message_expected, uint32_t message_expected_len) { - const IrdaMessage* message_decoded = 0; + IrdaMessage message_decoded_check_local; bool level = 0; uint32_t message_counter = 0; + const IrdaMessage* message_decoded = 0; for(uint32_t i = 0; i < input_delays_len; ++i) { + const IrdaMessage* message_decoded_check = 0; + + if(input_delays[i] > IRDA_RAW_RX_TIMING_DELAY_US) { + message_decoded_check = irda_check_decoder_ready(decoder_handler); + if(message_decoded_check) { + /* irda_decode() can reset message, but we have to call irda_decode() to perform real + * simulation: irda_check() by timeout, then irda_decode() when meet edge */ + message_decoded_check_local = *message_decoded_check; + message_decoded_check = &message_decoded_check_local; + } + } + message_decoded = irda_decode(decoder_handler, level, input_delays[i]); - if(message_decoded) { + + if(message_decoded_check || message_decoded) { + mu_assert( + !(message_decoded_check && message_decoded), + "both messages decoded: check_ready() and irda_decode()"); + + if(message_decoded_check) { + message_decoded = message_decoded_check; + } + mu_assert(message_counter < message_expected_len, "decoded more than expected"); - if(message_counter >= message_expected_len) break; compare_message_results(message_decoded, &message_expected[message_counter]); + ++message_counter; } level = !level; } + message_decoded = irda_check_decoder_ready(decoder_handler); + if(message_decoded) { + compare_message_results(message_decoded, &message_expected[message_counter]); + ++message_counter; + } + mu_assert(message_counter == message_expected_len, "decoded less than expected"); } @@ -155,6 +210,7 @@ MU_TEST(test_decoder_samsung32) { MU_TEST(test_mix) { RUN_DECODER(test_decoder_rc5_input2, test_decoder_rc5_expected2); + RUN_DECODER(test_decoder_sirc_input1, test_decoder_sirc_expected1); RUN_DECODER(test_decoder_necext_input1, test_decoder_necext_expected1); // can use encoder data for decoding, but can't do opposite RUN_DECODER(test_encoder_rc6_expected1, test_encoder_rc6_input1); @@ -162,12 +218,16 @@ MU_TEST(test_mix) { RUN_DECODER(test_decoder_rc6_input1, test_decoder_rc6_expected1); RUN_DECODER(test_decoder_samsung32_input1, test_decoder_samsung32_expected1); RUN_DECODER(test_decoder_rc5_input1, test_decoder_rc5_expected1); + RUN_DECODER(test_decoder_sirc_input2, test_decoder_sirc_expected2); RUN_DECODER(test_decoder_necext_input1, test_decoder_necext_expected1); + RUN_DECODER(test_decoder_sirc_input4, test_decoder_sirc_expected4); RUN_DECODER(test_decoder_nec_input2, test_decoder_nec_expected2); RUN_DECODER(test_decoder_rc6_input1, test_decoder_rc6_expected1); RUN_DECODER(test_decoder_necext_input1, test_decoder_necext_expected1); + RUN_DECODER(test_decoder_sirc_input5, test_decoder_sirc_expected5); RUN_DECODER(test_decoder_rc5_input5, test_decoder_rc5_expected5); RUN_DECODER(test_decoder_samsung32_input1, test_decoder_samsung32_expected1); + RUN_DECODER(test_decoder_sirc_input3, test_decoder_sirc_expected3); } MU_TEST(test_decoder_nec1) { @@ -191,6 +251,20 @@ MU_TEST(test_decoder_necext1) { RUN_DECODER(test_decoder_necext_input1, test_decoder_necext_expected1); } +MU_TEST(test_encoder_sirc) { + RUN_ENCODER(test_encoder_sirc_input1, test_encoder_sirc_expected1); + RUN_ENCODER(test_encoder_sirc_input2, test_encoder_sirc_expected2); +} + +MU_TEST(test_decoder_sirc) { + RUN_DECODER(test_decoder_sirc_input3, test_decoder_sirc_expected3); + RUN_DECODER(test_decoder_sirc_input1, test_decoder_sirc_expected1); + RUN_DECODER(test_decoder_sirc_input2, test_decoder_sirc_expected2); + RUN_DECODER(test_decoder_sirc_input4, test_decoder_sirc_expected4); + RUN_DECODER(test_decoder_sirc_input5, test_decoder_sirc_expected5); + RUN_ENCODER_DECODER(test_sirc); +} + MU_TEST(test_decoder_rc5) { RUN_DECODER(test_decoder_rc5x_input1, test_decoder_rc5x_expected1); RUN_DECODER(test_decoder_rc5_input1, test_decoder_rc5_expected1); @@ -219,16 +293,19 @@ MU_TEST(test_encoder_rc6) { } MU_TEST(test_encoder_decoder_all) { - run_encoder_decoder(test_nec_all, COUNT_OF(test_nec_all)); - run_encoder_decoder(test_necext_all, COUNT_OF(test_necext_all)); - run_encoder_decoder(test_samsung32_all, COUNT_OF(test_samsung32_all)); - run_encoder_decoder(test_rc6_all, COUNT_OF(test_rc6_all)); - run_encoder_decoder(test_rc5_all, COUNT_OF(test_rc5_all)); + RUN_ENCODER_DECODER(test_nec); + RUN_ENCODER_DECODER(test_necext); + RUN_ENCODER_DECODER(test_samsung32); + RUN_ENCODER_DECODER(test_rc6); + RUN_ENCODER_DECODER(test_rc5); + RUN_ENCODER_DECODER(test_sirc); } MU_TEST_SUITE(test_irda_decoder_encoder) { MU_SUITE_CONFIGURE(&test_setup, &test_teardown); + MU_RUN_TEST(test_encoder_sirc); + MU_RUN_TEST(test_decoder_sirc); MU_RUN_TEST(test_encoder_rc5x); MU_RUN_TEST(test_encoder_rc5); MU_RUN_TEST(test_decoder_rc5); diff --git a/applications/tests/irda_decoder_encoder/test_data/irda_nec_test_data.srcdata b/applications/tests/irda_decoder_encoder/test_data/irda_nec_test_data.srcdata index ce7fcbea..9b4dae7e 100644 --- a/applications/tests/irda_decoder_encoder/test_data/irda_nec_test_data.srcdata +++ b/applications/tests/irda_decoder_encoder/test_data/irda_nec_test_data.srcdata @@ -178,7 +178,7 @@ const IrdaMessage test_decoder_nec_expected2[] = { {IrdaProtocolNEC, 0x00, 0x0A, true}, }; -const IrdaMessage test_nec_all[] = { +const IrdaMessage test_nec[] = { {IrdaProtocolNEC, 0x00, 0x00, false}, {IrdaProtocolNEC, 0x01, 0x00, false}, {IrdaProtocolNEC, 0x01, 0x80, false}, diff --git a/applications/tests/irda_decoder_encoder/test_data/irda_necext_test_data.srcdata b/applications/tests/irda_decoder_encoder/test_data/irda_necext_test_data.srcdata index 211cd0b9..66c4f947 100644 --- a/applications/tests/irda_decoder_encoder/test_data/irda_necext_test_data.srcdata +++ b/applications/tests/irda_decoder_encoder/test_data/irda_necext_test_data.srcdata @@ -223,7 +223,7 @@ const IrdaMessage test_decoder_necext_expected1[] = { -const IrdaMessage test_necext_all[] = { +const IrdaMessage test_necext[] = { {IrdaProtocolNECext, 0x0000, 0x00, false}, {IrdaProtocolNECext, 0x0001, 0x00, false}, {IrdaProtocolNECext, 0x0001, 0x80, false}, diff --git a/applications/tests/irda_decoder_encoder/test_data/irda_rc5_test_data.srcdata b/applications/tests/irda_decoder_encoder/test_data/irda_rc5_test_data.srcdata index 4cd39742..4dd43bed 100644 --- a/applications/tests/irda_decoder_encoder/test_data/irda_rc5_test_data.srcdata +++ b/applications/tests/irda_decoder_encoder/test_data/irda_rc5_test_data.srcdata @@ -128,7 +128,7 @@ const IrdaMessage test_decoder_rc5_expected_all_repeats[] = { }; -const IrdaMessage test_rc5_all[] = { +const IrdaMessage test_rc5[] = { {IrdaProtocolRC5, 0x1F, 0x3F, false}, {IrdaProtocolRC5, 0x00, 0x00, false}, {IrdaProtocolRC5, 0x10, 0x01, false}, diff --git a/applications/tests/irda_decoder_encoder/test_data/irda_rc6_test_data.srcdata b/applications/tests/irda_decoder_encoder/test_data/irda_rc6_test_data.srcdata index ea764d43..4c3fadca 100644 --- a/applications/tests/irda_decoder_encoder/test_data/irda_rc6_test_data.srcdata +++ b/applications/tests/irda_decoder_encoder/test_data/irda_rc6_test_data.srcdata @@ -65,7 +65,7 @@ const uint32_t test_encoder_rc6_expected1[] = { }; -const IrdaMessage test_rc6_all[] = { +const IrdaMessage test_rc6[] = { {IrdaProtocolRC6, 0x00, 0x00, false}, // t 0 {IrdaProtocolRC6, 0x80, 0x00, false}, // t 1 {IrdaProtocolRC6, 0x80, 0x01, false}, // t 0 diff --git a/applications/tests/irda_decoder_encoder/test_data/irda_samsung_test_data.srcdata b/applications/tests/irda_decoder_encoder/test_data/irda_samsung_test_data.srcdata index 31f7b549..077a4a94 100644 --- a/applications/tests/irda_decoder_encoder/test_data/irda_samsung_test_data.srcdata +++ b/applications/tests/irda_decoder_encoder/test_data/irda_samsung_test_data.srcdata @@ -221,7 +221,7 @@ const IrdaMessage test_decoder_samsung32_expected1[] = { {IrdaProtocolSamsung32, 0x0E, 0x01, false}, {IrdaProtocolSamsung32, 0x0E, 0x01, true}, }; -const IrdaMessage test_samsung32_all[] = { +const IrdaMessage test_samsung32[] = { {IrdaProtocolSamsung32, 0x00, 0x00, false}, {IrdaProtocolSamsung32, 0x01, 0x00, false}, {IrdaProtocolSamsung32, 0x01, 0x80, false}, diff --git a/applications/tests/irda_decoder_encoder/test_data/irda_sirc_test_data.srcdata b/applications/tests/irda_decoder_encoder/test_data/irda_sirc_test_data.srcdata new file mode 100644 index 00000000..2968aaca --- /dev/null +++ b/applications/tests/irda_decoder_encoder/test_data/irda_sirc_test_data.srcdata @@ -0,0 +1,485 @@ +const uint32_t test_decoder_sirc_input1[] = { /* 121 timings */ +1000000, 2420, 608, 1194, 608, 596, 604, 1198, 603, 591, 610, 1192, 609, 596, 605, 599, 601, 593, 607, 597, 604, 590, 610, 594, 606, 1196, + 25957, 2426, 603, 1199, 603, 591, 610, 1192, 610, 594, 606, 1196, 606, 599, 603, 591, 609, 595, 606, 598, 602, 592, 609, 596, 605, 1197, + 25960, 2423, 606, 1196, 606, 599, 602, 1200, 602, 592, 609, 1193, 609, 596, 606, 599, 602, 592, 609, 595, 605, 600, 601, 593, 608, 1194, +1000000, 2422, 607, 1195, 607, 598, 603, 1199, 604, 590, 610, 1192, 610, 594, 606, 598, 603, 591, 609, 595, 605, 600, 601, 593, 607, 1195, + 25955, 2418, 610, 1192, 610, 594, 606, 1196, 606, 599, 602, 1200, 602, 592, 608, 596, 604, 590, 611, 594, 607, 597, 603, 591, 609, 1193, + 25959, 2424, 604, 1198, 604, 590, 610, 1192, 610, 594, 606, 1196, 605, 600, 601, 593, 608, 597, 603, 591, 610, 595, 606, 598, 602, 1200, +1000000, 2424, 605, 599, 601, 593, 607, 597, 603, 591, 610, 594, 606, 1196, 606, 1196, 605, 600, 601, 593, 608, 597, 604, 590, 611, 1191, + 26586, 2425, 604, 590, 611, 593, 607, 598, 603, 591, 610, 595, 606, 1196, 606, 1196, 606, 599, 602, 592, 608, 596, 604, 590, 611, 1191, + 26586, 2424, 604, 590, 611, 593, 607, 598, 603, 591, 609, 595, 605, 1197, 605, 1197, 604, 590, 611, 593, 607, 597, 603, 591, 610, 1192, +1000000, 2424, 604, 1198, 604, 590, 611, 1191, 610, 594, 606, 598, 603, 1199, 602, 1200, 602, 592, 609, 595, 605, 600, 601, 593, 608, 1194, + 25386, 2419, 610, 1192, 610, 594, 606, 1196, 607, 597, 603, 591, 610, 1192, 609, 1193, 610, 594, 606, 598, 602, 592, 609, 595, 605, 1197, + 25385, 2421, 608, 1194, 608, 596, 605, 1197, 605, 599, 601, 593, 608, 1194, 608, 1194, 608, 596, 605, 589, 611, 594, 607, 597, 604, 1198, +1000000, 2426, 603, 1199, 602, 1200, 602, 1200, 602, 592, 608, 1194, 608, 596, 604, 590, 611, 594, 607, 597, 603, 591, 610, 594, 606, 1196, 605, 600, 601, 593, 608, 596, 604, 590, 610, 594, 607, 1195, 606, 598, 603, 591, + 15078, 2419, 610, 1192, 610, 1192, 610, 1192, 610, 594, 606, 1196, 605, 600, 601, 593, 608, 597, 604, 590, 610, 595, 606, 598, 602, 1200, 602, 592, 608, 597, 604, 590, 611, 594, 607, 597, 603, 1199, 603, 591, 609, 595, + 15075, 2422, 607, 1195, 607, 1195, 607, 1195, 607, 597, 604, 1198, 603, 591, 610, 594, 606, 598, 603, 591, 609, 595, 605, 600, 601, 1191, 611, 594, 607, 597, 603, 591, 610, 594, 606, 598, 602, 1200, 602, 592, 608, 596, +1000000, 2422, 607, 1195, 606, 599, 602, 592, 608, 596, 604, 590, 610, 1192, 610, 594, 606, 599, 602, 592, 608, 596, 604, 590, 610, 1192, + 26585, 2426, 602, 1200, 602, 592, 608, 596, 604, 590, 611, 594, 607, 1195, 607, 598, 603, 591, 610, 594, 606, 598, 603, 591, 609, 1193, + 26586, 2425, 604, 1198, 603, 591, 610, 594, 606, 598, 602, 592, 609, 1193, 608, 597, 605, 600, 601, 593, 607, 597, 604, 590, 610, 1192, +1000000, 2418, 610, 594, 606, 598, 603, 1199, 603, 1199, 603, 1199, 603, 1199, 603, 1199, 603, 591, 610, 1192, 610, 594, 606, 1196, 606, 1196, 606, 1196, 606, 598, 602, 592, 609, 1193, 609, 1193, 609, 1193, 609, 595, 605, 599, + 11557, 2418, 611, 594, 607, 598, 603, 1199, 603, 1199, 603, 1199, 602, 1200, 602, 1200, 601, 593, 608, 1194, 607, 597, 604, 1198, 603, 1199, 603, 1199, 602, 592, 608, 596, 604, 1198, 603, 1199, 603, 1199, 603, 591, 609, 595, + 11561, 2424, 604, 590, 610, 594, 607, 1195, 606, 1196, 606, 1196, 606, 1196, 606, 1196, 605, 600, 601, 1191, 611, 594, 607, 1195, 607, 1195, 607, 1195, 607, 597, 603, 591, 610, 1192, 610, 1192, 610, 1192, 610, 594, 606, 598, +1000000, 2424, 604, 590, 611, 594, 607, 1195, 607, 1195, 607, 1195, 607, 1195, 607, 1195, 606, 598, 603, 1199, 602, 592, 609, 1193, 608, 1194, 608, 1194, 608, 596, 604, 590, 611, 1191, 611, 1191, 611, 1191, 611, 594, 607, 598, + 11559, 2427, 602, 592, 608, 596, 605, 1197, 604, 1198, 604, 1198, 604, 1198, 604, 1198, 604, 590, 610, 1192, 610, 595, 606, 1196, 606, 1196, 606, 1196, 606, 599, 603, 591, 609, 1193, 609, 1193, 609, 1193, 608, 597, 605, 589, + 11567, 2418, 610, 595, 607, 597, 603, 1199, 603, 1199, 602, 1200, 602, 1200, 601, 1201, 601, 593, 608, 1194, 607, 598, 603, 1199, 603, 1199, 603, 1199, 603, 591, 609, 595, 605, 1197, 605, 1197, 605, 1197, 604, 590, 611, 594, +1000000, 2421, 608, 597, 604, 590, 610, 1192, 610, 1192, 609, 1193, 609, 1193, 609, 1193, 608, 596, 605, 1197, 604, 590, 610, 1192, 611, 1191, 610, 1192, 610, 594, 606, 598, 603, 1199, 603, 1199, 602, 1200, 602, 592, 608, 596, + 11561, 2424, 604, 590, 610, 594, 606, 1196, 606, 1196, 606, 1196, 606, 1196, 605, 1197, 605, 600, 601, 1201, 601, 593, 607, 1195, 607, 1195, 606, 1196, 606, 598, 602, 592, 608, 1194, 608, 1194, 607, 1195, 607, 597, 603, 591, + 11564, 2421, 607, 597, 604, 590, 610, 1192, 610, 1192, 610, 1192, 610, 1192, 610, 1192, 609, 595, 606, 1196, 606, 598, 602, 1200, 601, 1201, 601, 1201, 601, 593, 607, 598, 603, 1199, 603, 1199, 602, 1200, 602, 592, 608, 596, +1000000, 2420, 609, 595, 606, 598, 602, 1200, 602, 1200, 602, 1200, 602, 1200, 602, 1200, 602, 592, 608, 1194, 608, 596, 604, 1198, 603, 1199, 603, 1199, 603, 591, 610, 594, 606, 1196, 606, 1196, 606, 1196, 606, 598, 602, 592, + 11565, 2420, 609, 595, 605, 600, 601, 1201, 601, 1201, 601, 1201, 601, 1201, 601, 1201, 601, 593, 607, 1195, 607, 597, 603, 1199, 603, 1199, 603, 1199, 603, 591, 609, 595, 605, 1197, 605, 1197, 605, 1197, 605, 599, 601, 593, + 11563, 2422, 607, 597, 603, 591, 609, 1193, 609, 1193, 608, 1194, 608, 1194, 608, 1194, 582, 623, 603, 1199, 603, 591, 610, 1202, 599, 1203, 599, 1203, 599, 595, 581, 623, 577, 1225, 601, 1201, 601, 1201, 601, 593, 582, 623, +1000000, 2425, 602, 1200, 602, 1200, 602, 592, 608, 1194, 608, 1194, 607, 1195, 607, 1195, 607, 597, 603, 1199, 602, 592, 609, 1193, 608, 1194, 608, 1194, 607, 597, 603, 601, 575, 1227, 599, 1203, 599, 1203, 573, 621, 580, 625, + 10931, 2426, 578, 1224, 578, 1224, 578, 616, 585, 1217, 585, 1217, 585, 1217, 585, 1217, 585, 620, 580, 1222, 580, 624, 577, 1225, 577, 1225, 577, 1225, 577, 617, 583, 622, 580, 1222, 580, 1222, 579, 1223, 579, 625, 576, 618, + 10936, 2421, 583, 1219, 583, 1219, 582, 622, 579, 1223, 578, 1224, 578, 1224, 578, 1224, 578, 616, 584, 1218, 584, 621, 580, 1222, 579, 1223, 579, 1223, 579, 625, 576, 618, 583, 1219, 582, 1220, 582, 1220, 582, 622, 578, 616, +1000000, 2419, 584, 620, 580, 1222, 580, 624, 576, 1226, 576, 1226, 576, 1226, 576, 1226, 576, 618, 582, 1220, 582, 622, 579, 1223, 578, 1224, 579, 1223, 578, 616, 585, 619, 581, 1221, 581, 1221, 581, 1221, 580, 624, 576, 618, + 11563, 2422, 582, 622, 579, 1223, 578, 616, 585, 1217, 585, 1217, 584, 1218, 584, 1218, 583, 622, 579, 1223, 579, 625, 575, 1216, 585, 1217, 585, 1217, 585, 619, 581, 623, 577, 1225, 577, 1225, 577, 1225, 576, 618, 583, 621, + 11558, 2427, 577, 617, 584, 1218, 583, 621, 579, 1223, 579, 1223, 578, 1224, 578, 1224, 578, 647, 553, 1249, 553, 651, 549, 1253, 548, 1254, 549, 1253, 549, 645, 555, 649, 551, 1251, 551, 1251, 551, 1251, 550, 654, 546, 648, +1000000, 2456, 548, 646, 554, 650, 551, 653, 547, 1255, 547, 1255, 547, 1255, 547, 1255, 547, 647, 554, 1248, 554, 650, 551, 1251, 551, 1251, 551, 1251, 551, 653, 547, 647, 554, 1248, 554, 1248, 554, 1248, 553, 651, 550, 644, + 12112, 2449, 555, 649, 551, 654, 547, 647, 554, 1248, 554, 1248, 553, 1249, 553, 1249, 553, 651, 549, 1253, 549, 645, 555, 1247, 555, 1247, 555, 1247, 554, 650, 550, 655, 547, 1244, 557, 1224, 578, 1224, 579, 615, 585, 619, + 12139, 2423, 580, 624, 576, 618, 582, 622, 578, 1224, 578, 1224, 578, 1224, 578, 1224, 578, 616, 584, 1218, 584, 620, 580, 1222, 580, 1222, 581, 1221, 580, 624, 577, 617, 584, 1218, 584, 1218, 584, 1218, 584, 620, 581, 623, +1000000, 2422, 582, 1220, 581, 623, 578, 616, 584, 1218, 584, 1218, 584, 1218, 584, 1218, 584, 620, 580, 1222, 580, 624, 576, 1226, 577, 1225, 576, 1226, 576, 618, 583, 622, 579, 1223, 578, 1224, 577, 1225, 577, 617, 585, 619, + 11559, 2426, 577, 1225, 577, 617, 583, 621, 579, 1223, 579, 1223, 578, 1224, 578, 1224, 578, 616, 584, 1218, 584, 620, 580, 1222, 580, 1222, 579, 1223, 579, 625, 575, 650, 550, 1252, 550, 1252, 549, 1253, 549, 645, 556, 648, + 11531, 2453, 549, 1253, 548, 646, 555, 649, 551, 1251, 551, 1251, 550, 1252, 549, 1253, 549, 645, 556, 1246, 555, 649, 552, 1219, 582, 1220, 582, 1220, 582, 622, 578, 616, 585, 1217, 584, 1218, 584, 1218, 584, 620, 581, 623, +1000000, 2428, 576, 618, 582, 1220, 583, 622, 579, 1223, 578, 1224, 578, 1224, 578, 1224, 578, 616, 585, 1217, 585, 619, 582, 1220, 582, 1220, 582, 1220, 582, 622, 578, 616, 585, 1217, 585, 1217, 584, 1218, 584, 620, 581, 623, + 11557, 2427, 577, 617, 584, 1218, 583, 621, 580, 1222, 580, 1222, 580, 1222, 580, 1222, 580, 624, 576, 1246, 555, 649, 552, 1250, 552, 1250, 551, 1251, 551, 653, 548, 646, 554, 1248, 555, 1247, 555, 1247, 555, 649, 551, 653, + 11528, 2447, 556, 648, 552, 1250, 552, 653, 548, 1254, 548, 1254, 547, 1245, 557, 1245, 557, 647, 553, 1249, 552, 652, 549, 1253, 548, 1254, 548, 1254, 548, 646, 555, 649, 551, 1251, 551, 1251, 551, 1251, 551, 643, 557, 647, +1000000, 2418, 610, 594, 606, 598, 603, 1199, 603, 1199, 602, 1200, 602, 1200, 602, 1200, 602, 592, 608, 1194, 608, 596, 604, 1198, 604, 1198, 604, 1198, 603, 591, 610, 594, 606, 1196, 606, 1196, 605, 1197, 605, 599, 601, 593, + 11563, 2422, 606, 598, 602, 592, 608, 1194, 608, 1194, 608, 1194, 607, 1195, 607, 1195, 607, 597, 603, 1199, 603, 591, 609, 1193, 609, 1193, 609, 1193, 608, 596, 605, 599, 601, 1201, 600, 1191, 611, 1191, 611, 593, 606, 598, + 11558, 2427, 601, 593, 607, 597, 603, 1199, 603, 1199, 603, 1199, 602, 1200, 602, 1200, 601, 593, 607, 1195, 607, 597, 603, 1199, 603, 1199, 602, 1200, 602, 592, 608, 596, 604, 1198, 604, 1198, 604, 1198, 603, 591, 609, 595, +1000000, 2424, 605, 1197, 604, 600, 600, 1191, 610, 1192, 610, 1192, 610, 1192, 609, 1193, 609, 595, 605, 1197, 606, 598, 602, 1200, 602, 1200, 601, 1201, 601, 593, 607, 597, 603, 1199, 603, 1199, 603, 1199, 603, 591, 609, 595, + 10937, 2420, 609, 1193, 609, 595, 605, 1197, 605, 1197, 605, 1197, 605, 1197, 605, 1197, 605, 600, 601, 1201, 601, 593, 608, 1194, 608, 1194, 608, 1194, 609, 595, 605, 599, 601, 1201, 601, 1201, 601, 1201, 601, 593, 608, 596, + 10936, 2420, 608, 1194, 608, 596, 604, 1198, 605, 1197, 605, 1197, 605, 1197, 605, 1197, 605, 600, 601, 1201, 601, 593, 607, 1195, 608, 1194, 608, 1194, 608, 596, 604, 600, 600, 1202, 601, 1201, 601, 1201, 601, 593, 607, 597, +1000000, 2420, 609, 1193, 608, 1194, 608, 596, 579, 625, 600, 1202, 600, 1202, 600, 1202, 600, 594, 607, 1195, 607, 597, 603, 1199, 603, 1199, 602, 1200, 602, 592, 609, 595, 605, 1197, 605, 1197, 605, 1197, 604, 600, 600, 594, + 11561, 2423, 605, 1197, 605, 1197, 605, 599, 601, 593, 607, 1195, 607, 1195, 607, 1195, 607, 597, 604, 1198, 603, 591, 610, 1192, 610, 1192, 610, 1192, 610, 594, 607, 597, 603, 1199, 603, 1199, 603, 1199, 603, 591, 610, 594, + 11563, 2421, 608, 1194, 608, 1194, 608, 596, 605, 599, 601, 1201, 602, 1200, 602, 1200, 602, 592, 609, 1193, 609, 595, 605, 1197, 606, 1196, 606, 1196, 606, 598, 602, 592, 609, 1193, 609, 1193, 610, 1192, 610, 594, 607, 597, +1000000, 2428, 576, 1226, 600, 1192, 610, 594, 606, 598, 602, 1200, 602, 592, 609, 595, 605, 600, 601, 593, 607, 597, 603, 591, 609, 1193, + 25955, 2427, 601, 1190, 610, 1192, 610, 594, 606, 598, 602, 1200, 601, 593, 607, 597, 603, 591, 610, 594, 606, 598, 602, 592, 608, 1194, + 25957, 2425, 604, 1198, 603, 1199, 603, 591, 609, 595, 605, 1197, 605, 599, 601, 593, 607, 598, 603, 591, 610, 594, 606, 598, 602, 1200, + 25952, 2420, 608, 1194, 608, 1194, 608, 596, 604, 601, 600, 1191, 610, 594, 606, 598, 603, 591, 609, 595, 605, 599, 601, 593, 608, 1194, +1000000, 2421, 607, 597, 603, 1199, 603, 591, 610, 594, 606, 1196, 605, 600, 576, 618, 583, 621, 604, 601, 575, 619, 606, 598, 603, 1199, + 26576, 2424, 605, 600, 576, 1226, 601, 593, 608, 596, 604, 1198, 604, 600, 600, 594, 607, 597, 603, 591, 609, 595, 606, 598, 602, 1200, + 26579, 2420, 583, 621, 605, 1197, 604, 600, 601, 593, 607, 1195, 607, 597, 604, 590, 610, 594, 607, 597, 603, 591, 610, 594, 606, 1196, + 26584, 2426, 603, 591, 609, 1193, 609, 595, 605, 599, 601, 1201, 601, 593, 607, 597, 603, 591, 610, 594, 606, 598, 603, 591, 609, 1193, +1000000, 2418, 610, 594, 606, 598, 602, 592, 609, 595, 605, 1197, 605, 1197, 605, 600, 602, 592, 608, 1194, 608, 596, 605, 1197, 605, 1197, 604, 1198, 604, 600, 601, 593, 607, 1195, 607, 1195, 607, 1195, 607, 597, 603, 591, + 13368, 2419, 610, 594, 606, 598, 602, 592, 608, 596, 605, 1197, 604, 1198, 604, 600, 601, 593, 607, 1195, 607, 597, 603, 1199, 603, 1199, 603, 1199, 603, 591, 609, 595, 605, 1197, 605, 1197, 605, 1197, 604, 601, 600, 594, + 13362, 2425, 604, 601, 600, 594, 607, 597, 603, 591, 610, 1192, 610, 1192, 610, 594, 606, 598, 603, 1199, 602, 592, 609, 1193, 609, 1193, 608, 1194, 608, 596, 604, 601, 600, 1191, 610, 1192, 610, 1192, 610, 594, 607, 597, +1000000, 2427, 601, 1201, 601, 593, 582, 623, 603, 1199, 578, 1224, 603, 1199, 577, 617, 584, 620, 605, 1197, 605, 600, 601, 1201, 601, 1201, 601, 1201, 601, 593, 582, 622, 603, 1199, 603, 1199, 578, 1224, 603, 591, 610, 594, + 12139, 2423, 605, 1197, 605, 600, 601, 593, 608, 1194, 608, 1194, 607, 1195, 607, 597, 604, 600, 601, 1201, 601, 593, 607, 1195, 608, 1194, 608, 1194, 583, 622, 604, 601, 600, 1202, 575, 1227, 601, 1201, 576, 618, 607, 597, + 12137, 2424, 604, 1198, 604, 590, 610, 594, 607, 1195, 607, 1195, 607, 1195, 607, 597, 604, 601, 600, 1202, 600, 594, 607, 1195, 606, 1196, 581, 1221, 607, 597, 603, 591, 610, 1202, 600, 1202, 576, 1226, 602, 592, 609, 595, +1000000, 2422, 607, 1195, 607, 597, 603, 591, 585, 619, 606, 1196, 606, 1196, 581, 624, 577, 617, 609, 1193, 584, 621, 605, 1197, 604, 1198, 604, 1198, 604, 590, 610, 595, 581, 1221, 605, 1197, 605, 1197, 605, 599, 601, 593, + 12763, 2427, 603, 1199, 603, 591, 609, 595, 605, 599, 577, 1225, 602, 1200, 601, 593, 583, 622, 604, 1198, 604, 590, 610, 1192, 610, 1192, 610, 1192, 610, 594, 606, 598, 603, 1199, 603, 1199, 603, 1199, 603, 591, 610, 594, + 12763, 2427, 602, 1200, 601, 593, 608, 596, 604, 600, 600, 1202, 601, 1201, 601, 593, 607, 597, 604, 1198, 604, 590, 610, 1192, 610, 1192, 611, 1191, 610, 594, 607, 598, 578, 1224, 603, 1199, 603, 1199, 603, 591, 610, 594, +1000000, 2422, 607, 597, 603, 591, 610, 1192, 610, 594, 606, 1196, 580, 1222, 605, 600, 601, 593, 583, 1219, 608, 596, 579, 1223, 604, 1198, 604, 1198, 604, 590, 610, 594, 606, 1196, 606, 1196, 606, 1196, 606, 599, 602, 592, + 12765, 2425, 603, 591, 610, 594, 606, 1196, 606, 598, 602, 1200, 601, 1201, 601, 593, 582, 623, 604, 1198, 604, 590, 610, 1192, 610, 1192, 609, 1193, 609, 596, 605, 599, 601, 1201, 601, 1201, 601, 1201, 600, 594, 607, 597, + 12758, 2421, 607, 597, 603, 591, 609, 1193, 609, 595, 605, 1197, 605, 1197, 605, 599, 601, 593, 607, 1195, 607, 597, 603, 1199, 603, 1199, 603, 1199, 603, 591, 609, 595, 580, 1222, 605, 1197, 605, 1197, 605, 600, 600, 594, +1000000, 2422, 580, 625, 601, 1201, 601, 593, 608, 596, 604, 1198, 604, 1198, 604, 600, 600, 594, 607, 1195, 607, 597, 603, 1199, 603, 1199, 603, 1199, 578, 616, 609, 595, 606, 1196, 606, 1196, 606, 1196, 581, 624, 602, 592, + 12766, 2424, 605, 599, 601, 1201, 601, 593, 608, 596, 604, 1198, 604, 1198, 579, 625, 601, 593, 608, 1194, 608, 596, 604, 1198, 580, 1222, 605, 1197, 605, 599, 602, 592, 608, 1194, 609, 1193, 609, 1193, 609, 596, 605, 599, + 12759, 2420, 608, 597, 604, 1198, 604, 590, 610, 594, 606, 1196, 606, 1196, 606, 598, 602, 592, 608, 1194, 607, 597, 604, 1198, 603, 1199, 603, 1199, 602, 592, 609, 595, 605, 1197, 605, 1197, 605, 1197, 604, 600, 601, 593, +1000000, 2429, 600, 1202, 575, 1227, 599, 595, 606, 598, 602, 1200, 602, 1200, 602, 592, 609, 595, 605, 1197, 605, 599, 601, 1201, 601, 1201, 601, 1201, 601, 593, 607, 597, 603, 1199, 603, 1199, 603, 1199, 603, 591, 609, 595, + 12136, 2425, 603, 1199, 603, 1199, 603, 591, 609, 595, 605, 1197, 605, 1197, 605, 599, 601, 593, 608, 1194, 608, 596, 604, 1198, 604, 1198, 603, 1199, 603, 591, 609, 595, 606, 1196, 606, 1196, 605, 1197, 605, 599, 601, 593, + 12137, 2424, 604, 1198, 603, 1199, 603, 591, 609, 595, 606, 1196, 605, 1197, 605, 599, 601, 593, 607, 1195, 607, 597, 603, 1199, 603, 1199, 603, 1199, 602, 592, 609, 595, 605, 1197, 605, 1197, 604, 1198, 604, 600, 600, 594, +1000000, 2429, 574, 1228, 573, 1229, 573, 1229, 573, 1229, 573, 621, 581, 624, 577, 617, 583, 622, 580, 1222, 579, 625, 576, 1226, 577, 1225, 576, 1226, 577, 617, 584, 620, 581, 1221, 580, 1222, 579, 1223, 579, 625, 577, 617, + 12142, 2419, 584, 1218, 584, 1218, 583, 1219, 583, 1219, 582, 623, 578, 616, 585, 619, 581, 623, 578, 1224, 577, 617, 584, 1218, 584, 1218, 584, 1218, 584, 620, 580, 624, 576, 1226, 575, 1227, 500, 1353, 523, 620, 582, 622, /* failed, noise pollution 500, 1353 timings */ + 12134, 2427, 576, 1226, 576, 1226, 576, 1226, 576, 1226, 576, 618, 583, 622, 579, 625, 576, 618, 583, 1219, 583, 673, 527, 1223, 579, 1223, 579, 1223, 579, 625, 576, 618, 582, 1220, 582, 1220, 582, 1220, 582, 622, 578, 616, + 12140, 2421, 582, 1220, 581, 1221, 581, 1221, 580, 1222, 580, 624, 576, 618, 582, 622, 578, 616, 585, 1217, 584, 620, 581, 1221, 580, 1222, 580, 1222, 580, 624, 576, 618, 582, 1220, 582, 1220, 582, 1220, 582, 623, 578, 616, +1000000, 2419, 584, 672, 528, 625, 577, 617, 583, 1219, 582, 1220, 581, 1221, 582, 622, 578, 616, 585, 1217, 583, 621, 580, 1222, 580, 1222, 580, 1222, 580, 624, 576, 618, 583, 1219, 583, 1219, 582, 1220, 583, 621, 580, 624, + 12732, 2427, 577, 617, 584, 672, 528, 676, 524, 1226, 576, 1226, 576, 1226, 576, 618, 583, 621, 579, 1223, 579, 625, 575, 1227, 575, 1227, 575, 1227, 575, 671, 529, 675, 526, 1224, 578, 1224, 578, 1224, 578, 616, 585, 619, + 12738, 2421, 583, 621, 580, 624, 576, 618, 582, 1220, 582, 1220, 583, 1219, 583, 621, 579, 625, 576, 1226, 576, 670, 530, 1220, 582, 1220, 582, 1220, 581, 624, 577, 617, 584, 1218, 583, 1219, 583, 1219, 583, 622, 580, 624, +1000000, 2430, 599, 1192, 609, 595, 605, 1197, 580, 624, 601, 1201, 601, 593, 607, 597, 603, 591, 610, 594, 606, 598, 602, 592, 608, 1194, + 25958, 2423, 605, 1197, 604, 600, 575, 1227, 600, 594, 606, 1196, 606, 598, 602, 592, 608, 596, 604, 601, 600, 594, 607, 597, 603, 1199, + 25949, 2422, 607, 1195, 606, 598, 603, 1199, 602, 592, 608, 1194, 608, 596, 604, 600, 601, 593, 607, 597, 604, 600, 600, 594, 607, 1195, + 25958, 2423, 606, 1196, 606, 598, 602, 1200, 602, 592, 608, 1194, 608, 596, 605, 600, 601, 593, 607, 597, 603, 591, 610, 594, 606, 1196, + 25957, 2425, 604, 1198, 603, 591, 610, 1192, 610, 594, 606, 1196, 606, 598, 602, 592, 609, 595, 605, 599, 602, 592, 608, 596, 604, 1198, + 25956, 2426, 604, 1198, 603, 591, 610, 1192, 610, 594, 606, 1196, 606, 598, 602, 592, 608, 597, 605, 599, 601, 593, 607, 597, 603, 1199, + 25952, 2420, 609, 1193, 608, 596, 604, 1198, 604, 590, 610, 1192, 610, 594, 606, 598, 602, 592, 608, 596, 605, 599, 601, 593, 607, 1195, +1000000, 2422, 583, 1219, 608, 596, 605, 1197, 580, 624, 601, 1201, 601, 593, 608, 596, 604, 600, 601, 593, 607, 597, 604, 590, 610, 1202, + 25955, 2427, 603, 1199, 603, 591, 609, 1193, 610, 594, 606, 1196, 607, 597, 603, 591, 609, 595, 606, 598, 602, 592, 609, 595, 605, 1197, + 25957, 2425, 604, 1198, 604, 590, 610, 1192, 610, 594, 581, 1221, 606, 598, 602, 592, 608, 596, 605, 599, 601, 593, 607, 597, 604, 1198, + 25954, 2418, 610, 1192, 610, 594, 606, 1196, 605, 599, 601, 1201, 601, 593, 608, 596, 604, 590, 610, 594, 606, 598, 603, 591, 609, 1193, + 25958, 2424, 604, 1198, 604, 590, 610, 1192, 610, 594, 606, 1196, 606, 598, 602, 592, 609, 595, 605, 600, 601, 593, 607, 597, 603, 1199, + 25953, 2419, 610, 1192, 609, 595, 605, 1197, 605, 600, 601, 1201, 600, 594, 607, 597, 603, 591, 609, 595, 605, 599, 601, 593, 608, 1194, + 25954, 2418, 611, 1191, 610, 594, 606, 1196, 606, 598, 602, 1200, 602, 592, 608, 596, 604, 601, 600, 594, 607, 597, 603, 591, 609, 1193, + 25958, 2424, 605, 1197, 605, 599, 601, 1201, 600, 594, 607, 1195, 607, 597, 603, 591, 609, 596, 605, 599, 602, 592, 608, 596, 605, 1197, + 25954, 2428, 601, 1190, 610, 594, 607, 1195, 606, 598, 602, 1200, 602, 592, 608, 596, 604, 590, 610, 594, 606, 598, 603, 591, 609, 1193, + 25960, 2422, 607, 1195, 606, 598, 602, 1200, 602, 592, 609, 1193, 609, 595, 605, 599, 601, 593, 607, 597, 604, 590, 610, 594, 606, 1196, + 25957, 2424, 605, 1197, 604, 600, 600, 1202, 601, 593, 607, 1195, 607, 597, 603, 591, 610, 594, 606, 598, 603, 591, 609, 595, 606, 1196, +1000000, 2421, 608, 1194, 608, 596, 604, 1198, 604, 601, 575, 1227, 601, 593, 607, 598, 604, 600, 600, 594, 607, 598, 604, 601, 600, 1202, + 25953, 2419, 609, 1193, 609, 596, 605, 1197, 605, 600, 601, 1201, 601, 593, 607, 597, 603, 591, 610, 594, 606, 599, 602, 592, 608, 1194, + 25958, 2424, 605, 1197, 605, 600, 601, 1201, 600, 594, 607, 1195, 606, 598, 602, 592, 609, 595, 605, 600, 601, 593, 608, 596, 604, 1198, +1000000, 2423, 606, 1196, 606, 598, 602, 1200, 602, 592, 608, 1194, 608, 597, 604, 590, 610, 594, 607, 597, 603, 591, 610, 594, 606, 1196, + 25958, 2424, 605, 1197, 604, 600, 601, 1201, 601, 593, 607, 1195, 607, 597, 604, 590, 610, 595, 607, 597, 603, 591, 610, 594, 607, 1195, + 25961, 2421, 608, 1194, 608, 596, 605, 1197, 605, 600, 601, 1201, 601, 593, 607, 597, 603, 591, 610, 594, 606, 598, 602, 592, 609, 1193, +1000000, 2429, 601, 1201, 601, 593, 607, 1195, 608, 596, 604, 1198, 604, 600, 601, 593, 607, 597, 604, 590, 611, 593, 607, 597, 604, 1198, + 25959, 2422, 607, 1195, 607, 597, 603, 1199, 603, 591, 609, 1193, 610, 594, 606, 598, 602, 592, 609, 595, 605, 599, 602, 592, 608, 1194, + 25959, 2421, 608, 1194, 607, 597, 603, 1199, 603, 591, 610, 1192, 610, 594, 606, 598, 603, 591, 609, 595, 605, 599, 602, 592, 608, 1194, + 25959, 2422, 608, 1194, 608, 596, 604, 1198, 604, 590, 611, 1201, 601, 593, 607, 597, 604, 590, 610, 594, 607, 597, 603, 591, 609, 1193, + 25962, 2418, 610, 1192, 610, 594, 606, 1196, 607, 597, 603, 1199, 603, 591, 609, 595, 605, 599, 602, 592, 608, 596, 605, 599, 601, 1201, + +1000000, 2357, 610, 1183, 592, 1191, 614, 1179, 595, 1188, 618, 584, 613, 1180, 593, 588, 613, 1190, 612, 590, 605, 587, 613, 589, 605, 587, + 25398, 2355, 623, 1180, 591, 1181, 627, 1186, 589, 1183, 618, 584, 616, 1187, 587, 584, 614, 1189, 615, 587, 605, 587, 615, 587, 609, 593, +1000000, 2383, 609, 1214, 600, 612, 580, 1213, 608, 614, 583, 1210, 605, 607, 586, 616, 611, 1192, 599, 613, 608, 614, 579, 613, 615, 607, + 26670, 2387, 601, 1212, 600, 612, 589, 1214, 603, 609, 586, 1217, 595, 607, 594, 618, 606, 1187, 602, 610, 609, 613, 588, 614, 610, 612, +1000000, 2445, 582, 1221, 603, 548, 602, 1191, 609, 572, 602, 1191, 609, 542, 607, 544, 631, 1172, 603, 568, 606, 545, 605, 566, 608, 543, + 26263, 2414, 611, 1192, 607, 544, 606, 1197, 602, 569, 606, 1197, 602, 539, 611, 540, 635, 1168, 606, 565, 610, 541, 608, 563, 587, 564, +}; + +const IrdaMessage test_decoder_sirc_expected1[] = { + {IrdaProtocolSIRC, 0x10, 0x15, false}, + {IrdaProtocolSIRC, 0x10, 0x15, false}, + {IrdaProtocolSIRC, 0x10, 0x15, false}, + {IrdaProtocolSIRC, 0x10, 0x15, false}, + {IrdaProtocolSIRC, 0x10, 0x15, false}, + {IrdaProtocolSIRC, 0x10, 0x15, false}, + {IrdaProtocolSIRC, 0x10, 0x60, false}, + {IrdaProtocolSIRC, 0x10, 0x60, false}, + {IrdaProtocolSIRC, 0x10, 0x60, false}, + {IrdaProtocolSIRC, 0x10, 0x65, false}, + {IrdaProtocolSIRC, 0x10, 0x65, false}, + {IrdaProtocolSIRC, 0x10, 0x65, false}, + {IrdaProtocolSIRC20, 0x410, 0x17, false}, + {IrdaProtocolSIRC20, 0x410, 0x17, false}, + {IrdaProtocolSIRC20, 0x410, 0x17, false}, + {IrdaProtocolSIRC, 0x10, 0x21, false}, + {IrdaProtocolSIRC, 0x10, 0x21, false}, + {IrdaProtocolSIRC, 0x10, 0x21, false}, + {IrdaProtocolSIRC20, 0x73A, 0x7C, false}, + {IrdaProtocolSIRC20, 0x73A, 0x7C, false}, + {IrdaProtocolSIRC20, 0x73A, 0x7C, false}, + {IrdaProtocolSIRC20, 0x73A, 0x7C, false}, + {IrdaProtocolSIRC20, 0x73A, 0x7C, false}, + {IrdaProtocolSIRC20, 0x73A, 0x7C, false}, + {IrdaProtocolSIRC20, 0x73A, 0x7C, false}, + {IrdaProtocolSIRC20, 0x73A, 0x7C, false}, + {IrdaProtocolSIRC20, 0x73A, 0x7C, false}, + {IrdaProtocolSIRC20, 0x73A, 0x7C, false}, + {IrdaProtocolSIRC20, 0x73A, 0x7C, false}, + {IrdaProtocolSIRC20, 0x73A, 0x7C, false}, + {IrdaProtocolSIRC20, 0x73A, 0x7B, false}, + {IrdaProtocolSIRC20, 0x73A, 0x7B, false}, + {IrdaProtocolSIRC20, 0x73A, 0x7B, false}, + {IrdaProtocolSIRC20, 0x73A, 0x7A, false}, + {IrdaProtocolSIRC20, 0x73A, 0x7A, false}, + {IrdaProtocolSIRC20, 0x73A, 0x7A, false}, + {IrdaProtocolSIRC20, 0x73A, 0x78, false}, + {IrdaProtocolSIRC20, 0x73A, 0x78, false}, + {IrdaProtocolSIRC20, 0x73A, 0x78, false}, + {IrdaProtocolSIRC20, 0x73A, 0x79, false}, + {IrdaProtocolSIRC20, 0x73A, 0x79, false}, + {IrdaProtocolSIRC20, 0x73A, 0x79, false}, + {IrdaProtocolSIRC20, 0x73A, 0x7A, false}, + {IrdaProtocolSIRC20, 0x73A, 0x7A, false}, + {IrdaProtocolSIRC20, 0x73A, 0x7A, false}, + {IrdaProtocolSIRC20, 0x73A, 0x7C, false}, + {IrdaProtocolSIRC20, 0x73A, 0x7C, false}, + {IrdaProtocolSIRC20, 0x73A, 0x7C, false}, + {IrdaProtocolSIRC20, 0x73A, 0x7D, false}, + {IrdaProtocolSIRC20, 0x73A, 0x7D, false}, + {IrdaProtocolSIRC20, 0x73A, 0x7D, false}, + {IrdaProtocolSIRC20, 0x73A, 0x73, false}, + {IrdaProtocolSIRC20, 0x73A, 0x73, false}, + {IrdaProtocolSIRC20, 0x73A, 0x73, false}, + {IrdaProtocolSIRC, 0x10, 0x13, false}, + {IrdaProtocolSIRC, 0x10, 0x13, false}, + {IrdaProtocolSIRC, 0x10, 0x13, false}, + {IrdaProtocolSIRC, 0x10, 0x13, false}, + {IrdaProtocolSIRC, 0x10, 0x12, false}, + {IrdaProtocolSIRC, 0x10, 0x12, false}, + {IrdaProtocolSIRC, 0x10, 0x12, false}, + {IrdaProtocolSIRC, 0x10, 0x12, false}, + {IrdaProtocolSIRC20, 0x73A, 0x30, false}, + {IrdaProtocolSIRC20, 0x73A, 0x30, false}, + {IrdaProtocolSIRC20, 0x73A, 0x30, false}, + {IrdaProtocolSIRC20, 0x73A, 0x39, false}, + {IrdaProtocolSIRC20, 0x73A, 0x39, false}, + {IrdaProtocolSIRC20, 0x73A, 0x39, false}, + {IrdaProtocolSIRC20, 0x73A, 0x31, false}, + {IrdaProtocolSIRC20, 0x73A, 0x31, false}, + {IrdaProtocolSIRC20, 0x73A, 0x31, false}, + {IrdaProtocolSIRC20, 0x73A, 0x34, false}, + {IrdaProtocolSIRC20, 0x73A, 0x34, false}, + {IrdaProtocolSIRC20, 0x73A, 0x34, false}, + {IrdaProtocolSIRC20, 0x73A, 0x32, false}, + {IrdaProtocolSIRC20, 0x73A, 0x32, false}, + {IrdaProtocolSIRC20, 0x73A, 0x32, false}, + {IrdaProtocolSIRC20, 0x73A, 0x33, false}, + {IrdaProtocolSIRC20, 0x73A, 0x33, false}, + {IrdaProtocolSIRC20, 0x73A, 0x33, false}, + {IrdaProtocolSIRC20, 0x73A, 0x0F, false}, + {IrdaProtocolSIRC20, 0x73A, 0x0F, false}, + {IrdaProtocolSIRC20, 0x73A, 0x0F, false}, + {IrdaProtocolSIRC20, 0x73A, 0x38, false}, + {IrdaProtocolSIRC20, 0x73A, 0x38, false}, + {IrdaProtocolSIRC20, 0x73A, 0x38, false}, + {IrdaProtocolSIRC, 0x10, 0x15, false}, + {IrdaProtocolSIRC, 0x10, 0x15, false}, + {IrdaProtocolSIRC, 0x10, 0x15, false}, + {IrdaProtocolSIRC, 0x10, 0x15, false}, + {IrdaProtocolSIRC, 0x10, 0x15, false}, + {IrdaProtocolSIRC, 0x10, 0x15, false}, + {IrdaProtocolSIRC, 0x10, 0x15, false}, + {IrdaProtocolSIRC, 0x10, 0x15, false}, + {IrdaProtocolSIRC, 0x10, 0x15, false}, + {IrdaProtocolSIRC, 0x10, 0x15, false}, + {IrdaProtocolSIRC, 0x10, 0x15, false}, + {IrdaProtocolSIRC, 0x10, 0x15, false}, + {IrdaProtocolSIRC, 0x10, 0x15, false}, + {IrdaProtocolSIRC, 0x10, 0x15, false}, + {IrdaProtocolSIRC, 0x10, 0x15, false}, + {IrdaProtocolSIRC, 0x10, 0x15, false}, + {IrdaProtocolSIRC, 0x10, 0x15, false}, + {IrdaProtocolSIRC, 0x10, 0x15, false}, + {IrdaProtocolSIRC, 0x10, 0x15, false}, + {IrdaProtocolSIRC, 0x10, 0x15, false}, + {IrdaProtocolSIRC, 0x10, 0x15, false}, + {IrdaProtocolSIRC, 0x10, 0x15, false}, + {IrdaProtocolSIRC, 0x10, 0x15, false}, + {IrdaProtocolSIRC, 0x10, 0x15, false}, + {IrdaProtocolSIRC, 0x10, 0x15, false}, + {IrdaProtocolSIRC, 0x10, 0x15, false}, + {IrdaProtocolSIRC, 0x10, 0x15, false}, + {IrdaProtocolSIRC, 0x10, 0x15, false}, + {IrdaProtocolSIRC, 0x10, 0x15, false}, + {IrdaProtocolSIRC, 0x01, 0x2F, false}, + {IrdaProtocolSIRC, 0x01, 0x2F, false}, + {IrdaProtocolSIRC, 0x01, 0x15, false}, + {IrdaProtocolSIRC, 0x01, 0x15, false}, + {IrdaProtocolSIRC, 0x01, 0x15, false}, + {IrdaProtocolSIRC, 0x01, 0x15, false}, +}; + + +// command (0x55) address (0x0A) SIRC +// 1 0 1 0 1 0 1 0 1 0 1 0 +// 2400, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, +// +// command (0x7F) address (0x1F) SIRC +// 1 1 1 1 1 1 1 1 1 1 1 1 +// 2400, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, +// +// command (0x00) address (0x00) SIRC +// 0 0 0 0 0 0 0 0 0 0 0 0 +// 2400, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, +// +// command (0x53) address (0x0D) SIRC +// 1 1 0 0 1 0 1 1 0 1 1 0 +// 2400, 600, 1200, 600, 1200, 600, 600, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, + +const uint32_t test_decoder_sirc_input2[] = { +1000000, 2400, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, +1000000, 2400, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, +1000000, 2400, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, +1000000, 2400, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 600, /* failed - should be skipped */ + +1000000, 2400, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, +1000000, 2400, 600, 1200, 600, 600, /* failed - should be skipped */ +1000000, 2400, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, +1000000, 2400, 600, 1200, 600, /* failed - should be skipped */ + 2400, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, +1000000, 2400, 600, 1200, 600, 600, /* failed - should be skipped */ +1000000, 2400, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, + +1000000, 2400, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, + +1000000, 2400, 600, 1200, 600, 1200, 600, 600, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, +}; + +const IrdaMessage test_decoder_sirc_expected2[] = { + {IrdaProtocolSIRC, 0xA, 0x55, false}, + {IrdaProtocolSIRC, 0xA, 0x55, false}, + {IrdaProtocolSIRC, 0xA, 0x55, false}, + /* failed - 13 data bits */ + + {IrdaProtocolSIRC, 0x1F, 0x7F, false}, + /* failed - 2 data bits */ + {IrdaProtocolSIRC, 0x1F, 0x7F, false}, + /* failed - sudden end */ + {IrdaProtocolSIRC, 0x1F, 0x7F, false}, + /* failed */ + {IrdaProtocolSIRC, 0x0A, 0x55, false}, + + {IrdaProtocolSIRC, 0x00, 0x00, false}, + + {IrdaProtocolSIRC, 0x0D, 0x53, false}, +}; + + +// command (0x13) address (0xFD) SIRC15 +// 1 1 0 0 1 0 0 1 0 1 1 1 1 1 1 +// 2400, 600, 1200, 600, 1200, 600, 600, 600, 600, 600, 1200, 600, 600, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, +// +// command (0x53) address (0x7D) SIRC15 +// 1 1 0 0 1 0 1 1 0 1 1 1 1 1 0 +// 2400, 600, 1200, 600, 1200, 600, 600, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 600, +// +// command (0x53) address (0x0D) SIRC15 +// 1 1 0 0 1 0 1 1 0 1 1 0 0 0 0 +// 2400, 600, 1200, 600, 1200, 600, 600, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 600, 600, 600, 600, 600, + +const uint32_t test_decoder_sirc_input3[] = { +1000000, 2400, 600, 1200, 600, 1200, 600, 600, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 600, + 10000, 2400, 600, 1200, 600, 1200, 600, 600, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 600, + 10000, 2400, 600, 1200, 600, 1200, 600, 600, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 600, + +1000000, 2400, 600, 1200, 600, 1200, 600, 600, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 600, 600, 600, 600, 600, + 10000, 2400, 600, 1200, 600, 1200, 600, 600, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 600, 600, 600, 600, 600, + 10000, 2400, 600, 1200, 600, 1200, 600, 600, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 600, 600, 600, 600, 600, + +1000000, 2400, 600, 1200, 600, 1200, 600, 600, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 600, 600, 600, 600, 600, +1000000, 2400, 600, 1200, 600, 1200, 600, 600, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 600, 600, 600, 600, 600, + +1000000, 2400, 600, 1200, 600, 1200, 600, 600, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 600, +1000000, 2400, 600, 1200, 600, 1200, 600, 600, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 600, + + 10000, 2400, 600, 1200, 600, 1200, 600, 600, 600, 600, 600, 1200, 600, 600, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, +}; + +const IrdaMessage test_decoder_sirc_expected3[] = { + {IrdaProtocolSIRC15, 0x7D, 0x53, false}, + {IrdaProtocolSIRC15, 0x7D, 0x53, false}, + {IrdaProtocolSIRC15, 0x7D, 0x53, false}, + {IrdaProtocolSIRC15, 0x0D, 0x53, false}, + {IrdaProtocolSIRC15, 0x0D, 0x53, false}, + {IrdaProtocolSIRC15, 0x0D, 0x53, false}, + {IrdaProtocolSIRC15, 0x0D, 0x53, false}, + {IrdaProtocolSIRC15, 0x0D, 0x53, false}, + {IrdaProtocolSIRC15, 0x7D, 0x53, false}, + {IrdaProtocolSIRC15, 0x7D, 0x53, false}, + {IrdaProtocolSIRC15, 0xFD, 0x13, false}, +}; + +const uint32_t test_decoder_sirc_input4[] = { +1000000, 2400, 600, 1200, 600, 1200, 600, 600, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 600, +10000, 2400, 600, 1200, 600, 1200, 600, 600, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 600, +10000, 2400, 600, 1200, 600, 1200, 600, 600, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 600, +1000000, 2400, 600, 1200, 600, 1200, 600, 600, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 600, +1000000, 2400, 600, 1200, 600, 1200, 600, 600, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 600, +1000000, 2400, 600, 1200, 600, 1200, 600, 600, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 600, +}; + +const IrdaMessage test_decoder_sirc_expected4[] = { + {IrdaProtocolSIRC20, 0xFB5, 0x53, false}, // {IrdaProtocolSIRC20, 0x15, 0x3ED3, false}, + {IrdaProtocolSIRC20, 0xFB5, 0x53, false}, + {IrdaProtocolSIRC20, 0xFB5, 0x53, false}, + {IrdaProtocolSIRC20, 0xFB5, 0x53, false}, + {IrdaProtocolSIRC20, 0xFB5, 0x53, false}, + {IrdaProtocolSIRC20, 0xFB5, 0x53, false}, +}; + +const uint32_t test_decoder_sirc_input5[] = { +1000000, 2400, 600, 1200, 600, 1200, 600, 600, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 600, +1000000, 2400, 600, 1200, 600, 1200, 600, 600, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 600, +1000000, 2400, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, +1000000, 2400, 600, 1200, 600, 1200, 600, 600, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 600, +1000000, 2400, 600, 1200, 600, 1200, 600, 600, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 600, +1000000, 2400, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, + +10000, 2400, 600, 1200, 600, 1200, 600, 600, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 600, +10000, 2400, 600, 1200, 600, 1200, 600, 600, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 600, +10000, 2400, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, +10000, 2400, 600, 1200, 600, 1200, 600, 600, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 600, +10000, 2400, 600, 1200, 600, 1200, 600, 600, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 600, +10000, 2400, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, + +10000, 2400, 600, 1200, 600, 1200, 600, 600, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 600, +10000, 2400, 600, 1200, 600, 1200, 600, 600, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 600, +10000, 2400, 600, 1200, 600, 1200, 600, 600, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 600, +10000, 2400, 600, 1200, 600, 1200, 600, 600, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 600, +10000, 2400, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, +10000, 2400, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, + +10000, 2400, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, +10000, 2400, 600, 1200, 600, 1200, 600, 600, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 600, +10000, 2400, 600, 1200, 600, 1200, 600, 600, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 600, +10000, 2400, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, +10000, 2400, 600, 1200, 600, 1200, 600, 600, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 600, +10000, 2400, 600, 1200, 600, 1200, 600, 600, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 600, +}; + +const IrdaMessage test_decoder_sirc_expected5[] = { + {IrdaProtocolSIRC20, 0xFB5, 0x53, false}, + {IrdaProtocolSIRC15, 0x7D, 0x53, false}, + {IrdaProtocolSIRC, 0xA, 0x55, false}, + {IrdaProtocolSIRC20, 0xFB5, 0x53, false}, + {IrdaProtocolSIRC15, 0x7D, 0x53, false}, + {IrdaProtocolSIRC, 0xA, 0x55, false}, + + {IrdaProtocolSIRC20, 0xFB5, 0x53, false}, + {IrdaProtocolSIRC15, 0x7D, 0x53, false}, + {IrdaProtocolSIRC, 0xA, 0x55, false}, + {IrdaProtocolSIRC20, 0xFB5, 0x53, false}, + {IrdaProtocolSIRC15, 0x7D, 0x53, false}, + {IrdaProtocolSIRC, 0xA, 0x55, false}, + + {IrdaProtocolSIRC20, 0xFB5, 0x53, false}, + {IrdaProtocolSIRC20, 0xFB5, 0x53, false}, + {IrdaProtocolSIRC15, 0x7D, 0x53, false}, + {IrdaProtocolSIRC15, 0x7D, 0x53, false}, + {IrdaProtocolSIRC, 0xA, 0x55, false}, + {IrdaProtocolSIRC, 0xA, 0x55, false}, + + {IrdaProtocolSIRC, 0xA, 0x55, false}, + {IrdaProtocolSIRC15, 0x7D, 0x53, false}, + {IrdaProtocolSIRC20, 0xFB5, 0x53, false}, + {IrdaProtocolSIRC, 0xA, 0x55, false}, + {IrdaProtocolSIRC15, 0x7D, 0x53, false}, + {IrdaProtocolSIRC20, 0xFB5, 0x53, false}, +}; + + + + +const IrdaMessage test_encoder_sirc_input1[] = { + {IrdaProtocolSIRC, 0xA, 0x55, false}, +}; + +const uint32_t test_encoder_sirc_expected1[] = { +10000, 2400, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, +}; + + + + +const IrdaMessage test_encoder_sirc_input2[] = { + {IrdaProtocolSIRC15, 0x7D, 0x53, false}, + {IrdaProtocolSIRC15, 0x7D, 0x53, true}, + {IrdaProtocolSIRC15, 0x7D, 0x53, true}, +}; + +const uint32_t test_encoder_sirc_expected2[] = { + 10000, 2400, 600, 1200, 600, 1200, 600, 600, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 600, 600, /* 2 low levels in row */ + 18000, 2400, 600, 1200, 600, 1200, 600, 600, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 600, 600, /* 2 low levels in row */ + 18000, 2400, 600, 1200, 600, 1200, 600, 600, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 600, 600, +}; + +const IrdaMessage test_sirc[] = { + {IrdaProtocolSIRC20, 0x1FFF, 0x7F, false}, + {IrdaProtocolSIRC20, 0x1FFF, 0x7F, true}, + {IrdaProtocolSIRC20, 0x1FFF, 0x7F, true}, + {IrdaProtocolSIRC, 0x00, 0x00, false}, + {IrdaProtocolSIRC, 0x00, 0x00, true}, + {IrdaProtocolSIRC, 0x00, 0x00, true}, + + {IrdaProtocolSIRC, 0x1A, 0x22, false}, + {IrdaProtocolSIRC, 0x1A, 0x22, true}, + {IrdaProtocolSIRC, 0x1A, 0x22, true}, + {IrdaProtocolSIRC, 0x17, 0x0A, false}, + + {IrdaProtocolSIRC15, 0x7D, 0x53, false}, + {IrdaProtocolSIRC15, 0x7D, 0x53, true}, + {IrdaProtocolSIRC15, 0x7D, 0x53, true}, + {IrdaProtocolSIRC15, 0x71, 0x0, false}, + {IrdaProtocolSIRC15, 0x15, 0x01, false}, + {IrdaProtocolSIRC15, 0x01, 0x15, false}, + + {IrdaProtocolSIRC20, 0xAA, 0x55, false}, + {IrdaProtocolSIRC20, 0x331, 0x71, false}, + + {IrdaProtocolSIRC, 0x00, 0x00, false}, + {IrdaProtocolSIRC, 0x1F, 0x7F, false}, + {IrdaProtocolSIRC15, 0x00, 0x00, false}, + {IrdaProtocolSIRC15, 0xFF, 0x7F, false}, + {IrdaProtocolSIRC20, 0x00, 0x00, false}, + {IrdaProtocolSIRC20, 0x1FFF, 0x7F, false}, +}; + diff --git a/core/furi/common_defines.h b/core/furi/common_defines.h index 7d514660..c8e2f311 100644 --- a/core/furi/common_defines.h +++ b/core/furi/common_defines.h @@ -19,6 +19,15 @@ }) #endif +#ifndef ROUND_UP_TO +#define ROUND_UP_TO(a, b) \ + ({ \ + __typeof__(a) _a = (a); \ + __typeof__(b) _b = (b); \ + _a / _b + !!(_a % _b); \ + }) +#endif + #ifndef CLAMP #define CLAMP(x, upper, lower) (MIN(upper, MAX(x, lower))) #endif diff --git a/firmware/targets/f6/furi-hal/furi-hal-irda.c b/firmware/targets/f6/furi-hal/furi-hal-irda.c index 7c5d832b..a148b44a 100644 --- a/firmware/targets/f6/furi-hal/furi-hal-irda.c +++ b/firmware/targets/f6/furi-hal/furi-hal-irda.c @@ -442,7 +442,7 @@ static void furi_hal_irda_tx_fill_buffer(uint8_t buf_num, uint8_t polarity_shift buffer->polarity[polarity_counter++] = IRDA_TX_CCMR_LOW; } - for (*size = 0; (*size < IRDA_TIM_TX_DMA_BUFFER_SIZE) && (status == FuriHalIrdaTxGetDataStateOk); ++(*size), ++polarity_counter) { + for (*size = 0; (*size < IRDA_TIM_TX_DMA_BUFFER_SIZE) && (status == FuriHalIrdaTxGetDataStateOk);) { if (irda_tim_tx.tx_timing_rest_duration > 0) { if (irda_tim_tx.tx_timing_rest_duration > 0xFFFF) { buffer->data[*size] = 0xFFFF; @@ -453,6 +453,8 @@ static void furi_hal_irda_tx_fill_buffer(uint8_t buf_num, uint8_t polarity_shift } irda_tim_tx.tx_timing_rest_duration -= buffer->data[*size]; buffer->polarity[polarity_counter] = irda_tim_tx.tx_timing_rest_level ? IRDA_TX_CCMR_HIGH : IRDA_TX_CCMR_LOW; + ++(*size); + ++polarity_counter; continue; } @@ -467,18 +469,16 @@ static void furi_hal_irda_tx_fill_buffer(uint8_t buf_num, uint8_t polarity_shift */ status = FuriHalIrdaTxGetDataStateOk; } - --(*size); - --polarity_counter; } else if ((num_of_impulses - 1) > 0xFFFF) { irda_tim_tx.tx_timing_rest_duration = num_of_impulses - 1; irda_tim_tx.tx_timing_rest_status = status; irda_tim_tx.tx_timing_rest_level = level; - --(*size); - --polarity_counter; status = FuriHalIrdaTxGetDataStateOk; } else { buffer->polarity[polarity_counter] = level ? IRDA_TX_CCMR_HIGH : IRDA_TX_CCMR_LOW; buffer->data[*size] = num_of_impulses - 1; + ++(*size); + ++polarity_counter; } } diff --git a/lib/irda/encoder_decoder/common/irda_common_decoder.c b/lib/irda/encoder_decoder/common/irda_common_decoder.c index e57844cc..d64b798d 100644 --- a/lib/irda/encoder_decoder/common/irda_common_decoder.c +++ b/lib/irda/encoder_decoder/common/irda_common_decoder.c @@ -4,8 +4,34 @@ #include #include #include "irda_i.h" +#include -static void irda_common_decoder_reset_state(IrdaCommonDecoder* common_decoder); +static void irda_common_decoder_reset_state(IrdaCommonDecoder* decoder); + +static inline size_t consume_samples(uint32_t* array, size_t len, size_t shift) { + furi_assert(len >= shift); + len -= shift; + for (int i = 0; i < len; ++i) + array[i] = array[i + shift]; + + return len; +} + +static inline void accumulate_lsb(IrdaCommonDecoder* decoder, bool bit) { + uint16_t index = decoder->databit_cnt / 8; + uint8_t shift = decoder->databit_cnt % 8; // LSB first + + if (!shift) + decoder->data[index] = 0; + + if (bit) { + decoder->data[index] |= (0x1 << shift); // add 1 + } else { + (void) decoder->data[index]; // add 0 + } + + ++decoder->databit_cnt; +} static bool irda_check_preamble(IrdaCommonDecoder* decoder) { furi_assert(decoder); @@ -16,8 +42,7 @@ static bool irda_check_preamble(IrdaCommonDecoder* decoder) { // align to start at Mark timing if (!start_level) { if (decoder->timings_cnt > 0) { - --decoder->timings_cnt; - shift_left_array(decoder->timings, decoder->timings_cnt, 1); + decoder->timings_cnt = consume_samples(decoder->timings, decoder->timings_cnt, 1); } } @@ -30,25 +55,22 @@ static bool irda_check_preamble(IrdaCommonDecoder* decoder) { uint16_t preamble_mark = decoder->protocol->timings.preamble_mark; uint16_t preamble_space = decoder->protocol->timings.preamble_space; - if ((MATCH_PREAMBLE_TIMING(decoder->timings[0], preamble_mark, preamble_tolerance)) - && (MATCH_PREAMBLE_TIMING(decoder->timings[1], preamble_space, preamble_tolerance))) { + if ((MATCH_TIMING(decoder->timings[0], preamble_mark, preamble_tolerance)) + && (MATCH_TIMING(decoder->timings[1], preamble_space, preamble_tolerance))) { result = true; } - decoder->timings_cnt -= 2; - shift_left_array(decoder->timings, decoder->timings_cnt, 2); + decoder->timings_cnt = consume_samples(decoder->timings, decoder->timings_cnt, 2); } return result; } -/* Pulse Distance-Width Modulation */ -IrdaStatus irda_common_decode_pdwm(IrdaCommonDecoder* decoder) { +/* Pulse Distance Modulation */ +IrdaStatus irda_common_decode_pdm(IrdaCommonDecoder* decoder) { furi_assert(decoder); uint32_t* timings = decoder->timings; - uint16_t index = 0; - uint8_t shift = 0; IrdaStatus status = IrdaStatusError; uint32_t bit_tolerance = decoder->protocol->timings.bit_tolerance; uint16_t bit1_mark = decoder->protocol->timings.bit1_mark; @@ -59,7 +81,7 @@ IrdaStatus irda_common_decode_pdwm(IrdaCommonDecoder* decoder) { while (1) { // Stop bit if ((decoder->databit_cnt == decoder->protocol->databit_len) && (decoder->timings_cnt == 1)) { - if (MATCH_BIT_TIMING(timings[0], bit1_mark, bit_tolerance)) { + if (MATCH_TIMING(timings[0], bit1_mark, bit_tolerance)) { decoder->timings_cnt = 0; status = IrdaStatusReady; } else { @@ -69,23 +91,17 @@ IrdaStatus irda_common_decode_pdwm(IrdaCommonDecoder* decoder) { } if (decoder->timings_cnt >= 2) { - index = decoder->databit_cnt / 8; - shift = decoder->databit_cnt % 8; // LSB first - if (!shift) - decoder->data[index] = 0; - if (MATCH_BIT_TIMING(timings[0], bit1_mark, bit_tolerance) - && MATCH_BIT_TIMING(timings[1], bit1_space, bit_tolerance)) { - decoder->data[index] |= (0x1 << shift); // add 1 - } else if (MATCH_BIT_TIMING(timings[0], bit0_mark, bit_tolerance) - && MATCH_BIT_TIMING(timings[1], bit0_space, bit_tolerance)) { - (void) decoder->data[index]; // add 0 + if (MATCH_TIMING(timings[0], bit1_mark, bit_tolerance) + && MATCH_TIMING(timings[1], bit1_space, bit_tolerance)) { + accumulate_lsb(decoder, 1); + } else if (MATCH_TIMING(timings[0], bit0_mark, bit_tolerance) + && MATCH_TIMING(timings[1], bit0_space, bit_tolerance)) { + accumulate_lsb(decoder, 0); } else { status = IrdaStatusError; break; } - ++decoder->databit_cnt; - decoder->timings_cnt -= 2; - shift_left_array(decoder->timings, decoder->timings_cnt, 2); + decoder->timings_cnt = consume_samples(decoder->timings, decoder->timings_cnt, 2); } else { status = IrdaStatusOk; break; @@ -107,8 +123,8 @@ IrdaStatus irda_common_decode_manchester(IrdaCommonDecoder* decoder) { bool* switch_detect = &decoder->switch_detect; furi_assert((*switch_detect == true) || (*switch_detect == false)); - bool single_timing = MATCH_BIT_TIMING(timing, bit, tolerance); - bool double_timing = MATCH_BIT_TIMING(timing, 2*bit, tolerance); + bool single_timing = MATCH_TIMING(timing, bit, tolerance); + bool double_timing = MATCH_TIMING(timing, 2*bit, tolerance); if(!single_timing && !double_timing) { status = IrdaStatusError; @@ -134,19 +150,13 @@ IrdaStatus irda_common_decode_manchester(IrdaCommonDecoder* decoder) { *switch_detect = 0; } - --decoder->timings_cnt; - shift_left_array(decoder->timings, decoder->timings_cnt, 1); + decoder->timings_cnt = consume_samples(decoder->timings, decoder->timings_cnt, 1); status = IrdaStatusOk; bool level = (decoder->level + decoder->timings_cnt) % 2; if (decoder->databit_cnt < decoder->protocol->databit_len) { if (*switch_detect) { - uint8_t index = decoder->databit_cnt / 8; - uint8_t shift = decoder->databit_cnt % 8; // LSB first - if (!shift) - decoder->data[index] = 0; - decoder->data[index] |= (level << shift); - ++decoder->databit_cnt; + accumulate_lsb(decoder, level); } if (decoder->databit_cnt == decoder->protocol->databit_len) { if (level) { @@ -169,6 +179,46 @@ IrdaStatus irda_common_decode_manchester(IrdaCommonDecoder* decoder) { return status; } +/* Pulse Width Modulation */ +IrdaStatus irda_common_decode_pwm(IrdaCommonDecoder* decoder) { + furi_assert(decoder); + + uint32_t* timings = decoder->timings; + IrdaStatus status = IrdaStatusOk; + uint32_t bit_tolerance = decoder->protocol->timings.bit_tolerance; + uint16_t bit1_mark = decoder->protocol->timings.bit1_mark; + uint16_t bit1_space = decoder->protocol->timings.bit1_space; + uint16_t bit0_mark = decoder->protocol->timings.bit0_mark; + + while (decoder->timings_cnt) { + bool level = (decoder->level + decoder->timings_cnt + 1) % 2; + + if (level) { + if (MATCH_TIMING(timings[0], bit1_mark, bit_tolerance)) { + accumulate_lsb(decoder, 1); + } else if (MATCH_TIMING(timings[0], bit0_mark, bit_tolerance)) { + accumulate_lsb(decoder, 0); + } else { + status = IrdaStatusError; + break; + } + } else { + if (!MATCH_TIMING(timings[0], bit1_space, bit_tolerance)) { + status = IrdaStatusError; + break; + } + } + decoder->timings_cnt = consume_samples(decoder->timings, decoder->timings_cnt, 1); + + if (decoder->databit_cnt == decoder->protocol->databit_len) { + status = IrdaStatusReady; + break; + } + } + + return status; +} + IrdaMessage* irda_common_decode(IrdaCommonDecoder* decoder, bool level, uint32_t duration) { furi_assert(decoder); @@ -176,7 +226,7 @@ IrdaMessage* irda_common_decode(IrdaCommonDecoder* decoder, bool level, uint32_t IrdaStatus status = IrdaStatusError; if (decoder->level == level) { - decoder->timings_cnt = 0; + irda_common_decoder_reset(decoder); } decoder->level = level; // start with low level (Space timing) @@ -242,32 +292,27 @@ void* irda_common_decoder_alloc(const IrdaCommonProtocolSpec* protocol) { return decoder; } -void irda_common_decoder_set_context(void* decoder, void* context) { - IrdaCommonDecoder* common_decoder = decoder; - common_decoder->context = context; -} - -void irda_common_decoder_free(void* decoder) { +void irda_common_decoder_free(IrdaCommonDecoder* decoder) { furi_assert(decoder); free(decoder); } -void irda_common_decoder_reset_state(IrdaCommonDecoder* common_decoder) { - common_decoder->state = IrdaCommonDecoderStateWaitPreamble; - common_decoder->databit_cnt = 0; - common_decoder->switch_detect = false; - common_decoder->message.protocol = IrdaProtocolUnknown; - if ((common_decoder->protocol->timings.preamble_mark == 0) && (common_decoder->timings_cnt > 0)) { - --common_decoder->timings_cnt; - shift_left_array(common_decoder->timings, common_decoder->timings_cnt, 1); +void irda_common_decoder_reset_state(IrdaCommonDecoder* decoder) { + decoder->state = IrdaCommonDecoderStateWaitPreamble; + decoder->databit_cnt = 0; + decoder->switch_detect = false; + decoder->message.protocol = IrdaProtocolUnknown; + if (decoder->protocol->timings.preamble_mark == 0) { + if (decoder->timings_cnt > 0) { + decoder->timings_cnt = consume_samples(decoder->timings, decoder->timings_cnt, 1); + } } } -void irda_common_decoder_reset(void* decoder) { +void irda_common_decoder_reset(IrdaCommonDecoder* decoder) { furi_assert(decoder); - IrdaCommonDecoder* common_decoder = decoder; - irda_common_decoder_reset_state(common_decoder); - common_decoder->timings_cnt = 0; + irda_common_decoder_reset_state(decoder); + decoder->timings_cnt = 0; } diff --git a/lib/irda/encoder_decoder/common/irda_common_encoder.c b/lib/irda/encoder_decoder/common/irda_common_encoder.c index 6e897233..cdb65d0a 100644 --- a/lib/irda/encoder_decoder/common/irda_common_encoder.c +++ b/lib/irda/encoder_decoder/common/irda_common_encoder.c @@ -35,6 +35,7 @@ IrdaStatus irda_common_encode_manchester(IrdaCommonEncoder* encoder, uint32_t* d if (even_timing) /* start encoding from space */ ++encoder->bits_encoded; ++encoder->timings_encoded; + encoder->timings_sum += *duration; bool finish = (encoder->bits_encoded == encoder->protocol->databit_len); finish |= (encoder->bits_encoded == (encoder->protocol->databit_len-1)) && *level && !even_timing; @@ -46,6 +47,7 @@ IrdaStatus irda_common_encode_pdwm(IrdaCommonEncoder* encoder, uint32_t* duratio furi_assert(duration); furi_assert(level); + bool done = false; const IrdaTimings* timings = &encoder->protocol->timings; uint8_t index = encoder->bits_encoded / 8; uint8_t shift = encoder->bits_encoded % 8; // LSB first @@ -53,9 +55,11 @@ IrdaStatus irda_common_encode_pdwm(IrdaCommonEncoder* encoder, uint32_t* duratio // stop bit if (encoder->bits_encoded == encoder->protocol->databit_len) { + furi_assert(!encoder->protocol->no_stop_bit); *duration = timings->bit1_mark; *level = true; ++encoder->timings_encoded; + encoder->timings_sum += *duration; return IrdaStatusDone; } @@ -68,8 +72,14 @@ IrdaStatus irda_common_encode_pdwm(IrdaCommonEncoder* encoder, uint32_t* duratio ++encoder->bits_encoded; } + if ((encoder->bits_encoded == encoder->protocol->databit_len) + && encoder->protocol->no_stop_bit) { + done = true; + } + ++encoder->timings_encoded; - return IrdaStatusOk; + encoder->timings_sum += *duration; + return done ? IrdaStatusDone : IrdaStatusOk; } IrdaStatus irda_common_encode(IrdaCommonEncoder* encoder, uint32_t* duration, bool* level) { @@ -80,12 +90,13 @@ IrdaStatus irda_common_encode(IrdaCommonEncoder* encoder, uint32_t* duration, bo const IrdaTimings* timings = &encoder->protocol->timings; switch (encoder->state) { - case IrdaCommonEncoderStateSpace: + case IrdaCommonEncoderStateSilence: *duration = encoder->protocol->timings.silence_time; *level = false; status = IrdaStatusOk; encoder->state = IrdaCommonEncoderStatePreamble; ++encoder->timings_encoded; + encoder->timings_sum = 0; break; case IrdaCommonEncoderStatePreamble: if (timings->preamble_mark) { @@ -98,6 +109,7 @@ IrdaStatus irda_common_encode(IrdaCommonEncoder* encoder, uint32_t* duration, bo encoder->state = IrdaCommonEncoderStateEncode; } ++encoder->timings_encoded; + encoder->timings_sum += *duration; break; } else { encoder->state = IrdaCommonEncoderStateEncode; @@ -110,9 +122,10 @@ IrdaStatus irda_common_encode(IrdaCommonEncoder* encoder, uint32_t* duration, bo encoder->state = IrdaCommonEncoderStateEncodeRepeat; } else { encoder->timings_encoded = 0; + encoder->timings_sum = 0; encoder->bits_encoded = 0; encoder->switch_detect = 0; - encoder->state = IrdaCommonEncoderStateSpace; + encoder->state = IrdaCommonEncoderStateSilence; } } break; @@ -144,8 +157,9 @@ void irda_common_encoder_free(IrdaCommonEncoder* encoder) { void irda_common_encoder_reset(IrdaCommonEncoder* encoder) { furi_assert(encoder); encoder->timings_encoded = 0; + encoder->timings_sum = 0; encoder->bits_encoded = 0; - encoder->state = IrdaCommonEncoderStateSpace; + encoder->state = IrdaCommonEncoderStateSilence; encoder->switch_detect = 0; uint8_t bytes_to_clear = encoder->protocol->databit_len / 8 @@ -153,8 +167,3 @@ void irda_common_encoder_reset(IrdaCommonEncoder* encoder) { memset(encoder->data, 0, bytes_to_clear); } -void irda_common_encoder_set_context(void* decoder, void* context) { - IrdaCommonEncoder* common_encoder = decoder; - common_encoder->context = context; -} - diff --git a/lib/irda/encoder_decoder/common/irda_common_i.h b/lib/irda/encoder_decoder/common/irda_common_i.h index c73ebee9..5cf7b584 100644 --- a/lib/irda/encoder_decoder/common/irda_common_i.h +++ b/lib/irda/encoder_decoder/common/irda_common_i.h @@ -5,11 +5,8 @@ #include "irda_i.h" -#define MATCH_BIT_TIMING(x, v, delta) ( ((x) < (v + delta)) \ - && ((x) > (v - delta))) - -#define MATCH_PREAMBLE_TIMING(x, v, delta) ( ((x) < ((v) * (1 + (delta)))) \ - && ((x) > ((v) * (1 - (delta))))) +#define MATCH_TIMING(x, v, delta) ( ((x) < (v + delta)) \ + && ((x) > (v - delta))) typedef struct IrdaCommonDecoder IrdaCommonDecoder; typedef struct IrdaCommonEncoder IrdaCommonEncoder; @@ -21,6 +18,7 @@ typedef IrdaStatus (*IrdaCommonEncode)(IrdaCommonEncoder* encoder, uint32_t* out typedef struct { IrdaTimings timings; bool manchester_start_from_space; + bool no_stop_bit; uint32_t databit_len; IrdaCommonDecode decode; IrdaCommonDecode decode_repeat; @@ -36,7 +34,7 @@ typedef enum { } IrdaCommonStateDecoder; typedef enum { - IrdaCommonEncoderStateSpace, + IrdaCommonEncoderStateSilence, IrdaCommonEncoderStatePreamble, IrdaCommonEncoderStateEncode, IrdaCommonEncoderStateEncodeRepeat, @@ -44,13 +42,13 @@ typedef enum { struct IrdaCommonDecoder { const IrdaCommonProtocolSpec* protocol; - IrdaCommonStateDecoder state; - IrdaMessage message; - uint32_t timings[6]; - uint8_t timings_cnt; void* context; + uint32_t timings[6]; + IrdaMessage message; + IrdaCommonStateDecoder state; + uint8_t timings_cnt; bool switch_detect; - uint32_t level; + bool level; uint16_t databit_cnt; uint8_t data[]; }; @@ -60,30 +58,23 @@ struct IrdaCommonEncoder { IrdaCommonStateEncoder state; bool switch_detect; uint32_t bits_encoded; + uint32_t timings_sum; uint32_t timings_encoded; void* context; uint8_t data[]; }; - -static inline void shift_left_array(uint32_t *array, uint32_t len, uint32_t shift) { - for (int i = 0; i < len; ++i) - array[i] = array[i + shift]; -} - - IrdaMessage* irda_common_decode(IrdaCommonDecoder *decoder, bool level, uint32_t duration); -IrdaStatus irda_common_decode_pdwm(IrdaCommonDecoder* decoder); +IrdaStatus irda_common_decode_pdm(IrdaCommonDecoder* decoder); +IrdaStatus irda_common_decode_pwm(IrdaCommonDecoder* decoder); IrdaStatus irda_common_decode_manchester(IrdaCommonDecoder* decoder); -void irda_common_decoder_set_context(void* decoder, void* context); void* irda_common_decoder_alloc(const IrdaCommonProtocolSpec *protocol); -void irda_common_decoder_free(void* decoder); -void irda_common_decoder_reset(void* decoder); +void irda_common_decoder_free(IrdaCommonDecoder* decoder); +void irda_common_decoder_reset(IrdaCommonDecoder* decoder); IrdaStatus irda_common_encode(IrdaCommonEncoder* encoder, uint32_t* duration, bool* polarity); IrdaStatus irda_common_encode_pdwm(IrdaCommonEncoder* encoder, uint32_t* duration, bool* polarity); IrdaStatus irda_common_encode_manchester(IrdaCommonEncoder* encoder, uint32_t* duration, bool* polarity); -void irda_common_encoder_set_context(void* decoder, void* context); void* irda_common_encoder_alloc(const IrdaCommonProtocolSpec* protocol); void irda_common_encoder_free(IrdaCommonEncoder* encoder); void irda_common_encoder_reset(IrdaCommonEncoder* encoder); diff --git a/lib/irda/encoder_decoder/common/irda_common_protocol_defs.c b/lib/irda/encoder_decoder/common/irda_common_protocol_defs.c index e516ab0c..75e3b604 100644 --- a/lib/irda/encoder_decoder/common/irda_common_protocol_defs.c +++ b/lib/irda/encoder_decoder/common/irda_common_protocol_defs.c @@ -3,8 +3,8 @@ const IrdaCommonProtocolSpec protocol_nec = { .timings = { - .preamble_mark = IRDA_NEC_PREAMBULE_MARK, - .preamble_space = IRDA_NEC_PREAMBULE_SPACE, + .preamble_mark = IRDA_NEC_PREAMBLE_MARK, + .preamble_space = IRDA_NEC_PREAMBLE_SPACE, .bit1_mark = IRDA_NEC_BIT1_MARK, .bit1_space = IRDA_NEC_BIT1_SPACE, .bit0_mark = IRDA_NEC_BIT0_MARK, @@ -14,7 +14,8 @@ const IrdaCommonProtocolSpec protocol_nec = { .silence_time = IRDA_NEC_SILENCE, }, .databit_len = 32, - .decode = irda_common_decode_pdwm, + .no_stop_bit = false, + .decode = irda_common_decode_pdm, .encode = irda_common_encode_pdwm, .interpret = irda_decoder_nec_interpret, .decode_repeat = irda_decoder_nec_decode_repeat, @@ -23,8 +24,8 @@ const IrdaCommonProtocolSpec protocol_nec = { const IrdaCommonProtocolSpec protocol_samsung32 = { .timings = { - .preamble_mark = IRDA_SAMSUNG_PREAMBULE_MARK, - .preamble_space = IRDA_SAMSUNG_PREAMBULE_SPACE, + .preamble_mark = IRDA_SAMSUNG_PREAMBLE_MARK, + .preamble_space = IRDA_SAMSUNG_PREAMBLE_SPACE, .bit1_mark = IRDA_SAMSUNG_BIT1_MARK, .bit1_space = IRDA_SAMSUNG_BIT1_SPACE, .bit0_mark = IRDA_SAMSUNG_BIT0_MARK, @@ -34,7 +35,8 @@ const IrdaCommonProtocolSpec protocol_samsung32 = { .silence_time = IRDA_SAMSUNG_SILENCE, }, .databit_len = 32, - .decode = irda_common_decode_pdwm, + .no_stop_bit = false, + .decode = irda_common_decode_pdm, .encode = irda_common_encode_pdwm, .interpret = irda_decoder_samsung32_interpret, .decode_repeat = irda_decoder_samsung32_decode_repeat, @@ -43,8 +45,8 @@ const IrdaCommonProtocolSpec protocol_samsung32 = { const IrdaCommonProtocolSpec protocol_rc6 = { .timings = { - .preamble_mark = IRDA_RC6_PREAMBULE_MARK, - .preamble_space = IRDA_RC6_PREAMBULE_SPACE, + .preamble_mark = IRDA_RC6_PREAMBLE_MARK, + .preamble_space = IRDA_RC6_PREAMBLE_SPACE, .bit1_mark = IRDA_RC6_BIT, .preamble_tolerance = IRDA_RC6_PREAMBLE_TOLERANCE, .bit_tolerance = IRDA_RC6_BIT_TOLERANCE, @@ -77,3 +79,24 @@ const IrdaCommonProtocolSpec protocol_rc5 = { .encode_repeat = NULL, }; +const IrdaCommonProtocolSpec protocol_sirc = { + .timings = { + .preamble_mark = IRDA_SIRC_PREAMBLE_MARK, + .preamble_space = IRDA_SIRC_PREAMBLE_SPACE, + .bit1_mark = IRDA_SIRC_BIT1_MARK, + .bit1_space = IRDA_SIRC_BIT1_SPACE, + .bit0_mark = IRDA_SIRC_BIT0_MARK, + .bit0_space = IRDA_SIRC_BIT0_SPACE, + .preamble_tolerance = IRDA_SIRC_PREAMBLE_TOLERANCE, + .bit_tolerance = IRDA_SIRC_BIT_TOLERANCE, + .silence_time = IRDA_SIRC_SILENCE, + }, + .databit_len = 20, /* 12/15/20 */ + .no_stop_bit = true, + .decode = irda_common_decode_pwm, + .encode = irda_common_encode_pdwm, + .interpret = irda_decoder_sirc_interpret, + .decode_repeat = NULL, + .encode_repeat = irda_encoder_sirc_encode_repeat, +}; + diff --git a/lib/irda/encoder_decoder/irda.c b/lib/irda/encoder_decoder/irda.c index 89552030..73bd4f5e 100644 --- a/lib/irda/encoder_decoder/irda.c +++ b/lib/irda/encoder_decoder/irda.c @@ -12,14 +12,15 @@ typedef struct { IrdaAlloc alloc; IrdaDecode decode; - IrdaReset reset; + IrdaDecoderReset reset; IrdaFree free; + IrdaDecoderCheckReady check_ready; } IrdaDecoders; typedef struct { - IrdaEncoderReset reset; IrdaAlloc alloc; IrdaEncode encode; + IrdaEncoderReset reset; IrdaFree free; } IrdaEncoders; @@ -39,19 +40,6 @@ typedef struct { } IrdaEncoderDecoder; static const IrdaEncoderDecoder irda_encoder_decoder[] = { - { - .decoder = { - .alloc = irda_decoder_rc5_alloc, - .decode = irda_decoder_rc5_decode, - .reset = irda_decoder_rc5_reset, - .free = irda_decoder_rc5_free}, - .encoder = { - .alloc = irda_encoder_rc5_alloc, - .encode = irda_encoder_rc5_encode, - .reset = irda_encoder_rc5_reset, - .free = irda_encoder_rc5_free}, - .get_protocol_spec = irda_rc5_get_spec, - }, { .decoder = { .alloc = irda_decoder_nec_alloc, @@ -78,6 +66,19 @@ static const IrdaEncoderDecoder irda_encoder_decoder[] = { .free = irda_encoder_samsung32_free}, .get_protocol_spec = irda_samsung32_get_spec, }, + { + .decoder = { + .alloc = irda_decoder_rc5_alloc, + .decode = irda_decoder_rc5_decode, + .reset = irda_decoder_rc5_reset, + .free = irda_decoder_rc5_free}, + .encoder = { + .alloc = irda_encoder_rc5_alloc, + .encode = irda_encoder_rc5_encode, + .reset = irda_encoder_rc5_reset, + .free = irda_encoder_rc5_free}, + .get_protocol_spec = irda_rc5_get_spec, + }, { .decoder = { .alloc = irda_decoder_rc6_alloc, @@ -91,8 +92,26 @@ static const IrdaEncoderDecoder irda_encoder_decoder[] = { .free = irda_encoder_rc6_free}, .get_protocol_spec = irda_rc6_get_spec, }, + { + .decoder = { + .alloc = irda_decoder_sirc_alloc, + .decode = irda_decoder_sirc_decode, + .reset = irda_decoder_sirc_reset, + .check_ready = irda_decoder_sirc_check_ready, + .free = irda_decoder_sirc_free}, + .encoder = { + .alloc = irda_encoder_sirc_alloc, + .encode = irda_encoder_sirc_encode, + .reset = irda_encoder_sirc_reset, + .free = irda_encoder_sirc_free}, + .get_protocol_spec = irda_sirc_get_spec, + }, }; + +static int irda_find_index_by_protocol(IrdaProtocol protocol); +static const IrdaProtocolSpecification* irda_get_spec_by_protocol(IrdaProtocol protocol); + const IrdaMessage* irda_decode(IrdaDecoderHandler* handler, bool level, uint32_t duration) { furi_assert(handler); @@ -121,6 +140,7 @@ IrdaDecoderHandler* irda_alloc_decoder(void) { handler->ctx[i] = irda_encoder_decoder[i].decoder.alloc(); } + irda_reset_decoder(handler); return handler; } @@ -144,6 +164,25 @@ void irda_reset_decoder(IrdaDecoderHandler* handler) { } } +const IrdaMessage* irda_check_decoder_ready(IrdaDecoderHandler* handler) { + furi_assert(handler); + + IrdaMessage* message = NULL; + IrdaMessage* result = NULL; + + for (int i = 0; i < COUNT_OF(irda_encoder_decoder); ++i) { + if (irda_encoder_decoder[i].decoder.check_ready) { + message = irda_encoder_decoder[i].decoder.check_ready(handler->ctx[i]); + if (!result && message) { + result = message; + } + } + } + + return result; +} + + IrdaEncoderHandler* irda_alloc_encoder(void) { IrdaEncoderHandler* handler = furi_alloc(sizeof(IrdaEncoderHandler)); handler->handler = NULL; diff --git a/lib/irda/encoder_decoder/irda.h b/lib/irda/encoder_decoder/irda.h index d1887e26..25a13528 100644 --- a/lib/irda/encoder_decoder/irda.h +++ b/lib/irda/encoder_decoder/irda.h @@ -15,11 +15,9 @@ extern "C" { #define IRDA_RAW_RX_TIMING_DELAY_US 150000 #define IRDA_RAW_TX_TIMING_DELAY_US 180000 - typedef struct IrdaDecoderHandler IrdaDecoderHandler; typedef struct IrdaEncoderHandler IrdaEncoderHandler; -// Do not change protocol order, as it can be saved into memory and fw update can be performed! typedef enum { IrdaProtocolUnknown = -1, IrdaProtocolNEC = 0, @@ -28,6 +26,9 @@ typedef enum { IrdaProtocolRC6 = 3, IrdaProtocolRC5 = 4, IrdaProtocolRC5X = 5, + IrdaProtocolSIRC = 6, + IrdaProtocolSIRC15 = 7, + IrdaProtocolSIRC20 = 8, IrdaProtocolMAX, } IrdaProtocol; @@ -62,10 +63,27 @@ IrdaDecoderHandler* irda_alloc_decoder(void); * \param[in] duration - duration of steady high/low input signal. * \return if message is ready, returns pointer to decoded message, returns NULL. * Note: ownership of returned ptr belongs to handler. So pointer is valid - * up to next irda_free_decoder(), irda_reset_decoder(), irda_decode() calls. + * up to next irda_free_decoder(), irda_reset_decoder(), + * irda_decode(), irda_check_decoder_ready() calls. */ const IrdaMessage* irda_decode(IrdaDecoderHandler* handler, bool level, uint32_t duration); +/** + * Check whether decoder is ready. + * Functionality is quite similar to irda_decode(), but with no timing providing. + * Some protocols (e.g. Sony SIRC) has variable payload length, which means we + * can't recognize end of message right after receiving last bit. That's why + * application should call to irda_check_decoder_ready() after some timeout to + * retrieve decoded message, if so. + * + * \param[in] handler - handler to IRDA decoders. Should be acquired with \c irda_alloc_decoder(). + * \return if message is ready, returns pointer to decoded message, returns NULL. + * Note: ownership of returned ptr belongs to handler. So pointer is valid + * up to next irda_free_decoder(), irda_reset_decoder(), + * irda_decode(), irda_check_decoder_ready() calls. + */ +const IrdaMessage* irda_check_decoder_ready(IrdaDecoderHandler* handler); + /** * Deinitialize decoder and free allocated memory. * @@ -100,7 +118,7 @@ IrdaProtocol irda_get_protocol_by_name(const char* protocol_name); * Get address length by protocol enum. * * \param[in] protocol - protocol identifier. - * \return length of address in nibbles. + * \return length of address in bits. */ uint8_t irda_get_protocol_address_length(IrdaProtocol protocol); @@ -108,7 +126,7 @@ uint8_t irda_get_protocol_address_length(IrdaProtocol protocol); * Get command length by protocol enum. * * \param[in] protocol - protocol identifier. - * \return length of command in nibbles. + * \return length of command in bits. */ uint8_t irda_get_protocol_command_length(IrdaProtocol protocol); diff --git a/lib/irda/encoder_decoder/irda_i.h b/lib/irda/encoder_decoder/irda_i.h index 4ca194a8..c147b3db 100644 --- a/lib/irda/encoder_decoder/irda_i.h +++ b/lib/irda/encoder_decoder/irda_i.h @@ -1,6 +1,7 @@ #pragma once #include "irda.h" #include +#include typedef struct { uint32_t silence_time; @@ -10,7 +11,7 @@ typedef struct { uint16_t bit1_space; uint16_t bit0_mark; uint16_t bit0_space; - float preamble_tolerance; + uint32_t preamble_tolerance; uint32_t bit_tolerance; } IrdaTimings; @@ -25,10 +26,12 @@ typedef struct { typedef const IrdaProtocolSpecification* (*IrdaGetProtocolSpec) (IrdaProtocol protocol); typedef void* (*IrdaAlloc) (void); -typedef IrdaMessage* (*IrdaDecode) (void* ctx, bool level, uint32_t duration); -typedef void (*IrdaReset) (void*); typedef void (*IrdaFree) (void*); +typedef void (*IrdaDecoderReset) (void*); +typedef IrdaMessage* (*IrdaDecode) (void* ctx, bool level, uint32_t duration); +typedef IrdaMessage* (*IrdaDecoderCheckReady) (void*); + typedef void (*IrdaEncoderReset)(void* encoder, const IrdaMessage* message); typedef IrdaStatus (*IrdaEncode)(void* encoder, uint32_t* out, bool* polarity); diff --git a/lib/irda/encoder_decoder/irda_protocol_defs_i.h b/lib/irda/encoder_decoder/irda_protocol_defs_i.h index 43703ea9..15d9fea2 100644 --- a/lib/irda/encoder_decoder/irda_protocol_defs_i.h +++ b/lib/irda/encoder_decoder/irda_protocol_defs_i.h @@ -11,29 +11,28 @@ * https://radioparty.ru/manuals/encyclopedia/213-ircontrol?start=1 **************************************************************************************************** * Preamble Preamble Pulse Distance/Width Pause Preamble Preamble Stop -* mark space Modulation repeat repeat bit +* mark space Modulation up to period repeat repeat bit * mark space * -* 9000 4500 32 bit + stop bit 40000/100000 9000 2250 +* 9000 4500 32 bit + stop bit ...110000 9000 2250 * __________ _ _ _ _ _ _ _ _ _ _ _ _ _ ___________ _ * ____ __________ _ _ _ __ __ __ _ _ __ __ _ _ ________________ ____________ ___ * ***************************************************************************************************/ -#define IRDA_NEC_PREAMBULE_MARK 9000 -#define IRDA_NEC_PREAMBULE_SPACE 4500 +#define IRDA_NEC_PREAMBLE_MARK 9000 +#define IRDA_NEC_PREAMBLE_SPACE 4500 #define IRDA_NEC_BIT1_MARK 560 #define IRDA_NEC_BIT1_SPACE 1600 #define IRDA_NEC_BIT0_MARK 560 #define IRDA_NEC_BIT0_SPACE 560 +#define IRDA_NEC_REPEAT_PERIOD 110000 +#define IRDA_NEC_SILENCE IRDA_NEC_REPEAT_PERIOD #define IRDA_NEC_REPEAT_PAUSE_MIN 30000 -#define IRDA_NEC_REPEAT_PAUSE1 46000 -#define IRDA_NEC_REPEAT_PAUSE2 97000 -#define IRDA_NEC_SILENCE IRDA_NEC_REPEAT_PAUSE2 #define IRDA_NEC_REPEAT_PAUSE_MAX 150000 #define IRDA_NEC_REPEAT_MARK 9000 #define IRDA_NEC_REPEAT_SPACE 2250 -#define IRDA_NEC_PREAMBLE_TOLERANCE 0.07 // percents +#define IRDA_NEC_PREAMBLE_TOLERANCE 200 // us #define IRDA_NEC_BIT_TOLERANCE 120 // us void* irda_decoder_nec_alloc(void); @@ -66,8 +65,8 @@ extern const IrdaCommonProtocolSpec protocol_nec; * ***************************************************************************************************/ -#define IRDA_SAMSUNG_PREAMBULE_MARK 4500 -#define IRDA_SAMSUNG_PREAMBULE_SPACE 4500 +#define IRDA_SAMSUNG_PREAMBLE_MARK 4500 +#define IRDA_SAMSUNG_PREAMBLE_SPACE 4500 #define IRDA_SAMSUNG_BIT1_MARK 550 #define IRDA_SAMSUNG_BIT1_SPACE 1650 #define IRDA_SAMSUNG_BIT0_MARK 550 @@ -84,7 +83,7 @@ extern const IrdaCommonProtocolSpec protocol_nec; #define IRDA_SAMSUNG_REPEAT_PAUSE_MAX 140000 #define IRDA_SAMSUNG_REPEAT_MARK 4500 #define IRDA_SAMSUNG_REPEAT_SPACE 4500 -#define IRDA_SAMSUNG_PREAMBLE_TOLERANCE 0.07 // percents +#define IRDA_SAMSUNG_PREAMBLE_TOLERANCE 200 // us #define IRDA_SAMSUNG_BIT_TOLERANCE 120 // us void* irda_decoder_samsung32_alloc(void); @@ -127,10 +126,10 @@ extern const IrdaCommonProtocolSpec protocol_samsung32; #define IRDA_RC6_CARRIER_FREQUENCY 36000 #define IRDA_RC6_DUTY_CYCLE 0.33 -#define IRDA_RC6_PREAMBULE_MARK 2666 -#define IRDA_RC6_PREAMBULE_SPACE 889 +#define IRDA_RC6_PREAMBLE_MARK 2666 +#define IRDA_RC6_PREAMBLE_SPACE 889 #define IRDA_RC6_BIT 444 // half of time-quant for 1 bit -#define IRDA_RC6_PREAMBLE_TOLERANCE 0.07 // percents +#define IRDA_RC6_PREAMBLE_TOLERANCE 200 // us #define IRDA_RC6_BIT_TOLERANCE 120 // us /* protocol allows 2700 silence, but it is hard to send 1 message without repeat */ #define IRDA_RC6_SILENCE (2700 * 10) @@ -169,17 +168,17 @@ extern const IrdaCommonProtocolSpec protocol_rc6; * s - start bit (always 1) * si - RC5: start bit (always 1), RC5X - 7-th bit of address (in our case always 0) * T - toggle bit, change it's value every button press -* address - 8 bit -* command - 8 bit +* address - 5 bit +* command - 6/7 bit ***************************************************************************************************/ #define IRDA_RC5_CARRIER_FREQUENCY 36000 #define IRDA_RC5_DUTY_CYCLE 0.33 -#define IRDA_RC5_PREAMBULE_MARK 0 -#define IRDA_RC5_PREAMBULE_SPACE 0 +#define IRDA_RC5_PREAMBLE_MARK 0 +#define IRDA_RC5_PREAMBLE_SPACE 0 #define IRDA_RC5_BIT 888 // half of time-quant for 1 bit -#define IRDA_RC5_PREAMBLE_TOLERANCE 0.07 // percents +#define IRDA_RC5_PREAMBLE_TOLERANCE 200 // us #define IRDA_RC5_BIT_TOLERANCE 120 // us /* protocol allows 2700 silence, but it is hard to send 1 message without repeat */ #define IRDA_RC5_SILENCE (2700 * 10) @@ -197,3 +196,56 @@ const IrdaProtocolSpecification* irda_rc5_get_spec(IrdaProtocol protocol); extern const IrdaCommonProtocolSpec protocol_rc5; + +/*************************************************************************************************** +* Sony SIRC protocol description +* https://www.sbprojects.net/knowledge/ir/sirc.php +* http://picprojects.org.uk/ +**************************************************************************************************** +* Preamble Preamble Pulse Width Modulation Pause Entirely repeat +* mark space up to period message.. +* +* 2400 600 12/15/20 bits (600,1200) ...45000 2400 600 +* __________ _ _ _ _ _ _ _ _ _ _ _ _ _ __________ _ _ +* ____ __________ _ _ _ __ __ __ _ _ __ __ _ _ ____________________ __________ _ +* | command | address | +* SIRC | 7b LSB | 5b LSB | +* SIRC15 | 7b LSB | 8b LSB | +* SIRC20 | 7b LSB | 13b LSB | +* +* No way to determine either next message is repeat or not, +* so recognize only fact message received. Sony remotes always send at least 3 messages. +* Assume 8 last extended bits for SIRC20 are address bits. +***************************************************************************************************/ + +#define IRDA_SIRC_CARRIER_FREQUENCY 40000 +#define IRDA_SIRC_DUTY_CYCLE 0.33 +#define IRDA_SIRC_PREAMBLE_MARK 2400 +#define IRDA_SIRC_PREAMBLE_SPACE 600 +#define IRDA_SIRC_BIT1_MARK 1200 +#define IRDA_SIRC_BIT1_SPACE 600 +#define IRDA_SIRC_BIT0_MARK 600 +#define IRDA_SIRC_BIT0_SPACE 600 +#define IRDA_SIRC_PREAMBLE_TOLERANCE 200 // us +#define IRDA_SIRC_BIT_TOLERANCE 120 // us +#define IRDA_SIRC_SILENCE 10000 +#define IRDA_SIRC_MIN_SILENCE (IRDA_SIRC_SILENCE - 1000) +#define IRDA_SIRC_REPEAT_PERIOD 45000 + + +void* irda_decoder_sirc_alloc(void); +void irda_decoder_sirc_reset(void* decoder); +IrdaMessage* irda_decoder_sirc_check_ready(void* decoder); +uint32_t irda_decoder_sirc_get_timeout(void* decoder); +void irda_decoder_sirc_free(void* decoder); +IrdaMessage* irda_decoder_sirc_decode(void* decoder, bool level, uint32_t duration); +void* irda_encoder_sirc_alloc(void); +void irda_encoder_sirc_reset(void* encoder_ptr, const IrdaMessage* message); +void irda_encoder_sirc_free(void* decoder); +IrdaStatus irda_encoder_sirc_encode(void* encoder_ptr, uint32_t* duration, bool* polarity); +bool irda_decoder_sirc_interpret(IrdaCommonDecoder* decoder); +const IrdaProtocolSpecification* irda_sirc_get_spec(IrdaProtocol protocol); +IrdaStatus irda_encoder_sirc_encode_repeat(IrdaCommonEncoder* encoder, uint32_t* duration, bool* level); + +extern const IrdaCommonProtocolSpec protocol_sirc; + diff --git a/lib/irda/encoder_decoder/nec/irda_decoder_nec.c b/lib/irda/encoder_decoder/nec/irda_decoder_nec.c index aaea7ec5..79a85d76 100644 --- a/lib/irda/encoder_decoder/nec/irda_decoder_nec.c +++ b/lib/irda/encoder_decoder/nec/irda_decoder_nec.c @@ -43,9 +43,9 @@ IrdaStatus irda_decoder_nec_decode_repeat(IrdaCommonDecoder* decoder) { if((decoder->timings[0] > IRDA_NEC_REPEAT_PAUSE_MIN) && (decoder->timings[0] < IRDA_NEC_REPEAT_PAUSE_MAX) && - MATCH_PREAMBLE_TIMING(decoder->timings[1], IRDA_NEC_REPEAT_MARK, preamble_tolerance) && - MATCH_PREAMBLE_TIMING(decoder->timings[2], IRDA_NEC_REPEAT_SPACE, preamble_tolerance) && - MATCH_BIT_TIMING(decoder->timings[3], decoder->protocol->timings.bit1_mark, bit_tolerance)) { + MATCH_TIMING(decoder->timings[1], IRDA_NEC_REPEAT_MARK, preamble_tolerance) && + MATCH_TIMING(decoder->timings[2], IRDA_NEC_REPEAT_SPACE, preamble_tolerance) && + MATCH_TIMING(decoder->timings[3], decoder->protocol->timings.bit1_mark, bit_tolerance)) { status = IrdaStatusReady; decoder->timings_cnt = 0; } else { diff --git a/lib/irda/encoder_decoder/nec/irda_encoder_nec.c b/lib/irda/encoder_decoder/nec/irda_encoder_nec.c index 8bf2dfd5..b6551b77 100644 --- a/lib/irda/encoder_decoder/nec/irda_encoder_nec.c +++ b/lib/irda/encoder_decoder/nec/irda_encoder_nec.c @@ -7,7 +7,7 @@ #include static const uint32_t repeat_timings[] = { - IRDA_NEC_REPEAT_PAUSE2, + IRDA_NEC_REPEAT_PERIOD - IRDA_NEC_REPEAT_MARK - IRDA_NEC_REPEAT_SPACE - IRDA_NEC_BIT1_MARK, IRDA_NEC_REPEAT_MARK, IRDA_NEC_REPEAT_SPACE, IRDA_NEC_BIT1_MARK, @@ -44,10 +44,11 @@ IrdaStatus irda_encoder_nec_encode_repeat(IrdaCommonEncoder* encoder, uint32_t* furi_assert(encoder->timings_encoded >= timings_encoded_up_to_repeat); - if (repeat_cnt > 0) + if (repeat_cnt > 0) { *duration = repeat_timings[repeat_cnt % COUNT_OF(repeat_timings)]; - else - *duration = IRDA_NEC_REPEAT_PAUSE1; + } else { + *duration = IRDA_NEC_REPEAT_PERIOD - encoder->timings_sum; + } *level = repeat_cnt % 2; ++encoder->timings_encoded; diff --git a/lib/irda/encoder_decoder/nec/irda_nec_spec.c b/lib/irda/encoder_decoder/nec/irda_nec_spec.c index 707e3595..9c27b69a 100644 --- a/lib/irda/encoder_decoder/nec/irda_nec_spec.c +++ b/lib/irda/encoder_decoder/nec/irda_nec_spec.c @@ -3,16 +3,16 @@ static const IrdaProtocolSpecification irda_nec_protocol_specification = { .name = "NEC", - .address_length = 2, - .command_length = 2, + .address_length = 8, + .command_length = 8, .frequency = IRDA_COMMON_CARRIER_FREQUENCY, .duty_cycle = IRDA_COMMON_DUTY_CYCLE, }; static const IrdaProtocolSpecification irda_necext_protocol_specification = { .name = "NECext", - .address_length = 4, - .command_length = 2, + .address_length = 16, + .command_length = 8, .frequency = IRDA_COMMON_CARRIER_FREQUENCY, .duty_cycle = IRDA_COMMON_DUTY_CYCLE, }; diff --git a/lib/irda/encoder_decoder/rc5/irda_decoder_rc5.c b/lib/irda/encoder_decoder/rc5/irda_decoder_rc5.c index 704dc5ae..6843b283 100644 --- a/lib/irda/encoder_decoder/rc5/irda_decoder_rc5.c +++ b/lib/irda/encoder_decoder/rc5/irda_decoder_rc5.c @@ -57,7 +57,7 @@ void* irda_decoder_rc5_alloc(void) { IrdaRc5Decoder* decoder = furi_alloc(sizeof(IrdaRc5Decoder)); decoder->toggle = false; decoder->common_decoder = irda_common_decoder_alloc(&protocol_rc5); - irda_common_decoder_set_context(decoder->common_decoder, decoder); + decoder->common_decoder->context = decoder; return decoder; } diff --git a/lib/irda/encoder_decoder/rc5/irda_rc5_spec.c b/lib/irda/encoder_decoder/rc5/irda_rc5_spec.c index 565b328c..6da80df9 100644 --- a/lib/irda/encoder_decoder/rc5/irda_rc5_spec.c +++ b/lib/irda/encoder_decoder/rc5/irda_rc5_spec.c @@ -3,16 +3,16 @@ static const IrdaProtocolSpecification irda_rc5_protocol_specification = { .name = "RC5", - .address_length = 2, - .command_length = 2, + .address_length = 5, + .command_length = 6, .frequency = IRDA_RC5_CARRIER_FREQUENCY, .duty_cycle = IRDA_RC5_DUTY_CYCLE, }; static const IrdaProtocolSpecification irda_rc5x_protocol_specification = { .name = "RC5X", - .address_length = 2, - .command_length = 2, + .address_length = 5, + .command_length = 7, .frequency = IRDA_RC5_CARRIER_FREQUENCY, .duty_cycle = IRDA_RC5_DUTY_CYCLE, }; diff --git a/lib/irda/encoder_decoder/rc6/irda_decoder_rc6.c b/lib/irda/encoder_decoder/rc6/irda_decoder_rc6.c index d561adad..9bab9da0 100644 --- a/lib/irda/encoder_decoder/rc6/irda_decoder_rc6.c +++ b/lib/irda/encoder_decoder/rc6/irda_decoder_rc6.c @@ -57,9 +57,9 @@ IrdaStatus irda_decoder_rc6_decode_manchester(IrdaCommonDecoder* decoder) { uint16_t tolerance = decoder->protocol->timings.bit_tolerance; uint16_t timing = decoder->timings[0]; - bool single_timing = MATCH_BIT_TIMING(timing, bit, tolerance); - bool double_timing = MATCH_BIT_TIMING(timing, 2*bit, tolerance); - bool triple_timing = MATCH_BIT_TIMING(timing, 3*bit, tolerance); + bool single_timing = MATCH_TIMING(timing, bit, tolerance); + bool double_timing = MATCH_TIMING(timing, 2*bit, tolerance); + bool triple_timing = MATCH_TIMING(timing, 3*bit, tolerance); if (decoder->databit_cnt == 4) { furi_assert(decoder->timings_cnt == 1); @@ -92,7 +92,7 @@ void* irda_decoder_rc6_alloc(void) { IrdaRc6Decoder* decoder = furi_alloc(sizeof(IrdaRc6Decoder)); decoder->toggle = false; decoder->common_decoder = irda_common_decoder_alloc(&protocol_rc6); - irda_common_decoder_set_context(decoder->common_decoder, decoder); + decoder->common_decoder->context = decoder; return decoder; } diff --git a/lib/irda/encoder_decoder/rc6/irda_rc6_spec.c b/lib/irda/encoder_decoder/rc6/irda_rc6_spec.c index bd7977c5..a6ea579d 100644 --- a/lib/irda/encoder_decoder/rc6/irda_rc6_spec.c +++ b/lib/irda/encoder_decoder/rc6/irda_rc6_spec.c @@ -3,8 +3,8 @@ static const IrdaProtocolSpecification irda_rc6_protocol_specification = { .name = "RC6", - .address_length = 2, - .command_length = 2, + .address_length = 8, + .command_length = 8, .frequency = IRDA_RC6_CARRIER_FREQUENCY, .duty_cycle = IRDA_RC6_DUTY_CYCLE, }; diff --git a/lib/irda/encoder_decoder/samsung/irda_decoder_samsung.c b/lib/irda/encoder_decoder/samsung/irda_decoder_samsung.c index 1a92de41..d7640f3d 100644 --- a/lib/irda/encoder_decoder/samsung/irda_decoder_samsung.c +++ b/lib/irda/encoder_decoder/samsung/irda_decoder_samsung.c @@ -39,11 +39,11 @@ IrdaStatus irda_decoder_samsung32_decode_repeat(IrdaCommonDecoder* decoder) { if ((decoder->timings[0] > IRDA_SAMSUNG_REPEAT_PAUSE_MIN) && (decoder->timings[0] < IRDA_SAMSUNG_REPEAT_PAUSE_MAX) - && MATCH_PREAMBLE_TIMING(decoder->timings[1], IRDA_SAMSUNG_REPEAT_MARK, preamble_tolerance) - && MATCH_PREAMBLE_TIMING(decoder->timings[2], IRDA_SAMSUNG_REPEAT_SPACE, preamble_tolerance) - && MATCH_BIT_TIMING(decoder->timings[3], decoder->protocol->timings.bit1_mark, bit_tolerance) - && MATCH_BIT_TIMING(decoder->timings[4], decoder->protocol->timings.bit1_space, bit_tolerance) - && MATCH_BIT_TIMING(decoder->timings[5], decoder->protocol->timings.bit1_mark, bit_tolerance) + && MATCH_TIMING(decoder->timings[1], IRDA_SAMSUNG_REPEAT_MARK, preamble_tolerance) + && MATCH_TIMING(decoder->timings[2], IRDA_SAMSUNG_REPEAT_SPACE, preamble_tolerance) + && MATCH_TIMING(decoder->timings[3], decoder->protocol->timings.bit1_mark, bit_tolerance) + && MATCH_TIMING(decoder->timings[4], decoder->protocol->timings.bit1_space, bit_tolerance) + && MATCH_TIMING(decoder->timings[5], decoder->protocol->timings.bit1_mark, bit_tolerance) ) { status = IrdaStatusReady; decoder->timings_cnt = 0; diff --git a/lib/irda/encoder_decoder/samsung/irda_samsung_spec.c b/lib/irda/encoder_decoder/samsung/irda_samsung_spec.c index 2043ce0a..e4c641a1 100644 --- a/lib/irda/encoder_decoder/samsung/irda_samsung_spec.c +++ b/lib/irda/encoder_decoder/samsung/irda_samsung_spec.c @@ -3,8 +3,8 @@ static const IrdaProtocolSpecification irda_samsung32_protocol_specification = { .name = "Samsung32", - .address_length = 2, - .command_length = 2, + .address_length = 8, + .command_length = 8, .frequency = IRDA_COMMON_CARRIER_FREQUENCY, .duty_cycle = IRDA_COMMON_DUTY_CYCLE, }; diff --git a/lib/irda/encoder_decoder/sirc/irda_decoder_sirc.c b/lib/irda/encoder_decoder/sirc/irda_decoder_sirc.c new file mode 100644 index 00000000..2ae76863 --- /dev/null +++ b/lib/irda/encoder_decoder/sirc/irda_decoder_sirc.c @@ -0,0 +1,92 @@ +#include "common/irda_common_i.h" +#include "irda.h" +#include "irda_protocol_defs_i.h" +#include +#include +#include +#include "../irda_i.h" + + +IrdaMessage* irda_decoder_sirc_check_ready(void* ctx) { + IrdaMessage* message = NULL; + IrdaCommonDecoder* decoder = ctx; + + if (irda_decoder_sirc_interpret(decoder)) { + message = &decoder->message; + decoder->timings_cnt = 0; + decoder->databit_cnt = 0; + } + + return message; +} + +bool irda_decoder_sirc_interpret(IrdaCommonDecoder* decoder) { + furi_assert(decoder); + + uint32_t* data = (void*) &decoder->data[0]; + uint16_t address = 0; + uint8_t command = 0; + IrdaProtocol protocol = IrdaProtocolUnknown; + + if (decoder->databit_cnt == 12) { + address = (*data >> 7) & 0x1F; + command = *data & 0x7F; + protocol = IrdaProtocolSIRC; + } else if (decoder->databit_cnt == 15) { + address = (*data >> 7) & 0xFF; + command = *data & 0x7F; + protocol = IrdaProtocolSIRC15; + } else if (decoder->databit_cnt == 20) { + address = (*data >> 7) & 0x1FFF; + command = *data & 0x7F; + protocol = IrdaProtocolSIRC20; + } else { + return false; + } + + decoder->message.protocol = protocol; + decoder->message.address = address; + decoder->message.command = command; + /* SIRC doesn't specify repeat detection */ + decoder->message.repeat = false; + + return true; +} + +void* irda_decoder_sirc_alloc(void) { + return irda_common_decoder_alloc(&protocol_sirc); +} + +IrdaMessage* irda_decoder_sirc_decode(void* context, bool level, uint32_t duration) { + IrdaCommonDecoder* decoder = context; + IrdaMessage* message = NULL; + + if ((decoder->databit_cnt == 12) || (decoder->databit_cnt == 15)) { + if (!level && (duration >= IRDA_SIRC_MIN_SILENCE)) { + if (irda_decoder_sirc_interpret(decoder)) { + message = &decoder->message; + decoder->timings_cnt = 0; + decoder->databit_cnt = 0; + } + } + } + + if (!message) { + message = irda_common_decode(decoder, level, duration); + if (message) { /* 20 bit */ + decoder->timings_cnt = 0; + decoder->databit_cnt = 0; + } + } + + return message; +} + +void irda_decoder_sirc_free(void* decoder) { + irda_common_decoder_free(decoder); +} + +void irda_decoder_sirc_reset(void* decoder) { + irda_common_decoder_reset(decoder); +} + diff --git a/lib/irda/encoder_decoder/sirc/irda_encoder_sirc.c b/lib/irda/encoder_decoder/sirc/irda_encoder_sirc.c new file mode 100644 index 00000000..d6cd54cf --- /dev/null +++ b/lib/irda/encoder_decoder/sirc/irda_encoder_sirc.c @@ -0,0 +1,89 @@ +#include "furi/check.h" +#include "irda.h" +#include "common/irda_common_i.h" +#include +#include "../irda_i.h" +#include "irda_protocol_defs_i.h" +#include + + +typedef struct { + IrdaCommonEncoder* common_encoder; + uint8_t databits; +} IrdaSircEncoder; + + +void irda_encoder_sirc_reset(void* encoder_ptr, const IrdaMessage* message) { + furi_assert(encoder_ptr); + furi_assert(message); + + IrdaCommonEncoder* encoder = encoder_ptr; + IrdaSircEncoder* encoder_sirc = encoder->context; + irda_common_encoder_reset(encoder); + + uint32_t* data = (void*) encoder->data; + + if (message->protocol == IrdaProtocolSIRC) { + encoder_sirc->databits = 12; + *data = (message->command & 0x7F); + *data |= (message->address & 0x1F) << 7; + } else if (message->protocol == IrdaProtocolSIRC15) { + encoder_sirc->databits = 15; + *data = (message->command & 0x7F); + *data |= (message->address & 0xFF) << 7; + } else if (message->protocol == IrdaProtocolSIRC20) { + encoder_sirc->databits = 20; + *data = (message->command & 0x7F); + *data |= (message->address & 0x1FFF) << 7; + } else { + furi_assert(0); + } +} + +IrdaStatus irda_encoder_sirc_encode_repeat(IrdaCommonEncoder* encoder, uint32_t* duration, bool* level) { + furi_assert(encoder); + + IrdaSircEncoder* encoder_sirc = encoder->context; + + uint32_t timings_in_message = 1 + 2 + encoder_sirc->databits * 2; + furi_assert(encoder->timings_encoded == timings_in_message); + + furi_assert(encoder->timings_sum < IRDA_SIRC_REPEAT_PERIOD); + *duration = IRDA_SIRC_REPEAT_PERIOD - encoder->timings_sum; + *level = false; + + encoder->timings_sum = 0; + encoder->timings_encoded = 1; + encoder->bits_encoded = 0; + encoder->state = IrdaCommonEncoderStatePreamble; + + return IrdaStatusOk; +} + +void* irda_encoder_sirc_alloc(void) { + IrdaCommonEncoder* encoder_common = irda_common_encoder_alloc(&protocol_sirc); + IrdaSircEncoder* encoder_sirc = furi_alloc(sizeof(IrdaSircEncoder)); + encoder_sirc->common_encoder = encoder_common; + encoder_common->context = encoder_sirc; + return encoder_common; +} + +void irda_encoder_sirc_free(void* encoder_ptr) { + IrdaCommonEncoder* encoder = encoder_ptr; + free(encoder->context); + irda_common_encoder_free(encoder); +} + +IrdaStatus irda_encoder_sirc_encode(void* encoder_ptr, uint32_t* duration, bool* level) { + IrdaCommonEncoder* encoder_common = encoder_ptr; + IrdaSircEncoder* encoder_sirc = encoder_common->context; + + IrdaStatus status = irda_common_encode(encoder_ptr, duration, level); + if ((status == IrdaStatusOk) && (encoder_common->bits_encoded == encoder_sirc->databits)) { + furi_assert(!*level); + status = IrdaStatusDone; + encoder_common->state = IrdaCommonEncoderStateEncodeRepeat; + } + return status; +} + diff --git a/lib/irda/encoder_decoder/sirc/irda_sirc_spec.c b/lib/irda/encoder_decoder/sirc/irda_sirc_spec.c new file mode 100644 index 00000000..8c9fdcc5 --- /dev/null +++ b/lib/irda/encoder_decoder/sirc/irda_sirc_spec.c @@ -0,0 +1,38 @@ +#include "../irda_i.h" +#include "irda_protocol_defs_i.h" + +static const IrdaProtocolSpecification irda_sirc_protocol_specification = { + .name = "SIRC", + .address_length = 5, + .command_length = 7, + .frequency = IRDA_SIRC_CARRIER_FREQUENCY, + .duty_cycle = IRDA_SIRC_DUTY_CYCLE, +}; + +static const IrdaProtocolSpecification irda_sirc15_protocol_specification = { + .name = "SIRC15", + .address_length = 8, + .command_length = 7, + .frequency = IRDA_SIRC_CARRIER_FREQUENCY, + .duty_cycle = IRDA_SIRC_DUTY_CYCLE, +}; + +static const IrdaProtocolSpecification irda_sirc20_protocol_specification = { + .name = "SIRC20", + .address_length = 13, + .command_length = 7, + .frequency = IRDA_SIRC_CARRIER_FREQUENCY, + .duty_cycle = IRDA_SIRC_DUTY_CYCLE, +}; + +const IrdaProtocolSpecification* irda_sirc_get_spec(IrdaProtocol protocol) { + if (protocol == IrdaProtocolSIRC) + return &irda_sirc_protocol_specification; + else if (protocol == IrdaProtocolSIRC15) + return &irda_sirc15_protocol_specification; + else if (protocol == IrdaProtocolSIRC20) + return &irda_sirc20_protocol_specification; + else + return NULL; +} + diff --git a/lib/irda/worker/irda_worker.c b/lib/irda/worker/irda_worker.c index 6d4f0f4b..98b091f4 100644 --- a/lib/irda/worker/irda_worker.c +++ b/lib/irda/worker/irda_worker.c @@ -118,7 +118,14 @@ static void irda_worker_process_timeout(IrdaWorker* instance) { if (instance->signal.timings_cnt < 2) return; - instance->signal.decoded = false; + const IrdaMessage* message_decoded = irda_check_decoder_ready(instance->irda_decoder); + if (message_decoded) { + instance->signal.message = *message_decoded; + instance->signal.timings_cnt = 0; + instance->signal.decoded = true; + } else { + instance->signal.decoded = false; + } if (instance->rx.received_signal_callback) instance->rx.received_signal_callback(instance->rx.received_signal_context, &instance->signal); } @@ -132,7 +139,7 @@ static void irda_worker_process_timings(IrdaWorker* instance, uint32_t duration, if (instance->rx.received_signal_callback) instance->rx.received_signal_callback(instance->rx.received_signal_context, &instance->signal); } else { - /* Skip first timing if it's starts from Space */ + /* Skip first timing if it starts from Space */ if ((instance->signal.timings_cnt == 0) && !level) { return; } @@ -253,6 +260,7 @@ void irda_worker_rx_start(IrdaWorker* instance) { furi_hal_irda_async_rx_start(); furi_hal_irda_async_rx_set_timeout(IRDA_WORKER_RX_TIMEOUT); + instance->rx.overrun = false; instance->state = IrdaWorkerStateRunRx; } From f385340b2e9470026438ba1a345d29bf921989fe Mon Sep 17 00:00:00 2001 From: Skorpionm <85568270+Skorpionm@users.noreply.github.com> Date: Fri, 10 Sep 2021 04:29:57 +0400 Subject: [PATCH 04/13] [FL-1758] SubGhz refactoring part 1 (#689) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * SubGhz: refactoring * WeGet: Add support for outputting formatted lines, events center button pressed, center button released * Variable Item: slightly changed the display of data on the screen * SubGhz: add show errors, add show preset, refactoring * SubGhz: refactoring transmitter * SubGhz: removed unused modules * SubGhz: Add FuriHalSubGhzPresetOok270Async setting menu * SubGhz: fix annotation * SubGhz: add support Nero Radio Co-authored-by: あく --- applications/gui/modules/variable-item-list.c | 19 +- applications/gui/modules/variable-item-list.h | 3 + applications/gui/modules/widget.c | 14 + applications/gui/modules/widget.h | 17 + .../widget_elements/widget_element_button.c | 13 +- .../widget_elements/widget_element_i.h | 11 + .../widget_element_string_multi.c | 67 ++ .../subghz/scenes/subghz_scene_config.h | 4 +- .../subghz/scenes/subghz_scene_receiver.c | 143 +++- .../scenes/subghz_scene_receiver_config.c | 156 ++++ .../scenes/subghz_scene_receiver_info.c | 163 +++++ .../subghz/scenes/subghz_scene_save_name.c | 6 +- .../subghz/scenes/subghz_scene_set_type.c | 64 +- ...ene_no_man.c => subghz_scene_show_error.c} | 13 +- .../subghz/scenes/subghz_scene_transmitter.c | 86 ++- applications/subghz/subghz.c | 92 ++- applications/subghz/subghz_history.c | 13 +- applications/subghz/subghz_history.h | 12 +- applications/subghz/subghz_i.c | 131 +++- applications/subghz/subghz_i.h | 53 +- applications/subghz/views/subghz_receiver.c | 669 ++++-------------- applications/subghz/views/subghz_receiver.h | 30 +- .../subghz/views/subghz_transmitter.c | 116 +-- .../subghz/views/subghz_transmitter.h | 12 +- lib/subghz/protocols/subghz_protocol.c | 13 +- .../protocols/subghz_protocol_gate_tx.h | 2 +- lib/subghz/protocols/subghz_protocol_keeloq.c | 6 +- lib/subghz/protocols/subghz_protocol_keeloq.h | 2 +- .../protocols/subghz_protocol_nero_radio.c | 280 ++++++++ .../protocols/subghz_protocol_nero_radio.h | 72 ++ .../protocols/subghz_protocol_nero_sketch.h | 2 +- .../protocols/subghz_protocol_nice_flo.h | 2 +- .../protocols/subghz_protocol_princeton.c | 2 +- .../protocols/subghz_protocol_star_line.c | 6 +- 34 files changed, 1493 insertions(+), 801 deletions(-) create mode 100644 applications/gui/modules/widget_elements/widget_element_string_multi.c create mode 100644 applications/subghz/scenes/subghz_scene_receiver_config.c create mode 100644 applications/subghz/scenes/subghz_scene_receiver_info.c rename applications/subghz/scenes/{subghz_scene_no_man.c => subghz_scene_show_error.c} (72%) create mode 100644 lib/subghz/protocols/subghz_protocol_nero_radio.c create mode 100644 lib/subghz/protocols/subghz_protocol_nero_radio.h diff --git a/applications/gui/modules/variable-item-list.c b/applications/gui/modules/variable-item-list.c index 3ccac4ae..1879353f 100644 --- a/applications/gui/modules/variable-item-list.c +++ b/applications/gui/modules/variable-item-list.c @@ -68,10 +68,10 @@ static void variable_item_list_draw_callback(Canvas* canvas, void* _model) { canvas_draw_str(canvas, 73, item_text_y, "<"); } - canvas_draw_str(canvas, 84, item_text_y, string_get_cstr(item->current_value_text)); + canvas_draw_str(canvas, 80, item_text_y, string_get_cstr(item->current_value_text)); if(item->current_value_index < (item->values_count - 1)) { - canvas_draw_str(canvas, 113, item_text_y, ">"); + canvas_draw_str(canvas, 115, item_text_y, ">"); } } @@ -235,6 +235,21 @@ void variable_item_list_free(VariableItemList* variable_item_list) { free(variable_item_list); } +void variable_item_list_clean(VariableItemList* variable_item_list) { + furi_assert(variable_item_list); + + with_view_model( + variable_item_list->view, (VariableItemListModel * model) { + VariableItemArray_it_t it; + for(VariableItemArray_it(it, model->items); !VariableItemArray_end_p(it); + VariableItemArray_next(it)) { + string_clean(VariableItemArray_ref(it)->current_value_text); + } + VariableItemArray_clean(model->items); + return false; + }); +} + View* variable_item_list_get_view(VariableItemList* variable_item_list) { furi_assert(variable_item_list); return variable_item_list->view; diff --git a/applications/gui/modules/variable-item-list.h b/applications/gui/modules/variable-item-list.h index ab64a74a..8844b419 100644 --- a/applications/gui/modules/variable-item-list.h +++ b/applications/gui/modules/variable-item-list.h @@ -18,6 +18,9 @@ VariableItemList* variable_item_list_alloc(); * @param variable_item_list VariableItemList instance */ void variable_item_list_free(VariableItemList* variable_item_list); + +void variable_item_list_clean(VariableItemList* variable_item_list); + View* variable_item_list_get_view(VariableItemList* variable_item_list); /** Add item to VariableItemList diff --git a/applications/gui/modules/widget.c b/applications/gui/modules/widget.c index 64a05605..4b561260 100755 --- a/applications/gui/modules/widget.c +++ b/applications/gui/modules/widget.c @@ -118,6 +118,20 @@ static void widget_add_element(Widget* widget, WidgetElement* element) { }); } +void widget_add_string_multi_element( + Widget* widget, + uint8_t x, + uint8_t y, + Align horizontal, + Align vertical, + Font font, + const char* text) { + furi_assert(widget); + WidgetElement* string_multi_element = + widget_element_string_multi_create(x, y, horizontal, vertical, font, text); + widget_add_element(widget, string_multi_element); +} + void widget_add_string_element( Widget* widget, uint8_t x, diff --git a/applications/gui/modules/widget.h b/applications/gui/modules/widget.h index 17c53dd9..943e63c4 100755 --- a/applications/gui/modules/widget.h +++ b/applications/gui/modules/widget.h @@ -26,6 +26,23 @@ void widget_clear(Widget* widget); */ View* widget_get_view(Widget* widget); +/** Add Multi String Element + * @param widget Widget instance + * @param x - x coordinate + * @param y - y coordinate + * @param horizontal - Align instance + * @param vertical - Align instance + * @param font Font instance + */ +void widget_add_string_multi_element( + Widget* widget, + uint8_t x, + uint8_t y, + Align horizontal, + Align vertical, + Font font, + const char* text); + /** Add String Element * @param widget Widget instance * @param x - x coordinate diff --git a/applications/gui/modules/widget_elements/widget_element_button.c b/applications/gui/modules/widget_elements/widget_element_button.c index c9eab8d1..4b8517e0 100644 --- a/applications/gui/modules/widget_elements/widget_element_button.c +++ b/applications/gui/modules/widget_elements/widget_element_button.c @@ -30,7 +30,18 @@ static bool gui_button_input(InputEvent* event, WidgetElement* element) { GuiButtonModel* model = element->model; bool consumed = false; - if((event->type == InputTypeShort) && model->callback) { + if(model->callback == NULL) return consumed; + + if(event->key == InputKeyOk && event->type == InputTypePress && + model->button_type == GuiButtonTypeCenter) { + model->callback(GuiButtonTypeCenterPress, model->context); + consumed = true; + } else if( + event->key == InputKeyOk && event->type == InputTypeRelease && + model->button_type == GuiButtonTypeCenter) { + model->callback(GuiButtonTypeCenterRelease, model->context); + consumed = true; + } else if(event->type == InputTypeShort) { if((model->button_type == GuiButtonTypeLeft) && (event->key == InputKeyLeft)) { model->callback(model->button_type, model->context); consumed = true; diff --git a/applications/gui/modules/widget_elements/widget_element_i.h b/applications/gui/modules/widget_elements/widget_element_i.h index d35325aa..d99e349f 100755 --- a/applications/gui/modules/widget_elements/widget_element_i.h +++ b/applications/gui/modules/widget_elements/widget_element_i.h @@ -6,6 +6,8 @@ typedef enum { GuiButtonTypeLeft, GuiButtonTypeCenter, GuiButtonTypeRight, + GuiButtonTypeCenterPress, + GuiButtonTypeCenterRelease, } GuiButtonType; typedef void (*ButtonCallback)(GuiButtonType result, void* context); @@ -28,6 +30,15 @@ struct WidgetElement { Widget* parent; }; +/* Create multi string element */ +WidgetElement* widget_element_string_multi_create( + uint8_t x, + uint8_t y, + Align horizontal, + Align vertical, + Font font, + const char* text); + /* Create string element */ WidgetElement* widget_element_string_create( uint8_t x, diff --git a/applications/gui/modules/widget_elements/widget_element_string_multi.c b/applications/gui/modules/widget_elements/widget_element_string_multi.c new file mode 100644 index 00000000..ad9c58f5 --- /dev/null +++ b/applications/gui/modules/widget_elements/widget_element_string_multi.c @@ -0,0 +1,67 @@ +#include "widget_element_i.h" +#include +#include + +typedef struct { + uint8_t x; + uint8_t y; + Align horizontal; + Align vertical; + Font font; + string_t text; +} GuiStringMultiModel; + +static void gui_string_multi_draw(Canvas* canvas, WidgetElement* element) { + furi_assert(canvas); + furi_assert(element); + GuiStringMultiModel* model = element->model; + + if(string_size(model->text)) { + canvas_set_font(canvas, model->font); + elements_multiline_text_aligned( + canvas, + model->x, + model->y, + model->horizontal, + model->vertical, + string_get_cstr(model->text)); + } +} + +static void gui_string_multi_free(WidgetElement* gui_string) { + furi_assert(gui_string); + + GuiStringMultiModel* model = gui_string->model; + string_clear(model->text); + free(gui_string->model); + free(gui_string); +} + +WidgetElement* widget_element_string_multi_create( + uint8_t x, + uint8_t y, + Align horizontal, + Align vertical, + Font font, + const char* text) { + furi_assert(text); + + // Allocate and init model + GuiStringMultiModel* model = furi_alloc(sizeof(GuiStringMultiModel)); + model->x = x; + model->y = y; + model->horizontal = horizontal; + model->vertical = vertical; + model->font = font; + string_init_set_str(model->text, text); + + // Allocate and init Element + WidgetElement* gui_string = furi_alloc(sizeof(WidgetElement)); + gui_string->parent = NULL; + gui_string->input = NULL; + gui_string->draw = gui_string_multi_draw; + gui_string->free = gui_string_multi_free; + gui_string->model = model; + + return gui_string; +} diff --git a/applications/subghz/scenes/subghz_scene_config.h b/applications/subghz/scenes/subghz_scene_config.h index 10ecd1c6..070097e7 100644 --- a/applications/subghz/scenes/subghz_scene_config.h +++ b/applications/subghz/scenes/subghz_scene_config.h @@ -1,10 +1,12 @@ ADD_SCENE(subghz, start, Start) ADD_SCENE(subghz, receiver, Receiver) +ADD_SCENE(subghz, receiver_config, ReceiverConfig) +ADD_SCENE(subghz, receiver_info, ReceiverInfo) ADD_SCENE(subghz, save_name, SaveName) ADD_SCENE(subghz, save_success, SaveSuccess) ADD_SCENE(subghz, saved, Saved) ADD_SCENE(subghz, transmitter, Transmitter) -ADD_SCENE(subghz, no_man, NoMan) +ADD_SCENE(subghz, show_error, ShowError) ADD_SCENE(subghz, test, Test) ADD_SCENE(subghz, test_static, TestStatic) ADD_SCENE(subghz, test_carrier, TestCarrier) diff --git a/applications/subghz/scenes/subghz_scene_receiver.c b/applications/subghz/scenes/subghz_scene_receiver.c index 3c9ba375..aa5eaabe 100644 --- a/applications/subghz/scenes/subghz_scene_receiver.c +++ b/applications/subghz/scenes/subghz_scene_receiver.c @@ -1,21 +1,102 @@ #include "../subghz_i.h" #include "../views/subghz_receiver.h" +static void subghz_scene_receiver_update_statusbar(void* context) { + SubGhz* subghz = context; + char frequency_str[20]; + char preset_str[10]; + string_t history_stat_str; + string_init(history_stat_str); + if(!subghz_history_get_text_space_left(subghz->txrx->history, history_stat_str)) { + snprintf( + frequency_str, + sizeof(frequency_str), + "%03ld.%02ld", + subghz->txrx->frequency / 1000000 % 1000, + subghz->txrx->frequency / 10000 % 100); + if(subghz->txrx->preset == FuriHalSubGhzPresetOok650Async || + subghz->txrx->preset == FuriHalSubGhzPresetOok270Async) { + snprintf(preset_str, sizeof(preset_str), "AM"); + } else if(subghz->txrx->preset == FuriHalSubGhzPreset2FSKAsync) { + snprintf(preset_str, sizeof(preset_str), "FM"); + } else { + furi_check(0); + } + subghz_receiver_add_data_statusbar( + subghz->subghz_receiver, frequency_str, preset_str, string_get_cstr(history_stat_str)); + } else { + subghz_receiver_add_data_statusbar( + subghz->subghz_receiver, string_get_cstr(history_stat_str), "", ""); + subghz->state_notifications = NOTIFICATION_IDLE_STATE; + } + string_clear(history_stat_str); +} + void subghz_scene_receiver_callback(SubghzReceverEvent event, void* context) { furi_assert(context); SubGhz* subghz = context; view_dispatcher_send_custom_event(subghz->view_dispatcher, event); } +void subghz_scene_add_to_history_callback(SubGhzProtocolCommon* parser, void* context) { + furi_assert(context); + SubGhz* subghz = context; + string_t str_buff; + string_init(str_buff); + + if(subghz_history_add_to_history( + subghz->txrx->history, parser, subghz->txrx->frequency, subghz->txrx->preset)) { + subghz_protocol_reset(subghz->txrx->protocol); + string_clean(str_buff); + subghz_history_get_text_item_menu( + subghz->txrx->history, str_buff, subghz_history_get_item(subghz->txrx->history) - 1); + subghz_receiver_add_item_to_menu( + subghz->subghz_receiver, + string_get_cstr(str_buff), + subghz_history_get_type_protocol( + subghz->txrx->history, subghz_history_get_item(subghz->txrx->history) - 1)); + subghz_scene_receiver_update_statusbar(subghz); + } + string_clear(str_buff); +} + const void subghz_scene_receiver_on_enter(void* context) { SubGhz* subghz = context; - SubghzReceiver* subghz_receiver = subghz->subghz_receiver; - subghz_receiver_set_callback(subghz_receiver, subghz_scene_receiver_callback, subghz); + string_t str_buff; + string_init(str_buff); + + //Load history to receiver + subghz_receiver_exit(subghz->subghz_receiver); + for(uint8_t i = 0; i < subghz_history_get_item(subghz->txrx->history); i++) { + string_clean(str_buff); + subghz_history_get_text_item_menu(subghz->txrx->history, str_buff, i); + subghz_receiver_add_item_to_menu( + subghz->subghz_receiver, + string_get_cstr(str_buff), + subghz_history_get_type_protocol(subghz->txrx->history, i)); + } + string_clear(str_buff); + subghz_scene_receiver_update_statusbar(subghz); + subghz_receiver_set_callback(subghz->subghz_receiver, subghz_scene_receiver_callback, subghz); + subghz_protocol_enable_dump( + subghz->txrx->protocol, subghz_scene_add_to_history_callback, subghz); - subghz_receiver_set_protocol(subghz_receiver, subghz->protocol_result, subghz->protocol); - subghz_receiver_set_worker(subghz_receiver, subghz->worker); subghz->state_notifications = NOTIFICATION_RX_STATE; + if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { + subghz_rx_end(subghz->txrx->worker); + //subghz_sleep(); + subghz->txrx->txrx_state = SubGhzTxRxStateIdle; + }; + if(subghz->txrx->txrx_state == SubGhzTxRxStateIdle) { + subghz_begin(subghz->txrx->preset); + subghz_rx(subghz->txrx->worker, subghz->txrx->frequency); + subghz->txrx->txrx_state = SubGhzTxRxStateRx; + } + if(subghz->txrx->idx_menu_chosen != 0) { + subghz_receiver_set_idx_menu(subghz->subghz_receiver, subghz->txrx->idx_menu_chosen); + } + view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewReceiver); } @@ -24,51 +105,43 @@ const bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event if(event.type == SceneManagerEventTypeCustom) { switch(event.event) { - case SubghzReceverEventSave: - subghz->state_notifications = NOTIFICATION_IDLE_STATE; - subghz->frequency = subghz_receiver_get_frequency(subghz->subghz_receiver); - subghz->preset = subghz_receiver_get_preset(subghz->subghz_receiver); - subghz->protocol_result = subghz_receiver_get_protocol(subghz->subghz_receiver); - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName); - return true; - break; case SubghzReceverEventBack: - scene_manager_previous_scene(subghz->scene_manager); + // Stop CC1101 Rx + if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { + subghz_rx_end(subghz->txrx->worker); + subghz_sleep(); + subghz->txrx->txrx_state = SubGhzTxRxStateIdle; + }; + subghz_history_clean(subghz->txrx->history); + subghz->txrx->hopper_state = SubGhzHopperStateOFF; + subghz->txrx->frequency = subghz_frequencies[subghz_frequencies_433_92]; + subghz->txrx->preset = FuriHalSubGhzPresetOok650Async; + subghz->txrx->idx_menu_chosen = 0; + subghz_protocol_enable_dump(subghz->txrx->protocol, NULL, subghz); + scene_manager_search_and_switch_to_previous_scene( + subghz->scene_manager, SubGhzSceneStart); return true; break; - case SubghzReceverEventSendStart: - subghz->state_notifications = NOTIFICATION_TX_STATE; - subghz->frequency = subghz_receiver_get_frequency(subghz->subghz_receiver); - subghz->preset = subghz_receiver_get_preset(subghz->subghz_receiver); - subghz->protocol_result = subghz_receiver_get_protocol(subghz->subghz_receiver); - subghz_transmitter_tx_start(subghz); - return true; - break; - case SubghzReceverEventSendStop: - subghz->state_notifications = NOTIFICATION_IDLE_STATE; - subghz_transmitter_tx_stop(subghz); - return true; - break; - case SubghzReceverEventMain: - subghz->state_notifications = NOTIFICATION_RX_STATE; + case SubghzReceverEventOK: + subghz->txrx->idx_menu_chosen = subghz_receiver_get_idx_menu(subghz->subghz_receiver); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverInfo); return true; break; case SubghzReceverEventConfig: subghz->state_notifications = NOTIFICATION_IDLE_STATE; - return true; - break; - case SubghzReceverEventSendHistoryFull: - subghz->state_notifications = NOTIFICATION_IDLE_STATE; + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverConfig); return true; break; default: break; } } else if(event.type == SceneManagerEventTypeTick) { + if(subghz->txrx->hopper_state != SubGhzHopperStateOFF) { + subghz_hopper_update(subghz->txrx); + subghz_scene_receiver_update_statusbar(subghz); + } + switch(subghz->state_notifications) { - case NOTIFICATION_TX_STATE: - notification_message(subghz->notifications, &sequence_blink_red_10); - break; case NOTIFICATION_RX_STATE: notification_message(subghz->notifications, &sequence_blink_blue_10); break; diff --git a/applications/subghz/scenes/subghz_scene_receiver_config.c b/applications/subghz/scenes/subghz_scene_receiver_config.c new file mode 100644 index 00000000..276fc4b9 --- /dev/null +++ b/applications/subghz/scenes/subghz_scene_receiver_config.c @@ -0,0 +1,156 @@ +#include "../subghz_i.h" + +#define PRESET_COUNT 3 +const char* const preset_text[PRESET_COUNT] = { + "AM270", + "AM650", + "FM", +}; +const uint32_t preset_value[PRESET_COUNT] = { + FuriHalSubGhzPresetOok270Async, /** OOK, bandwidth 270kHz, asynchronous */ + FuriHalSubGhzPresetOok650Async, /** OOK, bandwidth 650kHz, asynchronous */ + FuriHalSubGhzPreset2FSKAsync, /** FM, asynchronous */ +}; + +#define HOPPING_COUNT 2 +const char* const hopping_text[HOPPING_COUNT] = { + "OFF", + "ON", +}; +const uint32_t hopping_value[HOPPING_COUNT] = { + SubGhzHopperStateOFF, + SubGhzHopperStateRunnig, +}; + +uint8_t subghz_scene_receiver_config_uint32_value_index( + const uint32_t value, + const uint32_t values[], + uint8_t values_count) { + int64_t last_value = INT64_MIN; + uint8_t index = 0; + for(uint8_t i = 0; i < values_count; i++) { + if((value >= last_value) && (value <= values[i])) { + index = i; + break; + } + last_value = values[i]; + } + return index; +} + +uint8_t subghz_scene_receiver_config_hopper_value_index( + const uint32_t value, + const uint32_t values[], + uint8_t values_count, + void* context) { + furi_assert(context); + SubGhz* subghz = context; + + if(value == values[0]) { + return 0; + } else { + variable_item_set_current_value_text( + (VariableItem*)scene_manager_get_scene_state( + subghz->scene_manager, SubGhzSceneReceiverConfig), + " -----"); + return 1; + } +} + +static void subghz_scene_receiver_config_set_frequency(VariableItem* item) { + SubGhz* subghz = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + + if(subghz->txrx->hopper_state == SubGhzHopperStateOFF) { + variable_item_set_current_value_text(item, subghz_frequencies_text[index]); + subghz->txrx->frequency = subghz_frequencies[index]; + } +} + +static void subghz_scene_receiver_config_set_preset(VariableItem* item) { + SubGhz* subghz = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + + variable_item_set_current_value_text(item, preset_text[index]); + subghz->txrx->preset = preset_value[index]; +} + +static void subghz_scene_receiver_config_set_hopping_runing(VariableItem* item) { + SubGhz* subghz = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + + variable_item_set_current_value_text(item, hopping_text[index]); + if(hopping_value[index] == SubGhzHopperStateOFF) { + variable_item_set_current_value_text( + (VariableItem*)scene_manager_get_scene_state( + subghz->scene_manager, SubGhzSceneReceiverConfig), + subghz_frequencies_text[subghz_frequencies_433_92]); + subghz->txrx->frequency = subghz_frequencies[subghz_frequencies_433_92]; + } else { + variable_item_set_current_value_text( + (VariableItem*)scene_manager_get_scene_state( + subghz->scene_manager, SubGhzSceneReceiverConfig), + " -----"); + } + + subghz->txrx->hopper_state = hopping_value[index]; +} + +void subghz_scene_receiver_config_callback(SubghzReceverEvent event, void* context) { + furi_assert(context); + SubGhz* subghz = context; + view_dispatcher_send_custom_event(subghz->view_dispatcher, event); +} + +const void subghz_scene_receiver_config_on_enter(void* context) { + SubGhz* subghz = context; + VariableItem* item; + uint8_t value_index; + + item = variable_item_list_add( + subghz->variable_item_list, + "Frequency:", + subghz_frequencies_count, + subghz_scene_receiver_config_set_frequency, + subghz); + value_index = subghz_scene_receiver_config_uint32_value_index( + subghz->txrx->frequency, subghz_frequencies, subghz_frequencies_count); + scene_manager_set_scene_state( + subghz->scene_manager, SubGhzSceneReceiverConfig, (uint32_t)item); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, subghz_frequencies_text[value_index]); + + item = variable_item_list_add( + subghz->variable_item_list, + "Hopping:", + HOPPING_COUNT, + subghz_scene_receiver_config_set_hopping_runing, + subghz); + value_index = subghz_scene_receiver_config_hopper_value_index( + subghz->txrx->hopper_state, hopping_value, HOPPING_COUNT, subghz); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, hopping_text[value_index]); + + item = variable_item_list_add( + subghz->variable_item_list, + "Modulation:", + PRESET_COUNT, + subghz_scene_receiver_config_set_preset, + subghz); + value_index = subghz_scene_receiver_config_uint32_value_index( + subghz->txrx->preset, preset_value, PRESET_COUNT); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, preset_text[value_index]); + + view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewVariableItemList); +} + +const bool subghz_scene_receiver_config_on_event(void* context, SceneManagerEvent event) { + //SubGhz* subghz = context; + return false; +} + +const void subghz_scene_receiver_config_on_exit(void* context) { + SubGhz* subghz = context; + variable_item_list_clean(subghz->variable_item_list); +} diff --git a/applications/subghz/scenes/subghz_scene_receiver_info.c b/applications/subghz/scenes/subghz_scene_receiver_info.c new file mode 100644 index 00000000..6d0d371e --- /dev/null +++ b/applications/subghz/scenes/subghz_scene_receiver_info.c @@ -0,0 +1,163 @@ +#include "../subghz_i.h" + +void subghz_scene_receiver_info_callback(GuiButtonType result, void* context) { + furi_assert(context); + SubGhz* subghz = context; + view_dispatcher_send_custom_event(subghz->view_dispatcher, result); +} + +static bool subghz_scene_receiver_info_update_parser(void* context) { + SubGhz* subghz = context; + subghz->txrx->protocol_result = subghz_protocol_get_by_name( + subghz->txrx->protocol, + subghz_history_get_name(subghz->txrx->history, subghz->txrx->idx_menu_chosen)); + + if(subghz->txrx->protocol_result->to_load_protocol != NULL) { + subghz->txrx->protocol_result->to_load_protocol( + subghz->txrx->protocol_result, + subghz_history_get_raw_data(subghz->txrx->history, subghz->txrx->idx_menu_chosen)); + subghz->txrx->frequency = + subghz_history_get_frequency(subghz->txrx->history, subghz->txrx->idx_menu_chosen); + subghz->txrx->preset = + subghz_history_get_preset(subghz->txrx->history, subghz->txrx->idx_menu_chosen); + return true; + } + return false; +} + +const void subghz_scene_receiver_info_on_enter(void* context) { + SubGhz* subghz = context; + + if(subghz_scene_receiver_info_update_parser(subghz)) { + char buffer_str[16]; + snprintf( + buffer_str, + sizeof(buffer_str), + "%03ld.%02ld", + subghz->txrx->frequency / 1000000 % 1000, + subghz->txrx->frequency / 10000 % 100); + widget_add_string_element( + subghz->widget, 78, 0, AlignLeft, AlignTop, FontSecondary, buffer_str); + if(subghz->txrx->preset == FuriHalSubGhzPresetOok650Async || + subghz->txrx->preset == FuriHalSubGhzPresetOok270Async) { + snprintf(buffer_str, sizeof(buffer_str), "AM"); + } else if(subghz->txrx->preset == FuriHalSubGhzPreset2FSKAsync) { + snprintf(buffer_str, sizeof(buffer_str), "FM"); + } else { + furi_check(0); + } + widget_add_string_element( + subghz->widget, 113, 0, AlignLeft, AlignTop, FontSecondary, buffer_str); + string_t text; + string_init(text); + subghz->txrx->protocol_result->to_string(subghz->txrx->protocol_result, text); + widget_add_string_multi_element( + subghz->widget, 0, 0, AlignLeft, AlignTop, FontSecondary, string_get_cstr(text)); + string_clear(text); + + if(subghz->txrx->protocol_result && subghz->txrx->protocol_result->to_save_string && + strcmp(subghz->txrx->protocol_result->name, "KeeLoq")) { + widget_add_button_element( + subghz->widget, + GuiButtonTypeRight, + "Save", + subghz_scene_receiver_info_callback, + subghz); + widget_add_button_element( + subghz->widget, + GuiButtonTypeCenter, + "Send", + subghz_scene_receiver_info_callback, + subghz); + } + + } else { + widget_add_icon_element(subghz->widget, 32, 12, &I_DolphinFirstStart7_61x51); + widget_add_string_element( + subghz->widget, 13, 8, AlignLeft, AlignBottom, FontSecondary, "Error history parse."); + } + + view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewWidget); +} + +const bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) { + SubGhz* subghz = context; + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeCenterPress) { + //CC1101 Stop RX -> Start TX + subghz->state_notifications = NOTIFICATION_TX_STATE; + if(subghz->txrx->hopper_state != SubGhzHopperStateOFF) { + subghz->txrx->hopper_state = SubGhzHopperStatePause; + } + if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { + subghz_rx_end(subghz->txrx->worker); + //subghz_sleep(); + subghz->txrx->txrx_state = SubGhzTxRxStateIdle; + } + if(!subghz_scene_receiver_info_update_parser(subghz)) { + return false; + } + if(subghz->txrx->txrx_state == SubGhzTxRxStateIdle) { + subghz_tx_start(subghz); + subghz->txrx->txrx_state = SubGhzTxRxStateTx; + } + return true; + } else if(event.event == GuiButtonTypeCenterRelease) { + //CC1101 Stop Tx -> Start RX + subghz->state_notifications = NOTIFICATION_IDLE_STATE; + if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { + subghz_tx_stop(subghz); + subghz->txrx->txrx_state = SubGhzTxRxStateIdle; + } + if(subghz->txrx->txrx_state == SubGhzTxRxStateIdle) { + subghz_begin(subghz->txrx->preset); + subghz_rx(subghz->txrx->worker, subghz->txrx->frequency); + subghz->txrx->txrx_state = SubGhzTxRxStateRx; + } + if(subghz->txrx->hopper_state == SubGhzHopperStatePause) { + subghz->txrx->hopper_state = SubGhzHopperStateRunnig; + } + subghz->state_notifications = NOTIFICATION_RX_STATE; + return true; + } else if(event.event == GuiButtonTypeRight) { + //CC1101 Stop RX -> Save + subghz->state_notifications = NOTIFICATION_IDLE_STATE; + if(subghz->txrx->hopper_state != SubGhzHopperStateOFF) { + subghz->txrx->hopper_state = SubGhzHopperStateOFF; + } + if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { + subghz_rx_end(subghz->txrx->worker); + subghz_sleep(); + subghz->txrx->txrx_state = SubGhzTxRxStateIdle; + } + if(!subghz_scene_receiver_info_update_parser(subghz)) { + return false; + } + if(subghz->txrx->protocol_result && subghz->txrx->protocol_result->to_save_string && + strcmp(subghz->txrx->protocol_result->name, "KeeLoq")) { + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName); + } + return true; + } + } else if(event.type == SceneManagerEventTypeTick) { + if(subghz->txrx->hopper_state != SubGhzHopperStateOFF) { + subghz_hopper_update(subghz->txrx); + } + switch(subghz->state_notifications) { + case NOTIFICATION_TX_STATE: + notification_message(subghz->notifications, &sequence_blink_red_10); + break; + case NOTIFICATION_RX_STATE: + notification_message(subghz->notifications, &sequence_blink_blue_10); + break; + default: + break; + } + } + return false; +} + +const void subghz_scene_receiver_info_on_exit(void* context) { + SubGhz* subghz = context; + widget_clear(subghz->widget); +} diff --git a/applications/subghz/scenes/subghz_scene_save_name.c b/applications/subghz/scenes/subghz_scene_save_name.c index fba0c622..b73f31b9 100644 --- a/applications/subghz/scenes/subghz_scene_save_name.c +++ b/applications/subghz/scenes/subghz_scene_save_name.c @@ -35,11 +35,13 @@ const bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent even if(event.type == SceneManagerEventTypeCustom) { if(event.event == SCENE_SAVE_NAME_CUSTOM_EVENT) { - if(subghz_save_protocol_to_file(subghz, subghz->text_store)) { + if(strcmp(subghz->text_store, "") && + subghz_save_protocol_to_file(subghz, subghz->text_store)) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveSuccess); return true; } else { - //Error save + string_set(subghz->error_str, "No name file"); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); return true; } } diff --git a/applications/subghz/scenes/subghz_scene_set_type.c b/applications/subghz/scenes/subghz_scene_set_type.c index d0981792..c506a5c7 100644 --- a/applications/subghz/scenes/subghz_scene_set_type.c +++ b/applications/subghz/scenes/subghz_scene_set_type.c @@ -8,15 +8,18 @@ enum SubmenuIndex { SubmenuIndexCAME12bit, SubmenuIndexCAME24bit, SubmenuIndexNeroSketch, + SubmenuIndexNeroRadio, SubmenuIndexGateTX, SubmenuIndexDoorHan, }; bool subghz_scene_set_type_submenu_to_find_protocol(void* context, const char* protocol_name) { SubGhz* subghz = context; - subghz->protocol_result = subghz_protocol_get_by_name(subghz->protocol, protocol_name); - if(subghz->protocol_result == NULL) { - //show error + subghz->txrx->protocol_result = + subghz_protocol_get_by_name(subghz->txrx->protocol, protocol_name); + if(subghz->txrx->protocol_result == NULL) { + string_set(subghz->error_str, "Protocol not found"); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); return false; } return true; @@ -62,6 +65,8 @@ const void subghz_scene_set_type_on_enter(void* context) { subghz); // submenu_add_item( // subghz->submenu, "Nero Sketch", SubmenuIndexNeroSketch, subghz_scene_set_type_submenu_callback, subghz); + // submenu_add_item( + // subghz->submenu, "Nero Radio", SubmenuIndexNeroRadio, subghz_scene_set_type_submenu_callback, subghz); submenu_add_item( subghz->submenu, "Gate TX_433", @@ -90,81 +95,86 @@ const bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event switch(event.event) { case SubmenuIndexPricenton: if(subghz_scene_set_type_submenu_to_find_protocol(subghz, "Princeton")) { - subghz->protocol_result->code_last_count_bit = 24; + subghz->txrx->protocol_result->code_last_count_bit = 24; key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8 - subghz->protocol_result->code_last_found = key; + subghz->txrx->protocol_result->code_last_found = key; generated_protocol = true; } break; case SubmenuIndexNiceFlo12bit: if(subghz_scene_set_type_submenu_to_find_protocol(subghz, "Nice FLO")) { - subghz->protocol_result->code_last_count_bit = 12; + subghz->txrx->protocol_result->code_last_count_bit = 12; key = (key & 0x0000FFF0) | 0x1; //btn 0x1, 0x2, 0x4 - subghz->protocol_result->code_last_found = key; + subghz->txrx->protocol_result->code_last_found = key; generated_protocol = true; } break; case SubmenuIndexNiceFlo24bit: if(subghz_scene_set_type_submenu_to_find_protocol(subghz, "Nice FLO")) { - subghz->protocol_result->code_last_count_bit = 24; + subghz->txrx->protocol_result->code_last_count_bit = 24; key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8 - subghz->protocol_result->code_last_found = key; + subghz->txrx->protocol_result->code_last_found = key; generated_protocol = true; } break; case SubmenuIndexCAME12bit: if(subghz_scene_set_type_submenu_to_find_protocol(subghz, "CAME")) { - subghz->protocol_result->code_last_count_bit = 12; + subghz->txrx->protocol_result->code_last_count_bit = 12; key = (key & 0x0000FFF0) | 0x1; //btn 0x1, 0x2, 0x4 - subghz->protocol_result->code_last_found = key; + subghz->txrx->protocol_result->code_last_found = key; generated_protocol = true; } break; case SubmenuIndexCAME24bit: if(subghz_scene_set_type_submenu_to_find_protocol(subghz, "CAME")) { - subghz->protocol_result->code_last_count_bit = 24; + subghz->txrx->protocol_result->code_last_count_bit = 24; key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8 - subghz->protocol_result->code_last_found = key; + subghz->txrx->protocol_result->code_last_found = key; generated_protocol = true; } break; // case SubmenuIndexNeroSketch: // /* code */ // break; + // case SubmenuIndexNeroRadio: + // /* code */ + // break; case SubmenuIndexGateTX: if(subghz_scene_set_type_submenu_to_find_protocol(subghz, "GateTX")) { - subghz->protocol_result->code_last_count_bit = 24; + subghz->txrx->protocol_result->code_last_count_bit = 24; key = (key & 0x00F0FFFF) | 0xF << 16; //btn 0xF, 0xC, 0xA, 0x6 - subghz->protocol_result->code_last_found = subghz_protocol_common_reverse_key( - key, subghz->protocol_result->code_last_count_bit); + subghz->txrx->protocol_result->code_last_found = + subghz_protocol_common_reverse_key( + key, subghz->txrx->protocol_result->code_last_count_bit); generated_protocol = true; } break; case SubmenuIndexDoorHan: if(subghz_scene_set_type_submenu_to_find_protocol(subghz, "KeeLoq")) { - subghz->protocol_result->code_last_count_bit = 64; - subghz->protocol_result->serial = key & 0x0FFFFFFF; - subghz->protocol_result->btn = 0x2; //btn 0x1, 0x2, 0x4, 0x8 - subghz->protocol_result->cnt = 0x0003; + subghz->txrx->protocol_result->code_last_count_bit = 64; + subghz->txrx->protocol_result->serial = key & 0x0FFFFFFF; + subghz->txrx->protocol_result->btn = 0x2; //btn 0x1, 0x2, 0x4, 0x8 + subghz->txrx->protocol_result->cnt = 0x0003; if(subghz_protocol_keeloq_set_manufacture_name( - subghz->protocol_result, "DoorHan")) { - subghz->protocol_result->code_last_found = - subghz_protocol_keeloq_gen_key(subghz->protocol_result); + subghz->txrx->protocol_result, "DoorHan")) { + subghz->txrx->protocol_result->code_last_found = + subghz_protocol_keeloq_gen_key(subghz->txrx->protocol_result); generated_protocol = true; } else { generated_protocol = false; - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNoMan); + string_set(subghz->error_str, "No manufactory key"); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); } } break; - default: return false; break; } + if(generated_protocol) { - subghz->frequency = subghz_frequencies[subghz_frequencies_433_92]; - subghz->preset = FuriHalSubGhzPresetOok650Async; + subghz->txrx->frequency = subghz_frequencies[subghz_frequencies_433_92]; + subghz->txrx->preset = FuriHalSubGhzPresetOok650Async; scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName); return true; } diff --git a/applications/subghz/scenes/subghz_scene_no_man.c b/applications/subghz/scenes/subghz_scene_show_error.c similarity index 72% rename from applications/subghz/scenes/subghz_scene_no_man.c rename to applications/subghz/scenes/subghz_scene_show_error.c index d5f2e0de..08c487a7 100644 --- a/applications/subghz/scenes/subghz_scene_no_man.c +++ b/applications/subghz/scenes/subghz_scene_show_error.c @@ -2,26 +2,26 @@ #define SCENE_NO_MAN_CUSTOM_EVENT (11UL) -void subghz_scene_no_man_popup_callback(void* context) { +void subghz_scene_show_error_popup_callback(void* context) { SubGhz* subghz = context; view_dispatcher_send_custom_event(subghz->view_dispatcher, SCENE_NO_MAN_CUSTOM_EVENT); } -const void subghz_scene_no_man_on_enter(void* context) { +const void subghz_scene_show_error_on_enter(void* context) { SubGhz* subghz = context; // Setup view Popup* popup = subghz->popup; popup_set_icon(popup, 32, 12, &I_DolphinFirstStart7_61x51); - popup_set_header(popup, "No manufactory key", 13, 8, AlignLeft, AlignBottom); + popup_set_header(popup, string_get_cstr(subghz->error_str), 64, 8, AlignCenter, AlignBottom); popup_set_timeout(popup, 1500); popup_set_context(popup, subghz); - popup_set_callback(popup, subghz_scene_no_man_popup_callback); + popup_set_callback(popup, subghz_scene_show_error_popup_callback); popup_enable_timeout(popup); view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewPopup); } -const bool subghz_scene_no_man_on_event(void* context, SceneManagerEvent event) { +const bool subghz_scene_show_error_on_event(void* context, SceneManagerEvent event) { SubGhz* subghz = context; if(event.type == SceneManagerEventTypeCustom) { if(event.event == SCENE_NO_MAN_CUSTOM_EVENT) { @@ -33,7 +33,7 @@ const bool subghz_scene_no_man_on_event(void* context, SceneManagerEvent event) return false; } -const void subghz_scene_no_man_on_exit(void* context) { +const void subghz_scene_show_error_on_exit(void* context) { SubGhz* subghz = context; // Clear view @@ -45,4 +45,5 @@ const void subghz_scene_no_man_on_exit(void* context) { popup_set_context(popup, NULL); popup_set_timeout(popup, 0); popup_disable_timeout(popup); + string_clean(subghz->error_str); } diff --git a/applications/subghz/scenes/subghz_scene_transmitter.c b/applications/subghz/scenes/subghz_scene_transmitter.c index c363fff6..9628a094 100644 --- a/applications/subghz/scenes/subghz_scene_transmitter.c +++ b/applications/subghz/scenes/subghz_scene_transmitter.c @@ -1,5 +1,6 @@ #include "../subghz_i.h" #include "../views/subghz_transmitter.h" +#include void subghz_scene_transmitter_callback(SubghzTransmitterEvent event, void* context) { furi_assert(context); @@ -7,42 +8,90 @@ void subghz_scene_transmitter_callback(SubghzTransmitterEvent event, void* conte view_dispatcher_send_custom_event(subghz->view_dispatcher, event); } +static void subghz_scene_transmitter_update_data_show(void* context) { + SubGhz* subghz = context; + + if(subghz->txrx->protocol_result && subghz->txrx->protocol_result->get_upload_protocol) { + string_t key_str; + string_init(key_str); + char frequency_str[10]; + char preset_str[6]; + uint8_t show_button = 0; + subghz->txrx->protocol_result->to_string(subghz->txrx->protocol_result, key_str); + + if((!strcmp(subghz->txrx->protocol_result->name, "KeeLoq")) && + (!strcmp( + subghz_protocol_keeloq_get_manufacture_name(subghz->txrx->protocol_result), + "Unknown"))) { + show_button = 0; + } else { + show_button = 1; + } + snprintf( + frequency_str, + sizeof(frequency_str), + "%03ld.%02ld", + subghz->txrx->frequency / 1000000 % 1000, + subghz->txrx->frequency / 10000 % 100); + if(subghz->txrx->preset == FuriHalSubGhzPresetOok650Async || + subghz->txrx->preset == FuriHalSubGhzPresetOok270Async) { + snprintf(preset_str, sizeof(preset_str), "AM"); + } else if(subghz->txrx->preset == FuriHalSubGhzPreset2FSKAsync) { + snprintf(preset_str, sizeof(preset_str), "FM"); + } else { + furi_check(0); + } + + subghz_transmitter_add_data_to_show( + subghz->subghz_transmitter, + string_get_cstr(key_str), + frequency_str, + preset_str, + show_button); + string_clear(key_str); + } else { + string_set(subghz->error_str, "Protocol not found"); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); + } +} + const void subghz_scene_transmitter_on_enter(void* context) { SubGhz* subghz = context; - SubghzTransmitter* subghz_transmitter = subghz->subghz_transmitter; - - subghz_transmitter_set_callback(subghz_transmitter, subghz_scene_transmitter_callback, subghz); - subghz_transmitter_set_protocol(subghz_transmitter, subghz->protocol_result); - subghz_transmitter_set_frequency_preset(subghz_transmitter, subghz->frequency, subghz->preset); - - view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewTransmitter); - + subghz_transmitter_set_callback( + subghz->subghz_transmitter, subghz_scene_transmitter_callback, subghz); + subghz_scene_transmitter_update_data_show(subghz); subghz->state_notifications = NOTIFICATION_IDLE_STATE; + view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewTransmitter); } const bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { SubGhz* subghz = context; - if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubghzTransmitterEventSendStart) { subghz->state_notifications = NOTIFICATION_TX_STATE; - subghz_transmitter_tx_start(subghz); + if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { + subghz_rx_end(subghz->txrx->worker); + subghz->txrx->txrx_state = SubGhzTxRxStateIdle; + } + if(subghz->txrx->txrx_state == SubGhzTxRxStateIdle) { + subghz_tx_start(subghz); + subghz_scene_transmitter_update_data_show(subghz); + subghz->txrx->txrx_state = SubGhzTxRxStateTx; + } return true; } else if(event.event == SubghzTransmitterEventSendStop) { subghz->state_notifications = NOTIFICATION_IDLE_STATE; - subghz_transmitter_tx_stop(subghz); - subghz_sleep(); + if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { + subghz_tx_stop(subghz); + subghz_sleep(); + subghz->txrx->txrx_state = SubGhzTxRxStateIdle; + } return true; } else if(event.event == SubghzTransmitterEventBack) { subghz->state_notifications = NOTIFICATION_IDLE_STATE; scene_manager_search_and_switch_to_previous_scene( subghz->scene_manager, SubGhzSceneStart); return true; - } else if(event.event == SubghzTransmitterEventNoMan) { - subghz->state_notifications = NOTIFICATION_IDLE_STATE; - scene_manager_search_and_switch_to_previous_scene( - subghz->scene_manager, SubGhzSceneNoMan); - return true; } } else if(event.type == SceneManagerEventTypeTick) { if(subghz->state_notifications == NOTIFICATION_TX_STATE) { @@ -55,7 +104,6 @@ const bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent ev const void subghz_scene_transmitter_on_exit(void* context) { SubGhz* subghz = context; - SubghzTransmitter* subghz_transmitter = subghz->subghz_transmitter; - subghz_transmitter_set_callback(subghz_transmitter, NULL, subghz); + subghz->state_notifications = NOTIFICATION_IDLE_STATE; } diff --git a/applications/subghz/subghz.c b/applications/subghz/subghz.c index 865ec8df..5b356ab1 100644 --- a/applications/subghz/subghz.c +++ b/applications/subghz/subghz.c @@ -1,5 +1,22 @@ #include "subghz_i.h" +const char* const subghz_frequencies_text[] = { + "300.00", + "315.00", + "348.00", + "387.00", + "433.08", + "433.92", + "434.78", + "438.90", + "464.00", + "779.00", + "868.35", + "915.00", + "925.00", + "928.00", +}; + const uint32_t subghz_frequencies[] = { /* 300 - 348 */ 300000000, @@ -20,7 +37,15 @@ const uint32_t subghz_frequencies[] = { 928000000, }; +const uint32_t subghz_hopper_frequencies[] = { + 315000000, + 433920000, + 868350000, +}; + const uint32_t subghz_frequencies_count = sizeof(subghz_frequencies) / sizeof(uint32_t); +const uint32_t subghz_hopper_frequencies_count = + sizeof(subghz_hopper_frequencies) / sizeof(uint32_t); const uint32_t subghz_frequencies_433_92 = 5; bool subghz_custom_event_callback(void* context, uint32_t event) { @@ -77,11 +102,6 @@ SubGhz* subghz_alloc() { SubGhzViewReceiver, subghz_receiver_get_view(subghz->subghz_receiver)); - // Dialog - subghz->dialog_ex = dialog_ex_alloc(); - view_dispatcher_add_view( - subghz->view_dispatcher, SubGhzViewDialogEx, dialog_ex_get_view(subghz->dialog_ex)); - // Popup subghz->popup = popup_alloc(); view_dispatcher_add_view( @@ -92,6 +112,11 @@ SubGhz* subghz_alloc() { view_dispatcher_add_view( subghz->view_dispatcher, SubGhzViewTextInput, text_input_get_view(subghz->text_input)); + // Custom Widget + subghz->widget = widget_alloc(); + view_dispatcher_add_view( + subghz->view_dispatcher, SubGhzViewWidget, widget_get_view(subghz->widget)); + // Transmitter subghz->subghz_transmitter = subghz_transmitter_alloc(); view_dispatcher_add_view( @@ -99,6 +124,13 @@ SubGhz* subghz_alloc() { SubGhzViewTransmitter, subghz_transmitter_get_view(subghz->subghz_transmitter)); + // Variable Item List + subghz->variable_item_list = variable_item_list_alloc(); + view_dispatcher_add_view( + subghz->view_dispatcher, + SubGhzViewVariableItemList, + variable_item_list_get_view(subghz->variable_item_list)); + // Carrier Test Module subghz->subghz_test_carrier = subghz_test_carrier_alloc(); view_dispatcher_add_view( @@ -120,17 +152,26 @@ SubGhz* subghz_alloc() { SubGhzViewStatic, subghz_test_static_get_view(subghz->subghz_test_static)); - //init Worker & Protocol - subghz->worker = subghz_worker_alloc(); - subghz->protocol = subghz_protocol_alloc(); + //init Worker & Protocol & History + subghz->txrx = furi_alloc(sizeof(SubGhzTxRx)); + subghz->txrx->frequency = subghz_frequencies[subghz_frequencies_433_92]; + subghz->txrx->preset = FuriHalSubGhzPresetOok650Async; + subghz->txrx->txrx_state = SubGhzTxRxStateIdle; + subghz->txrx->hopper_state = SubGhzHopperStateOFF; + subghz->txrx->history = subghz_history_alloc(); + subghz->txrx->worker = subghz_worker_alloc(); + subghz->txrx->protocol = subghz_protocol_alloc(); subghz_worker_set_overrun_callback( - subghz->worker, (SubGhzWorkerOverrunCallback)subghz_protocol_reset); + subghz->txrx->worker, (SubGhzWorkerOverrunCallback)subghz_protocol_reset); subghz_worker_set_pair_callback( - subghz->worker, (SubGhzWorkerPairCallback)subghz_protocol_parse); - subghz_worker_set_context(subghz->worker, subghz->protocol); + subghz->txrx->worker, (SubGhzWorkerPairCallback)subghz_protocol_parse); + subghz_worker_set_context(subghz->txrx->worker, subghz->txrx->protocol); - subghz_protocol_load_keeloq_file(subghz->protocol, "/ext/subghz/keeloq_mfcodes"); - subghz_protocol_load_nice_flor_s_file(subghz->protocol, "/ext/subghz/nice_floor_s_rx"); + //Init Error_str + string_init(subghz->error_str); + + subghz_protocol_load_keeloq_file(subghz->txrx->protocol, "/ext/subghz/keeloq_mfcodes"); + subghz_protocol_load_nice_flor_s_file(subghz->txrx->protocol, "/ext/subghz/nice_floor_s_rx"); //subghz_protocol_enable_dump_text(subghz->protocol, subghz_text_callback, subghz); @@ -160,18 +201,22 @@ void subghz_free(SubGhz* subghz) { view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewTextInput); text_input_free(subghz->text_input); - // Receiver + // Custom Widget + view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewWidget); + widget_free(subghz->widget); + + // Transmitter view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewTransmitter); subghz_transmitter_free(subghz->subghz_transmitter); + // Variable Item List + view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewVariableItemList); + variable_item_list_free(subghz->variable_item_list); + // Submenu view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewMenu); submenu_free(subghz->submenu); - // DialogEx - view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewDialogEx); - dialog_ex_free(subghz->dialog_ex); - // Popup view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewPopup); popup_free(subghz->popup); @@ -186,9 +231,14 @@ void subghz_free(SubGhz* subghz) { furi_record_close("gui"); subghz->gui = NULL; - //Worker & Protocol - subghz_protocol_free(subghz->protocol); - subghz_worker_free(subghz->worker); + //Worker & Protocol & History + subghz_protocol_free(subghz->txrx->protocol); + subghz_worker_free(subghz->txrx->worker); + subghz_history_free(subghz->txrx->history); + free(subghz->txrx); + + //Error string + string_clear(subghz->error_str); // Notifications furi_record_close("notification"); diff --git a/applications/subghz/subghz_history.c b/applications/subghz/subghz_history.c index 16fac74b..b9fb90e7 100644 --- a/applications/subghz/subghz_history.c +++ b/applications/subghz/subghz_history.c @@ -128,21 +128,27 @@ void subghz_history_get_text_item_menu(SubGhzHistory* instance, string_t output, } } -void subghz_history_add_to_history(SubGhzHistory* instance, void* context) { +bool subghz_history_add_to_history( + SubGhzHistory* instance, + void* context, + uint32_t frequency, + FuriHalSubGhzPreset preset) { furi_assert(instance); furi_assert(context); SubGhzProtocolCommon* protocol = context; - if(instance->last_index_write >= SUBGHZ_HISTORY_MAX) return; + if(instance->last_index_write >= SUBGHZ_HISTORY_MAX) return false; if((instance->code_last_found == (protocol->code_last_found & 0xFFFF0FFFFFFFFFFF)) && ((millis() - instance->last_update_timestamp) < 500)) { instance->last_update_timestamp = millis(); - return; + return false; } instance->code_last_found = protocol->code_last_found & 0xFFFF0FFFFFFFFFFF; instance->last_update_timestamp = millis(); + instance->history[instance->last_index_write].real_frequency = frequency; + instance->history[instance->last_index_write].preset = preset; instance->history[instance->last_index_write].te = 0; instance->history[instance->last_index_write].manufacture_name = NULL; instance->history[instance->last_index_write].name = protocol->name; @@ -161,4 +167,5 @@ void subghz_history_add_to_history(SubGhzHistory* instance, void* context) { instance->history[instance->last_index_write].type_protocol = protocol->type_protocol; instance->last_index_write++; + return true; } \ No newline at end of file diff --git a/applications/subghz/subghz_history.h b/applications/subghz/subghz_history.h index a1f7ee7f..406c1cee 100644 --- a/applications/subghz/subghz_history.h +++ b/applications/subghz/subghz_history.h @@ -1,3 +1,4 @@ + #pragma once #include @@ -94,8 +95,15 @@ bool subghz_history_get_text_space_left(SubGhzHistory* instance, string_t output * * @param instance - SubGhzHistory instance * @param context - SubGhzProtocolCommon context + * @param frequency - frequency Hz + * @param preset - FuriHalSubGhzPreset preset + * @return bool; */ -void subghz_history_add_to_history(SubGhzHistory* instance, void* context); +bool subghz_history_add_to_history( + SubGhzHistory* instance, + void* context, + uint32_t frequency, + FuriHalSubGhzPreset preset); /** Get SubGhzProtocolCommonLoad to load into the protocol decoder bin data * @@ -104,3 +112,5 @@ void subghz_history_add_to_history(SubGhzHistory* instance, void* context); * @return SubGhzProtocolCommonLoad* */ SubGhzProtocolCommonLoad* subghz_history_get_raw_data(SubGhzHistory* instance, uint16_t idx); + +void subghz_hopper_update(void* context); diff --git a/applications/subghz/subghz_i.c b/applications/subghz/subghz_i.c index a339edfb..cdac50c6 100644 --- a/applications/subghz/subghz_i.c +++ b/applications/subghz/subghz_i.c @@ -19,6 +19,9 @@ void subghz_begin(FuriHalSubGhzPreset preset) { uint32_t subghz_rx(void* context, uint32_t frequency) { furi_assert(context); + if(!furi_hal_subghz_is_frequency_valid(frequency)) { + furi_check(0); + } SubGhzWorker* worker = context; furi_hal_subghz_idle(); @@ -33,6 +36,9 @@ uint32_t subghz_rx(void* context, uint32_t frequency) { } uint32_t subghz_tx(uint32_t frequency) { + if(!furi_hal_subghz_is_frequency_valid(frequency)) { + furi_check(0); + } furi_hal_subghz_idle(); uint32_t value = furi_hal_subghz_set_frequency_and_path(frequency); hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); @@ -53,6 +59,7 @@ void subghz_rx_end(void* context) { subghz_worker_stop(worker); furi_hal_subghz_stop_async_rx(); } + furi_hal_subghz_idle(); } void subghz_sleep(void) { @@ -66,41 +73,46 @@ void subghz_frequency_preset_to_str(void* context, string_t output) { output, "Frequency: %d\n" "Preset: %d\n", - (int)subghz->frequency, - (int)subghz->preset); + (int)subghz->txrx->frequency, + (int)subghz->txrx->preset); } -void subghz_transmitter_tx_start(void* context) { +void subghz_tx_start(void* context) { + furi_assert(context); SubGhz* subghz = context; - subghz->encoder = subghz_protocol_encoder_common_alloc(); - subghz->encoder->repeat = 200; //max repeat with the button held down + subghz->txrx->encoder = subghz_protocol_encoder_common_alloc(); + subghz->txrx->encoder->repeat = 200; //max repeat with the button held down //get upload - if(subghz->protocol_result->get_upload_protocol) { - if(subghz->protocol_result->get_upload_protocol(subghz->protocol_result, subghz->encoder)) { - if(subghz->preset) { - subghz_begin(subghz->preset); + if(subghz->txrx->protocol_result->get_upload_protocol) { + if(subghz->txrx->protocol_result->get_upload_protocol( + subghz->txrx->protocol_result, subghz->txrx->encoder)) { + if(subghz->txrx->preset) { + subghz_begin(subghz->txrx->preset); } else { - subghz_begin(FuriHalSubGhzPresetOok650Async); + subghz_begin(FuriHalSubGhzPresetOok270Async); } - if(subghz->frequency) { - subghz_tx(subghz->frequency); + if(subghz->txrx->frequency) { + subghz_tx(subghz->txrx->frequency); } else { subghz_tx(433920000); } //Start TX - furi_hal_subghz_start_async_tx(subghz_protocol_encoder_common_yield, subghz->encoder); + furi_hal_subghz_start_async_tx( + subghz_protocol_encoder_common_yield, subghz->txrx->encoder); } } } -void subghz_transmitter_tx_stop(void* context) { +void subghz_tx_stop(void* context) { + furi_assert(context); SubGhz* subghz = context; //Stop TX furi_hal_subghz_stop_async_tx(); - subghz_protocol_encoder_common_free(subghz->encoder); + subghz_protocol_encoder_common_free(subghz->txrx->encoder); + furi_hal_subghz_idle(); //if protocol dynamic then we save the last upload - if(subghz->protocol_result->type_protocol == TYPE_PROTOCOL_DYNAMIC) { + if(subghz->txrx->protocol_result->type_protocol == TYPE_PROTOCOL_DYNAMIC) { subghz_save_protocol_to_file(subghz, subghz->text_store); } notification_message(subghz->notifications, &sequence_reset_red); @@ -133,7 +145,7 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path) { if(res != 1) { break; } - subghz->frequency = (uint32_t)data; + subghz->txrx->frequency = (uint32_t)data; // Read and parse preset from 2st line if(!file_worker_read_until(file_worker, temp_str, '\n')) { @@ -143,7 +155,7 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path) { if(res != 1) { break; } - subghz->preset = (FuriHalSubGhzPreset)data; + subghz->txrx->preset = (FuriHalSubGhzPreset)data; // Read and parse name protocol from 2st line if(!file_worker_read_until(file_worker, temp_str, '\n')) { @@ -151,13 +163,13 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path) { } // strlen("Protocol: ") = 10 string_right(temp_str, 10); - subghz->protocol_result = - subghz_protocol_get_by_name(subghz->protocol, string_get_cstr(temp_str)); - if(subghz->protocol_result == NULL) { + subghz->txrx->protocol_result = + subghz_protocol_get_by_name(subghz->txrx->protocol, string_get_cstr(temp_str)); + if(subghz->txrx->protocol_result == NULL) { break; } - if(!subghz->protocol_result->to_load_protocol_from_file( - file_worker, subghz->protocol_result)) { + if(!subghz->txrx->protocol_result->to_load_protocol_from_file( + file_worker, subghz->txrx->protocol_result)) { break; } loaded = true; @@ -175,8 +187,9 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path) { } bool subghz_save_protocol_to_file(void* context, const char* dev_name) { + furi_assert(context); SubGhz* subghz = context; - furi_assert(subghz->protocol_result); + furi_assert(subghz->txrx->protocol_result); FileWorker* file_worker = file_worker_alloc(false); string_t dev_file_name; string_init(dev_file_name); @@ -210,7 +223,7 @@ bool subghz_save_protocol_to_file(void* context, const char* dev_name) { break; } //Get string save - subghz->protocol_result->to_save_string(subghz->protocol_result, temp_str); + subghz->txrx->protocol_result->to_save_string(subghz->txrx->protocol_result, temp_str); // Prepare and write data to file if(!file_worker_write(file_worker, string_get_cstr(temp_str), string_size(temp_str))) { break; @@ -276,7 +289,7 @@ bool subghz_load_protocol_from_file(SubGhz* subghz) { if(sscanf_res != 1) { break; } - subghz->frequency = (uint32_t)data; + subghz->txrx->frequency = (uint32_t)data; // Read and parse preset from 2st line if(!file_worker_read_until(file_worker, temp_str, '\n')) { @@ -286,7 +299,7 @@ bool subghz_load_protocol_from_file(SubGhz* subghz) { if(sscanf_res != 1) { break; } - subghz->preset = (FuriHalSubGhzPreset)data; + subghz->txrx->preset = (FuriHalSubGhzPreset)data; // Read and parse name protocol from 3st line if(!file_worker_read_until(file_worker, temp_str, '\n')) { @@ -294,13 +307,13 @@ bool subghz_load_protocol_from_file(SubGhz* subghz) { } // strlen("Protocol: ") = 10 string_right(temp_str, 10); - subghz->protocol_result = - subghz_protocol_get_by_name(subghz->protocol, string_get_cstr(temp_str)); - if(subghz->protocol_result == NULL) { + subghz->txrx->protocol_result = + subghz_protocol_get_by_name(subghz->txrx->protocol, string_get_cstr(temp_str)); + if(subghz->txrx->protocol_result == NULL) { break; } - if(!subghz->protocol_result->to_load_protocol_from_file( - file_worker, subghz->protocol_result)) { + if(!subghz->txrx->protocol_result->to_load_protocol_from_file( + file_worker, subghz->txrx->protocol_result)) { break; } res = true; @@ -328,3 +341,57 @@ uint32_t subghz_random_serial(void) { } return (uint32_t)rand(); } + +void subghz_hopper_update(void* context) { + furi_assert(context); + SubGhzTxRx* txrx = context; + + switch(txrx->hopper_state) { + case SubGhzHopperStateOFF: + return; + break; + case SubGhzHopperStatePause: + return; + break; + case SubGhzHopperStateRSSITimeOut: + if(txrx->hopper_timeout != 0) { + txrx->hopper_timeout--; + return; + } + break; + default: + break; + } + float rssi = -127.0f; + if(txrx->hopper_state != SubGhzHopperStateRSSITimeOut) { + // See RSSI Calculation timings in CC1101 17.3 RSSI + rssi = furi_hal_subghz_get_rssi(); + + // Stay if RSSI is high enough + if(rssi > -90.0f) { + txrx->hopper_timeout = 10; + txrx->hopper_state = SubGhzHopperStateRSSITimeOut; + return; + } + } else { + txrx->hopper_state = SubGhzHopperStateRunnig; + } + + // Select next frequency + if(txrx->hopper_idx_frequency < subghz_hopper_frequencies_count - 1) { + txrx->hopper_idx_frequency++; + } else { + txrx->hopper_idx_frequency = 0; + } + + if(txrx->txrx_state == SubGhzTxRxStateRx) { + subghz_rx_end(txrx->worker); + txrx->txrx_state = SubGhzTxRxStateIdle; + }; + if(txrx->txrx_state == SubGhzTxRxStateIdle) { + subghz_protocol_reset(txrx->protocol); + txrx->frequency = subghz_hopper_frequencies[txrx->hopper_idx_frequency]; + subghz_rx(txrx->worker, txrx->frequency); + txrx->txrx_state = SubGhzTxRxStateRx; + } +} diff --git a/applications/subghz/subghz_i.h b/applications/subghz/subghz_i.h index 8d4ab93c..9d088dc6 100644 --- a/applications/subghz/subghz_i.h +++ b/applications/subghz/subghz_i.h @@ -15,9 +15,9 @@ #include #include #include -#include #include #include +#include #include @@ -26,6 +26,8 @@ #include #include "subghz_history.h" +#include + #define SUBGHZ_TEXT_STORE_SIZE 128 #define NOTIFICATION_STARTING_STATE 0u @@ -33,48 +35,81 @@ #define NOTIFICATION_TX_STATE 2u #define NOTIFICATION_RX_STATE 3u +extern const char* const subghz_frequencies_text[]; extern const uint32_t subghz_frequencies[]; +extern const uint32_t subghz_hopper_frequencies[]; extern const uint32_t subghz_frequencies_count; +extern const uint32_t subghz_hopper_frequencies_count; extern const uint32_t subghz_frequencies_433_92; -struct SubGhz { - Gui* gui; - NotificationApp* notifications; +/** SubGhzTxRx state */ +typedef enum { + SubGhzTxRxStateIdle, + SubGhzTxRxStateRx, + SubGhzTxRxStateTx, +} SubGhzTxRxState; +/** SubGhzHopperState state */ +typedef enum { + SubGhzHopperStateOFF, + SubGhzHopperStateRunnig, + SubGhzHopperStatePause, + SubGhzHopperStateRSSITimeOut, +} SubGhzHopperState; + +struct SubGhzTxRx { SubGhzWorker* worker; SubGhzProtocol* protocol; SubGhzProtocolCommon* protocol_result; SubGhzProtocolCommonEncoder* encoder; uint32_t frequency; FuriHalSubGhzPreset preset; + SubGhzHistory* history; + uint16_t idx_menu_chosen; + SubGhzTxRxState txrx_state; + //bool hopper_runing; + SubGhzHopperState hopper_state; + uint8_t hopper_timeout; + uint8_t hopper_idx_frequency; +}; + +typedef struct SubGhzTxRx SubGhzTxRx; + +struct SubGhz { + Gui* gui; + NotificationApp* notifications; + + SubGhzTxRx* txrx; SceneManager* scene_manager; ViewDispatcher* view_dispatcher; Submenu* submenu; - DialogEx* dialog_ex; Popup* popup; TextInput* text_input; + Widget* widget; char text_store[SUBGHZ_TEXT_STORE_SIZE + 1]; uint8_t state_notifications; SubghzReceiver* subghz_receiver; SubghzTransmitter* subghz_transmitter; + VariableItemList* variable_item_list; SubghzTestStatic* subghz_test_static; SubghzTestCarrier* subghz_test_carrier; SubghzTestPacket* subghz_test_packet; + string_t error_str; }; typedef enum { SubGhzViewMenu, - SubGhzViewDialogEx, SubGhzViewReceiver, SubGhzViewPopup, SubGhzViewTextInput, + SubGhzViewWidget, SubGhzViewTransmitter, - + SubGhzViewVariableItemList, SubGhzViewStatic, SubGhzViewTestCarrier, SubGhzViewTestPacket, @@ -86,8 +121,8 @@ uint32_t subghz_tx(uint32_t frequency); void subghz_idle(void); void subghz_rx_end(void* context); void subghz_sleep(void); -void subghz_transmitter_tx_start(void* context); -void subghz_transmitter_tx_stop(void* context); +void subghz_tx_start(void* context); +void subghz_tx_stop(void* context); bool subghz_key_load(SubGhz* subghz, const char* file_path); bool subghz_save_protocol_to_file(void* context, const char* dev_name); bool subghz_load_protocol_from_file(SubGhz* subghz); diff --git a/applications/subghz/views/subghz_receiver.c b/applications/subghz/views/subghz_receiver.c index df70786b..4abf8225 100644 --- a/applications/subghz/views/subghz_receiver.c +++ b/applications/subghz/views/subghz_receiver.c @@ -1,42 +1,32 @@ #include "subghz_receiver.h" #include "../subghz_i.h" #include -#include -#include + #include #include -#include -#include - #include +#include +#include #define FRAME_HEIGHT 12 #define MAX_LEN_PX 100 #define MENU_ITEMS 4 -#define COUNT_FREQUNCY_HOPPER 3 -const uint32_t subghz_frequencies_hopper[] = { - /* 300 - 348 */ - 315000000, - /* 387 - 464 */ - 433920000, /* LPD433 mid */ - /* 779 - 928 */ - 868350000, +typedef struct { + string_t item_str; + uint8_t type; +} SubGhzReceiverMenuItem; + +ARRAY_DEF(SubGhzReceiverMenuItemArray, SubGhzReceiverMenuItem, M_POD_OPLIST) + +#define M_OPL_SubGhzReceiverMenuItemArray_t() \ + ARRAY_OPLIST(SubGhzReceiverMenuItemArray, M_POD_OPLIST) + +struct SubGhzReceiverHistory { + SubGhzReceiverMenuItemArray_t data; }; -typedef enum { - ReceiverSceneStart, - ReceiverSceneMain, - ReceiverSceneConfig, - ReceiverSceneInfo, -} SubghzReceiverScene; - -typedef enum { - SubGhzHopperStateOFF, - SubGhzHopperStatePause, - SubGhzHopperStateRunnig, - SubGhzHopperStateRSSITimeOut, -} SubGhzHopperState; +typedef struct SubGhzReceiverHistory SubGhzReceiverHistory; static const Icon* ReceiverItemIcons[] = { [TYPE_PROTOCOL_UNKNOWN] = &I_Quest_7x8, @@ -48,27 +38,16 @@ struct SubghzReceiver { View* view; SubghzReceiverCallback callback; void* context; - SubGhzWorker* worker; - SubGhzProtocol* protocol; - osTimerId timer; - SubGhzHopperState hopper_state; - uint8_t hopper_timeout; - uint32_t event_key_sequence; }; typedef struct { - string_t text; - uint16_t scene; - SubGhzProtocolCommon* protocol_result; - SubGhzHistory* history; - uint8_t frequency; - uint8_t temp_frequency; - uint32_t real_frequency; - + string_t frequency_str; + string_t preset_str; + string_t history_stat_str; + SubGhzReceiverHistory* history; uint16_t idx; uint16_t list_offset; uint16_t history_item; - bool menu; } SubghzReceiverModel; void subghz_receiver_set_callback( @@ -81,35 +60,6 @@ void subghz_receiver_set_callback( subghz_receiver->context = context; } -void subghz_receiver_set_protocol( - SubghzReceiver* subghz_receiver, - SubGhzProtocolCommon* protocol_result, - SubGhzProtocol* protocol) { - furi_assert(subghz_receiver); - with_view_model( - subghz_receiver->view, (SubghzReceiverModel * model) { - model->protocol_result = protocol_result; - return true; - }); - subghz_receiver->protocol = protocol; -} - -SubGhzProtocolCommon* subghz_receiver_get_protocol(SubghzReceiver* subghz_receiver) { - furi_assert(subghz_receiver); - SubGhzProtocolCommon* result = NULL; - with_view_model( - subghz_receiver->view, (SubghzReceiverModel * model) { - result = model->protocol_result; - return false; - }); - return result; -} - -void subghz_receiver_set_worker(SubghzReceiver* subghz_receiver, SubGhzWorker* worker) { - furi_assert(subghz_receiver); - subghz_receiver->worker = worker; -} - static void subghz_receiver_update_offset(SubghzReceiver* subghz_receiver) { furi_assert(subghz_receiver); @@ -129,6 +79,38 @@ static void subghz_receiver_update_offset(SubghzReceiver* subghz_receiver) { }); } +void subghz_receiver_add_item_to_menu( + SubghzReceiver* subghz_receiver, + const char* name, + uint8_t type) { + furi_assert(subghz_receiver); + with_view_model( + subghz_receiver->view, (SubghzReceiverModel * model) { + SubGhzReceiverMenuItem* item_menu = + SubGhzReceiverMenuItemArray_push_raw(model->history->data); + string_init_set_str(item_menu->item_str, name); + item_menu->type = type; + model->history_item++; + return true; + }); + subghz_receiver_update_offset(subghz_receiver); +} + +void subghz_receiver_add_data_statusbar( + SubghzReceiver* subghz_receiver, + const char* frequency_str, + const char* preset_str, + const char* history_stat_str) { + furi_assert(subghz_receiver); + with_view_model( + subghz_receiver->view, (SubghzReceiverModel * model) { + string_set(model->frequency_str, frequency_str); + string_set(model->preset_str, preset_str); + string_set(model->history_stat_str, history_stat_str); + return true; + }); +} + static void subghz_receiver_draw_frame(Canvas* canvas, uint16_t idx, bool scrollbar) { canvas_set_color(canvas, ColorBlack); canvas_draw_box(canvas, 0, 0 + idx * FRAME_HEIGHT, scrollbar ? 122 : 127, FRAME_HEIGHT); @@ -144,462 +126,113 @@ static void subghz_receiver_draw_frame(Canvas* canvas, uint16_t idx, bool scroll } void subghz_receiver_draw(Canvas* canvas, SubghzReceiverModel* model) { - bool scrollbar = model->history_item > 4; - string_t str_buff; - char buffer[64]; - uint32_t frequency; - string_init(str_buff); - canvas_clear(canvas); canvas_set_color(canvas, ColorBlack); + canvas_set_font(canvas, FontSecondary); - switch(model->scene) { - case ReceiverSceneMain: - for(size_t i = 0; i < MIN(model->history_item, MENU_ITEMS); ++i) { - size_t idx = CLAMP(i + model->list_offset, model->history_item, 0); - subghz_history_get_text_item_menu(model->history, str_buff, idx); - elements_string_fit_width(canvas, str_buff, scrollbar ? MAX_LEN_PX - 6 : MAX_LEN_PX); - if(model->idx == idx) { - subghz_receiver_draw_frame(canvas, i, scrollbar); - } else { - canvas_set_color(canvas, ColorBlack); - } - canvas_draw_icon( - canvas, - 1, - 2 + i * FRAME_HEIGHT, - ReceiverItemIcons[subghz_history_get_type_protocol(model->history, idx)]); - canvas_draw_str(canvas, 15, 9 + i * FRAME_HEIGHT, string_get_cstr(str_buff)); - string_clean(str_buff); - } - if(scrollbar) { - elements_scrollbar_pos(canvas, 128, 0, 49, model->idx, model->history_item); - } - canvas_set_color(canvas, ColorBlack); - canvas_set_font(canvas, FontSecondary); + elements_button_left(canvas, "Config"); - elements_button_left(canvas, "Config"); - canvas_draw_line(canvas, 46, 51, 125, 51); - if(subghz_history_get_text_space_left(model->history, str_buff)) { - canvas_draw_str(canvas, 54, 62, string_get_cstr(str_buff)); - } else { - if((model->real_frequency / 1000 % 10) > 4) { - frequency = model->real_frequency + 10000; - } else { - frequency = model->real_frequency; - } - snprintf( - buffer, - sizeof(buffer), - "%03ld.%02ld", - frequency / 1000000 % 1000, - frequency / 10000 % 100); - canvas_draw_str(canvas, 44, 62, buffer); - canvas_draw_str(canvas, 79, 62, "AM"); - canvas_draw_str(canvas, 96, 62, string_get_cstr(str_buff)); - } - break; - - case ReceiverSceneStart: + canvas_draw_str(canvas, 44, 62, string_get_cstr(model->frequency_str)); + canvas_draw_str(canvas, 79, 62, string_get_cstr(model->preset_str)); + canvas_draw_str(canvas, 96, 62, string_get_cstr(model->history_stat_str)); + if(model->history_item == 0) { canvas_draw_icon(canvas, 0, 0, &I_Scanning_123x52); canvas_set_font(canvas, FontPrimary); canvas_draw_str(canvas, 63, 46, "Scanning..."); - canvas_set_color(canvas, ColorBlack); - canvas_set_font(canvas, FontSecondary); - elements_button_left(canvas, "Config"); - if((model->real_frequency / 1000 % 10) > 4) { - frequency = model->real_frequency + 10000; - } else { - frequency = model->real_frequency; - } - snprintf( - buffer, - sizeof(buffer), - "%03ld.%02ld", - frequency / 1000000 % 1000, - frequency / 10000 % 100); - canvas_draw_str(canvas, 44, 62, buffer); - canvas_draw_str(canvas, 79, 62, "AM"); - subghz_history_get_text_space_left(model->history, str_buff); - canvas_draw_str(canvas, 96, 62, string_get_cstr(str_buff)); canvas_draw_line(canvas, 46, 51, 125, 51); - break; - - case ReceiverSceneConfig: - if(model->frequency < subghz_frequencies_count) { - snprintf( - buffer, - sizeof(buffer), - "Frequency: < %03ld.%03ldMHz >", - model->real_frequency / 1000000 % 1000, - model->real_frequency / 1000 % 1000); - canvas_draw_str(canvas, 0, 8, buffer); - canvas_draw_str(canvas, 0, 18, "Frequency Hopping: "); - } else { - canvas_draw_str(canvas, 0, 8, "Frequency: < --- >"); - canvas_draw_str(canvas, 0, 18, "Frequency Hopping: "); - } - canvas_draw_str(canvas, 0, 28, "Modulation: "); - - elements_button_center(canvas, "Save"); - break; - - case ReceiverSceneInfo: - canvas_set_font(canvas, FontSecondary); - elements_multiline_text(canvas, 0, 8, string_get_cstr(model->text)); - snprintf( - buffer, - sizeof(buffer), - "%03ld.%03ld", - subghz_history_get_frequency(model->history, model->idx) / 1000000 % 1000, - subghz_history_get_frequency(model->history, model->idx) / 1000 % 1000); - canvas_draw_str(canvas, 90, 8, buffer); - if(model->protocol_result && model->protocol_result->to_save_string && - strcmp(model->protocol_result->name, "KeeLoq")) { - elements_button_right(canvas, "Save"); - elements_button_center(canvas, "Send"); - } - break; - - default: - - break; + return; } + canvas_draw_line(canvas, 46, 51, 125, 51); + bool scrollbar = model->history_item > 4; + string_t str_buff; + string_init(str_buff); + + SubGhzReceiverMenuItem* item_menu; + + for(size_t i = 0; i < MIN(model->history_item, MENU_ITEMS); ++i) { + size_t idx = CLAMP(i + model->list_offset, model->history_item, 0); + item_menu = SubGhzReceiverMenuItemArray_get(model->history->data, idx); + string_set(str_buff, item_menu->item_str); + elements_string_fit_width(canvas, str_buff, scrollbar ? MAX_LEN_PX - 6 : MAX_LEN_PX); + if(model->idx == idx) { + subghz_receiver_draw_frame(canvas, i, scrollbar); + } else { + canvas_set_color(canvas, ColorBlack); + } + canvas_draw_icon(canvas, 1, 2 + i * FRAME_HEIGHT, ReceiverItemIcons[item_menu->type]); + canvas_draw_str(canvas, 15, 9 + i * FRAME_HEIGHT, string_get_cstr(str_buff)); + string_clean(str_buff); + } + if(scrollbar) { + elements_scrollbar_pos(canvas, 128, 0, 49, model->idx, model->history_item); + } string_clear(str_buff); } -void subghz_receiver_history_full(void* context) { - furi_assert(context); - SubghzReceiver* subghz_receiver = context; - subghz_receiver->callback(SubghzReceverEventSendHistoryFull, subghz_receiver->context); - subghz_receiver->hopper_state = SubGhzHopperStateOFF; -} - bool subghz_receiver_input(InputEvent* event, void* context) { furi_assert(context); - - uint8_t scene = 0; SubghzReceiver* subghz_receiver = context; - with_view_model( - subghz_receiver->view, (SubghzReceiverModel * model) { - scene = model->scene; - return false; - }); - bool can_be_saved = false; - - switch(scene) { - case ReceiverSceneMain: - if(event->key == InputKeyBack && event->type == InputTypeShort) { - with_view_model( - subghz_receiver->view, (SubghzReceiverModel * model) { - model->idx = 0; - model->list_offset = 0; - model->history_item = 0; - subghz_history_clean(model->history); - return true; - }); - return false; - } else if( - event->key == InputKeyUp && - (event->type == InputTypeShort || event->type == InputTypeRepeat)) { - with_view_model( - subghz_receiver->view, (SubghzReceiverModel * model) { - if(model->idx != 0) model->idx--; - return true; - }); - } else if( - event->key == InputKeyDown && - (event->type == InputTypeShort || event->type == InputTypeRepeat)) { - with_view_model( - subghz_receiver->view, (SubghzReceiverModel * model) { - if(model->idx != subghz_history_get_item(model->history) - 1) model->idx++; - return true; - }); - } else if(event->key == InputKeyLeft && event->type == InputTypeShort) { - subghz_receiver->hopper_state = SubGhzHopperStatePause; - with_view_model( - subghz_receiver->view, (SubghzReceiverModel * model) { - model->scene = ReceiverSceneConfig; - model->temp_frequency = model->frequency; - return true; - }); - subghz_receiver->callback(SubghzReceverEventConfig, subghz_receiver->context); - } else if(event->key == InputKeyOk && event->type == InputTypeShort) { - subghz_receiver->event_key_sequence = event->sequence; - with_view_model( - subghz_receiver->view, (SubghzReceiverModel * model) { - string_clean(model->text); - model->protocol_result = subghz_protocol_get_by_name( - subghz_receiver->protocol, - subghz_history_get_name(model->history, model->idx)); - if(model->protocol_result->to_load_protocol != NULL) { - model->protocol_result->to_load_protocol( - model->protocol_result, - subghz_history_get_raw_data(model->history, model->idx)); - model->protocol_result->to_string(model->protocol_result, model->text); - model->scene = ReceiverSceneInfo; - } - return true; - }); - } - break; - - case ReceiverSceneInfo: + if(event->key == InputKeyBack && event->type == InputTypeShort) { + subghz_receiver->callback(SubghzReceverEventBack, subghz_receiver->context); + } else if( + event->key == InputKeyUp && + (event->type == InputTypeShort || event->type == InputTypeRepeat)) { with_view_model( subghz_receiver->view, (SubghzReceiverModel * model) { - can_be_saved = - (model->protocol_result && model->protocol_result->to_save_string && - strcmp(model->protocol_result->name, "KeeLoq")); - return false; + if(model->idx != 0) model->idx--; + return true; }); - if(event->key == InputKeyBack && event->type == InputTypeShort) { - with_view_model( - subghz_receiver->view, (SubghzReceiverModel * model) { - subghz_rx_end(subghz_receiver->worker); - model->real_frequency = - subghz_rx(subghz_receiver->worker, subghz_frequencies[model->frequency]); - subghz_receiver->hopper_state = SubGhzHopperStateRunnig; - model->scene = ReceiverSceneMain; - return true; - }); - subghz_receiver->callback(SubghzReceverEventMain, subghz_receiver->context); - } else if(can_be_saved && event->key == InputKeyRight) { - subghz_receiver->callback(SubghzReceverEventSave, subghz_receiver->context); - return false; - } else if( - can_be_saved && event->key == InputKeyOk && event->type == InputTypePress && - subghz_receiver->event_key_sequence != event->sequence) { - subghz_receiver->hopper_state = SubGhzHopperStatePause; - subghz_rx_end(subghz_receiver->worker); - subghz_receiver->callback(SubghzReceverEventSendStart, subghz_receiver->context); - return true; - } else if( - can_be_saved && event->key == InputKeyOk && event->type == InputTypeRelease && - subghz_receiver->event_key_sequence != event->sequence) { - subghz_receiver->callback(SubghzReceverEventSendStop, subghz_receiver->context); - return true; - } - break; - - case ReceiverSceneConfig: - if(event->type != InputTypeShort) return false; - if(event->key == InputKeyBack) { - with_view_model( - subghz_receiver->view, (SubghzReceiverModel * model) { - model->frequency = model->temp_frequency; - model->real_frequency = subghz_frequencies[model->frequency]; - subghz_receiver->hopper_state = SubGhzHopperStateRunnig; - if(subghz_history_get_item(model->history) == 0) { - model->scene = ReceiverSceneStart; - } else { - model->scene = ReceiverSceneMain; - } - return true; - }); - subghz_receiver->callback(SubghzReceverEventMain, subghz_receiver->context); - } else if(event->key == InputKeyOk) { - with_view_model( - subghz_receiver->view, (SubghzReceiverModel * model) { - if(model->frequency < subghz_frequencies_count) { - subghz_rx_end(subghz_receiver->worker); - model->real_frequency = subghz_rx( - subghz_receiver->worker, subghz_frequencies[model->frequency]); - subghz_receiver->hopper_state = SubGhzHopperStateOFF; - } else { - osTimerStart(subghz_receiver->timer, 1024 / 10); - subghz_receiver->hopper_state = SubGhzHopperStateRunnig; - } - if(subghz_history_get_item(model->history) == 0) { - model->scene = ReceiverSceneStart; - } else { - model->scene = ReceiverSceneMain; - } - return true; - }); - subghz_receiver->callback(SubghzReceverEventMain, subghz_receiver->context); - } else { - with_view_model( - subghz_receiver->view, (SubghzReceiverModel * model) { - bool model_updated = false; - - if(event->key == InputKeyLeft) { - if(model->frequency > 0) model->frequency--; - model_updated = true; - } else if(event->key == InputKeyRight) { - if(model->frequency < subghz_frequencies_count) model->frequency++; - model_updated = true; - } - if(model_updated) { - model->real_frequency = subghz_frequencies[model->frequency]; - } - return model_updated; - }); - } - break; - - case ReceiverSceneStart: - if(event->type != InputTypeShort) return false; - if(event->key == InputKeyBack) { - return false; - } else if(event->key == InputKeyLeft) { - subghz_receiver->hopper_state = SubGhzHopperStatePause; - with_view_model( - subghz_receiver->view, (SubghzReceiverModel * model) { - model->temp_frequency = model->frequency; - model->scene = ReceiverSceneConfig; - return true; - }); - subghz_receiver->callback(SubghzReceverEventConfig, subghz_receiver->context); - } - break; - - default: - break; - } - - subghz_receiver_update_offset(subghz_receiver); - if(scene != ReceiverSceneInfo) { + } else if( + event->key == InputKeyDown && + (event->type == InputTypeShort || event->type == InputTypeRepeat)) { with_view_model( subghz_receiver->view, (SubghzReceiverModel * model) { - if(subghz_history_get_text_space_left(model->history, NULL)) { - subghz_receiver_history_full(subghz_receiver); + if(model->idx != model->history_item - 1) model->idx++; + return true; + }); + } else if(event->key == InputKeyLeft && event->type == InputTypeShort) { + subghz_receiver->callback(SubghzReceverEventConfig, subghz_receiver->context); + } else if(event->key == InputKeyOk && event->type == InputTypeShort) { + with_view_model( + subghz_receiver->view, (SubghzReceiverModel * model) { + if(model->history_item != 0) { + subghz_receiver->callback(SubghzReceverEventOK, subghz_receiver->context); } return false; }); } + subghz_receiver_update_offset(subghz_receiver); + return true; } -void subghz_receiver_text_callback(string_t text, void* context) { - furi_assert(context); - SubghzReceiver* subghz_receiver = context; - - with_view_model( - subghz_receiver->view, (SubghzReceiverModel * model) { - string_set(model->text, text); - model->scene = ReceiverSceneMain; - return true; - }); -} - -void subghz_receiver_protocol_callback(SubGhzProtocolCommon* parser, void* context) { - furi_assert(context); - SubghzReceiver* subghz_receiver = context; - - with_view_model( - subghz_receiver->view, (SubghzReceiverModel * model) { - model->protocol_result = parser; - subghz_history_set_frequency_preset( - model->history, - model->history_item, - model->real_frequency, - FuriHalSubGhzPresetOok650Async); - subghz_history_add_to_history(model->history, parser); - - model->history_item = subghz_history_get_item(model->history); - model->scene = ReceiverSceneMain; - if(subghz_history_get_text_space_left(model->history, NULL)) { - subghz_receiver_history_full(subghz_receiver); - } - return true; - }); - subghz_protocol_reset(subghz_receiver->protocol); - subghz_receiver_update_offset(subghz_receiver); -} - -static void subghz_receiver_timer_callback(void* context) { - furi_assert(context); - SubghzReceiver* subghz_receiver = context; - - switch(subghz_receiver->hopper_state) { - case SubGhzHopperStatePause: - return; - break; - case SubGhzHopperStateOFF: - osTimerStop(subghz_receiver->timer); - return; - break; - case SubGhzHopperStateRSSITimeOut: - if(subghz_receiver->hopper_timeout != 0) { - subghz_receiver->hopper_timeout--; - return; - } - break; - default: - break; - } - float rssi = -127.0f; - with_view_model( - subghz_receiver->view, (SubghzReceiverModel * model) { - if(subghz_receiver->hopper_state != SubGhzHopperStateRSSITimeOut) { - // See RSSI Calculation timings in CC1101 17.3 RSSI - rssi = furi_hal_subghz_get_rssi(); - - // Stay if RSSI is high enough - if(rssi > -90.0f) { - subghz_receiver->hopper_timeout = 10; - subghz_receiver->hopper_state = SubGhzHopperStateRSSITimeOut; - return false; - } - } else { - subghz_receiver->hopper_state = SubGhzHopperStateRunnig; - } - - // Select next frequency - if(model->frequency < COUNT_FREQUNCY_HOPPER - 1) { - model->frequency++; - } else { - model->frequency = 0; - } - - // Restart radio - furi_hal_subghz_idle(); - subghz_protocol_reset(subghz_receiver->protocol); - model->real_frequency = furi_hal_subghz_set_frequency_and_path( - subghz_frequencies_hopper[model->frequency]); - furi_hal_subghz_rx(); - - return true; - }); -} - void subghz_receiver_enter(void* context) { furi_assert(context); - SubghzReceiver* subghz_receiver = context; - //Start CC1101 Rx - subghz_begin(FuriHalSubGhzPresetOok650Async); - with_view_model( - subghz_receiver->view, (SubghzReceiverModel * model) { - subghz_rx_end(subghz_receiver->worker); - model->frequency = subghz_frequencies_433_92; - model->real_frequency = - subghz_rx(subghz_receiver->worker, subghz_frequencies[model->frequency]); - if(subghz_history_get_item(model->history) == 0) { - model->scene = ReceiverSceneStart; - } else { - model->scene = ReceiverSceneMain; - } - return true; - }); - subghz_protocol_enable_dump( - subghz_receiver->protocol, subghz_receiver_protocol_callback, subghz_receiver); + //SubghzReceiver* subghz_receiver = context; } void subghz_receiver_exit(void* context) { furi_assert(context); SubghzReceiver* subghz_receiver = context; - osTimerStop(subghz_receiver->timer); with_view_model( subghz_receiver->view, (SubghzReceiverModel * model) { - string_clean(model->text); - return true; + string_clean(model->frequency_str); + string_clean(model->preset_str); + string_clean(model->history_stat_str); + for + M_EACH(item_menu, model->history->data, SubGhzReceiverMenuItemArray_t) { + string_clear(item_menu->item_str); + item_menu->type = 0; + } + SubGhzReceiverMenuItemArray_clean(model->history->data); + model->idx = 0; + model->list_offset = 0; + model->history_item = 0; + return false; }); - // Stop CC1101 Rx - subghz_rx_end(subghz_receiver->worker); - subghz_sleep(); } SubghzReceiver* subghz_receiver_alloc() { @@ -616,14 +249,14 @@ SubghzReceiver* subghz_receiver_alloc() { with_view_model( subghz_receiver->view, (SubghzReceiverModel * model) { - string_init(model->text); - model->history = subghz_history_alloc(); + string_init(model->frequency_str); + string_init(model->preset_str); + string_init(model->history_stat_str); + model->history = furi_alloc(sizeof(SubGhzReceiverHistory)); + SubGhzReceiverMenuItemArray_init(model->history->data); return true; }); - subghz_receiver->timer = - osTimerNew(subghz_receiver_timer_callback, osTimerPeriodic, subghz_receiver, NULL); - subghz_receiver->hopper_state = SubGhzHopperStateOFF; return subghz_receiver; } @@ -632,11 +265,18 @@ void subghz_receiver_free(SubghzReceiver* subghz_receiver) { with_view_model( subghz_receiver->view, (SubghzReceiverModel * model) { - string_clear(model->text); - subghz_history_free(model->history); - return false; + string_clear(model->frequency_str); + string_clear(model->preset_str); + string_clear(model->history_stat_str); + for + M_EACH(item_menu, model->history->data, SubGhzReceiverMenuItemArray_t) { + string_clear(item_menu->item_str); + item_menu->type = 0; + } + SubGhzReceiverMenuItemArray_clear(model->history->data); + free(model->history); + return false; }); - osTimerDelete(subghz_receiver->timer); view_free(subghz_receiver->view); free(subghz_receiver); } @@ -646,43 +286,24 @@ View* subghz_receiver_get_view(SubghzReceiver* subghz_receiver) { return subghz_receiver->view; } -uint32_t subghz_receiver_get_frequency(SubghzReceiver* subghz_receiver) { +uint16_t subghz_receiver_get_idx_menu(SubghzReceiver* subghz_receiver) { furi_assert(subghz_receiver); - uint32_t frequency; + uint32_t idx = 0; with_view_model( subghz_receiver->view, (SubghzReceiverModel * model) { - frequency = subghz_history_get_frequency(model->history, model->idx); + idx = model->idx; return false; }); - return frequency; + return idx; } -FuriHalSubGhzPreset subghz_receiver_get_preset(SubghzReceiver* subghz_receiver) { +void subghz_receiver_set_idx_menu(SubghzReceiver* subghz_receiver, uint16_t idx) { furi_assert(subghz_receiver); - FuriHalSubGhzPreset preset; with_view_model( subghz_receiver->view, (SubghzReceiverModel * model) { - preset = subghz_history_get_preset(model->history, model->idx); - return false; + model->idx = idx; + if(model->idx > 2) model->list_offset = idx - 2; + return true; }); - return preset; -} - -void subghz_receiver_frequency_preset_to_str(SubghzReceiver* subghz_receiver, string_t output) { - furi_assert(subghz_receiver); - uint32_t frequency; - uint32_t preset; - with_view_model( - subghz_receiver->view, (SubghzReceiverModel * model) { - frequency = subghz_history_get_frequency(model->history, model->idx); - preset = (uint32_t)subghz_history_get_preset(model->history, model->idx); - return false; - }); - - string_cat_printf( - output, - "Frequency: %d\n" - "Preset: %d\n", - (int)frequency, - (int)preset); -} + subghz_receiver_update_offset(subghz_receiver); +} \ No newline at end of file diff --git a/applications/subghz/views/subghz_receiver.h b/applications/subghz/views/subghz_receiver.h index 513f438c..be9a9ef1 100644 --- a/applications/subghz/views/subghz_receiver.h +++ b/applications/subghz/views/subghz_receiver.h @@ -1,21 +1,11 @@ #pragma once #include -#include -#include -#include -#include "../subghz_history.h" typedef enum { SubghzReceverEventOK, SubghzReceverEventConfig, - SubghzReceverEventMain, - SubghzReceverEventSave, SubghzReceverEventBack, - SubghzReceverEventMore, - SubghzReceverEventSendStart, - SubghzReceverEventSendStop, - SubghzReceverEventSendHistoryFull, } SubghzReceverEvent; typedef struct SubghzReceiver SubghzReceiver; @@ -33,17 +23,19 @@ void subghz_receiver_free(SubghzReceiver* subghz_receiver); View* subghz_receiver_get_view(SubghzReceiver* subghz_receiver); -void subghz_receiver_set_protocol( +void subghz_receiver_add_data_statusbar( SubghzReceiver* subghz_receiver, - SubGhzProtocolCommon* protocol_result, - SubGhzProtocol* protocol); + const char* frequency_str, + const char* preset_str, + const char* history_stat_str); -SubGhzProtocolCommon* subghz_receiver_get_protocol(SubghzReceiver* subghz_receiver); +void subghz_receiver_add_item_to_menu( + SubghzReceiver* subghz_receiver, + const char* name, + uint8_t type); -void subghz_receiver_set_worker(SubghzReceiver* subghz_receiver, SubGhzWorker* worker); +uint16_t subghz_receiver_get_idx_menu(SubghzReceiver* subghz_receiver); -uint32_t subghz_receiver_get_frequency(SubghzReceiver* subghz_receiver); +void subghz_receiver_set_idx_menu(SubghzReceiver* subghz_receiver, uint16_t idx); -FuriHalSubGhzPreset subghz_receiver_get_preset(SubghzReceiver* subghz_receiver); - -void subghz_receiver_frequency_preset_to_str(SubghzReceiver* subghz_receiver, string_t output); +void subghz_receiver_exit(void* context); \ No newline at end of file diff --git a/applications/subghz/views/subghz_transmitter.c b/applications/subghz/views/subghz_transmitter.c index 1dd4e7d9..6e29f5dd 100644 --- a/applications/subghz/views/subghz_transmitter.c +++ b/applications/subghz/views/subghz_transmitter.c @@ -1,13 +1,8 @@ #include "subghz_transmitter.h" #include "../subghz_i.h" -#include -#include -#include #include #include -#include -#include struct SubghzTransmitter { View* view; @@ -16,11 +11,10 @@ struct SubghzTransmitter { }; typedef struct { - string_t text; - uint16_t scene; - uint32_t real_frequency; - FuriHalSubGhzPreset preset; - SubGhzProtocolCommon* protocol; + string_t frequency_str; + string_t preset_str; + string_t key_str; + uint8_t show_button; } SubghzTransmitterModel; void subghz_transmitter_set_callback( @@ -33,24 +27,19 @@ void subghz_transmitter_set_callback( subghz_transmitter->context = context; } -void subghz_transmitter_set_protocol( +void subghz_transmitter_add_data_to_show( SubghzTransmitter* subghz_transmitter, - SubGhzProtocolCommon* protocol) { + const char* key_str, + const char* frequency_str, + const char* preset_str, + uint8_t show_button) { + furi_assert(subghz_transmitter); with_view_model( subghz_transmitter->view, (SubghzTransmitterModel * model) { - model->protocol = protocol; - return true; - }); -} - -void subghz_transmitter_set_frequency_preset( - SubghzTransmitter* subghz_transmitter, - uint32_t frequency, - FuriHalSubGhzPreset preset) { - with_view_model( - subghz_transmitter->view, (SubghzTransmitterModel * model) { - model->real_frequency = frequency; - model->preset = preset; + string_set(model->key_str, key_str); + string_set(model->frequency_str, frequency_str); + string_set(model->preset_str, preset_str); + model->show_button = show_button; return true; }); } @@ -87,26 +76,13 @@ static void subghz_transmitter_button_right(Canvas* canvas, const char* str) { } void subghz_transmitter_draw(Canvas* canvas, SubghzTransmitterModel* model) { - char buffer[64]; canvas_clear(canvas); canvas_set_color(canvas, ColorBlack); canvas_set_font(canvas, FontSecondary); - elements_multiline_text(canvas, 0, 8, string_get_cstr(model->text)); - snprintf( - buffer, - sizeof(buffer), - "%03ld.%03ld", - model->real_frequency / 1000000 % 1000, - model->real_frequency / 1000 % 1000); - canvas_draw_str(canvas, 90, 8, buffer); - - if(model->protocol && model->protocol->get_upload_protocol) { - if((!strcmp(model->protocol->name, "KeeLoq")) && - (!strcmp(subghz_protocol_keeloq_get_manufacture_name(model->protocol), "Unknown"))) { - return; - } - subghz_transmitter_button_right(canvas, "Send"); - } + elements_multiline_text(canvas, 0, 8, string_get_cstr(model->key_str)); + canvas_draw_str(canvas, 78, 8, string_get_cstr(model->frequency_str)); + canvas_draw_str(canvas, 113, 8, string_get_cstr(model->preset_str)); + if(model->show_button) subghz_transmitter_button_right(canvas, "Send"); } bool subghz_transmitter_input(InputEvent* event, void* context) { @@ -114,26 +90,25 @@ bool subghz_transmitter_input(InputEvent* event, void* context) { SubghzTransmitter* subghz_transmitter = context; bool can_be_sent = false; - if(event->key == InputKeyBack) { + if(event->key == InputKeyBack && event->type == InputTypeShort) { + with_view_model( + subghz_transmitter->view, (SubghzTransmitterModel * model) { + string_clean(model->frequency_str); + string_clean(model->preset_str); + string_clean(model->key_str); + model->show_button = 0; + return false; + }); return false; } with_view_model( subghz_transmitter->view, (SubghzTransmitterModel * model) { - if(model->protocol && model->protocol->get_upload_protocol) { - if((!strcmp(model->protocol->name, "KeeLoq")) && - (!strcmp( - subghz_protocol_keeloq_get_manufacture_name(model->protocol), "Unknown"))) { - return false; - } + if(model->show_button) { can_be_sent = true; } - //can_be_sent = (model->protocol && model->protocol->get_upload_protocol); - string_clean(model->text); - model->protocol->to_string(model->protocol, model->text); return true; }); - //if(event->type != InputTypeShort) return false; if(can_be_sent && event->key == InputKeyOk && event->type == InputTypePress) { subghz_transmitter->callback(SubghzTransmitterEventSendStart, subghz_transmitter->context); @@ -146,37 +121,14 @@ bool subghz_transmitter_input(InputEvent* event, void* context) { return true; } -void subghz_transmitter_text_callback(string_t text, void* context) { - furi_assert(context); - SubghzTransmitter* subghz_transmitter = context; - - with_view_model( - subghz_transmitter->view, (SubghzTransmitterModel * model) { - string_set(model->text, text); - model->scene = 0; - return true; - }); -} - void subghz_transmitter_enter(void* context) { furi_assert(context); - SubghzTransmitter* subghz_transmitter = context; - with_view_model( - subghz_transmitter->view, (SubghzTransmitterModel * model) { - string_clean(model->text); - model->protocol->to_string(model->protocol, model->text); - return true; - }); + // SubghzTransmitter* subghz_transmitter = context; } void subghz_transmitter_exit(void* context) { furi_assert(context); - SubghzTransmitter* subghz_transmitter = context; - with_view_model( - subghz_transmitter->view, (SubghzTransmitterModel * model) { - string_clean(model->text); - return true; - }); + // SubghzTransmitter* subghz_transmitter = context; } SubghzTransmitter* subghz_transmitter_alloc() { @@ -194,7 +146,9 @@ SubghzTransmitter* subghz_transmitter_alloc() { with_view_model( subghz_transmitter->view, (SubghzTransmitterModel * model) { - string_init(model->text); + string_init(model->frequency_str); + string_init(model->preset_str); + string_init(model->key_str); return true; }); return subghz_transmitter; @@ -205,7 +159,9 @@ void subghz_transmitter_free(SubghzTransmitter* subghz_transmitter) { with_view_model( subghz_transmitter->view, (SubghzTransmitterModel * model) { - string_clear(model->text); + string_clear(model->frequency_str); + string_clear(model->preset_str); + string_clear(model->key_str); return true; }); view_free(subghz_transmitter->view); diff --git a/applications/subghz/views/subghz_transmitter.h b/applications/subghz/views/subghz_transmitter.h index c4dd5982..8ddeaaf8 100644 --- a/applications/subghz/views/subghz_transmitter.h +++ b/applications/subghz/views/subghz_transmitter.h @@ -1,7 +1,6 @@ #pragma once #include -#include typedef enum { SubghzTransmitterEventSendStart, @@ -25,10 +24,9 @@ void subghz_transmitter_free(SubghzTransmitter* subghz_transmitter); View* subghz_transmitter_get_view(SubghzTransmitter* subghz_transmitter); -void subghz_transmitter_set_protocol( +void subghz_transmitter_add_data_to_show( SubghzTransmitter* subghz_transmitter, - SubGhzProtocolCommon* protocol); -void subghz_transmitter_set_frequency_preset( - SubghzTransmitter* subghz_transmitter, - uint32_t frequency, - FuriHalSubGhzPreset preset); + const char* key_str, + const char* frequency_str, + const char* preset_str, + uint8_t show_button); diff --git a/lib/subghz/protocols/subghz_protocol.c b/lib/subghz/protocols/subghz_protocol.c index c2e3efec..616139a2 100644 --- a/lib/subghz/protocols/subghz_protocol.c +++ b/lib/subghz/protocols/subghz_protocol.c @@ -10,6 +10,7 @@ #include "subghz_protocol_faac_slh.h" #include "subghz_protocol_nero_sketch.h" #include "subghz_protocol_star_line.h" +#include "subghz_protocol_nero_radio.h" #include "../subghz_keystore.h" @@ -27,6 +28,7 @@ typedef enum { SubGhzProtocolTypeFaacSLH, SubGhzProtocolTypeNeroSketch, SubGhzProtocolTypeStarLine, + SubGhzProtocolTypeNeroRadio, SubGhzProtocolTypeMax, } SubGhzProtocolType; @@ -88,6 +90,8 @@ SubGhzProtocol* subghz_protocol_alloc() { (SubGhzProtocolCommon*)subghz_protocol_nero_sketch_alloc(); instance->protocols[SubGhzProtocolTypeStarLine] = (SubGhzProtocolCommon*)subghz_protocol_star_line_alloc(instance->keystore); + instance->protocols[SubGhzProtocolTypeNeroRadio] = + (SubGhzProtocolCommon*)subghz_protocol_nero_radio_alloc(); return instance; } @@ -113,6 +117,8 @@ void subghz_protocol_free(SubGhzProtocol* instance) { (SubGhzProtocolNeroSketch*)instance->protocols[SubGhzProtocolTypeNeroSketch]); subghz_protocol_star_line_free( (SubGhzProtocolStarLine*)instance->protocols[SubGhzProtocolTypeStarLine]); + subghz_protocol_nero_radio_free( + (SubGhzProtocolNeroRadio*)instance->protocols[SubGhzProtocolTypeNeroRadio]); subghz_keystore_free(instance->keystore); @@ -163,7 +169,6 @@ void subghz_protocol_enable_dump( } void subghz_protocol_load_nice_flor_s_file(SubGhzProtocol* instance, const char* file_name) { - // subghz_protocol_nice_flor_s_name_file(instance->nice_flor_s, file_name); subghz_protocol_nice_flor_s_name_file( (SubGhzProtocolNiceFlorS*)instance->protocols[SubGhzProtocolTypeNiceFlorS], file_name); } @@ -191,6 +196,8 @@ void subghz_protocol_reset(SubGhzProtocol* instance) { (SubGhzProtocolNeroSketch*)instance->protocols[SubGhzProtocolTypeNeroSketch]); subghz_protocol_star_line_reset( (SubGhzProtocolStarLine*)instance->protocols[SubGhzProtocolTypeStarLine]); + subghz_protocol_nero_radio_reset( + (SubGhzProtocolNeroRadio*)instance->protocols[SubGhzProtocolTypeNeroRadio]); } void subghz_protocol_parse(SubGhzProtocol* instance, bool level, uint32_t duration) { @@ -220,4 +227,8 @@ void subghz_protocol_parse(SubGhzProtocol* instance, bool level, uint32_t durati duration); subghz_protocol_star_line_parse( (SubGhzProtocolStarLine*)instance->protocols[SubGhzProtocolTypeStarLine], level, duration); + subghz_protocol_nero_radio_parse( + (SubGhzProtocolNeroRadio*)instance->protocols[SubGhzProtocolTypeNeroRadio], + level, + duration); } diff --git a/lib/subghz/protocols/subghz_protocol_gate_tx.h b/lib/subghz/protocols/subghz_protocol_gate_tx.h index 79f3b9db..5fc1001e 100644 --- a/lib/subghz/protocols/subghz_protocol_gate_tx.h +++ b/lib/subghz/protocols/subghz_protocol_gate_tx.h @@ -18,7 +18,7 @@ void subghz_protocol_gate_tx_free(SubGhzProtocolGateTX* instance); /** Get upload protocol * - * @param instance - SubGhzProtocolCame instance + * @param instance - SubGhzProtocolGateTX instance * @param encoder - SubGhzProtocolCommonEncoder encoder * @return bool */ diff --git a/lib/subghz/protocols/subghz_protocol_keeloq.c b/lib/subghz/protocols/subghz_protocol_keeloq.c index 875e6002..ccb2e1ae 100644 --- a/lib/subghz/protocols/subghz_protocol_keeloq.c +++ b/lib/subghz/protocols/subghz_protocol_keeloq.c @@ -398,9 +398,9 @@ void subghz_protocol_keeloq_to_str(SubGhzProtocolKeeloq* instance, string_t outp string_cat_printf( output, "%s %dbit\r\n" - "Key:0x%lX%lX\r\n" - "Fix:0x%08lX Cnt:%04X\r\n" - "Hop:0x%08lX Btn:%02lX\r\n" + "Key:%08lX%08lX\r\n" + "Fix:0x%08lX Cnt:%04X\r\n" + "Hop:0x%08lX Btn:%02lX\r\n" "MF:%s\r\n" "Sn:0x%07lX \r\n", instance->common.name, diff --git a/lib/subghz/protocols/subghz_protocol_keeloq.h b/lib/subghz/protocols/subghz_protocol_keeloq.h index 1cbacd8c..313b7cb3 100644 --- a/lib/subghz/protocols/subghz_protocol_keeloq.h +++ b/lib/subghz/protocols/subghz_protocol_keeloq.h @@ -49,7 +49,7 @@ uint64_t subghz_protocol_keeloq_gen_key(void* context); /** Get upload protocol * - * @param instance - SubGhzProtocolCame instance + * @param instance - SubGhzProtocolKeeloq instance * @param encoder - SubGhzProtocolCommonEncoder encoder * @return bool */ diff --git a/lib/subghz/protocols/subghz_protocol_nero_radio.c b/lib/subghz/protocols/subghz_protocol_nero_radio.c new file mode 100644 index 00000000..2a03d722 --- /dev/null +++ b/lib/subghz/protocols/subghz_protocol_nero_radio.c @@ -0,0 +1,280 @@ +#include "subghz_protocol_nero_radio.h" + +struct SubGhzProtocolNeroRadio { + SubGhzProtocolCommon common; +}; + +SubGhzProtocolNeroRadio* subghz_protocol_nero_radio_alloc(void) { + SubGhzProtocolNeroRadio* instance = furi_alloc(sizeof(SubGhzProtocolNeroRadio)); + + instance->common.name = "Nero Radio"; + instance->common.code_min_count_bit_for_found = 55; + instance->common.te_short = 200; + instance->common.te_long = 400; + instance->common.te_delta = 80; + instance->common.type_protocol = TYPE_PROTOCOL_STATIC; + instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_nero_radio_to_str; + instance->common.to_save_string = + (SubGhzProtocolCommonGetStrSave)subghz_protocol_nero_radio_to_save_str; + instance->common.to_load_protocol_from_file = + (SubGhzProtocolCommonLoadFromFile)subghz_protocol_nero_radio_to_load_protocol_from_file; + instance->common.to_load_protocol = + (SubGhzProtocolCommonLoadFromRAW)subghz_decoder_nero_radio_to_load_protocol; + instance->common.get_upload_protocol = + (SubGhzProtocolCommonEncoderGetUpLoad)subghz_protocol_nero_radio_send_key; + + return instance; +} + +void subghz_protocol_nero_radio_free(SubGhzProtocolNeroRadio* instance) { + furi_assert(instance); + free(instance); +} + +bool subghz_protocol_nero_radio_send_key( + SubGhzProtocolNeroRadio* instance, + SubGhzProtocolCommonEncoder* encoder) { + furi_assert(instance); + furi_assert(encoder); + size_t index = 0; + encoder->size_upload = 2 + 47 * 2 + 2 + (instance->common.code_last_count_bit * 2); + if(encoder->size_upload > SUBGHZ_ENCODER_UPLOAD_MAX_SIZE) return false; + + //Send header + encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->common.te_short); + encoder->upload[index++] = + level_duration_make(false, (uint32_t)instance->common.te_short * 37); + for(uint8_t i = 0; i < 47; i++) { + encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->common.te_short); + encoder->upload[index++] = level_duration_make(false, (uint32_t)instance->common.te_short); + } + + //Send start bit + encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->common.te_short * 4); + encoder->upload[index++] = level_duration_make(false, (uint32_t)instance->common.te_short); + + //Send key data + for(uint8_t i = instance->common.code_last_count_bit; i > 0; i--) { + if(bit_read(instance->common.code_last_found, i - 1)) { + //send bit 1 + encoder->upload[index++] = + level_duration_make(true, (uint32_t)instance->common.te_long); + encoder->upload[index++] = + level_duration_make(false, (uint32_t)instance->common.te_short); + } else { + //send bit 0 + encoder->upload[index++] = + level_duration_make(true, (uint32_t)instance->common.te_short); + encoder->upload[index++] = + level_duration_make(false, (uint32_t)instance->common.te_long); + } + } + + return true; +} + +void subghz_protocol_nero_radio_reset(SubGhzProtocolNeroRadio* instance) { + instance->common.parser_step = 0; +} + +/** Analysis of received data + * + * @param instance SubGhzProtocolNeroRadio instance + */ +// void subghz_protocol_nero_radio_check_remote_controller(SubGhzProtocolNeroRadio* instance) { +// //пока не понятно с серийником, но код статический +// // uint64_t code_found_reverse = subghz_protocol_common_reverse_key(instance->common.code_found, instance->common.code_count_bit); +// // uint32_t code_fix = code_found_reverse & 0xFFFFFFFF; +// // //uint32_t code_hop = (code_found_reverse >> 24) & 0xFFFFF; + +// // instance->common.serial = code_fix & 0xFFFFFFF; +// // instance->common.btn = (code_fix >> 28) & 0x0F; + +// //if (instance->common.callback) instance->common.callback((SubGhzProtocolCommon*)instance, instance->common.context); + +// } + +void subghz_protocol_nero_radio_parse( + SubGhzProtocolNeroRadio* instance, + bool level, + uint32_t duration) { + switch(instance->common.parser_step) { + case 0: + if((level) && + (DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta)) { + instance->common.parser_step = 1; + instance->common.te_last = duration; + instance->common.header_count = 0; + } else { + instance->common.parser_step = 0; + } + break; + case 1: + if(level) { + if((DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta) || + (DURATION_DIFF(duration, instance->common.te_short * 4) < + instance->common.te_delta)) { + instance->common.te_last = duration; + } else { + instance->common.parser_step = 0; + } + } else if(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta) { + if(DURATION_DIFF(instance->common.te_last, instance->common.te_short) < + instance->common.te_delta) { + // Found header + instance->common.header_count++; + break; + } else if( + DURATION_DIFF(instance->common.te_last, instance->common.te_short * 4) < + instance->common.te_delta) { + // Found start bit + if(instance->common.header_count > 40) { + instance->common.parser_step = 2; + instance->common.code_found = 0; + instance->common.code_count_bit = 0; + } else { + instance->common.parser_step = 0; + } + } else { + instance->common.parser_step = 0; + } + } else { + instance->common.parser_step = 0; + } + break; + case 2: + if(level) { + instance->common.te_last = duration; + instance->common.parser_step = 3; + } else { + instance->common.parser_step = 0; + } + break; + case 3: + if(!level) { + if(duration >= (instance->common.te_short * 10 + instance->common.te_delta * 2)) { + //Found stop bit + instance->common.parser_step = 0; + if(instance->common.code_count_bit >= + instance->common.code_min_count_bit_for_found) { + instance->common.code_last_found = instance->common.code_found; + instance->common.code_last_count_bit = instance->common.code_count_bit; + if(instance->common.callback) + instance->common.callback( + (SubGhzProtocolCommon*)instance, instance->common.context); + } + instance->common.code_found = 0; + instance->common.code_count_bit = 0; + instance->common.parser_step = 0; + break; + } else if( + (DURATION_DIFF(instance->common.te_last, instance->common.te_short) < + instance->common.te_delta) && + (DURATION_DIFF(duration, instance->common.te_long) < instance->common.te_delta)) { + subghz_protocol_common_add_bit(&instance->common, 0); + instance->common.parser_step = 2; + } else if( + (DURATION_DIFF(instance->common.te_last, instance->common.te_long) < + instance->common.te_delta) && + (DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta)) { + subghz_protocol_common_add_bit(&instance->common, 1); + instance->common.parser_step = 2; + } else { + instance->common.parser_step = 0; + } + } else { + instance->common.parser_step = 0; + } + break; + } +} + +void subghz_protocol_nero_radio_to_str(SubGhzProtocolNeroRadio* instance, string_t output) { + uint32_t code_found_hi = instance->common.code_last_found >> 32; + uint32_t code_found_lo = instance->common.code_last_found & 0x00000000ffffffff; + + uint64_t code_found_reverse = subghz_protocol_common_reverse_key( + instance->common.code_last_found, instance->common.code_last_count_bit); + + uint32_t code_found_reverse_hi = code_found_reverse >> 32; + uint32_t code_found_reverse_lo = code_found_reverse & 0x00000000ffffffff; + + string_cat_printf( + output, + "%s %dbit\r\n" + "Key:0x%lX%08lX\r\n" + "Yek:0x%lX%08lX\r\n", + instance->common.name, + instance->common.code_last_count_bit, + code_found_hi, + code_found_lo, + code_found_reverse_hi, + code_found_reverse_lo); +} + +void subghz_protocol_nero_radio_to_save_str(SubGhzProtocolNeroRadio* instance, string_t output) { + uint32_t code_found_hi = instance->common.code_last_found >> 32; + uint32_t code_found_lo = instance->common.code_last_found & 0x00000000ffffffff; + + string_printf( + output, + "Protocol: %s\n" + "Bit: %d\n" + "Key: %08lX%08lX\n", + instance->common.name, + instance->common.code_last_count_bit, + code_found_hi, + code_found_lo); +} + +bool subghz_protocol_nero_radio_to_load_protocol_from_file( + FileWorker* file_worker, + SubGhzProtocolNeroRadio* instance) { + bool loaded = false; + string_t temp_str; + string_init(temp_str); + int res = 0; + int data = 0; + + do { + // Read and parse bit data from 2nd line + if(!file_worker_read_until(file_worker, temp_str, '\n')) { + break; + } + res = sscanf(string_get_cstr(temp_str), "Bit: %d\n", &data); + if(res != 1) { + break; + } + instance->common.code_last_count_bit = (uint8_t)data; + + // Read and parse key data from 3nd line + if(!file_worker_read_until(file_worker, temp_str, '\n')) { + break; + } + // strlen("Key: ") = 5 + string_right(temp_str, 5); + + uint8_t buf_key[8] = {0}; + if(!subghz_protocol_common_read_hex(temp_str, buf_key, 8)) { + break; + } + + for(uint8_t i = 0; i < 8; i++) { + instance->common.code_last_found = instance->common.code_last_found << 8 | buf_key[i]; + } + + loaded = true; + } while(0); + + string_clear(temp_str); + + return loaded; +} + +void subghz_decoder_nero_radio_to_load_protocol(SubGhzProtocolNeroRadio* instance, void* context) { + furi_assert(context); + furi_assert(instance); + SubGhzProtocolCommonLoad* data = context; + instance->common.code_last_found = data->code_found; + instance->common.code_last_count_bit = data->code_count_bit; +} \ No newline at end of file diff --git a/lib/subghz/protocols/subghz_protocol_nero_radio.h b/lib/subghz/protocols/subghz_protocol_nero_radio.h new file mode 100644 index 00000000..11f13201 --- /dev/null +++ b/lib/subghz/protocols/subghz_protocol_nero_radio.h @@ -0,0 +1,72 @@ +#pragma once + +#include "subghz_protocol_common.h" + +typedef struct SubGhzProtocolNeroRadio SubGhzProtocolNeroRadio; + +/** Allocate SubGhzProtocolNeroRadio + * + * @return SubGhzProtocolNeroRadio* + */ +SubGhzProtocolNeroRadio* subghz_protocol_nero_radio_alloc(); + +/** Free SubGhzProtocolNeroRadio + * + * @param instance + */ +void subghz_protocol_nero_radio_free(SubGhzProtocolNeroRadio* instance); + +/** Get upload protocol + * + * @param instance - SubGhzProtocolNeroRadio instance + * @param encoder - SubGhzProtocolCommonEncoder encoder + * @return bool + */ +bool subghz_protocol_nero_radio_send_key(SubGhzProtocolNeroRadio* instance, SubGhzProtocolCommonEncoder* encoder); + +/** Reset internal state + * @param instance - SubGhzProtocolNeroRadio instance + */ +void subghz_protocol_nero_radio_reset(SubGhzProtocolNeroRadio* instance); + +/** Analysis of received data + * + * @param instance SubGhzProtocolNeroRadio instance + */ +void subghz_protocol_nero_radio_check_remote_controller(SubGhzProtocolNeroRadio* instance); + +/** Parse accepted duration + * + * @param instance - SubGhzProtocolNeroRadio instance + * @param data - LevelDuration level_duration + */ +void subghz_protocol_nero_radio_parse(SubGhzProtocolNeroRadio* instance, bool level, uint32_t duration); + +/** Outputting information from the parser + * + * @param instance - SubGhzProtocolNeroRadio* instance + * @param output - output string + */ +void subghz_protocol_nero_radio_to_str(SubGhzProtocolNeroRadio* instance, string_t output); + +/** Get a string to save the protocol + * + * @param instance - SubGhzProtocolNeroRadio instance + * @param output - the resulting string + */ +void subghz_protocol_nero_radio_to_save_str(SubGhzProtocolNeroRadio* instance, string_t output); + +/** Loading protocol from file + * + * @param file_worker - FileWorker file_worker + * @param instance - SubGhzProtocolNeroRadio instance + * @return bool + */ +bool subghz_protocol_nero_radio_to_load_protocol_from_file(FileWorker* file_worker, SubGhzProtocolNeroRadio* instance); + +/** Loading protocol from bin data + * + * @param instance - SubGhzProtocolNeroRadio instance + * @param context - SubGhzProtocolCommonLoad context + */ +void subghz_decoder_nero_radio_to_load_protocol(SubGhzProtocolNeroRadio* instance, void* context); \ No newline at end of file diff --git a/lib/subghz/protocols/subghz_protocol_nero_sketch.h b/lib/subghz/protocols/subghz_protocol_nero_sketch.h index e8a19a50..cdce88fd 100644 --- a/lib/subghz/protocols/subghz_protocol_nero_sketch.h +++ b/lib/subghz/protocols/subghz_protocol_nero_sketch.h @@ -18,7 +18,7 @@ void subghz_protocol_nero_sketch_free(SubGhzProtocolNeroSketch* instance); /** Get upload protocol * - * @param instance - SubGhzProtocolCame instance + * @param instance - SubGhzProtocolNeroSketch instance * @param encoder - SubGhzProtocolCommonEncoder encoder * @return bool */ diff --git a/lib/subghz/protocols/subghz_protocol_nice_flo.h b/lib/subghz/protocols/subghz_protocol_nice_flo.h index 0f88636d..5c665cc2 100644 --- a/lib/subghz/protocols/subghz_protocol_nice_flo.h +++ b/lib/subghz/protocols/subghz_protocol_nice_flo.h @@ -18,7 +18,7 @@ void subghz_protocol_nice_flo_free(SubGhzProtocolNiceFlo* instance); /** Get upload protocol * - * @param instance - SubGhzProtocolCame instance + * @param instance - SubGhzProtocolNiceFlo instance * @param encoder - SubGhzProtocolCommonEncoder encoder * @return bool */ diff --git a/lib/subghz/protocols/subghz_protocol_princeton.c b/lib/subghz/protocols/subghz_protocol_princeton.c index 201f07d0..0cd60387 100644 --- a/lib/subghz/protocols/subghz_protocol_princeton.c +++ b/lib/subghz/protocols/subghz_protocol_princeton.c @@ -172,7 +172,7 @@ void subghz_decoder_princeton_parse( if(!level) { if(duration >= (instance->common.te_short * 10 + instance->common.te_delta)) { instance->common.parser_step = 1; - if(instance->common.code_count_bit >= + if(instance->common.code_count_bit == instance->common.code_min_count_bit_for_found) { if(instance->common.code_last_found == instance->common.code_found) { //instance->te = (instance->te+instance->common.te_last)/2; //Option 1 TE averaging diff --git a/lib/subghz/protocols/subghz_protocol_star_line.c b/lib/subghz/protocols/subghz_protocol_star_line.c index f8207348..001285f3 100644 --- a/lib/subghz/protocols/subghz_protocol_star_line.c +++ b/lib/subghz/protocols/subghz_protocol_star_line.c @@ -282,9 +282,9 @@ void subghz_protocol_star_line_to_str(SubGhzProtocolStarLine* instance, string_t string_cat_printf( output, "%s %dbit\r\n" - "Key:0x%lX%lX\r\n" - "Fix:0x%08lX Cnt:%04X\r\n" - "Hop:0x%08lX Btn:%02lX\r\n" + "Key:%08lX%08lX\r\n" + "Fix:0x%08lX Cnt:%04X\r\n" + "Hop:0x%08lX Btn:%02lX\r\n" "MF:%s\r\n" "Sn:0x%07lX \r\n", instance->common.name, From 9c39290f12cc4c763300da4251e4cf355982e6a9 Mon Sep 17 00:00:00 2001 From: DF Date: Fri, 10 Sep 2021 08:33:21 +0800 Subject: [PATCH 05/13] fix: correct the docker-compose command. (#691) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Anna Prosvetova Co-authored-by: あく --- ReadMe.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ReadMe.md b/ReadMe.md index d5d54baf..9fd85687 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -67,13 +67,13 @@ One liner: `./flash_core1_main.sh` ``` 3. Prepare the container: ```sh - docker compose up -d + docker-compose up -d ``` ## Compile bootloader ```sh -docker compose exec dev make -j$(nproc) -C bootloader TARGET=f6 +docker-compose exec dev make -j$(nproc) -C bootloader TARGET=f6 ``` Bootloader compilation results: @@ -85,7 +85,7 @@ Bootloader compilation results: ## Compile firmware ```sh -docker compose exec dev make -j$(nproc) -C firmware TARGET=f6 +docker-compose exec dev make -j$(nproc) -C firmware TARGET=f6 ``` Firmware compilation results: @@ -102,14 +102,14 @@ That's exactly how we generate our `full` builds. 1. Concatenate HEX files: ```sh - docker compose exec dev srec_cat \ + docker-compose exec dev srec_cat \ bootloader/.obj/f6/bootloader.hex -Intel \ firmware/.obj/f6/firmware.hex -Intel \ -o firmware/.obj/f6/full.hex -Intel ``` 2. Convert HEX to DFU: ```sh - docker compose exec dev hex2dfu \ + docker-compose exec dev hex2dfu \ -i firmware/.obj/f6/full.hex \ -o firmware/.obj/f6/full.dfu \ -l "Flipper Zero F6" From b6579d66d83ed207c92df2aa6a03e41d9092730c Mon Sep 17 00:00:00 2001 From: its your bedtime <23366927+itsyourbedtime@users.noreply.github.com> Date: Fri, 10 Sep 2021 03:57:43 +0300 Subject: [PATCH 06/13] Archive refactoring WIP (#688) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * view_dispatcher queue * refactoring, all works * scenes Co-authored-by: あく --- applications/archive/archive.c | 844 +----------------- applications/archive/archive_i.h | 74 +- applications/archive/archive_views.c | 168 ---- .../archive/helpers/archive_favorites.c | 171 ++++ .../archive/helpers/archive_favorites.h | 11 + applications/archive/helpers/archive_files.c | 143 +++ .../archive_files.h} | 43 +- applications/archive/scenes/archive_scene.c | 30 + applications/archive/scenes/archive_scene.h | 29 + .../archive/scenes/archive_scene_browser.c | 42 + .../archive/scenes/archive_scene_config.h | 2 + .../archive/scenes/archive_scene_rename.c | 80 ++ .../archive/views/archive_main_view.c | 642 +++++++++++++ .../archive/views/archive_main_view.h | 117 +++ 14 files changed, 1324 insertions(+), 1072 deletions(-) delete mode 100644 applications/archive/archive_views.c create mode 100644 applications/archive/helpers/archive_favorites.c create mode 100644 applications/archive/helpers/archive_favorites.h create mode 100644 applications/archive/helpers/archive_files.c rename applications/archive/{archive_views.h => helpers/archive_files.h} (58%) create mode 100644 applications/archive/scenes/archive_scene.c create mode 100644 applications/archive/scenes/archive_scene.h create mode 100644 applications/archive/scenes/archive_scene_browser.c create mode 100644 applications/archive/scenes/archive_scene_config.h create mode 100644 applications/archive/scenes/archive_scene_rename.c create mode 100644 applications/archive/views/archive_main_view.c create mode 100644 applications/archive/views/archive_main_view.h diff --git a/applications/archive/archive.c b/applications/archive/archive.c index c9667e66..68fc7287 100644 --- a/applications/archive/archive.c +++ b/applications/archive/archive.c @@ -1,831 +1,69 @@ #include "archive_i.h" -static bool archive_get_filenames(ArchiveApp* archive); - -static void update_offset(ArchiveApp* archive) { - furi_assert(archive); - - with_view_model( - archive->view_archive_main, (ArchiveViewModel * model) { - size_t array_size = files_array_size(model->files); - uint16_t bounds = array_size > 3 ? 2 : array_size; - - if(array_size > 3 && model->idx >= array_size - 1) { - model->list_offset = model->idx - 3; - } else if(model->list_offset < model->idx - bounds) { - model->list_offset = CLAMP(model->list_offset + 1, array_size - bounds, 0); - } else if(model->list_offset > model->idx - bounds) { - model->list_offset = CLAMP(model->idx - 1, array_size - bounds, 0); - } - return true; - }); -} - -static void archive_update_last_idx(ArchiveApp* archive) { - furi_assert(archive); - - with_view_model( - archive->view_archive_main, (ArchiveViewModel * model) { - archive->browser.last_idx[archive->browser.depth] = - CLAMP(model->idx, files_array_size(model->files) - 1, 0); - model->idx = 0; - return true; - }); -} - -static void archive_switch_dir(ArchiveApp* archive, const char* path) { - furi_assert(archive); - furi_assert(path); - string_set(archive->browser.path, path); - archive_get_filenames(archive); - update_offset(archive); -} - -static void archive_switch_tab(ArchiveApp* archive) { - furi_assert(archive); - - with_view_model( - archive->view_archive_main, (ArchiveViewModel * model) { - model->tab_idx = archive->browser.tab_id; - model->idx = 0; - - return true; - }); - - archive->browser.depth = 0; - archive_switch_dir(archive, tab_default_paths[archive->browser.tab_id]); -} - -static void archive_leave_dir(ArchiveApp* archive) { - furi_assert(archive); - - char* last_char_ptr = strrchr(string_get_cstr(archive->browser.path), '/'); - - if(last_char_ptr) { - size_t pos = last_char_ptr - string_get_cstr(archive->browser.path); - string_left(archive->browser.path, pos); - } - - archive->browser.depth = CLAMP(archive->browser.depth - 1, MAX_DEPTH, 0); - - with_view_model( - archive->view_archive_main, (ArchiveViewModel * model) { - model->idx = archive->browser.last_idx[archive->browser.depth]; - model->list_offset = - model->idx - - (files_array_size(model->files) > 3 ? 3 : files_array_size(model->files)); - return true; - }); - - archive_switch_dir(archive, string_get_cstr(archive->browser.path)); - update_offset(archive); -} - -static void archive_enter_dir(ArchiveApp* archive, string_t name) { - furi_assert(archive); - furi_assert(name); - - archive_update_last_idx(archive); - archive->browser.depth = CLAMP(archive->browser.depth + 1, MAX_DEPTH, 0); - - string_cat(archive->browser.path, "/"); - string_cat(archive->browser.path, archive->browser.name); - - archive_switch_dir(archive, string_get_cstr(archive->browser.path)); -} - -static bool filter_by_extension(ArchiveApp* archive, FileInfo* file_info, const char* name) { - furi_assert(archive); - furi_assert(file_info); - furi_assert(name); - - bool result = false; - const char* filter_ext_ptr = get_tab_ext(archive->browser.tab_id); - - if(strcmp(filter_ext_ptr, "*") == 0) { - result = true; - } else if(strstr(name, filter_ext_ptr) != NULL) { - result = true; - } else if(file_info->flags & FSF_DIRECTORY) { - result = true; - } - - return result; -} - -static void set_file_type(ArchiveFile_t* file, FileInfo* file_info) { - furi_assert(file); - furi_assert(file_info); - - for(size_t i = 0; i < SIZEOF_ARRAY(known_ext); i++) { - if(string_search_str(file->name, known_ext[i], 0) != STRING_FAILURE) { - file->type = i; - return; - } - } - - if(file_info->flags & FSF_DIRECTORY) { - file->type = ArchiveFileTypeFolder; - } else { - file->type = ArchiveFileTypeUnknown; - } -} - -static void archive_file_append(ArchiveApp* archive, const char* path, string_t string) { - furi_assert(archive); - furi_assert(path); - furi_assert(string); - - FileWorker* file_worker = file_worker_alloc(false); - - if(!file_worker_open(file_worker, path, FSAM_WRITE, FSOM_OPEN_APPEND)) { - FURI_LOG_E("Archive", "Append open error"); - } - - if(!file_worker_write(file_worker, string_get_cstr(string), string_size(string))) { - FURI_LOG_E("Archive", "Append write error"); - } - - file_worker_close(file_worker); - file_worker_free(file_worker); -} - -static void archive_view_add_item(ArchiveApp* archive, FileInfo* file_info, const char* name) { - furi_assert(archive); - furi_assert(file_info); - furi_assert(name); - - ArchiveFile_t item; - - if(filter_by_extension(archive, file_info, name)) { - ArchiveFile_t_init(&item); - string_init_set_str(item.name, name); - set_file_type(&item, file_info); - - with_view_model( - archive->view_archive_main, (ArchiveViewModel * model) { - files_array_push_back(model->files, item); - return true; - }); - - ArchiveFile_t_clear(&item); - } -} - -static bool archive_is_favorite(ArchiveApp* archive, ArchiveFile_t* selected) { - furi_assert(selected); - string_t path; - string_t buffer; - string_init(buffer); - bool found = false; - - string_init_printf( - path, "%s/%s", string_get_cstr(archive->browser.path), string_get_cstr(selected->name)); - - bool load_result = - file_worker_open(archive->file_worker, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_ALWAYS); - - if(load_result) { - while(1) { - if(!file_worker_read_until(archive->file_worker, buffer, '\n')) { - break; - } - if(!string_size(buffer)) { - break; - } - if(!string_search(buffer, path)) { - found = true; - break; - } - } - } - - string_clear(buffer); - string_clear(path); - file_worker_close(archive->file_worker); - - return found; -} - -static bool archive_favorites_read(ArchiveApp* archive) { - string_t buffer; - FileInfo file_info; - string_init(buffer); - - bool load_result = - file_worker_open(archive->file_worker, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING); - - if(load_result) { - while(1) { - if(!file_worker_read_until(archive->file_worker, buffer, '\n')) { - break; - } - if(!string_size(buffer)) { - break; - } - - archive_view_add_item(archive, &file_info, string_get_cstr(buffer)); - string_clean(buffer); - } - } - string_clear(buffer); - file_worker_close(archive->file_worker); - - return load_result; -} - -static bool - archive_favorites_rename(ArchiveApp* archive, ArchiveFile_t* selected, const char* dst) { - furi_assert(selected); - string_t path; - string_t buffer; - string_t temp; - - string_init(buffer); - string_init(temp); - - string_init_printf( - path, "%s/%s", string_get_cstr(archive->browser.path), string_get_cstr(selected->name)); - bool load_result = - file_worker_open(archive->file_worker, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING); - - if(load_result) { - while(1) { - if(!file_worker_read_until(archive->file_worker, buffer, '\n')) { - break; - } - if(!string_size(buffer)) { - break; - } - - string_printf( - temp, "%s\r\n", string_search(buffer, path) ? string_get_cstr(buffer) : dst); - archive_file_append(archive, ARCHIVE_FAV_TEMP_PATH, temp); - string_clean(temp); - } - } - - string_clear(temp); - string_clear(buffer); - string_clear(path); - - file_worker_close(archive->file_worker); - file_worker_remove(archive->file_worker, ARCHIVE_FAV_PATH); - file_worker_rename(archive->file_worker, ARCHIVE_FAV_TEMP_PATH, ARCHIVE_FAV_PATH); - - return load_result; -} - -static bool archive_favorites_delete(ArchiveApp* archive, ArchiveFile_t* selected) { - furi_assert(selected); - string_t path; - string_t buffer; - string_init(buffer); - - string_init_printf( - path, "%s/%s", string_get_cstr(archive->browser.path), string_get_cstr(selected->name)); - - bool load_result = - file_worker_open(archive->file_worker, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING); - if(load_result) { - while(1) { - if(!file_worker_read_until(archive->file_worker, buffer, '\n')) { - break; - } - if(!string_size(buffer)) { - break; - } - - if(string_search(buffer, path)) { - string_t temp; - string_init_printf(temp, "%s\r\n", string_get_cstr(buffer)); - archive_file_append(archive, ARCHIVE_FAV_TEMP_PATH, temp); - string_clear(temp); - } - } - } - - string_clear(buffer); - string_clear(path); - - file_worker_close(archive->file_worker); - file_worker_remove(archive->file_worker, ARCHIVE_FAV_PATH); - file_worker_rename(archive->file_worker, ARCHIVE_FAV_TEMP_PATH, ARCHIVE_FAV_PATH); - - return load_result; -} - -static bool archive_read_dir(ArchiveApp* archive) { - FileInfo file_info; - File* directory = storage_file_alloc(archive->api); - char name[MAX_NAME_LEN]; - - if(!storage_dir_open(directory, string_get_cstr(archive->browser.path))) { - storage_dir_close(directory); - storage_file_free(directory); - return false; - } - while(1) { - if(!storage_dir_read(directory, &file_info, name, MAX_NAME_LEN)) { - break; - } - - uint16_t files_cnt; - with_view_model( - archive->view_archive_main, (ArchiveViewModel * model) { - files_cnt = files_array_size(model->files); - - return true; - }); - - if(files_cnt > MAX_FILES) { - break; - } else if(storage_file_get_error(directory) == FSE_OK) { - archive_view_add_item(archive, &file_info, name); - } else { - storage_dir_close(directory); - storage_file_free(directory); - return false; - } - } - storage_dir_close(directory); - storage_file_free(directory); - - return true; -} - -static bool archive_get_filenames(ArchiveApp* archive) { - furi_assert(archive); - with_view_model( - archive->view_archive_main, (ArchiveViewModel * model) { - files_array_clean(model->files); - return true; - }); - - if(archive->browser.tab_id != ArchiveTabFavorites) { - archive_read_dir(archive); - } else { - archive_favorites_read(archive); - } - return true; -} -static void archive_exit_callback(ArchiveApp* archive) { - furi_assert(archive); - - AppEvent event; - event.type = EventTypeExit; - furi_check(osMessageQueuePut(archive->event_queue, &event, 0, osWaitForever) == osOK); -} - -static uint32_t archive_previous_callback(void* context) { - return ArchiveViewMain; -} - -/* file menu */ -static void archive_add_to_favorites(ArchiveApp* archive) { - furi_assert(archive); - string_t buffer_src; - - string_init_printf( - buffer_src, - "%s/%s\r\n", - string_get_cstr(archive->browser.path), - string_get_cstr(archive->browser.name)); - - archive_file_append(archive, ARCHIVE_FAV_PATH, buffer_src); - - string_clear(buffer_src); -} - -static void archive_text_input_callback(void* context) { +bool archive_custom_event_callback(void* context, uint32_t event) { furi_assert(context); - ArchiveApp* archive = (ArchiveApp*)context; - - string_t buffer_src; - string_t buffer_dst; - - string_init_printf( - buffer_src, - "%s/%s", - string_get_cstr(archive->browser.path), - string_get_cstr(archive->browser.name)); - string_init_printf( - buffer_dst, - "%s/%s", - string_get_cstr(archive->browser.path), - archive->browser.text_input_buffer); - - string_set(archive->browser.name, archive->browser.text_input_buffer); - // append extension - - ArchiveFile_t* file; - - with_view_model( - archive->view_archive_main, (ArchiveViewModel * model) { - file = files_array_get( - model->files, CLAMP(model->idx, files_array_size(model->files) - 1, 0)); - file->fav = archive_is_favorite(archive, file); - - return true; - }); - - string_cat(buffer_dst, known_ext[file->type]); - storage_common_rename(archive->api, string_get_cstr(buffer_src), string_get_cstr(buffer_dst)); - - if(file->fav) { - archive_favorites_rename(archive, file, string_get_cstr(buffer_dst)); - } - - view_dispatcher_switch_to_view(archive->view_dispatcher, ArchiveViewMain); - archive_get_filenames(archive); - - with_view_model( - archive->view_archive_main, (ArchiveViewModel * model) { - model->idx = 0; - while(model->idx < files_array_size(model->files)) { - ArchiveFile_t* current = files_array_get(model->files, model->idx); - if(!string_search(current->name, archive->browser.text_input_buffer)) { - break; - } - ++model->idx; - } - return true; - }); - - update_offset(archive); - - string_clear(buffer_src); - string_clear(buffer_dst); + return scene_manager_handle_custom_event(archive->scene_manager, event); } -static void archive_enter_text_input(ArchiveApp* archive) { - furi_assert(archive); - *archive->browser.text_input_buffer = '\0'; - - strlcpy( - archive->browser.text_input_buffer, string_get_cstr(archive->browser.name), MAX_NAME_LEN); - - archive_trim_file_ext(archive->browser.text_input_buffer); - - text_input_set_header_text(archive->text_input, "Rename:"); - - text_input_set_result_callback( - archive->text_input, - archive_text_input_callback, - archive, - archive->browser.text_input_buffer, - MAX_NAME_LEN, - false); - - view_dispatcher_switch_to_view(archive->view_dispatcher, ArchiveViewTextInput); -} - -static void archive_show_file_menu(ArchiveApp* archive) { - furi_assert(archive); - - archive->browser.menu = true; - - with_view_model( - archive->view_archive_main, (ArchiveViewModel * model) { - ArchiveFile_t* selected; - selected = files_array_get(model->files, model->idx); - model->menu = true; - model->menu_idx = 0; - selected->fav = is_known_app(selected->type) ? archive_is_favorite(archive, selected) : - false; - - return true; - }); -} - -static void archive_close_file_menu(ArchiveApp* archive) { - furi_assert(archive); - - archive->browser.menu = false; - - with_view_model( - archive->view_archive_main, (ArchiveViewModel * model) { - model->menu = false; - model->menu_idx = 0; - return true; - }); -} - -static void archive_open_app(ArchiveApp* archive, const char* app_name, const char* args) { - furi_assert(archive); - furi_assert(app_name); - - loader_start(archive->loader, app_name, args); -} - -static void archive_delete_file(ArchiveApp* archive, ArchiveFile_t* file) { - furi_assert(archive); - furi_assert(file); - - string_t path; - string_init(path); - - string_printf( - path, "%s/%s", string_get_cstr(archive->browser.path), string_get_cstr(file->name)); - - if(archive_is_favorite(archive, file)) { // remove from favorites - archive_favorites_delete(archive, file); - } - - file_worker_remove(archive->file_worker, string_get_cstr(path)); - - string_clear(path); - archive_get_filenames(archive); - - with_view_model( - archive->view_archive_main, (ArchiveViewModel * model) { - model->idx = CLAMP(model->idx, files_array_size(model->files) - 1, 0); - return true; - }); - - update_offset(archive); -} - -static void - archive_run_in_app(ArchiveApp* archive, ArchiveFile_t* selected, bool full_path_provided) { - string_t full_path; - - if(!full_path_provided) { - string_init_printf( - full_path, - "%s/%s", - string_get_cstr(archive->browser.path), - string_get_cstr(selected->name)); - } else { - string_init_set(full_path, selected->name); - } - - archive_open_app(archive, flipper_app_name[selected->type], string_get_cstr(full_path)); - string_clear(full_path); -} - -static void archive_file_menu_callback(ArchiveApp* archive) { - furi_assert(archive); - - ArchiveFile_t* selected; - uint8_t idx = 0; - - with_view_model( - archive->view_archive_main, (ArchiveViewModel * model) { - selected = files_array_get(model->files, model->idx); - idx = model->menu_idx; - return true; - }); - - switch(idx) { - case 0: - if(is_known_app(selected->type)) { - archive_run_in_app(archive, selected, false); - } - break; - case 1: - if(is_known_app(selected->type)) { - if(!archive_is_favorite(archive, selected)) { - string_set(archive->browser.name, selected->name); - archive_add_to_favorites(archive); - } else { - // delete from favorites - archive_favorites_delete(archive, selected); - } - archive_close_file_menu(archive); - } - break; - case 2: - // open rename view - if(is_known_app(selected->type)) { - archive_enter_text_input(archive); - } - break; - case 3: - // confirmation? - archive_delete_file(archive, selected); - archive_close_file_menu(archive); - - break; - - default: - archive_close_file_menu(archive); - break; - } - selected = NULL; -} - -static void menu_input_handler(ArchiveApp* archive, InputEvent* event) { - furi_assert(archive); - furi_assert(archive); - - if(event->type == InputTypeShort) { - if(event->key == InputKeyUp || event->key == InputKeyDown) { - with_view_model( - archive->view_archive_main, (ArchiveViewModel * model) { - if(event->key == InputKeyUp) { - model->menu_idx = ((model->menu_idx - 1) + MENU_ITEMS) % MENU_ITEMS; - } else if(event->key == InputKeyDown) { - model->menu_idx = (model->menu_idx + 1) % MENU_ITEMS; - } - return true; - }); - } - - if(event->key == InputKeyOk) { - archive_file_menu_callback(archive); - } else if(event->key == InputKeyBack) { - archive_close_file_menu(archive); - } - } -} - -/* main controls */ - -static bool archive_view_input(InputEvent* event, void* context) { - furi_assert(event); +bool archive_back_event_callback(void* context) { furi_assert(context); - - ArchiveApp* archive = context; - bool in_menu = archive->browser.menu; - - if(in_menu) { - menu_input_handler(archive, event); - return true; - } - - if(event->type == InputTypeShort) { - if(event->key == InputKeyLeft) { - if(archive->browser.tab_id > 0) { - archive->browser.tab_id = CLAMP(archive->browser.tab_id - 1, ArchiveTabTotal, 0); - archive_switch_tab(archive); - return true; - } - } else if(event->key == InputKeyRight) { - if(archive->browser.tab_id < ArchiveTabTotal - 1) { - archive->browser.tab_id = - CLAMP(archive->browser.tab_id + 1, ArchiveTabTotal - 1, 0); - archive_switch_tab(archive); - return true; - } - - } else if(event->key == InputKeyBack) { - if(archive->browser.depth == 0) { - archive_exit_callback(archive); - } else { - archive_leave_dir(archive); - } - - return true; - } - } - if(event->key == InputKeyUp || event->key == InputKeyDown) { - with_view_model( - archive->view_archive_main, (ArchiveViewModel * model) { - uint16_t num_elements = (uint16_t)files_array_size(model->files); - if((event->type == InputTypeShort || event->type == InputTypeRepeat)) { - if(event->key == InputKeyUp) { - model->idx = ((model->idx - 1) + num_elements) % num_elements; - } else if(event->key == InputKeyDown) { - model->idx = (model->idx + 1) % num_elements; - } - } - - return true; - }); - update_offset(archive); - } - - if(event->key == InputKeyOk) { - ArchiveFile_t* selected; - - with_view_model( - archive->view_archive_main, (ArchiveViewModel * model) { - selected = files_array_size(model->files) > 0 ? - files_array_get(model->files, model->idx) : - NULL; - return true; - }); - - if(selected) { - string_set(archive->browser.name, selected->name); - - if(selected->type == ArchiveFileTypeFolder) { - if(event->type == InputTypeShort) { - archive_enter_dir(archive, archive->browser.name); - } else if(event->type == InputTypeLong) { - archive_show_file_menu(archive); - } - } else { - if(event->type == InputTypeShort) { - if(archive->browser.tab_id == ArchiveTabFavorites) { - if(is_known_app(selected->type)) { - archive_run_in_app(archive, selected, true); - } - } else { - archive_show_file_menu(archive); - } - } - } - } - } - - update_offset(archive); - - return true; -} - -void archive_free(ArchiveApp* archive) { - furi_assert(archive); - - file_worker_free(archive->file_worker); - - view_dispatcher_remove_view(archive->view_dispatcher, ArchiveViewMain); - view_dispatcher_remove_view(archive->view_dispatcher, ArchiveViewTextInput); - view_dispatcher_free(archive->view_dispatcher); - - with_view_model( - archive->view_archive_main, (ArchiveViewModel * model) { - files_array_clear(model->files); - return false; - }); - - view_free(archive->view_archive_main); - - string_clear(archive->browser.name); - string_clear(archive->browser.path); - - text_input_free(archive->text_input); - - furi_record_close("storage"); - archive->api = NULL; - furi_record_close("gui"); - archive->gui = NULL; - furi_record_close("loader"); - archive->loader = NULL; - furi_thread_free(archive->app_thread); - furi_check(osMessageQueueDelete(archive->event_queue) == osOK); - - free(archive); + ArchiveApp* archive = (ArchiveApp*)context; + return scene_manager_handle_back_event(archive->scene_manager); } ArchiveApp* archive_alloc() { ArchiveApp* archive = furi_alloc(sizeof(ArchiveApp)); - archive->event_queue = osMessageQueueNew(8, sizeof(AppEvent), NULL); - archive->app_thread = furi_thread_alloc(); archive->gui = furi_record_open("gui"); - archive->loader = furi_record_open("loader"); - archive->api = furi_record_open("storage"); archive->text_input = text_input_alloc(); - archive->view_archive_main = view_alloc(); - archive->file_worker = file_worker_alloc(true); - furi_check(archive->event_queue); - - view_allocate_model( - archive->view_archive_main, ViewModelTypeLocking, sizeof(ArchiveViewModel)); - with_view_model( - archive->view_archive_main, (ArchiveViewModel * model) { - files_array_init(model->files); - return false; - }); - - view_set_context(archive->view_archive_main, archive); - view_set_draw_callback(archive->view_archive_main, archive_view_render); - view_set_input_callback(archive->view_archive_main, archive_view_input); - view_set_previous_callback( - text_input_get_view(archive->text_input), archive_previous_callback); - - // View Dispatcher archive->view_dispatcher = view_dispatcher_alloc(); - view_dispatcher_add_view( - archive->view_dispatcher, ArchiveViewMain, archive->view_archive_main); - view_dispatcher_add_view( - archive->view_dispatcher, ArchiveViewTextInput, text_input_get_view(archive->text_input)); + archive->scene_manager = scene_manager_alloc(&archive_scene_handlers, archive); + + view_dispatcher_enable_queue(archive->view_dispatcher); view_dispatcher_attach_to_gui( archive->view_dispatcher, archive->gui, ViewDispatcherTypeFullscreen); - view_dispatcher_switch_to_view(archive->view_dispatcher, ArchiveTabFavorites); + view_dispatcher_set_event_callback_context(archive->view_dispatcher, archive); + view_dispatcher_set_custom_event_callback( + archive->view_dispatcher, archive_custom_event_callback); + view_dispatcher_set_navigation_event_callback( + archive->view_dispatcher, archive_back_event_callback); + + archive->main_view = main_view_alloc(); + + view_dispatcher_add_view( + archive->view_dispatcher, ArchiveViewBrowser, archive_main_get_view(archive->main_view)); + + view_dispatcher_add_view( + archive->view_dispatcher, ArchiveViewTextInput, text_input_get_view(archive->text_input)); return archive; } +void archive_free(ArchiveApp* archive) { + furi_assert(archive); + + view_dispatcher_remove_view(archive->view_dispatcher, ArchiveViewBrowser); + view_dispatcher_remove_view(archive->view_dispatcher, ArchiveViewTextInput); + view_dispatcher_free(archive->view_dispatcher); + scene_manager_free(archive->scene_manager); + main_view_free(archive->main_view); + + text_input_free(archive->text_input); + + furi_record_close("gui"); + archive->gui = NULL; + + free(archive); +} + int32_t archive_app(void* p) { ArchiveApp* archive = archive_alloc(); - - // default tab - archive_switch_tab(archive); - - AppEvent event; - while(1) { - furi_check(osMessageQueueGet(archive->event_queue, &event, NULL, osWaitForever) == osOK); - if(event.type == EventTypeExit) { - break; - } - } - + scene_manager_next_scene(archive->scene_manager, ArchiveAppSceneBrowser); + view_dispatcher_run(archive->view_dispatcher); archive_free(archive); + return 0; } diff --git a/applications/archive/archive_i.h b/applications/archive/archive_i.h index a7c3a901..474b18e5 100644 --- a/applications/archive/archive_i.h +++ b/applications/archive/archive_i.h @@ -5,44 +5,27 @@ #include #include #include +#include #include #include #include #include #include -#include "archive_views.h" #include "applications.h" #include "file-worker.h" -#define MAX_DEPTH 32 -#define MAX_FILES 100 //temp +#include "views/archive_main_view.h" +#include "scenes/archive_scene.h" + #define MAX_FILE_SIZE 128 -#define ARCHIVE_FAV_PATH "/any/favorites.txt" -#define ARCHIVE_FAV_TEMP_PATH "/any/favorites.tmp" typedef enum { - ArchiveViewMain, + ArchiveViewBrowser, ArchiveViewTextInput, ArchiveViewTotal, } ArchiveViewEnum; -static const char* flipper_app_name[] = { - [ArchiveFileTypeIButton] = "iButton", - [ArchiveFileTypeNFC] = "NFC", - [ArchiveFileTypeSubGhz] = "Sub-GHz", - [ArchiveFileTypeLFRFID] = "125 kHz RFID", - [ArchiveFileTypeIrda] = "Infrared", -}; - -static const char* known_ext[] = { - [ArchiveFileTypeIButton] = ".ibtn", - [ArchiveFileTypeNFC] = ".nfc", - [ArchiveFileTypeSubGhz] = ".sub", - [ArchiveFileTypeLFRFID] = ".rfid", - [ArchiveFileTypeIrda] = ".ir", -}; - static const char* tab_default_paths[] = { [ArchiveTabFavorites] = "/any/favorites", [ArchiveTabIButton] = "/any/ibutton", @@ -53,23 +36,6 @@ static const char* tab_default_paths[] = { [ArchiveTabBrowser] = "/any", }; -static inline const char* get_tab_ext(ArchiveTabEnum tab) { - switch(tab) { - case ArchiveTabIButton: - return known_ext[ArchiveFileTypeIButton]; - case ArchiveTabNFC: - return known_ext[ArchiveFileTypeNFC]; - case ArchiveTabSubGhz: - return known_ext[ArchiveFileTypeSubGhz]; - case ArchiveTabLFRFID: - return known_ext[ArchiveFileTypeLFRFID]; - case ArchiveTabIrda: - return known_ext[ArchiveFileTypeIrda]; - default: - return "*"; - } -} - static inline const char* get_default_path(ArchiveFileTypeEnum type) { switch(type) { case ArchiveFileTypeIButton: @@ -104,35 +70,11 @@ typedef struct { EventType type; } AppEvent; -typedef enum { - FavoritesCheck, - FavoritesRead, - FavoritesDelete, - FavoritesRename, -} FavActionsEnum; - -typedef struct { - ArchiveTabEnum tab_id; - string_t name; - string_t path; - char text_input_buffer[MAX_NAME_LEN]; - - uint8_t depth; - uint16_t last_idx[MAX_DEPTH]; - - bool menu; -} ArchiveBrowser; - struct ArchiveApp { - osMessageQueueId_t event_queue; - FuriThread* app_thread; - Loader* loader; Gui* gui; ViewDispatcher* view_dispatcher; - View* view_archive_main; + SceneManager* scene_manager; + ArchiveMainView* main_view; TextInput* text_input; - - Storage* api; - FileWorker* file_worker; - ArchiveBrowser browser; + char text_store[MAX_NAME_LEN]; }; diff --git a/applications/archive/archive_views.c b/applications/archive/archive_views.c deleted file mode 100644 index 00f4d0f3..00000000 --- a/applications/archive/archive_views.c +++ /dev/null @@ -1,168 +0,0 @@ -#include "archive_views.h" - -static const char* ArchiveTabNames[] = { - [ArchiveTabFavorites] = "Favorites", - [ArchiveTabIButton] = "iButton", - [ArchiveTabNFC] = "NFC", - [ArchiveTabSubGhz] = "Sub-GHz", - [ArchiveTabLFRFID] = "RFID LF", - [ArchiveTabIrda] = "Infrared", - [ArchiveTabBrowser] = "Browser"}; - -static const Icon* ArchiveItemIcons[] = { - [ArchiveFileTypeIButton] = &I_ibutt_10px, - [ArchiveFileTypeNFC] = &I_Nfc_10px, - [ArchiveFileTypeSubGhz] = &I_sub1_10px, - [ArchiveFileTypeLFRFID] = &I_125_10px, - [ArchiveFileTypeIrda] = &I_ir_10px, - [ArchiveFileTypeFolder] = &I_dir_10px, - [ArchiveFileTypeUnknown] = &I_unknown_10px, -}; - -static void render_item_menu(Canvas* canvas, ArchiveViewModel* model) { - canvas_set_color(canvas, ColorWhite); - canvas_draw_box(canvas, 71, 17, 57, 46); - canvas_set_color(canvas, ColorBlack); - elements_slightly_rounded_frame(canvas, 70, 16, 58, 48); - - string_t menu[MENU_ITEMS]; - - string_init_set_str(menu[0], "Run in app"); - string_init_set_str(menu[1], "Pin"); - string_init_set_str(menu[2], "Rename"); - string_init_set_str(menu[3], "Delete"); - - ArchiveFile_t* selected = files_array_get(model->files, model->idx); - - if(!is_known_app(selected->type)) { - string_set_str(menu[0], "---"); - string_set_str(menu[1], "---"); - string_set_str(menu[2], "---"); - } else if(model->tab_idx == 0 || selected->fav) { - string_set_str(menu[1], "Unpin"); - } - - for(size_t i = 0; i < MENU_ITEMS; i++) { - canvas_draw_str(canvas, 82, 27 + i * 11, string_get_cstr(menu[i])); - string_clear(menu[i]); - } - - canvas_draw_icon(canvas, 74, 20 + model->menu_idx * 11, &I_ButtonRight_4x7); -} - -void archive_trim_file_ext(char* name) { - size_t str_len = strlen(name); - char* end = name + str_len; - while(end > name && *end != '.' && *end != '\\' && *end != '/') { - --end; - } - if((end > name && *end == '.') && (*(end - 1) != '\\' && *(end - 1) != '/')) { - *end = '\0'; - } -} - -static void archive_draw_frame(Canvas* canvas, uint16_t idx, bool scrollbar) { - canvas_set_color(canvas, ColorBlack); - canvas_draw_box(canvas, 0, 15 + idx * FRAME_HEIGHT, scrollbar ? 122 : 127, FRAME_HEIGHT); - - canvas_set_color(canvas, ColorWhite); - canvas_draw_dot(canvas, 0, 15 + idx * FRAME_HEIGHT); - canvas_draw_dot(canvas, 1, 15 + idx * FRAME_HEIGHT); - canvas_draw_dot(canvas, 0, (15 + idx * FRAME_HEIGHT) + 1); - - canvas_draw_dot(canvas, 0, (15 + idx * FRAME_HEIGHT) + 11); - canvas_draw_dot(canvas, scrollbar ? 121 : 126, 15 + idx * FRAME_HEIGHT); - canvas_draw_dot(canvas, scrollbar ? 121 : 126, (15 + idx * FRAME_HEIGHT) + 11); -} - -static void draw_list(Canvas* canvas, ArchiveViewModel* model) { - furi_assert(model); - - size_t array_size = files_array_size(model->files); - bool scrollbar = array_size > 4; - - for(size_t i = 0; i < MIN(array_size, MENU_ITEMS); ++i) { - string_t str_buff; - char cstr_buff[MAX_NAME_LEN]; - - size_t idx = CLAMP(i + model->list_offset, array_size, 0); - ArchiveFile_t* file = files_array_get(model->files, CLAMP(idx, array_size - 1, 0)); - - string_init_set(str_buff, file->name); - string_right(str_buff, string_search_rchar(str_buff, '/') + 1); - strlcpy(cstr_buff, string_get_cstr(str_buff), string_size(str_buff) + 1); - - if(is_known_app(file->type)) archive_trim_file_ext(cstr_buff); - - string_clean(str_buff); - string_set_str(str_buff, cstr_buff); - - elements_string_fit_width(canvas, str_buff, scrollbar ? MAX_LEN_PX - 6 : MAX_LEN_PX); - - if(model->idx == idx) { - archive_draw_frame(canvas, i, scrollbar); - } else { - canvas_set_color(canvas, ColorBlack); - } - - canvas_draw_icon(canvas, 2, 16 + i * FRAME_HEIGHT, ArchiveItemIcons[file->type]); - canvas_draw_str(canvas, 15, 24 + i * FRAME_HEIGHT, string_get_cstr(str_buff)); - string_clear(str_buff); - } - - if(scrollbar) { - elements_scrollbar_pos(canvas, 126, 15, 49, model->idx, array_size); - } - - if(model->menu) { - render_item_menu(canvas, model); - } -} - -static void archive_render_status_bar(Canvas* canvas, ArchiveViewModel* model) { - furi_assert(model); - - const char* tab_name = ArchiveTabNames[model->tab_idx]; - - canvas_draw_icon(canvas, 0, 0, &I_Background_128x11); - - canvas_set_color(canvas, ColorWhite); - canvas_draw_box(canvas, 0, 0, 50, 13); - canvas_draw_box(canvas, 107, 0, 20, 13); - - canvas_set_color(canvas, ColorBlack); - canvas_draw_frame(canvas, 1, 0, 50, 12); - canvas_draw_line(canvas, 0, 1, 0, 11); - canvas_draw_line(canvas, 1, 12, 49, 12); - canvas_draw_str_aligned(canvas, 26, 9, AlignCenter, AlignBottom, tab_name); - - canvas_draw_frame(canvas, 108, 0, 20, 12); - canvas_draw_line(canvas, 107, 1, 107, 11); - canvas_draw_line(canvas, 108, 12, 126, 12); - - if(model->tab_idx > 0) { - canvas_draw_icon(canvas, 112, 2, &I_ButtonLeft_4x7); - } - if(model->tab_idx < SIZEOF_ARRAY(ArchiveTabNames) - 1) { - canvas_draw_icon(canvas, 120, 2, &I_ButtonRight_4x7); - } - - canvas_set_color(canvas, ColorWhite); - canvas_draw_dot(canvas, 50, 0); - canvas_draw_dot(canvas, 127, 0); - - canvas_set_color(canvas, ColorBlack); -} - -void archive_view_render(Canvas* canvas, void* model) { - ArchiveViewModel* m = model; - - archive_render_status_bar(canvas, model); - - if(files_array_size(m->files) > 0) { - draw_list(canvas, m); - } else { - canvas_draw_str_aligned( - canvas, GUI_DISPLAY_WIDTH / 2, 40, AlignCenter, AlignCenter, "Empty"); - } -} \ No newline at end of file diff --git a/applications/archive/helpers/archive_favorites.c b/applications/archive/helpers/archive_favorites.c new file mode 100644 index 00000000..6eeefdbb --- /dev/null +++ b/applications/archive/helpers/archive_favorites.c @@ -0,0 +1,171 @@ +#include "archive_favorites.h" +#include "archive_files.h" +#include "../views/archive_main_view.h" + +bool archive_favorites_read(void* context) { + furi_assert(context); + + ArchiveMainView* archive_view = context; + FileWorker* file_worker = file_worker_alloc(true); + + string_t buffer; + FileInfo file_info; + string_init(buffer); + + bool result = file_worker_open(file_worker, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_ALWAYS); + + if(result) { + while(1) { + if(!file_worker_read_until(file_worker, buffer, '\n')) { + break; + } + if(!string_size(buffer)) { + break; + } + + archive_view_add_item(archive_view, &file_info, string_get_cstr(buffer)); + string_clean(buffer); + } + } + string_clear(buffer); + file_worker_close(file_worker); + file_worker_free(file_worker); + return result; +} + +bool archive_favorites_delete(const char* file_path, const char* name) { + furi_assert(file_path); + furi_assert(name); + + FileWorker* file_worker = file_worker_alloc(true); + + string_t path; + string_t buffer; + string_init(buffer); + + string_init_printf(path, "%s/%s", file_path, name); + + bool result = file_worker_open(file_worker, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING); + if(result) { + while(1) { + if(!file_worker_read_until(file_worker, buffer, '\n')) { + break; + } + if(!string_size(buffer)) { + break; + } + + if(string_search(buffer, path)) { + string_t temp; + string_init_printf(temp, "%s\r\n", string_get_cstr(buffer)); + archive_file_append(ARCHIVE_FAV_TEMP_PATH, temp); + string_clear(temp); + } + } + } + + string_clear(buffer); + string_clear(path); + + file_worker_close(file_worker); + file_worker_remove(file_worker, ARCHIVE_FAV_PATH); + file_worker_rename(file_worker, ARCHIVE_FAV_TEMP_PATH, ARCHIVE_FAV_PATH); + + file_worker_free(file_worker); + + return result; +} + +bool archive_is_favorite(const char* file_path, const char* name) { + furi_assert(file_path); + furi_assert(name); + + FileWorker* file_worker = file_worker_alloc(true); + + string_t path; + string_t buffer; + string_init(buffer); + bool found = false; + + string_init_printf(path, "%s/%s", file_path, name); + bool result = file_worker_open(file_worker, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_ALWAYS); + + if(result) { + while(1) { + if(!file_worker_read_until(file_worker, buffer, '\n')) { + break; + } + if(!string_size(buffer)) { + break; + } + if(!string_search(buffer, path)) { + found = true; + break; + } + } + } + + string_clear(buffer); + string_clear(path); + file_worker_close(file_worker); + file_worker_free(file_worker); + + return found; +} + +bool archive_favorites_rename(const char* file_path, const char* src, const char* dst) { + furi_assert(file_path); + furi_assert(src); + furi_assert(dst); + + FileWorker* file_worker = file_worker_alloc(true); + + string_t path; + string_t buffer; + string_t temp; + + string_init(buffer); + string_init(temp); + string_init(path); + + string_printf(path, "%s/%s", file_path, src); + bool result = file_worker_open(file_worker, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING); + + if(result) { + while(1) { + if(!file_worker_read_until(file_worker, buffer, '\n')) { + break; + } + if(!string_size(buffer)) { + break; + } + string_printf( + temp, "%s\r\n", string_search(buffer, path) ? string_get_cstr(buffer) : dst); + archive_file_append(ARCHIVE_FAV_TEMP_PATH, temp); + string_clean(temp); + } + } + + string_clear(temp); + string_clear(buffer); + string_clear(path); + + file_worker_close(file_worker); + file_worker_remove(file_worker, ARCHIVE_FAV_PATH); + file_worker_rename(file_worker, ARCHIVE_FAV_TEMP_PATH, ARCHIVE_FAV_PATH); + + file_worker_free(file_worker); + + return result; +} + +void archive_add_to_favorites(const char* file_path, const char* name) { + furi_assert(file_path); + furi_assert(name); + + string_t buffer_src; + + string_init_printf(buffer_src, "%s/%s\r\n", file_path, name); + archive_file_append(ARCHIVE_FAV_PATH, buffer_src); + string_clear(buffer_src); +} diff --git a/applications/archive/helpers/archive_favorites.h b/applications/archive/helpers/archive_favorites.h new file mode 100644 index 00000000..7a8fce00 --- /dev/null +++ b/applications/archive/helpers/archive_favorites.h @@ -0,0 +1,11 @@ +#pragma once +#include "file-worker.h" + +#define ARCHIVE_FAV_PATH "/any/favorites.txt" +#define ARCHIVE_FAV_TEMP_PATH "/any/favorites.tmp" + +bool archive_favorites_read(void* context); +bool archive_favorites_delete(const char* file_path, const char* name); +bool archive_is_favorite(const char* file_path, const char* name); +bool archive_favorites_rename(const char* file_path, const char* src, const char* dst); +void archive_add_to_favorites(const char* file_path, const char* name); diff --git a/applications/archive/helpers/archive_files.c b/applications/archive/helpers/archive_files.c new file mode 100644 index 00000000..036df166 --- /dev/null +++ b/applications/archive/helpers/archive_files.c @@ -0,0 +1,143 @@ +#include "archive_files.h" +#include "archive_favorites.h" +#include "../archive_i.h" + +bool filter_by_extension(FileInfo* file_info, const char* tab_ext, const char* name) { + furi_assert(file_info); + furi_assert(tab_ext); + furi_assert(name); + + bool result = false; + + if(strcmp(tab_ext, "*") == 0) { + result = true; + } else if(strstr(name, tab_ext) != NULL) { + result = true; + } else if(file_info->flags & FSF_DIRECTORY) { + result = true; + } + + return result; +} + +void archive_trim_file_ext(char* name) { + size_t str_len = strlen(name); + char* end = name + str_len; + while(end > name && *end != '.' && *end != '\\' && *end != '/') { + --end; + } + if((end > name && *end == '.') && (*(end - 1) != '\\' && *(end - 1) != '/')) { + *end = '\0'; + } +} + +void set_file_type(ArchiveFile_t* file, FileInfo* file_info) { + furi_assert(file); + furi_assert(file_info); + + for(size_t i = 0; i < SIZEOF_ARRAY(known_ext); i++) { + if(string_search_str(file->name, known_ext[i], 0) != STRING_FAILURE) { + file->type = i; + return; + } + } + + if(file_info->flags & FSF_DIRECTORY) { + file->type = ArchiveFileTypeFolder; + } else { + file->type = ArchiveFileTypeUnknown; + } +} + +bool archive_get_filenames(void* context, uint8_t tab_id, const char* path) { + furi_assert(context); + + ArchiveMainView* main_view = context; + archive_file_array_clean(main_view); + + if(tab_id != ArchiveTabFavorites) { + archive_read_dir(main_view, path); + } else { + archive_favorites_read(main_view); + } + return true; +} + +bool archive_read_dir(void* context, const char* path) { + furi_assert(context); + + ArchiveMainView* main_view = context; + FileInfo file_info; + Storage* fs_api = furi_record_open("storage"); + File* directory = storage_file_alloc(fs_api); + char name[MAX_NAME_LEN]; + + if(!storage_dir_open(directory, path)) { + storage_dir_close(directory); + storage_file_free(directory); + return false; + } + + while(1) { + if(!storage_dir_read(directory, &file_info, name, MAX_NAME_LEN)) { + break; + } + + uint16_t files_cnt = archive_file_array_size(main_view); + + if(files_cnt > MAX_FILES) { + break; + } else if(storage_file_get_error(directory) == FSE_OK) { + archive_view_add_item(main_view, &file_info, name); + } else { + storage_dir_close(directory); + storage_file_free(directory); + return false; + } + } + storage_dir_close(directory); + storage_file_free(directory); + + furi_record_close("storage"); + + return true; +} + +void archive_file_append(const char* path, string_t string) { + furi_assert(path); + furi_assert(string); + + FileWorker* file_worker = file_worker_alloc(false); + + if(!file_worker_open(file_worker, path, FSAM_WRITE, FSOM_OPEN_APPEND)) { + FURI_LOG_E("Archive", "Append open error"); + } + + if(!file_worker_write(file_worker, string_get_cstr(string), string_size(string))) { + FURI_LOG_E("Archive", "Append write error"); + } + + file_worker_close(file_worker); + file_worker_free(file_worker); +} + +void archive_delete_file(void* context, string_t path, string_t name) { + furi_assert(context); + furi_assert(path); + furi_assert(name); + ArchiveMainView* main_view = context; + FileWorker* file_worker = file_worker_alloc(false); + + string_t full_path; + string_init(full_path); + string_printf(full_path, "%s/%s", string_get_cstr(path), string_get_cstr(name)); + file_worker_remove(file_worker, string_get_cstr(full_path)); + file_worker_free(file_worker); + string_clear(full_path); + + if(archive_is_favorite(string_get_cstr(path), string_get_cstr(name))) { + archive_favorites_delete(string_get_cstr(path), string_get_cstr(name)); + } + + archive_file_array_remove_selected(main_view); +} diff --git a/applications/archive/archive_views.h b/applications/archive/helpers/archive_files.h similarity index 58% rename from applications/archive/archive_views.h rename to applications/archive/helpers/archive_files.h index 9c9cd8f6..71864fe9 100644 --- a/applications/archive/archive_views.h +++ b/applications/archive/helpers/archive_files.h @@ -1,15 +1,7 @@ #pragma once +#include "file-worker.h" -#include -#include -#include -#include -#include - -#define MAX_LEN_PX 100 -#define MAX_NAME_LEN 255 -#define FRAME_HEIGHT 12 -#define MENU_ITEMS 4 +#define MAX_FILES 100 //temp typedef enum { ArchiveFileTypeIButton, @@ -22,17 +14,6 @@ typedef enum { AppIdTotal, } ArchiveFileTypeEnum; -typedef enum { - ArchiveTabFavorites, - ArchiveTabLFRFID, - ArchiveTabSubGhz, - ArchiveTabNFC, - ArchiveTabIButton, - ArchiveTabIrda, - ArchiveTabBrowser, - ArchiveTabTotal, -} ArchiveTabEnum; - typedef struct { string_t name; ArchiveFileTypeEnum type; @@ -66,18 +47,10 @@ ARRAY_DEF( INIT_SET(API_6(ArchiveFile_t_init_set)), CLEAR(API_2(ArchiveFile_t_clear)))) -typedef struct { - uint8_t tab_idx; - uint8_t menu_idx; - uint16_t idx; - uint16_t list_offset; - files_array_t files; - bool menu; -} ArchiveViewModel; - -void archive_view_render(Canvas* canvas, void* model); +bool filter_by_extension(FileInfo* file_info, const char* tab_ext, const char* name); +void set_file_type(ArchiveFile_t* file, FileInfo* file_info); void archive_trim_file_ext(char* name); - -static inline bool is_known_app(ArchiveFileTypeEnum type) { - return (type != ArchiveFileTypeFolder && type != ArchiveFileTypeUnknown); -} +bool archive_get_filenames(void* context, uint8_t tab_id, const char* path); +bool archive_read_dir(void* context, const char* path); +void archive_file_append(const char* path, string_t string); +void archive_delete_file(void* context, string_t path, string_t name); \ No newline at end of file diff --git a/applications/archive/scenes/archive_scene.c b/applications/archive/scenes/archive_scene.c new file mode 100644 index 00000000..d5f5ae2c --- /dev/null +++ b/applications/archive/scenes/archive_scene.c @@ -0,0 +1,30 @@ +#include "archive_scene.h" + +// Generate scene on_enter handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter, +void (*const archive_on_enter_handlers[])(void*) = { +#include "archive_scene_config.h" +}; +#undef ADD_SCENE + +// Generate scene on_event handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event, +bool (*const archive_on_event_handlers[])(void* context, SceneManagerEvent event) = { +#include "archive_scene_config.h" +}; +#undef ADD_SCENE + +// Generate scene on_exit handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit, +void (*const archive_on_exit_handlers[])(void* context) = { +#include "archive_scene_config.h" +}; +#undef ADD_SCENE + +// Initialize scene handlers configuration structure +const SceneManagerHandlers archive_scene_handlers = { + .on_enter_handlers = archive_on_enter_handlers, + .on_event_handlers = archive_on_event_handlers, + .on_exit_handlers = archive_on_exit_handlers, + .scene_num = ArchiveAppSceneNum, +}; diff --git a/applications/archive/scenes/archive_scene.h b/applications/archive/scenes/archive_scene.h new file mode 100644 index 00000000..3f8063fa --- /dev/null +++ b/applications/archive/scenes/archive_scene.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +// Generate scene id and total number +#define ADD_SCENE(prefix, name, id) ArchiveAppScene##id, +typedef enum { +#include "archive_scene_config.h" + ArchiveAppSceneNum, +} ArchiveAppScene; +#undef ADD_SCENE + +extern const SceneManagerHandlers archive_scene_handlers; + +// Generate scene on_enter handlers declaration +#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*); +#include "archive_scene_config.h" +#undef ADD_SCENE + +// Generate scene on_event handlers declaration +#define ADD_SCENE(prefix, name, id) \ + bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event); +#include "archive_scene_config.h" +#undef ADD_SCENE + +// Generate scene on_exit handlers declaration +#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context); +#include "archive_scene_config.h" +#undef ADD_SCENE diff --git a/applications/archive/scenes/archive_scene_browser.c b/applications/archive/scenes/archive_scene_browser.c new file mode 100644 index 00000000..ed6204ff --- /dev/null +++ b/applications/archive/scenes/archive_scene_browser.c @@ -0,0 +1,42 @@ +#include "../archive_i.h" +#include "../views/archive_main_view.h" + +void archive_scene_browser_callback(ArchiveBrowserEvent event, void* context) { + ArchiveApp* archive = (ArchiveApp*)context; + view_dispatcher_send_custom_event(archive->view_dispatcher, event); +} + +const void archive_scene_browser_on_enter(void* context) { + ArchiveApp* archive = (ArchiveApp*)context; + ArchiveMainView* main_view = archive->main_view; + + archive_browser_set_callback(main_view, archive_scene_browser_callback, archive); + archive_browser_update(main_view); + view_dispatcher_switch_to_view(archive->view_dispatcher, ArchiveViewBrowser); +} + +const bool archive_scene_browser_on_event(void* context, SceneManagerEvent event) { + ArchiveApp* archive = (ArchiveApp*)context; + bool consumed; + + if(event.type == SceneManagerEventTypeCustom) { + switch(event.event) { + case ArchiveBrowserEventRename: + scene_manager_next_scene(archive->scene_manager, ArchiveAppSceneRename); + consumed = true; + break; + case ArchiveBrowserEventExit: + view_dispatcher_stop(archive->view_dispatcher); + consumed = true; + break; + + default: + break; + } + } + return consumed; +} + +const void archive_scene_browser_on_exit(void* context) { + // ArchiveApp* archive = (ArchiveApp*)context; +} diff --git a/applications/archive/scenes/archive_scene_config.h b/applications/archive/scenes/archive_scene_config.h new file mode 100644 index 00000000..2ed4e00c --- /dev/null +++ b/applications/archive/scenes/archive_scene_config.h @@ -0,0 +1,2 @@ +ADD_SCENE(archive, browser, Browser) +ADD_SCENE(archive, rename, Rename) diff --git a/applications/archive/scenes/archive_scene_rename.c b/applications/archive/scenes/archive_scene_rename.c new file mode 100644 index 00000000..51918e5a --- /dev/null +++ b/applications/archive/scenes/archive_scene_rename.c @@ -0,0 +1,80 @@ +#include "../archive_i.h" +#include "../helpers/archive_favorites.h" +#include "../helpers/archive_files.h" + +#define SCENE_RENAME_CUSTOM_EVENT (0UL) + +void archive_scene_rename_text_input_callback(void* context) { + ArchiveApp* archive = (ArchiveApp*)context; + view_dispatcher_send_custom_event(archive->view_dispatcher, SCENE_RENAME_CUSTOM_EVENT); +} + +const void archive_scene_rename_on_enter(void* context) { + ArchiveApp* archive = (ArchiveApp*)context; + + TextInput* text_input = archive->text_input; + ArchiveFile_t* current = archive_get_current_file(archive->main_view); + strlcpy(archive->text_store, string_get_cstr(current->name), MAX_NAME_LEN); + + archive_trim_file_ext(archive->text_store); + + text_input_set_header_text(text_input, "Rename:"); + + text_input_set_result_callback( + text_input, + archive_scene_rename_text_input_callback, + archive, + archive->text_store, + MAX_NAME_LEN, + false); + + view_dispatcher_switch_to_view(archive->view_dispatcher, ArchiveViewTextInput); +} + +const bool archive_scene_rename_on_event(void* context, SceneManagerEvent event) { + ArchiveApp* archive = (ArchiveApp*)context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SCENE_RENAME_CUSTOM_EVENT) { + Storage* fs_api = furi_record_open("storage"); + + string_t buffer_src; + string_t buffer_dst; + + const char* path = archive_get_path(archive->main_view); + const char* name = archive_get_name(archive->main_view); + + string_init_printf(buffer_src, "%s/%s", path, name); + string_init_printf(buffer_dst, "%s/%s", path, archive->text_store); + + archive_set_name(archive->main_view, archive->text_store); + + // append extension + ArchiveFile_t* file = archive_get_current_file(archive->main_view); + + string_cat(buffer_dst, known_ext[file->type]); + storage_common_rename( + fs_api, string_get_cstr(buffer_src), string_get_cstr(buffer_dst)); + furi_record_close("storage"); + + if(file->fav) { + archive_favorites_rename(path, name, string_get_cstr(buffer_dst)); + } + + string_clear(buffer_src); + string_clear(buffer_dst); + + scene_manager_next_scene(archive->scene_manager, ArchiveAppSceneBrowser); + consumed = true; + } + } + return consumed; +} + +const void archive_scene_rename_on_exit(void* context) { + ArchiveApp* archive = (ArchiveApp*)context; + // Clear view + text_input_set_header_text(archive->text_input, NULL); + text_input_set_result_callback(archive->text_input, NULL, NULL, NULL, 0, false); +} diff --git a/applications/archive/views/archive_main_view.c b/applications/archive/views/archive_main_view.c new file mode 100644 index 00000000..826a7483 --- /dev/null +++ b/applications/archive/views/archive_main_view.c @@ -0,0 +1,642 @@ +#include +#include "../archive_i.h" +#include "archive_main_view.h" + +static const char* flipper_app_name[] = { + [ArchiveFileTypeIButton] = "iButton", + [ArchiveFileTypeNFC] = "NFC", + [ArchiveFileTypeSubGhz] = "Sub-GHz", + [ArchiveFileTypeLFRFID] = "125 kHz RFID", + [ArchiveFileTypeIrda] = "Infrared", +}; + +static const char* ArchiveTabNames[] = { + [ArchiveTabFavorites] = "Favorites", + [ArchiveTabIButton] = "iButton", + [ArchiveTabNFC] = "NFC", + [ArchiveTabSubGhz] = "Sub-GHz", + [ArchiveTabLFRFID] = "RFID LF", + [ArchiveTabIrda] = "Infrared", + [ArchiveTabBrowser] = "Browser"}; + +static const Icon* ArchiveItemIcons[] = { + [ArchiveFileTypeIButton] = &I_ibutt_10px, + [ArchiveFileTypeNFC] = &I_Nfc_10px, + [ArchiveFileTypeSubGhz] = &I_sub1_10px, + [ArchiveFileTypeLFRFID] = &I_125_10px, + [ArchiveFileTypeIrda] = &I_ir_10px, + [ArchiveFileTypeFolder] = &I_dir_10px, + [ArchiveFileTypeUnknown] = &I_unknown_10px, +}; + +void archive_browser_set_callback( + ArchiveMainView* main_view, + ArchiveMainViewCallback callback, + void* context) { + furi_assert(main_view); + furi_assert(callback); + main_view->callback = callback; + main_view->context = context; +} + +void update_offset(ArchiveMainView* main_view) { + furi_assert(main_view); + + with_view_model( + main_view->view, (ArchiveMainViewModel * model) { + size_t array_size = files_array_size(model->files); + uint16_t bounds = array_size > 3 ? 2 : array_size; + + if(array_size > 3 && model->idx >= array_size - 1) { + model->list_offset = model->idx - 3; + } else if(model->list_offset < model->idx - bounds) { + model->list_offset = CLAMP(model->list_offset + 1, array_size - bounds, 0); + } else if(model->list_offset > model->idx - bounds) { + model->list_offset = CLAMP(model->idx - 1, array_size - bounds, 0); + } + return true; + }); +} + +size_t archive_file_array_size(ArchiveMainView* main_view) { + uint16_t size = 0; + with_view_model( + main_view->view, (ArchiveMainViewModel * model) { + size = files_array_size(model->files); + return true; + }); + return size; +} + +void archive_file_array_remove_selected(ArchiveMainView* main_view) { + with_view_model( + main_view->view, (ArchiveMainViewModel * model) { + files_array_remove_v(model->files, model->idx, model->idx + 1); + model->idx = CLAMP(model->idx, files_array_size(model->files) - 1, 0); + return true; + }); + + update_offset(main_view); +} + +void archive_file_array_clean(ArchiveMainView* main_view) { + with_view_model( + main_view->view, (ArchiveMainViewModel * model) { + files_array_clean(model->files); + return true; + }); +} + +ArchiveFile_t* archive_get_current_file(ArchiveMainView* main_view) { + ArchiveFile_t* selected; + with_view_model( + main_view->view, (ArchiveMainViewModel * model) { + selected = files_array_size(model->files) > 0 ? + files_array_get(model->files, model->idx) : + NULL; + return true; + }); + return selected; +} + +ArchiveTabEnum archive_get_tab(ArchiveMainView* main_view) { + ArchiveTabEnum tab_id; + with_view_model( + main_view->view, (ArchiveMainViewModel * model) { + tab_id = model->tab_idx; + return true; + }); + return tab_id; +} + +void archive_set_tab(ArchiveMainView* main_view, ArchiveTabEnum tab) { + with_view_model( + main_view->view, (ArchiveMainViewModel * model) { + model->tab_idx = tab; + return true; + }); +} + +uint8_t archive_get_depth(ArchiveMainView* main_view) { + uint8_t depth; + with_view_model( + main_view->view, (ArchiveMainViewModel * model) { + depth = model->depth; + return true; + }); + + return depth; +} + +const char* archive_get_path(ArchiveMainView* main_view) { + return string_get_cstr(main_view->path); +} +const char* archive_get_name(ArchiveMainView* main_view) { + ArchiveFile_t* selected = archive_get_current_file(main_view); + return string_get_cstr(selected->name); +} + +void archive_set_name(ArchiveMainView* main_view, const char* name) { + furi_assert(main_view); + furi_assert(name); + + string_set(main_view->name, name); +} + +void archive_browser_update(ArchiveMainView* main_view) { + furi_assert(main_view); + + archive_get_filenames(main_view, archive_get_tab(main_view), string_get_cstr(main_view->path)); + + with_view_model( + main_view->view, (ArchiveMainViewModel * model) { + uint16_t idx = 0; + while(idx < files_array_size(model->files)) { + ArchiveFile_t* current = files_array_get(model->files, idx); + if(!string_search(current->name, string_get_cstr(main_view->name))) { + model->idx = idx; + break; + } + ++idx; + } + return true; + }); + + update_offset(main_view); +} + +void archive_view_add_item(ArchiveMainView* main_view, FileInfo* file_info, const char* name) { + furi_assert(main_view); + furi_assert(file_info); + furi_assert(name); + + ArchiveFile_t item; + + if(filter_by_extension(file_info, get_tab_ext(archive_get_tab(main_view)), name)) { + ArchiveFile_t_init(&item); + string_init_set_str(item.name, name); + set_file_type(&item, file_info); + + with_view_model( + main_view->view, (ArchiveMainViewModel * model) { + files_array_push_back(model->files, item); + return true; + }); + + ArchiveFile_t_clear(&item); + } +} + +static void render_item_menu(Canvas* canvas, ArchiveMainViewModel* model) { + canvas_set_color(canvas, ColorWhite); + canvas_draw_box(canvas, 71, 17, 57, 46); + canvas_set_color(canvas, ColorBlack); + elements_slightly_rounded_frame(canvas, 70, 16, 58, 48); + + string_t menu[MENU_ITEMS]; + + string_init_set_str(menu[0], "Run in app"); + string_init_set_str(menu[1], "Pin"); + string_init_set_str(menu[2], "Rename"); + string_init_set_str(menu[3], "Delete"); + + ArchiveFile_t* selected = files_array_get(model->files, model->idx); + + if(!is_known_app(selected->type)) { + string_set_str(menu[0], "---"); + string_set_str(menu[1], "---"); + string_set_str(menu[2], "---"); + } else if(selected->fav) { + string_set_str(menu[1], "Unpin"); + } + + for(size_t i = 0; i < MENU_ITEMS; i++) { + canvas_draw_str(canvas, 82, 27 + i * 11, string_get_cstr(menu[i])); + string_clear(menu[i]); + } + + canvas_draw_icon(canvas, 74, 20 + model->menu_idx * 11, &I_ButtonRight_4x7); +} + +static void archive_draw_frame(Canvas* canvas, uint16_t idx, bool scrollbar) { + canvas_set_color(canvas, ColorBlack); + canvas_draw_box(canvas, 0, 15 + idx * FRAME_HEIGHT, scrollbar ? 122 : 127, FRAME_HEIGHT); + + canvas_set_color(canvas, ColorWhite); + canvas_draw_dot(canvas, 0, 15 + idx * FRAME_HEIGHT); + canvas_draw_dot(canvas, 1, 15 + idx * FRAME_HEIGHT); + canvas_draw_dot(canvas, 0, (15 + idx * FRAME_HEIGHT) + 1); + + canvas_draw_dot(canvas, 0, (15 + idx * FRAME_HEIGHT) + 11); + canvas_draw_dot(canvas, scrollbar ? 121 : 126, 15 + idx * FRAME_HEIGHT); + canvas_draw_dot(canvas, scrollbar ? 121 : 126, (15 + idx * FRAME_HEIGHT) + 11); +} + +static void draw_list(Canvas* canvas, ArchiveMainViewModel* model) { + furi_assert(model); + + size_t array_size = files_array_size(model->files); + bool scrollbar = array_size > 4; + + for(size_t i = 0; i < MIN(array_size, MENU_ITEMS); ++i) { + string_t str_buff; + char cstr_buff[MAX_NAME_LEN]; + + size_t idx = CLAMP(i + model->list_offset, array_size, 0); + ArchiveFile_t* file = files_array_get(model->files, CLAMP(idx, array_size - 1, 0)); + + string_init_set(str_buff, file->name); + string_right(str_buff, string_search_rchar(str_buff, '/') + 1); + strlcpy(cstr_buff, string_get_cstr(str_buff), string_size(str_buff) + 1); + + if(is_known_app(file->type)) archive_trim_file_ext(cstr_buff); + + string_clean(str_buff); + string_set_str(str_buff, cstr_buff); + + elements_string_fit_width(canvas, str_buff, scrollbar ? MAX_LEN_PX - 6 : MAX_LEN_PX); + + if(model->idx == idx) { + archive_draw_frame(canvas, i, scrollbar); + } else { + canvas_set_color(canvas, ColorBlack); + } + + canvas_draw_icon(canvas, 2, 16 + i * FRAME_HEIGHT, ArchiveItemIcons[file->type]); + canvas_draw_str(canvas, 15, 24 + i * FRAME_HEIGHT, string_get_cstr(str_buff)); + string_clear(str_buff); + } + + if(scrollbar) { + elements_scrollbar_pos(canvas, 126, 15, 49, model->idx, array_size); + } + + if(model->action == BrowserActionItemMenu) { + render_item_menu(canvas, model); + } +} + +static void archive_render_status_bar(Canvas* canvas, ArchiveMainViewModel* model) { + furi_assert(model); + + const char* tab_name = ArchiveTabNames[model->tab_idx]; + + canvas_draw_icon(canvas, 0, 0, &I_Background_128x11); + + canvas_set_color(canvas, ColorWhite); + canvas_draw_box(canvas, 0, 0, 50, 13); + canvas_draw_box(canvas, 107, 0, 20, 13); + + canvas_set_color(canvas, ColorBlack); + canvas_draw_frame(canvas, 1, 0, 50, 12); + canvas_draw_line(canvas, 0, 1, 0, 11); + canvas_draw_line(canvas, 1, 12, 49, 12); + canvas_draw_str_aligned(canvas, 26, 9, AlignCenter, AlignBottom, tab_name); + + canvas_draw_frame(canvas, 108, 0, 20, 12); + canvas_draw_line(canvas, 107, 1, 107, 11); + canvas_draw_line(canvas, 108, 12, 126, 12); + + if(model->tab_idx > 0) { + canvas_draw_icon(canvas, 112, 2, &I_ButtonLeft_4x7); + } + if(model->tab_idx < SIZEOF_ARRAY(ArchiveTabNames) - 1) { + canvas_draw_icon(canvas, 120, 2, &I_ButtonRight_4x7); + } + + canvas_set_color(canvas, ColorWhite); + canvas_draw_dot(canvas, 50, 0); + canvas_draw_dot(canvas, 127, 0); + + canvas_set_color(canvas, ColorBlack); +} + +void archive_view_render(Canvas* canvas, void* model) { + ArchiveMainViewModel* m = model; + + archive_render_status_bar(canvas, model); + + if(files_array_size(m->files) > 0) { + draw_list(canvas, m); + } else { + canvas_draw_str_aligned( + canvas, GUI_DISPLAY_WIDTH / 2, 40, AlignCenter, AlignCenter, "Empty"); + } +} + +View* archive_main_get_view(ArchiveMainView* main_view) { + furi_assert(main_view); + return main_view->view; +} + +static void archive_show_file_menu(ArchiveMainView* main_view) { + furi_assert(main_view); + with_view_model( + main_view->view, (ArchiveMainViewModel * model) { + ArchiveFile_t* selected; + selected = files_array_get(model->files, model->idx); + model->action = BrowserActionItemMenu; + model->menu_idx = 0; + selected->fav = is_known_app(selected->type) ? archive_is_favorite( + string_get_cstr(main_view->path), + string_get_cstr(selected->name)) : + false; + + return true; + }); +} + +static void archive_close_file_menu(ArchiveMainView* main_view) { + furi_assert(main_view); + + with_view_model( + main_view->view, (ArchiveMainViewModel * model) { + model->action = BrowserActionBrowse; + model->menu_idx = 0; + return true; + }); +} + +static void archive_run_in_app( + ArchiveMainView* main_view, + ArchiveFile_t* selected, + bool full_path_provided) { + Loader* loader = furi_record_open("loader"); + + string_t full_path; + + if(!full_path_provided) { + string_init_printf( + full_path, "%s/%s", string_get_cstr(main_view->path), string_get_cstr(selected->name)); + } else { + string_init_set(full_path, selected->name); + } + loader_start(loader, flipper_app_name[selected->type], string_get_cstr(full_path)); + + string_clear(full_path); + furi_record_close("loader"); +} + +static void archive_file_menu_callback(ArchiveMainView* main_view) { + furi_assert(main_view); + + ArchiveFile_t* selected = archive_get_current_file(main_view); + const char* path = archive_get_path(main_view); + const char* name = archive_get_name(main_view); + + uint8_t idx; + with_view_model( + main_view->view, (ArchiveMainViewModel * model) { + idx = model->menu_idx; + return true; + }); + + switch(idx) { + case 0: + if(is_known_app(selected->type)) { + archive_run_in_app(main_view, selected, false); + } + break; + case 1: + if(is_known_app(selected->type)) { + if(!archive_is_favorite(path, name)) { + archive_set_name(main_view, string_get_cstr(selected->name)); + archive_add_to_favorites(path, name); + } else { + // delete from favorites + archive_favorites_delete(path, name); + } + archive_close_file_menu(main_view); + } + break; + case 2: + // open rename view + if(is_known_app(selected->type)) { + main_view->callback(ArchiveBrowserEventRename, main_view->context); + } + break; + case 3: + // confirmation? + archive_delete_file(main_view, main_view->path, selected->name); + archive_close_file_menu(main_view); + break; + + default: + archive_close_file_menu(main_view); + break; + } + selected = NULL; +} + +static void archive_switch_dir(ArchiveMainView* main_view, const char* path) { + furi_assert(main_view); + furi_assert(path); + + string_set(main_view->path, path); + archive_get_filenames(main_view, archive_get_tab(main_view), string_get_cstr(main_view->path)); + update_offset(main_view); +} + +void archive_switch_tab(ArchiveMainView* main_view) { + furi_assert(main_view); + + with_view_model( + main_view->view, (ArchiveMainViewModel * model) { + model->idx = 0; + model->depth = 0; + return true; + }); + + archive_switch_dir(main_view, tab_default_paths[archive_get_tab(main_view)]); +} + +static void archive_enter_dir(ArchiveMainView* main_view, string_t name) { + furi_assert(main_view); + furi_assert(name); + + // update last index + with_view_model( + main_view->view, (ArchiveMainViewModel * model) { + model->last_idx[model->depth] = + CLAMP(model->idx, files_array_size(model->files) - 1, 0); + model->idx = 0; + model->depth = CLAMP(model->depth + 1, MAX_DEPTH, 0); + return true; + }); + + string_cat(main_view->path, "/"); + string_cat(main_view->path, main_view->name); + + archive_switch_dir(main_view, string_get_cstr(main_view->path)); +} + +static void archive_leave_dir(ArchiveMainView* main_view) { + furi_assert(main_view); + + char* last_char_ptr = strrchr(string_get_cstr(main_view->path), '/'); + + if(last_char_ptr) { + size_t pos = last_char_ptr - string_get_cstr(main_view->path); + string_left(main_view->path, pos); + } + + with_view_model( + main_view->view, (ArchiveMainViewModel * model) { + model->depth = CLAMP(model->depth - 1, MAX_DEPTH, 0); + model->idx = model->last_idx[model->depth]; + return true; + }); + + archive_switch_dir(main_view, string_get_cstr(main_view->path)); +} + +bool archive_view_input(InputEvent* event, void* context) { + furi_assert(event); + furi_assert(context); + + ArchiveMainView* main_view = context; + + BrowserActionEnum action; + with_view_model( + main_view->view, (ArchiveMainViewModel * model) { + action = model->action; + return true; + }); + + switch(action) { + case BrowserActionItemMenu: + + if(event->type == InputTypeShort) { + if(event->key == InputKeyUp || event->key == InputKeyDown) { + with_view_model( + main_view->view, (ArchiveMainViewModel * model) { + if(event->key == InputKeyUp) { + model->menu_idx = ((model->menu_idx - 1) + MENU_ITEMS) % MENU_ITEMS; + } else if(event->key == InputKeyDown) { + model->menu_idx = (model->menu_idx + 1) % MENU_ITEMS; + } + return true; + }); + } + + if(event->key == InputKeyOk) { + archive_file_menu_callback(main_view); + } else if(event->key == InputKeyBack) { + archive_close_file_menu(main_view); + } + } + break; + + case BrowserActionBrowse: + + if(event->type == InputTypeShort) { + if(event->key == InputKeyLeft) { + ArchiveTabEnum tab = archive_get_tab(main_view); + if(tab) { + archive_set_tab(main_view, CLAMP(tab - 1, ArchiveTabTotal, 0)); + archive_switch_tab(main_view); + return true; + } + } else if(event->key == InputKeyRight) { + ArchiveTabEnum tab = archive_get_tab(main_view); + + if(tab < ArchiveTabTotal - 1) { + archive_set_tab(main_view, CLAMP(tab + 1, ArchiveTabTotal - 1, 0)); + archive_switch_tab(main_view); + return true; + } + + } else if(event->key == InputKeyBack) { + if(!archive_get_depth(main_view)) { + main_view->callback(ArchiveBrowserEventExit, main_view->context); + } else { + archive_leave_dir(main_view); + } + + return true; + } + } + if(event->key == InputKeyUp || event->key == InputKeyDown) { + with_view_model( + main_view->view, (ArchiveMainViewModel * model) { + uint16_t num_elements = (uint16_t)files_array_size(model->files); + if((event->type == InputTypeShort || event->type == InputTypeRepeat)) { + if(event->key == InputKeyUp) { + model->idx = ((model->idx - 1) + num_elements) % num_elements; + } else if(event->key == InputKeyDown) { + model->idx = (model->idx + 1) % num_elements; + } + } + + return true; + }); + update_offset(main_view); + } + + if(event->key == InputKeyOk) { + ArchiveFile_t* selected = archive_get_current_file(main_view); + + if(selected) { + archive_set_name(main_view, string_get_cstr(selected->name)); + if(selected->type == ArchiveFileTypeFolder) { + if(event->type == InputTypeShort) { + archive_enter_dir(main_view, main_view->name); + } else if(event->type == InputTypeLong) { + archive_show_file_menu(main_view); + } + } else { + if(event->type == InputTypeShort) { + if(archive_get_tab(main_view) == ArchiveTabFavorites) { + if(is_known_app(selected->type)) { + archive_run_in_app(main_view, selected, true); + } + } else { + archive_show_file_menu(main_view); + } + } + } + } + } + break; + default: + break; + } + + return true; +} + +ArchiveMainView* main_view_alloc() { + ArchiveMainView* main_view = furi_alloc(sizeof(ArchiveMainView)); + main_view->view = view_alloc(); + view_allocate_model(main_view->view, ViewModelTypeLocking, sizeof(ArchiveMainViewModel)); + view_set_context(main_view->view, main_view); + view_set_draw_callback(main_view->view, (ViewDrawCallback)archive_view_render); + view_set_input_callback(main_view->view, archive_view_input); + + string_init(main_view->name); + string_init(main_view->path); + + with_view_model( + main_view->view, (ArchiveMainViewModel * model) { + files_array_init(model->files); + return true; + }); + + return main_view; +} + +void main_view_free(ArchiveMainView* main_view) { + furi_assert(main_view); + + with_view_model( + main_view->view, (ArchiveMainViewModel * model) { + files_array_clear(model->files); + return false; + }); + + string_clear(main_view->name); + string_clear(main_view->path); + + view_free(main_view->view); + free(main_view); +} diff --git a/applications/archive/views/archive_main_view.h b/applications/archive/views/archive_main_view.h new file mode 100644 index 00000000..b3d07879 --- /dev/null +++ b/applications/archive/views/archive_main_view.h @@ -0,0 +1,117 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include "../helpers/archive_files.h" +#include "../helpers/archive_favorites.h" + +#define MAX_LEN_PX 110 +#define MAX_NAME_LEN 255 +#define FRAME_HEIGHT 12 +#define MENU_ITEMS 4 +#define MAX_DEPTH 32 + +typedef enum { + ArchiveTabFavorites, + ArchiveTabLFRFID, + ArchiveTabSubGhz, + ArchiveTabNFC, + ArchiveTabIButton, + ArchiveTabIrda, + ArchiveTabBrowser, + ArchiveTabTotal, +} ArchiveTabEnum; + +static const char* known_ext[] = { + [ArchiveFileTypeIButton] = ".ibtn", + [ArchiveFileTypeNFC] = ".nfc", + [ArchiveFileTypeSubGhz] = ".sub", + [ArchiveFileTypeLFRFID] = ".rfid", + [ArchiveFileTypeIrda] = ".ir", +}; + +static inline const char* get_tab_ext(ArchiveTabEnum tab) { + switch(tab) { + case ArchiveTabIButton: + return known_ext[ArchiveFileTypeIButton]; + case ArchiveTabNFC: + return known_ext[ArchiveFileTypeNFC]; + case ArchiveTabSubGhz: + return known_ext[ArchiveFileTypeSubGhz]; + case ArchiveTabLFRFID: + return known_ext[ArchiveFileTypeLFRFID]; + case ArchiveTabIrda: + return known_ext[ArchiveFileTypeIrda]; + default: + return "*"; + } +} + +typedef enum { + ArchiveBrowserEventRename, + ArchiveBrowserEventExit, + ArchiveBrowserEventLeaveDir, +} ArchiveBrowserEvent; + +typedef struct ArchiveMainView ArchiveMainView; + +typedef void (*ArchiveMainViewCallback)(ArchiveBrowserEvent event, void* context); + +typedef enum { + BrowserActionBrowse, + BrowserActionItemMenu, + BrowserActionTotal, +} BrowserActionEnum; + +struct ArchiveMainView { + View* view; + ArchiveMainViewCallback callback; + void* context; + + string_t name; + string_t path; +}; + +typedef struct { + ArchiveTabEnum tab_idx; + BrowserActionEnum action; + files_array_t files; + + uint8_t depth; + uint8_t menu_idx; + + uint16_t idx; + uint16_t last_idx[MAX_DEPTH]; + uint16_t list_offset; + +} ArchiveMainViewModel; + +void archive_browser_set_callback( + ArchiveMainView* main_view, + ArchiveMainViewCallback callback, + void* context); + +View* archive_main_get_view(ArchiveMainView* main_view); + +ArchiveMainView* main_view_alloc(); +void main_view_free(ArchiveMainView* main_view); + +void archive_file_array_remove_selected(ArchiveMainView* main_view); +void archive_file_array_clean(ArchiveMainView* main_view); + +void archive_view_add_item(ArchiveMainView* main_view, FileInfo* file_info, const char* name); +void archive_browser_update(ArchiveMainView* main_view); + +size_t archive_file_array_size(ArchiveMainView* main_view); +ArchiveFile_t* archive_get_current_file(ArchiveMainView* main_view); +const char* archive_get_path(ArchiveMainView* main_view); +const char* archive_get_name(ArchiveMainView* main_view); +void archive_set_name(ArchiveMainView* main_view, const char* name); + +static inline bool is_known_app(ArchiveFileTypeEnum type) { + return (type != ArchiveFileTypeFolder && type != ArchiveFileTypeUnknown); +} From 80739929255ff1861eef82600f216c76c1064a08 Mon Sep 17 00:00:00 2001 From: SG Date: Fri, 10 Sep 2021 12:19:02 +1000 Subject: [PATCH 07/13] [FL-1587] RFID: Clock for emulation timer from antenna (#622) * RFID: pull antenna down when emulating * Rfid: fixed HID emulation by adding zero pulse every 4 bits * Rfid: HID emulation fixed with DSP based FSK oscillator. * Rfid: receive 125KHz clock for emulation timer from antenna and comparator * Rfid: commented unused variable * Firmware: rollback changes in f6. * Add F7 target based on F6. * F7/F6: update cube projects, apply changes to the targets, update linker scripts with correct RAM start values. * FuriHal: RFID init routine. * Scripts: update OTP tool for v11 board Co-authored-by: Aleksandr Kutuzov --- .github/workflows/build.yml | 2 +- .github/workflows/lint_c.yml | 2 +- .../targets/f7/furi-hal/furi-hal-gpio.c | 189 +++ .../targets/f7/furi-hal/furi-hal-gpio.h | 264 ++++ bootloader/targets/f7/furi-hal/furi-hal-i2c.c | 137 +++ bootloader/targets/f7/furi-hal/furi-hal-i2c.h | 43 + .../targets/f7/furi-hal/furi-hal-light.c | 43 + .../targets/f7/furi-hal/furi-hal-light.h | 17 + .../targets/f7/furi-hal/furi-hal-resources.c | 41 + .../targets/f7/furi-hal/furi-hal-resources.h | 82 ++ .../targets/f7/furi-hal/furi-hal-spi-config.c | 114 ++ .../targets/f7/furi-hal/furi-hal-spi-config.h | 61 + bootloader/targets/f7/furi-hal/furi-hal-spi.c | 240 ++++ bootloader/targets/f7/furi-hal/furi-hal-spi.h | 129 ++ bootloader/targets/f7/furi-hal/furi-hal.c | 7 + bootloader/targets/f7/furi-hal/furi-hal.h | 8 + bootloader/targets/f7/furi-hal/main.h | 108 ++ .../targets/f7/furi-hal/u8g2_periphery.c | 69 ++ .../targets/f7/stm32wb55xx_flash_cm4.ld | 187 +++ bootloader/targets/f7/target.c | 264 ++++ bootloader/targets/f7/target.mk | 48 + firmware/targets/f6/Inc/FreeRTOSConfig.h | 8 + firmware/targets/f6/cube/Inc/FreeRTOSConfig.h | 20 +- firmware/targets/f6/cube/Inc/main.h | 38 +- firmware/targets/f6/cube/Inc/usbd_cdc_if.h | 3 +- firmware/targets/f6/cube/Makefile | 126 +- firmware/targets/f6/cube/Src/adc.c | 11 + firmware/targets/f6/cube/Src/aes.c | 20 + firmware/targets/f6/cube/Src/comp.c | 10 + firmware/targets/f6/cube/Src/crc.c | 10 + firmware/targets/f6/cube/Src/i2c.c | 11 + firmware/targets/f6/cube/Src/main.c | 8 +- firmware/targets/f6/cube/Src/pka.c | 10 + firmware/targets/f6/cube/Src/rf.c | 11 + firmware/targets/f6/cube/Src/rng.c | 11 + firmware/targets/f6/cube/Src/rtc.c | 11 + firmware/targets/f6/cube/Src/spi.c | 20 + .../targets/f6/cube/Src/system_stm32wbxx.c | 725 +++++------ firmware/targets/f6/cube/Src/tim.c | 33 + firmware/targets/f6/cube/Src/usart.c | 13 +- firmware/targets/f6/cube/Src/usbd_cdc_if.c | 2 +- firmware/targets/f6/cube/Src/usbd_conf.c | 6 +- firmware/targets/f6/cube/Src/usbd_desc.c | 2 +- firmware/targets/f6/cube/f6.ioc | 23 +- .../targets/f6/cube/startup_stm32wb55xx_cm4.s | 889 +++++++------- .../targets/f6/cube/stm32wb55xx_flash_cm4.ld | 2 +- firmware/targets/f6/furi-hal/furi-hal-clock.c | 1 + firmware/targets/f6/furi-hal/furi-hal-rfid.c | 4 + firmware/targets/f6/furi-hal/furi-hal.c | 1 + .../targets/f6/stm32wb55xx_flash_cm4_boot.ld | 2 +- .../f6/stm32wb55xx_flash_cm4_no_boot.ld | 2 +- firmware/targets/f7/Inc/FreeRTOSConfig.h | 180 +++ firmware/targets/f7/Inc/aes.h | 54 + firmware/targets/f7/Inc/comp.h | 52 + firmware/targets/f7/Inc/gpio.h | 49 + firmware/targets/f7/Inc/main.h | 149 +++ firmware/targets/f7/Inc/pka.h | 52 + firmware/targets/f7/Inc/rf.h | 50 + firmware/targets/f7/Inc/rng.h | 52 + firmware/targets/f7/Inc/rtc.h | 52 + firmware/targets/f7/Inc/stm32wbxx_hal_conf.h | 353 ++++++ firmware/targets/f7/Inc/stm32wbxx_it.h | 69 ++ firmware/targets/f7/Inc/tim.h | 58 + firmware/targets/f7/Src/aes.c | 127 ++ firmware/targets/f7/Src/comp.c | 103 ++ firmware/targets/f7/Src/fatfs/fatfs.c | 56 + firmware/targets/f7/Src/fatfs/fatfs.h | 49 + firmware/targets/f7/Src/fatfs/ffconf.h | 270 +++++ firmware/targets/f7/Src/fatfs/spi_sd_hal.c | 100 ++ .../targets/f7/Src/fatfs/stm32_adafruit_sd.c | 1073 +++++++++++++++++ .../targets/f7/Src/fatfs/stm32_adafruit_sd.h | 252 ++++ firmware/targets/f7/Src/fatfs/syscall.c | 138 +++ firmware/targets/f7/Src/fatfs/user_diskio.c | 223 ++++ firmware/targets/f7/Src/fatfs/user_diskio.h | 48 + firmware/targets/f7/Src/freertos-openocd.c | 21 + firmware/targets/f7/Src/gpio.c | 139 +++ firmware/targets/f7/Src/main.c | 55 + firmware/targets/f7/Src/pka.c | 77 ++ firmware/targets/f7/Src/rf.c | 37 + firmware/targets/f7/Src/rng.c | 77 ++ firmware/targets/f7/Src/rtc.c | 123 ++ firmware/targets/f7/Src/stm32wbxx_hal_msp.c | 93 ++ firmware/targets/f7/Src/stm32wbxx_it.c | 52 + firmware/targets/f7/Src/system_stm32wbxx.c | 357 ++++++ firmware/targets/f7/Src/tim.c | 361 ++++++ firmware/targets/f7/ble-glue/app_ble.c | 776 ++++++++++++ firmware/targets/f7/ble-glue/app_ble.h | 27 + firmware/targets/f7/ble-glue/app_common.h | 43 + firmware/targets/f7/ble-glue/app_conf.h | 474 ++++++++ firmware/targets/f7/ble-glue/app_entry.c | 192 +++ firmware/targets/f7/ble-glue/app_entry.h | 20 + .../targets/f7/ble-glue/battery_service.c | 55 + .../targets/f7/ble-glue/battery_service.h | 16 + firmware/targets/f7/ble-glue/ble_conf.h | 69 ++ firmware/targets/f7/ble-glue/ble_dbg_conf.h | 199 +++ .../targets/f7/ble-glue/dev_info_service.c | 121 ++ .../targets/f7/ble-glue/dev_info_service.h | 20 + firmware/targets/f7/ble-glue/hw_conf.h | 199 +++ firmware/targets/f7/ble-glue/hw_if.h | 250 ++++ firmware/targets/f7/ble-glue/hw_ipcc.c | 675 +++++++++++ firmware/targets/f7/ble-glue/hw_timerserver.c | 893 ++++++++++++++ firmware/targets/f7/ble-glue/serial_service.c | 102 ++ firmware/targets/f7/ble-glue/serial_service.h | 22 + firmware/targets/f7/ble-glue/tl_dbg_conf.h | 136 +++ firmware/targets/f7/ble-glue/utilities_conf.h | 68 ++ firmware/targets/f7/cube/Inc/FreeRTOSConfig.h | 186 +++ firmware/targets/f7/cube/Inc/adc.h | 52 + firmware/targets/f7/cube/Inc/aes.h | 54 + firmware/targets/f7/cube/Inc/comp.h | 52 + firmware/targets/f7/cube/Inc/crc.h | 52 + firmware/targets/f7/cube/Inc/gpio.h | 49 + firmware/targets/f7/cube/Inc/i2c.h | 50 + firmware/targets/f7/cube/Inc/main.h | 175 +++ firmware/targets/f7/cube/Inc/pka.h | 52 + firmware/targets/f7/cube/Inc/rf.h | 50 + firmware/targets/f7/cube/Inc/rng.h | 52 + firmware/targets/f7/cube/Inc/rtc.h | 52 + firmware/targets/f7/cube/Inc/spi.h | 54 + firmware/targets/f7/cube/Inc/stm32_assert.h | 53 + .../targets/f7/cube/Inc/stm32wbxx_hal_conf.h | 353 ++++++ firmware/targets/f7/cube/Inc/stm32wbxx_it.h | 77 ++ firmware/targets/f7/cube/Inc/tim.h | 58 + firmware/targets/f7/cube/Inc/usart.h | 50 + firmware/targets/f7/cube/Inc/usb_device.h | 105 ++ firmware/targets/f7/cube/Inc/usbd_cdc_if.h | 133 ++ firmware/targets/f7/cube/Inc/usbd_conf.h | 176 +++ firmware/targets/f7/cube/Inc/usbd_desc.h | 145 +++ firmware/targets/f7/cube/Makefile | 253 ++++ firmware/targets/f7/cube/Src/adc.c | 139 +++ firmware/targets/f7/cube/Src/aes.c | 147 +++ firmware/targets/f7/cube/Src/app_freertos.c | 183 +++ firmware/targets/f7/cube/Src/comp.c | 113 ++ firmware/targets/f7/cube/Src/crc.c | 92 ++ firmware/targets/f7/cube/Src/gpio.c | 181 +++ firmware/targets/f7/cube/Src/i2c.c | 83 ++ firmware/targets/f7/cube/Src/main.c | 290 +++++ firmware/targets/f7/cube/Src/pka.c | 87 ++ firmware/targets/f7/cube/Src/rf.c | 48 + firmware/targets/f7/cube/Src/rng.c | 88 ++ firmware/targets/f7/cube/Src/rtc.c | 134 ++ firmware/targets/f7/cube/Src/spi.c | 232 ++++ .../targets/f7/cube/Src/stm32wbxx_hal_msp.c | 93 ++ firmware/targets/f7/cube/Src/stm32wbxx_it.c | 326 +++++ .../targets/f7/cube/Src/system_stm32wbxx.c | 368 ++++++ firmware/targets/f7/cube/Src/tim.c | 394 ++++++ firmware/targets/f7/cube/Src/usart.c | 95 ++ firmware/targets/f7/cube/Src/usb_device.c | 99 ++ firmware/targets/f7/cube/Src/usbd_cdc_if.c | 331 +++++ firmware/targets/f7/cube/Src/usbd_conf.c | 810 +++++++++++++ firmware/targets/f7/cube/Src/usbd_desc.c | 396 ++++++ firmware/targets/f7/cube/f7.ioc | 598 +++++++++ .../targets/f7/cube/startup_stm32wb55xx_cm4.s | 444 +++++++ .../targets/f7/cube/stm32wb55xx_flash_cm4.ld | 187 +++ firmware/targets/f7/furi-hal/furi-hal-boot.c | 31 + firmware/targets/f7/furi-hal/furi-hal-bt.c | 144 +++ firmware/targets/f7/furi-hal/furi-hal-clock.c | 141 +++ firmware/targets/f7/furi-hal/furi-hal-clock.h | 10 + .../targets/f7/furi-hal/furi-hal-console.c | 73 ++ .../targets/f7/furi-hal/furi-hal-console.h | 26 + firmware/targets/f7/furi-hal/furi-hal-delay.c | 34 + firmware/targets/f7/furi-hal/furi-hal-flash.c | 89 ++ firmware/targets/f7/furi-hal/furi-hal-flash.h | 74 ++ firmware/targets/f7/furi-hal/furi-hal-gpio.c | 299 +++++ firmware/targets/f7/furi-hal/furi-hal-gpio.h | 264 ++++ firmware/targets/f7/furi-hal/furi-hal-i2c.c | 152 +++ .../targets/f7/furi-hal/furi-hal-ibutton.c | 24 + .../targets/f7/furi-hal/furi-hal-interrupt.c | 208 ++++ .../targets/f7/furi-hal/furi-hal-interrupt.h | 34 + firmware/targets/f7/furi-hal/furi-hal-irda.c | 639 ++++++++++ firmware/targets/f7/furi-hal/furi-hal-light.c | 44 + firmware/targets/f7/furi-hal/furi-hal-nfc.c | 174 +++ .../targets/f7/furi-hal/furi-hal-os-timer.h | 64 + firmware/targets/f7/furi-hal/furi-hal-os.c | 143 +++ firmware/targets/f7/furi-hal/furi-hal-os.h | 17 + firmware/targets/f7/furi-hal/furi-hal-power.c | 280 +++++ firmware/targets/f7/furi-hal/furi-hal-pwm.c | 50 + firmware/targets/f7/furi-hal/furi-hal-pwm.h | 16 + .../targets/f7/furi-hal/furi-hal-resources.c | 57 + .../targets/f7/furi-hal/furi-hal-resources.h | 105 ++ firmware/targets/f7/furi-hal/furi-hal-rfid.c | 297 +++++ firmware/targets/f7/furi-hal/furi-hal-sd.c | 22 + .../targets/f7/furi-hal/furi-hal-spi-config.c | 103 ++ .../targets/f7/furi-hal/furi-hal-spi-config.h | 63 + firmware/targets/f7/furi-hal/furi-hal-spi.c | 200 +++ firmware/targets/f7/furi-hal/furi-hal-spi.h | 108 ++ .../targets/f7/furi-hal/furi-hal-subghz.c | 714 +++++++++++ firmware/targets/f7/furi-hal/furi-hal-task.c | 54 + firmware/targets/f7/furi-hal/furi-hal-task.h | 12 + firmware/targets/f7/furi-hal/furi-hal-vcp.c | 128 ++ firmware/targets/f7/furi-hal/furi-hal-vcp_i.h | 13 + .../targets/f7/furi-hal/furi-hal-version.c | 242 ++++ firmware/targets/f7/furi-hal/furi-hal-vibro.c | 13 + firmware/targets/f7/furi-hal/furi-hal.c | 65 + firmware/targets/f7/startup_stm32wb55xx_cm4.s | 444 +++++++ .../targets/f7/stm32wb55xx_flash_cm4_boot.ld | 192 +++ .../f7/stm32wb55xx_flash_cm4_no_boot.ld | 192 +++ firmware/targets/f7/target.mk | 169 +++ firmware/targets/f7/usb-glue/usb_device.c | 34 + firmware/targets/f7/usb-glue/usb_device.h | 11 + firmware/targets/f7/usb-glue/usbd_cdc_if.c | 142 +++ firmware/targets/f7/usb-glue/usbd_cdc_if.h | 22 + firmware/targets/f7/usb-glue/usbd_conf.c | 506 ++++++++ firmware/targets/f7/usb-glue/usbd_conf.h | 73 ++ firmware/targets/f7/usb-glue/usbd_desc.c | 206 ++++ firmware/targets/f7/usb-glue/usbd_desc.h | 19 + .../targets/furi-hal-include/furi-hal-rfid.h | 3 + scripts/otp.py | 8 +- 207 files changed, 28052 insertions(+), 932 deletions(-) create mode 100644 bootloader/targets/f7/furi-hal/furi-hal-gpio.c create mode 100644 bootloader/targets/f7/furi-hal/furi-hal-gpio.h create mode 100644 bootloader/targets/f7/furi-hal/furi-hal-i2c.c create mode 100644 bootloader/targets/f7/furi-hal/furi-hal-i2c.h create mode 100644 bootloader/targets/f7/furi-hal/furi-hal-light.c create mode 100644 bootloader/targets/f7/furi-hal/furi-hal-light.h create mode 100644 bootloader/targets/f7/furi-hal/furi-hal-resources.c create mode 100644 bootloader/targets/f7/furi-hal/furi-hal-resources.h create mode 100644 bootloader/targets/f7/furi-hal/furi-hal-spi-config.c create mode 100644 bootloader/targets/f7/furi-hal/furi-hal-spi-config.h create mode 100644 bootloader/targets/f7/furi-hal/furi-hal-spi.c create mode 100644 bootloader/targets/f7/furi-hal/furi-hal-spi.h create mode 100644 bootloader/targets/f7/furi-hal/furi-hal.c create mode 100644 bootloader/targets/f7/furi-hal/furi-hal.h create mode 100644 bootloader/targets/f7/furi-hal/main.h create mode 100644 bootloader/targets/f7/furi-hal/u8g2_periphery.c create mode 100644 bootloader/targets/f7/stm32wb55xx_flash_cm4.ld create mode 100644 bootloader/targets/f7/target.c create mode 100644 bootloader/targets/f7/target.mk create mode 100644 firmware/targets/f7/Inc/FreeRTOSConfig.h create mode 100644 firmware/targets/f7/Inc/aes.h create mode 100644 firmware/targets/f7/Inc/comp.h create mode 100644 firmware/targets/f7/Inc/gpio.h create mode 100644 firmware/targets/f7/Inc/main.h create mode 100644 firmware/targets/f7/Inc/pka.h create mode 100644 firmware/targets/f7/Inc/rf.h create mode 100644 firmware/targets/f7/Inc/rng.h create mode 100644 firmware/targets/f7/Inc/rtc.h create mode 100644 firmware/targets/f7/Inc/stm32wbxx_hal_conf.h create mode 100644 firmware/targets/f7/Inc/stm32wbxx_it.h create mode 100644 firmware/targets/f7/Inc/tim.h create mode 100644 firmware/targets/f7/Src/aes.c create mode 100644 firmware/targets/f7/Src/comp.c create mode 100644 firmware/targets/f7/Src/fatfs/fatfs.c create mode 100644 firmware/targets/f7/Src/fatfs/fatfs.h create mode 100644 firmware/targets/f7/Src/fatfs/ffconf.h create mode 100644 firmware/targets/f7/Src/fatfs/spi_sd_hal.c create mode 100644 firmware/targets/f7/Src/fatfs/stm32_adafruit_sd.c create mode 100644 firmware/targets/f7/Src/fatfs/stm32_adafruit_sd.h create mode 100644 firmware/targets/f7/Src/fatfs/syscall.c create mode 100644 firmware/targets/f7/Src/fatfs/user_diskio.c create mode 100644 firmware/targets/f7/Src/fatfs/user_diskio.h create mode 100644 firmware/targets/f7/Src/freertos-openocd.c create mode 100644 firmware/targets/f7/Src/gpio.c create mode 100644 firmware/targets/f7/Src/main.c create mode 100644 firmware/targets/f7/Src/pka.c create mode 100644 firmware/targets/f7/Src/rf.c create mode 100644 firmware/targets/f7/Src/rng.c create mode 100644 firmware/targets/f7/Src/rtc.c create mode 100644 firmware/targets/f7/Src/stm32wbxx_hal_msp.c create mode 100644 firmware/targets/f7/Src/stm32wbxx_it.c create mode 100644 firmware/targets/f7/Src/system_stm32wbxx.c create mode 100644 firmware/targets/f7/Src/tim.c create mode 100644 firmware/targets/f7/ble-glue/app_ble.c create mode 100644 firmware/targets/f7/ble-glue/app_ble.h create mode 100644 firmware/targets/f7/ble-glue/app_common.h create mode 100644 firmware/targets/f7/ble-glue/app_conf.h create mode 100644 firmware/targets/f7/ble-glue/app_entry.c create mode 100644 firmware/targets/f7/ble-glue/app_entry.h create mode 100644 firmware/targets/f7/ble-glue/battery_service.c create mode 100644 firmware/targets/f7/ble-glue/battery_service.h create mode 100644 firmware/targets/f7/ble-glue/ble_conf.h create mode 100644 firmware/targets/f7/ble-glue/ble_dbg_conf.h create mode 100644 firmware/targets/f7/ble-glue/dev_info_service.c create mode 100644 firmware/targets/f7/ble-glue/dev_info_service.h create mode 100644 firmware/targets/f7/ble-glue/hw_conf.h create mode 100644 firmware/targets/f7/ble-glue/hw_if.h create mode 100644 firmware/targets/f7/ble-glue/hw_ipcc.c create mode 100644 firmware/targets/f7/ble-glue/hw_timerserver.c create mode 100644 firmware/targets/f7/ble-glue/serial_service.c create mode 100644 firmware/targets/f7/ble-glue/serial_service.h create mode 100644 firmware/targets/f7/ble-glue/tl_dbg_conf.h create mode 100644 firmware/targets/f7/ble-glue/utilities_conf.h create mode 100644 firmware/targets/f7/cube/Inc/FreeRTOSConfig.h create mode 100644 firmware/targets/f7/cube/Inc/adc.h create mode 100644 firmware/targets/f7/cube/Inc/aes.h create mode 100644 firmware/targets/f7/cube/Inc/comp.h create mode 100644 firmware/targets/f7/cube/Inc/crc.h create mode 100644 firmware/targets/f7/cube/Inc/gpio.h create mode 100644 firmware/targets/f7/cube/Inc/i2c.h create mode 100644 firmware/targets/f7/cube/Inc/main.h create mode 100644 firmware/targets/f7/cube/Inc/pka.h create mode 100644 firmware/targets/f7/cube/Inc/rf.h create mode 100644 firmware/targets/f7/cube/Inc/rng.h create mode 100644 firmware/targets/f7/cube/Inc/rtc.h create mode 100644 firmware/targets/f7/cube/Inc/spi.h create mode 100644 firmware/targets/f7/cube/Inc/stm32_assert.h create mode 100644 firmware/targets/f7/cube/Inc/stm32wbxx_hal_conf.h create mode 100644 firmware/targets/f7/cube/Inc/stm32wbxx_it.h create mode 100644 firmware/targets/f7/cube/Inc/tim.h create mode 100644 firmware/targets/f7/cube/Inc/usart.h create mode 100644 firmware/targets/f7/cube/Inc/usb_device.h create mode 100644 firmware/targets/f7/cube/Inc/usbd_cdc_if.h create mode 100644 firmware/targets/f7/cube/Inc/usbd_conf.h create mode 100644 firmware/targets/f7/cube/Inc/usbd_desc.h create mode 100644 firmware/targets/f7/cube/Makefile create mode 100644 firmware/targets/f7/cube/Src/adc.c create mode 100644 firmware/targets/f7/cube/Src/aes.c create mode 100644 firmware/targets/f7/cube/Src/app_freertos.c create mode 100644 firmware/targets/f7/cube/Src/comp.c create mode 100644 firmware/targets/f7/cube/Src/crc.c create mode 100644 firmware/targets/f7/cube/Src/gpio.c create mode 100644 firmware/targets/f7/cube/Src/i2c.c create mode 100644 firmware/targets/f7/cube/Src/main.c create mode 100644 firmware/targets/f7/cube/Src/pka.c create mode 100644 firmware/targets/f7/cube/Src/rf.c create mode 100644 firmware/targets/f7/cube/Src/rng.c create mode 100644 firmware/targets/f7/cube/Src/rtc.c create mode 100644 firmware/targets/f7/cube/Src/spi.c create mode 100644 firmware/targets/f7/cube/Src/stm32wbxx_hal_msp.c create mode 100644 firmware/targets/f7/cube/Src/stm32wbxx_it.c create mode 100644 firmware/targets/f7/cube/Src/system_stm32wbxx.c create mode 100644 firmware/targets/f7/cube/Src/tim.c create mode 100644 firmware/targets/f7/cube/Src/usart.c create mode 100644 firmware/targets/f7/cube/Src/usb_device.c create mode 100644 firmware/targets/f7/cube/Src/usbd_cdc_if.c create mode 100644 firmware/targets/f7/cube/Src/usbd_conf.c create mode 100644 firmware/targets/f7/cube/Src/usbd_desc.c create mode 100644 firmware/targets/f7/cube/f7.ioc create mode 100644 firmware/targets/f7/cube/startup_stm32wb55xx_cm4.s create mode 100644 firmware/targets/f7/cube/stm32wb55xx_flash_cm4.ld create mode 100644 firmware/targets/f7/furi-hal/furi-hal-boot.c create mode 100644 firmware/targets/f7/furi-hal/furi-hal-bt.c create mode 100644 firmware/targets/f7/furi-hal/furi-hal-clock.c create mode 100644 firmware/targets/f7/furi-hal/furi-hal-clock.h create mode 100644 firmware/targets/f7/furi-hal/furi-hal-console.c create mode 100644 firmware/targets/f7/furi-hal/furi-hal-console.h create mode 100644 firmware/targets/f7/furi-hal/furi-hal-delay.c create mode 100644 firmware/targets/f7/furi-hal/furi-hal-flash.c create mode 100644 firmware/targets/f7/furi-hal/furi-hal-flash.h create mode 100644 firmware/targets/f7/furi-hal/furi-hal-gpio.c create mode 100644 firmware/targets/f7/furi-hal/furi-hal-gpio.h create mode 100644 firmware/targets/f7/furi-hal/furi-hal-i2c.c create mode 100644 firmware/targets/f7/furi-hal/furi-hal-ibutton.c create mode 100644 firmware/targets/f7/furi-hal/furi-hal-interrupt.c create mode 100644 firmware/targets/f7/furi-hal/furi-hal-interrupt.h create mode 100644 firmware/targets/f7/furi-hal/furi-hal-irda.c create mode 100644 firmware/targets/f7/furi-hal/furi-hal-light.c create mode 100644 firmware/targets/f7/furi-hal/furi-hal-nfc.c create mode 100644 firmware/targets/f7/furi-hal/furi-hal-os-timer.h create mode 100644 firmware/targets/f7/furi-hal/furi-hal-os.c create mode 100644 firmware/targets/f7/furi-hal/furi-hal-os.h create mode 100644 firmware/targets/f7/furi-hal/furi-hal-power.c create mode 100644 firmware/targets/f7/furi-hal/furi-hal-pwm.c create mode 100644 firmware/targets/f7/furi-hal/furi-hal-pwm.h create mode 100644 firmware/targets/f7/furi-hal/furi-hal-resources.c create mode 100644 firmware/targets/f7/furi-hal/furi-hal-resources.h create mode 100644 firmware/targets/f7/furi-hal/furi-hal-rfid.c create mode 100644 firmware/targets/f7/furi-hal/furi-hal-sd.c create mode 100644 firmware/targets/f7/furi-hal/furi-hal-spi-config.c create mode 100644 firmware/targets/f7/furi-hal/furi-hal-spi-config.h create mode 100644 firmware/targets/f7/furi-hal/furi-hal-spi.c create mode 100644 firmware/targets/f7/furi-hal/furi-hal-spi.h create mode 100644 firmware/targets/f7/furi-hal/furi-hal-subghz.c create mode 100644 firmware/targets/f7/furi-hal/furi-hal-task.c create mode 100644 firmware/targets/f7/furi-hal/furi-hal-task.h create mode 100644 firmware/targets/f7/furi-hal/furi-hal-vcp.c create mode 100644 firmware/targets/f7/furi-hal/furi-hal-vcp_i.h create mode 100644 firmware/targets/f7/furi-hal/furi-hal-version.c create mode 100644 firmware/targets/f7/furi-hal/furi-hal-vibro.c create mode 100644 firmware/targets/f7/furi-hal/furi-hal.c create mode 100644 firmware/targets/f7/startup_stm32wb55xx_cm4.s create mode 100644 firmware/targets/f7/stm32wb55xx_flash_cm4_boot.ld create mode 100644 firmware/targets/f7/stm32wb55xx_flash_cm4_no_boot.ld create mode 100644 firmware/targets/f7/target.mk create mode 100644 firmware/targets/f7/usb-glue/usb_device.c create mode 100644 firmware/targets/f7/usb-glue/usb_device.h create mode 100644 firmware/targets/f7/usb-glue/usbd_cdc_if.c create mode 100644 firmware/targets/f7/usb-glue/usbd_cdc_if.h create mode 100644 firmware/targets/f7/usb-glue/usbd_conf.c create mode 100644 firmware/targets/f7/usb-glue/usbd_conf.h create mode 100644 firmware/targets/f7/usb-glue/usbd_desc.c create mode 100644 firmware/targets/f7/usb-glue/usbd_desc.h diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 765da29a..722c7711 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,7 +10,7 @@ on: pull_request: env: - TARGETS: f6 + TARGETS: f6 f7 jobs: build: diff --git a/.github/workflows/lint_c.yml b/.github/workflows/lint_c.yml index 7d4942a2..1fa47e5a 100644 --- a/.github/workflows/lint_c.yml +++ b/.github/workflows/lint_c.yml @@ -10,7 +10,7 @@ on: pull_request: env: - TARGETS: f6 + TARGETS: f6 f7 jobs: lint_c_cpp: diff --git a/bootloader/targets/f7/furi-hal/furi-hal-gpio.c b/bootloader/targets/f7/furi-hal/furi-hal-gpio.c new file mode 100644 index 00000000..ec926d77 --- /dev/null +++ b/bootloader/targets/f7/furi-hal/furi-hal-gpio.c @@ -0,0 +1,189 @@ +#include +#include +#include + +#define GET_SYSCFG_EXTI_PORT(gpio) \ + (((gpio) == (GPIOA)) ? LL_SYSCFG_EXTI_PORTA : \ + ((gpio) == (GPIOB)) ? LL_SYSCFG_EXTI_PORTB : \ + ((gpio) == (GPIOC)) ? LL_SYSCFG_EXTI_PORTC : \ + ((gpio) == (GPIOD)) ? LL_SYSCFG_EXTI_PORTD : \ + ((gpio) == (GPIOE)) ? LL_SYSCFG_EXTI_PORTE : \ + LL_SYSCFG_EXTI_PORTH) + +#define GPIO_PIN_MAP(pin, prefix) \ + (((pin) == (LL_GPIO_PIN_0)) ? prefix##0 : \ + ((pin) == (LL_GPIO_PIN_1)) ? prefix##1 : \ + ((pin) == (LL_GPIO_PIN_2)) ? prefix##2 : \ + ((pin) == (LL_GPIO_PIN_3)) ? prefix##3 : \ + ((pin) == (LL_GPIO_PIN_4)) ? prefix##4 : \ + ((pin) == (LL_GPIO_PIN_5)) ? prefix##5 : \ + ((pin) == (LL_GPIO_PIN_6)) ? prefix##6 : \ + ((pin) == (LL_GPIO_PIN_7)) ? prefix##7 : \ + ((pin) == (LL_GPIO_PIN_8)) ? prefix##8 : \ + ((pin) == (LL_GPIO_PIN_9)) ? prefix##9 : \ + ((pin) == (LL_GPIO_PIN_10)) ? prefix##10 : \ + ((pin) == (LL_GPIO_PIN_11)) ? prefix##11 : \ + ((pin) == (LL_GPIO_PIN_12)) ? prefix##12 : \ + ((pin) == (LL_GPIO_PIN_13)) ? prefix##13 : \ + ((pin) == (LL_GPIO_PIN_14)) ? prefix##14 : \ + prefix##15) + +#define GET_SYSCFG_EXTI_LINE(pin) GPIO_PIN_MAP(pin, LL_SYSCFG_EXTI_LINE) +#define GET_EXTI_LINE(pin) GPIO_PIN_MAP(pin, LL_EXTI_LINE_) + +static volatile GpioInterrupt gpio_interrupt[GPIO_NUMBER]; + +static uint8_t hal_gpio_get_pin_num(const GpioPin* gpio) { + uint8_t pin_num = 0; + for(pin_num = 0; pin_num < GPIO_NUMBER; pin_num++) { + if(gpio->pin & (1 << pin_num)) break; + } + return pin_num; +} + +void hal_gpio_init_simple(const GpioPin* gpio, const GpioMode mode) { + hal_gpio_init(gpio, mode, GpioPullNo, GpioSpeedLow); +} + +void hal_gpio_init( + const GpioPin* gpio, + const GpioMode mode, + const GpioPull pull, + const GpioSpeed speed) { + // we cannot set alternate mode in this function + assert(mode != GpioModeAltFunctionPushPull); + assert(mode != GpioModeAltFunctionOpenDrain); + + hal_gpio_init_ex(gpio, mode, pull, speed, GpioAltFnUnused); +} + +void hal_gpio_init_ex( + const GpioPin* gpio, + const GpioMode mode, + const GpioPull pull, + const GpioSpeed speed, + const GpioAltFn alt_fn) { + uint32_t sys_exti_port = GET_SYSCFG_EXTI_PORT(gpio->port); + uint32_t sys_exti_line = GET_SYSCFG_EXTI_LINE(gpio->pin); + uint32_t exti_line = GET_EXTI_LINE(gpio->pin); + + // Configure gpio with interrupts disabled + __disable_irq(); + // Set gpio speed + if(speed == GpioSpeedLow) { + LL_GPIO_SetPinSpeed(gpio->port, gpio->pin, LL_GPIO_SPEED_FREQ_LOW); + } else if(speed == GpioSpeedMedium) { + LL_GPIO_SetPinSpeed(gpio->port, gpio->pin, LL_GPIO_SPEED_FREQ_MEDIUM); + } else if(speed == GpioSpeedHigh) { + LL_GPIO_SetPinSpeed(gpio->port, gpio->pin, LL_GPIO_SPEED_FREQ_HIGH); + } else { + LL_GPIO_SetPinSpeed(gpio->port, gpio->pin, LL_GPIO_SPEED_FREQ_VERY_HIGH); + } + // Set gpio pull mode + if(pull == GpioPullNo) { + LL_GPIO_SetPinPull(gpio->port, gpio->pin, LL_GPIO_PULL_NO); + } else if(pull == GpioPullUp) { + LL_GPIO_SetPinPull(gpio->port, gpio->pin, LL_GPIO_PULL_UP); + } else { + LL_GPIO_SetPinPull(gpio->port, gpio->pin, LL_GPIO_PULL_DOWN); + } + // Set gpio mode + if(mode >= GpioModeInterruptRise) { + // Set pin in interrupt mode + LL_GPIO_SetPinMode(gpio->port, gpio->pin, LL_GPIO_MODE_INPUT); + LL_SYSCFG_SetEXTISource(sys_exti_port, sys_exti_line); + if(mode == GpioModeInterruptRise || mode == GpioModeInterruptRiseFall) { + LL_EXTI_EnableIT_0_31(exti_line); + LL_EXTI_EnableRisingTrig_0_31(exti_line); + } + if(mode == GpioModeInterruptFall || mode == GpioModeInterruptRiseFall) { + LL_EXTI_EnableIT_0_31(exti_line); + LL_EXTI_EnableFallingTrig_0_31(exti_line); + } + if(mode == GpioModeEventRise || mode == GpioModeInterruptRiseFall) { + LL_EXTI_EnableEvent_0_31(exti_line); + LL_EXTI_EnableRisingTrig_0_31(exti_line); + } + if(mode == GpioModeEventFall || mode == GpioModeInterruptRiseFall) { + LL_EXTI_EnableEvent_0_31(exti_line); + LL_EXTI_EnableFallingTrig_0_31(exti_line); + } + } else { + // Disable interrupt if it was set + if(LL_SYSCFG_GetEXTISource(sys_exti_line) == sys_exti_port && + LL_EXTI_IsEnabledIT_0_31(exti_line)) { + LL_EXTI_DisableIT_0_31(exti_line); + LL_EXTI_DisableRisingTrig_0_31(exti_line); + LL_EXTI_DisableFallingTrig_0_31(exti_line); + } + // Set not interrupt pin modes + if(mode == GpioModeInput) { + LL_GPIO_SetPinMode(gpio->port, gpio->pin, LL_GPIO_MODE_INPUT); + } else if(mode == GpioModeOutputPushPull || mode == GpioModeAltFunctionPushPull) { + LL_GPIO_SetPinMode(gpio->port, gpio->pin, LL_GPIO_MODE_OUTPUT); + LL_GPIO_SetPinOutputType(gpio->port, gpio->pin, LL_GPIO_OUTPUT_PUSHPULL); + } else if(mode == GpioModeOutputOpenDrain || mode == GpioModeAltFunctionOpenDrain) { + LL_GPIO_SetPinMode(gpio->port, gpio->pin, LL_GPIO_MODE_OUTPUT); + LL_GPIO_SetPinOutputType(gpio->port, gpio->pin, LL_GPIO_OUTPUT_OPENDRAIN); + } else if(mode == GpioModeAnalog) { + LL_GPIO_SetPinMode(gpio->port, gpio->pin, LL_GPIO_MODE_ANALOG); + } + } + + if(mode == GpioModeAltFunctionPushPull || mode == GpioModeAltFunctionOpenDrain) { + // enable alternate mode + LL_GPIO_SetPinMode(gpio->port, gpio->pin, LL_GPIO_MODE_ALTERNATE); + + // set alternate function + if(hal_gpio_get_pin_num(gpio) < 8) { + LL_GPIO_SetAFPin_0_7(gpio->port, gpio->pin, alt_fn); + } else { + LL_GPIO_SetAFPin_8_15(gpio->port, gpio->pin, alt_fn); + } + } + + __enable_irq(); +} + +void hal_gpio_add_int_callback(const GpioPin* gpio, GpioExtiCallback cb, void* ctx) { + assert(gpio); + assert(cb); + + __disable_irq(); + uint8_t pin_num = hal_gpio_get_pin_num(gpio); + gpio_interrupt[pin_num].callback = cb; + gpio_interrupt[pin_num].context = ctx; + gpio_interrupt[pin_num].ready = true; + __enable_irq(); +} + +void hal_gpio_enable_int_callback(const GpioPin* gpio) { + assert(gpio); + + __disable_irq(); + uint8_t pin_num = hal_gpio_get_pin_num(gpio); + if(gpio_interrupt[pin_num].callback) { + gpio_interrupt[pin_num].ready = true; + } + __enable_irq(); +} + +void hal_gpio_disable_int_callback(const GpioPin* gpio) { + assert(gpio); + + __disable_irq(); + uint8_t pin_num = hal_gpio_get_pin_num(gpio); + gpio_interrupt[pin_num].ready = false; + __enable_irq(); +} + +void hal_gpio_remove_int_callback(const GpioPin* gpio) { + assert(gpio); + + __disable_irq(); + uint8_t pin_num = hal_gpio_get_pin_num(gpio); + gpio_interrupt[pin_num].callback = NULL; + gpio_interrupt[pin_num].context = NULL; + gpio_interrupt[pin_num].ready = false; + __enable_irq(); +} diff --git a/bootloader/targets/f7/furi-hal/furi-hal-gpio.h b/bootloader/targets/f7/furi-hal/furi-hal-gpio.h new file mode 100644 index 00000000..a81afb39 --- /dev/null +++ b/bootloader/targets/f7/furi-hal/furi-hal-gpio.h @@ -0,0 +1,264 @@ +#pragma once +#include "main.h" +#include "stdbool.h" +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Number of gpio on one port + */ +#define GPIO_NUMBER (16U) + +/** + * Interrupt callback prototype + */ +typedef void (*GpioExtiCallback)(void* ctx); + +/** + * Gpio interrupt type + */ +typedef struct { + GpioExtiCallback callback; + void* context; + volatile bool ready; +} GpioInterrupt; + +/** + * Gpio modes + */ +typedef enum { + GpioModeInput, + GpioModeOutputPushPull, + GpioModeOutputOpenDrain, + GpioModeAltFunctionPushPull, + GpioModeAltFunctionOpenDrain, + GpioModeAnalog, + GpioModeInterruptRise, + GpioModeInterruptFall, + GpioModeInterruptRiseFall, + GpioModeEventRise, + GpioModeEventFall, + GpioModeEventRiseFall, +} GpioMode; + +/** + * Gpio pull modes + */ +typedef enum { + GpioPullNo, + GpioPullUp, + GpioPullDown, +} GpioPull; + +/** + * Gpio speed modes + */ +typedef enum { + GpioSpeedLow, + GpioSpeedMedium, + GpioSpeedHigh, + GpioSpeedVeryHigh, +} GpioSpeed; + +/** + * Gpio alternate functions + */ +typedef enum { + GpioAltFn0MCO = 0, /*!< MCO Alternate Function mapping */ + GpioAltFn0LSCO = 0, /*!< LSCO Alternate Function mapping */ + GpioAltFn0JTMS_SWDIO = 0, /*!< JTMS-SWDIO Alternate Function mapping */ + GpioAltFn0JTCK_SWCLK = 0, /*!< JTCK-SWCLK Alternate Function mapping */ + GpioAltFn0JTDI = 0, /*!< JTDI Alternate Function mapping */ + GpioAltFn0RTC_OUT = 0, /*!< RCT_OUT Alternate Function mapping */ + GpioAltFn0JTD_TRACE = 0, /*!< JTDO-TRACESWO Alternate Function mapping */ + GpioAltFn0NJTRST = 0, /*!< NJTRST Alternate Function mapping */ + GpioAltFn0RTC_REFIN = 0, /*!< RTC_REFIN Alternate Function mapping */ + GpioAltFn0TRACED0 = 0, /*!< TRACED0 Alternate Function mapping */ + GpioAltFn0TRACED1 = 0, /*!< TRACED1 Alternate Function mapping */ + GpioAltFn0TRACED2 = 0, /*!< TRACED2 Alternate Function mapping */ + GpioAltFn0TRACED3 = 0, /*!< TRACED3 Alternate Function mapping */ + GpioAltFn0TRIG_INOUT = 0, /*!< TRIG_INOUT Alternate Function mapping */ + GpioAltFn0TRACECK = 0, /*!< TRACECK Alternate Function mapping */ + GpioAltFn0SYS = 0, /*!< System Function mapping */ + + GpioAltFn1TIM1 = 1, /*!< TIM1 Alternate Function mapping */ + GpioAltFn1TIM2 = 1, /*!< TIM2 Alternate Function mapping */ + GpioAltFn1LPTIM1 = 1, /*!< LPTIM1 Alternate Function mapping */ + + GpioAltFn2TIM2 = 2, /*!< TIM2 Alternate Function mapping */ + GpioAltFn2TIM1 = 2, /*!< TIM1 Alternate Function mapping */ + + GpioAltFn3SAI1 = 3, /*!< SAI1_CK1 Alternate Function mapping */ + GpioAltFn3SPI2 = 3, /*!< SPI2 Alternate Function mapping */ + GpioAltFn3TIM1 = 3, /*!< TIM1 Alternate Function mapping */ + + GpioAltFn4I2C1 = 4, /*!< I2C1 Alternate Function mapping */ + GpioAltFn4I2C3 = 4, /*!< I2C3 Alternate Function mapping */ + + GpioAltFn5SPI1 = 5, /*!< SPI1 Alternate Function mapping */ + GpioAltFn5SPI2 = 5, /*!< SPI2 Alternate Function mapping */ + + GpioAltFn6MCO = 6, /*!< MCO Alternate Function mapping */ + GpioAltFn6LSCO = 6, /*!< LSCO Alternate Function mapping */ + GpioAltFn6RF_DTB0 = 6, /*!< RF_DTB0 Alternate Function mapping */ + GpioAltFn6RF_DTB1 = 6, /*!< RF_DTB1 Alternate Function mapping */ + GpioAltFn6RF_DTB2 = 6, /*!< RF_DTB2 Alternate Function mapping */ + GpioAltFn6RF_DTB3 = 6, /*!< RF_DTB3 Alternate Function mapping */ + GpioAltFn6RF_DTB4 = 6, /*!< RF_DTB4 Alternate Function mapping */ + GpioAltFn6RF_DTB5 = 6, /*!< RF_DTB5 Alternate Function mapping */ + GpioAltFn6RF_DTB6 = 6, /*!< RF_DTB6 Alternate Function mapping */ + GpioAltFn6RF_DTB7 = 6, /*!< RF_DTB7 Alternate Function mapping */ + GpioAltFn6RF_DTB8 = 6, /*!< RF_DTB8 Alternate Function mapping */ + GpioAltFn6RF_DTB9 = 6, /*!< RF_DTB9 Alternate Function mapping */ + GpioAltFn6RF_DTB10 = 6, /*!< RF_DTB10 Alternate Function mapping */ + GpioAltFn6RF_DTB11 = 6, /*!< RF_DTB11 Alternate Function mapping */ + GpioAltFn6RF_DTB12 = 6, /*!< RF_DTB12 Alternate Function mapping */ + GpioAltFn6RF_DTB13 = 6, /*!< RF_DTB13 Alternate Function mapping */ + GpioAltFn6RF_DTB14 = 6, /*!< RF_DTB14 Alternate Function mapping */ + GpioAltFn6RF_DTB15 = 6, /*!< RF_DTB15 Alternate Function mapping */ + GpioAltFn6RF_DTB16 = 6, /*!< RF_DTB16 Alternate Function mapping */ + GpioAltFn6RF_DTB17 = 6, /*!< RF_DTB17 Alternate Function mapping */ + GpioAltFn6RF_DTB18 = 6, /*!< RF_DTB18 Alternate Function mapping */ + GpioAltFn6RF_MISO = 6, /*!< RF_MISO Alternate Function mapping */ + GpioAltFn6RF_MOSI = 6, /*!< RF_MOSI Alternate Function mapping */ + GpioAltFn6RF_SCK = 6, /*!< RF_SCK Alternate Function mapping */ + GpioAltFn6RF_NSS = 6, /*!< RF_NSS Alternate Function mapping */ + + GpioAltFn7USART1 = 7, /*!< USART1 Alternate Function mapping */ + + GpioAltFn8LPUART1 = 8, /*!< LPUART1 Alternate Function mapping */ + GpioAltFn8IR = 8, /*!< IR Alternate Function mapping */ + + GpioAltFn9TSC = 9, /*!< TSC Alternate Function mapping */ + + GpioAltFn10QUADSPI = 10, /*!< QUADSPI Alternate Function mapping */ + GpioAltFn10USB = 10, /*!< USB Alternate Function mapping */ + + GpioAltFn11LCD = 11, /*!< LCD Alternate Function mapping */ + + GpioAltFn12COMP1 = 12, /*!< COMP1 Alternate Function mapping */ + GpioAltFn12COMP2 = 12, /*!< COMP2 Alternate Function mapping */ + GpioAltFn12TIM1 = 12, /*!< TIM1 Alternate Function mapping */ + + GpioAltFn13SAI1 = 13, /*!< SAI1 Alternate Function mapping */ + + GpioAltFn14TIM2 = 14, /*!< TIM2 Alternate Function mapping */ + GpioAltFn14TIM16 = 14, /*!< TIM16 Alternate Function mapping */ + GpioAltFn14TIM17 = 14, /*!< TIM17 Alternate Function mapping */ + GpioAltFn14LPTIM2 = 14, /*!< LPTIM2 Alternate Function mapping */ + + GpioAltFn15EVENTOUT = 15, /*!< EVENTOUT Alternate Function mapping */ + + GpioAltFnUnused = 16, /*!< just dummy value */ +} GpioAltFn; + +/** + * Gpio structure + */ +typedef struct { + GPIO_TypeDef* port; + uint16_t pin; +} GpioPin; + +/** + * GPIO initialization function, simple version + * @param gpio GpioPin + * @param mode GpioMode + */ +void hal_gpio_init_simple(const GpioPin* gpio, const GpioMode mode); + +/** + * GPIO initialization function, normal version + * @param gpio GpioPin + * @param mode GpioMode + * @param pull GpioPull + * @param speed GpioSpeed + */ +void hal_gpio_init( + const GpioPin* gpio, + const GpioMode mode, + const GpioPull pull, + const GpioSpeed speed); + +/** + * GPIO initialization function, extended version + * @param gpio GpioPin + * @param mode GpioMode + * @param pull GpioPull + * @param speed GpioSpeed + * @param alt_fn GpioAltFn + */ +void hal_gpio_init_ex( + const GpioPin* gpio, + const GpioMode mode, + const GpioPull pull, + const GpioSpeed speed, + const GpioAltFn alt_fn); + +/** + * Add and enable interrupt + * @param gpio GpioPin + * @param cb GpioExtiCallback + * @param ctx context for callback + */ +void hal_gpio_add_int_callback(const GpioPin* gpio, GpioExtiCallback cb, void* ctx); + +/** + * Enable interrupt + * @param gpio GpioPin + */ +void hal_gpio_enable_int_callback(const GpioPin* gpio); + +/** + * Disable interrupt + * @param gpio GpioPin + */ +void hal_gpio_disable_int_callback(const GpioPin* gpio); + +/** + * Remove interrupt + * @param gpio GpioPin + */ +void hal_gpio_remove_int_callback(const GpioPin* gpio); + +/** + * GPIO write pin + * @param gpio GpioPin + * @param state true / false + */ +static inline void hal_gpio_write(const GpioPin* gpio, const bool state) { + // writing to BSSR is an atomic operation + if(state == true) { + gpio->port->BSRR = gpio->pin; + } else { + gpio->port->BSRR = (uint32_t)gpio->pin << GPIO_NUMBER; + } +} + +/** + * GPIO read pin + * @param gpio GpioPin + * @return true / false + */ +static inline bool hal_gpio_read(const GpioPin* gpio) { + if((gpio->port->IDR & gpio->pin) != 0x00U) { + return true; + } else { + return false; + } +} + +/** + * Get RFID IN level + * @return false = LOW, true = HIGH + */ +bool hal_gpio_get_rfid_in_level(); + +#ifdef __cplusplus +} +#endif diff --git a/bootloader/targets/f7/furi-hal/furi-hal-i2c.c b/bootloader/targets/f7/furi-hal/furi-hal-i2c.c new file mode 100644 index 00000000..c40a70af --- /dev/null +++ b/bootloader/targets/f7/furi-hal/furi-hal-i2c.c @@ -0,0 +1,137 @@ +#include + +#include +#include +#include +#include +#include + +void furi_hal_i2c_init() { + LL_I2C_InitTypeDef I2C_InitStruct = {0}; + LL_GPIO_InitTypeDef GPIO_InitStruct = {0}; + + LL_RCC_SetI2CClockSource(LL_RCC_I2C1_CLKSOURCE_PCLK1); + + LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA); + GPIO_InitStruct.Pin = POWER_I2C_SCL_Pin | POWER_I2C_SDA_Pin; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE; + GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW; + GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_OPENDRAIN; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + GPIO_InitStruct.Alternate = LL_GPIO_AF_4; + LL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C1); + + I2C_InitStruct.PeripheralMode = LL_I2C_MODE_I2C; + I2C_InitStruct.Timing = POWER_I2C_TIMINGS; + I2C_InitStruct.AnalogFilter = LL_I2C_ANALOGFILTER_ENABLE; + I2C_InitStruct.DigitalFilter = 0; + I2C_InitStruct.OwnAddress1 = 0; + I2C_InitStruct.TypeAcknowledge = LL_I2C_ACK; + I2C_InitStruct.OwnAddrSize = LL_I2C_OWNADDRESS1_7BIT; + LL_I2C_Init(I2C1, &I2C_InitStruct); + LL_I2C_EnableAutoEndMode(I2C1); + LL_I2C_SetOwnAddress2(I2C1, 0, LL_I2C_OWNADDRESS2_NOMASK); + LL_I2C_DisableOwnAddress2(I2C1); + LL_I2C_DisableGeneralCall(I2C1); + LL_I2C_EnableClockStretching(I2C1); +} + +bool furi_hal_i2c_tx( + I2C_TypeDef* instance, + uint8_t address, + const uint8_t* data, + uint8_t size, + uint32_t timeout) { + uint32_t time_left = timeout; + bool ret = true; + + while(LL_I2C_IsActiveFlag_BUSY(instance)) + ; + + LL_I2C_HandleTransfer( + instance, + address, + LL_I2C_ADDRSLAVE_7BIT, + size, + LL_I2C_MODE_AUTOEND, + LL_I2C_GENERATE_START_WRITE); + + while(!LL_I2C_IsActiveFlag_STOP(instance) || size > 0) { + if(LL_I2C_IsActiveFlag_TXIS(instance)) { + LL_I2C_TransmitData8(instance, (*data)); + data++; + size--; + time_left = timeout; + } + + if(LL_SYSTICK_IsActiveCounterFlag()) { + if(--time_left == 0) { + ret = false; + break; + } + } + } + + LL_I2C_ClearFlag_STOP(instance); + + return ret; +} + +bool furi_hal_i2c_rx( + I2C_TypeDef* instance, + uint8_t address, + uint8_t* data, + uint8_t size, + uint32_t timeout) { + uint32_t time_left = timeout; + bool ret = true; + + while(LL_I2C_IsActiveFlag_BUSY(instance)) + ; + + LL_I2C_HandleTransfer( + instance, + address, + LL_I2C_ADDRSLAVE_7BIT, + size, + LL_I2C_MODE_AUTOEND, + LL_I2C_GENERATE_START_READ); + + while(!LL_I2C_IsActiveFlag_STOP(instance) || size > 0) { + if(LL_I2C_IsActiveFlag_RXNE(instance)) { + *data = LL_I2C_ReceiveData8(instance); + data++; + size--; + time_left = timeout; + } + + if(LL_SYSTICK_IsActiveCounterFlag()) { + if(--time_left == 0) { + ret = false; + break; + } + } + } + + LL_I2C_ClearFlag_STOP(instance); + + return ret; +} + +bool furi_hal_i2c_trx( + I2C_TypeDef* instance, + uint8_t address, + const uint8_t* tx_data, + uint8_t tx_size, + uint8_t* rx_data, + uint8_t rx_size, + uint32_t timeout) { + if(furi_hal_i2c_tx(instance, address, tx_data, tx_size, timeout) && + furi_hal_i2c_rx(instance, address, rx_data, rx_size, timeout)) { + return true; + } else { + return false; + } +} diff --git a/bootloader/targets/f7/furi-hal/furi-hal-i2c.h b/bootloader/targets/f7/furi-hal/furi-hal-i2c.h new file mode 100644 index 00000000..5db562e0 --- /dev/null +++ b/bootloader/targets/f7/furi-hal/furi-hal-i2c.h @@ -0,0 +1,43 @@ +#pragma once + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void furi_hal_i2c_init(); + +bool furi_hal_i2c_tx( + I2C_TypeDef* instance, + const uint8_t address, + const uint8_t* data, + const uint8_t size, + uint32_t timeout); + +bool furi_hal_i2c_rx( + I2C_TypeDef* instance, + const uint8_t address, + uint8_t* data, + const uint8_t size, + uint32_t timeout); + +bool furi_hal_i2c_trx( + I2C_TypeDef* instance, + const uint8_t address, + const uint8_t* tx_data, + const uint8_t tx_size, + uint8_t* rx_data, + const uint8_t rx_size, + uint32_t timeout); + +#define with_furi_hal_i2c(type, pointer, function_body) \ + { \ + *pointer = ({ type __fn__ function_body __fn__; })(); \ + } + +#ifdef __cplusplus +} +#endif diff --git a/bootloader/targets/f7/furi-hal/furi-hal-light.c b/bootloader/targets/f7/furi-hal/furi-hal-light.c new file mode 100644 index 00000000..d5f54f6d --- /dev/null +++ b/bootloader/targets/f7/furi-hal/furi-hal-light.c @@ -0,0 +1,43 @@ +#include +#include + +#define LED_CURRENT_RED 50 +#define LED_CURRENT_GREEN 50 +#define LED_CURRENT_BLUE 50 +#define LED_CURRENT_WHITE 150 + +void furi_hal_light_init() { + lp5562_reset(); + + lp5562_set_channel_current(LP5562ChannelRed, LED_CURRENT_RED); + lp5562_set_channel_current(LP5562ChannelGreen, LED_CURRENT_GREEN); + lp5562_set_channel_current(LP5562ChannelBlue, LED_CURRENT_BLUE); + lp5562_set_channel_current(LP5562ChannelWhite, LED_CURRENT_WHITE); + + lp5562_set_channel_value(LP5562ChannelRed, 0x00); + lp5562_set_channel_value(LP5562ChannelGreen, 0x00); + lp5562_set_channel_value(LP5562ChannelBlue, 0x00); + lp5562_set_channel_value(LP5562ChannelWhite, 0x00); + + lp5562_enable(); + lp5562_configure(); +} + +void furi_hal_light_set(Light light, uint8_t value) { + switch(light) { + case LightRed: + lp5562_set_channel_value(LP5562ChannelRed, value); + break; + case LightGreen: + lp5562_set_channel_value(LP5562ChannelGreen, value); + break; + case LightBlue: + lp5562_set_channel_value(LP5562ChannelBlue, value); + break; + case LightBacklight: + lp5562_set_channel_value(LP5562ChannelWhite, value); + break; + default: + break; + } +} \ No newline at end of file diff --git a/bootloader/targets/f7/furi-hal/furi-hal-light.h b/bootloader/targets/f7/furi-hal/furi-hal-light.h new file mode 100644 index 00000000..de976103 --- /dev/null +++ b/bootloader/targets/f7/furi-hal/furi-hal-light.h @@ -0,0 +1,17 @@ +#pragma once + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void furi_hal_light_init(); + +void furi_hal_light_set(Light light, uint8_t value); + +#ifdef __cplusplus +} +#endif diff --git a/bootloader/targets/f7/furi-hal/furi-hal-resources.c b/bootloader/targets/f7/furi-hal/furi-hal-resources.c new file mode 100644 index 00000000..1260a485 --- /dev/null +++ b/bootloader/targets/f7/furi-hal/furi-hal-resources.c @@ -0,0 +1,41 @@ +#include "furi-hal-resources.h" +#include "main.h" + +const GpioPin vibro_gpio = {.port = VIBRO_GPIO_Port, .pin = VIBRO_Pin}; +const GpioPin ibutton_gpio = {.port = iBTN_GPIO_Port, .pin = iBTN_Pin}; + +const GpioPin gpio_cc1101_g0 = {.port = CC1101_G0_GPIO_Port, .pin = CC1101_G0_Pin}; +const GpioPin gpio_rf_sw_0 = {.port = RF_SW_0_GPIO_Port, .pin = RF_SW_0_Pin}; + +const GpioPin gpio_subghz_cs = {.port = CC1101_CS_GPIO_Port, .pin = CC1101_CS_Pin}; +const GpioPin gpio_display_cs = {.port = DISPLAY_CS_GPIO_Port, .pin = DISPLAY_CS_Pin}; +const GpioPin gpio_display_rst = {.port = DISPLAY_RST_GPIO_Port, .pin = DISPLAY_RST_Pin}; +const GpioPin gpio_display_di = {.port = DISPLAY_DI_GPIO_Port, .pin = DISPLAY_DI_Pin}; +const GpioPin gpio_sdcard_cs = {.port = SD_CS_GPIO_Port, .pin = SD_CS_Pin}; +const GpioPin gpio_nfc_cs = {.port = NFC_CS_GPIO_Port, .pin = NFC_CS_Pin}; + +const GpioPin gpio_spi_d_miso = {.port = SPI_D_MISO_GPIO_Port, .pin = SPI_D_MISO_Pin}; +const GpioPin gpio_spi_d_mosi = {.port = SPI_D_MOSI_GPIO_Port, .pin = SPI_D_MOSI_Pin}; +const GpioPin gpio_spi_d_sck = {.port = SPI_D_SCK_GPIO_Port, .pin = SPI_D_SCK_Pin}; +const GpioPin gpio_spi_r_miso = {.port = SPI_R_MISO_GPIO_Port, .pin = SPI_R_MISO_Pin}; +const GpioPin gpio_spi_r_mosi = {.port = SPI_R_MOSI_GPIO_Port, .pin = SPI_R_MOSI_Pin}; +const GpioPin gpio_spi_r_sck = {.port = SPI_R_SCK_GPIO_Port, .pin = SPI_R_SCK_Pin}; + +const GpioPin gpio_ext_pc0 = {.port = GPIOC, .pin = LL_GPIO_PIN_0}; +const GpioPin gpio_ext_pc1 = {.port = GPIOC, .pin = LL_GPIO_PIN_1}; +const GpioPin gpio_ext_pc3 = {.port = GPIOC, .pin = LL_GPIO_PIN_3}; +const GpioPin gpio_ext_pb2 = {.port = GPIOB, .pin = LL_GPIO_PIN_2}; +const GpioPin gpio_ext_pb3 = {.port = GPIOB, .pin = LL_GPIO_PIN_3}; +const GpioPin gpio_ext_pa4 = {.port = GPIOA, .pin = LL_GPIO_PIN_4}; +const GpioPin gpio_ext_pa6 = {.port = GPIOA, .pin = LL_GPIO_PIN_6}; +const GpioPin gpio_ext_pa7 = {.port = GPIOA, .pin = LL_GPIO_PIN_7}; + +const GpioPin gpio_rfid_pull = {.port = RFID_PULL_GPIO_Port, .pin = RFID_PULL_Pin}; +const GpioPin gpio_rfid_carrier_out = {.port = RFID_OUT_GPIO_Port, .pin = RFID_OUT_Pin}; +const GpioPin gpio_rfid_data_in = {.port = RFID_RF_IN_GPIO_Port, .pin = RFID_RF_IN_Pin}; + +const GpioPin gpio_irda_rx = {.port = IR_RX_GPIO_Port, .pin = IR_RX_Pin}; +const GpioPin gpio_irda_tx = {.port = IR_TX_GPIO_Port, .pin = IR_TX_Pin}; + +const GpioPin gpio_usart_tx = {.port = USART1_TX_Port, .pin = USART1_TX_Pin}; +const GpioPin gpio_usart_rx = {.port = USART1_RX_Port, .pin = USART1_RX_Pin}; diff --git a/bootloader/targets/f7/furi-hal/furi-hal-resources.h b/bootloader/targets/f7/furi-hal/furi-hal-resources.h new file mode 100644 index 00000000..95bb4d0d --- /dev/null +++ b/bootloader/targets/f7/furi-hal/furi-hal-resources.h @@ -0,0 +1,82 @@ +#pragma once + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define POWER_I2C_SCL_Pin LL_GPIO_PIN_9 +#define POWER_I2C_SCL_GPIO_Port GPIOA +#define POWER_I2C_SDA_Pin LL_GPIO_PIN_10 +#define POWER_I2C_SDA_GPIO_Port GPIOA + +#define POWER_I2C I2C1 +/* Timing register value is computed with the STM32CubeMX Tool, + * Fast Mode @100kHz with I2CCLK = 64 MHz, + * rise time = 0ns, fall time = 0ns + */ +#define POWER_I2C_TIMINGS 0x10707DBC + +/* Input Keys */ +typedef enum { + InputKeyUp, + InputKeyDown, + InputKeyRight, + InputKeyLeft, + InputKeyOk, + InputKeyBack, +} InputKey; + +/* Light */ +typedef enum { + LightRed, + LightGreen, + LightBlue, + LightBacklight, +} Light; + +extern const GpioPin vibro_gpio; +extern const GpioPin ibutton_gpio; + +extern const GpioPin gpio_cc1101_g0; +extern const GpioPin gpio_rf_sw_0; + +extern const GpioPin gpio_subghz_cs; +extern const GpioPin gpio_display_cs; +extern const GpioPin gpio_display_rst; +extern const GpioPin gpio_display_di; +extern const GpioPin gpio_sdcard_cs; +extern const GpioPin gpio_nfc_cs; + +extern const GpioPin gpio_spi_d_miso; +extern const GpioPin gpio_spi_d_mosi; +extern const GpioPin gpio_spi_d_sck; +extern const GpioPin gpio_spi_r_miso; +extern const GpioPin gpio_spi_r_mosi; +extern const GpioPin gpio_spi_r_sck; + +extern const GpioPin gpio_ext_pc0; +extern const GpioPin gpio_ext_pc1; +extern const GpioPin gpio_ext_pc3; +extern const GpioPin gpio_ext_pb2; +extern const GpioPin gpio_ext_pb3; +extern const GpioPin gpio_ext_pa4; +extern const GpioPin gpio_ext_pa6; +extern const GpioPin gpio_ext_pa7; + +extern const GpioPin gpio_rfid_pull; +extern const GpioPin gpio_rfid_carrier_out; +extern const GpioPin gpio_rfid_data_in; + +extern const GpioPin gpio_irda_rx; +extern const GpioPin gpio_irda_tx; + +extern const GpioPin gpio_usart_tx; +extern const GpioPin gpio_usart_rx; + +#ifdef __cplusplus +} +#endif diff --git a/bootloader/targets/f7/furi-hal/furi-hal-spi-config.c b/bootloader/targets/f7/furi-hal/furi-hal-spi-config.c new file mode 100644 index 00000000..00b06a4f --- /dev/null +++ b/bootloader/targets/f7/furi-hal/furi-hal-spi-config.c @@ -0,0 +1,114 @@ +#include +#include + +#define SPI_R SPI1 +#define SPI_D SPI2 + +const LL_SPI_InitTypeDef furi_hal_spi_config_nfc = { + .Mode = LL_SPI_MODE_MASTER, + .TransferDirection = LL_SPI_FULL_DUPLEX, + .DataWidth = LL_SPI_DATAWIDTH_8BIT, + .ClockPolarity = LL_SPI_POLARITY_LOW, + .ClockPhase = LL_SPI_PHASE_2EDGE, + .NSS = LL_SPI_NSS_SOFT, + .BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV8, + .BitOrder = LL_SPI_MSB_FIRST, + .CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE, + .CRCPoly = 7, +}; + +const LL_SPI_InitTypeDef furi_hal_spi_config_subghz = { + .Mode = LL_SPI_MODE_MASTER, + .TransferDirection = LL_SPI_FULL_DUPLEX, + .DataWidth = LL_SPI_DATAWIDTH_8BIT, + .ClockPolarity = LL_SPI_POLARITY_LOW, + .ClockPhase = LL_SPI_PHASE_1EDGE, + .NSS = LL_SPI_NSS_SOFT, + .BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV8, + .BitOrder = LL_SPI_MSB_FIRST, + .CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE, + .CRCPoly = 7, +}; + +const LL_SPI_InitTypeDef furi_hal_spi_config_display = { + .Mode = LL_SPI_MODE_MASTER, + .TransferDirection = LL_SPI_FULL_DUPLEX, + .DataWidth = LL_SPI_DATAWIDTH_8BIT, + .ClockPolarity = LL_SPI_POLARITY_LOW, + .ClockPhase = LL_SPI_PHASE_1EDGE, + .NSS = LL_SPI_NSS_SOFT, + .BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV16, + .BitOrder = LL_SPI_MSB_FIRST, + .CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE, + .CRCPoly = 7, +}; + +/** + * SD Card in fast mode (after init) + */ +const LL_SPI_InitTypeDef furi_hal_spi_config_sd_fast = { + .Mode = LL_SPI_MODE_MASTER, + .TransferDirection = LL_SPI_FULL_DUPLEX, + .DataWidth = LL_SPI_DATAWIDTH_8BIT, + .ClockPolarity = LL_SPI_POLARITY_LOW, + .ClockPhase = LL_SPI_PHASE_1EDGE, + .NSS = LL_SPI_NSS_SOFT, + .BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV2, + .BitOrder = LL_SPI_MSB_FIRST, + .CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE, + .CRCPoly = 7, +}; + +/** + * SD Card in slow mode (before init) + */ +const LL_SPI_InitTypeDef furi_hal_spi_config_sd_slow = { + .Mode = LL_SPI_MODE_MASTER, + .TransferDirection = LL_SPI_FULL_DUPLEX, + .DataWidth = LL_SPI_DATAWIDTH_8BIT, + .ClockPolarity = LL_SPI_POLARITY_LOW, + .ClockPhase = LL_SPI_PHASE_1EDGE, + .NSS = LL_SPI_NSS_SOFT, + .BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV32, + .BitOrder = LL_SPI_MSB_FIRST, + .CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE, + .CRCPoly = 7, +}; + +const FuriHalSpiBus spi_r = { + .spi = SPI_R, + .miso = &gpio_spi_r_miso, + .mosi = &gpio_spi_r_mosi, + .clk = &gpio_spi_r_sck, +}; + +const FuriHalSpiBus spi_d = { + .spi = SPI_D, + .miso = &gpio_spi_d_miso, + .mosi = &gpio_spi_d_mosi, + .clk = &gpio_spi_d_sck, +}; + +const FuriHalSpiDevice furi_hal_spi_devices[FuriHalSpiDeviceIdMax] = { + { + .bus = &spi_r, + .config = &furi_hal_spi_config_subghz, + .chip_select = &gpio_subghz_cs, + }, + { + .bus = &spi_d, + .config = &furi_hal_spi_config_display, + .chip_select = &gpio_display_cs, + }, + { + .bus = &spi_d, + .config = &furi_hal_spi_config_sd_fast, + .chip_select = &gpio_sdcard_cs, + }, + { + .bus = &spi_d, + .config = &furi_hal_spi_config_sd_slow, + .chip_select = &gpio_sdcard_cs, + }, + {.bus = &spi_r, .config = &furi_hal_spi_config_nfc, .chip_select = &gpio_nfc_cs}, +}; diff --git a/bootloader/targets/f7/furi-hal/furi-hal-spi-config.h b/bootloader/targets/f7/furi-hal/furi-hal-spi-config.h new file mode 100644 index 00000000..dea1cd65 --- /dev/null +++ b/bootloader/targets/f7/furi-hal/furi-hal-spi-config.h @@ -0,0 +1,61 @@ +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern const LL_SPI_InitTypeDef furi_hal_spi_config_nfc; +extern const LL_SPI_InitTypeDef furi_hal_spi_config_subghz; +extern const LL_SPI_InitTypeDef furi_hal_spi_config_display; +extern const LL_SPI_InitTypeDef furi_hal_spi_config_sd_fast; +extern const LL_SPI_InitTypeDef furi_hal_spi_config_sd_slow; + +/** FURI HAL SPI BUS handler + * Structure content may change at some point + */ +typedef struct { + const SPI_TypeDef* spi; + const GpioPin* miso; + const GpioPin* mosi; + const GpioPin* clk; +} FuriHalSpiBus; + +/** FURI HAL SPI Device handler + * Structure content may change at some point + */ +typedef struct { + const FuriHalSpiBus* bus; + const LL_SPI_InitTypeDef* config; + const GpioPin* chip_select; +} FuriHalSpiDevice; + +/** FURI HAL SPI Standard Device IDs */ +typedef enum { + FuriHalSpiDeviceIdSubGhz, /** SubGhz: CC1101, non-standard SPI usage */ + FuriHalSpiDeviceIdDisplay, /** Display: ERC12864, only have MOSI */ + FuriHalSpiDeviceIdSdCardFast, /** SDCARD: fast mode, after initialization */ + FuriHalSpiDeviceIdSdCardSlow, /** SDCARD: slow mode, before initialization */ + FuriHalSpiDeviceIdNfc, /** NFC: ST25R3916, pretty standard, but RFAL makes it complex */ + + FuriHalSpiDeviceIdMax, /** Service Value, do not use */ +} FuriHalSpiDeviceId; + +/** Furi Hal Spi Bus R + * CC1101, Nfc + */ +extern const FuriHalSpiBus spi_r; + +/** Furi Hal Spi Bus D + * Display, SdCard + */ +extern const FuriHalSpiBus spi_d; + +/** Furi Hal Spi devices */ +extern const FuriHalSpiDevice furi_hal_spi_devices[FuriHalSpiDeviceIdMax]; + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/bootloader/targets/f7/furi-hal/furi-hal-spi.c b/bootloader/targets/f7/furi-hal/furi-hal-spi.c new file mode 100644 index 00000000..e36e9230 --- /dev/null +++ b/bootloader/targets/f7/furi-hal/furi-hal-spi.c @@ -0,0 +1,240 @@ +#include "furi-hal-spi.h" +#include "furi-hal-resources.h" + +#include +#include + +#include +#include +#include + +extern void Enable_SPI(SPI_TypeDef* spi); + +void furi_hal_spi_init() { + for(size_t i = 0; i < FuriHalSpiDeviceIdMax; ++i) { + hal_gpio_write(furi_hal_spi_devices[i].chip_select, true); + hal_gpio_init( + furi_hal_spi_devices[i].chip_select, + GpioModeOutputPushPull, + GpioPullNo, + GpioSpeedVeryHigh); + } + + hal_gpio_init_ex( + &gpio_spi_r_miso, + GpioModeAltFunctionPushPull, + GpioPullNo, + GpioSpeedVeryHigh, + GpioAltFn5SPI1); + hal_gpio_init_ex( + &gpio_spi_r_mosi, + GpioModeAltFunctionPushPull, + GpioPullNo, + GpioSpeedVeryHigh, + GpioAltFn5SPI1); + hal_gpio_init_ex( + &gpio_spi_r_sck, + GpioModeAltFunctionPushPull, + GpioPullNo, + GpioSpeedVeryHigh, + GpioAltFn5SPI1); + + hal_gpio_init_ex( + &gpio_spi_d_miso, + GpioModeAltFunctionPushPull, + GpioPullUp, + GpioSpeedVeryHigh, + GpioAltFn5SPI2); + hal_gpio_init_ex( + &gpio_spi_d_mosi, + GpioModeAltFunctionPushPull, + GpioPullUp, + GpioSpeedVeryHigh, + GpioAltFn5SPI2); + hal_gpio_init_ex( + &gpio_spi_d_sck, + GpioModeAltFunctionPushPull, + GpioPullUp, + GpioSpeedVeryHigh, + GpioAltFn5SPI2); +} + +void furi_hal_spi_bus_lock(const FuriHalSpiBus* bus) { + assert(bus); +} + +void furi_hal_spi_bus_unlock(const FuriHalSpiBus* bus) { + assert(bus); +} + +void furi_hal_spi_bus_configure(const FuriHalSpiBus* bus, const LL_SPI_InitTypeDef* config) { + assert(bus); + LL_SPI_DeInit((SPI_TypeDef*)bus->spi); + LL_SPI_Init((SPI_TypeDef*)bus->spi, (LL_SPI_InitTypeDef*)config); + LL_SPI_SetRxFIFOThreshold((SPI_TypeDef*)bus->spi, LL_SPI_RX_FIFO_TH_QUARTER); + LL_SPI_Enable((SPI_TypeDef*)bus->spi); +} + +void furi_hal_spi_bus_end_txrx(const FuriHalSpiBus* bus, uint32_t timeout) { + while(LL_SPI_GetTxFIFOLevel((SPI_TypeDef*)bus->spi) != LL_SPI_TX_FIFO_EMPTY) + ; + while(LL_SPI_IsActiveFlag_BSY((SPI_TypeDef*)bus->spi)) + ; + while(LL_SPI_GetRxFIFOLevel((SPI_TypeDef*)bus->spi) != LL_SPI_RX_FIFO_EMPTY) { + LL_SPI_ReceiveData8((SPI_TypeDef*)bus->spi); + } +} + +bool furi_hal_spi_bus_rx(const FuriHalSpiBus* bus, uint8_t* buffer, size_t size, uint32_t timeout) { + assert(bus); + assert(buffer); + assert(size > 0); + + return furi_hal_spi_bus_trx(bus, buffer, buffer, size, timeout); +} + +bool furi_hal_spi_bus_tx(const FuriHalSpiBus* bus, uint8_t* buffer, size_t size, uint32_t timeout) { + assert(bus); + assert(buffer); + assert(size > 0); + bool ret = true; + + while(size > 0) { + if(LL_SPI_IsActiveFlag_TXE((SPI_TypeDef*)bus->spi)) { + LL_SPI_TransmitData8((SPI_TypeDef*)bus->spi, *buffer); + buffer++; + size--; + } + } + + furi_hal_spi_bus_end_txrx(bus, timeout); + LL_SPI_ClearFlag_OVR((SPI_TypeDef*)bus->spi); + + return ret; +} + +bool furi_hal_spi_bus_trx( + const FuriHalSpiBus* bus, + uint8_t* tx_buffer, + uint8_t* rx_buffer, + size_t size, + uint32_t timeout) { + assert(bus); + assert(tx_buffer); + assert(rx_buffer); + assert(size > 0); + bool ret = true; + size_t tx_size = size; + bool tx_allowed = true; + + while(size > 0) { + if(tx_size > 0 && LL_SPI_IsActiveFlag_TXE((SPI_TypeDef*)bus->spi) && tx_allowed) { + LL_SPI_TransmitData8((SPI_TypeDef*)bus->spi, *tx_buffer); + tx_buffer++; + tx_size--; + tx_allowed = false; + } + + if(LL_SPI_IsActiveFlag_RXNE((SPI_TypeDef*)bus->spi)) { + *rx_buffer = LL_SPI_ReceiveData8((SPI_TypeDef*)bus->spi); + rx_buffer++; + size--; + tx_allowed = true; + } + } + + furi_hal_spi_bus_end_txrx(bus, timeout); + + return ret; +} + +void furi_hal_spi_device_configure(const FuriHalSpiDevice* device) { + assert(device); + assert(device->config); + + furi_hal_spi_bus_configure(device->bus, device->config); +} + +const FuriHalSpiDevice* furi_hal_spi_device_get(FuriHalSpiDeviceId device_id) { + assert(device_id < FuriHalSpiDeviceIdMax); + + const FuriHalSpiDevice* device = &furi_hal_spi_devices[device_id]; + assert(device); + + furi_hal_spi_bus_lock(device->bus); + furi_hal_spi_device_configure(device); + + return device; +} + +void furi_hal_spi_device_return(const FuriHalSpiDevice* device) { + furi_hal_spi_bus_unlock(device->bus); +} + +bool furi_hal_spi_device_rx( + const FuriHalSpiDevice* device, + uint8_t* buffer, + size_t size, + uint32_t timeout) { + assert(device); + assert(buffer); + assert(size > 0); + + if(device->chip_select) { + hal_gpio_write(device->chip_select, false); + } + + bool ret = furi_hal_spi_bus_rx(device->bus, buffer, size, timeout); + + if(device->chip_select) { + hal_gpio_write(device->chip_select, true); + } + + return ret; +} + +bool furi_hal_spi_device_tx( + const FuriHalSpiDevice* device, + uint8_t* buffer, + size_t size, + uint32_t timeout) { + assert(device); + assert(buffer); + assert(size > 0); + + if(device->chip_select) { + hal_gpio_write(device->chip_select, false); + } + + bool ret = furi_hal_spi_bus_tx(device->bus, buffer, size, timeout); + + if(device->chip_select) { + hal_gpio_write(device->chip_select, true); + } + + return ret; +} + +bool furi_hal_spi_device_trx( + const FuriHalSpiDevice* device, + uint8_t* tx_buffer, + uint8_t* rx_buffer, + size_t size, + uint32_t timeout) { + assert(device); + assert(tx_buffer); + assert(rx_buffer); + assert(size > 0); + + if(device->chip_select) { + hal_gpio_write(device->chip_select, false); + } + + bool ret = furi_hal_spi_bus_trx(device->bus, tx_buffer, rx_buffer, size, timeout); + + if(device->chip_select) { + hal_gpio_write(device->chip_select, true); + } + + return ret; +} diff --git a/bootloader/targets/f7/furi-hal/furi-hal-spi.h b/bootloader/targets/f7/furi-hal/furi-hal-spi.h new file mode 100644 index 00000000..8027eb5d --- /dev/null +++ b/bootloader/targets/f7/furi-hal/furi-hal-spi.h @@ -0,0 +1,129 @@ +#pragma once + +#include "main.h" + +#include "furi-hal-spi-config.h" +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Init SPI API + */ +void furi_hal_spi_init(); + +/* Bus Level API */ + +/** Lock SPI bus + * Takes bus mutex, if used + */ +void furi_hal_spi_bus_lock(const FuriHalSpiBus* bus); + +/** Unlock SPI bus + * Releases BUS mutex, if used + */ +void furi_hal_spi_bus_unlock(const FuriHalSpiBus* bus); + +/** + * Configure SPI bus + * @param bus - spi bus handler + * @param config - spi configuration structure + */ +void furi_hal_spi_bus_configure(const FuriHalSpiBus* bus, const LL_SPI_InitTypeDef* config); + +/** SPI Receive + * @param bus - spi bus handler + * @param buffer - receive buffer + * @param size - transaction size + * @param timeout - bus operation timeout in ms + */ +bool furi_hal_spi_bus_rx(const FuriHalSpiBus* bus, uint8_t* buffer, size_t size, uint32_t timeout); + +/** SPI Transmit + * @param bus - spi bus handler + * @param buffer - transmit buffer + * @param size - transaction size + * @param timeout - bus operation timeout in ms + */ +bool furi_hal_spi_bus_tx(const FuriHalSpiBus* bus, uint8_t* buffer, size_t size, uint32_t timeout); + +/** SPI Transmit and Receive + * @param bus - spi bus handlere + * @param tx_buffer - device handle + * @param rx_buffer - device handle + * @param size - transaction size + * @param timeout - bus operation timeout in ms + */ +bool furi_hal_spi_bus_trx( + const FuriHalSpiBus* bus, + uint8_t* tx_buffer, + uint8_t* rx_buffer, + size_t size, + uint32_t timeout); + +/* Device Level API */ + +/** Reconfigure SPI bus for device + * @param device - device description + */ +void furi_hal_spi_device_configure(const FuriHalSpiDevice* device); + +/** Get Device handle + * And lock access to the corresponding SPI BUS + * @param device_id - device identifier + * @return device handle + */ +const FuriHalSpiDevice* furi_hal_spi_device_get(FuriHalSpiDeviceId device_id); + +/** Return Device handle + * And unlock access to the corresponding SPI BUS + * @param device - device handle + */ +void furi_hal_spi_device_return(const FuriHalSpiDevice* device); + +/** SPI Recieve + * @param device - device handle + * @param buffer - receive buffer + * @param size - transaction size + * @param timeout - bus operation timeout in ms + */ +bool furi_hal_spi_device_rx( + const FuriHalSpiDevice* device, + uint8_t* buffer, + size_t size, + uint32_t timeout); + +/** SPI Transmit + * @param device - device handle + * @param buffer - transmit buffer + * @param size - transaction size + * @param timeout - bus operation timeout in ms + */ +bool furi_hal_spi_device_tx( + const FuriHalSpiDevice* device, + uint8_t* buffer, + size_t size, + uint32_t timeout); + +/** SPI Transmit and Receive + * @param device - device handle + * @param tx_buffer - device handle + * @param rx_buffer - device handle + * @param size - transaction size + * @param timeout - bus operation timeout in ms + */ +bool furi_hal_spi_device_trx( + const FuriHalSpiDevice* device, + uint8_t* tx_buffer, + uint8_t* rx_buffer, + size_t size, + uint32_t timeout); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/bootloader/targets/f7/furi-hal/furi-hal.c b/bootloader/targets/f7/furi-hal/furi-hal.c new file mode 100644 index 00000000..e0521cc9 --- /dev/null +++ b/bootloader/targets/f7/furi-hal/furi-hal.c @@ -0,0 +1,7 @@ +#include + +void furi_hal_init() { + furi_hal_i2c_init(); + furi_hal_light_init(); + furi_hal_spi_init(); +} \ No newline at end of file diff --git a/bootloader/targets/f7/furi-hal/furi-hal.h b/bootloader/targets/f7/furi-hal/furi-hal.h new file mode 100644 index 00000000..9e60092f --- /dev/null +++ b/bootloader/targets/f7/furi-hal/furi-hal.h @@ -0,0 +1,8 @@ +#pragma once + +#include +#include +#include +#include + +void furi_hal_init(); \ No newline at end of file diff --git a/bootloader/targets/f7/furi-hal/main.h b/bootloader/targets/f7/furi-hal/main.h new file mode 100644 index 00000000..1c453c57 --- /dev/null +++ b/bootloader/targets/f7/furi-hal/main.h @@ -0,0 +1,108 @@ +#pragma once + +#include +#include +#include + +#define BUTTON_BACK_GPIO_Port GPIOC +#define BUTTON_BACK_Pin LL_GPIO_PIN_13 +#define BUTTON_DOWN_GPIO_Port GPIOC +#define BUTTON_DOWN_Pin LL_GPIO_PIN_6 +#define BUTTON_LEFT_GPIO_Port GPIOB +#define BUTTON_LEFT_Pin LL_GPIO_PIN_11 +#define BUTTON_OK_GPIO_Port GPIOH +#define BUTTON_OK_Pin LL_GPIO_PIN_3 +#define BUTTON_RIGHT_GPIO_Port GPIOB +#define BUTTON_RIGHT_Pin LL_GPIO_PIN_12 +#define BUTTON_UP_GPIO_Port GPIOB +#define BUTTON_UP_Pin LL_GPIO_PIN_10 + +#define CC1101_CS_GPIO_Port GPIOD +#define CC1101_CS_Pin LL_GPIO_PIN_0 +#define CC1101_G0_GPIO_Port GPIOA +#define CC1101_G0_Pin LL_GPIO_PIN_1 + +#define DISPLAY_CS_GPIO_Port GPIOC +#define DISPLAY_CS_Pin LL_GPIO_PIN_11 +#define DISPLAY_DI_GPIO_Port GPIOB +#define DISPLAY_DI_Pin LL_GPIO_PIN_1 +#define DISPLAY_RST_GPIO_Port GPIOB +#define DISPLAY_RST_Pin LL_GPIO_PIN_0 + +#define IR_RX_GPIO_Port GPIOA +#define IR_RX_Pin LL_GPIO_PIN_0 +#define IR_TX_GPIO_Port GPIOB +#define IR_TX_Pin LL_GPIO_PIN_9 + +#define NFC_CS_GPIO_Port GPIOE +#define NFC_CS_Pin LL_GPIO_PIN_4 + +#define PA4_GPIO_Port GPIOA +#define PA4_Pin LL_GPIO_PIN_4 +#define PA6_GPIO_Port GPIOA +#define PA6_Pin LL_GPIO_PIN_6 +#define PA7_GPIO_Port GPIOA +#define PA7_Pin LL_GPIO_PIN_7 +#define PB2_GPIO_Port GPIOB +#define PB2_Pin LL_GPIO_PIN_2 +#define PB3_GPIO_Port GPIOB +#define PB3_Pin LL_GPIO_PIN_3 +#define PC0_GPIO_Port GPIOC +#define PC0_Pin LL_GPIO_PIN_0 +#define PC1_GPIO_Port GPIOC +#define PC1_Pin LL_GPIO_PIN_1 +#define PC3_GPIO_Port GPIOC +#define PC3_Pin LL_GPIO_PIN_3 + +#define PERIPH_POWER_GPIO_Port GPIOA +#define PERIPH_POWER_Pin LL_GPIO_PIN_3 + +#define QUARTZ_32MHZ_IN_GPIO_Port GPIOC +#define QUARTZ_32MHZ_IN_Pin LL_GPIO_PIN_14 +#define QUARTZ_32MHZ_OUT_GPIO_Port GPIOC +#define QUARTZ_32MHZ_OUT_Pin LL_GPIO_PIN_15 + +#define RFID_OUT_GPIO_Port GPIOB +#define RFID_OUT_Pin LL_GPIO_PIN_13 +#define RFID_PULL_GPIO_Port GPIOA +#define RFID_PULL_Pin LL_GPIO_PIN_2 +#define RFID_RF_IN_GPIO_Port GPIOC +#define RFID_RF_IN_Pin LL_GPIO_PIN_5 +#define RFID_TUNE_GPIO_Port GPIOA +#define RFID_TUNE_Pin LL_GPIO_PIN_8 + +#define RF_SW_0_GPIO_Port GPIOC +#define RF_SW_0_Pin LL_GPIO_PIN_4 + +#define SD_CD_GPIO_Port GPIOC +#define SD_CD_Pin LL_GPIO_PIN_10 +#define SD_CS_GPIO_Port GPIOC +#define SD_CS_Pin LL_GPIO_PIN_12 + +#define SPEAKER_GPIO_Port GPIOB +#define SPEAKER_Pin LL_GPIO_PIN_8 + +#define VIBRO_GPIO_Port GPIOA +#define VIBRO_Pin LL_GPIO_PIN_15 + +#define iBTN_GPIO_Port GPIOB +#define iBTN_Pin LL_GPIO_PIN_14 + +#define USART1_TX_Pin LL_GPIO_PIN_6 +#define USART1_TX_Port GPIOB +#define USART1_RX_Pin LL_GPIO_PIN_7 +#define USART1_RX_Port GPIOB + +#define SPI_D_MISO_GPIO_Port GPIOC +#define SPI_D_MISO_Pin LL_GPIO_PIN_2 +#define SPI_D_MOSI_GPIO_Port GPIOB +#define SPI_D_MOSI_Pin LL_GPIO_PIN_15 +#define SPI_D_SCK_GPIO_Port GPIOD +#define SPI_D_SCK_Pin LL_GPIO_PIN_1 + +#define SPI_R_MISO_GPIO_Port GPIOB +#define SPI_R_MISO_Pin LL_GPIO_PIN_4 +#define SPI_R_MOSI_GPIO_Port GPIOB +#define SPI_R_MOSI_Pin LL_GPIO_PIN_5 +#define SPI_R_SCK_GPIO_Port GPIOA +#define SPI_R_SCK_Pin LL_GPIO_PIN_5 diff --git a/bootloader/targets/f7/furi-hal/u8g2_periphery.c b/bootloader/targets/f7/furi-hal/u8g2_periphery.c new file mode 100644 index 00000000..a1c153f7 --- /dev/null +++ b/bootloader/targets/f7/furi-hal/u8g2_periphery.c @@ -0,0 +1,69 @@ +#include +#include +#include +#include + +static FuriHalSpiDevice* u8g2_periphery_display = NULL; + +uint8_t u8g2_gpio_and_delay_stm32(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* arg_ptr) { + switch(msg) { + case U8X8_MSG_GPIO_AND_DELAY_INIT: + /* HAL initialization contains all what we need so we can skip this part. */ + break; + + case U8X8_MSG_DELAY_MILLI: + LL_mDelay(arg_int); + break; + + case U8X8_MSG_DELAY_10MICRO: + LL_mDelay(1); + break; + + case U8X8_MSG_DELAY_100NANO: + asm("nop"); + break; + + case U8X8_MSG_GPIO_RESET: + hal_gpio_write(&gpio_display_rst, arg_int); + break; + + default: + return 0; + } + + return 1; +} + +uint8_t u8x8_hw_spi_stm32(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* arg_ptr) { + switch(msg) { + case U8X8_MSG_BYTE_SEND: + furi_hal_spi_bus_tx(u8g2_periphery_display->bus, (uint8_t*)arg_ptr, arg_int, 10000); + break; + + case U8X8_MSG_BYTE_SET_DC: + hal_gpio_write(&gpio_display_di, arg_int); + break; + + case U8X8_MSG_BYTE_INIT: + break; + + case U8X8_MSG_BYTE_START_TRANSFER: + assert(u8g2_periphery_display == NULL); + u8g2_periphery_display = + (FuriHalSpiDevice*)furi_hal_spi_device_get(FuriHalSpiDeviceIdDisplay); + hal_gpio_write(u8g2_periphery_display->chip_select, false); + break; + + case U8X8_MSG_BYTE_END_TRANSFER: + assert(u8g2_periphery_display); + hal_gpio_write(u8g2_periphery_display->chip_select, true); + furi_hal_spi_device_return(u8g2_periphery_display); + u8g2_periphery_display = NULL; + break; + + default: + return 0; + } + + return 1; +} diff --git a/bootloader/targets/f7/stm32wb55xx_flash_cm4.ld b/bootloader/targets/f7/stm32wb55xx_flash_cm4.ld new file mode 100644 index 00000000..41d36b11 --- /dev/null +++ b/bootloader/targets/f7/stm32wb55xx_flash_cm4.ld @@ -0,0 +1,187 @@ +/** +***************************************************************************** +** +** File : stm32wb55xx_flash_cm4.ld +** +** Abstract : System Workbench Minimal System calls file +** +** For more information about which c-functions +** need which of these lowlevel functions +** please consult the Newlib libc-manual +** +** Environment : System Workbench for MCU +** +** Distribution: The file is distributed “as is,” without any warranty +** of any kind. +** +***************************************************************************** +** +**

© COPYRIGHT(c) 2019 Ac6

+** +** Redistribution and use in source and binary forms, with or without modification, +** are permitted provided that the following conditions are met: +** 1. Redistributions of source code must retain the above copyright notice, +** this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright notice, +** this list of conditions and the following disclaimer in the documentation +** and/or other materials provided with the distribution. +** 3. Neither the name of Ac6 nor the names of its contributors +** may be used to endorse or promote products derived from this software +** without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +** +***************************************************************************** +*/ + +/* Entry Point */ +ENTRY(Reset_Handler) + +/* Highest address of the user mode stack */ +_estack = 0x20030000; /* end of RAM */ +/* Generate a link error if heap and stack don't fit into RAM */ +_Min_Heap_Size = 0x200; /* required amount of heap */ +_Min_Stack_Size = 0x400; /* required amount of stack */ + +/* Specify the memory areas */ +MEMORY +{ +FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 32K +RAM1 (xrw) : ORIGIN = 0x20000004, LENGTH = 0x2FFFC +RAM_SHARED (xrw) : ORIGIN = 0x20030000, LENGTH = 10K +} + +/* Define output sections */ +SECTIONS +{ + /* The startup code goes first into FLASH */ + .isr_vector : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) /* Startup code */ + . = ALIGN(4); + } >FLASH + + /* The program code and other data goes into FLASH */ + .text : + { + . = ALIGN(4); + *(.text) /* .text sections (code) */ + *(.text*) /* .text* sections (code) */ + *(.glue_7) /* glue arm to thumb code */ + *(.glue_7t) /* glue thumb to arm code */ + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + . = ALIGN(4); + _etext = .; /* define a global symbols at end of code */ + } >FLASH + + /* Constant data goes into FLASH */ + .rodata : + { + . = ALIGN(4); + *(.rodata) /* .rodata sections (constants, strings, etc.) */ + *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ + . = ALIGN(4); + } >FLASH + + .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH + .ARM : { + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + } >FLASH + + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array*)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } >FLASH + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array*)) + PROVIDE_HIDDEN (__init_array_end = .); + } >FLASH + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT(.fini_array.*))) + KEEP (*(.fini_array*)) + PROVIDE_HIDDEN (__fini_array_end = .); + } >FLASH + + /* used by the startup to initialize data */ + _sidata = LOADADDR(.data); + + /* Initialized data sections goes into RAM, load LMA copy after code */ + .data : + { + . = ALIGN(4); + _sdata = .; /* create a global symbol at data start */ + *(.data) /* .data sections */ + *(.data*) /* .data* sections */ + + . = ALIGN(4); + _edata = .; /* define a global symbol at data end */ + } >RAM1 AT> FLASH + + + /* Uninitialized data section */ + . = ALIGN(4); + .bss : + { + /* This is used by the startup in order to initialize the .bss secion */ + _sbss = .; /* define a global symbol at bss start */ + __bss_start__ = _sbss; + *(.bss) + *(.bss*) + *(COMMON) + + . = ALIGN(4); + _ebss = .; /* define a global symbol at bss end */ + __bss_end__ = _ebss; + } >RAM1 + + /* User_heap_stack section, used to check that there is enough RAM left */ + ._user_heap_stack : + { + . = ALIGN(8); + PROVIDE ( end = . ); + PROVIDE ( _end = . ); + . = . + _Min_Heap_Size; + . = . + _Min_Stack_Size; + . = ALIGN(8); + } >RAM1 + + + + /* Remove information from the standard libraries */ + /DISCARD/ : + { + libc.a ( * ) + libm.a ( * ) + libgcc.a ( * ) + } + + .ARM.attributes 0 : { *(.ARM.attributes) } + MAPPING_TABLE (NOLOAD) : { *(MAPPING_TABLE) } >RAM_SHARED + MB_MEM1 (NOLOAD) : { *(MB_MEM1) } >RAM_SHARED + MB_MEM2 (NOLOAD) : { _sMB_MEM2 = . ; *(MB_MEM2) ; _eMB_MEM2 = . ; } >RAM_SHARED +} + + diff --git a/bootloader/targets/f7/target.c b/bootloader/targets/f7/target.c new file mode 100644 index 00000000..da1d6397 --- /dev/null +++ b/bootloader/targets/f7/target.c @@ -0,0 +1,264 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +const uint8_t I_DFU_128x50[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0xC0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8F, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x7F, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x75, 0x00, 0x00, 0xF0, 0x3F, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x0A, 0x00, 0x00, 0x0F, 0x60, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xE0, 0x0F, 0x00, 0xC0, 0xE0, 0x4F, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x18, 0x00, 0x30, 0x1E, 0x90, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x18, 0x00, 0x8C, 0x01, 0xA0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x81, 0xFF, 0x19, 0x00, 0x63, 0x00, 0xC0, 0xF0, 0x07, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x60, 0x5E, 0x1F, 0x80, 0x18, 0x00, 0xE0, 0x0E, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x18, 0xAF, 0x0F, 0x40, 0x06, 0x00, 0xF8, 0x01, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x06, 0x57, 0x01, 0x20, 0x01, 0x00, 0x78, 0x00, 0x3E, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x81, 0xAF, 0x02, 0x90, 0x00, 0x00, 0x38, 0x80, 0x41, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x80, 0x57, 0x01, 0x48, 0x00, 0x00, 0x10, 0x60, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x10, 0x80, 0xAB, 0x00, 0x24, 0x00, 0x00, 0x08, 0x10, 0x40, + 0x3F, 0x00, 0x00, 0x00, 0x00, 0x38, 0x0C, 0xC0, 0x57, 0x01, 0x12, 0x00, 0x00, 0x04, 0x08, 0x40, + 0xC0, 0x0F, 0x00, 0x00, 0xC0, 0x07, 0x03, 0xF0, 0xAB, 0x00, 0x0A, 0x00, 0x00, 0x02, 0x04, 0x40, + 0x00, 0xF0, 0x1F, 0x80, 0x3F, 0xC0, 0x00, 0xFC, 0x55, 0x01, 0x05, 0xE0, 0x00, 0x01, 0x04, 0x40, + 0x00, 0x00, 0xE0, 0x7F, 0x00, 0x30, 0x00, 0xFF, 0xAB, 0x00, 0x05, 0xE0, 0x80, 0x00, 0x02, 0x40, + 0x0F, 0x00, 0x00, 0x00, 0x80, 0x0F, 0xE0, 0xCF, 0x55, 0x81, 0x02, 0xF0, 0x40, 0x00, 0x02, 0x40, + 0xF0, 0x0F, 0x00, 0x00, 0x7F, 0x00, 0xFE, 0xC3, 0xAB, 0x80, 0x02, 0x78, 0x20, 0x00, 0x01, 0x40, + 0x00, 0xF0, 0xFF, 0xFF, 0x00, 0xF0, 0xFF, 0xC0, 0xD5, 0x81, 0x01, 0x7E, 0x10, 0x80, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0x0F, 0xE0, 0xFA, 0x83, 0xC1, 0x3F, 0x08, 0x80, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x01, 0xD8, 0x07, 0x83, 0xF1, 0x1F, 0x04, 0x40, 0x00, 0x20, + 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0x0F, 0x80, 0xC7, 0x01, 0x83, 0xF1, 0x0F, 0x00, 0x20, 0x00, 0x10, + 0xE0, 0xFF, 0xFF, 0xFF, 0x3F, 0xC0, 0x7F, 0x40, 0x80, 0x83, 0xE1, 0x01, 0x00, 0x20, 0x00, 0x18, + 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x3F, 0x00, 0x20, 0xFC, 0x83, 0x01, 0x00, 0x00, 0x10, 0x00, 0x18, + 0xFF, 0xFF, 0xFF, 0x3F, 0xF0, 0x00, 0x00, 0x10, 0xD7, 0x01, 0x03, 0x00, 0x00, 0x08, 0x00, 0x1C, + 0xFF, 0xFF, 0x01, 0x00, 0x0F, 0x00, 0x00, 0x88, 0xAB, 0x02, 0xE3, 0x01, 0x00, 0x08, 0x00, 0x0C, + 0xFF, 0x07, 0x00, 0xE0, 0x00, 0x00, 0x00, 0xC4, 0x55, 0x05, 0x1E, 0x00, 0x00, 0x04, 0x00, 0x0E, + 0x7F, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0xA3, 0xAB, 0x02, 0x06, 0x00, 0x00, 0x02, 0x00, 0x0F, + 0x0F, 0x00, 0x80, 0x03, 0x00, 0x00, 0xC0, 0x10, 0x57, 0x05, 0x02, 0x00, 0x00, 0x01, 0x80, 0x07, + 0x03, 0x00, 0x70, 0x00, 0x00, 0x00, 0x30, 0x08, 0xAB, 0x0A, 0x02, 0x00, 0xC0, 0x00, 0xC0, 0x07, + 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0C, 0x84, 0x57, 0x15, 0x01, 0x00, 0x30, 0x00, 0xE0, 0x07, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0xC3, 0xFF, 0x2A, 0x01, 0x00, 0x0C, 0x00, 0xF0, 0x0F, + 0x00, 0xC0, 0x00, 0x00, 0x00, 0xE0, 0xC0, 0xE0, 0xFE, 0x55, 0x01, 0x82, 0x03, 0x00, 0xF8, 0x15, + 0x00, 0x30, 0x00, 0x00, 0x00, 0x1C, 0x30, 0x78, 0xFE, 0xAA, 0x01, 0x7C, 0x00, 0x00, 0xFC, 0x23, + 0x00, 0x0E, 0x00, 0x00, 0xC0, 0x03, 0x0C, 0x3C, 0x7F, 0x5D, 0x01, 0x00, 0x00, 0x00, 0xFF, 0x45, + 0xC0, 0x01, 0x00, 0x00, 0x3E, 0x00, 0x02, 0x8F, 0xBF, 0xAE, 0x03, 0x00, 0x00, 0xC0, 0xFF, 0x82, + 0x30, 0x00, 0x00, 0xC0, 0x01, 0x80, 0xC1, 0x43, 0xFE, 0x5D, 0x01, 0x00, 0x00, 0xF0, 0xFF, 0x05, + 0x0F, 0x00, 0x80, 0x3F, 0x00, 0x60, 0xF0, 0x31, 0xF6, 0xAE, 0x03, 0x00, 0x00, 0xFA, 0xAF, 0x02, + 0xFC, 0xFF, 0x7F, 0x00, 0x00, 0x18, 0x7C, 0x08, 0x23, 0xFF, 0x05, 0x00, 0x00, 0xFD, 0x55, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0x1F, 0x84, 0x30, 0xFE, 0x0A, 0x00, 0x00, 0xAA, 0xAA, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0xF1, 0x07, 0x43, 0x18, 0xFF, 0x15, 0x00, 0x00, 0x54, 0x15, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x80, 0x20, 0x8C, 0xFF, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +// Boot request enum +#define BOOT_REQUEST_TAINTED 0x00000000 +#define BOOT_REQUEST_CLEAN 0xDADEDADE +#define BOOT_REQUEST_DFU 0xDF00B000 +// Boot to DFU pin +#define BOOT_DFU_PORT GPIOB +#define BOOT_DFU_PIN LL_GPIO_PIN_11 +// USB pins +#define BOOT_USB_PORT GPIOA +#define BOOT_USB_DM_PIN LL_GPIO_PIN_11 +#define BOOT_USB_DP_PIN LL_GPIO_PIN_12 +#define BOOT_USB_PIN (BOOT_USB_DM_PIN | BOOT_USB_DP_PIN) + +#define RTC_CLOCK_IS_READY() (LL_RCC_LSE_IsReady() && LL_RCC_LSI1_IsReady()) + +uint8_t u8g2_gpio_and_delay_stm32(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* arg_ptr); +uint8_t u8x8_hw_spi_stm32(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* arg_ptr); + +void target_led_control(char* c) { + furi_hal_light_set(LightRed, 0x00); + furi_hal_light_set(LightGreen, 0x00); + furi_hal_light_set(LightBlue, 0x00); + do { + if(*c == 'R') { + furi_hal_light_set(LightRed, 0xFF); + } else if(*c == 'G') { + furi_hal_light_set(LightGreen, 0xFF); + } else if(*c == 'B') { + furi_hal_light_set(LightBlue, 0xFF); + } else if(*c == '.') { + LL_mDelay(125); + furi_hal_light_set(LightRed, 0x00); + furi_hal_light_set(LightGreen, 0x00); + furi_hal_light_set(LightBlue, 0x00); + LL_mDelay(125); + } else if(*c == '-') { + LL_mDelay(250); + furi_hal_light_set(LightRed, 0x00); + furi_hal_light_set(LightGreen, 0x00); + furi_hal_light_set(LightBlue, 0x00); + LL_mDelay(250); + } else if(*c == '|') { + furi_hal_light_set(LightRed, 0x00); + furi_hal_light_set(LightGreen, 0x00); + furi_hal_light_set(LightBlue, 0x00); + } + c++; + } while(*c != 0); +} + +void target_clock_init() { + LL_Init1msTick(4000000); + LL_SetSystemCoreClock(4000000); + + LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA); + LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB); + LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOC); + LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOD); + LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOE); + LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOH); + + LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SPI1); + LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_SPI2); +} + +void target_gpio_init() { + // USB D+ + LL_GPIO_SetPinMode(BOOT_USB_PORT, BOOT_USB_DP_PIN, LL_GPIO_MODE_OUTPUT); + LL_GPIO_SetPinSpeed(BOOT_USB_PORT, BOOT_USB_DP_PIN, LL_GPIO_SPEED_FREQ_VERY_HIGH); + LL_GPIO_SetPinOutputType(BOOT_USB_PORT, BOOT_USB_DP_PIN, LL_GPIO_OUTPUT_OPENDRAIN); + // USB D- + LL_GPIO_SetPinMode(BOOT_USB_PORT, BOOT_USB_DM_PIN, LL_GPIO_MODE_OUTPUT); + LL_GPIO_SetPinSpeed(BOOT_USB_PORT, BOOT_USB_DM_PIN, LL_GPIO_SPEED_FREQ_VERY_HIGH); + LL_GPIO_SetPinOutputType(BOOT_USB_PORT, BOOT_USB_DM_PIN, LL_GPIO_OUTPUT_OPENDRAIN); + // Button: back + LL_GPIO_SetPinMode(BOOT_DFU_PORT, BOOT_DFU_PIN, LL_GPIO_MODE_INPUT); + LL_GPIO_SetPinPull(BOOT_DFU_PORT, BOOT_DFU_PIN, LL_GPIO_PULL_UP); +} + +void target_rtc_init() { + // LSE and RTC + LL_PWR_EnableBkUpAccess(); + if(!RTC_CLOCK_IS_READY()) { + // Start LSI1 needed for CSS + LL_RCC_LSI1_Enable(); + // Try to start LSE normal way + LL_RCC_LSE_SetDriveCapability(LL_RCC_LSEDRIVE_HIGH); + LL_RCC_LSE_Enable(); + uint32_t c = 0; + while(!RTC_CLOCK_IS_READY() && c < 200) { + LL_mDelay(10); + c++; + } + // Plan B: reset backup domain + if(!RTC_CLOCK_IS_READY()) { + target_led_control("-R.R.R."); + LL_RCC_ForceBackupDomainReset(); + LL_RCC_ReleaseBackupDomainReset(); + NVIC_SystemReset(); + } + // Set RTC domain clock to LSE + LL_RCC_SetRTCClockSource(LL_RCC_RTC_CLKSOURCE_LSE); + // Enable LSE CSS + LL_RCC_LSE_EnableCSS(); + } + // Enable clocking + LL_RCC_EnableRTC(); + LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_RTCAPB); +} + +void target_version_save(void) { + LL_RTC_BAK_SetRegister(RTC, LL_RTC_BKP_DR1, (uint32_t)version_get()); +} + +void target_usb_wire_reset() { + LL_GPIO_ResetOutputPin(BOOT_USB_PORT, BOOT_USB_PIN); +} + +void target_display_init() { + // Prepare gpio + hal_gpio_init_simple(&gpio_display_rst, GpioModeOutputPushPull); + hal_gpio_init_simple(&gpio_display_di, GpioModeOutputPushPull); + // Initialize + u8g2_t fb; + u8g2_Setup_st7565_erc12864_alt_f(&fb, U8G2_R0, u8x8_hw_spi_stm32, u8g2_gpio_and_delay_stm32); + u8g2_InitDisplay(&fb); + u8g2_SetContrast(&fb, 36); + // Create payload + u8g2_ClearBuffer(&fb); + u8g2_SetDrawColor(&fb, 0x01); + u8g2_SetFont(&fb, u8g2_font_helvB08_tf); + u8g2_DrawXBM(&fb, 0, 64 - 50, 128, 50, I_DFU_128x50); + u8g2_DrawStr(&fb, 2, 8, "Update & Recovery Mode"); + u8g2_DrawStr(&fb, 2, 21, "DFU started"); + // Send buffer + u8g2_SetPowerSave(&fb, 0); + u8g2_SendBuffer(&fb); +} + +void target_init() { + target_clock_init(); + target_gpio_init(); + furi_hal_init(); + target_led_control("RGB"); + target_rtc_init(); + target_version_save(); + target_usb_wire_reset(); + + // Errata 2.2.9, Flash OPTVERR flag is always set after system reset + __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS); +} + +int target_is_dfu_requested() { + if(LL_RTC_BAK_GetRegister(RTC, LL_RTC_BKP_DR0) == BOOT_REQUEST_TAINTED) { + // Default system state is tainted + // We must ensure that MCU is cleanly booted + LL_RTC_BAK_SetRegister(RTC, LL_RTC_BKP_DR0, BOOT_REQUEST_CLEAN); + NVIC_SystemReset(); + } else if(LL_RTC_BAK_GetRegister(RTC, LL_RTC_BKP_DR0) == BOOT_REQUEST_DFU) { + return 1; + } + LL_mDelay(100); + if(!LL_GPIO_IsInputPinSet(BOOT_DFU_PORT, BOOT_DFU_PIN)) { + return 1; + } + + return 0; +} + +void target_switch(void* offset) { + asm volatile("ldr r3, [%0] \n" + "msr msp, r3 \n" + "ldr r3, [%1] \n" + "mov pc, r3 \n" + : + : "r"(offset), "r"(offset + 0x4) + : "r3"); +} + +void target_switch2dfu() { + target_led_control("B"); + furi_hal_light_set(LightBacklight, 0xFF); + target_display_init(); + // Mark system as tainted, it will be soon + LL_RTC_BAK_SetRegister(RTC, LL_RTC_BKP_DR0, BOOT_REQUEST_TAINTED); + // Remap memory to system bootloader + LL_SYSCFG_SetRemapMemory(LL_SYSCFG_REMAP_SYSTEMFLASH); + // Jump + target_switch(0x0); +} + +void target_switch2os() { + target_led_control("G"); + SCB->VTOR = OS_OFFSET; + target_switch((void*)(BOOT_ADDRESS + OS_OFFSET)); +} diff --git a/bootloader/targets/f7/target.mk b/bootloader/targets/f7/target.mk new file mode 100644 index 00000000..e6430585 --- /dev/null +++ b/bootloader/targets/f7/target.mk @@ -0,0 +1,48 @@ +TOOLCHAIN = arm + +BOOT_ADDRESS = 0x08000000 +FW_ADDRESS = 0x08008000 +OS_OFFSET = 0x00008000 +FLASH_ADDRESS = 0x08000000 + +OPENOCD_OPTS = -f interface/stlink.cfg -c "transport select hla_swd" -f ../debug/stm32wbx.cfg -c "init" +BOOT_CFLAGS = -DBOOT_ADDRESS=$(BOOT_ADDRESS) -DFW_ADDRESS=$(FW_ADDRESS) -DOS_OFFSET=$(OS_OFFSET) +MCU_FLAGS = -mcpu=cortex-m4 -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard + +CFLAGS += $(MCU_FLAGS) $(BOOT_CFLAGS) -DSTM32WB55xx -Wall -fdata-sections -ffunction-sections +LDFLAGS += $(MCU_FLAGS) -specs=nosys.specs -specs=nano.specs + +CUBE_DIR = $(PROJECT_ROOT)/lib/STM32CubeWB + +# ST HAL +CFLAGS += -DUSE_FULL_LL_DRIVER +ASM_SOURCES += $(CUBE_DIR)/Drivers/CMSIS/Device/ST/STM32WBxx/Source/Templates/gcc/startup_stm32wb55xx_cm4.s +C_SOURCES += $(CUBE_DIR)/Drivers/CMSIS/Device/ST/STM32WBxx/Source/Templates/system_stm32wbxx.c +C_SOURCES += $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_utils.c +C_SOURCES += $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_gpio.c +C_SOURCES += $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_i2c.c +C_SOURCES += $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_spi.c + +CFLAGS += -I$(CUBE_DIR)/Drivers/CMSIS/Include +CFLAGS += -I$(CUBE_DIR)/Drivers/CMSIS/Device/ST/STM32WBxx/Include +CFLAGS += -I$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Inc + +LDFLAGS += -T$(TARGET_DIR)/stm32wb55xx_flash_cm4.ld + +# Drivers +DRIVERS_DIR = $(PROJECT_ROOT)//lib/drivers +CFLAGS += -I$(DRIVERS_DIR) +C_SOURCES += $(DRIVERS_DIR)/lp5562.c + +# API-HAL +CFLAGS += -I$(TARGET_DIR)/furi-hal +C_SOURCES += $(wildcard $(TARGET_DIR)/furi-hal/*.c) + +# Version generation +C_SOURCES += $(PROJECT_ROOT)/lib/toolbox/version.c + +ASM_SOURCES += $(wildcard $(TARGET_DIR)/*.s) +C_SOURCES += $(wildcard $(TARGET_DIR)/*.c) +CPP_SOURCES += $(wildcard $(TARGET_DIR)/*.cpp) + +SVD_FILE = $(PROJECT_ROOT)/debug/STM32WB55_CM4.svd diff --git a/firmware/targets/f6/Inc/FreeRTOSConfig.h b/firmware/targets/f6/Inc/FreeRTOSConfig.h index 5d2befde..1e32e894 100644 --- a/firmware/targets/f6/Inc/FreeRTOSConfig.h +++ b/firmware/targets/f6/Inc/FreeRTOSConfig.h @@ -118,6 +118,14 @@ to exclude the API function. */ #define INCLUDE_xTaskGetSchedulerState 1 #define INCLUDE_xTimerPendFunctionCall 1 +/* CMSIS-RTOS V2 flags */ +#define configUSE_OS2_THREAD_SUSPEND_RESUME 1 +#define configUSE_OS2_THREAD_ENUMERATE 1 +#define configUSE_OS2_EVENTFLAGS_FROM_ISR 1 +#define configUSE_OS2_THREAD_FLAGS 1 +#define configUSE_OS2_TIMER 1 +#define configUSE_OS2_MUTEX 1 + /* * The CMSIS-RTOS V2 FreeRTOS wrapper is dependent on the heap implementation used * by the application thus the correct define need to be enabled below diff --git a/firmware/targets/f6/cube/Inc/FreeRTOSConfig.h b/firmware/targets/f6/cube/Inc/FreeRTOSConfig.h index a5b9c959..258ab421 100644 --- a/firmware/targets/f6/cube/Inc/FreeRTOSConfig.h +++ b/firmware/targets/f6/cube/Inc/FreeRTOSConfig.h @@ -1,6 +1,6 @@ /* USER CODE BEGIN Header */ /* - * FreeRTOS Kernel V10.2.1 + * FreeRTOS Kernel V10.3.1 * Portion Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. * Portion Copyright (C) 2019 StMicroelectronics, Inc. All Rights Reserved. * @@ -57,6 +57,10 @@ extern unsigned long getRunTimeCounterValue(void); /* USER CODE END 0 */ #endif +#ifndef CMSIS_device_header +#define CMSIS_device_header "stm32wbxx.h" +#endif /* CMSIS_device_header */ + #define configENABLE_FPU 1 #define configENABLE_MPU 0 @@ -99,6 +103,14 @@ #define configTIMER_QUEUE_LENGTH 10 #define configTIMER_TASK_STACK_DEPTH 256 +/* CMSIS-RTOS V2 flags */ +#define configUSE_OS2_THREAD_SUSPEND_RESUME 1 +#define configUSE_OS2_THREAD_ENUMERATE 1 +#define configUSE_OS2_EVENTFLAGS_FROM_ISR 1 +#define configUSE_OS2_THREAD_FLAGS 1 +#define configUSE_OS2_TIMER 1 +#define configUSE_OS2_MUTEX 1 + /* Set the following definitions to 1 to include the API function, or zero to exclude the API function. */ #define INCLUDE_vTaskPrioritySet 1 @@ -112,6 +124,7 @@ to exclude the API function. */ #define INCLUDE_xTimerPendFunctionCall 1 #define INCLUDE_xQueueGetMutexHolder 1 #define INCLUDE_uxTaskGetStackHighWaterMark 1 +#define INCLUDE_xTaskGetCurrentTaskHandle 1 #define INCLUDE_eTaskGetState 1 /* @@ -156,10 +169,9 @@ standard names. */ #define vPortSVCHandler SVC_Handler #define xPortPendSVHandler PendSV_Handler -/* IMPORTANT: This define is commented when used with STM32Cube firmware, when the timebase source is SysTick, - to prevent overwriting SysTick_Handler defined within STM32Cube HAL */ +/* IMPORTANT: After 10.3.1 update, Systick_Handler comes from NVIC (if SYS timebase = systick), otherwise from cmsis_os2.c */ -/* #define xPortSysTickHandler SysTick_Handler */ +#define USE_CUSTOM_SYSTICK_HANDLER_IMPLEMENTATION 1 /* USER CODE BEGIN 2 */ /* Definitions needed when configGENERATE_RUN_TIME_STATS is on */ diff --git a/firmware/targets/f6/cube/Inc/main.h b/firmware/targets/f6/cube/Inc/main.h index 4e159c5d..77c128f0 100644 --- a/firmware/targets/f6/cube/Inc/main.h +++ b/firmware/targets/f6/cube/Inc/main.h @@ -29,7 +29,7 @@ extern "C" { /* Includes ------------------------------------------------------------------*/ #include "stm32wbxx_hal.h" -#include "stm32wbxx.h" + #include "stm32wbxx_ll_i2c.h" #include "stm32wbxx_ll_crs.h" #include "stm32wbxx_ll_rcc.h" @@ -164,42 +164,6 @@ void Error_Handler(void); #define SPI_R_MOSI_GPIO_Port GPIOB /* USER CODE BEGIN Private defines */ -#define MISO_PIN GpioPin{.port = SPI_R_MISO_GPIO_Port, .pin = SPI_R_MISO_Pin} - -#define SPI_R hspi1 -#define SPI_D hspi2 -#define SPI_SD_HANDLE SPI_D - -extern TIM_HandleTypeDef htim1; -extern TIM_HandleTypeDef htim2; -extern TIM_HandleTypeDef htim16; - -#define TIM_A htim1 -#define TIM_B htim2 -#define TIM_C htim16 - -#define SPEAKER_TIM htim16 -#define SPEAKER_CH TIM_CHANNEL_1 - -#define LFRFID_TIM htim1 -#define LFRFID_CH TIM_CHANNEL_1 - -#define IRDA_TX_TIM htim1 -#define IRDA_TX_CH TIM_CHANNEL_3 - -// only for reference -// IRDA RX timer dont exist in F2 -// and timer need more data to init (NVIC IRQn to set priority) -#define IRDA_RX_TIM htim2 -#define IRDA_RX_FALLING_CH TIM_CHANNEL_1 -#define IRDA_RX_RISING_CH TIM_CHANNEL_2 - -#define NFC_IRQ_Pin RFID_PULL_Pin -#define NFC_IRQ_GPIO_Port RFID_PULL_GPIO_Port - -#define VIBRO_Pin GPIO_PIN_10 -#define VIBRO_GPIO_Port GPIOC - /* USER CODE END Private defines */ #ifdef __cplusplus diff --git a/firmware/targets/f6/cube/Inc/usbd_cdc_if.h b/firmware/targets/f6/cube/Inc/usbd_cdc_if.h index e9a32911..bbd5af07 100644 --- a/firmware/targets/f6/cube/Inc/usbd_cdc_if.h +++ b/firmware/targets/f6/cube/Inc/usbd_cdc_if.h @@ -48,11 +48,10 @@ * @brief Defines. * @{ */ -/* USER CODE BEGIN EXPORTED_DEFINES */ /* Define size for the receive and transmit buffer over CDC */ -/* It's up to user to redefine and/or remove those define */ #define APP_RX_DATA_SIZE 512 #define APP_TX_DATA_SIZE 512 +/* USER CODE BEGIN EXPORTED_DEFINES */ /* USER CODE END EXPORTED_DEFINES */ diff --git a/firmware/targets/f6/cube/Makefile b/firmware/targets/f6/cube/Makefile index 21254942..e86835f7 100644 --- a/firmware/targets/f6/cube/Makefile +++ b/firmware/targets/f6/cube/Makefile @@ -1,5 +1,5 @@ ########################################################################################################################## -# File automatically-generated by tool: [projectgenerator] version: [3.13.0-B3] date: [Tue Jul 20 02:23:07 MSK 2021] +# File automatically-generated by tool: [projectgenerator] version: [3.14.1] date: [Fri Sep 10 04:51:15 MSK 2021] ########################################################################################################################## # ------------------------------------------------ @@ -57,60 +57,60 @@ Src/usbd_desc.c \ Src/usbd_cdc_if.c \ Src/stm32wbxx_it.c \ Src/stm32wbxx_hal_msp.c \ -/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_utils.c \ -/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_exti.c \ -/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_pcd.c \ -/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_pcd_ex.c \ -/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_usb.c \ -/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_rcc.c \ -/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_rcc_ex.c \ -/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_flash.c \ -/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_flash_ex.c \ -/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_gpio.c \ -/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_hsem.c \ -/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_dma.c \ -/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_dma_ex.c \ -/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_pwr.c \ -/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_pwr_ex.c \ -/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_cortex.c \ -/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal.c \ -/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_exti.c \ -/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_adc.c \ -/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_adc_ex.c \ -/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_adc.c \ -/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_cryp.c \ -/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_cryp_ex.c \ -/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_comp.c \ -/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_crc.c \ -/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_crc_ex.c \ -/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_i2c.c \ -/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_gpio.c \ -/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_dma.c \ -/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_pka.c \ -/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_rng.c \ -/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_rtc.c \ -/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_rtc_ex.c \ -/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_spi.c \ -/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_spi_ex.c \ -/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_tim.c \ -/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_tim_ex.c \ -/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_usart.c \ -/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_rcc.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_utils.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_exti.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_pcd.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_pcd_ex.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_usb.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_rcc.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_rcc_ex.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_flash.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_flash_ex.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_gpio.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_hsem.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_dma.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_dma_ex.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_pwr.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_pwr_ex.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_cortex.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_exti.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_adc.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_adc_ex.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_adc.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_cryp.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_cryp_ex.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_comp.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_crc.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_crc_ex.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_i2c.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_gpio.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_dma.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_pka.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_rng.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_rtc.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_rtc_ex.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_spi.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_spi_ex.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_tim.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_tim_ex.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_usart.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_rcc.c \ Src/system_stm32wbxx.c \ -/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Middlewares/Third_Party/FreeRTOS/Source/croutine.c \ -/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Middlewares/Third_Party/FreeRTOS/Source/event_groups.c \ -/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Middlewares/Third_Party/FreeRTOS/Source/list.c \ -/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Middlewares/Third_Party/FreeRTOS/Source/queue.c \ -/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Middlewares/Third_Party/FreeRTOS/Source/stream_buffer.c \ -/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Middlewares/Third_Party/FreeRTOS/Source/tasks.c \ -/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Middlewares/Third_Party/FreeRTOS/Source/timers.c \ -/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/cmsis_os2.c \ -/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Middlewares/Third_Party/FreeRTOS/Source/portable/MemMang/heap_4.c \ -/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c \ -/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_core.c \ -/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_ctlreq.c \ -/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_ioreq.c \ -/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/croutine.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/event_groups.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/list.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/queue.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/stream_buffer.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/tasks.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/timers.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/cmsis_os2.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/portable/MemMang/heap_4.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_core.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_ctlreq.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_ioreq.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c # ASM sources ASM_SOURCES = \ @@ -170,15 +170,15 @@ AS_INCLUDES = \ # C includes C_INCLUDES = \ -IInc \ --I/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Inc \ --I/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Inc/Legacy \ --I/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Middlewares/Third_Party/FreeRTOS/Source/include \ --I/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2 \ --I/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F \ --I/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Middlewares/ST/STM32_USB_Device_Library/Core/Inc \ --I/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Inc \ --I/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/CMSIS/Device/ST/STM32WBxx/Include \ --I/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/CMSIS/Include +-I/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc \ +-I/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/Legacy \ +-I/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/include \ +-I/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2 \ +-I/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F \ +-I/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/ST/STM32_USB_Device_Library/Core/Inc \ +-I/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Inc \ +-I/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/CMSIS/Device/ST/STM32WBxx/Include \ +-I/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/CMSIS/Include # compile gcc flags diff --git a/firmware/targets/f6/cube/Src/adc.c b/firmware/targets/f6/cube/Src/adc.c index 1ad43f2f..e1294c43 100644 --- a/firmware/targets/f6/cube/Src/adc.c +++ b/firmware/targets/f6/cube/Src/adc.c @@ -29,8 +29,16 @@ ADC_HandleTypeDef hadc1; /* ADC1 init function */ void MX_ADC1_Init(void) { + + /* USER CODE BEGIN ADC1_Init 0 */ + + /* USER CODE END ADC1_Init 0 */ + ADC_ChannelConfTypeDef sConfig = {0}; + /* USER CODE BEGIN ADC1_Init 1 */ + + /* USER CODE END ADC1_Init 1 */ /** Common config */ hadc1.Instance = ADC1; @@ -64,6 +72,9 @@ void MX_ADC1_Init(void) { Error_Handler(); } + /* USER CODE BEGIN ADC1_Init 2 */ + + /* USER CODE END ADC1_Init 2 */ } diff --git a/firmware/targets/f6/cube/Src/aes.c b/firmware/targets/f6/cube/Src/aes.c index 1a042e9b..06d5aacb 100644 --- a/firmware/targets/f6/cube/Src/aes.c +++ b/firmware/targets/f6/cube/Src/aes.c @@ -35,6 +35,13 @@ __ALIGN_BEGIN static const uint32_t pKeyAES2[4] __ALIGN_END = { void MX_AES1_Init(void) { + /* USER CODE BEGIN AES1_Init 0 */ + + /* USER CODE END AES1_Init 0 */ + + /* USER CODE BEGIN AES1_Init 1 */ + + /* USER CODE END AES1_Init 1 */ hcryp1.Instance = AES1; hcryp1.Init.DataType = CRYP_DATATYPE_32B; hcryp1.Init.KeySize = CRYP_KEYSIZE_128B; @@ -46,12 +53,22 @@ void MX_AES1_Init(void) { Error_Handler(); } + /* USER CODE BEGIN AES1_Init 2 */ + + /* USER CODE END AES1_Init 2 */ } /* AES2 init function */ void MX_AES2_Init(void) { + /* USER CODE BEGIN AES2_Init 0 */ + + /* USER CODE END AES2_Init 0 */ + + /* USER CODE BEGIN AES2_Init 1 */ + + /* USER CODE END AES2_Init 1 */ hcryp2.Instance = AES2; hcryp2.Init.DataType = CRYP_DATATYPE_32B; hcryp2.Init.KeySize = CRYP_KEYSIZE_128B; @@ -63,6 +80,9 @@ void MX_AES2_Init(void) { Error_Handler(); } + /* USER CODE BEGIN AES2_Init 2 */ + + /* USER CODE END AES2_Init 2 */ } diff --git a/firmware/targets/f6/cube/Src/comp.c b/firmware/targets/f6/cube/Src/comp.c index 9401ed34..00f9fa66 100644 --- a/firmware/targets/f6/cube/Src/comp.c +++ b/firmware/targets/f6/cube/Src/comp.c @@ -30,6 +30,13 @@ COMP_HandleTypeDef hcomp1; void MX_COMP1_Init(void) { + /* USER CODE BEGIN COMP1_Init 0 */ + + /* USER CODE END COMP1_Init 0 */ + + /* USER CODE BEGIN COMP1_Init 1 */ + + /* USER CODE END COMP1_Init 1 */ hcomp1.Instance = COMP1; hcomp1.Init.InputMinus = COMP_INPUT_MINUS_1_4VREFINT; hcomp1.Init.InputPlus = COMP_INPUT_PLUS_IO1; @@ -43,6 +50,9 @@ void MX_COMP1_Init(void) { Error_Handler(); } + /* USER CODE BEGIN COMP1_Init 2 */ + + /* USER CODE END COMP1_Init 2 */ } diff --git a/firmware/targets/f6/cube/Src/crc.c b/firmware/targets/f6/cube/Src/crc.c index 42b98724..be2138ec 100644 --- a/firmware/targets/f6/cube/Src/crc.c +++ b/firmware/targets/f6/cube/Src/crc.c @@ -30,6 +30,13 @@ CRC_HandleTypeDef hcrc; void MX_CRC_Init(void) { + /* USER CODE BEGIN CRC_Init 0 */ + + /* USER CODE END CRC_Init 0 */ + + /* USER CODE BEGIN CRC_Init 1 */ + + /* USER CODE END CRC_Init 1 */ hcrc.Instance = CRC; hcrc.Init.DefaultPolynomialUse = DEFAULT_POLYNOMIAL_ENABLE; hcrc.Init.DefaultInitValueUse = DEFAULT_INIT_VALUE_ENABLE; @@ -40,6 +47,9 @@ void MX_CRC_Init(void) { Error_Handler(); } + /* USER CODE BEGIN CRC_Init 2 */ + + /* USER CODE END CRC_Init 2 */ } diff --git a/firmware/targets/f6/cube/Src/i2c.c b/firmware/targets/f6/cube/Src/i2c.c index c41b35d5..507de62c 100644 --- a/firmware/targets/f6/cube/Src/i2c.c +++ b/firmware/targets/f6/cube/Src/i2c.c @@ -27,6 +27,11 @@ /* I2C1 init function */ void MX_I2C1_Init(void) { + + /* USER CODE BEGIN I2C1_Init 0 */ + + /* USER CODE END I2C1_Init 0 */ + LL_I2C_InitTypeDef I2C_InitStruct = {0}; LL_GPIO_InitTypeDef GPIO_InitStruct = {0}; @@ -47,6 +52,9 @@ void MX_I2C1_Init(void) /* Peripheral clock enable */ LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C1); + /* USER CODE BEGIN I2C1_Init 1 */ + + /* USER CODE END I2C1_Init 1 */ /** I2C Initialization */ I2C_InitStruct.PeripheralMode = LL_I2C_MODE_I2C; @@ -62,6 +70,9 @@ void MX_I2C1_Init(void) LL_I2C_DisableOwnAddress2(I2C1); LL_I2C_DisableGeneralCall(I2C1); LL_I2C_EnableClockStretching(I2C1); + /* USER CODE BEGIN I2C1_Init 2 */ + + /* USER CODE END I2C1_Init 2 */ } diff --git a/firmware/targets/f6/cube/Src/main.c b/firmware/targets/f6/cube/Src/main.c index d4bfe02f..c8cada7b 100644 --- a/firmware/targets/f6/cube/Src/main.c +++ b/firmware/targets/f6/cube/Src/main.c @@ -163,6 +163,11 @@ void SystemClock_Config(void) } LL_PWR_EnableBkUpAccess(); + if(LL_RCC_GetRTCClockSource() != LL_RCC_RTC_CLKSOURCE_LSE) + { + LL_RCC_ForceBackupDomainReset(); + LL_RCC_ReleaseBackupDomainReset(); + } LL_RCC_LSE_SetDriveCapability(LL_RCC_LSEDRIVE_MEDIUMLOW); LL_RCC_LSE_Enable(); @@ -229,8 +234,6 @@ void SystemClock_Config(void) } if(LL_RCC_GetRTCClockSource() != LL_RCC_RTC_CLKSOURCE_LSE) { - LL_RCC_ForceBackupDomainReset(); - LL_RCC_ReleaseBackupDomainReset(); LL_RCC_SetRTCClockSource(LL_RCC_RTC_CLKSOURCE_LSE); } LL_RCC_EnableRTC(); @@ -239,6 +242,7 @@ void SystemClock_Config(void) LL_RCC_SetI2CClockSource(LL_RCC_I2C1_CLKSOURCE_PCLK1); LL_RCC_SetRNGClockSource(LL_RCC_RNG_CLKSOURCE_CLK48); LL_RCC_SetUSBClockSource(LL_RCC_USB_CLKSOURCE_PLLSAI1); + LL_RCC_SetCLK48ClockSource(LL_RCC_CLK48_CLKSOURCE_PLLSAI1); LL_RCC_SetSMPSClockSource(LL_RCC_SMPS_CLKSOURCE_HSE); LL_RCC_SetSMPSPrescaler(LL_RCC_SMPS_DIV_1); LL_RCC_SetRFWKPClockSource(LL_RCC_RFWKP_CLKSOURCE_LSE); diff --git a/firmware/targets/f6/cube/Src/pka.c b/firmware/targets/f6/cube/Src/pka.c index 8377ce57..9728cf5e 100644 --- a/firmware/targets/f6/cube/Src/pka.c +++ b/firmware/targets/f6/cube/Src/pka.c @@ -30,11 +30,21 @@ PKA_HandleTypeDef hpka; void MX_PKA_Init(void) { + /* USER CODE BEGIN PKA_Init 0 */ + + /* USER CODE END PKA_Init 0 */ + + /* USER CODE BEGIN PKA_Init 1 */ + + /* USER CODE END PKA_Init 1 */ hpka.Instance = PKA; if (HAL_PKA_Init(&hpka) != HAL_OK) { Error_Handler(); } + /* USER CODE BEGIN PKA_Init 2 */ + + /* USER CODE END PKA_Init 2 */ } diff --git a/firmware/targets/f6/cube/Src/rf.c b/firmware/targets/f6/cube/Src/rf.c index 62daf9b2..5682dd9d 100644 --- a/firmware/targets/f6/cube/Src/rf.c +++ b/firmware/targets/f6/cube/Src/rf.c @@ -28,6 +28,17 @@ void MX_RF_Init(void) { + /* USER CODE BEGIN RF_Init 0 */ + + /* USER CODE END RF_Init 0 */ + + /* USER CODE BEGIN RF_Init 1 */ + + /* USER CODE END RF_Init 1 */ + /* USER CODE BEGIN RF_Init 2 */ + + /* USER CODE END RF_Init 2 */ + } /* USER CODE BEGIN 1 */ diff --git a/firmware/targets/f6/cube/Src/rng.c b/firmware/targets/f6/cube/Src/rng.c index c2fb144e..ba70ae7b 100644 --- a/firmware/targets/f6/cube/Src/rng.c +++ b/firmware/targets/f6/cube/Src/rng.c @@ -30,11 +30,22 @@ RNG_HandleTypeDef hrng; void MX_RNG_Init(void) { + /* USER CODE BEGIN RNG_Init 0 */ + + /* USER CODE END RNG_Init 0 */ + + /* USER CODE BEGIN RNG_Init 1 */ + + /* USER CODE END RNG_Init 1 */ hrng.Instance = RNG; + hrng.Init.ClockErrorDetection = RNG_CED_ENABLE; if (HAL_RNG_Init(&hrng) != HAL_OK) { Error_Handler(); } + /* USER CODE BEGIN RNG_Init 2 */ + + /* USER CODE END RNG_Init 2 */ } diff --git a/firmware/targets/f6/cube/Src/rtc.c b/firmware/targets/f6/cube/Src/rtc.c index a460c52d..2aaa7897 100644 --- a/firmware/targets/f6/cube/Src/rtc.c +++ b/firmware/targets/f6/cube/Src/rtc.c @@ -29,9 +29,17 @@ RTC_HandleTypeDef hrtc; /* RTC init function */ void MX_RTC_Init(void) { + + /* USER CODE BEGIN RTC_Init 0 */ + + /* USER CODE END RTC_Init 0 */ + RTC_TimeTypeDef sTime = {0}; RTC_DateTypeDef sDate = {0}; + /* USER CODE BEGIN RTC_Init 1 */ + + /* USER CODE END RTC_Init 1 */ /** Initialize RTC Only */ hrtc.Instance = RTC; @@ -72,6 +80,9 @@ void MX_RTC_Init(void) { Error_Handler(); } + /* USER CODE BEGIN RTC_Init 2 */ + + /* USER CODE END RTC_Init 2 */ } diff --git a/firmware/targets/f6/cube/Src/spi.c b/firmware/targets/f6/cube/Src/spi.c index 637a9807..81864c8b 100644 --- a/firmware/targets/f6/cube/Src/spi.c +++ b/firmware/targets/f6/cube/Src/spi.c @@ -31,6 +31,13 @@ SPI_HandleTypeDef hspi2; void MX_SPI1_Init(void) { + /* USER CODE BEGIN SPI1_Init 0 */ + + /* USER CODE END SPI1_Init 0 */ + + /* USER CODE BEGIN SPI1_Init 1 */ + + /* USER CODE END SPI1_Init 1 */ hspi1.Instance = SPI1; hspi1.Init.Mode = SPI_MODE_MASTER; hspi1.Init.Direction = SPI_DIRECTION_2LINES; @@ -49,12 +56,22 @@ void MX_SPI1_Init(void) { Error_Handler(); } + /* USER CODE BEGIN SPI1_Init 2 */ + + /* USER CODE END SPI1_Init 2 */ } /* SPI2 init function */ void MX_SPI2_Init(void) { + /* USER CODE BEGIN SPI2_Init 0 */ + + /* USER CODE END SPI2_Init 0 */ + + /* USER CODE BEGIN SPI2_Init 1 */ + + /* USER CODE END SPI2_Init 1 */ hspi2.Instance = SPI2; hspi2.Init.Mode = SPI_MODE_MASTER; hspi2.Init.Direction = SPI_DIRECTION_2LINES; @@ -73,6 +90,9 @@ void MX_SPI2_Init(void) { Error_Handler(); } + /* USER CODE BEGIN SPI2_Init 2 */ + + /* USER CODE END SPI2_Init 2 */ } diff --git a/firmware/targets/f6/cube/Src/system_stm32wbxx.c b/firmware/targets/f6/cube/Src/system_stm32wbxx.c index 9d136693..d0ff7d2d 100644 --- a/firmware/targets/f6/cube/Src/system_stm32wbxx.c +++ b/firmware/targets/f6/cube/Src/system_stm32wbxx.c @@ -1,357 +1,368 @@ -/** - ****************************************************************************** - * @file system_stm32wbxx.c - * @author MCD Application Team - * @brief CMSIS Cortex Device Peripheral Access Layer System Source File - * - * This file provides two functions and one global variable to be called from - * user application: - * - SystemInit(): This function is called at startup just after reset and - * before branch to main program. This call is made inside - * the "startup_stm32wbxx.s" file. - * - * - SystemCoreClock variable: Contains the core clock (HCLK), it can be used - * by the user application to setup the SysTick - * timer or configure other parameters. - * - * - SystemCoreClockUpdate(): Updates the variable SystemCoreClock and must - * be called whenever the core clock is changed - * during program execution. - * - * After each device reset the MSI (4 MHz) is used as system clock source. - * Then SystemInit() function is called, in "startup_stm32wbxx.s" file, to - * configure the system clock before to branch to main program. - * - * This file configures the system clock as follows: - *============================================================================= - *----------------------------------------------------------------------------- - * System Clock source | MSI - *----------------------------------------------------------------------------- - * SYSCLK(Hz) | 4000000 - *----------------------------------------------------------------------------- - * HCLK(Hz) | 4000000 - *----------------------------------------------------------------------------- - * AHB Prescaler | 1 - *----------------------------------------------------------------------------- - * APB1 Prescaler | 1 - *----------------------------------------------------------------------------- - * APB2 Prescaler | 1 - *----------------------------------------------------------------------------- - * PLL_M | 1 - *----------------------------------------------------------------------------- - * PLL_N | 8 - *----------------------------------------------------------------------------- - * PLL_P | 7 - *----------------------------------------------------------------------------- - * PLL_Q | 2 - *----------------------------------------------------------------------------- - * PLL_R | 2 - *----------------------------------------------------------------------------- - * PLLSAI1_P | NA - *----------------------------------------------------------------------------- - * PLLSAI1_Q | NA - *----------------------------------------------------------------------------- - * PLLSAI1_R | NA - *----------------------------------------------------------------------------- - * Require 48MHz for USB OTG FS, | Disabled - * SDIO and RNG clock | - *----------------------------------------------------------------------------- - *============================================================================= - ****************************************************************************** - * @attention - * - *

© Copyright (c) 2019 STMicroelectronics. - * All rights reserved.

- * - * This software component is licensed by ST under BSD 3-Clause license, - * the "License"; You may not use this file except in compliance with the - * License. You may obtain a copy of the License at: - * opensource.org/licenses/BSD-3-Clause - * - ****************************************************************************** - */ - -/** @addtogroup CMSIS - * @{ - */ - -/** @addtogroup stm32WBxx_system - * @{ - */ - -/** @addtogroup stm32WBxx_System_Private_Includes - * @{ - */ - -#include "stm32wbxx.h" - -#if !defined (HSE_VALUE) - #define HSE_VALUE (32000000UL) /*!< Value of the External oscillator in Hz */ -#endif /* HSE_VALUE */ - -#if !defined (MSI_VALUE) - #define MSI_VALUE (4000000UL) /*!< Value of the Internal oscillator in Hz*/ -#endif /* MSI_VALUE */ - -#if !defined (HSI_VALUE) - #define HSI_VALUE (16000000UL) /*!< Value of the Internal oscillator in Hz*/ -#endif /* HSI_VALUE */ - -#if !defined (LSI_VALUE) - #define LSI_VALUE (32000UL) /*!< Value of LSI in Hz*/ -#endif /* LSI_VALUE */ - -#if !defined (LSE_VALUE) - #define LSE_VALUE (32768UL) /*!< Value of LSE in Hz*/ -#endif /* LSE_VALUE */ - -/** - * @} - */ - -/** @addtogroup STM32WBxx_System_Private_TypesDefinitions - * @{ - */ - -/** - * @} - */ - -/** @addtogroup STM32WBxx_System_Private_Defines - * @{ - */ - -/*!< Uncomment the following line if you need to relocate your vector Table in - Internal SRAM. */ -/* #define VECT_TAB_SRAM */ -#define VECT_TAB_OFFSET 0x0U /*!< Vector Table base offset field. - This value must be a multiple of 0x200. */ - -#define VECT_TAB_BASE_ADDRESS SRAM1_BASE /*!< Vector Table base offset field. - This value must be a multiple of 0x200. */ -/** - * @} - */ - -/** @addtogroup STM32WBxx_System_Private_Macros - * @{ - */ - -/** - * @} - */ - -/** @addtogroup STM32WBxx_System_Private_Variables - * @{ - */ - /* The SystemCoreClock variable is updated in three ways: - 1) by calling CMSIS function SystemCoreClockUpdate() - 2) by calling HAL API function HAL_RCC_GetHCLKFreq() - 3) each time HAL_RCC_ClockConfig() is called to configure the system clock frequency - Note: If you use this function to configure the system clock; then there - is no need to call the 2 first functions listed above, since SystemCoreClock - variable is updated automatically. - */ - uint32_t SystemCoreClock = 4000000UL ; /*CPU1: M4 on MSI clock after startup (4MHz)*/ - - const uint32_t AHBPrescTable[16UL] = {1UL, 3UL, 5UL, 1UL, 1UL, 6UL, 10UL, 32UL, 2UL, 4UL, 8UL, 16UL, 64UL, 128UL, 256UL, 512UL}; - - const uint32_t APBPrescTable[8UL] = {0UL, 0UL, 0UL, 0UL, 1UL, 2UL, 3UL, 4UL}; - - const uint32_t MSIRangeTable[16UL] = {100000UL, 200000UL, 400000UL, 800000UL, 1000000UL, 2000000UL, \ - 4000000UL, 8000000UL, 16000000UL, 24000000UL, 32000000UL, 48000000UL, 0UL, 0UL, 0UL, 0UL}; /* 0UL values are incorrect cases */ - -#if defined(STM32WB55xx) || defined(STM32WB5Mxx) || defined(STM32WB35xx) - const uint32_t SmpsPrescalerTable[4UL][6UL]={{1UL,3UL,2UL,2UL,1UL,2UL}, \ - {2UL,6UL,4UL,3UL,2UL,4UL}, \ - {4UL,12UL,8UL,6UL,4UL,8UL}, \ - {4UL,12UL,8UL,6UL,4UL,8UL}}; -#endif - -/** - * @} - */ - -/** @addtogroup STM32WBxx_System_Private_FunctionPrototypes - * @{ - */ - -/** - * @} - */ - -/** @addtogroup STM32WBxx_System_Private_Functions - * @{ - */ - -/** - * @brief Setup the microcontroller system. - * @param None - * @retval None - */ -void SystemInit(void) -{ - /* Configure the Vector Table location add offset address ------------------*/ -#if defined(VECT_TAB_SRAM) && defined(VECT_TAB_BASE_ADDRESS) - /* program in SRAMx */ - SCB->VTOR = VECT_TAB_BASE_ADDRESS | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAMx for CPU1 */ -#else /* program in FLASH */ - SCB->VTOR = VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */ -#endif - - /* FPU settings ------------------------------------------------------------*/ - #if (__FPU_PRESENT == 1) && (__FPU_USED == 1) - SCB->CPACR |= ((3UL << (10UL*2UL))|(3UL << (11UL*2UL))); /* set CP10 and CP11 Full Access */ - #endif - - /* Reset the RCC clock configuration to the default reset state ------------*/ - /* Set MSION bit */ - RCC->CR |= RCC_CR_MSION; - - /* Reset CFGR register */ - RCC->CFGR = 0x00070000U; - - /* Reset PLLSAI1ON, PLLON, HSECSSON, HSEON, HSION, and MSIPLLON bits */ - RCC->CR &= (uint32_t)0xFAF6FEFBU; - - /*!< Reset LSI1 and LSI2 bits */ - RCC->CSR &= (uint32_t)0xFFFFFFFAU; - - /*!< Reset HSI48ON bit */ - RCC->CRRCR &= (uint32_t)0xFFFFFFFEU; - - /* Reset PLLCFGR register */ - RCC->PLLCFGR = 0x22041000U; - -#if defined(STM32WB55xx) || defined(STM32WB5Mxx) - /* Reset PLLSAI1CFGR register */ - RCC->PLLSAI1CFGR = 0x22041000U; -#endif - - /* Reset HSEBYP bit */ - RCC->CR &= 0xFFFBFFFFU; - - /* Disable all interrupts */ - RCC->CIER = 0x00000000; -} - -/** - * @brief Update SystemCoreClock variable according to Clock Register Values. - * The SystemCoreClock variable contains the core clock (HCLK), it can - * be used by the user application to setup the SysTick timer or configure - * other parameters. - * - * @note Each time the core clock (HCLK) changes, this function must be called - * to update SystemCoreClock variable value. Otherwise, any configuration - * based on this variable will be incorrect. - * - * @note - The system frequency computed by this function is not the real - * frequency in the chip. It is calculated based on the predefined - * constant and the selected clock source: - * - * - If SYSCLK source is MSI, SystemCoreClock will contain the MSI_VALUE(*) - * - * - If SYSCLK source is HSI, SystemCoreClock will contain the HSI_VALUE(**) - * - * - If SYSCLK source is HSE, SystemCoreClock will contain the HSE_VALUE(***) - * - * - If SYSCLK source is PLL, SystemCoreClock will contain the HSE_VALUE(***) - * or HSI_VALUE(*) or MSI_VALUE(*) multiplied/divided by the PLL factors. - * - * (*) MSI_VALUE is a constant defined in stm32wbxx_hal.h file (default value - * 4 MHz) but the real value may vary depending on the variations - * in voltage and temperature. - * - * (**) HSI_VALUE is a constant defined in stm32wbxx_hal_conf.h file (default value - * 16 MHz) but the real value may vary depending on the variations - * in voltage and temperature. - * - * (***) HSE_VALUE is a constant defined in stm32wbxx_hal_conf.h file (default value - * 32 MHz), user has to ensure that HSE_VALUE is same as the real - * frequency of the crystal used. Otherwise, this function may - * have wrong result. - * - * - The result of this function could be not correct when using fractional - * value for HSE crystal. - * - * @param None - * @retval None - */ -void SystemCoreClockUpdate(void) -{ - uint32_t tmp, msirange, pllvco, pllr, pllsource , pllm; - - /* Get MSI Range frequency--------------------------------------------------*/ - - /*MSI frequency range in Hz*/ - msirange = MSIRangeTable[(RCC->CR & RCC_CR_MSIRANGE) >> RCC_CR_MSIRANGE_Pos]; - - /* Get SYSCLK source -------------------------------------------------------*/ - switch (RCC->CFGR & RCC_CFGR_SWS) - { - case 0x00: /* MSI used as system clock source */ - SystemCoreClock = msirange; - break; - - case 0x04: /* HSI used as system clock source */ - /* HSI used as system clock source */ - SystemCoreClock = HSI_VALUE; - break; - - case 0x08: /* HSE used as system clock source */ - SystemCoreClock = HSE_VALUE; - break; - - case 0x0C: /* PLL used as system clock source */ - /* PLL_VCO = (HSE_VALUE or HSI_VALUE or MSI_VALUE/ PLLM) * PLLN - SYSCLK = PLL_VCO / PLLR - */ - pllsource = (RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC); - pllm = ((RCC->PLLCFGR & RCC_PLLCFGR_PLLM) >> RCC_PLLCFGR_PLLM_Pos) + 1UL ; - - if(pllsource == 0x02UL) /* HSI used as PLL clock source */ - { - pllvco = (HSI_VALUE / pllm); - } - else if(pllsource == 0x03UL) /* HSE used as PLL clock source */ - { - pllvco = (HSE_VALUE / pllm); - } - else /* MSI used as PLL clock source */ - { - pllvco = (msirange / pllm); - } - - pllvco = pllvco * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> RCC_PLLCFGR_PLLN_Pos); - pllr = (((RCC->PLLCFGR & RCC_PLLCFGR_PLLR) >> RCC_PLLCFGR_PLLR_Pos) + 1UL); - - SystemCoreClock = pllvco/pllr; - break; - - default: - SystemCoreClock = msirange; - break; - } - - /* Compute HCLK clock frequency --------------------------------------------*/ - /* Get HCLK1 prescaler */ - tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> RCC_CFGR_HPRE_Pos)]; - /* HCLK clock frequency */ - SystemCoreClock = SystemCoreClock / tmp; - -} - - -/** - * @} - */ - -/** - * @} - */ - -/** - * @} - */ - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +/** + ****************************************************************************** + * @file system_stm32wbxx.c + * @author MCD Application Team + * @brief CMSIS Cortex Device Peripheral Access Layer System Source File + * + * This file provides two functions and one global variable to be called from + * user application: + * - SystemInit(): This function is called at startup just after reset and + * before branch to main program. This call is made inside + * the "startup_stm32wbxx.s" file. + * + * - SystemCoreClock variable: Contains the core clock (HCLK), it can be used + * by the user application to setup the SysTick + * timer or configure other parameters. + * + * - SystemCoreClockUpdate(): Updates the variable SystemCoreClock and must + * be called whenever the core clock is changed + * during program execution. + * + * After each device reset the MSI (4 MHz) is used as system clock source. + * Then SystemInit() function is called, in "startup_stm32wbxx.s" file, to + * configure the system clock before to branch to main program. + * + * This file configures the system clock as follows: + *============================================================================= + *----------------------------------------------------------------------------- + * System Clock source | MSI + *----------------------------------------------------------------------------- + * SYSCLK(Hz) | 4000000 + *----------------------------------------------------------------------------- + * HCLK(Hz) | 4000000 + *----------------------------------------------------------------------------- + * AHB Prescaler | 1 + *----------------------------------------------------------------------------- + * APB1 Prescaler | 1 + *----------------------------------------------------------------------------- + * APB2 Prescaler | 1 + *----------------------------------------------------------------------------- + * PLL_M | 1 + *----------------------------------------------------------------------------- + * PLL_N | 8 + *----------------------------------------------------------------------------- + * PLL_P | 7 + *----------------------------------------------------------------------------- + * PLL_Q | 2 + *----------------------------------------------------------------------------- + * PLL_R | 2 + *----------------------------------------------------------------------------- + * PLLSAI1_P | NA + *----------------------------------------------------------------------------- + * PLLSAI1_Q | NA + *----------------------------------------------------------------------------- + * PLLSAI1_R | NA + *----------------------------------------------------------------------------- + * Require 48MHz for USB OTG FS, | Disabled + * SDIO and RNG clock | + *----------------------------------------------------------------------------- + *============================================================================= + ****************************************************************************** + * @attention + * + * Copyright (c) 2019-2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/** @addtogroup CMSIS + * @{ + */ + +/** @addtogroup stm32WBxx_system + * @{ + */ + +/** @addtogroup stm32WBxx_System_Private_Includes + * @{ + */ + +#include "stm32wbxx.h" + +#if !defined (HSE_VALUE) + #define HSE_VALUE (32000000UL) /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +#if !defined (MSI_VALUE) + #define MSI_VALUE (4000000UL) /*!< Value of the Internal oscillator in Hz*/ +#endif /* MSI_VALUE */ + +#if !defined (HSI_VALUE) + #define HSI_VALUE (16000000UL) /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI_VALUE */ + +#if !defined (LSI_VALUE) + #define LSI_VALUE (32000UL) /*!< Value of LSI in Hz*/ +#endif /* LSI_VALUE */ + +#if !defined (LSE_VALUE) + #define LSE_VALUE (32768UL) /*!< Value of LSE in Hz*/ +#endif /* LSE_VALUE */ + +/** + * @} + */ + +/** @addtogroup STM32WBxx_System_Private_TypesDefinitions + * @{ + */ + +/** + * @} + */ + +/** @addtogroup STM32WBxx_System_Private_Defines + * @{ + */ + +/* Note: Following vector table addresses must be defined in line with linker + configuration. */ +/*!< Uncomment the following line if you need to relocate CPU1 CM4 and/or CPU2 + CM0+ vector table anywhere in Sram or Flash. Else vector table will be kept + at address 0x00 which correspond to automatic remap of boot address selected */ +/* #define USER_VECT_TAB_ADDRESS */ +#if defined(USER_VECT_TAB_ADDRESS) + /*!< Uncomment this line for user vector table remap in Sram else user remap + will be done in Flash. */ +/* #define VECT_TAB_SRAM */ +#if defined(VECT_TAB_SRAM) +#define VECT_TAB_BASE_ADDRESS SRAM1_BASE /*!< Vector Table base address field. + This value must be a multiple of 0x200. */ +#define VECT_TAB_OFFSET 0x00000000U /*!< Vector Table base offset field. + This value must be a multiple of 0x200. */ +#else +#define VECT_TAB_BASE_ADDRESS FLASH_BASE /*!< Vector Table base address field. + This value must be a multiple of 0x200. */ +#define VECT_TAB_OFFSET 0x00000000U /*!< Vector Table base offset field. + This value must be a multiple of 0x200. */ +#endif +#endif + +/** + * @} + */ + +/** @addtogroup STM32WBxx_System_Private_Macros + * @{ + */ + +/** + * @} + */ + +/** @addtogroup STM32WBxx_System_Private_Variables + * @{ + */ + /* The SystemCoreClock variable is updated in three ways: + 1) by calling CMSIS function SystemCoreClockUpdate() + 2) by calling HAL API function HAL_RCC_GetHCLKFreq() + 3) each time HAL_RCC_ClockConfig() is called to configure the system clock frequency + Note: If you use this function to configure the system clock; then there + is no need to call the 2 first functions listed above, since SystemCoreClock + variable is updated automatically. + */ + uint32_t SystemCoreClock = 4000000UL ; /*CPU1: M4 on MSI clock after startup (4MHz)*/ + + const uint32_t AHBPrescTable[16UL] = {1UL, 3UL, 5UL, 1UL, 1UL, 6UL, 10UL, 32UL, 2UL, 4UL, 8UL, 16UL, 64UL, 128UL, 256UL, 512UL}; + + const uint32_t APBPrescTable[8UL] = {0UL, 0UL, 0UL, 0UL, 1UL, 2UL, 3UL, 4UL}; + + const uint32_t MSIRangeTable[16UL] = {100000UL, 200000UL, 400000UL, 800000UL, 1000000UL, 2000000UL, \ + 4000000UL, 8000000UL, 16000000UL, 24000000UL, 32000000UL, 48000000UL, 0UL, 0UL, 0UL, 0UL}; /* 0UL values are incorrect cases */ + +#if defined(STM32WB55xx) || defined(STM32WB5Mxx) || defined(STM32WB35xx) || defined (STM32WB15xx) || defined (STM32WB10xx) + const uint32_t SmpsPrescalerTable[4UL][6UL]={{1UL,3UL,2UL,2UL,1UL,2UL}, \ + {2UL,6UL,4UL,3UL,2UL,4UL}, \ + {4UL,12UL,8UL,6UL,4UL,8UL}, \ + {4UL,12UL,8UL,6UL,4UL,8UL}}; +#endif + +/** + * @} + */ + +/** @addtogroup STM32WBxx_System_Private_FunctionPrototypes + * @{ + */ + +/** + * @} + */ + +/** @addtogroup STM32WBxx_System_Private_Functions + * @{ + */ + +/** + * @brief Setup the microcontroller system. + * @param None + * @retval None + */ +void SystemInit(void) +{ +#if defined(USER_VECT_TAB_ADDRESS) + /* Configure the Vector Table location add offset address ------------------*/ + SCB->VTOR = VECT_TAB_BASE_ADDRESS | VECT_TAB_OFFSET; +#endif + + /* FPU settings ------------------------------------------------------------*/ + #if (__FPU_PRESENT == 1) && (__FPU_USED == 1) + SCB->CPACR |= ((3UL << (10UL*2UL))|(3UL << (11UL*2UL))); /* set CP10 and CP11 Full Access */ + #endif + + /* Reset the RCC clock configuration to the default reset state ------------*/ + /* Set MSION bit */ + RCC->CR |= RCC_CR_MSION; + + /* Reset CFGR register */ + RCC->CFGR = 0x00070000U; + + /* Reset PLLSAI1ON, PLLON, HSECSSON, HSEON, HSION, and MSIPLLON bits */ + RCC->CR &= (uint32_t)0xFAF6FEFBU; + + /*!< Reset LSI1 and LSI2 bits */ + RCC->CSR &= (uint32_t)0xFFFFFFFAU; + + /*!< Reset HSI48ON bit */ + RCC->CRRCR &= (uint32_t)0xFFFFFFFEU; + + /* Reset PLLCFGR register */ + RCC->PLLCFGR = 0x22041000U; + +#if defined(STM32WB55xx) || defined(STM32WB5Mxx) + /* Reset PLLSAI1CFGR register */ + RCC->PLLSAI1CFGR = 0x22041000U; +#endif + + /* Reset HSEBYP bit */ + RCC->CR &= 0xFFFBFFFFU; + + /* Disable all interrupts */ + RCC->CIER = 0x00000000; +} + +/** + * @brief Update SystemCoreClock variable according to Clock Register Values. + * The SystemCoreClock variable contains the core clock (HCLK), it can + * be used by the user application to setup the SysTick timer or configure + * other parameters. + * + * @note Each time the core clock (HCLK) changes, this function must be called + * to update SystemCoreClock variable value. Otherwise, any configuration + * based on this variable will be incorrect. + * + * @note - The system frequency computed by this function is not the real + * frequency in the chip. It is calculated based on the predefined + * constant and the selected clock source: + * + * - If SYSCLK source is MSI, SystemCoreClock will contain the MSI_VALUE(*) + * + * - If SYSCLK source is HSI, SystemCoreClock will contain the HSI_VALUE(**) + * + * - If SYSCLK source is HSE, SystemCoreClock will contain the HSE_VALUE(***) + * + * - If SYSCLK source is PLL, SystemCoreClock will contain the HSE_VALUE(***) + * or HSI_VALUE(*) or MSI_VALUE(*) multiplied/divided by the PLL factors. + * + * (*) MSI_VALUE is a constant defined in stm32wbxx_hal.h file (default value + * 4 MHz) but the real value may vary depending on the variations + * in voltage and temperature. + * + * (**) HSI_VALUE is a constant defined in stm32wbxx_hal_conf.h file (default value + * 16 MHz) but the real value may vary depending on the variations + * in voltage and temperature. + * + * (***) HSE_VALUE is a constant defined in stm32wbxx_hal_conf.h file (default value + * 32 MHz), user has to ensure that HSE_VALUE is same as the real + * frequency of the crystal used. Otherwise, this function may + * have wrong result. + * + * - The result of this function could be not correct when using fractional + * value for HSE crystal. + * + * @param None + * @retval None + */ +void SystemCoreClockUpdate(void) +{ + uint32_t tmp, msirange, pllvco, pllr, pllsource , pllm; + + /* Get MSI Range frequency--------------------------------------------------*/ + + /*MSI frequency range in Hz*/ + msirange = MSIRangeTable[(RCC->CR & RCC_CR_MSIRANGE) >> RCC_CR_MSIRANGE_Pos]; + + /* Get SYSCLK source -------------------------------------------------------*/ + switch (RCC->CFGR & RCC_CFGR_SWS) + { + case 0x00: /* MSI used as system clock source */ + SystemCoreClock = msirange; + break; + + case 0x04: /* HSI used as system clock source */ + /* HSI used as system clock source */ + SystemCoreClock = HSI_VALUE; + break; + + case 0x08: /* HSE used as system clock source */ + SystemCoreClock = HSE_VALUE; + break; + + case 0x0C: /* PLL used as system clock source */ + /* PLL_VCO = (HSE_VALUE or HSI_VALUE or MSI_VALUE/ PLLM) * PLLN + SYSCLK = PLL_VCO / PLLR + */ + pllsource = (RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC); + pllm = ((RCC->PLLCFGR & RCC_PLLCFGR_PLLM) >> RCC_PLLCFGR_PLLM_Pos) + 1UL ; + + if(pllsource == 0x02UL) /* HSI used as PLL clock source */ + { + pllvco = (HSI_VALUE / pllm); + } + else if(pllsource == 0x03UL) /* HSE used as PLL clock source */ + { + pllvco = (HSE_VALUE / pllm); + } + else /* MSI used as PLL clock source */ + { + pllvco = (msirange / pllm); + } + + pllvco = pllvco * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> RCC_PLLCFGR_PLLN_Pos); + pllr = (((RCC->PLLCFGR & RCC_PLLCFGR_PLLR) >> RCC_PLLCFGR_PLLR_Pos) + 1UL); + + SystemCoreClock = pllvco/pllr; + break; + + default: + SystemCoreClock = msirange; + break; + } + + /* Compute HCLK clock frequency --------------------------------------------*/ + /* Get HCLK1 prescaler */ + tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> RCC_CFGR_HPRE_Pos)]; + /* HCLK clock frequency */ + SystemCoreClock = SystemCoreClock / tmp; + +} + + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f6/cube/Src/tim.c b/firmware/targets/f6/cube/Src/tim.c index 37685b9d..1c38c1d7 100644 --- a/firmware/targets/f6/cube/Src/tim.c +++ b/firmware/targets/f6/cube/Src/tim.c @@ -31,11 +31,19 @@ TIM_HandleTypeDef htim16; /* TIM1 init function */ void MX_TIM1_Init(void) { + + /* USER CODE BEGIN TIM1_Init 0 */ + + /* USER CODE END TIM1_Init 0 */ + TIM_ClockConfigTypeDef sClockSourceConfig = {0}; TIM_MasterConfigTypeDef sMasterConfig = {0}; TIM_OC_InitTypeDef sConfigOC = {0}; TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0}; + /* USER CODE BEGIN TIM1_Init 1 */ + + /* USER CODE END TIM1_Init 1 */ htim1.Instance = TIM1; htim1.Init.Prescaler = 0; htim1.Init.CounterMode = TIM_COUNTERMODE_UP; @@ -100,16 +108,27 @@ void MX_TIM1_Init(void) { Error_Handler(); } + /* USER CODE BEGIN TIM1_Init 2 */ + + /* USER CODE END TIM1_Init 2 */ HAL_TIM_MspPostInit(&htim1); } /* TIM2 init function */ void MX_TIM2_Init(void) { + + /* USER CODE BEGIN TIM2_Init 0 */ + + /* USER CODE END TIM2_Init 0 */ + TIM_ClockConfigTypeDef sClockSourceConfig = {0}; TIM_MasterConfigTypeDef sMasterConfig = {0}; TIM_IC_InitTypeDef sConfigIC = {0}; + /* USER CODE BEGIN TIM2_Init 1 */ + + /* USER CODE END TIM2_Init 1 */ htim2.Instance = TIM2; htim2.Init.Prescaler = 64-1; htim2.Init.CounterMode = TIM_COUNTERMODE_UP; @@ -149,14 +168,25 @@ void MX_TIM2_Init(void) { Error_Handler(); } + /* USER CODE BEGIN TIM2_Init 2 */ + + /* USER CODE END TIM2_Init 2 */ } /* TIM16 init function */ void MX_TIM16_Init(void) { + + /* USER CODE BEGIN TIM16_Init 0 */ + + /* USER CODE END TIM16_Init 0 */ + TIM_OC_InitTypeDef sConfigOC = {0}; TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0}; + /* USER CODE BEGIN TIM16_Init 1 */ + + /* USER CODE END TIM16_Init 1 */ htim16.Instance = TIM16; htim16.Init.Prescaler = 500 - 1; htim16.Init.CounterMode = TIM_COUNTERMODE_UP; @@ -195,6 +225,9 @@ void MX_TIM16_Init(void) { Error_Handler(); } + /* USER CODE BEGIN TIM16_Init 2 */ + + /* USER CODE END TIM16_Init 2 */ HAL_TIM_MspPostInit(&htim16); } diff --git a/firmware/targets/f6/cube/Src/usart.c b/firmware/targets/f6/cube/Src/usart.c index 51a8298c..0a0466dc 100644 --- a/firmware/targets/f6/cube/Src/usart.c +++ b/firmware/targets/f6/cube/Src/usart.c @@ -28,6 +28,11 @@ void MX_USART1_UART_Init(void) { + + /* USER CODE BEGIN USART1_Init 0 */ + + /* USER CODE END USART1_Init 0 */ + LL_USART_InitTypeDef USART_InitStruct = {0}; LL_GPIO_InitTypeDef GPIO_InitStruct = {0}; @@ -48,6 +53,9 @@ void MX_USART1_UART_Init(void) GPIO_InitStruct.Alternate = LL_GPIO_AF_7; LL_GPIO_Init(GPIOB, &GPIO_InitStruct); + /* USER CODE BEGIN USART1_Init 1 */ + + /* USER CODE END USART1_Init 1 */ USART_InitStruct.PrescalerValue = LL_USART_PRESCALER_DIV1; USART_InitStruct.BaudRate = 115200; USART_InitStruct.DataWidth = LL_USART_DATAWIDTH_8B; @@ -71,9 +79,12 @@ void MX_USART1_UART_Init(void) LL_USART_Enable(USART1); /* Polling USART1 initialisation */ - while((!(LL_USART_IsActiveFlag_TEACK(USART1))) || (!(LL_USART_IsActiveFlag_REACK(USART1)))) + while(!(LL_USART_IsActiveFlag_TEACK(USART1))) { } + /* USER CODE BEGIN USART1_Init 2 */ + + /* USER CODE END USART1_Init 2 */ } diff --git a/firmware/targets/f6/cube/Src/usbd_cdc_if.c b/firmware/targets/f6/cube/Src/usbd_cdc_if.c index e3301aae..d52d1e3e 100644 --- a/firmware/targets/f6/cube/Src/usbd_cdc_if.c +++ b/firmware/targets/f6/cube/Src/usbd_cdc_if.c @@ -295,7 +295,7 @@ uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len) /** * @brief CDC_TransmitCplt_FS - * Data transmited callback + * Data transmitted callback * * @note * This function is IN transfer complete callback used to inform user that diff --git a/firmware/targets/f6/cube/Src/usbd_conf.c b/firmware/targets/f6/cube/Src/usbd_conf.c index 2ebde906..033e619a 100644 --- a/firmware/targets/f6/cube/Src/usbd_conf.c +++ b/firmware/targets/f6/cube/Src/usbd_conf.c @@ -685,10 +685,10 @@ USBD_StatusTypeDef USBD_LL_PrepareReceive(USBD_HandleTypeDef *pdev, uint8_t ep_a } /** - * @brief Returns the last transfered packet size. + * @brief Returns the last transferred packet size. * @param pdev: Device handle * @param ep_addr: Endpoint number - * @retval Recived Data Size + * @retval Received Data Size */ uint32_t USBD_LL_GetRxDataSize(USBD_HandleTypeDef *pdev, uint8_t ep_addr) { @@ -779,7 +779,7 @@ static void SystemClockConfig_Resume(void) /* USER CODE END 5 */ /** - * @brief Retuns the USB status depending on the HAL status: + * @brief Returns the USB status depending on the HAL status: * @param hal_status: HAL status * @retval USB status */ diff --git a/firmware/targets/f6/cube/Src/usbd_desc.c b/firmware/targets/f6/cube/Src/usbd_desc.c index 9fbb3f5c..26f4b7c5 100644 --- a/firmware/targets/f6/cube/Src/usbd_desc.c +++ b/firmware/targets/f6/cube/Src/usbd_desc.c @@ -182,7 +182,7 @@ __ALIGN_BEGIN uint8_t USBD_CDC_DeviceDesc[USB_LEN_DEV_DESC] __ALIGN_END = #pragma data_alignment=4 #endif /* defined ( __ICCARM__ ) */ -/** USB lang indentifier descriptor. */ +/** USB lang identifier descriptor. */ __ALIGN_BEGIN uint8_t USBD_LangIDDesc[USB_LEN_LANGID_STR_DESC] __ALIGN_END = { USB_LEN_LANGID_STR_DESC, diff --git a/firmware/targets/f6/cube/f6.ioc b/firmware/targets/f6/cube/f6.ioc index fcf156c7..03c9c140 100644 --- a/firmware/targets/f6/cube/f6.ioc +++ b/firmware/targets/f6/cube/f6.ioc @@ -135,8 +135,8 @@ Mcu.PinsNb=69 Mcu.ThirdPartyNb=0 Mcu.UserConstants= Mcu.UserName=STM32WB55RGVx -MxCube.Version=6.1.2 -MxDb.Version=DB.6.0.10 +MxCube.Version=6.3.0 +MxDb.Version=DB.6.0.30 NVIC.ADC1_IRQn=true\:5\:0\:true\:false\:true\:false\:true\:true NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false NVIC.COMP_IRQn=true\:5\:0\:true\:false\:true\:false\:false\:true @@ -178,8 +178,9 @@ PA1.GPIOParameters=GPIO_Label PA1.GPIO_Label=CC1101_G0 PA1.Locked=true PA1.Signal=GPIO_Analog -PA10.GPIOParameters=GPIO_Speed,GPIO_Label +PA10.GPIOParameters=GPIO_Speed,GPIO_Label,GPIO_Pu PA10.GPIO_Label=I2C_SDA +PA10.GPIO_Pu=GPIO_PULLUP PA10.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH PA10.Locked=true PA10.Mode=I2C @@ -233,8 +234,9 @@ PA8.GPIOParameters=GPIO_Label PA8.GPIO_Label=RFID_TUNE PA8.Locked=true PA8.Signal=GPIO_Output -PA9.GPIOParameters=GPIO_Speed,GPIO_Label +PA9.GPIOParameters=GPIO_Speed,GPIO_Label,GPIO_Pu PA9.GPIO_Label=I2C_SCL +PA9.GPIO_Pu=GPIO_PULLUP PA9.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH PA9.Locked=true PA9.Mode=I2C @@ -371,8 +373,15 @@ PC6.Locked=true PC6.Signal=GPIO_Input PCC.Ble.ConnectionInterval=1000.0 PCC.Ble.DataLength=6 +PCC.Ble.IsUsed=false PCC.Ble.Mode=NOT_SELECTED PCC.Ble.PowerLevel=Min +PCC.Zigbee.IsUsed=false +PCC.Zigbee.Mode=Sleepy End Device +PCC.Zigbee.Payload=15 +PCC.Zigbee.PoolPeriodicity=480.0 +PCC.Zigbee.PowerLevel=Min +PCC.Zigbee.RequestPeriodicity=1500.0 PD0.GPIOParameters=GPIO_Speed,PinState,GPIO_Label PD0.GPIO_Label=CC1101_CS PD0.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH @@ -401,11 +410,11 @@ ProjectManager.BackupPrevious=false ProjectManager.CompilerOptimize=6 ProjectManager.ComputerToolchain=false ProjectManager.CoupleFile=true -ProjectManager.CustomerFirmwarePackage= -ProjectManager.DefaultFWLocation=true +ProjectManager.CustomerFirmwarePackage=../../../../lib/STM32CubeWB +ProjectManager.DefaultFWLocation=false ProjectManager.DeletePrevious=true ProjectManager.DeviceId=STM32WB55RGVx -ProjectManager.FirmwarePackage=STM32Cube FW_WB V1.10.1 +ProjectManager.FirmwarePackage=STM32Cube FW_WB V1.12.1 ProjectManager.FreePins=false ProjectManager.HalAssertFull=false ProjectManager.HeapSize=0x400 diff --git a/firmware/targets/f6/cube/startup_stm32wb55xx_cm4.s b/firmware/targets/f6/cube/startup_stm32wb55xx_cm4.s index fc26cb42..c5c2b3fc 100644 --- a/firmware/targets/f6/cube/startup_stm32wb55xx_cm4.s +++ b/firmware/targets/f6/cube/startup_stm32wb55xx_cm4.s @@ -1,445 +1,444 @@ -/** - ****************************************************************************** - * @file startup_stm32wb55xx_cm4.s - * @author MCD Application Team - * @brief STM32WB55xx devices vector table GCC toolchain. - * This module performs: - * - Set the initial SP - * - Set the initial PC == Reset_Handler, - * - Set the vector table entries with the exceptions ISR address - * - Branches to main in the C library (which eventually - * calls main()). - * After Reset the Cortex-M4 processor is in Thread mode, - * priority is Privileged, and the Stack is set to Main. - ****************************************************************************** - * @attention - * - *

© Copyright (c) 2019 STMicroelectronics. - * All rights reserved.

- * - * This software component is licensed by ST under BSD 3-Clause license, - * the "License"; You may not use this file except in compliance with the - * License. You may obtain a copy of the License at: - * opensource.org/licenses/BSD-3-Clause - * - ****************************************************************************** - */ - - .syntax unified - .cpu cortex-m4 - .fpu softvfp - .thumb - -.global g_pfnVectors -.global Default_Handler - -/* start address for the initialization values of the .data section. -defined in linker script */ -.word _sidata -/* start address for the .data section. defined in linker script */ -.word _sdata -/* end address for the .data section. defined in linker script */ -.word _edata -/* start address for the .bss section. defined in linker script */ -.word _sbss -/* end address for the .bss section. defined in linker script */ -.word _ebss -/* start address for the .MB_MEM2 section. defined in linker script */ -.word _sMB_MEM2 -/* end address for the .MB_MEM2 section. defined in linker script */ -.word _eMB_MEM2 - -/* INIT_BSS macro is used to fill the specified region [start : end] with zeros */ -.macro INIT_BSS start, end - ldr r0, =\start - ldr r1, =\end - movs r3, #0 - bl LoopFillZerobss -.endm - -/* INIT_DATA macro is used to copy data in the region [start : end] starting from 'src' */ -.macro INIT_DATA start, end, src - ldr r0, =\start - ldr r1, =\end - ldr r2, =\src - movs r3, #0 - bl LoopCopyDataInit -.endm - -.section .text.data_initializers -CopyDataInit: - ldr r4, [r2, r3] - str r4, [r0, r3] - adds r3, r3, #4 - -LoopCopyDataInit: - adds r4, r0, r3 - cmp r4, r1 - bcc CopyDataInit - bx lr - -FillZerobss: - str r3, [r0] - adds r0, r0, #4 - -LoopFillZerobss: - cmp r0, r1 - bcc FillZerobss - bx lr - - .section .text.Reset_Handler - .weak Reset_Handler - .type Reset_Handler, %function -Reset_Handler: - ldr r0, =_estack - mov sp, r0 /* set stack pointer */ -/* Call the clock system intitialization function.*/ - bl SystemInit - -/* Copy the data segment initializers from flash to SRAM */ - INIT_DATA _sdata, _edata, _sidata - -/* Zero fill the bss segments. */ - INIT_BSS _sbss, _ebss - INIT_BSS _sMB_MEM2, _eMB_MEM2 - -/* Call static constructors */ - bl __libc_init_array -/* Call the application s entry point.*/ - bl main - -LoopForever: - b LoopForever - -.size Reset_Handler, .-Reset_Handler - -/** - * @brief This is the code that gets called when the processor receives an - * unexpected interrupt. This simply enters an infinite loop, preserving - * the system state for examination by a debugger. - * - * @param None - * @retval None -*/ - .section .text.Default_Handler,"ax",%progbits -Default_Handler: -Infinite_Loop: - b Infinite_Loop - .size Default_Handler, .-Default_Handler -/****************************************************************************** -* -* The minimal vector table for a Cortex-M4. Note that the proper constructs -* must be placed on this to ensure that it ends up at physical address -* 0x0000.0000. -* -******************************************************************************/ - .section .isr_vector,"a",%progbits - .type g_pfnVectors, %object - .size g_pfnVectors, .-g_pfnVectors - - -g_pfnVectors: - .word _estack - .word Reset_Handler - .word NMI_Handler - .word HardFault_Handler - .word MemManage_Handler - .word BusFault_Handler - .word UsageFault_Handler - .word 0 - .word 0 - .word 0 - .word 0 - .word SVC_Handler - .word DebugMon_Handler - .word 0 - .word PendSV_Handler - .word SysTick_Handler - .word WWDG_IRQHandler - .word PVD_PVM_IRQHandler - .word TAMP_STAMP_LSECSS_IRQHandler - .word RTC_WKUP_IRQHandler - .word FLASH_IRQHandler - .word RCC_IRQHandler - .word EXTI0_IRQHandler - .word EXTI1_IRQHandler - .word EXTI2_IRQHandler - .word EXTI3_IRQHandler - .word EXTI4_IRQHandler - .word DMA1_Channel1_IRQHandler - .word DMA1_Channel2_IRQHandler - .word DMA1_Channel3_IRQHandler - .word DMA1_Channel4_IRQHandler - .word DMA1_Channel5_IRQHandler - .word DMA1_Channel6_IRQHandler - .word DMA1_Channel7_IRQHandler - .word ADC1_IRQHandler - .word USB_HP_IRQHandler - .word USB_LP_IRQHandler - .word C2SEV_PWR_C2H_IRQHandler - .word COMP_IRQHandler - .word EXTI9_5_IRQHandler - .word TIM1_BRK_IRQHandler - .word TIM1_UP_TIM16_IRQHandler - .word TIM1_TRG_COM_TIM17_IRQHandler - .word TIM1_CC_IRQHandler - .word TIM2_IRQHandler - .word PKA_IRQHandler - .word I2C1_EV_IRQHandler - .word I2C1_ER_IRQHandler - .word I2C3_EV_IRQHandler - .word I2C3_ER_IRQHandler - .word SPI1_IRQHandler - .word SPI2_IRQHandler - .word USART1_IRQHandler - .word LPUART1_IRQHandler - .word SAI1_IRQHandler - .word TSC_IRQHandler - .word EXTI15_10_IRQHandler - .word RTC_Alarm_IRQHandler - .word CRS_IRQHandler - .word PWR_SOTF_BLEACT_802ACT_RFPHASE_IRQHandler - .word IPCC_C1_RX_IRQHandler - .word IPCC_C1_TX_IRQHandler - .word HSEM_IRQHandler - .word LPTIM1_IRQHandler - .word LPTIM2_IRQHandler - .word LCD_IRQHandler - .word QUADSPI_IRQHandler - .word AES1_IRQHandler - .word AES2_IRQHandler - .word RNG_IRQHandler - .word FPU_IRQHandler - .word DMA2_Channel1_IRQHandler - .word DMA2_Channel2_IRQHandler - .word DMA2_Channel3_IRQHandler - .word DMA2_Channel4_IRQHandler - .word DMA2_Channel5_IRQHandler - .word DMA2_Channel6_IRQHandler - .word DMA2_Channel7_IRQHandler - .word DMAMUX1_OVR_IRQHandler - -/******************************************************************************* -* -* Provide weak aliases for each Exception handler to the Default_Handler. -* As they are weak aliases, any function with the same name will override -* this definition. -* -*******************************************************************************/ - .weak NMI_Handler - .thumb_set NMI_Handler,Default_Handler - - .weak HardFault_Handler - .thumb_set HardFault_Handler,Default_Handler - - .weak MemManage_Handler - .thumb_set MemManage_Handler,Default_Handler - - .weak BusFault_Handler - .thumb_set BusFault_Handler,Default_Handler - - .weak UsageFault_Handler - .thumb_set UsageFault_Handler,Default_Handler - - .weak SVC_Handler - .thumb_set SVC_Handler,Default_Handler - - .weak DebugMon_Handler - .thumb_set DebugMon_Handler,Default_Handler - - .weak PendSV_Handler - .thumb_set PendSV_Handler,Default_Handler - - .weak SysTick_Handler - .thumb_set SysTick_Handler,Default_Handler - - .weak WWDG_IRQHandler - .thumb_set WWDG_IRQHandler,Default_Handler - - .weak PVD_PVM_IRQHandler - .thumb_set PVD_PVM_IRQHandler,Default_Handler - - .weak TAMP_STAMP_LSECSS_IRQHandler - .thumb_set TAMP_STAMP_LSECSS_IRQHandler,Default_Handler - - .weak RTC_WKUP_IRQHandler - .thumb_set RTC_WKUP_IRQHandler,Default_Handler - - .weak FLASH_IRQHandler - .thumb_set FLASH_IRQHandler,Default_Handler - - .weak RCC_IRQHandler - .thumb_set RCC_IRQHandler,Default_Handler - - .weak EXTI0_IRQHandler - .thumb_set EXTI0_IRQHandler,Default_Handler - - .weak EXTI1_IRQHandler - .thumb_set EXTI1_IRQHandler,Default_Handler - - .weak EXTI2_IRQHandler - .thumb_set EXTI2_IRQHandler,Default_Handler - - .weak EXTI3_IRQHandler - .thumb_set EXTI3_IRQHandler,Default_Handler - - .weak EXTI4_IRQHandler - .thumb_set EXTI4_IRQHandler,Default_Handler - - .weak DMA1_Channel1_IRQHandler - .thumb_set DMA1_Channel1_IRQHandler,Default_Handler - - .weak DMA1_Channel2_IRQHandler - .thumb_set DMA1_Channel2_IRQHandler,Default_Handler - - .weak DMA1_Channel3_IRQHandler - .thumb_set DMA1_Channel3_IRQHandler,Default_Handler - - .weak DMA1_Channel4_IRQHandler - .thumb_set DMA1_Channel4_IRQHandler,Default_Handler - - .weak DMA1_Channel5_IRQHandler - .thumb_set DMA1_Channel5_IRQHandler,Default_Handler - - .weak DMA1_Channel6_IRQHandler - .thumb_set DMA1_Channel6_IRQHandler,Default_Handler - - .weak DMA1_Channel7_IRQHandler - .thumb_set DMA1_Channel7_IRQHandler,Default_Handler - - .weak ADC1_IRQHandler - .thumb_set ADC1_IRQHandler,Default_Handler - - .weak USB_HP_IRQHandler - .thumb_set USB_HP_IRQHandler,Default_Handler - - .weak USB_LP_IRQHandler - .thumb_set USB_LP_IRQHandler,Default_Handler - - .weak C2SEV_PWR_C2H_IRQHandler - .thumb_set C2SEV_PWR_C2H_IRQHandler,Default_Handler - - .weak COMP_IRQHandler - .thumb_set COMP_IRQHandler,Default_Handler - - .weak EXTI9_5_IRQHandler - .thumb_set EXTI9_5_IRQHandler,Default_Handler - - .weak TIM1_BRK_IRQHandler - .thumb_set TIM1_BRK_IRQHandler,Default_Handler - - .weak TIM1_UP_TIM16_IRQHandler - .thumb_set TIM1_UP_TIM16_IRQHandler,Default_Handler - - .weak TIM1_TRG_COM_TIM17_IRQHandler - .thumb_set TIM1_TRG_COM_TIM17_IRQHandler,Default_Handler - - .weak TIM1_CC_IRQHandler - .thumb_set TIM1_CC_IRQHandler,Default_Handler - - .weak TIM2_IRQHandler - .thumb_set TIM2_IRQHandler,Default_Handler - - .weak PKA_IRQHandler - .thumb_set PKA_IRQHandler,Default_Handler - - .weak I2C1_EV_IRQHandler - .thumb_set I2C1_EV_IRQHandler,Default_Handler - - .weak I2C1_ER_IRQHandler - .thumb_set I2C1_ER_IRQHandler,Default_Handler - - .weak I2C3_EV_IRQHandler - .thumb_set I2C3_EV_IRQHandler,Default_Handler - - .weak I2C3_ER_IRQHandler - .thumb_set I2C3_ER_IRQHandler,Default_Handler - - .weak SPI1_IRQHandler - .thumb_set SPI1_IRQHandler,Default_Handler - - .weak SPI2_IRQHandler - .thumb_set SPI2_IRQHandler,Default_Handler - - .weak USART1_IRQHandler - .thumb_set USART1_IRQHandler,Default_Handler - - .weak LPUART1_IRQHandler - .thumb_set LPUART1_IRQHandler,Default_Handler - - .weak SAI1_IRQHandler - .thumb_set SAI1_IRQHandler,Default_Handler - - .weak TSC_IRQHandler - .thumb_set TSC_IRQHandler,Default_Handler - - .weak EXTI15_10_IRQHandler - .thumb_set EXTI15_10_IRQHandler,Default_Handler - - .weak RTC_Alarm_IRQHandler - .thumb_set RTC_Alarm_IRQHandler,Default_Handler - - .weak CRS_IRQHandler - .thumb_set CRS_IRQHandler,Default_Handler - - .weak PWR_SOTF_BLEACT_802ACT_RFPHASE_IRQHandler - .thumb_set PWR_SOTF_BLEACT_802ACT_RFPHASE_IRQHandler,Default_Handler - - .weak IPCC_C1_RX_IRQHandler - .thumb_set IPCC_C1_RX_IRQHandler,Default_Handler - - .weak IPCC_C1_TX_IRQHandler - .thumb_set IPCC_C1_TX_IRQHandler,Default_Handler - - .weak HSEM_IRQHandler - .thumb_set HSEM_IRQHandler,Default_Handler - - .weak LPTIM1_IRQHandler - .thumb_set LPTIM1_IRQHandler,Default_Handler - - .weak LPTIM2_IRQHandler - .thumb_set LPTIM2_IRQHandler,Default_Handler - - .weak LCD_IRQHandler - .thumb_set LCD_IRQHandler,Default_Handler - - .weak QUADSPI_IRQHandler - .thumb_set QUADSPI_IRQHandler,Default_Handler - - .weak AES1_IRQHandler - .thumb_set AES1_IRQHandler,Default_Handler - - .weak AES2_IRQHandler - .thumb_set AES2_IRQHandler,Default_Handler - - .weak RNG_IRQHandler - .thumb_set RNG_IRQHandler,Default_Handler - - .weak FPU_IRQHandler - .thumb_set FPU_IRQHandler,Default_Handler - - .weak DMA2_Channel1_IRQHandler - .thumb_set DMA2_Channel1_IRQHandler,Default_Handler - - .weak DMA2_Channel2_IRQHandler - .thumb_set DMA2_Channel2_IRQHandler,Default_Handler - - .weak DMA2_Channel3_IRQHandler - .thumb_set DMA2_Channel3_IRQHandler,Default_Handler - - .weak DMA2_Channel4_IRQHandler - .thumb_set DMA2_Channel4_IRQHandler,Default_Handler - - .weak DMA2_Channel5_IRQHandler - .thumb_set DMA2_Channel5_IRQHandler,Default_Handler - - .weak DMA2_Channel6_IRQHandler - .thumb_set DMA2_Channel6_IRQHandler,Default_Handler - - .weak DMA2_Channel7_IRQHandler - .thumb_set DMA2_Channel7_IRQHandler,Default_Handler - - .weak DMAMUX1_OVR_IRQHandler - .thumb_set DMAMUX1_OVR_IRQHandler,Default_Handler - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +/** + ****************************************************************************** + * @file startup_stm32wb55xx_cm4.s + * @author MCD Application Team + * @brief STM32WB55xx devices vector table GCC toolchain. + * This module performs: + * - Set the initial SP + * - Set the initial PC == Reset_Handler, + * - Set the vector table entries with the exceptions ISR address + * - Branches to main in the C library (which eventually + * calls main()). + * After Reset the Cortex-M4 processor is in Thread mode, + * priority is Privileged, and the Stack is set to Main. + ****************************************************************************** + * @attention + * + * Copyright (c) 2019-2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + + .syntax unified + .cpu cortex-m4 + .fpu softvfp + .thumb + +.global g_pfnVectors +.global Default_Handler + +/* start address for the initialization values of the .data section. +defined in linker script */ +.word _sidata +/* start address for the .data section. defined in linker script */ +.word _sdata +/* end address for the .data section. defined in linker script */ +.word _edata +/* start address for the .bss section. defined in linker script */ +.word _sbss +/* end address for the .bss section. defined in linker script */ +.word _ebss +/* start address for the .MB_MEM2 section. defined in linker script */ +.word _sMB_MEM2 +/* end address for the .MB_MEM2 section. defined in linker script */ +.word _eMB_MEM2 + +/* INIT_BSS macro is used to fill the specified region [start : end] with zeros */ +.macro INIT_BSS start, end + ldr r0, =\start + ldr r1, =\end + movs r3, #0 + bl LoopFillZerobss +.endm + +/* INIT_DATA macro is used to copy data in the region [start : end] starting from 'src' */ +.macro INIT_DATA start, end, src + ldr r0, =\start + ldr r1, =\end + ldr r2, =\src + movs r3, #0 + bl LoopCopyDataInit +.endm + +.section .text.data_initializers +CopyDataInit: + ldr r4, [r2, r3] + str r4, [r0, r3] + adds r3, r3, #4 + +LoopCopyDataInit: + adds r4, r0, r3 + cmp r4, r1 + bcc CopyDataInit + bx lr + +FillZerobss: + str r3, [r0] + adds r0, r0, #4 + +LoopFillZerobss: + cmp r0, r1 + bcc FillZerobss + bx lr + + .section .text.Reset_Handler + .weak Reset_Handler + .type Reset_Handler, %function +Reset_Handler: + ldr r0, =_estack + mov sp, r0 /* set stack pointer */ +/* Call the clock system intitialization function.*/ + bl SystemInit + +/* Copy the data segment initializers from flash to SRAM */ + INIT_DATA _sdata, _edata, _sidata + +/* Zero fill the bss segments. */ + INIT_BSS _sbss, _ebss + INIT_BSS _sMB_MEM2, _eMB_MEM2 + +/* Call static constructors */ + bl __libc_init_array +/* Call the application s entry point.*/ + bl main + +LoopForever: + b LoopForever + +.size Reset_Handler, .-Reset_Handler + +/** + * @brief This is the code that gets called when the processor receives an + * unexpected interrupt. This simply enters an infinite loop, preserving + * the system state for examination by a debugger. + * + * @param None + * @retval None +*/ + .section .text.Default_Handler,"ax",%progbits +Default_Handler: +Infinite_Loop: + b Infinite_Loop + .size Default_Handler, .-Default_Handler +/****************************************************************************** +* +* The minimal vector table for a Cortex-M4. Note that the proper constructs +* must be placed on this to ensure that it ends up at physical address +* 0x0000.0000. +* +******************************************************************************/ + .section .isr_vector,"a",%progbits + .type g_pfnVectors, %object + .size g_pfnVectors, .-g_pfnVectors + + +g_pfnVectors: + .word _estack + .word Reset_Handler + .word NMI_Handler + .word HardFault_Handler + .word MemManage_Handler + .word BusFault_Handler + .word UsageFault_Handler + .word 0 + .word 0 + .word 0 + .word 0 + .word SVC_Handler + .word DebugMon_Handler + .word 0 + .word PendSV_Handler + .word SysTick_Handler + .word WWDG_IRQHandler + .word PVD_PVM_IRQHandler + .word TAMP_STAMP_LSECSS_IRQHandler + .word RTC_WKUP_IRQHandler + .word FLASH_IRQHandler + .word RCC_IRQHandler + .word EXTI0_IRQHandler + .word EXTI1_IRQHandler + .word EXTI2_IRQHandler + .word EXTI3_IRQHandler + .word EXTI4_IRQHandler + .word DMA1_Channel1_IRQHandler + .word DMA1_Channel2_IRQHandler + .word DMA1_Channel3_IRQHandler + .word DMA1_Channel4_IRQHandler + .word DMA1_Channel5_IRQHandler + .word DMA1_Channel6_IRQHandler + .word DMA1_Channel7_IRQHandler + .word ADC1_IRQHandler + .word USB_HP_IRQHandler + .word USB_LP_IRQHandler + .word C2SEV_PWR_C2H_IRQHandler + .word COMP_IRQHandler + .word EXTI9_5_IRQHandler + .word TIM1_BRK_IRQHandler + .word TIM1_UP_TIM16_IRQHandler + .word TIM1_TRG_COM_TIM17_IRQHandler + .word TIM1_CC_IRQHandler + .word TIM2_IRQHandler + .word PKA_IRQHandler + .word I2C1_EV_IRQHandler + .word I2C1_ER_IRQHandler + .word I2C3_EV_IRQHandler + .word I2C3_ER_IRQHandler + .word SPI1_IRQHandler + .word SPI2_IRQHandler + .word USART1_IRQHandler + .word LPUART1_IRQHandler + .word SAI1_IRQHandler + .word TSC_IRQHandler + .word EXTI15_10_IRQHandler + .word RTC_Alarm_IRQHandler + .word CRS_IRQHandler + .word PWR_SOTF_BLEACT_802ACT_RFPHASE_IRQHandler + .word IPCC_C1_RX_IRQHandler + .word IPCC_C1_TX_IRQHandler + .word HSEM_IRQHandler + .word LPTIM1_IRQHandler + .word LPTIM2_IRQHandler + .word LCD_IRQHandler + .word QUADSPI_IRQHandler + .word AES1_IRQHandler + .word AES2_IRQHandler + .word RNG_IRQHandler + .word FPU_IRQHandler + .word DMA2_Channel1_IRQHandler + .word DMA2_Channel2_IRQHandler + .word DMA2_Channel3_IRQHandler + .word DMA2_Channel4_IRQHandler + .word DMA2_Channel5_IRQHandler + .word DMA2_Channel6_IRQHandler + .word DMA2_Channel7_IRQHandler + .word DMAMUX1_OVR_IRQHandler + +/******************************************************************************* +* +* Provide weak aliases for each Exception handler to the Default_Handler. +* As they are weak aliases, any function with the same name will override +* this definition. +* +*******************************************************************************/ + .weak NMI_Handler + .thumb_set NMI_Handler,Default_Handler + + .weak HardFault_Handler + .thumb_set HardFault_Handler,Default_Handler + + .weak MemManage_Handler + .thumb_set MemManage_Handler,Default_Handler + + .weak BusFault_Handler + .thumb_set BusFault_Handler,Default_Handler + + .weak UsageFault_Handler + .thumb_set UsageFault_Handler,Default_Handler + + .weak SVC_Handler + .thumb_set SVC_Handler,Default_Handler + + .weak DebugMon_Handler + .thumb_set DebugMon_Handler,Default_Handler + + .weak PendSV_Handler + .thumb_set PendSV_Handler,Default_Handler + + .weak SysTick_Handler + .thumb_set SysTick_Handler,Default_Handler + + .weak WWDG_IRQHandler + .thumb_set WWDG_IRQHandler,Default_Handler + + .weak PVD_PVM_IRQHandler + .thumb_set PVD_PVM_IRQHandler,Default_Handler + + .weak TAMP_STAMP_LSECSS_IRQHandler + .thumb_set TAMP_STAMP_LSECSS_IRQHandler,Default_Handler + + .weak RTC_WKUP_IRQHandler + .thumb_set RTC_WKUP_IRQHandler,Default_Handler + + .weak FLASH_IRQHandler + .thumb_set FLASH_IRQHandler,Default_Handler + + .weak RCC_IRQHandler + .thumb_set RCC_IRQHandler,Default_Handler + + .weak EXTI0_IRQHandler + .thumb_set EXTI0_IRQHandler,Default_Handler + + .weak EXTI1_IRQHandler + .thumb_set EXTI1_IRQHandler,Default_Handler + + .weak EXTI2_IRQHandler + .thumb_set EXTI2_IRQHandler,Default_Handler + + .weak EXTI3_IRQHandler + .thumb_set EXTI3_IRQHandler,Default_Handler + + .weak EXTI4_IRQHandler + .thumb_set EXTI4_IRQHandler,Default_Handler + + .weak DMA1_Channel1_IRQHandler + .thumb_set DMA1_Channel1_IRQHandler,Default_Handler + + .weak DMA1_Channel2_IRQHandler + .thumb_set DMA1_Channel2_IRQHandler,Default_Handler + + .weak DMA1_Channel3_IRQHandler + .thumb_set DMA1_Channel3_IRQHandler,Default_Handler + + .weak DMA1_Channel4_IRQHandler + .thumb_set DMA1_Channel4_IRQHandler,Default_Handler + + .weak DMA1_Channel5_IRQHandler + .thumb_set DMA1_Channel5_IRQHandler,Default_Handler + + .weak DMA1_Channel6_IRQHandler + .thumb_set DMA1_Channel6_IRQHandler,Default_Handler + + .weak DMA1_Channel7_IRQHandler + .thumb_set DMA1_Channel7_IRQHandler,Default_Handler + + .weak ADC1_IRQHandler + .thumb_set ADC1_IRQHandler,Default_Handler + + .weak USB_HP_IRQHandler + .thumb_set USB_HP_IRQHandler,Default_Handler + + .weak USB_LP_IRQHandler + .thumb_set USB_LP_IRQHandler,Default_Handler + + .weak C2SEV_PWR_C2H_IRQHandler + .thumb_set C2SEV_PWR_C2H_IRQHandler,Default_Handler + + .weak COMP_IRQHandler + .thumb_set COMP_IRQHandler,Default_Handler + + .weak EXTI9_5_IRQHandler + .thumb_set EXTI9_5_IRQHandler,Default_Handler + + .weak TIM1_BRK_IRQHandler + .thumb_set TIM1_BRK_IRQHandler,Default_Handler + + .weak TIM1_UP_TIM16_IRQHandler + .thumb_set TIM1_UP_TIM16_IRQHandler,Default_Handler + + .weak TIM1_TRG_COM_TIM17_IRQHandler + .thumb_set TIM1_TRG_COM_TIM17_IRQHandler,Default_Handler + + .weak TIM1_CC_IRQHandler + .thumb_set TIM1_CC_IRQHandler,Default_Handler + + .weak TIM2_IRQHandler + .thumb_set TIM2_IRQHandler,Default_Handler + + .weak PKA_IRQHandler + .thumb_set PKA_IRQHandler,Default_Handler + + .weak I2C1_EV_IRQHandler + .thumb_set I2C1_EV_IRQHandler,Default_Handler + + .weak I2C1_ER_IRQHandler + .thumb_set I2C1_ER_IRQHandler,Default_Handler + + .weak I2C3_EV_IRQHandler + .thumb_set I2C3_EV_IRQHandler,Default_Handler + + .weak I2C3_ER_IRQHandler + .thumb_set I2C3_ER_IRQHandler,Default_Handler + + .weak SPI1_IRQHandler + .thumb_set SPI1_IRQHandler,Default_Handler + + .weak SPI2_IRQHandler + .thumb_set SPI2_IRQHandler,Default_Handler + + .weak USART1_IRQHandler + .thumb_set USART1_IRQHandler,Default_Handler + + .weak LPUART1_IRQHandler + .thumb_set LPUART1_IRQHandler,Default_Handler + + .weak SAI1_IRQHandler + .thumb_set SAI1_IRQHandler,Default_Handler + + .weak TSC_IRQHandler + .thumb_set TSC_IRQHandler,Default_Handler + + .weak EXTI15_10_IRQHandler + .thumb_set EXTI15_10_IRQHandler,Default_Handler + + .weak RTC_Alarm_IRQHandler + .thumb_set RTC_Alarm_IRQHandler,Default_Handler + + .weak CRS_IRQHandler + .thumb_set CRS_IRQHandler,Default_Handler + + .weak PWR_SOTF_BLEACT_802ACT_RFPHASE_IRQHandler + .thumb_set PWR_SOTF_BLEACT_802ACT_RFPHASE_IRQHandler,Default_Handler + + .weak IPCC_C1_RX_IRQHandler + .thumb_set IPCC_C1_RX_IRQHandler,Default_Handler + + .weak IPCC_C1_TX_IRQHandler + .thumb_set IPCC_C1_TX_IRQHandler,Default_Handler + + .weak HSEM_IRQHandler + .thumb_set HSEM_IRQHandler,Default_Handler + + .weak LPTIM1_IRQHandler + .thumb_set LPTIM1_IRQHandler,Default_Handler + + .weak LPTIM2_IRQHandler + .thumb_set LPTIM2_IRQHandler,Default_Handler + + .weak LCD_IRQHandler + .thumb_set LCD_IRQHandler,Default_Handler + + .weak QUADSPI_IRQHandler + .thumb_set QUADSPI_IRQHandler,Default_Handler + + .weak AES1_IRQHandler + .thumb_set AES1_IRQHandler,Default_Handler + + .weak AES2_IRQHandler + .thumb_set AES2_IRQHandler,Default_Handler + + .weak RNG_IRQHandler + .thumb_set RNG_IRQHandler,Default_Handler + + .weak FPU_IRQHandler + .thumb_set FPU_IRQHandler,Default_Handler + + .weak DMA2_Channel1_IRQHandler + .thumb_set DMA2_Channel1_IRQHandler,Default_Handler + + .weak DMA2_Channel2_IRQHandler + .thumb_set DMA2_Channel2_IRQHandler,Default_Handler + + .weak DMA2_Channel3_IRQHandler + .thumb_set DMA2_Channel3_IRQHandler,Default_Handler + + .weak DMA2_Channel4_IRQHandler + .thumb_set DMA2_Channel4_IRQHandler,Default_Handler + + .weak DMA2_Channel5_IRQHandler + .thumb_set DMA2_Channel5_IRQHandler,Default_Handler + + .weak DMA2_Channel6_IRQHandler + .thumb_set DMA2_Channel6_IRQHandler,Default_Handler + + .weak DMA2_Channel7_IRQHandler + .thumb_set DMA2_Channel7_IRQHandler,Default_Handler + + .weak DMAMUX1_OVR_IRQHandler + .thumb_set DMAMUX1_OVR_IRQHandler,Default_Handler + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f6/cube/stm32wb55xx_flash_cm4.ld b/firmware/targets/f6/cube/stm32wb55xx_flash_cm4.ld index 226505bf..fc975f4a 100644 --- a/firmware/targets/f6/cube/stm32wb55xx_flash_cm4.ld +++ b/firmware/targets/f6/cube/stm32wb55xx_flash_cm4.ld @@ -56,7 +56,7 @@ _Min_Stack_Size = 0x1000; /* required amount of stack */ MEMORY { FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K -RAM1 (xrw) : ORIGIN = 0x20000004, LENGTH = 0x2FFFC +RAM1 (xrw) : ORIGIN = 0x20000008, LENGTH = 0x2FFF8 RAM_SHARED (xrw) : ORIGIN = 0x20030000, LENGTH = 10K } diff --git a/firmware/targets/f6/furi-hal/furi-hal-clock.c b/firmware/targets/f6/furi-hal/furi-hal-clock.c index 59637ddb..0ed918e3 100644 --- a/firmware/targets/f6/furi-hal/furi-hal-clock.c +++ b/firmware/targets/f6/furi-hal/furi-hal-clock.c @@ -88,6 +88,7 @@ void furi_hal_clock_init() { LL_RCC_SetI2CClockSource(LL_RCC_I2C1_CLKSOURCE_PCLK1); LL_RCC_SetRNGClockSource(LL_RCC_RNG_CLKSOURCE_CLK48); LL_RCC_SetUSBClockSource(LL_RCC_USB_CLKSOURCE_PLLSAI1); + LL_RCC_SetCLK48ClockSource(LL_RCC_CLK48_CLKSOURCE_PLLSAI1); LL_RCC_SetSMPSClockSource(LL_RCC_SMPS_CLKSOURCE_HSE); LL_RCC_SetSMPSPrescaler(LL_RCC_SMPS_DIV_1); LL_RCC_SetRFWKPClockSource(LL_RCC_RFWKP_CLKSOURCE_LSE); diff --git a/firmware/targets/f6/furi-hal/furi-hal-rfid.c b/firmware/targets/f6/furi-hal/furi-hal-rfid.c index 4990c5a9..f4d8ff6b 100644 --- a/firmware/targets/f6/furi-hal/furi-hal-rfid.c +++ b/firmware/targets/f6/furi-hal/furi-hal-rfid.c @@ -9,6 +9,10 @@ #define LFRFID_EMULATE_TIM htim2 #define LFRFID_EMULATE_CHANNEL TIM_CHANNEL_3 +void furi_hal_rfid_init() { + furi_hal_rfid_pins_reset(); +} + void furi_hal_rfid_pins_reset() { // ibutton bus disable furi_hal_ibutton_stop(); diff --git a/firmware/targets/f6/furi-hal/furi-hal.c b/firmware/targets/f6/furi-hal/furi-hal.c index 3dc94a50..eebe1423 100644 --- a/firmware/targets/f6/furi-hal/furi-hal.c +++ b/firmware/targets/f6/furi-hal/furi-hal.c @@ -58,6 +58,7 @@ void furi_hal_init() { furi_hal_vibro_init(); furi_hal_subghz_init(); furi_hal_nfc_init(); + furi_hal_rfid_init(); // FreeRTOS glue furi_hal_os_init(); diff --git a/firmware/targets/f6/stm32wb55xx_flash_cm4_boot.ld b/firmware/targets/f6/stm32wb55xx_flash_cm4_boot.ld index f87127cc..6d55107e 100644 --- a/firmware/targets/f6/stm32wb55xx_flash_cm4_boot.ld +++ b/firmware/targets/f6/stm32wb55xx_flash_cm4_boot.ld @@ -56,7 +56,7 @@ _Min_Stack_Size = 0x1000; /* required amount of stack */ MEMORY { FLASH (rx) : ORIGIN = 0x08008000, LENGTH = 992K -RAM1 (xrw) : ORIGIN = 0x20000004, LENGTH = 0x2FFFC +RAM1 (xrw) : ORIGIN = 0x20000008, LENGTH = 0x2FFF8 RAM_SHARED (xrw) : ORIGIN = 0x20030000, LENGTH = 10K } diff --git a/firmware/targets/f6/stm32wb55xx_flash_cm4_no_boot.ld b/firmware/targets/f6/stm32wb55xx_flash_cm4_no_boot.ld index ac7a1015..c03809f3 100644 --- a/firmware/targets/f6/stm32wb55xx_flash_cm4_no_boot.ld +++ b/firmware/targets/f6/stm32wb55xx_flash_cm4_no_boot.ld @@ -56,7 +56,7 @@ _Min_Stack_Size = 0x1000; /* required amount of stack */ MEMORY { FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K -RAM1 (xrw) : ORIGIN = 0x20000004, LENGTH = 0x2FFFC +RAM1 (xrw) : ORIGIN = 0x20000008, LENGTH = 0x2FFF8 RAM_SHARED (xrw) : ORIGIN = 0x20030000, LENGTH = 10K } diff --git a/firmware/targets/f7/Inc/FreeRTOSConfig.h b/firmware/targets/f7/Inc/FreeRTOSConfig.h new file mode 100644 index 00000000..1e32e894 --- /dev/null +++ b/firmware/targets/f7/Inc/FreeRTOSConfig.h @@ -0,0 +1,180 @@ +/* USER CODE BEGIN Header */ +/* + * FreeRTOS Kernel V10.2.1 + * Portion Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Portion Copyright (C) 2019 StMicroelectronics, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ +/* USER CODE END Header */ + +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +/*----------------------------------------------------------- + * Application specific definitions. + * + * These definitions should be adjusted for your particular hardware and + * application requirements. + * + * These parameters and more are described within the 'configuration' section of the + * FreeRTOS API documentation available on the FreeRTOS.org web site. + * + * See http://www.freertos.org/a00110.html + *----------------------------------------------------------*/ + +/* USER CODE BEGIN Includes */ +/* Section where include file can be added */ +/* USER CODE END Includes */ + +/* Ensure definitions are only used by the compiler, and not by the assembler. */ +#if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__) + #include + extern uint32_t SystemCoreClock; +#endif +#ifndef CMSIS_device_header +#define CMSIS_device_header "stm32wbxx.h" +#endif /* CMSIS_device_header */ + +#define configENABLE_FPU 1 +#define configENABLE_MPU 1 + +#define configUSE_PREEMPTION 1 +#define configSUPPORT_STATIC_ALLOCATION 0 +#define configSUPPORT_DYNAMIC_ALLOCATION 1 +#define configUSE_IDLE_HOOK 0 +#define configUSE_TICK_HOOK 0 +#define configCPU_CLOCK_HZ ( SystemCoreClock ) +#define configTICK_RATE_HZ ((TickType_t)1024) +#define configMAX_PRIORITIES ( 56 ) +#define configMINIMAL_STACK_SIZE ((uint16_t)128) +/* Heap size determined automatically by linker */ +// #define configTOTAL_HEAP_SIZE ((size_t)0) +#define configMAX_TASK_NAME_LEN ( 16 ) +#define configGENERATE_RUN_TIME_STATS 0 +#define configUSE_TRACE_FACILITY 1 +#define configUSE_16_BIT_TICKS 0 +#define configUSE_MUTEXES 1 +#define configQUEUE_REGISTRY_SIZE 8 +#define configCHECK_FOR_STACK_OVERFLOW 1 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configENABLE_BACKWARD_COMPATIBILITY 0 +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 +#define configUSE_TICKLESS_IDLE 2 +#define configRECORD_STACK_HIGH_ADDRESS 1 +#define configUSE_NEWLIB_REENTRANT 0 +/* USER CODE BEGIN MESSAGE_BUFFER_LENGTH_TYPE */ +/* Defaults to size_t for backward compatibility, but can be changed + if lengths will always be less than the number of bytes in a size_t. */ +#define configMESSAGE_BUFFER_LENGTH_TYPE size_t +#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 1 +#define configEXPECTED_IDLE_TIME_BEFORE_SLEEP 8 +/* USER CODE END MESSAGE_BUFFER_LENGTH_TYPE */ + +/* Co-routine definitions. */ +#define configUSE_CO_ROUTINES 0 +#define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) + +/* Software timer definitions. */ +#define configUSE_TIMERS 1 +#define configTIMER_TASK_PRIORITY ( 2 ) +#define configTIMER_QUEUE_LENGTH 32 +#define configTIMER_TASK_STACK_DEPTH 256 + +/* Set the following definitions to 1 to include the API function, or zero +to exclude the API function. */ +#define INCLUDE_eTaskGetState 1 +#define INCLUDE_uxTaskGetStackHighWaterMark 1 +#define INCLUDE_uxTaskPriorityGet 1 +#define INCLUDE_vTaskCleanUpResources 0 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_vTaskSuspend 1 +#define INCLUDE_xQueueGetMutexHolder 1 +#define INCLUDE_xTaskGetCurrentTaskHandle 1 +#define INCLUDE_xTaskGetSchedulerState 1 +#define INCLUDE_xTimerPendFunctionCall 1 + +/* CMSIS-RTOS V2 flags */ +#define configUSE_OS2_THREAD_SUSPEND_RESUME 1 +#define configUSE_OS2_THREAD_ENUMERATE 1 +#define configUSE_OS2_EVENTFLAGS_FROM_ISR 1 +#define configUSE_OS2_THREAD_FLAGS 1 +#define configUSE_OS2_TIMER 1 +#define configUSE_OS2_MUTEX 1 + +/* + * The CMSIS-RTOS V2 FreeRTOS wrapper is dependent on the heap implementation used + * by the application thus the correct define need to be enabled below + */ +#define USE_FreeRTOS_HEAP_4 + +/* Cortex-M specific definitions. */ +#ifdef __NVIC_PRIO_BITS + /* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */ + #define configPRIO_BITS __NVIC_PRIO_BITS +#else + #define configPRIO_BITS 4 +#endif + +/* The lowest interrupt priority that can be used in a call to a "set priority" +function. */ +#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 15 + +/* The highest interrupt priority that can be used by any interrupt service +routine that makes calls to interrupt safe FreeRTOS API functions. DO NOT CALL +INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER +PRIORITY THAN THIS! (higher priorities are lower numeric values. */ +#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5 + +/* Interrupt priorities used by the kernel port layer itself. These are generic +to all Cortex-M ports, and do not rely on any particular library functions. */ +#define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) ) +/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!! +See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */ +#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) ) + +/* Normal assert() semantics without relying on the provision of an assert.h +header file. */ +/* USER CODE BEGIN 1 */ +#define configASSERT( x ) if ((x) == 0) {taskDISABLE_INTERRUPTS(); asm("bkpt 1"); for( ;; );} +/* USER CODE END 1 */ + +/* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS +standard names. */ +#define vPortSVCHandler SVC_Handler +#define xPortPendSVHandler PendSV_Handler + +/* IMPORTANT: After 10.3.1 update, Systick_Handler comes from NVIC (if SYS timebase = systick), otherwise from cmsis_os2.c */ + +#define USE_CUSTOM_SYSTICK_HANDLER_IMPLEMENTATION 1 + +/* USER CODE BEGIN Defines */ +/* Section where parameter definitions can be added (for instance, to override default ones in FreeRTOS.h) */ +#define configOVERRIDE_DEFAULT_TICK_CONFIGURATION 1 /* required only for Keil but does not hurt otherwise */ +/* USER CODE END Defines */ + +#endif /* FREERTOS_CONFIG_H */ diff --git a/firmware/targets/f7/Inc/aes.h b/firmware/targets/f7/Inc/aes.h new file mode 100644 index 00000000..bde8ad5a --- /dev/null +++ b/firmware/targets/f7/Inc/aes.h @@ -0,0 +1,54 @@ +/** + ****************************************************************************** + * @file aes.h + * @brief This file contains all the function prototypes for + * the aes.c file + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __AES_H__ +#define __AES_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "main.h" + +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +extern CRYP_HandleTypeDef hcryp1; +extern CRYP_HandleTypeDef hcryp2; + +/* USER CODE BEGIN Private defines */ + +/* USER CODE END Private defines */ + +void MX_AES1_Init(void); +void MX_AES2_Init(void); + +/* USER CODE BEGIN Prototypes */ + +/* USER CODE END Prototypes */ + +#ifdef __cplusplus +} +#endif + +#endif /* __AES_H__ */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/Inc/comp.h b/firmware/targets/f7/Inc/comp.h new file mode 100644 index 00000000..5cc7f16e --- /dev/null +++ b/firmware/targets/f7/Inc/comp.h @@ -0,0 +1,52 @@ +/** + ****************************************************************************** + * @file comp.h + * @brief This file contains all the function prototypes for + * the comp.c file + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __COMP_H__ +#define __COMP_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "main.h" + +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +extern COMP_HandleTypeDef hcomp1; + +/* USER CODE BEGIN Private defines */ + +/* USER CODE END Private defines */ + +void MX_COMP1_Init(void); + +/* USER CODE BEGIN Prototypes */ + +/* USER CODE END Prototypes */ + +#ifdef __cplusplus +} +#endif + +#endif /* __COMP_H__ */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/Inc/gpio.h b/firmware/targets/f7/Inc/gpio.h new file mode 100644 index 00000000..6b6fe6fb --- /dev/null +++ b/firmware/targets/f7/Inc/gpio.h @@ -0,0 +1,49 @@ +/** + ****************************************************************************** + * @file gpio.h + * @brief This file contains all the function prototypes for + * the gpio.c file + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __GPIO_H__ +#define __GPIO_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "main.h" + +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +/* USER CODE BEGIN Private defines */ + +/* USER CODE END Private defines */ + +void MX_GPIO_Init(void); + +/* USER CODE BEGIN Prototypes */ + +/* USER CODE END Prototypes */ + +#ifdef __cplusplus +} +#endif +#endif /*__ GPIO_H__ */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/Inc/main.h b/firmware/targets/f7/Inc/main.h new file mode 100644 index 00000000..7462a3ba --- /dev/null +++ b/firmware/targets/f7/Inc/main.h @@ -0,0 +1,149 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stm32wbxx_hal.h" + +void Error_Handler(void); + +#define BUTTON_BACK_EXTI_IRQn EXTI15_10_IRQn +#define BUTTON_BACK_GPIO_Port GPIOC +#define BUTTON_BACK_Pin GPIO_PIN_13 +#define BUTTON_DOWN_EXTI_IRQn EXTI6_IRQn +#define BUTTON_DOWN_GPIO_Port GPIOC +#define BUTTON_DOWN_Pin GPIO_PIN_6 +#define BUTTON_LEFT_EXTI_IRQn EXTI15_10_IRQn +#define BUTTON_LEFT_GPIO_Port GPIOB +#define BUTTON_LEFT_Pin GPIO_PIN_11 +#define BUTTON_OK_EXTI_IRQn EXTI3_IRQn +#define BUTTON_OK_GPIO_Port GPIOH +#define BUTTON_OK_Pin GPIO_PIN_3 +#define BUTTON_RIGHT_EXTI_IRQn EXTI15_10_IRQn +#define BUTTON_RIGHT_GPIO_Port GPIOB +#define BUTTON_RIGHT_Pin GPIO_PIN_12 +#define BUTTON_UP_EXTI_IRQn EXTI15_10_IRQn +#define BUTTON_UP_GPIO_Port GPIOB +#define BUTTON_UP_Pin GPIO_PIN_10 + +#define CC1101_CS_GPIO_Port GPIOD +#define CC1101_CS_Pin GPIO_PIN_0 +#define CC1101_G0_GPIO_Port GPIOA +#define CC1101_G0_Pin GPIO_PIN_1 + +#define DISPLAY_CS_GPIO_Port GPIOC +#define DISPLAY_CS_Pin GPIO_PIN_11 +#define DISPLAY_DI_GPIO_Port GPIOB +#define DISPLAY_DI_Pin GPIO_PIN_1 +#define DISPLAY_RST_GPIO_Port GPIOB +#define DISPLAY_RST_Pin GPIO_PIN_0 + +#define IR_RX_GPIO_Port GPIOA +#define IR_RX_Pin GPIO_PIN_0 +#define IR_TX_GPIO_Port GPIOB +#define IR_TX_Pin GPIO_PIN_9 + +#define NFC_CS_GPIO_Port GPIOE +#define NFC_CS_Pin GPIO_PIN_4 + +#define PA4_GPIO_Port GPIOA +#define PA4_Pin GPIO_PIN_4 +#define PA6_GPIO_Port GPIOA +#define PA6_Pin GPIO_PIN_6 +#define PA7_GPIO_Port GPIOA +#define PA7_Pin GPIO_PIN_7 +#define PB2_GPIO_Port GPIOB +#define PB2_Pin GPIO_PIN_2 +#define PB3_GPIO_Port GPIOB +#define PB3_Pin GPIO_PIN_3 +#define PC0_GPIO_Port GPIOC +#define PC0_Pin GPIO_PIN_0 +#define PC1_GPIO_Port GPIOC +#define PC1_Pin GPIO_PIN_1 +#define PC3_GPIO_Port GPIOC +#define PC3_Pin GPIO_PIN_3 + +#define PERIPH_POWER_GPIO_Port GPIOA +#define PERIPH_POWER_Pin GPIO_PIN_3 + +#define QUARTZ_32MHZ_IN_GPIO_Port GPIOC +#define QUARTZ_32MHZ_IN_Pin GPIO_PIN_14 +#define QUARTZ_32MHZ_OUT_GPIO_Port GPIOC +#define QUARTZ_32MHZ_OUT_Pin GPIO_PIN_15 + +#define RFID_OUT_GPIO_Port GPIOB +#define RFID_OUT_Pin GPIO_PIN_13 +#define RFID_PULL_GPIO_Port GPIOA +#define RFID_PULL_Pin GPIO_PIN_2 +#define RFID_RF_IN_GPIO_Port GPIOC +#define RFID_RF_IN_Pin GPIO_PIN_5 +#define RFID_CARRIER_GPIO_Port GPIOA +#define RFID_CARRIER_Pin GPIO_PIN_15 + +#define RF_SW_0_GPIO_Port GPIOC +#define RF_SW_0_Pin GPIO_PIN_4 + +#define SD_CD_GPIO_Port GPIOC +#define SD_CD_Pin GPIO_PIN_10 +#define SD_CS_GPIO_Port GPIOC +#define SD_CS_Pin GPIO_PIN_12 + +#define SPEAKER_GPIO_Port GPIOB +#define SPEAKER_Pin GPIO_PIN_8 + +#define VIBRO_GPIO_Port GPIOA +#define VIBRO_Pin GPIO_PIN_8 + +#define iBTN_GPIO_Port GPIOB +#define iBTN_Pin GPIO_PIN_14 + +#define USART1_TX_Pin GPIO_PIN_6 +#define USART1_TX_Port GPIOB +#define USART1_RX_Pin GPIO_PIN_7 +#define USART1_RX_Port GPIOB + +#define SPI_D_MISO_GPIO_Port GPIOC +#define SPI_D_MISO_Pin GPIO_PIN_2 +#define SPI_D_MOSI_GPIO_Port GPIOB +#define SPI_D_MOSI_Pin GPIO_PIN_15 +#define SPI_D_SCK_GPIO_Port GPIOD +#define SPI_D_SCK_Pin GPIO_PIN_1 + +#define SPI_R_MISO_GPIO_Port GPIOB +#define SPI_R_MISO_Pin GPIO_PIN_4 +#define SPI_R_MOSI_GPIO_Port GPIOB +#define SPI_R_MOSI_Pin GPIO_PIN_5 +#define SPI_R_SCK_GPIO_Port GPIOA +#define SPI_R_SCK_Pin GPIO_PIN_5 + +extern TIM_HandleTypeDef htim1; +extern TIM_HandleTypeDef htim2; +extern TIM_HandleTypeDef htim16; + +#define TIM_A htim1 +#define TIM_B htim2 +#define TIM_C htim16 + +#define SPEAKER_TIM htim16 +#define SPEAKER_CH TIM_CHANNEL_1 + +#define LFRFID_TIM htim1 +#define LFRFID_CH TIM_CHANNEL_1 + +#define IRDA_TX_TIM htim1 +#define IRDA_TX_CH TIM_CHANNEL_3 + +// only for reference +// IRDA RX timer dont exist in F2 +// and timer need more data to init (NVIC IRQn to set priority) +#define IRDA_RX_TIM htim2 +#define IRDA_RX_FALLING_CH TIM_CHANNEL_1 +#define IRDA_RX_RISING_CH TIM_CHANNEL_2 + +#define NFC_IRQ_Pin RFID_PULL_Pin +#define NFC_IRQ_GPIO_Port RFID_PULL_GPIO_Port + +#ifdef __cplusplus +} +#endif diff --git a/firmware/targets/f7/Inc/pka.h b/firmware/targets/f7/Inc/pka.h new file mode 100644 index 00000000..377ed010 --- /dev/null +++ b/firmware/targets/f7/Inc/pka.h @@ -0,0 +1,52 @@ +/** + ****************************************************************************** + * @file pka.h + * @brief This file contains all the function prototypes for + * the pka.c file + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __PKA_H__ +#define __PKA_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "main.h" + +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +extern PKA_HandleTypeDef hpka; + +/* USER CODE BEGIN Private defines */ + +/* USER CODE END Private defines */ + +void MX_PKA_Init(void); + +/* USER CODE BEGIN Prototypes */ + +/* USER CODE END Prototypes */ + +#ifdef __cplusplus +} +#endif + +#endif /* __PKA_H__ */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/Inc/rf.h b/firmware/targets/f7/Inc/rf.h new file mode 100644 index 00000000..1796e939 --- /dev/null +++ b/firmware/targets/f7/Inc/rf.h @@ -0,0 +1,50 @@ +/** + ****************************************************************************** + * @file rf.h + * @brief This file contains all the function prototypes for + * the rf.c file + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __RF_H__ +#define __RF_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "main.h" + +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +/* USER CODE BEGIN Private defines */ + +/* USER CODE END Private defines */ + +void MX_RF_Init(void); + +/* USER CODE BEGIN Prototypes */ + +/* USER CODE END Prototypes */ + +#ifdef __cplusplus +} +#endif + +#endif /* __RF_H__ */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/Inc/rng.h b/firmware/targets/f7/Inc/rng.h new file mode 100644 index 00000000..fa121ad1 --- /dev/null +++ b/firmware/targets/f7/Inc/rng.h @@ -0,0 +1,52 @@ +/** + ****************************************************************************** + * @file rng.h + * @brief This file contains all the function prototypes for + * the rng.c file + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __RNG_H__ +#define __RNG_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "main.h" + +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +extern RNG_HandleTypeDef hrng; + +/* USER CODE BEGIN Private defines */ + +/* USER CODE END Private defines */ + +void MX_RNG_Init(void); + +/* USER CODE BEGIN Prototypes */ + +/* USER CODE END Prototypes */ + +#ifdef __cplusplus +} +#endif + +#endif /* __RNG_H__ */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/Inc/rtc.h b/firmware/targets/f7/Inc/rtc.h new file mode 100644 index 00000000..3e961b71 --- /dev/null +++ b/firmware/targets/f7/Inc/rtc.h @@ -0,0 +1,52 @@ +/** + ****************************************************************************** + * @file rtc.h + * @brief This file contains all the function prototypes for + * the rtc.c file + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __RTC_H__ +#define __RTC_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "main.h" + +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +extern RTC_HandleTypeDef hrtc; + +/* USER CODE BEGIN Private defines */ + +/* USER CODE END Private defines */ + +void MX_RTC_Init(void); + +/* USER CODE BEGIN Prototypes */ + +/* USER CODE END Prototypes */ + +#ifdef __cplusplus +} +#endif + +#endif /* __RTC_H__ */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/Inc/stm32wbxx_hal_conf.h b/firmware/targets/f7/Inc/stm32wbxx_hal_conf.h new file mode 100644 index 00000000..1c96d8cd --- /dev/null +++ b/firmware/targets/f7/Inc/stm32wbxx_hal_conf.h @@ -0,0 +1,353 @@ +/** + ****************************************************************************** + * @file stm32wbxx_hal_conf.h + * @author MCD Application Team + * @brief HAL configuration file. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2019 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32WBxx_HAL_CONF_H +#define __STM32WBxx_HAL_CONF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +/* ########################## Module Selection ############################## */ +/** + * @brief This is the list of modules to be used in the HAL driver + */ +#define HAL_MODULE_ENABLED +/*#define HAL_ADC_MODULE_ENABLED */ +#define HAL_CRYP_MODULE_ENABLED +#define HAL_COMP_MODULE_ENABLED +/*#define HAL_CRC_MODULE_ENABLED */ +#define HAL_HSEM_MODULE_ENABLED +/*#define HAL_I2C_MODULE_ENABLED */ +/*#define HAL_IPCC_MODULE_ENABLED */ +/*#define HAL_IRDA_MODULE_ENABLED */ +/*#define HAL_IWDG_MODULE_ENABLED */ +/*#define HAL_LCD_MODULE_ENABLED */ +/*#define HAL_LPTIM_MODULE_ENABLED */ +#define HAL_PCD_MODULE_ENABLED +#define HAL_PKA_MODULE_ENABLED +/*#define HAL_QSPI_MODULE_ENABLED */ +#define HAL_RNG_MODULE_ENABLED +#define HAL_RTC_MODULE_ENABLED +/*#define HAL_SAI_MODULE_ENABLED */ +/*#define HAL_SMBUS_MODULE_ENABLED */ +/*#define HAL_SMARTCARD_MODULE_ENABLED */ +/*#define HAL_SPI_MODULE_ENABLED */ +#define HAL_TIM_MODULE_ENABLED +/*#define HAL_TSC_MODULE_ENABLED */ +/*#define HAL_UART_MODULE_ENABLED */ +/*#define HAL_USART_MODULE_ENABLED */ +/*#define HAL_WWDG_MODULE_ENABLED */ +#define HAL_EXTI_MODULE_ENABLED +#define HAL_CORTEX_MODULE_ENABLED +#define HAL_DMA_MODULE_ENABLED +#define HAL_FLASH_MODULE_ENABLED +#define HAL_GPIO_MODULE_ENABLED +#define HAL_PWR_MODULE_ENABLED +#define HAL_RCC_MODULE_ENABLED + +#define USE_HAL_ADC_REGISTER_CALLBACKS 0u +#define USE_HAL_COMP_REGISTER_CALLBACKS 0u +#define USE_HAL_CRYP_REGISTER_CALLBACKS 0u +#define USE_HAL_I2C_REGISTER_CALLBACKS 0u +#define USE_HAL_IRDA_REGISTER_CALLBACKS 0u +#define USE_HAL_LPTIM_REGISTER_CALLBACKS 0u +#define USE_HAL_PCD_REGISTER_CALLBACKS 0u +#define USE_HAL_PKA_REGISTER_CALLBACKS 0u +#define USE_HAL_QSPI_REGISTER_CALLBACKS 0u +#define USE_HAL_RNG_REGISTER_CALLBACKS 0u +#define USE_HAL_RTC_REGISTER_CALLBACKS 0u +#define USE_HAL_SAI_REGISTER_CALLBACKS 0u +#define USE_HAL_SMARTCARD_REGISTER_CALLBACKS 0u +#define USE_HAL_SMBUS_REGISTER_CALLBACKS 0u +#define USE_HAL_SPI_REGISTER_CALLBACKS 0u +#define USE_HAL_TIM_REGISTER_CALLBACKS 0u +#define USE_HAL_TSC_REGISTER_CALLBACKS 0u +#define USE_HAL_UART_REGISTER_CALLBACKS 0u +#define USE_HAL_USART_REGISTER_CALLBACKS 0u +#define USE_HAL_WWDG_REGISTER_CALLBACKS 0u + +/* ########################## Oscillator Values adaptation ####################*/ +/** + * @brief Adjust the value of External High Speed oscillator (HSE) used in your application. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSE is used as system clock source, directly or through the PLL). + */ +#if !defined (HSE_VALUE) +#define HSE_VALUE 32000000U /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +#if !defined (HSE_STARTUP_TIMEOUT) + #define HSE_STARTUP_TIMEOUT ((uint32_t)100) /*!< Time out for HSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief Internal Multiple Speed oscillator (MSI) default value. + * This value is the default MSI range value after Reset. + */ +#if !defined (MSI_VALUE) + #define MSI_VALUE ((uint32_t)4000000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* MSI_VALUE */ + +/** + * @brief Internal High Speed oscillator (HSI) value. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSI is used as system clock source, directly or through the PLL). + */ +#if !defined (HSI_VALUE) +#define HSI_VALUE 16000000U /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI_VALUE */ + +/** + * @brief Internal Low Speed oscillator (LSI1) value. + */ +#if !defined (LSI1_VALUE) + #define LSI1_VALUE ((uint32_t)32000) /*!< LSI1 Typical Value in Hz*/ +#endif /* LSI1_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz + The real value may vary depending on the variations + in voltage and temperature.*/ +/** + * @brief Internal Low Speed oscillator (LSI2) value. + */ +#if !defined (LSI2_VALUE) + #define LSI2_VALUE ((uint32_t)32000) /*!< LSI2 Typical Value in Hz*/ +#endif /* LSI2_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz + The real value may vary depending on the variations + in voltage and temperature.*/ + +/** + * @brief External Low Speed oscillator (LSE) value. + * This value is used by the UART, RTC HAL module to compute the system frequency + */ +#if !defined (LSE_VALUE) +#define LSE_VALUE 32768U /*!< Value of the External oscillator in Hz*/ +#endif /* LSE_VALUE */ + +/** + * @brief Internal Multiple Speed oscillator (HSI48) default value. + * This value is the default HSI48 range value after Reset. + */ +#if !defined (HSI48_VALUE) + #define HSI48_VALUE ((uint32_t)48000000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI48_VALUE */ + +#if !defined (LSE_STARTUP_TIMEOUT) +#define LSE_STARTUP_TIMEOUT 1000U /*!< Time out for LSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief External clock source for SAI1 peripheral + * This value is used by the RCC HAL module to compute the SAI1 & SAI2 clock source + * frequency. + */ +#if !defined (EXTERNAL_SAI1_CLOCK_VALUE) + #define EXTERNAL_SAI1_CLOCK_VALUE ((uint32_t)2097000) /*!< Value of the SAI1 External clock source in Hz*/ +#endif /* EXTERNAL_SAI1_CLOCK_VALUE */ + +/* Tip: To avoid modifying this file each time you need to use different HSE, + === you can define the HSE value in your toolchain compiler preprocessor. */ + +/* ########################### System Configuration ######################### */ +/** + * @brief This is the HAL system configuration section + */ + +#define VDD_VALUE 3300U /*!< Value of VDD in mv */ +#define TICK_INT_PRIORITY 0U /*!< tick interrupt priority */ +#define USE_RTOS 0U +#define PREFETCH_ENABLE 1U +#define INSTRUCTION_CACHE_ENABLE 1U +#define DATA_CACHE_ENABLE 1U + +/* ########################## Assert Selection ############################## */ +/** + * @brief Uncomment the line below to expanse the "assert_param" macro in the + * HAL drivers code + */ +/* #define USE_FULL_ASSERT 1U */ + +/* ################## SPI peripheral configuration ########################## */ + +/* CRC FEATURE: Use to activate CRC feature inside HAL SPI Driver + * Activated: CRC code is present inside driver + * Deactivated: CRC code cleaned from driver + */ + +#define USE_SPI_CRC 0U + +/* Includes ------------------------------------------------------------------*/ +/** + * @brief Include module's header file + */ +#ifdef HAL_DMA_MODULE_ENABLED + #include "stm32wbxx_hal_dma.h" +#endif /* HAL_DMA_MODULE_ENABLED */ + +#ifdef HAL_ADC_MODULE_ENABLED + #include "stm32wbxx_hal_adc.h" +#endif /* HAL_ADC_MODULE_ENABLED */ + +#ifdef HAL_COMP_MODULE_ENABLED + #include "stm32wbxx_hal_comp.h" +#endif /* HAL_COMP_MODULE_ENABLED */ + +#ifdef HAL_CORTEX_MODULE_ENABLED + #include "stm32wbxx_hal_cortex.h" +#endif /* HAL_CORTEX_MODULE_ENABLED */ + +#ifdef HAL_CRC_MODULE_ENABLED + #include "stm32wbxx_hal_crc.h" +#endif /* HAL_CRC_MODULE_ENABLED */ + +#ifdef HAL_CRYP_MODULE_ENABLED + #include "stm32wbxx_hal_cryp.h" +#endif /* HAL_CRYP_MODULE_ENABLED */ + +#ifdef HAL_EXTI_MODULE_ENABLED + #include "stm32wbxx_hal_exti.h" +#endif /* HAL_EXTI_MODULE_ENABLED */ + +#ifdef HAL_FLASH_MODULE_ENABLED + #include "stm32wbxx_hal_flash.h" +#endif /* HAL_FLASH_MODULE_ENABLED */ + +#ifdef HAL_GPIO_MODULE_ENABLED + #include "stm32wbxx_hal_gpio.h" +#endif /* HAL_GPIO_MODULE_ENABLED */ + +#ifdef HAL_HSEM_MODULE_ENABLED + #include "stm32wbxx_hal_hsem.h" +#endif /* HAL_HSEM_MODULE_ENABLED */ + +#ifdef HAL_I2C_MODULE_ENABLED + #include "stm32wbxx_hal_i2c.h" +#endif /* HAL_I2C_MODULE_ENABLED */ + +#ifdef HAL_IPCC_MODULE_ENABLED + #include "stm32wbxx_hal_ipcc.h" +#endif /* HAL_IPCC_MODULE_ENABLED */ + +#ifdef HAL_IRDA_MODULE_ENABLED + #include "stm32wbxx_hal_irda.h" +#endif /* HAL_IRDA_MODULE_ENABLED */ + +#ifdef HAL_IWDG_MODULE_ENABLED + #include "stm32wbxx_hal_iwdg.h" +#endif /* HAL_IWDG_MODULE_ENABLED */ + +#ifdef HAL_LCD_MODULE_ENABLED + #include "stm32wbxx_hal_lcd.h" +#endif /* HAL_LCD_MODULE_ENABLED */ + +#ifdef HAL_LPTIM_MODULE_ENABLED + #include "stm32wbxx_hal_lptim.h" +#endif /* HAL_LPTIM_MODULE_ENABLED */ + +#ifdef HAL_PCD_MODULE_ENABLED + #include "stm32wbxx_hal_pcd.h" +#endif /* HAL_PCD_MODULE_ENABLED */ + +#ifdef HAL_PKA_MODULE_ENABLED + #include "stm32wbxx_hal_pka.h" +#endif /* HAL_PKA_MODULE_ENABLED */ + +#ifdef HAL_PWR_MODULE_ENABLED + #include "stm32wbxx_hal_pwr.h" +#endif /* HAL_PWR_MODULE_ENABLED */ + +#ifdef HAL_QSPI_MODULE_ENABLED + #include "stm32wbxx_hal_qspi.h" +#endif /* HAL_QSPI_MODULE_ENABLED */ + +#ifdef HAL_RCC_MODULE_ENABLED + #include "stm32wbxx_hal_rcc.h" +#endif /* HAL_RCC_MODULE_ENABLED */ + +#ifdef HAL_RNG_MODULE_ENABLED + #include "stm32wbxx_hal_rng.h" +#endif /* HAL_RNG_MODULE_ENABLED */ + +#ifdef HAL_RTC_MODULE_ENABLED + #include "stm32wbxx_hal_rtc.h" +#endif /* HAL_RTC_MODULE_ENABLED */ + +#ifdef HAL_SAI_MODULE_ENABLED + #include "stm32wbxx_hal_sai.h" +#endif /* HAL_SAI_MODULE_ENABLED */ + +#ifdef HAL_SMARTCARD_MODULE_ENABLED + #include "stm32wbxx_hal_smartcard.h" +#endif /* HAL_SMARTCARD_MODULE_ENABLED */ + +#ifdef HAL_SMBUS_MODULE_ENABLED + #include "stm32wbxx_hal_smbus.h" +#endif /* HAL_SMBUS_MODULE_ENABLED */ + +#ifdef HAL_SPI_MODULE_ENABLED + #include "stm32wbxx_hal_spi.h" +#endif /* HAL_SPI_MODULE_ENABLED */ + +#ifdef HAL_TIM_MODULE_ENABLED + #include "stm32wbxx_hal_tim.h" +#endif /* HAL_TIM_MODULE_ENABLED */ + +#ifdef HAL_TSC_MODULE_ENABLED + #include "stm32wbxx_hal_tsc.h" +#endif /* HAL_TSC_MODULE_ENABLED */ + +#ifdef HAL_UART_MODULE_ENABLED + #include "stm32wbxx_hal_uart.h" +#endif /* HAL_UART_MODULE_ENABLED */ + +#ifdef HAL_USART_MODULE_ENABLED + #include "stm32wbxx_hal_usart.h" +#endif /* HAL_USART_MODULE_ENABLED */ + +#ifdef HAL_WWDG_MODULE_ENABLED + #include "stm32wbxx_hal_wwdg.h" +#endif /* HAL_WWDG_MODULE_ENABLED */ + +/* Exported macro ------------------------------------------------------------*/ +#ifdef USE_FULL_ASSERT +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr If expr is false, it calls assert_failed function + * which reports the name of the source file and the source + * line number of the call that failed. + * If expr is true, it returns no value. + * @retval None + */ + #define assert_param(expr) ((expr) ? (void)0U : assert_failed((uint8_t *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ + void assert_failed(uint8_t* file, uint32_t line); +#else + #define assert_param(expr) ((void)0U) +#endif /* USE_FULL_ASSERT */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32WBxx_HAL_CONF_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/Inc/stm32wbxx_it.h b/firmware/targets/f7/Inc/stm32wbxx_it.h new file mode 100644 index 00000000..1804c941 --- /dev/null +++ b/firmware/targets/f7/Inc/stm32wbxx_it.h @@ -0,0 +1,69 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file stm32wbxx_it.h + * @brief This file contains the headers of the interrupt handlers. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2020 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32WBxx_IT_H +#define __STM32WBxx_IT_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Private includes ----------------------------------------------------------*/ +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +/* Exported types ------------------------------------------------------------*/ +/* USER CODE BEGIN ET */ + +/* USER CODE END ET */ + +/* Exported constants --------------------------------------------------------*/ +/* USER CODE BEGIN EC */ + +/* USER CODE END EC */ + +/* Exported macro ------------------------------------------------------------*/ +/* USER CODE BEGIN EM */ + +/* USER CODE END EM */ + +/* Exported functions prototypes ---------------------------------------------*/ +void SysTick_Handler(void); +void ADC1_IRQHandler(void); +void USB_LP_IRQHandler(void); +void COMP_IRQHandler(void); +void TIM1_UP_TIM16_IRQHandler(void); +void TIM1_TRG_COM_TIM17_IRQHandler(void); +void TIM1_CC_IRQHandler(void); +void TIM2_IRQHandler(void); +void HSEM_IRQHandler(void); +/* USER CODE BEGIN EFP */ + +/* USER CODE END EFP */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32WBxx_IT_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/Inc/tim.h b/firmware/targets/f7/Inc/tim.h new file mode 100644 index 00000000..9d530bce --- /dev/null +++ b/firmware/targets/f7/Inc/tim.h @@ -0,0 +1,58 @@ +/** + ****************************************************************************** + * @file tim.h + * @brief This file contains all the function prototypes for + * the tim.c file + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __TIM_H__ +#define __TIM_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "main.h" + +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +extern TIM_HandleTypeDef htim1; +extern TIM_HandleTypeDef htim2; +extern TIM_HandleTypeDef htim16; + +/* USER CODE BEGIN Private defines */ + +/* USER CODE END Private defines */ + +void MX_TIM1_Init(void); +void MX_TIM2_Init(void); +void MX_TIM16_Init(void); + +void HAL_TIM_MspPostInit(TIM_HandleTypeDef *htim); + +/* USER CODE BEGIN Prototypes */ + +/* USER CODE END Prototypes */ + +#ifdef __cplusplus +} +#endif + +#endif /* __TIM_H__ */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/Src/aes.c b/firmware/targets/f7/Src/aes.c new file mode 100644 index 00000000..1a042e9b --- /dev/null +++ b/firmware/targets/f7/Src/aes.c @@ -0,0 +1,127 @@ +/** + ****************************************************************************** + * @file aes.c + * @brief This file provides code for the configuration + * of the AES instances. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "aes.h" + +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ + +CRYP_HandleTypeDef hcryp1; +__ALIGN_BEGIN static const uint32_t pKeyAES1[4] __ALIGN_END = { + 0x00000000,0x00000000,0x00000000,0x00000000}; +CRYP_HandleTypeDef hcryp2; +__ALIGN_BEGIN static const uint32_t pKeyAES2[4] __ALIGN_END = { + 0x00000000,0x00000000,0x00000000,0x00000000}; + +/* AES1 init function */ +void MX_AES1_Init(void) +{ + + hcryp1.Instance = AES1; + hcryp1.Init.DataType = CRYP_DATATYPE_32B; + hcryp1.Init.KeySize = CRYP_KEYSIZE_128B; + hcryp1.Init.pKey = (uint32_t *)pKeyAES1; + hcryp1.Init.Algorithm = CRYP_AES_ECB; + hcryp1.Init.DataWidthUnit = CRYP_DATAWIDTHUNIT_WORD; + hcryp1.Init.KeyIVConfigSkip = CRYP_KEYIVCONFIG_ALWAYS; + if (HAL_CRYP_Init(&hcryp1) != HAL_OK) + { + Error_Handler(); + } + +} +/* AES2 init function */ +void MX_AES2_Init(void) +{ + + hcryp2.Instance = AES2; + hcryp2.Init.DataType = CRYP_DATATYPE_32B; + hcryp2.Init.KeySize = CRYP_KEYSIZE_128B; + hcryp2.Init.pKey = (uint32_t *)pKeyAES2; + hcryp2.Init.Algorithm = CRYP_AES_ECB; + hcryp2.Init.DataWidthUnit = CRYP_DATAWIDTHUNIT_WORD; + hcryp2.Init.KeyIVConfigSkip = CRYP_KEYIVCONFIG_ALWAYS; + if (HAL_CRYP_Init(&hcryp2) != HAL_OK) + { + Error_Handler(); + } + +} + +void HAL_CRYP_MspInit(CRYP_HandleTypeDef* crypHandle) +{ + + if(crypHandle->Instance==AES1) + { + /* USER CODE BEGIN AES1_MspInit 0 */ + + /* USER CODE END AES1_MspInit 0 */ + /* AES1 clock enable */ + __HAL_RCC_AES1_CLK_ENABLE(); + /* USER CODE BEGIN AES1_MspInit 1 */ + + /* USER CODE END AES1_MspInit 1 */ + } + else if(crypHandle->Instance==AES2) + { + /* USER CODE BEGIN AES2_MspInit 0 */ + + /* USER CODE END AES2_MspInit 0 */ + /* AES2 clock enable */ + __HAL_RCC_AES2_CLK_ENABLE(); + /* USER CODE BEGIN AES2_MspInit 1 */ + + /* USER CODE END AES2_MspInit 1 */ + } +} + +void HAL_CRYP_MspDeInit(CRYP_HandleTypeDef* crypHandle) +{ + + if(crypHandle->Instance==AES1) + { + /* USER CODE BEGIN AES1_MspDeInit 0 */ + + /* USER CODE END AES1_MspDeInit 0 */ + /* Peripheral clock disable */ + __HAL_RCC_AES1_CLK_DISABLE(); + /* USER CODE BEGIN AES1_MspDeInit 1 */ + + /* USER CODE END AES1_MspDeInit 1 */ + } + else if(crypHandle->Instance==AES2) + { + /* USER CODE BEGIN AES2_MspDeInit 0 */ + + /* USER CODE END AES2_MspDeInit 0 */ + /* Peripheral clock disable */ + __HAL_RCC_AES2_CLK_DISABLE(); + /* USER CODE BEGIN AES2_MspDeInit 1 */ + + /* USER CODE END AES2_MspDeInit 1 */ + } +} + +/* USER CODE BEGIN 1 */ + +/* USER CODE END 1 */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/Src/comp.c b/firmware/targets/f7/Src/comp.c new file mode 100644 index 00000000..9401ed34 --- /dev/null +++ b/firmware/targets/f7/Src/comp.c @@ -0,0 +1,103 @@ +/** + ****************************************************************************** + * @file comp.c + * @brief This file provides code for the configuration + * of the COMP instances. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "comp.h" + +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ + +COMP_HandleTypeDef hcomp1; + +/* COMP1 init function */ +void MX_COMP1_Init(void) +{ + + hcomp1.Instance = COMP1; + hcomp1.Init.InputMinus = COMP_INPUT_MINUS_1_4VREFINT; + hcomp1.Init.InputPlus = COMP_INPUT_PLUS_IO1; + hcomp1.Init.OutputPol = COMP_OUTPUTPOL_NONINVERTED; + hcomp1.Init.Hysteresis = COMP_HYSTERESIS_HIGH; + hcomp1.Init.BlankingSrce = COMP_BLANKINGSRC_NONE; + hcomp1.Init.Mode = COMP_POWERMODE_MEDIUMSPEED; + hcomp1.Init.WindowMode = COMP_WINDOWMODE_DISABLE; + hcomp1.Init.TriggerMode = COMP_TRIGGERMODE_IT_RISING_FALLING; + if (HAL_COMP_Init(&hcomp1) != HAL_OK) + { + Error_Handler(); + } + +} + +void HAL_COMP_MspInit(COMP_HandleTypeDef* compHandle) +{ + + GPIO_InitTypeDef GPIO_InitStruct = {0}; + if(compHandle->Instance==COMP1) + { + /* USER CODE BEGIN COMP1_MspInit 0 */ + + /* USER CODE END COMP1_MspInit 0 */ + + __HAL_RCC_GPIOC_CLK_ENABLE(); + /**COMP1 GPIO Configuration + PC5 ------> COMP1_INP + */ + GPIO_InitStruct.Pin = RFID_RF_IN_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = GPIO_NOPULL; + HAL_GPIO_Init(RFID_RF_IN_GPIO_Port, &GPIO_InitStruct); + + /* COMP1 interrupt Init */ + HAL_NVIC_SetPriority(COMP_IRQn, 5, 0); + HAL_NVIC_EnableIRQ(COMP_IRQn); + /* USER CODE BEGIN COMP1_MspInit 1 */ + + /* USER CODE END COMP1_MspInit 1 */ + } +} + +void HAL_COMP_MspDeInit(COMP_HandleTypeDef* compHandle) +{ + + if(compHandle->Instance==COMP1) + { + /* USER CODE BEGIN COMP1_MspDeInit 0 */ + + /* USER CODE END COMP1_MspDeInit 0 */ + + /**COMP1 GPIO Configuration + PC5 ------> COMP1_INP + */ + HAL_GPIO_DeInit(RFID_RF_IN_GPIO_Port, RFID_RF_IN_Pin); + + /* COMP1 interrupt Deinit */ + HAL_NVIC_DisableIRQ(COMP_IRQn); + /* USER CODE BEGIN COMP1_MspDeInit 1 */ + + /* USER CODE END COMP1_MspDeInit 1 */ + } +} + +/* USER CODE BEGIN 1 */ + +/* USER CODE END 1 */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/Src/fatfs/fatfs.c b/firmware/targets/f7/Src/fatfs/fatfs.c new file mode 100644 index 00000000..d52b3d4e --- /dev/null +++ b/firmware/targets/f7/Src/fatfs/fatfs.c @@ -0,0 +1,56 @@ +/** + ****************************************************************************** + * @file fatfs.c + * @brief Code for fatfs applications + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2020 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ + +#include "fatfs.h" + +uint8_t retUSER; /* Return value for USER */ +char USERPath[4]; /* USER logical drive path */ +FATFS USERFatFS; /* File system object for USER logical drive */ +FIL USERFile; /* File object for USER */ + +/* USER CODE BEGIN Variables */ + +/* USER CODE END Variables */ + +void MX_FATFS_Init(void) +{ + /*## FatFS: Link the USER driver ###########################*/ + retUSER = FATFS_LinkDriver(&USER_Driver, USERPath); + + /* USER CODE BEGIN Init */ + /* additional user code for init */ + /* USER CODE END Init */ +} + +/** + * @brief Gets Time from RTC + * @param None + * @retval Time in DWORD + */ +DWORD get_fattime(void) +{ + /* USER CODE BEGIN get_fattime */ + return 0; + /* USER CODE END get_fattime */ +} + +/* USER CODE BEGIN Application */ + +/* USER CODE END Application */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/Src/fatfs/fatfs.h b/firmware/targets/f7/Src/fatfs/fatfs.h new file mode 100644 index 00000000..a0775d88 --- /dev/null +++ b/firmware/targets/f7/Src/fatfs/fatfs.h @@ -0,0 +1,49 @@ +/** + ****************************************************************************** + * @file fatfs.h + * @brief Header for fatfs applications + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2020 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __fatfs_H +#define __fatfs_H +#ifdef __cplusplus +extern "C" { +#endif + +#include "fatfs/ff.h" +#include "fatfs/ff_gen_drv.h" +#include "user_diskio.h" /* defines USER_Driver as external */ + +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +extern uint8_t retUSER; /* Return value for USER */ +extern char USERPath[4]; /* USER logical drive path */ +extern FATFS USERFatFS; /* File system object for USER logical drive */ +extern FIL USERFile; /* File object for USER */ + +void MX_FATFS_Init(void); + +/* USER CODE BEGIN Prototypes */ + +/* USER CODE END Prototypes */ +#ifdef __cplusplus +} +#endif +#endif /*__fatfs_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/Src/fatfs/ffconf.h b/firmware/targets/f7/Src/fatfs/ffconf.h new file mode 100644 index 00000000..d32d49a4 --- /dev/null +++ b/firmware/targets/f7/Src/fatfs/ffconf.h @@ -0,0 +1,270 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * FatFs - Generic FAT file system module R0.12c (C)ChaN, 2017 + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2020 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +#ifndef _FFCONF +#define _FFCONF 68300 /* Revision ID */ + +/*-----------------------------------------------------------------------------/ +/ Additional user header to be used +/-----------------------------------------------------------------------------*/ + +#include "main.h" +#include "stm32wbxx_hal.h" +#include "cmsis_os.h" /* _FS_REENTRANT set to 1 and CMSIS API chosen */ + +/*-----------------------------------------------------------------------------/ +/ Function Configurations +/-----------------------------------------------------------------------------*/ + +#define _FS_READONLY 0 /* 0:Read/Write or 1:Read only */ +/* This option switches read-only configuration. (0:Read/Write or 1:Read-only) +/ Read-only configuration removes writing API functions, f_write(), f_sync(), +/ f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree() +/ and optional writing functions as well. */ + +#define _FS_MINIMIZE 0 /* 0 to 3 */ +/* This option defines minimization level to remove some basic API functions. +/ +/ 0: All basic functions are enabled. +/ 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_truncate() and f_rename() +/ are removed. +/ 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1. +/ 3: f_lseek() function is removed in addition to 2. */ + +#define _USE_STRFUNC 0 /* 0:Disable or 1-2:Enable */ +/* This option switches string functions, f_gets(), f_putc(), f_puts() and +/ f_printf(). +/ +/ 0: Disable string functions. +/ 1: Enable without LF-CRLF conversion. +/ 2: Enable with LF-CRLF conversion. */ + +#define _USE_FIND 0 +/* This option switches filtered directory read functions, f_findfirst() and +/ f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */ + +#define _USE_MKFS 1 +/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */ + +#define _USE_FASTSEEK 1 +/* This option switches fast seek feature. (0:Disable or 1:Enable) */ + +#define _USE_EXPAND 0 +/* This option switches f_expand function. (0:Disable or 1:Enable) */ + +#define _USE_CHMOD 0 +/* This option switches attribute manipulation functions, f_chmod() and f_utime(). +/ (0:Disable or 1:Enable) Also _FS_READONLY needs to be 0 to enable this option. */ + +#define _USE_LABEL 1 +/* This option switches volume label functions, f_getlabel() and f_setlabel(). +/ (0:Disable or 1:Enable) */ + +#define _USE_FORWARD 0 +/* This option switches f_forward() function. (0:Disable or 1:Enable) */ + +/*-----------------------------------------------------------------------------/ +/ Locale and Namespace Configurations +/-----------------------------------------------------------------------------*/ + +#define _CODE_PAGE 850 +/* This option specifies the OEM code page to be used on the target system. +/ Incorrect setting of the code page can cause a file open failure. +/ +/ 1 - ASCII (No extended character. Non-LFN cfg. only) +/ 437 - U.S. +/ 720 - Arabic +/ 737 - Greek +/ 771 - KBL +/ 775 - Baltic +/ 850 - Latin 1 +/ 852 - Latin 2 +/ 855 - Cyrillic +/ 857 - Turkish +/ 860 - Portuguese +/ 861 - Icelandic +/ 862 - Hebrew +/ 863 - Canadian French +/ 864 - Arabic +/ 865 - Nordic +/ 866 - Russian +/ 869 - Greek 2 +/ 932 - Japanese (DBCS) +/ 936 - Simplified Chinese (DBCS) +/ 949 - Korean (DBCS) +/ 950 - Traditional Chinese (DBCS) +*/ + +#define _USE_LFN 2 /* 0 to 3 */ +#define _MAX_LFN 255 /* Maximum LFN length to handle (12 to 255) */ +/* The _USE_LFN switches the support of long file name (LFN). +/ +/ 0: Disable support of LFN. _MAX_LFN has no effect. +/ 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe. +/ 2: Enable LFN with dynamic working buffer on the STACK. +/ 3: Enable LFN with dynamic working buffer on the HEAP. +/ +/ To enable the LFN, Unicode handling functions (option/unicode.c) must be added +/ to the project. The working buffer occupies (_MAX_LFN + 1) * 2 bytes and +/ additional 608 bytes at exFAT enabled. _MAX_LFN can be in range from 12 to 255. +/ It should be set 255 to support full featured LFN operations. +/ When use stack for the working buffer, take care on stack overflow. When use heap +/ memory for the working buffer, memory management functions, ff_memalloc() and +/ ff_memfree(), must be added to the project. */ + +#define _LFN_UNICODE 0 /* 0:ANSI/OEM or 1:Unicode */ +/* This option switches character encoding on the API. (0:ANSI/OEM or 1:UTF-16) +/ To use Unicode string for the path name, enable LFN and set _LFN_UNICODE = 1. +/ This option also affects behavior of string I/O functions. */ + +#define _STRF_ENCODE 0 +/* When _LFN_UNICODE == 1, this option selects the character encoding ON THE FILE to +/ be read/written via string I/O functions, f_gets(), f_putc(), f_puts and f_printf(). +/ +/ 0: ANSI/OEM +/ 1: UTF-16LE +/ 2: UTF-16BE +/ 3: UTF-8 +/ +/ This option has no effect when _LFN_UNICODE == 0. */ + +#define _FS_RPATH 0 /* 0 to 2 */ +/* This option configures support of relative path. +/ +/ 0: Disable relative path and remove related functions. +/ 1: Enable relative path. f_chdir() and f_chdrive() are available. +/ 2: f_getcwd() function is available in addition to 1. +*/ + +/*---------------------------------------------------------------------------/ +/ Drive/Volume Configurations +/----------------------------------------------------------------------------*/ + +#define _VOLUMES 1 +/* Number of volumes (logical drives) to be used. */ + +/* USER CODE BEGIN Volumes */ +#define _STR_VOLUME_ID 0 /* 0:Use only 0-9 for drive ID, 1:Use strings for drive ID */ +#define _VOLUME_STRS "RAM","NAND","CF","SD1","SD2","USB1","USB2","USB3" +/* _STR_VOLUME_ID switches string support of volume ID. +/ When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive +/ number in the path name. _VOLUME_STRS defines the drive ID strings for each +/ logical drives. Number of items must be equal to _VOLUMES. Valid characters for +/ the drive ID strings are: A-Z and 0-9. */ +/* USER CODE END Volumes */ + +#define _MULTI_PARTITION 0 /* 0:Single partition, 1:Multiple partition */ +/* This option switches support of multi-partition on a physical drive. +/ By default (0), each logical drive number is bound to the same physical drive +/ number and only an FAT volume found on the physical drive will be mounted. +/ When multi-partition is enabled (1), each logical drive number can be bound to +/ arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk() +/ funciton will be available. */ +#define _MIN_SS 512 /* 512, 1024, 2048 or 4096 */ +#define _MAX_SS 512 /* 512, 1024, 2048 or 4096 */ +/* These options configure the range of sector size to be supported. (512, 1024, +/ 2048 or 4096) Always set both 512 for most systems, all type of memory cards and +/ harddisk. But a larger value may be required for on-board flash memory and some +/ type of optical media. When _MAX_SS is larger than _MIN_SS, FatFs is configured +/ to variable sector size and GET_SECTOR_SIZE command must be implemented to the +/ disk_ioctl() function. */ + +#define _USE_TRIM 0 +/* This option switches support of ATA-TRIM. (0:Disable or 1:Enable) +/ To enable Trim function, also CTRL_TRIM command should be implemented to the +/ disk_ioctl() function. */ + +#define _FS_NOFSINFO 0 /* 0,1,2 or 3 */ +/* If you need to know correct free space on the FAT32 volume, set bit 0 of this +/ option, and f_getfree() function at first time after volume mount will force +/ a full FAT scan. Bit 1 controls the use of last allocated cluster number. +/ +/ bit0=0: Use free cluster count in the FSINFO if available. +/ bit0=1: Do not trust free cluster count in the FSINFO. +/ bit1=0: Use last allocated cluster number in the FSINFO if available. +/ bit1=1: Do not trust last allocated cluster number in the FSINFO. +*/ + +/*---------------------------------------------------------------------------/ +/ System Configurations +/----------------------------------------------------------------------------*/ + +#define _FS_TINY 0 /* 0:Normal or 1:Tiny */ +/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny) +/ At the tiny configuration, size of file object (FIL) is reduced _MAX_SS bytes. +/ Instead of private sector buffer eliminated from the file object, common sector +/ buffer in the file system object (FATFS) is used for the file data transfer. */ + +#define _FS_EXFAT 1 +/* This option switches support of exFAT file system. (0:Disable or 1:Enable) +/ When enable exFAT, also LFN needs to be enabled. (_USE_LFN >= 1) +/ Note that enabling exFAT discards C89 compatibility. */ + +#define _FS_NORTC 1 +#define _NORTC_MON 7 +#define _NORTC_MDAY 20 +#define _NORTC_YEAR 2021 +/* The option _FS_NORTC switches timestamp functiton. If the system does not have +/ any RTC function or valid timestamp is not needed, set _FS_NORTC = 1 to disable +/ the timestamp function. All objects modified by FatFs will have a fixed timestamp +/ defined by _NORTC_MON, _NORTC_MDAY and _NORTC_YEAR in local time. +/ To enable timestamp function (_FS_NORTC = 0), get_fattime() function need to be +/ added to the project to get current time form real-time clock. _NORTC_MON, +/ _NORTC_MDAY and _NORTC_YEAR have no effect. +/ These options have no effect at read-only configuration (_FS_READONLY = 1). */ + +#define _FS_LOCK 0 /* 0:Disable or >=1:Enable */ +/* The option _FS_LOCK switches file lock function to control duplicated file open +/ and illegal operation to open objects. This option must be 0 when _FS_READONLY +/ is 1. +/ +/ 0: Disable file lock function. To avoid volume corruption, application program +/ should avoid illegal open, remove and rename to the open objects. +/ >0: Enable file lock function. The value defines how many files/sub-directories +/ can be opened simultaneously under file lock control. Note that the file +/ lock control is independent of re-entrancy. */ + +#define _FS_REENTRANT 0 /* 0:Disable or 1:Enable */ +#define _FS_TIMEOUT 1000 /* Timeout period in unit of time ticks */ +#define _SYNC_t osMutexId_t +/* The option _FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs +/ module itself. Note that regardless of this option, file access to different +/ volume is always re-entrant and volume control functions, f_mount(), f_mkfs() +/ and f_fdisk() function, are always not re-entrant. Only file/directory access +/ to the same volume is under control of this function. +/ +/ 0: Disable re-entrancy. _FS_TIMEOUT and _SYNC_t have no effect. +/ 1: Enable re-entrancy. Also user provided synchronization handlers, +/ ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj() +/ function, must be added to the project. Samples are available in +/ option/syscall.c. +/ +/ The _FS_TIMEOUT defines timeout period in unit of time tick. +/ The _SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*, +/ SemaphoreHandle_t and etc.. A header file for O/S definitions needs to be +/ included somewhere in the scope of ff.h. */ + +/* define the ff_malloc ff_free macros as standard malloc free */ +#if !defined(ff_malloc) && !defined(ff_free) +#include +#define ff_malloc malloc +#define ff_free free +#endif + +#endif /* _FFCONF */ diff --git a/firmware/targets/f7/Src/fatfs/spi_sd_hal.c b/firmware/targets/f7/Src/fatfs/spi_sd_hal.c new file mode 100644 index 00000000..70e9bbf1 --- /dev/null +++ b/firmware/targets/f7/Src/fatfs/spi_sd_hal.c @@ -0,0 +1,100 @@ +#include "main.h" +#include +#include + +#define SD_DUMMY_BYTE 0xFF + +const uint32_t SpiTimeout = 1000; +uint8_t SD_IO_WriteByte(uint8_t Data); + +static const FuriHalSpiDevice* sd_spi_dev = &furi_hal_spi_devices[FuriHalSpiDeviceIdSdCardFast]; + +/****************************************************************************** + BUS OPERATIONS + *******************************************************************************/ + +/** + * @brief SPI Write byte(s) to device + * @param DataIn: Pointer to data buffer to write + * @param DataOut: Pointer to data buffer for read data + * @param DataLength: number of bytes to write + * @retval None + */ +static void SPIx_WriteReadData(const uint8_t* DataIn, uint8_t* DataOut, uint16_t DataLength) { + furi_check(furi_hal_spi_bus_trx(sd_spi_dev->bus, (uint8_t*)DataIn, DataOut, DataLength, SpiTimeout)); +} + +/** + * @brief SPI Write a byte to device + * @param Value: value to be written + * @retval None + */ +__attribute__((unused)) static void SPIx_Write(uint8_t Value) { + furi_check(furi_hal_spi_bus_tx(sd_spi_dev->bus, (uint8_t*)&Value, 1, SpiTimeout)); +} + +/****************************************************************************** + LINK OPERATIONS + *******************************************************************************/ + +/********************************* LINK SD ************************************/ +/** + * @brief Initialize the SD Card and put it into StandBy State (Ready for + * data transfer). + * @retval None + */ +void SD_IO_Init(void) { + uint8_t counter = 0; + + /* SD chip select high */ + hal_gpio_write(sd_spi_dev->chip_select, true); + delay_us(10); + + /* Send dummy byte 0xFF, 10 times with CS high */ + /* Rise CS and MOSI for 80 clocks cycles */ + for(counter = 0; counter <= 200; counter++) { + /* Send dummy byte 0xFF */ + SD_IO_WriteByte(SD_DUMMY_BYTE); + } +} + +/** + * @brief Set SD interface Chip Select state + * @param val: 0 (low) or 1 (high) state + * @retval None + */ +void SD_IO_CSState(uint8_t val) { + /* Some SD Cards are prone to fail if CLK-ed too soon after CS transition. Worst case found: 8us */ + if(val == 1) { + delay_us(10); // Exit guard time for some SD cards + hal_gpio_write(sd_spi_dev->chip_select, true); + } else { + hal_gpio_write(sd_spi_dev->chip_select, false); + delay_us(10); // Entry guard time for some SD cards + } +} + +/** + * @brief Write byte(s) on the SD + * @param DataIn: Pointer to data buffer to write + * @param DataOut: Pointer to data buffer for read data + * @param DataLength: number of bytes to write + * @retval None + */ +void SD_IO_WriteReadData(const uint8_t* DataIn, uint8_t* DataOut, uint16_t DataLength) { + /* Send the byte */ + SPIx_WriteReadData(DataIn, DataOut, DataLength); +} + +/** + * @brief Write a byte on the SD. + * @param Data: byte to send. + * @retval Data written + */ +uint8_t SD_IO_WriteByte(uint8_t Data) { + uint8_t tmp; + + /* Send the byte */ + SPIx_WriteReadData(&Data, &tmp, 1); + return tmp; +} diff --git a/firmware/targets/f7/Src/fatfs/stm32_adafruit_sd.c b/firmware/targets/f7/Src/fatfs/stm32_adafruit_sd.c new file mode 100644 index 00000000..e90ebd62 --- /dev/null +++ b/firmware/targets/f7/Src/fatfs/stm32_adafruit_sd.c @@ -0,0 +1,1073 @@ +/** + ****************************************************************************** + * @file stm32_adafruit_sd.c + * @author MCD Application Team + * @version V3.0.0 + * @date 23-December-2016 + * @brief This file provides a set of functions needed to manage the SD card + * mounted on the Adafruit 1.8" TFT LCD shield (reference ID 802), + * that is used with the STM32 Nucleo board through SPI interface. + * It implements a high level communication layer for read and write + * from/to this memory. The needed STM32XXxx hardware resources (SPI and + * GPIO) are defined in stm32XXxx_nucleo.h file, and the initialization is + * performed in SD_IO_Init() function declared in stm32XXxx_nucleo.c + * file. + * You can easily tailor this driver to any other development board, + * by just adapting the defines for hardware resources and + * SD_IO_Init() function. + * + * +-------------------------------------------------------+ + * | Pin assignment | + * +-------------------------+---------------+-------------+ + * | STM32XXxx SPI Pins | SD | Pin | + * +-------------------------+---------------+-------------+ + * | SD_SPI_CS_PIN | ChipSelect | 1 | + * | SD_SPI_MOSI_PIN / MOSI | DataIn | 2 | + * | | GND | 3 (0 V) | + * | | VDD | 4 (3.3 V)| + * | SD_SPI_SCK_PIN / SCLK | Clock | 5 | + * | | GND | 6 (0 V) | + * | SD_SPI_MISO_PIN / MISO | DataOut | 7 | + * +-------------------------+---------------+-------------+ + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* File Info : ----------------------------------------------------------------- + User NOTES +1. How to use this driver: +-------------------------- + - This driver does not need a specific component driver for the micro SD device + to be included with. + +2. Driver description: +--------------------- + + Initialization steps: + o Initialize the micro SD card using the BSP_SD_Init() function. + o Checking the SD card presence is not managed because SD detection pin is + not physically mapped on the Adafruit shield. + o The function BSP_SD_GetCardInfo() is used to get the micro SD card information + which is stored in the structure "SD_CardInfo". + + + Micro SD card operations + o The micro SD card can be accessed with read/write block(s) operations once + it is ready for access. The access can be performed in polling + mode by calling the functions BSP_SD_ReadBlocks()/BSP_SD_WriteBlocks() + + o The SD erase block(s) is performed using the function BSP_SD_Erase() with + specifying the number of blocks to erase. + o The SD runtime status is returned when calling the function BSP_SD_GetStatus(). + +------------------------------------------------------------------------------*/ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32_adafruit_sd.h" +#include "stdlib.h" +#include "string.h" +#include "stdio.h" +#include +#include +#include +#include +#include +#include + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32_ADAFRUIT + * @{ + */ + +/** @defgroup STM32_ADAFRUIT_SD + * @{ + */ + +/* Private typedef -----------------------------------------------------------*/ + +/** @defgroup STM32_ADAFRUIT_SD_Private_Types_Definitions + * @{ + */ +typedef struct { + uint8_t r1; + uint8_t r2; + uint8_t r3; + uint8_t r4; + uint8_t r5; +} SD_CmdAnswer_typedef; + +/** + * @} + */ + +/* Private define ------------------------------------------------------------*/ + +/** @defgroup STM32_ADAFRUIT_SD_Private_Defines + * @{ + */ +#define SD_DUMMY_BYTE 0xFF + +#define SD_MAX_FRAME_LENGTH 17 /* Lenght = 16 + 1 */ +#define SD_CMD_LENGTH 6 + +#define SD_MAX_TRY 100 /* Number of try */ + +#define SD_CSD_STRUCT_V1 0x2 /* CSD struct version V1 */ +#define SD_CSD_STRUCT_V2 0x1 /* CSD struct version V2 */ + +/** + * @brief SD ansewer format + */ +typedef enum { + SD_ANSWER_R1_EXPECTED, + SD_ANSWER_R1B_EXPECTED, + SD_ANSWER_R2_EXPECTED, + SD_ANSWER_R3_EXPECTED, + SD_ANSWER_R4R5_EXPECTED, + SD_ANSWER_R7_EXPECTED, +} SD_Answer_type; + +/** + * @brief Start Data tokens: + * Tokens (necessary because at nop/idle (and CS active) only 0xff is + * on the data/command line) + */ +#define SD_TOKEN_START_DATA_SINGLE_BLOCK_READ \ + 0xFE /* Data token start byte, Start Single Block Read */ +#define SD_TOKEN_START_DATA_MULTIPLE_BLOCK_READ \ + 0xFE /* Data token start byte, Start Multiple Block Read */ +#define SD_TOKEN_START_DATA_SINGLE_BLOCK_WRITE \ + 0xFE /* Data token start byte, Start Single Block Write */ +#define SD_TOKEN_START_DATA_MULTIPLE_BLOCK_WRITE \ + 0xFD /* Data token start byte, Start Multiple Block Write */ +#define SD_TOKEN_STOP_DATA_MULTIPLE_BLOCK_WRITE \ + 0xFD /* Data toke stop byte, Stop Multiple Block Write */ + +/** + * @brief Commands: CMDxx = CMD-number | 0x40 + */ +#define SD_CMD_GO_IDLE_STATE 0 /* CMD0 = 0x40 */ +#define SD_CMD_SEND_OP_COND 1 /* CMD1 = 0x41 */ +#define SD_CMD_SEND_IF_COND 8 /* CMD8 = 0x48 */ +#define SD_CMD_SEND_CSD 9 /* CMD9 = 0x49 */ +#define SD_CMD_SEND_CID 10 /* CMD10 = 0x4A */ +#define SD_CMD_STOP_TRANSMISSION 12 /* CMD12 = 0x4C */ +#define SD_CMD_SEND_STATUS 13 /* CMD13 = 0x4D */ +#define SD_CMD_SET_BLOCKLEN 16 /* CMD16 = 0x50 */ +#define SD_CMD_READ_SINGLE_BLOCK 17 /* CMD17 = 0x51 */ +#define SD_CMD_READ_MULT_BLOCK 18 /* CMD18 = 0x52 */ +#define SD_CMD_SET_BLOCK_COUNT 23 /* CMD23 = 0x57 */ +#define SD_CMD_WRITE_SINGLE_BLOCK 24 /* CMD24 = 0x58 */ +#define SD_CMD_WRITE_MULT_BLOCK 25 /* CMD25 = 0x59 */ +#define SD_CMD_PROG_CSD 27 /* CMD27 = 0x5B */ +#define SD_CMD_SET_WRITE_PROT 28 /* CMD28 = 0x5C */ +#define SD_CMD_CLR_WRITE_PROT 29 /* CMD29 = 0x5D */ +#define SD_CMD_SEND_WRITE_PROT 30 /* CMD30 = 0x5E */ +#define SD_CMD_SD_ERASE_GRP_START 32 /* CMD32 = 0x60 */ +#define SD_CMD_SD_ERASE_GRP_END 33 /* CMD33 = 0x61 */ +#define SD_CMD_UNTAG_SECTOR 34 /* CMD34 = 0x62 */ +#define SD_CMD_ERASE_GRP_START 35 /* CMD35 = 0x63 */ +#define SD_CMD_ERASE_GRP_END 36 /* CMD36 = 0x64 */ +#define SD_CMD_UNTAG_ERASE_GROUP 37 /* CMD37 = 0x65 */ +#define SD_CMD_ERASE 38 /* CMD38 = 0x66 */ +#define SD_CMD_SD_APP_OP_COND 41 /* CMD41 = 0x69 */ +#define SD_CMD_APP_CMD 55 /* CMD55 = 0x77 */ +#define SD_CMD_READ_OCR 58 /* CMD55 = 0x79 */ + +/** + * @brief SD reponses and error flags + */ +typedef enum { + /* R1 answer value */ + SD_R1_NO_ERROR = (0x00), + SD_R1_IN_IDLE_STATE = (0x01), + SD_R1_ERASE_RESET = (0x02), + SD_R1_ILLEGAL_COMMAND = (0x04), + SD_R1_COM_CRC_ERROR = (0x08), + SD_R1_ERASE_SEQUENCE_ERROR = (0x10), + SD_R1_ADDRESS_ERROR = (0x20), + SD_R1_PARAMETER_ERROR = (0x40), + + /* R2 answer value */ + SD_R2_NO_ERROR = 0x00, + SD_R2_CARD_LOCKED = 0x01, + SD_R2_LOCKUNLOCK_ERROR = 0x02, + SD_R2_ERROR = 0x04, + SD_R2_CC_ERROR = 0x08, + SD_R2_CARD_ECC_FAILED = 0x10, + SD_R2_WP_VIOLATION = 0x20, + SD_R2_ERASE_PARAM = 0x40, + SD_R2_OUTOFRANGE = 0x80, + + /** + * @brief Data response error + */ + SD_DATA_OK = (0x05), + SD_DATA_CRC_ERROR = (0x0B), + SD_DATA_WRITE_ERROR = (0x0D), + SD_DATA_OTHER_ERROR = (0xFF) +} SD_Error; + +/** + * @} + */ + +/* Private macro -------------------------------------------------------------*/ + +/** @defgroup STM32_ADAFRUIT_SD_Private_Macros + * @{ + */ + +/** + * @} + */ + +/* Private variables ---------------------------------------------------------*/ + +/** @defgroup STM32_ADAFRUIT_SD_Private_Variables + * @{ + */ +__IO uint8_t SdStatus = SD_NOT_PRESENT; + +/* flag_SDHC : + 0 : Standard capacity + 1 : High capacity +*/ +uint16_t flag_SDHC = 0; + +/** + * @} + */ + +/* Private function prototypes -----------------------------------------------*/ +static uint8_t SD_GetCIDRegister(SD_CID* Cid); +static uint8_t SD_GetCSDRegister(SD_CSD* Csd); +static uint8_t SD_GetDataResponse(void); +static uint8_t SD_GoIdleState(void); +static SD_CmdAnswer_typedef SD_SendCmd(uint8_t Cmd, uint32_t Arg, uint8_t Crc, uint8_t Answer); +static uint8_t SD_WaitData(uint8_t data); +static uint8_t SD_ReadData(void); +/** @defgroup STM32_ADAFRUIT_SD_Private_Function_Prototypes + * @{ + */ +/** + * @} + */ + +/* Private functions ---------------------------------------------------------*/ + +void SD_SPI_Bus_To_Down_State(){ + hal_gpio_init_ex(&gpio_spi_d_miso, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh, GpioAltFnUnused); + hal_gpio_init_ex(&gpio_spi_d_mosi, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh, GpioAltFnUnused); + hal_gpio_init_ex(&gpio_spi_d_sck, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh, GpioAltFnUnused); + + hal_gpio_write(&gpio_sdcard_cs, false); + hal_gpio_write(&gpio_spi_d_miso, false); + hal_gpio_write(&gpio_spi_d_mosi, false); + hal_gpio_write(&gpio_spi_d_sck, false); +} + +void SD_SPI_Bus_To_Normal_State(){ + hal_gpio_write(&gpio_sdcard_cs, true); + + hal_gpio_init_ex(&gpio_spi_d_miso, GpioModeAltFunctionPushPull, GpioPullUp, GpioSpeedVeryHigh, GpioAltFn5SPI2); + hal_gpio_init_ex(&gpio_spi_d_mosi, GpioModeAltFunctionPushPull, GpioPullUp, GpioSpeedVeryHigh, GpioAltFn5SPI2); + hal_gpio_init_ex(&gpio_spi_d_sck, GpioModeAltFunctionPushPull, GpioPullUp, GpioSpeedVeryHigh, GpioAltFn5SPI2); +} + +/** @defgroup STM32_ADAFRUIT_SD_Private_Functions + * @{ + */ + +/** + * @brief Initializes the SD/SD communication. + * @param None + * @retval The SD Response: + * - MSD_ERROR: Sequence failed + * - MSD_OK: Sequence succeed + */ +uint8_t BSP_SD_Init(bool reset_card) { + /* Slow speed init */ + const FuriHalSpiDevice* sd_spi_slow_dev = furi_hal_spi_device_get(FuriHalSpiDeviceIdSdCardSlow); + + /* We must reset card in spi_lock context */ + if(reset_card) { + /* disable power and set low on all bus pins */ + furi_hal_power_disable_external_3_3v(); + SD_SPI_Bus_To_Down_State(); + hal_sd_detect_set_low(); + delay(250); + + /* reinit bus and enable power */ + SD_SPI_Bus_To_Normal_State(); + hal_sd_detect_init(); + furi_hal_power_enable_external_3_3v(); + delay(100); + } + + /* Configure IO functionalities for SD pin */ + SD_IO_Init(); + + /* SD detection pin is not physically mapped on the Adafruit shield */ + SdStatus = SD_PRESENT; + uint8_t res = BSP_SD_ERROR; + + for(uint8_t i = 0; i < 128; i++) { + res = SD_GoIdleState(); + if(res == BSP_SD_OK) break; + } + + furi_hal_spi_device_return(sd_spi_slow_dev); + + /* SD initialized and set to SPI mode properly */ + return res; +} + +/** + * @brief Returns information about specific card. + * @param pCardInfo: Pointer to a SD_CardInfo structure that contains all SD + * card information. + * @retval The SD Response: + * - MSD_ERROR: Sequence failed + * - MSD_OK: Sequence succeed + */ +uint8_t BSP_SD_GetCardInfo(SD_CardInfo* pCardInfo) { + uint8_t status; + + status = SD_GetCSDRegister(&(pCardInfo->Csd)); + status |= SD_GetCIDRegister(&(pCardInfo->Cid)); + if(flag_SDHC == 1) { + pCardInfo->LogBlockSize = 512; + pCardInfo->CardBlockSize = 512; + pCardInfo->CardCapacity = ((uint64_t)pCardInfo->Csd.version.v2.DeviceSize + 1UL) * 1024UL * + (uint64_t)pCardInfo->LogBlockSize; + pCardInfo->LogBlockNbr = (pCardInfo->CardCapacity) / (pCardInfo->LogBlockSize); + } else { + pCardInfo->CardCapacity = (pCardInfo->Csd.version.v1.DeviceSize + 1); + pCardInfo->CardCapacity *= (1 << (pCardInfo->Csd.version.v1.DeviceSizeMul + 2)); + pCardInfo->LogBlockSize = 512; + pCardInfo->CardBlockSize = 1 << (pCardInfo->Csd.RdBlockLen); + pCardInfo->CardCapacity *= pCardInfo->CardBlockSize; + pCardInfo->LogBlockNbr = (pCardInfo->CardCapacity) / (pCardInfo->LogBlockSize); + } + + return status; +} + +/** + * @brief Reads block(s) from a specified address in the SD card, in polling mode. + * @param pData: Pointer to the buffer that will contain the data to transmit + * @param ReadAddr: Address from where data is to be read. The address is counted + * in blocks of 512bytes + * @param NumOfBlocks: Number of SD blocks to read + * @param Timeout: This parameter is used for compatibility with BSP implementation + * @retval SD status + */ +uint8_t +BSP_SD_ReadBlocks(uint32_t* pData, uint32_t ReadAddr, uint32_t NumOfBlocks, uint32_t Timeout) { + uint32_t offset = 0; + uint32_t addr; + uint8_t retr = BSP_SD_ERROR; + uint8_t* ptr = NULL; + SD_CmdAnswer_typedef response; + uint16_t BlockSize = 512; + + /* Send CMD16 (SD_CMD_SET_BLOCKLEN) to set the size of the block and + Check if the SD acknowledged the set block length command: R1 response (0x00: no errors) */ + response = SD_SendCmd(SD_CMD_SET_BLOCKLEN, BlockSize, 0xFF, SD_ANSWER_R1_EXPECTED); + SD_IO_CSState(1); + SD_IO_WriteByte(SD_DUMMY_BYTE); + if(response.r1 != SD_R1_NO_ERROR) { + goto error; + } + + ptr = malloc(sizeof(uint8_t) * BlockSize); + if(ptr == NULL) { + goto error; + } + memset(ptr, SD_DUMMY_BYTE, sizeof(uint8_t) * BlockSize); + + /* Initialize the address */ + addr = (ReadAddr * ((flag_SDHC == 1) ? 1 : BlockSize)); + + /* Data transfer */ + while(NumOfBlocks--) { + /* Send CMD17 (SD_CMD_READ_SINGLE_BLOCK) to read one block */ + /* Check if the SD acknowledged the read block command: R1 response (0x00: no errors) */ + response = SD_SendCmd(SD_CMD_READ_SINGLE_BLOCK, addr, 0xFF, SD_ANSWER_R1_EXPECTED); + if(response.r1 != SD_R1_NO_ERROR) { + goto error; + } + + /* Now look for the data token to signify the start of the data */ + if(SD_WaitData(SD_TOKEN_START_DATA_SINGLE_BLOCK_READ) == BSP_SD_OK) { + /* Read the SD block data : read NumByteToRead data */ + SD_IO_WriteReadData(ptr, (uint8_t*)pData + offset, BlockSize); + + /* Set next read address*/ + offset += BlockSize; + addr = ((flag_SDHC == 1) ? (addr + 1) : (addr + BlockSize)); + + /* get CRC bytes (not really needed by us, but required by SD) */ + SD_IO_WriteByte(SD_DUMMY_BYTE); + SD_IO_WriteByte(SD_DUMMY_BYTE); + } else { + goto error; + } + + /* End the command data read cycle */ + SD_IO_CSState(1); + SD_IO_WriteByte(SD_DUMMY_BYTE); + } + + retr = BSP_SD_OK; + +error: + /* Send dummy byte: 8 Clock pulses of delay */ + SD_IO_CSState(1); + SD_IO_WriteByte(SD_DUMMY_BYTE); + if(ptr != NULL) free(ptr); + + /* Return the reponse */ + return retr; +} + +/** + * @brief Writes block(s) to a specified address in the SD card, in polling mode. + * @param pData: Pointer to the buffer that will contain the data to transmit + * @param WriteAddr: Address from where data is to be written. The address is counted + * in blocks of 512bytes + * @param NumOfBlocks: Number of SD blocks to write + * @param Timeout: This parameter is used for compatibility with BSP implementation + * @retval SD status + */ +uint8_t +BSP_SD_WriteBlocks(uint32_t* pData, uint32_t WriteAddr, uint32_t NumOfBlocks, uint32_t Timeout) { + uint32_t offset = 0; + uint32_t addr; + uint8_t retr = BSP_SD_ERROR; + uint8_t* ptr = NULL; + SD_CmdAnswer_typedef response; + uint16_t BlockSize = 512; + + /* Send CMD16 (SD_CMD_SET_BLOCKLEN) to set the size of the block and + Check if the SD acknowledged the set block length command: R1 response (0x00: no errors) */ + response = SD_SendCmd(SD_CMD_SET_BLOCKLEN, BlockSize, 0xFF, SD_ANSWER_R1_EXPECTED); + SD_IO_CSState(1); + SD_IO_WriteByte(SD_DUMMY_BYTE); + if(response.r1 != SD_R1_NO_ERROR) { + goto error; + } + + ptr = malloc(sizeof(uint8_t) * BlockSize); + if(ptr == NULL) { + goto error; + } + + /* Initialize the address */ + addr = (WriteAddr * ((flag_SDHC == 1) ? 1 : BlockSize)); + + /* Data transfer */ + while(NumOfBlocks--) { + /* Send CMD24 (SD_CMD_WRITE_SINGLE_BLOCK) to write blocks and + Check if the SD acknowledged the write block command: R1 response (0x00: no errors) */ + response = SD_SendCmd(SD_CMD_WRITE_SINGLE_BLOCK, addr, 0xFF, SD_ANSWER_R1_EXPECTED); + if(response.r1 != SD_R1_NO_ERROR) { + goto error; + } + + /* Send dummy byte for NWR timing : one byte between CMDWRITE and TOKEN */ + SD_IO_WriteByte(SD_DUMMY_BYTE); + SD_IO_WriteByte(SD_DUMMY_BYTE); + + /* Send the data token to signify the start of the data */ + SD_IO_WriteByte(SD_TOKEN_START_DATA_SINGLE_BLOCK_WRITE); + + /* Write the block data to SD */ + SD_IO_WriteReadData((uint8_t*)pData + offset, ptr, BlockSize); + + /* Set next write address */ + offset += BlockSize; + addr = ((flag_SDHC == 1) ? (addr + 1) : (addr + BlockSize)); + + /* Put CRC bytes (not really needed by us, but required by SD) */ + SD_IO_WriteByte(SD_DUMMY_BYTE); + SD_IO_WriteByte(SD_DUMMY_BYTE); + + /* Read data response */ + if(SD_GetDataResponse() != SD_DATA_OK) { + /* Set response value to failure */ + goto error; + } + + SD_IO_CSState(1); + SD_IO_WriteByte(SD_DUMMY_BYTE); + } + retr = BSP_SD_OK; + +error: + if(ptr != NULL) free(ptr); + /* Send dummy byte: 8 Clock pulses of delay */ + SD_IO_CSState(1); + SD_IO_WriteByte(SD_DUMMY_BYTE); + + /* Return the reponse */ + return retr; +} + +/** + * @brief Erases the specified memory area of the given SD card. + * @param StartAddr: Start address in Blocks (Size of a block is 512bytes) + * @param EndAddr: End address in Blocks (Size of a block is 512bytes) + * @retval SD status + */ +uint8_t BSP_SD_Erase(uint32_t StartAddr, uint32_t EndAddr) { + uint8_t retr = BSP_SD_ERROR; + SD_CmdAnswer_typedef response; + uint16_t BlockSize = 512; + + /* Send CMD32 (Erase group start) and check if the SD acknowledged the erase command: R1 response (0x00: no errors) */ + response = SD_SendCmd( + SD_CMD_SD_ERASE_GRP_START, + (StartAddr) * (flag_SDHC == 1 ? 1 : BlockSize), + 0xFF, + SD_ANSWER_R1_EXPECTED); + SD_IO_CSState(1); + SD_IO_WriteByte(SD_DUMMY_BYTE); + if(response.r1 == SD_R1_NO_ERROR) { + /* Send CMD33 (Erase group end) and Check if the SD acknowledged the erase command: R1 response (0x00: no errors) */ + response = SD_SendCmd( + SD_CMD_SD_ERASE_GRP_END, + (EndAddr * 512) * (flag_SDHC == 1 ? 1 : BlockSize), + 0xFF, + SD_ANSWER_R1_EXPECTED); + SD_IO_CSState(1); + SD_IO_WriteByte(SD_DUMMY_BYTE); + if(response.r1 == SD_R1_NO_ERROR) { + /* Send CMD38 (Erase) and Check if the SD acknowledged the erase command: R1 response (0x00: no errors) */ + response = SD_SendCmd(SD_CMD_ERASE, 0, 0xFF, SD_ANSWER_R1B_EXPECTED); + if(response.r1 == SD_R1_NO_ERROR) { + retr = BSP_SD_OK; + } + SD_IO_CSState(1); + SD_IO_WriteByte(SD_DUMMY_BYTE); + } + } + + /* Return the reponse */ + return retr; +} + +/** + * @brief Returns the SD status. + * @param None + * @retval The SD status. + */ +uint8_t BSP_SD_GetCardState(void) { + SD_CmdAnswer_typedef retr; + + /* Send CMD13 (SD_SEND_STATUS) to get SD status */ + retr = SD_SendCmd(SD_CMD_SEND_STATUS, 0, 0xFF, SD_ANSWER_R2_EXPECTED); + SD_IO_CSState(1); + SD_IO_WriteByte(SD_DUMMY_BYTE); + + /* Find SD status according to card state */ + if((retr.r1 == SD_R1_NO_ERROR) && (retr.r2 == SD_R2_NO_ERROR)) { + return BSP_SD_OK; + } + + return BSP_SD_ERROR; +} + +/** + * @brief Reads the SD card SCD register. + * Reading the contents of the CSD register in SPI mode is a simple + * read-block transaction. + * @param Csd: pointer on an SCD register structure + * @retval SD status + */ +uint8_t SD_GetCSDRegister(SD_CSD* Csd) { + uint16_t counter = 0; + uint8_t CSD_Tab[16]; + uint8_t retr = BSP_SD_ERROR; + SD_CmdAnswer_typedef response; + + /* Send CMD9 (CSD register) or CMD10(CSD register) and Wait for response in the R1 format (0x00 is no errors) */ + response = SD_SendCmd(SD_CMD_SEND_CSD, 0, 0xFF, SD_ANSWER_R1_EXPECTED); + if(response.r1 == SD_R1_NO_ERROR) { + if(SD_WaitData(SD_TOKEN_START_DATA_SINGLE_BLOCK_READ) == BSP_SD_OK) { + for(counter = 0; counter < 16; counter++) { + /* Store CSD register value on CSD_Tab */ + CSD_Tab[counter] = SD_IO_WriteByte(SD_DUMMY_BYTE); + } + + /* Get CRC bytes (not really needed by us, but required by SD) */ + SD_IO_WriteByte(SD_DUMMY_BYTE); + SD_IO_WriteByte(SD_DUMMY_BYTE); + + /************************************************************************* + CSD header decoding + *************************************************************************/ + + /* Byte 0 */ + Csd->CSDStruct = (CSD_Tab[0] & 0xC0) >> 6; + Csd->Reserved1 = CSD_Tab[0] & 0x3F; + + /* Byte 1 */ + Csd->TAAC = CSD_Tab[1]; + + /* Byte 2 */ + Csd->NSAC = CSD_Tab[2]; + + /* Byte 3 */ + Csd->MaxBusClkFrec = CSD_Tab[3]; + + /* Byte 4/5 */ + Csd->CardComdClasses = (CSD_Tab[4] << 4) | ((CSD_Tab[5] & 0xF0) >> 4); + Csd->RdBlockLen = CSD_Tab[5] & 0x0F; + + /* Byte 6 */ + Csd->PartBlockRead = (CSD_Tab[6] & 0x80) >> 7; + Csd->WrBlockMisalign = (CSD_Tab[6] & 0x40) >> 6; + Csd->RdBlockMisalign = (CSD_Tab[6] & 0x20) >> 5; + Csd->DSRImpl = (CSD_Tab[6] & 0x10) >> 4; + + /************************************************************************* + CSD v1/v2 decoding + *************************************************************************/ + + if(flag_SDHC == 0) { + Csd->version.v1.Reserved1 = ((CSD_Tab[6] & 0x0C) >> 2); + + Csd->version.v1.DeviceSize = ((CSD_Tab[6] & 0x03) << 10) | (CSD_Tab[7] << 2) | + ((CSD_Tab[8] & 0xC0) >> 6); + Csd->version.v1.MaxRdCurrentVDDMin = (CSD_Tab[8] & 0x38) >> 3; + Csd->version.v1.MaxRdCurrentVDDMax = (CSD_Tab[8] & 0x07); + Csd->version.v1.MaxWrCurrentVDDMin = (CSD_Tab[9] & 0xE0) >> 5; + Csd->version.v1.MaxWrCurrentVDDMax = (CSD_Tab[9] & 0x1C) >> 2; + Csd->version.v1.DeviceSizeMul = ((CSD_Tab[9] & 0x03) << 1) | + ((CSD_Tab[10] & 0x80) >> 7); + } else { + Csd->version.v2.Reserved1 = ((CSD_Tab[6] & 0x0F) << 2) | + ((CSD_Tab[7] & 0xC0) >> 6); + Csd->version.v2.DeviceSize = ((CSD_Tab[7] & 0x3F) << 16) | (CSD_Tab[8] << 8) | + CSD_Tab[9]; + Csd->version.v2.Reserved2 = ((CSD_Tab[10] & 0x80) >> 8); + } + + Csd->EraseSingleBlockEnable = (CSD_Tab[10] & 0x40) >> 6; + Csd->EraseSectorSize = ((CSD_Tab[10] & 0x3F) << 1) | ((CSD_Tab[11] & 0x80) >> 7); + Csd->WrProtectGrSize = (CSD_Tab[11] & 0x7F); + Csd->WrProtectGrEnable = (CSD_Tab[12] & 0x80) >> 7; + Csd->Reserved2 = (CSD_Tab[12] & 0x60) >> 5; + Csd->WrSpeedFact = (CSD_Tab[12] & 0x1C) >> 2; + Csd->MaxWrBlockLen = ((CSD_Tab[12] & 0x03) << 2) | ((CSD_Tab[13] & 0xC0) >> 6); + Csd->WriteBlockPartial = (CSD_Tab[13] & 0x20) >> 5; + Csd->Reserved3 = (CSD_Tab[13] & 0x1F); + Csd->FileFormatGrouop = (CSD_Tab[14] & 0x80) >> 7; + Csd->CopyFlag = (CSD_Tab[14] & 0x40) >> 6; + Csd->PermWrProtect = (CSD_Tab[14] & 0x20) >> 5; + Csd->TempWrProtect = (CSD_Tab[14] & 0x10) >> 4; + Csd->FileFormat = (CSD_Tab[14] & 0x0C) >> 2; + Csd->Reserved4 = (CSD_Tab[14] & 0x03); + Csd->crc = (CSD_Tab[15] & 0xFE) >> 1; + Csd->Reserved5 = (CSD_Tab[15] & 0x01); + + retr = BSP_SD_OK; + } + } + + /* Send dummy byte: 8 Clock pulses of delay */ + SD_IO_CSState(1); + SD_IO_WriteByte(SD_DUMMY_BYTE); + + /* Return the reponse */ + return retr; +} + +/** + * @brief Reads the SD card CID register. + * Reading the contents of the CID register in SPI mode is a simple + * read-block transaction. + * @param Cid: pointer on an CID register structure + * @retval SD status + */ +uint8_t SD_GetCIDRegister(SD_CID* Cid) { + uint32_t counter = 0; + uint8_t retr = BSP_SD_ERROR; + uint8_t CID_Tab[16]; + SD_CmdAnswer_typedef response; + + /* Send CMD10 (CID register) and Wait for response in the R1 format (0x00 is no errors) */ + response = SD_SendCmd(SD_CMD_SEND_CID, 0, 0xFF, SD_ANSWER_R1_EXPECTED); + if(response.r1 == SD_R1_NO_ERROR) { + if(SD_WaitData(SD_TOKEN_START_DATA_SINGLE_BLOCK_READ) == BSP_SD_OK) { + /* Store CID register value on CID_Tab */ + for(counter = 0; counter < 16; counter++) { + CID_Tab[counter] = SD_IO_WriteByte(SD_DUMMY_BYTE); + } + + /* Get CRC bytes (not really needed by us, but required by SD) */ + SD_IO_WriteByte(SD_DUMMY_BYTE); + SD_IO_WriteByte(SD_DUMMY_BYTE); + + /* Byte 0 */ + Cid->ManufacturerID = CID_Tab[0]; + + /* Byte 1 */ + Cid->OEM_AppliID = CID_Tab[1] << 8; + + /* Byte 2 */ + Cid->OEM_AppliID |= CID_Tab[2]; + + /* Byte 3 */ + Cid->ProdName1 = CID_Tab[3] << 24; + + /* Byte 4 */ + Cid->ProdName1 |= CID_Tab[4] << 16; + + /* Byte 5 */ + Cid->ProdName1 |= CID_Tab[5] << 8; + + /* Byte 6 */ + Cid->ProdName1 |= CID_Tab[6]; + + /* Byte 7 */ + Cid->ProdName2 = CID_Tab[7]; + + /* Byte 8 */ + Cid->ProdRev = CID_Tab[8]; + + /* Byte 9 */ + Cid->ProdSN = CID_Tab[9] << 24; + + /* Byte 10 */ + Cid->ProdSN |= CID_Tab[10] << 16; + + /* Byte 11 */ + Cid->ProdSN |= CID_Tab[11] << 8; + + /* Byte 12 */ + Cid->ProdSN |= CID_Tab[12]; + + /* Byte 13 */ + Cid->Reserved1 |= (CID_Tab[13] & 0xF0) >> 4; + Cid->ManufactDate = (CID_Tab[13] & 0x0F) << 8; + + /* Byte 14 */ + Cid->ManufactDate |= CID_Tab[14]; + + /* Byte 15 */ + Cid->CID_CRC = (CID_Tab[15] & 0xFE) >> 1; + Cid->Reserved2 = 1; + + retr = BSP_SD_OK; + } + } + + /* Send dummy byte: 8 Clock pulses of delay */ + SD_IO_CSState(1); + SD_IO_WriteByte(SD_DUMMY_BYTE); + + /* Return the reponse */ + return retr; +} + +/** + * @brief Sends 5 bytes command to the SD card and get response + * @param Cmd: The user expected command to send to SD card. + * @param Arg: The command argument. + * @param Crc: The CRC. + * @param Answer: SD_ANSWER_NOT_EXPECTED or SD_ANSWER_EXPECTED + * @retval SD status + */ +SD_CmdAnswer_typedef SD_SendCmd(uint8_t Cmd, uint32_t Arg, uint8_t Crc, uint8_t Answer) { + uint8_t frame[SD_CMD_LENGTH], frameout[SD_CMD_LENGTH]; + SD_CmdAnswer_typedef retr = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + + /* R1 Lenght = NCS(0)+ 6 Bytes command + NCR(min1 max8) + 1 Bytes answer + NEC(0) = 15bytes */ + /* R1b identical to R1 + Busy information */ + /* R2 Lenght = NCS(0)+ 6 Bytes command + NCR(min1 max8) + 2 Bytes answer + NEC(0) = 16bytes */ + + /* Prepare Frame to send */ + frame[0] = (Cmd | 0x40); /* Construct byte 1 */ + frame[1] = (uint8_t)(Arg >> 24); /* Construct byte 2 */ + frame[2] = (uint8_t)(Arg >> 16); /* Construct byte 3 */ + frame[3] = (uint8_t)(Arg >> 8); /* Construct byte 4 */ + frame[4] = (uint8_t)(Arg); /* Construct byte 5 */ + frame[5] = (Crc | 0x01); /* Construct byte 6 */ + + /* Send the command */ + SD_IO_CSState(0); + SD_IO_WriteReadData(frame, frameout, SD_CMD_LENGTH); /* Send the Cmd bytes */ + + switch(Answer) { + case SD_ANSWER_R1_EXPECTED: + retr.r1 = SD_ReadData(); + break; + case SD_ANSWER_R1B_EXPECTED: + retr.r1 = SD_ReadData(); + retr.r2 = SD_IO_WriteByte(SD_DUMMY_BYTE); + /* Set CS High */ + SD_IO_CSState(1); + HAL_Delay(1); + /* Set CS Low */ + SD_IO_CSState(0); + + /* Wait IO line return 0xFF */ + while(SD_IO_WriteByte(SD_DUMMY_BYTE) != 0xFF) + ; + break; + case SD_ANSWER_R2_EXPECTED: + retr.r1 = SD_ReadData(); + retr.r2 = SD_IO_WriteByte(SD_DUMMY_BYTE); + break; + case SD_ANSWER_R3_EXPECTED: + case SD_ANSWER_R7_EXPECTED: + retr.r1 = SD_ReadData(); + retr.r2 = SD_IO_WriteByte(SD_DUMMY_BYTE); + retr.r3 = SD_IO_WriteByte(SD_DUMMY_BYTE); + retr.r4 = SD_IO_WriteByte(SD_DUMMY_BYTE); + retr.r5 = SD_IO_WriteByte(SD_DUMMY_BYTE); + break; + default: + break; + } + return retr; +} + +/** + * @brief Gets the SD card data response and check the busy flag. + * @param None + * @retval The SD status: Read data response xxx01 + * - status 010: Data accecpted + * - status 101: Data rejected due to a crc error + * - status 110: Data rejected due to a Write error. + * - status 111: Data rejected due to other error. + */ +uint8_t SD_GetDataResponse(void) { + uint8_t dataresponse; + uint8_t rvalue = SD_DATA_OTHER_ERROR; + + dataresponse = SD_IO_WriteByte(SD_DUMMY_BYTE); + SD_IO_WriteByte(SD_DUMMY_BYTE); /* read the busy response byte*/ + + /* Mask unused bits */ + switch(dataresponse & 0x1F) { + case SD_DATA_OK: + rvalue = SD_DATA_OK; + + /* Set CS High */ + SD_IO_CSState(1); + /* Set CS Low */ + SD_IO_CSState(0); + + /* Wait IO line return 0xFF */ + while(SD_IO_WriteByte(SD_DUMMY_BYTE) != 0xFF) + ; + break; + case SD_DATA_CRC_ERROR: + rvalue = SD_DATA_CRC_ERROR; + break; + case SD_DATA_WRITE_ERROR: + rvalue = SD_DATA_WRITE_ERROR; + break; + default: + break; + } + + /* Return response */ + return rvalue; +} + +/** + * @brief Put the SD in Idle state. + * @param None + * @retval SD status + */ +uint8_t SD_GoIdleState(void) { + SD_CmdAnswer_typedef response; + __IO uint8_t counter; + /* Send CMD0 (SD_CMD_GO_IDLE_STATE) to put SD in SPI mode and + wait for In Idle State Response (R1 Format) equal to 0x01 */ + counter = 0; + do { + counter++; + response = SD_SendCmd(SD_CMD_GO_IDLE_STATE, 0, 0x95, SD_ANSWER_R1_EXPECTED); + SD_IO_CSState(1); + SD_IO_WriteByte(SD_DUMMY_BYTE); + if(counter >= SD_MAX_TRY) { + return BSP_SD_ERROR; + } + } while(response.r1 != SD_R1_IN_IDLE_STATE); + + /* Send CMD8 (SD_CMD_SEND_IF_COND) to check the power supply status + and wait until response (R7 Format) equal to 0xAA and */ + response = SD_SendCmd(SD_CMD_SEND_IF_COND, 0x1AA, 0x87, SD_ANSWER_R7_EXPECTED); + SD_IO_CSState(1); + SD_IO_WriteByte(SD_DUMMY_BYTE); + if((response.r1 & SD_R1_ILLEGAL_COMMAND) == SD_R1_ILLEGAL_COMMAND) { + /* initialise card V1 */ + counter = 0; + do { + counter++; + /* initialise card V1 */ + /* Send CMD55 (SD_CMD_APP_CMD) before any ACMD command: R1 response (0x00: no errors) */ + response = SD_SendCmd(SD_CMD_APP_CMD, 0x00000000, 0xFF, SD_ANSWER_R1_EXPECTED); + SD_IO_CSState(1); + SD_IO_WriteByte(SD_DUMMY_BYTE); + + /* Send ACMD41 (SD_CMD_SD_APP_OP_COND) to initialize SDHC or SDXC cards: R1 response (0x00: no errors) */ + response = SD_SendCmd(SD_CMD_SD_APP_OP_COND, 0x00000000, 0xFF, SD_ANSWER_R1_EXPECTED); + SD_IO_CSState(1); + SD_IO_WriteByte(SD_DUMMY_BYTE); + if(counter >= SD_MAX_TRY) { + return BSP_SD_ERROR; + } + } while(response.r1 == SD_R1_IN_IDLE_STATE); + flag_SDHC = 0; + } else if(response.r1 == SD_R1_IN_IDLE_STATE) { + /* initialise card V2 */ + counter = 0; + do { + counter++; + /* Send CMD55 (SD_CMD_APP_CMD) before any ACMD command: R1 response (0x00: no errors) */ + response = SD_SendCmd(SD_CMD_APP_CMD, 0, 0xFF, SD_ANSWER_R1_EXPECTED); + SD_IO_CSState(1); + SD_IO_WriteByte(SD_DUMMY_BYTE); + + /* Send ACMD41 (SD_CMD_SD_APP_OP_COND) to initialize SDHC or SDXC cards: R1 response (0x00: no errors) */ + response = SD_SendCmd(SD_CMD_SD_APP_OP_COND, 0x40000000, 0xFF, SD_ANSWER_R1_EXPECTED); + SD_IO_CSState(1); + SD_IO_WriteByte(SD_DUMMY_BYTE); + if(counter >= SD_MAX_TRY) { + return BSP_SD_ERROR; + } + } while(response.r1 == SD_R1_IN_IDLE_STATE); + + if((response.r1 & SD_R1_ILLEGAL_COMMAND) == SD_R1_ILLEGAL_COMMAND) { + counter = 0; + do { + counter++; + /* Send CMD55 (SD_CMD_APP_CMD) before any ACMD command: R1 response (0x00: no errors) */ + response = SD_SendCmd(SD_CMD_APP_CMD, 0, 0xFF, SD_ANSWER_R1_EXPECTED); + SD_IO_CSState(1); + SD_IO_WriteByte(SD_DUMMY_BYTE); + if(response.r1 != SD_R1_IN_IDLE_STATE) { + return BSP_SD_ERROR; + } + /* Send ACMD41 (SD_CMD_SD_APP_OP_COND) to initialize SDHC or SDXC cards: R1 response (0x00: no errors) */ + response = + SD_SendCmd(SD_CMD_SD_APP_OP_COND, 0x00000000, 0xFF, SD_ANSWER_R1_EXPECTED); + SD_IO_CSState(1); + SD_IO_WriteByte(SD_DUMMY_BYTE); + if(counter >= SD_MAX_TRY) { + return BSP_SD_ERROR; + } + } while(response.r1 == SD_R1_IN_IDLE_STATE); + } + + /* Send CMD58 (SD_CMD_READ_OCR) to initialize SDHC or SDXC cards: R3 response (0x00: no errors) */ + response = SD_SendCmd(SD_CMD_READ_OCR, 0x00000000, 0xFF, SD_ANSWER_R3_EXPECTED); + SD_IO_CSState(1); + SD_IO_WriteByte(SD_DUMMY_BYTE); + if(response.r1 != SD_R1_NO_ERROR) { + return BSP_SD_ERROR; + } + flag_SDHC = (response.r2 & 0x40) >> 6; + } else { + return BSP_SD_ERROR; + } + + return BSP_SD_OK; +} + +/** + * @brief Waits a data until a value different from SD_DUMMY_BITE + * @param None + * @retval the value read + */ +uint8_t SD_ReadData(void) { + uint8_t timeout = 0x08; + uint8_t readvalue; + + /* Check if response is got or a timeout is happen */ + do { + readvalue = SD_IO_WriteByte(SD_DUMMY_BYTE); + timeout--; + + } while((readvalue == SD_DUMMY_BYTE) && timeout); + + /* Right response got */ + return readvalue; +} + +/** + * @brief Waits a data from the SD card + * @param data : Expected data from the SD card + * @retval BSP_SD_OK or BSP_SD_TIMEOUT + */ +uint8_t SD_WaitData(uint8_t data) { + uint16_t timeout = 0xFFFF; + uint8_t readvalue; + + /* Check if response is got or a timeout is happen */ + + do { + readvalue = SD_IO_WriteByte(SD_DUMMY_BYTE); + timeout--; + } while((readvalue != data) && timeout); + + if(timeout == 0) { + /* After time out */ + return BSP_SD_TIMEOUT; + } + + /* Right response got */ + return BSP_SD_OK; +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/Src/fatfs/stm32_adafruit_sd.h b/firmware/targets/f7/Src/fatfs/stm32_adafruit_sd.h new file mode 100644 index 00000000..38f9da49 --- /dev/null +++ b/firmware/targets/f7/Src/fatfs/stm32_adafruit_sd.h @@ -0,0 +1,252 @@ +/** + ****************************************************************************** + * @file stm32_adafruit_sd.h + * @author MCD Application Team + * @version V3.0.0 + * @date 23-December-2016 + * @brief This file contains the common defines and functions prototypes for + * the stm32_adafruit_sd.c driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32_ADAFRUIT_SD_H +#define __STM32_ADAFRUIT_SD_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include +#include + +/** @addtogroup BSP + * @{ + */ +#define __IO volatile + +/** @addtogroup STM32_ADAFRUIT + * @{ + */ + +/** @defgroup STM32_ADAFRUIT_SD + * @{ + */ + +/** @defgroup STM32_ADAFRUIT_SD_Exported_Types + * @{ + */ + +/** + * @brief SD status structure definition + */ +enum { + BSP_SD_OK = 0x00, + MSD_OK = 0x00, + BSP_SD_ERROR = 0x01, + BSP_SD_TIMEOUT +}; + +typedef struct +{ + uint8_t Reserved1:2; /* Reserved */ + uint16_t DeviceSize:12; /* Device Size */ + uint8_t MaxRdCurrentVDDMin:3; /* Max. read current @ VDD min */ + uint8_t MaxRdCurrentVDDMax:3; /* Max. read current @ VDD max */ + uint8_t MaxWrCurrentVDDMin:3; /* Max. write current @ VDD min */ + uint8_t MaxWrCurrentVDDMax:3; /* Max. write current @ VDD max */ + uint8_t DeviceSizeMul:3; /* Device size multiplier */ +} struct_v1; + + +typedef struct +{ + uint8_t Reserved1:6; /* Reserved */ + uint32_t DeviceSize:22; /* Device Size */ + uint8_t Reserved2:1; /* Reserved */ +} struct_v2; + +/** + * @brief Card Specific Data: CSD Register + */ +typedef struct +{ + /* Header part */ + uint8_t CSDStruct:2; /* CSD structure */ + uint8_t Reserved1:6; /* Reserved */ + uint8_t TAAC:8; /* Data read access-time 1 */ + uint8_t NSAC:8; /* Data read access-time 2 in CLK cycles */ + uint8_t MaxBusClkFrec:8; /* Max. bus clock frequency */ + uint16_t CardComdClasses:12; /* Card command classes */ + uint8_t RdBlockLen:4; /* Max. read data block length */ + uint8_t PartBlockRead:1; /* Partial blocks for read allowed */ + uint8_t WrBlockMisalign:1; /* Write block misalignment */ + uint8_t RdBlockMisalign:1; /* Read block misalignment */ + uint8_t DSRImpl:1; /* DSR implemented */ + + /* v1 or v2 struct */ + union csd_version { + struct_v1 v1; + struct_v2 v2; + } version; + + uint8_t EraseSingleBlockEnable:1; /* Erase single block enable */ + uint8_t EraseSectorSize:7; /* Erase group size multiplier */ + uint8_t WrProtectGrSize:7; /* Write protect group size */ + uint8_t WrProtectGrEnable:1; /* Write protect group enable */ + uint8_t Reserved2:2; /* Reserved */ + uint8_t WrSpeedFact:3; /* Write speed factor */ + uint8_t MaxWrBlockLen:4; /* Max. write data block length */ + uint8_t WriteBlockPartial:1; /* Partial blocks for write allowed */ + uint8_t Reserved3:5; /* Reserved */ + uint8_t FileFormatGrouop:1; /* File format group */ + uint8_t CopyFlag:1; /* Copy flag (OTP) */ + uint8_t PermWrProtect:1; /* Permanent write protection */ + uint8_t TempWrProtect:1; /* Temporary write protection */ + uint8_t FileFormat:2; /* File Format */ + uint8_t Reserved4:2; /* Reserved */ + uint8_t crc:7; /* Reserved */ + uint8_t Reserved5:1; /* always 1*/ + +} SD_CSD; + +/** + * @brief Card Identification Data: CID Register + */ +typedef struct +{ + __IO uint8_t ManufacturerID; /* ManufacturerID */ + __IO uint16_t OEM_AppliID; /* OEM/Application ID */ + __IO uint32_t ProdName1; /* Product Name part1 */ + __IO uint8_t ProdName2; /* Product Name part2*/ + __IO uint8_t ProdRev; /* Product Revision */ + __IO uint32_t ProdSN; /* Product Serial Number */ + __IO uint8_t Reserved1; /* Reserved1 */ + __IO uint16_t ManufactDate; /* Manufacturing Date */ + __IO uint8_t CID_CRC; /* CID CRC */ + __IO uint8_t Reserved2; /* always 1 */ +} SD_CID; + +/** + * @brief SD Card information + */ +typedef struct +{ + SD_CSD Csd; + SD_CID Cid; + uint64_t CardCapacity; /*!< Card Capacity */ + uint32_t CardBlockSize; /*!< Card Block Size */ + uint32_t LogBlockNbr; /*!< Specifies the Card logical Capacity in blocks */ + uint32_t LogBlockSize; /*!< Specifies logical block size in bytes */ +} SD_CardInfo; + +/** + * @} + */ + +/** @defgroup STM32_ADAFRUIT_SPI_SD_Exported_Constants + * @{ + */ + +/** + * @brief Block Size + */ +#define SD_BLOCK_SIZE 0x200 + +/** + * @brief SD detection on its memory slot + */ +#define SD_PRESENT ((uint8_t)0x01) +#define SD_NOT_PRESENT ((uint8_t)0x00) + +#define SD_DATATIMEOUT ((uint32_t)100000000) + +/** + * @brief SD Card information structure + */ +#define BSP_SD_CardInfo SD_CardInfo + +/** + * @} + */ + +/** @defgroup STM32_ADAFRUIT_SD_Exported_Macro + * @{ + */ + +/** + * @} + */ + +/** @defgroup STM32_ADAFRUIT_SD_Exported_Functions + * @{ + */ +uint8_t BSP_SD_Init(bool reset_card); +uint8_t BSP_SD_ReadBlocks(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks, uint32_t Timeout); +uint8_t BSP_SD_WriteBlocks(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks, uint32_t Timeout); +uint8_t BSP_SD_Erase(uint32_t StartAddr, uint32_t EndAddr); +uint8_t BSP_SD_GetCardState(void); +uint8_t BSP_SD_GetCardInfo(SD_CardInfo *pCardInfo); + +/* Link functions for SD Card peripheral*/ +void SD_SPI_Slow_Init(void); +void SD_SPI_Fast_Init(void); +void SD_IO_Init(void); +void SD_IO_CSState(uint8_t state); +void SD_IO_WriteReadData(const uint8_t *DataIn, uint8_t *DataOut, uint16_t DataLength); +uint8_t SD_IO_WriteByte(uint8_t Data); + +/* Link function for HAL delay */ +void HAL_Delay(__IO uint32_t Delay); + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32_ADAFRUIT_SD_H */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/Src/fatfs/syscall.c b/firmware/targets/f7/Src/fatfs/syscall.c new file mode 100644 index 00000000..8d488dc7 --- /dev/null +++ b/firmware/targets/f7/Src/fatfs/syscall.c @@ -0,0 +1,138 @@ +/*------------------------------------------------------------------------*/ +/* Sample code of OS dependent controls for FatFs */ +/* (C)ChaN, 2014 */ +/* Portions COPYRIGHT 2017 STMicroelectronics */ +/* Portions Copyright (C) 2014, ChaN, all right reserved */ +/*------------------------------------------------------------------------*/ + +/** + ****************************************************************************** + * @attention + * + * Copyright (c) 2017 STMicroelectronics. All rights reserved. + * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** +**/ + + + +#include "fatfs/ff.h" + + +#if _FS_REENTRANT +/*------------------------------------------------------------------------*/ +/* Create a Synchronization Object */ +/*------------------------------------------------------------------------*/ +/* This function is called in f_mount() function to create a new +/ synchronization object, such as semaphore and mutex. When a 0 is returned, +/ the f_mount() function fails with FR_INT_ERR. +*/ + +int ff_cre_syncobj ( /* 1:Function succeeded, 0:Could not create the sync object */ + BYTE vol, /* Corresponding volume (logical drive number) */ + _SYNC_t *sobj /* Pointer to return the created sync object */ +) +{ + + int ret; + + //osSemaphoreDef(SEM); + //*sobj = osSemaphoreCreate(osSemaphore(SEM), 1); + *sobj = osMutexNew(NULL); + ret = (*sobj != NULL); + + return ret; +} + + + +/*------------------------------------------------------------------------*/ +/* Delete a Synchronization Object */ +/*------------------------------------------------------------------------*/ +/* This function is called in f_mount() function to delete a synchronization +/ object that created with ff_cre_syncobj() function. When a 0 is returned, +/ the f_mount() function fails with FR_INT_ERR. +*/ + +int ff_del_syncobj ( /* 1:Function succeeded, 0:Could not delete due to any error */ + _SYNC_t sobj /* Sync object tied to the logical drive to be deleted */ +) +{ + osMutexDelete(sobj); + return 1; +} + + + +/*------------------------------------------------------------------------*/ +/* Request Grant to Access the Volume */ +/*------------------------------------------------------------------------*/ +/* This function is called on entering file functions to lock the volume. +/ When a 0 is returned, the file function fails with FR_TIMEOUT. +*/ + +int ff_req_grant ( /* 1:Got a grant to access the volume, 0:Could not get a grant */ + _SYNC_t sobj /* Sync object to wait */ +) +{ + int ret = 0; + + if(osMutexAcquire(sobj, _FS_TIMEOUT) == osOK) { + ret = 1; + } + + return ret; +} + + + +/*------------------------------------------------------------------------*/ +/* Release Grant to Access the Volume */ +/*------------------------------------------------------------------------*/ +/* This function is called on leaving file functions to unlock the volume. +*/ + +void ff_rel_grant ( + _SYNC_t sobj /* Sync object to be signaled */ +) +{ + osMutexRelease(sobj); +} + +#endif + + + + +#if _USE_LFN == 3 /* LFN with a working buffer on the heap */ +/*------------------------------------------------------------------------*/ +/* Allocate a memory block */ +/*------------------------------------------------------------------------*/ +/* If a NULL is returned, the file function fails with FR_NOT_ENOUGH_CORE. +*/ + +void* ff_memalloc ( /* Returns pointer to the allocated memory block */ + UINT msize /* Number of bytes to allocate */ +) +{ + return ff_malloc(msize); /* Allocate a new memory block with POSIX API */ +} + + +/*------------------------------------------------------------------------*/ +/* Free a memory block */ +/*------------------------------------------------------------------------*/ + +void ff_memfree ( + void* mblock /* Pointer to the memory block to free */ +) +{ + ff_free(mblock); /* Discard the memory block with POSIX API */ +} + +#endif diff --git a/firmware/targets/f7/Src/fatfs/user_diskio.c b/firmware/targets/f7/Src/fatfs/user_diskio.c new file mode 100644 index 00000000..ca3d60a5 --- /dev/null +++ b/firmware/targets/f7/Src/fatfs/user_diskio.c @@ -0,0 +1,223 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file user_diskio.c + * @brief This file includes a diskio driver skeleton to be completed by the user. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2020 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +#ifdef USE_OBSOLETE_USER_CODE_SECTION_0 +/* + * Warning: the user section 0 is no more in use (starting from CubeMx version 4.16.0) + * To be suppressed in the future. + * Kept to ensure backward compatibility with previous CubeMx versions when + * migrating projects. + * User code previously added there should be copied in the new user sections before + * the section contents can be deleted. + */ +/* USER CODE BEGIN 0 */ +/* USER CODE END 0 */ +#endif + +/* USER CODE BEGIN DECL */ + +/* Includes ------------------------------------------------------------------*/ +#include "user_diskio.h" +#include "furi-hal-spi.h" +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ + +/* Private variables ---------------------------------------------------------*/ +/* Disk status */ +static volatile DSTATUS Stat = STA_NOINIT; + +static DSTATUS User_CheckStatus(BYTE lun) { + Stat = STA_NOINIT; + if(BSP_SD_GetCardState() == MSD_OK) { + Stat &= ~STA_NOINIT; + } + + return Stat; +} + +/* USER CODE END DECL */ + +/* Private function prototypes -----------------------------------------------*/ +DSTATUS USER_initialize(BYTE pdrv); +DSTATUS USER_status(BYTE pdrv); +DRESULT USER_read(BYTE pdrv, BYTE* buff, DWORD sector, UINT count); +#if _USE_WRITE == 1 +DRESULT USER_write(BYTE pdrv, const BYTE* buff, DWORD sector, UINT count); +#endif /* _USE_WRITE == 1 */ +#if _USE_IOCTL == 1 +DRESULT USER_ioctl(BYTE pdrv, BYTE cmd, void* buff); +#endif /* _USE_IOCTL == 1 */ + +Diskio_drvTypeDef USER_Driver = { + USER_initialize, + USER_status, + USER_read, +#if _USE_WRITE + USER_write, +#endif /* _USE_WRITE == 1 */ +#if _USE_IOCTL == 1 + USER_ioctl, +#endif /* _USE_IOCTL == 1 */ +}; + +/* Private functions ---------------------------------------------------------*/ + +/** + * @brief Initializes a Drive + * @param pdrv: Physical drive number (0..) + * @retval DSTATUS: Operation status + */ +DSTATUS USER_initialize(BYTE pdrv) { + /* USER CODE BEGIN INIT */ + + const FuriHalSpiDevice* sd_spi_fast_dev = furi_hal_spi_device_get(FuriHalSpiDeviceIdSdCardFast); + + DSTATUS status = User_CheckStatus(pdrv); + + furi_hal_spi_device_return(sd_spi_fast_dev); + + return status; + /* USER CODE END INIT */ +} + +/** + * @brief Gets Disk Status + * @param pdrv: Physical drive number (0..) + * @retval DSTATUS: Operation status + */ +DSTATUS USER_status(BYTE pdrv) { + /* USER CODE BEGIN STATUS */ + return Stat; + /* USER CODE END STATUS */ +} + +/** + * @brief Reads Sector(s) + * @param pdrv: Physical drive number (0..) + * @param *buff: Data buffer to store read data + * @param sector: Sector address (LBA) + * @param count: Number of sectors to read (1..128) + * @retval DRESULT: Operation result + */ +DRESULT USER_read(BYTE pdrv, BYTE* buff, DWORD sector, UINT count) { + /* USER CODE BEGIN READ */ + DRESULT res = RES_ERROR; + + const FuriHalSpiDevice* sd_spi_fast_dev = furi_hal_spi_device_get(FuriHalSpiDeviceIdSdCardFast); + + if(BSP_SD_ReadBlocks((uint32_t*)buff, (uint32_t)(sector), count, SD_DATATIMEOUT) == MSD_OK) { + /* wait until the read operation is finished */ + while(BSP_SD_GetCardState() != MSD_OK) { + } + res = RES_OK; + } + + furi_hal_spi_device_return(sd_spi_fast_dev); + + return res; + /* USER CODE END READ */ +} + +/** + * @brief Writes Sector(s) + * @param pdrv: Physical drive number (0..) + * @param *buff: Data to be written + * @param sector: Sector address (LBA) + * @param count: Number of sectors to write (1..128) + * @retval DRESULT: Operation result + */ +#if _USE_WRITE == 1 +DRESULT USER_write(BYTE pdrv, const BYTE* buff, DWORD sector, UINT count) { + /* USER CODE BEGIN WRITE */ + /* USER CODE HERE */ + DRESULT res = RES_ERROR; + + const FuriHalSpiDevice* sd_spi_fast_dev = furi_hal_spi_device_get(FuriHalSpiDeviceIdSdCardFast); + + if(BSP_SD_WriteBlocks((uint32_t*)buff, (uint32_t)(sector), count, SD_DATATIMEOUT) == MSD_OK) { + /* wait until the Write operation is finished */ + while(BSP_SD_GetCardState() != MSD_OK) { + } + res = RES_OK; + } + + furi_hal_spi_device_return(sd_spi_fast_dev); + + return res; + /* USER CODE END WRITE */ +} +#endif /* _USE_WRITE == 1 */ + +/** + * @brief I/O control operation + * @param pdrv: Physical drive number (0..) + * @param cmd: Control code + * @param *buff: Buffer to send/receive control data + * @retval DRESULT: Operation result + */ +#if _USE_IOCTL == 1 +DRESULT USER_ioctl(BYTE pdrv, BYTE cmd, void* buff) { + /* USER CODE BEGIN IOCTL */ + DRESULT res = RES_ERROR; + BSP_SD_CardInfo CardInfo; + + if(Stat & STA_NOINIT) return RES_NOTRDY; + + const FuriHalSpiDevice* sd_spi_fast_dev = furi_hal_spi_device_get(FuriHalSpiDeviceIdSdCardFast); + + switch(cmd) { + /* Make sure that no pending write process */ + case CTRL_SYNC: + res = RES_OK; + break; + + /* Get number of sectors on the disk (DWORD) */ + case GET_SECTOR_COUNT: + BSP_SD_GetCardInfo(&CardInfo); + *(DWORD*)buff = CardInfo.LogBlockNbr; + res = RES_OK; + break; + + /* Get R/W sector size (WORD) */ + case GET_SECTOR_SIZE: + BSP_SD_GetCardInfo(&CardInfo); + *(WORD*)buff = CardInfo.LogBlockSize; + res = RES_OK; + break; + + /* Get erase block size in unit of sector (DWORD) */ + case GET_BLOCK_SIZE: + BSP_SD_GetCardInfo(&CardInfo); + *(DWORD*)buff = CardInfo.LogBlockSize; + res = RES_OK; + break; + + default: + res = RES_PARERR; + } + + furi_hal_spi_device_return(sd_spi_fast_dev); + + return res; + /* USER CODE END IOCTL */ +} +#endif /* _USE_IOCTL == 1 */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ \ No newline at end of file diff --git a/firmware/targets/f7/Src/fatfs/user_diskio.h b/firmware/targets/f7/Src/fatfs/user_diskio.h new file mode 100644 index 00000000..177723be --- /dev/null +++ b/firmware/targets/f7/Src/fatfs/user_diskio.h @@ -0,0 +1,48 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file user_diskio.h + * @brief This file contains the common defines and functions prototypes for + * the user_diskio driver. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2020 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USER_DISKIO_H +#define __USER_DISKIO_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* USER CODE BEGIN 0 */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32_adafruit_sd.h" +#include "fatfs/ff_gen_drv.h" +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ +extern Diskio_drvTypeDef USER_Driver; + +/* USER CODE END 0 */ + +#ifdef __cplusplus +} +#endif + +#endif /* __USER_DISKIO_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/Src/freertos-openocd.c b/firmware/targets/f7/Src/freertos-openocd.c new file mode 100644 index 00000000..abde4411 --- /dev/null +++ b/firmware/targets/f7/Src/freertos-openocd.c @@ -0,0 +1,21 @@ + +/* + * Since at least FreeRTOS V7.5.3 uxTopUsedPriority is no longer + * present in the kernel, so it has to be supplied by other means for + * OpenOCD's threads awareness. + * + * Add this file to your project, and, if you're using --gc-sections, + * ``--undefined=uxTopUsedPriority'' (or + * ``-Wl,--undefined=uxTopUsedPriority'' when using gcc for final + * linking) to your LDFLAGS; same with all the other symbols you need. + */ + +#include "FreeRTOS.h" + +#ifdef __GNUC__ +#define USED __attribute__((used)) +#else +#define USED +#endif + +const int USED uxTopUsedPriority = configMAX_PRIORITIES - 1; \ No newline at end of file diff --git a/firmware/targets/f7/Src/gpio.c b/firmware/targets/f7/Src/gpio.c new file mode 100644 index 00000000..8363bc91 --- /dev/null +++ b/firmware/targets/f7/Src/gpio.c @@ -0,0 +1,139 @@ +#include "gpio.h" + +void MX_GPIO_Init(void) { + GPIO_InitTypeDef GPIO_InitStruct = {0}; + + /* GPIO Ports Clock Enable */ + __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOD_CLK_ENABLE(); + __HAL_RCC_GPIOE_CLK_ENABLE(); + __HAL_RCC_GPIOH_CLK_ENABLE(); + + /*Configure GPIO pin : PtPin */ + GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING; + GPIO_InitStruct.Pull = GPIO_PULLUP; + GPIO_InitStruct.Pin = BUTTON_BACK_Pin; + HAL_GPIO_Init(BUTTON_BACK_GPIO_Port, &GPIO_InitStruct); + + /*Configure GPIO pin : PtPin */ + GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Pin = BUTTON_OK_Pin; + HAL_GPIO_Init(BUTTON_OK_GPIO_Port, &GPIO_InitStruct); + + /*Configure GPIO pins : PCPin PCPin PCPin PCPin */ + GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Pin = PC0_Pin; + HAL_GPIO_Init(PC0_GPIO_Port, &GPIO_InitStruct); + GPIO_InitStruct.Pin = PC1_Pin; + HAL_GPIO_Init(PC1_GPIO_Port, &GPIO_InitStruct); + GPIO_InitStruct.Pin = PC3_Pin; + HAL_GPIO_Init(PC3_GPIO_Port, &GPIO_InitStruct); + GPIO_InitStruct.Pin = VIBRO_Pin; + HAL_GPIO_Init(VIBRO_GPIO_Port, &GPIO_InitStruct); + + /* RF_SW_0 */ + HAL_GPIO_WritePin(RF_SW_0_GPIO_Port, RF_SW_0_Pin, GPIO_PIN_RESET); + GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStruct.Pin = RF_SW_0_Pin; + HAL_GPIO_Init(RF_SW_0_GPIO_Port, &GPIO_InitStruct); + + /* PERIPH_POWER */ + HAL_GPIO_WritePin(PERIPH_POWER_GPIO_Port, PERIPH_POWER_Pin, GPIO_PIN_SET); + GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStruct.Pin = PERIPH_POWER_Pin; + HAL_GPIO_Init(PERIPH_POWER_GPIO_Port, &GPIO_InitStruct); + + /*Configure GPIO pins : PAPin PAPin PAPin */ + GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Pin = PA4_Pin; + HAL_GPIO_Init(PA4_GPIO_Port, &GPIO_InitStruct); + GPIO_InitStruct.Pin = PA6_Pin; + HAL_GPIO_Init(PA6_GPIO_Port, &GPIO_InitStruct); + GPIO_InitStruct.Pin = PA7_Pin; + HAL_GPIO_Init(PA7_GPIO_Port, &GPIO_InitStruct); + + /*Configure GPIO pin : PtPin */ + GPIO_InitStruct.Pin = RFID_PULL_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING; + GPIO_InitStruct.Pull = GPIO_NOPULL; + HAL_GPIO_Init(RFID_PULL_GPIO_Port, &GPIO_InitStruct); + + /*Configure GPIO pins : PBPin PBPin PBPin */ + GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Pin = PB2_Pin; + HAL_GPIO_Init(PB2_GPIO_Port, &GPIO_InitStruct); + GPIO_InitStruct.Pin = iBTN_Pin; + HAL_GPIO_Init(iBTN_GPIO_Port, &GPIO_InitStruct); + GPIO_InitStruct.Pin = PB3_Pin; + HAL_GPIO_Init(PB3_GPIO_Port, &GPIO_InitStruct); + + /*Configure GPIO pins : PBPin PBPin PBPin PBPin */ + GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING; + GPIO_InitStruct.Pull = GPIO_PULLUP; + GPIO_InitStruct.Pin = BUTTON_UP_Pin; + HAL_GPIO_Init(BUTTON_UP_GPIO_Port, &GPIO_InitStruct); + GPIO_InitStruct.Pin = BUTTON_LEFT_Pin; + HAL_GPIO_Init(BUTTON_LEFT_GPIO_Port, &GPIO_InitStruct); + GPIO_InitStruct.Pin = BUTTON_RIGHT_Pin; + HAL_GPIO_Init(BUTTON_RIGHT_GPIO_Port, &GPIO_InitStruct); + + /*Configure GPIO pins : PBPin PBPin PBPin PBPin */ + GPIO_InitStruct.Pin = BUTTON_DOWN_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING; + GPIO_InitStruct.Pull = GPIO_PULLUP; + HAL_GPIO_Init(BUTTON_DOWN_GPIO_Port, &GPIO_InitStruct); + + /* DISPLAY_RST */ + HAL_GPIO_WritePin(DISPLAY_RST_GPIO_Port, DISPLAY_RST_Pin, GPIO_PIN_RESET); + GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStruct.Pin = DISPLAY_RST_Pin; + HAL_GPIO_Init(DISPLAY_RST_GPIO_Port, &GPIO_InitStruct); + + /* DISPLAY_DI */ + HAL_GPIO_WritePin(DISPLAY_DI_GPIO_Port, DISPLAY_DI_Pin, GPIO_PIN_RESET); + GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStruct.Pin = DISPLAY_DI_Pin; + HAL_GPIO_Init(DISPLAY_DI_GPIO_Port, &GPIO_InitStruct); + + /* SD_CD */ + GPIO_InitStruct.Pin = SD_CD_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_INPUT; + GPIO_InitStruct.Pull = GPIO_NOPULL; + HAL_GPIO_Init(SD_CD_GPIO_Port, &GPIO_InitStruct); + + /* Enable all NVIC lines related to gpio */ + HAL_NVIC_SetPriority(EXTI0_IRQn, 5, 0); + HAL_NVIC_EnableIRQ(EXTI0_IRQn); + + HAL_NVIC_SetPriority(EXTI1_IRQn, 5, 0); + HAL_NVIC_EnableIRQ(EXTI1_IRQn); + + HAL_NVIC_SetPriority(EXTI2_IRQn, 5, 0); + HAL_NVIC_EnableIRQ(EXTI2_IRQn); + + HAL_NVIC_SetPriority(EXTI3_IRQn, 5, 0); + HAL_NVIC_EnableIRQ(EXTI3_IRQn); + + HAL_NVIC_SetPriority(EXTI4_IRQn, 5, 0); + HAL_NVIC_EnableIRQ(EXTI4_IRQn); + + HAL_NVIC_SetPriority(EXTI9_5_IRQn, 5, 0); + HAL_NVIC_EnableIRQ(EXTI9_5_IRQn); + + HAL_NVIC_SetPriority(EXTI15_10_IRQn, 5, 0); + HAL_NVIC_EnableIRQ(EXTI15_10_IRQn); +} diff --git a/firmware/targets/f7/Src/main.c b/firmware/targets/f7/Src/main.c new file mode 100644 index 00000000..b9deedf2 --- /dev/null +++ b/firmware/targets/f7/Src/main.c @@ -0,0 +1,55 @@ +#include "main.h" + +#include "fatfs/fatfs.h" + +#include +#include +#include + +int main(void) { + // Initialize FURI layer + furi_init(); + + // Initialize ST HAL + HAL_Init(); + + // Flipper FURI HAL + furi_hal_init(); + + // 3rd party + MX_FATFS_Init(); + FURI_LOG_I("HAL", "FATFS OK"); + + // CMSIS initialization + osKernelInitialize(); + FURI_LOG_I("HAL", "KERNEL OK"); + + // Init flipper + flipper_init(); + + // Start kernel + osKernelStart(); + + while (1) {} +} + +void Error_Handler(void) { + asm("bkpt 1"); + while(1) {} +} + +#ifdef USE_FULL_ASSERT +/** + * @brief Reports the name of the source file and the source line number + * where the assert_param error has occurred. + * @param file: pointer to the source file name + * @param line: assert_param error line source number + * @retval None + */ +void assert_failed(uint8_t *file, uint32_t line) { + /* USER CODE BEGIN 6 */ + /* User can add his own implementation to report the file name and line number, + tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ + /* USER CODE END 6 */ +} +#endif /* USE_FULL_ASSERT */ diff --git a/firmware/targets/f7/Src/pka.c b/firmware/targets/f7/Src/pka.c new file mode 100644 index 00000000..8377ce57 --- /dev/null +++ b/firmware/targets/f7/Src/pka.c @@ -0,0 +1,77 @@ +/** + ****************************************************************************** + * @file pka.c + * @brief This file provides code for the configuration + * of the PKA instances. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "pka.h" + +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ + +PKA_HandleTypeDef hpka; + +/* PKA init function */ +void MX_PKA_Init(void) +{ + + hpka.Instance = PKA; + if (HAL_PKA_Init(&hpka) != HAL_OK) + { + Error_Handler(); + } + +} + +void HAL_PKA_MspInit(PKA_HandleTypeDef* pkaHandle) +{ + + if(pkaHandle->Instance==PKA) + { + /* USER CODE BEGIN PKA_MspInit 0 */ + + /* USER CODE END PKA_MspInit 0 */ + /* PKA clock enable */ + __HAL_RCC_PKA_CLK_ENABLE(); + /* USER CODE BEGIN PKA_MspInit 1 */ + + /* USER CODE END PKA_MspInit 1 */ + } +} + +void HAL_PKA_MspDeInit(PKA_HandleTypeDef* pkaHandle) +{ + + if(pkaHandle->Instance==PKA) + { + /* USER CODE BEGIN PKA_MspDeInit 0 */ + + /* USER CODE END PKA_MspDeInit 0 */ + /* Peripheral clock disable */ + __HAL_RCC_PKA_CLK_DISABLE(); + /* USER CODE BEGIN PKA_MspDeInit 1 */ + + /* USER CODE END PKA_MspDeInit 1 */ + } +} + +/* USER CODE BEGIN 1 */ + +/* USER CODE END 1 */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/Src/rf.c b/firmware/targets/f7/Src/rf.c new file mode 100644 index 00000000..62daf9b2 --- /dev/null +++ b/firmware/targets/f7/Src/rf.c @@ -0,0 +1,37 @@ +/** + ****************************************************************************** + * @file rf.c + * @brief This file provides code for the configuration + * of the RF instances. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "rf.h" + +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ + +/* RF init function */ +void MX_RF_Init(void) +{ + +} + +/* USER CODE BEGIN 1 */ + +/* USER CODE END 1 */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/Src/rng.c b/firmware/targets/f7/Src/rng.c new file mode 100644 index 00000000..c2fb144e --- /dev/null +++ b/firmware/targets/f7/Src/rng.c @@ -0,0 +1,77 @@ +/** + ****************************************************************************** + * @file rng.c + * @brief This file provides code for the configuration + * of the RNG instances. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "rng.h" + +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ + +RNG_HandleTypeDef hrng; + +/* RNG init function */ +void MX_RNG_Init(void) +{ + + hrng.Instance = RNG; + if (HAL_RNG_Init(&hrng) != HAL_OK) + { + Error_Handler(); + } + +} + +void HAL_RNG_MspInit(RNG_HandleTypeDef* rngHandle) +{ + + if(rngHandle->Instance==RNG) + { + /* USER CODE BEGIN RNG_MspInit 0 */ + + /* USER CODE END RNG_MspInit 0 */ + /* RNG clock enable */ + __HAL_RCC_RNG_CLK_ENABLE(); + /* USER CODE BEGIN RNG_MspInit 1 */ + + /* USER CODE END RNG_MspInit 1 */ + } +} + +void HAL_RNG_MspDeInit(RNG_HandleTypeDef* rngHandle) +{ + + if(rngHandle->Instance==RNG) + { + /* USER CODE BEGIN RNG_MspDeInit 0 */ + + /* USER CODE END RNG_MspDeInit 0 */ + /* Peripheral clock disable */ + __HAL_RCC_RNG_CLK_DISABLE(); + /* USER CODE BEGIN RNG_MspDeInit 1 */ + + /* USER CODE END RNG_MspDeInit 1 */ + } +} + +/* USER CODE BEGIN 1 */ + +/* USER CODE END 1 */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/Src/rtc.c b/firmware/targets/f7/Src/rtc.c new file mode 100644 index 00000000..8a6f4c92 --- /dev/null +++ b/firmware/targets/f7/Src/rtc.c @@ -0,0 +1,123 @@ +/** + ****************************************************************************** + * @file rtc.c + * @brief This file provides code for the configuration + * of the RTC instances. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "rtc.h" + +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ + +RTC_HandleTypeDef hrtc; + +/* RTC init function */ +void MX_RTC_Init(void) +{ + RTC_TimeTypeDef sTime = {0}; + RTC_DateTypeDef sDate = {0}; + + /** Initialize RTC Only + */ + hrtc.Instance = RTC; + hrtc.Init.HourFormat = RTC_HOURFORMAT_24; + hrtc.Init.AsynchPrediv = 127; + hrtc.Init.SynchPrediv = 255; + hrtc.Init.OutPut = RTC_OUTPUT_DISABLE; + hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH; + hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN; + hrtc.Init.OutPutRemap = RTC_OUTPUT_REMAP_NONE; + if (HAL_RTC_Init(&hrtc) != HAL_OK) + { + Error_Handler(); + } + + /* USER CODE BEGIN Check_RTC_BKUP */ + return; + /* USER CODE END Check_RTC_BKUP */ + + /** Initialize RTC and set the Time and Date + */ + sTime.Hours = 0x0; + sTime.Minutes = 0x0; + sTime.Seconds = 0x0; + sTime.SubSeconds = 0x0; + sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE; + sTime.StoreOperation = RTC_STOREOPERATION_RESET; + if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BCD) != HAL_OK) + { + Error_Handler(); + } + sDate.WeekDay = RTC_WEEKDAY_MONDAY; + sDate.Month = RTC_MONTH_JANUARY; + sDate.Date = 0x1; + sDate.Year = 0x0; + + if (HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BCD) != HAL_OK) + { + Error_Handler(); + } + +} + +void HAL_RTC_MspInit(RTC_HandleTypeDef* rtcHandle) +{ + + if(rtcHandle->Instance==RTC) + { + /* USER CODE BEGIN RTC_MspInit 0 */ + + /* USER CODE END RTC_MspInit 0 */ + /* RTC clock enable */ + __HAL_RCC_RTC_ENABLE(); + __HAL_RCC_RTCAPB_CLK_ENABLE(); + + /* RTC interrupt Init */ + HAL_NVIC_SetPriority(TAMP_STAMP_LSECSS_IRQn, 5, 0); + HAL_NVIC_EnableIRQ(TAMP_STAMP_LSECSS_IRQn); + /* USER CODE BEGIN RTC_MspInit 1 */ + + /* USER CODE END RTC_MspInit 1 */ + } +} + +void HAL_RTC_MspDeInit(RTC_HandleTypeDef* rtcHandle) +{ + + if(rtcHandle->Instance==RTC) + { + /* USER CODE BEGIN RTC_MspDeInit 0 */ + + /* USER CODE END RTC_MspDeInit 0 */ + /* Peripheral clock disable */ + __HAL_RCC_RTC_DISABLE(); + __HAL_RCC_RTCAPB_CLK_DISABLE(); + + /* RTC interrupt Deinit */ + HAL_NVIC_DisableIRQ(TAMP_STAMP_LSECSS_IRQn); + /* USER CODE BEGIN RTC_MspDeInit 1 */ + + /* USER CODE END RTC_MspDeInit 1 */ + } +} + +/* USER CODE BEGIN 1 */ + +/* USER CODE END 1 */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/Src/stm32wbxx_hal_msp.c b/firmware/targets/f7/Src/stm32wbxx_hal_msp.c new file mode 100644 index 00000000..c96a5dfa --- /dev/null +++ b/firmware/targets/f7/Src/stm32wbxx_hal_msp.c @@ -0,0 +1,93 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * File Name : stm32wbxx_hal_msp.c + * Description : This file provides code for the MSP Initialization + * and de-Initialization codes. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2020 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +/* Includes ------------------------------------------------------------------*/ +#include "main.h" +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +/* Private typedef -----------------------------------------------------------*/ +/* USER CODE BEGIN TD */ + +/* USER CODE END TD */ + +/* Private define ------------------------------------------------------------*/ +/* USER CODE BEGIN Define */ + +/* USER CODE END Define */ + +/* Private macro -------------------------------------------------------------*/ +/* USER CODE BEGIN Macro */ + +/* USER CODE END Macro */ + +/* Private variables ---------------------------------------------------------*/ +/* USER CODE BEGIN PV */ + +/* USER CODE END PV */ + +/* Private function prototypes -----------------------------------------------*/ +/* USER CODE BEGIN PFP */ + +/* USER CODE END PFP */ + +/* External functions --------------------------------------------------------*/ +/* USER CODE BEGIN ExternalFunctions */ + +/* USER CODE END ExternalFunctions */ + +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ +/** + * Initializes the Global MSP. + */ +void HAL_MspInit(void) +{ + /* USER CODE BEGIN MspInit 0 */ + + /* USER CODE END MspInit 0 */ + + __HAL_RCC_HSEM_CLK_ENABLE(); + + /* System interrupt init*/ + /* PendSV_IRQn interrupt configuration */ + HAL_NVIC_SetPriority(PendSV_IRQn, 15, 0); + + /* Peripheral interrupt init */ + /* RCC_IRQn interrupt configuration */ + HAL_NVIC_SetPriority(RCC_IRQn, 5, 0); + HAL_NVIC_EnableIRQ(RCC_IRQn); + /* HSEM_IRQn interrupt configuration */ + HAL_NVIC_SetPriority(HSEM_IRQn, 5, 0); + HAL_NVIC_EnableIRQ(HSEM_IRQn); + + /* USER CODE BEGIN MspInit 1 */ + + /* USER CODE END MspInit 1 */ +} + +/* USER CODE BEGIN 1 */ + +/* USER CODE END 1 */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/Src/stm32wbxx_it.c b/firmware/targets/f7/Src/stm32wbxx_it.c new file mode 100644 index 00000000..01fbdc1d --- /dev/null +++ b/firmware/targets/f7/Src/stm32wbxx_it.c @@ -0,0 +1,52 @@ +#include "main.h" +#include "stm32wbxx_it.h" +#include "FreeRTOS.h" +#include "task.h" + +extern PCD_HandleTypeDef hpcd_USB_FS; +extern COMP_HandleTypeDef hcomp1; +extern RTC_HandleTypeDef hrtc; +extern TIM_HandleTypeDef htim1; +extern TIM_HandleTypeDef htim2; +extern TIM_HandleTypeDef htim16; +extern TIM_HandleTypeDef htim17; + +extern void HW_TS_RTC_Wakeup_Handler(); +extern void HW_IPCC_Tx_Handler(); +extern void HW_IPCC_Rx_Handler(); + +void SysTick_Handler(void) { + HAL_IncTick(); +} + +void USB_LP_IRQHandler(void) { + HAL_PCD_IRQHandler(&hpcd_USB_FS); +} + +void COMP_IRQHandler(void) { + HAL_COMP_IRQHandler(&hcomp1); +} + +void TIM1_TRG_COM_TIM17_IRQHandler(void) { + HAL_TIM_IRQHandler(&htim1); +} + +void TIM1_CC_IRQHandler(void) { + HAL_TIM_IRQHandler(&htim1); +} + +void HSEM_IRQHandler(void) { + HAL_HSEM_IRQHandler(); +} + +void RTC_WKUP_IRQHandler(void){ + HW_TS_RTC_Wakeup_Handler(); +} + +void IPCC_C1_TX_IRQHandler(void){ + HW_IPCC_Tx_Handler(); +} + +void IPCC_C1_RX_IRQHandler(void){ + HW_IPCC_Rx_Handler(); +} diff --git a/firmware/targets/f7/Src/system_stm32wbxx.c b/firmware/targets/f7/Src/system_stm32wbxx.c new file mode 100644 index 00000000..38db6ece --- /dev/null +++ b/firmware/targets/f7/Src/system_stm32wbxx.c @@ -0,0 +1,357 @@ +/** + ****************************************************************************** + * @file system_stm32wbxx.c + * @author MCD Application Team + * @brief CMSIS Cortex Device Peripheral Access Layer System Source File + * + * This file provides two functions and one global variable to be called from + * user application: + * - SystemInit(): This function is called at startup just after reset and + * before branch to main program. This call is made inside + * the "startup_stm32wbxx.s" file. + * + * - SystemCoreClock variable: Contains the core clock (HCLK), it can be used + * by the user application to setup the SysTick + * timer or configure other parameters. + * + * - SystemCoreClockUpdate(): Updates the variable SystemCoreClock and must + * be called whenever the core clock is changed + * during program execution. + * + * After each device reset the MSI (4 MHz) is used as system clock source. + * Then SystemInit() function is called, in "startup_stm32wbxx.s" file, to + * configure the system clock before to branch to main program. + * + * This file configures the system clock as follows: + *============================================================================= + *----------------------------------------------------------------------------- + * System Clock source | MSI + *----------------------------------------------------------------------------- + * SYSCLK(Hz) | 4000000 + *----------------------------------------------------------------------------- + * HCLK(Hz) | 4000000 + *----------------------------------------------------------------------------- + * AHB Prescaler | 1 + *----------------------------------------------------------------------------- + * APB1 Prescaler | 1 + *----------------------------------------------------------------------------- + * APB2 Prescaler | 1 + *----------------------------------------------------------------------------- + * PLL_M | 1 + *----------------------------------------------------------------------------- + * PLL_N | 8 + *----------------------------------------------------------------------------- + * PLL_P | 7 + *----------------------------------------------------------------------------- + * PLL_Q | 2 + *----------------------------------------------------------------------------- + * PLL_R | 2 + *----------------------------------------------------------------------------- + * PLLSAI1_P | NA + *----------------------------------------------------------------------------- + * PLLSAI1_Q | NA + *----------------------------------------------------------------------------- + * PLLSAI1_R | NA + *----------------------------------------------------------------------------- + * Require 48MHz for USB OTG FS, | Disabled + * SDIO and RNG clock | + *----------------------------------------------------------------------------- + *============================================================================= + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2019 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/** @addtogroup CMSIS + * @{ + */ + +/** @addtogroup stm32WBxx_system + * @{ + */ + +/** @addtogroup stm32WBxx_System_Private_Includes + * @{ + */ + +#include "stm32wbxx.h" + +#if !defined (HSE_VALUE) + #define HSE_VALUE (32000000UL) /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +#if !defined (MSI_VALUE) + #define MSI_VALUE (4000000UL) /*!< Value of the Internal oscillator in Hz*/ +#endif /* MSI_VALUE */ + +#if !defined (HSI_VALUE) + #define HSI_VALUE (16000000UL) /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI_VALUE */ + +#if !defined (LSI_VALUE) + #define LSI_VALUE (32000UL) /*!< Value of LSI in Hz*/ +#endif /* LSI_VALUE */ + +#if !defined (LSE_VALUE) + #define LSE_VALUE (32768UL) /*!< Value of LSE in Hz*/ +#endif /* LSE_VALUE */ + +/** + * @} + */ + +/** @addtogroup STM32WBxx_System_Private_TypesDefinitions + * @{ + */ + +/** + * @} + */ + +/** @addtogroup STM32WBxx_System_Private_Defines + * @{ + */ + +/*!< Uncomment the following line if you need to relocate your vector Table in + Internal SRAM. */ +/* #define VECT_TAB_SRAM */ +#define VECT_TAB_OFFSET OS_OFFSET /*!< Vector Table base offset field. + This value must be a multiple of 0x200. */ + +#define VECT_TAB_BASE_ADDRESS SRAM1_BASE /*!< Vector Table base offset field. + This value must be a multiple of 0x200. */ +/** + * @} + */ + +/** @addtogroup STM32WBxx_System_Private_Macros + * @{ + */ + +/** + * @} + */ + +/** @addtogroup STM32WBxx_System_Private_Variables + * @{ + */ + /* The SystemCoreClock variable is updated in three ways: + 1) by calling CMSIS function SystemCoreClockUpdate() + 2) by calling HAL API function HAL_RCC_GetHCLKFreq() + 3) each time HAL_RCC_ClockConfig() is called to configure the system clock frequency + Note: If you use this function to configure the system clock; then there + is no need to call the 2 first functions listed above, since SystemCoreClock + variable is updated automatically. + */ + uint32_t SystemCoreClock = 4000000UL ; /*CPU1: M4 on MSI clock after startup (4MHz)*/ + + const uint32_t AHBPrescTable[16UL] = {1UL, 3UL, 5UL, 1UL, 1UL, 6UL, 10UL, 32UL, 2UL, 4UL, 8UL, 16UL, 64UL, 128UL, 256UL, 512UL}; + + const uint32_t APBPrescTable[8UL] = {0UL, 0UL, 0UL, 0UL, 1UL, 2UL, 3UL, 4UL}; + + const uint32_t MSIRangeTable[16UL] = {100000UL, 200000UL, 400000UL, 800000UL, 1000000UL, 2000000UL, \ + 4000000UL, 8000000UL, 16000000UL, 24000000UL, 32000000UL, 48000000UL, 0UL, 0UL, 0UL, 0UL}; /* 0UL values are incorrect cases */ + +#if defined(STM32WB55xx) || defined(STM32WB5Mxx) || defined(STM32WB35xx) + const uint32_t SmpsPrescalerTable[4UL][6UL]={{1UL,3UL,2UL,2UL,1UL,2UL}, \ + {2UL,6UL,4UL,3UL,2UL,4UL}, \ + {4UL,12UL,8UL,6UL,4UL,8UL}, \ + {4UL,12UL,8UL,6UL,4UL,8UL}}; +#endif + +/** + * @} + */ + +/** @addtogroup STM32WBxx_System_Private_FunctionPrototypes + * @{ + */ + +/** + * @} + */ + +/** @addtogroup STM32WBxx_System_Private_Functions + * @{ + */ + +/** + * @brief Setup the microcontroller system. + * @param None + * @retval None + */ +void SystemInit(void) +{ + /* Configure the Vector Table location add offset address ------------------*/ +#if defined(VECT_TAB_SRAM) && defined(VECT_TAB_BASE_ADDRESS) + /* program in SRAMx */ + SCB->VTOR = VECT_TAB_BASE_ADDRESS | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAMx for CPU1 */ +#else /* program in FLASH */ + SCB->VTOR = VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */ +#endif + + /* FPU settings ------------------------------------------------------------*/ + #if (__FPU_PRESENT == 1) && (__FPU_USED == 1) + SCB->CPACR |= ((3UL << (10UL*2UL))|(3UL << (11UL*2UL))); /* set CP10 and CP11 Full Access */ + #endif + + /* Reset the RCC clock configuration to the default reset state ------------*/ + /* Set MSION bit */ + RCC->CR |= RCC_CR_MSION; + + /* Reset CFGR register */ + RCC->CFGR = 0x00070000U; + + /* Reset PLLSAI1ON, PLLON, HSECSSON, HSEON, HSION, and MSIPLLON bits */ + RCC->CR &= (uint32_t)0xFAF6FEFBU; + + /*!< Reset LSI1 and LSI2 bits */ + RCC->CSR &= (uint32_t)0xFFFFFFFAU; + + /*!< Reset HSI48ON bit */ + RCC->CRRCR &= (uint32_t)0xFFFFFFFEU; + + /* Reset PLLCFGR register */ + RCC->PLLCFGR = 0x22041000U; + +#if defined(STM32WB55xx) || defined(STM32WB5Mxx) + /* Reset PLLSAI1CFGR register */ + RCC->PLLSAI1CFGR = 0x22041000U; +#endif + + /* Reset HSEBYP bit */ + RCC->CR &= 0xFFFBFFFFU; + + /* Disable all interrupts */ + RCC->CIER = 0x00000000; +} + +/** + * @brief Update SystemCoreClock variable according to Clock Register Values. + * The SystemCoreClock variable contains the core clock (HCLK), it can + * be used by the user application to setup the SysTick timer or configure + * other parameters. + * + * @note Each time the core clock (HCLK) changes, this function must be called + * to update SystemCoreClock variable value. Otherwise, any configuration + * based on this variable will be incorrect. + * + * @note - The system frequency computed by this function is not the real + * frequency in the chip. It is calculated based on the predefined + * constant and the selected clock source: + * + * - If SYSCLK source is MSI, SystemCoreClock will contain the MSI_VALUE(*) + * + * - If SYSCLK source is HSI, SystemCoreClock will contain the HSI_VALUE(**) + * + * - If SYSCLK source is HSE, SystemCoreClock will contain the HSE_VALUE(***) + * + * - If SYSCLK source is PLL, SystemCoreClock will contain the HSE_VALUE(***) + * or HSI_VALUE(*) or MSI_VALUE(*) multiplied/divided by the PLL factors. + * + * (*) MSI_VALUE is a constant defined in stm32wbxx_hal.h file (default value + * 4 MHz) but the real value may vary depending on the variations + * in voltage and temperature. + * + * (**) HSI_VALUE is a constant defined in stm32wbxx_hal_conf.h file (default value + * 16 MHz) but the real value may vary depending on the variations + * in voltage and temperature. + * + * (***) HSE_VALUE is a constant defined in stm32wbxx_hal_conf.h file (default value + * 32 MHz), user has to ensure that HSE_VALUE is same as the real + * frequency of the crystal used. Otherwise, this function may + * have wrong result. + * + * - The result of this function could be not correct when using fractional + * value for HSE crystal. + * + * @param None + * @retval None + */ +void SystemCoreClockUpdate(void) +{ + uint32_t tmp, msirange, pllvco, pllr, pllsource , pllm; + + /* Get MSI Range frequency--------------------------------------------------*/ + + /*MSI frequency range in Hz*/ + msirange = MSIRangeTable[(RCC->CR & RCC_CR_MSIRANGE) >> RCC_CR_MSIRANGE_Pos]; + + /* Get SYSCLK source -------------------------------------------------------*/ + switch (RCC->CFGR & RCC_CFGR_SWS) + { + case 0x00: /* MSI used as system clock source */ + SystemCoreClock = msirange; + break; + + case 0x04: /* HSI used as system clock source */ + /* HSI used as system clock source */ + SystemCoreClock = HSI_VALUE; + break; + + case 0x08: /* HSE used as system clock source */ + SystemCoreClock = HSE_VALUE; + break; + + case 0x0C: /* PLL used as system clock source */ + /* PLL_VCO = (HSE_VALUE or HSI_VALUE or MSI_VALUE/ PLLM) * PLLN + SYSCLK = PLL_VCO / PLLR + */ + pllsource = (RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC); + pllm = ((RCC->PLLCFGR & RCC_PLLCFGR_PLLM) >> RCC_PLLCFGR_PLLM_Pos) + 1UL ; + + if(pllsource == 0x02UL) /* HSI used as PLL clock source */ + { + pllvco = (HSI_VALUE / pllm); + } + else if(pllsource == 0x03UL) /* HSE used as PLL clock source */ + { + pllvco = (HSE_VALUE / pllm); + } + else /* MSI used as PLL clock source */ + { + pllvco = (msirange / pllm); + } + + pllvco = pllvco * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> RCC_PLLCFGR_PLLN_Pos); + pllr = (((RCC->PLLCFGR & RCC_PLLCFGR_PLLR) >> RCC_PLLCFGR_PLLR_Pos) + 1UL); + + SystemCoreClock = pllvco/pllr; + break; + + default: + SystemCoreClock = msirange; + break; + } + + /* Compute HCLK clock frequency --------------------------------------------*/ + /* Get HCLK1 prescaler */ + tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> RCC_CFGR_HPRE_Pos)]; + /* HCLK clock frequency */ + SystemCoreClock = SystemCoreClock / tmp; + +} + + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/Src/tim.c b/firmware/targets/f7/Src/tim.c new file mode 100644 index 00000000..1d558dd5 --- /dev/null +++ b/firmware/targets/f7/Src/tim.c @@ -0,0 +1,361 @@ +/** + ****************************************************************************** + * @file tim.c + * @brief This file provides code for the configuration + * of the TIM instances. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "tim.h" + +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ + +TIM_HandleTypeDef htim1; +TIM_HandleTypeDef htim2; +TIM_HandleTypeDef htim16; + +/* TIM1 init function */ +void MX_TIM1_Init(void) +{ + TIM_ClockConfigTypeDef sClockSourceConfig = {0}; + TIM_MasterConfigTypeDef sMasterConfig = {0}; + TIM_OC_InitTypeDef sConfigOC = {0}; + TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0}; + + htim1.Instance = TIM1; + htim1.Init.Prescaler = 0; + htim1.Init.CounterMode = TIM_COUNTERMODE_UP; + htim1.Init.Period = 65535; + htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; + htim1.Init.RepetitionCounter = 0; + htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; + if (HAL_TIM_Base_Init(&htim1) != HAL_OK) + { + Error_Handler(); + } + sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; + if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK) + { + Error_Handler(); + } + if (HAL_TIM_OC_Init(&htim1) != HAL_OK) + { + Error_Handler(); + } + if (HAL_TIM_PWM_Init(&htim1) != HAL_OK) + { + Error_Handler(); + } + sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; + sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET; + sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; + if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK) + { + Error_Handler(); + } + sConfigOC.OCMode = TIM_OCMODE_TIMING; + sConfigOC.Pulse = 0; + sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; + sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH; + sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; + sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET; + sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET; + if (HAL_TIM_OC_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1) != HAL_OK) + { + Error_Handler(); + } + sConfigOC.OCMode = TIM_OCMODE_PWM1; + if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_3) != HAL_OK) + { + Error_Handler(); + } + sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE; + sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE; + sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF; + sBreakDeadTimeConfig.DeadTime = 0; + sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE; + sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH; + sBreakDeadTimeConfig.BreakFilter = 0; + sBreakDeadTimeConfig.BreakAFMode = TIM_BREAK_AFMODE_INPUT; + sBreakDeadTimeConfig.Break2State = TIM_BREAK2_DISABLE; + sBreakDeadTimeConfig.Break2Polarity = TIM_BREAK2POLARITY_HIGH; + sBreakDeadTimeConfig.Break2Filter = 0; + sBreakDeadTimeConfig.Break2AFMode = TIM_BREAK_AFMODE_INPUT; + sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE; + if (HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig) != HAL_OK) + { + Error_Handler(); + } + HAL_TIM_MspPostInit(&htim1); + +} +/* TIM2 init function */ +void MX_TIM2_Init(void) +{ + TIM_ClockConfigTypeDef sClockSourceConfig = {0}; + TIM_MasterConfigTypeDef sMasterConfig = {0}; + TIM_IC_InitTypeDef sConfigIC = {0}; + + htim2.Instance = TIM2; + htim2.Init.Prescaler = 64-1; + htim2.Init.CounterMode = TIM_COUNTERMODE_UP; + htim2.Init.Period = 4294967295; + htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; + htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; + if (HAL_TIM_Base_Init(&htim2) != HAL_OK) + { + Error_Handler(); + } + sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; + if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK) + { + Error_Handler(); + } + if (HAL_TIM_IC_Init(&htim2) != HAL_OK) + { + Error_Handler(); + } + sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; + sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; + if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK) + { + Error_Handler(); + } + sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_FALLING; + sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI; + sConfigIC.ICPrescaler = TIM_ICPSC_DIV1; + sConfigIC.ICFilter = 0; + if (HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_1) != HAL_OK) + { + Error_Handler(); + } + sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING; + sConfigIC.ICSelection = TIM_ICSELECTION_INDIRECTTI; + if (HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_2) != HAL_OK) + { + Error_Handler(); + } + +} +/* TIM16 init function */ +void MX_TIM16_Init(void) +{ + TIM_OC_InitTypeDef sConfigOC = {0}; + TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0}; + + htim16.Instance = TIM16; + htim16.Init.Prescaler = 500 - 1; + htim16.Init.CounterMode = TIM_COUNTERMODE_UP; + htim16.Init.Period = 291; + htim16.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; + htim16.Init.RepetitionCounter = 0; + htim16.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; + if (HAL_TIM_Base_Init(&htim16) != HAL_OK) + { + Error_Handler(); + } + if (HAL_TIM_PWM_Init(&htim16) != HAL_OK) + { + Error_Handler(); + } + sConfigOC.OCMode = TIM_OCMODE_PWM1; + sConfigOC.Pulse = 145; + sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; + sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH; + sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; + sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET; + sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET; + if (HAL_TIM_PWM_ConfigChannel(&htim16, &sConfigOC, TIM_CHANNEL_1) != HAL_OK) + { + Error_Handler(); + } + sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE; + sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE; + sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF; + sBreakDeadTimeConfig.DeadTime = 0; + sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE; + sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH; + sBreakDeadTimeConfig.BreakFilter = 0; + sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE; + if (HAL_TIMEx_ConfigBreakDeadTime(&htim16, &sBreakDeadTimeConfig) != HAL_OK) + { + Error_Handler(); + } + HAL_TIM_MspPostInit(&htim16); + +} + +void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle) +{ + + GPIO_InitTypeDef GPIO_InitStruct = {0}; + if(tim_baseHandle->Instance==TIM1) + { + /* USER CODE BEGIN TIM1_MspInit 0 */ + + /* USER CODE END TIM1_MspInit 0 */ + /* TIM1 clock enable */ + __HAL_RCC_TIM1_CLK_ENABLE(); + + /* TIM1 interrupt Init */ + HAL_NVIC_SetPriority(TIM1_TRG_COM_TIM17_IRQn, 0, 0); + HAL_NVIC_EnableIRQ(TIM1_TRG_COM_TIM17_IRQn); + /* USER CODE BEGIN TIM1_MspInit 1 */ + + /* USER CODE END TIM1_MspInit 1 */ + } + else if(tim_baseHandle->Instance==TIM2) + { + /* USER CODE BEGIN TIM2_MspInit 0 */ + + /* USER CODE END TIM2_MspInit 0 */ + /* TIM2 clock enable */ + __HAL_RCC_TIM2_CLK_ENABLE(); + + __HAL_RCC_GPIOA_CLK_ENABLE(); + /**TIM2 GPIO Configuration + PA0 ------> TIM2_CH1 + */ + GPIO_InitStruct.Pin = IR_RX_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStruct.Alternate = GPIO_AF1_TIM2; + HAL_GPIO_Init(IR_RX_GPIO_Port, &GPIO_InitStruct); + + /* TIM2 interrupt Init */ + HAL_NVIC_SetPriority(TIM2_IRQn, 5, 0); + HAL_NVIC_EnableIRQ(TIM2_IRQn); + /* USER CODE BEGIN TIM2_MspInit 1 */ + + /* USER CODE END TIM2_MspInit 1 */ + } + else if(tim_baseHandle->Instance==TIM16) + { + /* USER CODE BEGIN TIM16_MspInit 0 */ + + /* USER CODE END TIM16_MspInit 0 */ + /* TIM16 clock enable */ + __HAL_RCC_TIM16_CLK_ENABLE(); + /* USER CODE BEGIN TIM16_MspInit 1 */ + + /* USER CODE END TIM16_MspInit 1 */ + } +} +void HAL_TIM_MspPostInit(TIM_HandleTypeDef* timHandle) +{ + + GPIO_InitTypeDef GPIO_InitStruct = {0}; + if(timHandle->Instance==TIM1) + { + /* USER CODE BEGIN TIM1_MspPostInit 0 */ + + /* USER CODE END TIM1_MspPostInit 0 */ + __HAL_RCC_GPIOB_CLK_ENABLE(); + /**TIM1 GPIO Configuration + PB9 ------> TIM1_CH3N + PB13 ------> TIM1_CH1N + */ + GPIO_InitStruct.Pin = IR_TX_Pin|RFID_OUT_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStruct.Alternate = GPIO_AF1_TIM1; + HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); + + /* USER CODE BEGIN TIM1_MspPostInit 1 */ + + /* USER CODE END TIM1_MspPostInit 1 */ + } + else if(timHandle->Instance==TIM16) + { + /* USER CODE BEGIN TIM16_MspPostInit 0 */ + + /* USER CODE END TIM16_MspPostInit 0 */ + + __HAL_RCC_GPIOB_CLK_ENABLE(); + /**TIM16 GPIO Configuration + PB8 ------> TIM16_CH1 + */ + GPIO_InitStruct.Pin = SPEAKER_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStruct.Alternate = GPIO_AF14_TIM16; + HAL_GPIO_Init(SPEAKER_GPIO_Port, &GPIO_InitStruct); + + /* USER CODE BEGIN TIM16_MspPostInit 1 */ + + /* USER CODE END TIM16_MspPostInit 1 */ + } + +} + +void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* tim_baseHandle) +{ + + if(tim_baseHandle->Instance==TIM1) + { + /* USER CODE BEGIN TIM1_MspDeInit 0 */ + + /* USER CODE END TIM1_MspDeInit 0 */ + /* Peripheral clock disable */ + __HAL_RCC_TIM1_CLK_DISABLE(); + + /* TIM1 interrupt Deinit */ + HAL_NVIC_DisableIRQ(TIM1_TRG_COM_TIM17_IRQn); + /* USER CODE BEGIN TIM1_MspDeInit 1 */ + + /* USER CODE END TIM1_MspDeInit 1 */ + } + else if(tim_baseHandle->Instance==TIM2) + { + /* USER CODE BEGIN TIM2_MspDeInit 0 */ + + /* USER CODE END TIM2_MspDeInit 0 */ + /* Peripheral clock disable */ + __HAL_RCC_TIM2_CLK_DISABLE(); + + /**TIM2 GPIO Configuration + PA0 ------> TIM2_CH1 + */ + HAL_GPIO_DeInit(IR_RX_GPIO_Port, IR_RX_Pin); + + /* TIM2 interrupt Deinit */ + HAL_NVIC_DisableIRQ(TIM2_IRQn); + /* USER CODE BEGIN TIM2_MspDeInit 1 */ + + /* USER CODE END TIM2_MspDeInit 1 */ + } + else if(tim_baseHandle->Instance==TIM16) + { + /* USER CODE BEGIN TIM16_MspDeInit 0 */ + + /* USER CODE END TIM16_MspDeInit 0 */ + /* Peripheral clock disable */ + __HAL_RCC_TIM16_CLK_DISABLE(); + /* USER CODE BEGIN TIM16_MspDeInit 1 */ + + /* USER CODE END TIM16_MspDeInit 1 */ + } +} + +/* USER CODE BEGIN 1 */ + +/* USER CODE END 1 */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/ble-glue/app_ble.c b/firmware/targets/f7/ble-glue/app_ble.c new file mode 100644 index 00000000..bb80fcea --- /dev/null +++ b/firmware/targets/f7/ble-glue/app_ble.c @@ -0,0 +1,776 @@ +#include "main.h" + +#include "app_entry.h" +#include "app_common.h" +#include "dbg_trace.h" +#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 + +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 */ + +}; + +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, + .cb_mem = CFG_HCI_USER_EVT_PROCESS_CB_MEM, + .cb_size = CFG_HCI_USER_EVT_PROCESS_CB_SIZE, + .stack_mem = CFG_HCI_USER_EVT_PROCESS_STACK_MEM, + .priority = CFG_HCI_USER_EVT_PROCESS_PRIORITY, + .stack_size = CFG_HCI_USER_EVT_PROCESS_STACK_SIZE +}; + +/* Private function prototypes -----------------------------------------------*/ +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 = { + {{0,0,0}}, /**< Header unused */ + {0, /** pBleBufferAddress not used */ + 0, /** BleBufferSize not used */ + CFG_BLE_NUM_GATT_ATTRIBUTES, + CFG_BLE_NUM_GATT_SERVICES, + CFG_BLE_ATT_VALUE_ARRAY_SIZE, + CFG_BLE_NUM_LINK, + CFG_BLE_DATA_LENGTH_EXTENSION, + CFG_BLE_PREPARE_WRITE_LIST_SIZE, + CFG_BLE_MBLOCK_COUNT, + CFG_BLE_MAX_ATT_MTU, + CFG_BLE_SLAVE_SCA, + CFG_BLE_MASTER_SCA, + CFG_BLE_LSE_SOURCE, + CFG_BLE_MAX_CONN_EVENT_LENGTH, + CFG_BLE_HSE_STARTUP_TIME, + CFG_BLE_VITERBI_MODE, + CFG_BLE_LL_ONLY, + 0} + }; + + // Initialize Ble Transport Layer + Ble_Tl_Init( ); + // Register the hci transport layer to handle BLE User Asynchronous Events + HciUserEvtProcessId = osThreadNew(HciUserEvtProcess, NULL, &HciUserEvtProcess_attr); + // Starts the BLE Stack on CPU2 + 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; + + MtxHciId = osMutexNew( NULL ); + SemHciId = osSemaphoreNew( 1, 0, NULL ); /*< Create the semaphore and make it busy at initialization */ + + Hci_Tl_Init_Conf.p_cmdbuffer = (uint8_t*)&BleCmdBuffer; + Hci_Tl_Init_Conf.StatusNotCallBack = BLE_StatusNot; + 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); + + for(;;) + { + osThreadFlagsWait( 1, osFlagsWaitAny, osWaitForever); + hci_user_evt_proc( ); + } +} + +/************************************************************* + * + * WRAP FUNCTIONS + * + *************************************************************/ +void hci_notify_asynch_evt(void* pdata) { + UNUSED(pdata); + osThreadFlagsSet( HciUserEvtProcessId, 1 ); +} + +void hci_cmd_resp_release(uint32_t flag) { + UNUSED(flag); + osSemaphoreRelease( SemHciId ); +} + +void hci_cmd_resp_wait(uint32_t timeout) { + UNUSED(timeout); + osSemaphoreAcquire( SemHciId, osWaitForever ); +} + +static void BLE_UserEvtRx( void * pPayload ) { + SVCCTL_UserEvtFlowStatus_t svctl_return_status; + tHCI_UserEvtRxParam *pParam; + + pParam = (tHCI_UserEvtRxParam *)pPayload; + + svctl_return_status = SVCCTL_UserEvtRx((void *)&(pParam->pckt->evtserial)); + if (svctl_return_status != SVCCTL_UserEvtFlowDisable) { + pParam->status = HCI_TL_UserEventFlow_Enable; + } else { + pParam->status = HCI_TL_UserEventFlow_Disable; + } +} + +static void BLE_StatusNot( HCI_TL_CmdStatus_t status ) { + switch (status) { + case HCI_TL_CmdBusy: + osMutexAcquire( MtxHciId, osWaitForever ); + break; + case HCI_TL_CmdAvailable: + osMutexRelease( MtxHciId ); + break; + default: + break; + } +} + +void SVCCTL_ResumeUserEventFlow( void ) { + hci_resume_flow(); +} diff --git a/firmware/targets/f7/ble-glue/app_ble.h b/firmware/targets/f7/ble-glue/app_ble.h new file mode 100644 index 00000000..2bbd5165 --- /dev/null +++ b/firmware/targets/f7/ble-glue/app_ble.h @@ -0,0 +1,27 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#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 +} +#endif diff --git a/firmware/targets/f7/ble-glue/app_common.h b/firmware/targets/f7/ble-glue/app_common.h new file mode 100644 index 00000000..d21860f6 --- /dev/null +++ b/firmware/targets/f7/ble-glue/app_common.h @@ -0,0 +1,43 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * File Name : app_common.h + * Description : App Common application configuration file for STM32WPAN Middleware. + * + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2020 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* USER CODE END Header */ +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef APP_COMMON_H +#define APP_COMMON_H + +#ifdef __cplusplus +extern "C"{ +#endif + +#include +#include +#include +#include +#include + +#include + +#include "app_conf.h" + +#define DIVC( x, y ) (((x)+(y)-1)/(y)) + +#define DIVR( x, y ) (((x)+((y)/2))/(y)) + +#endif \ No newline at end of file diff --git a/firmware/targets/f7/ble-glue/app_conf.h b/firmware/targets/f7/ble-glue/app_conf.h new file mode 100644 index 00000000..dc22b4ba --- /dev/null +++ b/firmware/targets/f7/ble-glue/app_conf.h @@ -0,0 +1,474 @@ +#pragma once + +#include "hw.h" +#include "hw_conf.h" +#include "hw_if.h" +#include "ble_bufsize.h" + +#define CFG_TX_POWER (0x19) /* +0dBm */ + +/** + * Define Advertising parameters + */ +#define CFG_ADV_BD_ADDRESS (0x7257acd87a6c) +#define CFG_FAST_CONN_ADV_INTERVAL_MIN (0x80) /**< 80ms */ +#define CFG_FAST_CONN_ADV_INTERVAL_MAX (0xa0) /**< 100ms */ +#define CFG_LP_CONN_ADV_INTERVAL_MIN (0x640) /**< 1s */ +#define CFG_LP_CONN_ADV_INTERVAL_MAX (0xfa0) /**< 2.5s */ + +/** + * Define IO Authentication + */ +#define CFG_BONDING_MODE (1) +#define CFG_FIXED_PIN (111111) +#define CFG_USED_FIXED_PIN (1) +#define CFG_ENCRYPTION_KEY_SIZE_MAX (16) +#define CFG_ENCRYPTION_KEY_SIZE_MIN (8) + +/** + * Define IO capabilities + */ +#define CFG_IO_CAPABILITY_DISPLAY_ONLY (0x00) +#define CFG_IO_CAPABILITY_DISPLAY_YES_NO (0x01) +#define CFG_IO_CAPABILITY_KEYBOARD_ONLY (0x02) +#define CFG_IO_CAPABILITY_NO_INPUT_NO_OUTPUT (0x03) +#define CFG_IO_CAPABILITY_KEYBOARD_DISPLAY (0x04) + +#define CFG_IO_CAPABILITY CFG_IO_CAPABILITY_DISPLAY_YES_NO + +/** + * Define MITM modes + */ +#define CFG_MITM_PROTECTION_NOT_REQUIRED (0x00) +#define CFG_MITM_PROTECTION_REQUIRED (0x01) + +#define CFG_MITM_PROTECTION CFG_MITM_PROTECTION_REQUIRED + +/** + * Define Secure Connections Support + */ +#define CFG_SECURE_NOT_SUPPORTED (0x00) +#define CFG_SECURE_OPTIONAL (0x01) +#define CFG_SECURE_MANDATORY (0x02) + +#define CFG_SC_SUPPORT CFG_SECURE_OPTIONAL + +/** + * Define Keypress Notification Support + */ +#define CFG_KEYPRESS_NOT_SUPPORTED (0x00) +#define CFG_KEYPRESS_SUPPORTED (0x01) + +#define CFG_KEYPRESS_NOTIFICATION_SUPPORT CFG_KEYPRESS_NOT_SUPPORTED + +/** + * Numeric Comparison Answers + */ +#define YES (0x01) +#define NO (0x00) + +/** + * Device name configuration for Generic Access Service + */ +#define CFG_GAP_DEVICE_NAME "TEMPLATE" +#define CFG_GAP_DEVICE_NAME_LENGTH (8) + +/** + * Define PHY + */ +#define ALL_PHYS_PREFERENCE 0x00 +#define RX_2M_PREFERRED 0x02 +#define TX_2M_PREFERRED 0x02 +#define TX_1M 0x01 +#define TX_2M 0x02 +#define RX_1M 0x01 +#define RX_2M 0x02 + +/** +* Identity root key used to derive LTK and CSRK +*/ +#define CFG_BLE_IRK {0x12,0x34,0x56,0x78,0x9a,0xbc,0xde,0xf0,0x12,0x34,0x56,0x78,0x9a,0xbc,0xde,0xf0} + +/** +* Encryption root key used to derive LTK and CSRK +*/ +#define CFG_BLE_ERK {0xfe,0xdc,0xba,0x09,0x87,0x65,0x43,0x21,0xfe,0xdc,0xba,0x09,0x87,0x65,0x43,0x21} + +/* USER CODE BEGIN Generic_Parameters */ +/** + * SMPS supply + * SMPS not used when Set to 0 + * SMPS used when Set to 1 + */ +#define CFG_USE_SMPS 1 +/* USER CODE END Generic_Parameters */ + +/**< specific parameters */ +/*****************************************************/ + +/** +* AD Element - Group B Feature +*/ +/* LSB - Second Byte */ +#define CFG_FEATURE_OTA_REBOOT (0x20) + +/****************************************************************************** + * BLE Stack + ******************************************************************************/ +/** + * Maximum number of simultaneous connections that the device will support. + * Valid values are from 1 to 8 + */ +#define CFG_BLE_NUM_LINK 2 + +/** + * Maximum number of Services that can be stored in the GATT database. + * Note that the GAP and GATT services are automatically added so this parameter should be 2 plus the number of user services + */ +#define CFG_BLE_NUM_GATT_SERVICES 8 + +/** + * Maximum number of Attributes + * (i.e. the number of characteristic + the number of characteristic values + the number of descriptors, excluding the services) + * that can be stored in the GATT database. + * Note that certain characteristics and relative descriptors are added automatically during device initialization + * so this parameters should be 9 plus the number of user Attributes + */ +#define CFG_BLE_NUM_GATT_ATTRIBUTES 68 + +/** + * Maximum supported ATT_MTU size + */ +#define CFG_BLE_MAX_ATT_MTU (156) + +/** + * Size of the storage area for Attribute values + * This value depends on the number of attributes used by application. In particular the sum of the following quantities (in octets) should be made for each attribute: + * - attribute value length + * - 5, if UUID is 16 bit; 19, if UUID is 128 bit + * - 2, if server configuration descriptor is used + * - 2*DTM_NUM_LINK, if client configuration descriptor is used + * - 2, if extended properties is used + * The total amount of memory needed is the sum of the above quantities for each attribute. + */ +#define CFG_BLE_ATT_VALUE_ARRAY_SIZE (1344) + +/** + * Prepare Write List size in terms of number of packet + */ +#define CFG_BLE_PREPARE_WRITE_LIST_SIZE BLE_PREP_WRITE_X_ATT(CFG_BLE_MAX_ATT_MTU) + +/** + * Number of allocated memory blocks + */ +#define CFG_BLE_MBLOCK_COUNT (BLE_MBLOCKS_CALC(CFG_BLE_PREPARE_WRITE_LIST_SIZE, CFG_BLE_MAX_ATT_MTU, CFG_BLE_NUM_LINK)) + +/** + * Enable or disable the Extended Packet length feature. Valid values are 0 or 1. + */ +#define CFG_BLE_DATA_LENGTH_EXTENSION 1 + +/** + * Sleep clock accuracy in Slave mode (ppm value) + */ +#define CFG_BLE_SLAVE_SCA 500 + +/** + * Sleep clock accuracy in Master mode + * 0 : 251 ppm to 500 ppm + * 1 : 151 ppm to 250 ppm + * 2 : 101 ppm to 150 ppm + * 3 : 76 ppm to 100 ppm + * 4 : 51 ppm to 75 ppm + * 5 : 31 ppm to 50 ppm + * 6 : 21 ppm to 30 ppm + * 7 : 0 ppm to 20 ppm + */ +#define CFG_BLE_MASTER_SCA 0 + +/** + * Source for the low speed clock for RF wake-up + * 1 : external high speed crystal HSE/32/32 + * 0 : external low speed crystal ( no calibration ) + */ +#define CFG_BLE_LSE_SOURCE 0 + +/** + * Start up time of the high speed (16 or 32 MHz) crystal oscillator in units of 625/256 us (~2.44 us) + */ +#define CFG_BLE_HSE_STARTUP_TIME 0x148 + +/** + * Maximum duration of the connection event when the device is in Slave mode in units of 625/256 us (~2.44 us) + */ +#define CFG_BLE_MAX_CONN_EVENT_LENGTH ( 0xFFFFFFFF ) + +/** + * Viterbi Mode + * 1 : enabled + * 0 : disabled + */ +#define CFG_BLE_VITERBI_MODE 1 + +/** + * LL Only Mode + * 1 : LL Only + * 0 : LL + Host + */ +#define CFG_BLE_LL_ONLY 0 +/****************************************************************************** + * Transport Layer + ******************************************************************************/ +/** + * Queue length of BLE Event + * This parameter defines the number of asynchronous events that can be stored in the HCI layer before + * being reported to the application. When a command is sent to the BLE core coprocessor, the HCI layer + * is waiting for the event with the Num_HCI_Command_Packets set to 1. The receive queue shall be large + * enough to store all asynchronous events received in between. + * When CFG_TLBLE_MOST_EVENT_PAYLOAD_SIZE is set to 27, this allow to store three 255 bytes long asynchronous events + * between the HCI command and its event. + * This parameter depends on the value given to CFG_TLBLE_MOST_EVENT_PAYLOAD_SIZE. When the queue size is to small, + * the system may hang if the queue is full with asynchronous events and the HCI layer is still waiting + * for a CC/CS event, In that case, the notification TL_BLE_HCI_ToNot() is called to indicate + * to the application a HCI command did not receive its command event within 30s (Default HCI Timeout). + */ +#define CFG_TLBLE_EVT_QUEUE_LENGTH 5 +/** + * This parameter should be set to fit most events received by the HCI layer. It defines the buffer size of each element + * allocated in the queue of received events and can be used to optimize the amount of RAM allocated by the Memory Manager. + * It should not exceed 255 which is the maximum HCI packet payload size (a greater value is a lost of memory as it will + * never be used) + * With the current wireless firmware implementation, this parameter shall be kept to 255 + * + */ +#define CFG_TLBLE_MOST_EVENT_PAYLOAD_SIZE 255 /**< Set to 255 with the memory manager and the mailbox */ + +#define TL_BLE_EVENT_FRAME_SIZE ( TL_EVT_HDR_SIZE + CFG_TLBLE_MOST_EVENT_PAYLOAD_SIZE ) +/****************************************************************************** + * UART interfaces + ******************************************************************************/ + +/** + * Select UART interfaces + */ +#define CFG_DEBUG_TRACE_UART hw_uart1 +#define CFG_CONSOLE_MENU 0 + +/****************************************************************************** + * Low Power + ******************************************************************************/ +/** + * When set to 1, the low power mode is enable + * When set to 0, the device stays in RUN mode + */ +#define CFG_LPM_SUPPORTED 1 + +/****************************************************************************** + * Timer Server + ******************************************************************************/ +/** + * CFG_RTC_WUCKSEL_DIVIDER: This sets the RTCCLK divider to the wakeup timer. + * The lower is the value, the better is the power consumption and the accuracy of the timerserver + * The higher is the value, the finest is the granularity + * + * CFG_RTC_ASYNCH_PRESCALER: This sets the asynchronous prescaler of the RTC. It should as high as possible ( to ouput + * clock as low as possible) but the output clock should be equal or higher frequency compare to the clock feeding + * the wakeup timer. A lower clock speed would impact the accuracy of the timer server. + * + * CFG_RTC_SYNCH_PRESCALER: This sets the synchronous prescaler of the RTC. + * When the 1Hz calendar clock is required, it shall be sets according to other settings + * When the 1Hz calendar clock is not needed, CFG_RTC_SYNCH_PRESCALER should be set to 0x7FFF (MAX VALUE) + * + * CFG_RTCCLK_DIVIDER_CONF: + * Shall be set to either 0,2,4,8,16 + * When set to either 2,4,8,16, the 1Hhz calendar is supported + * When set to 0, the user sets its own configuration + * + * The following settings are computed with LSI as input to the RTC + */ +#define CFG_RTCCLK_DIVIDER_CONF 0 + +#if (CFG_RTCCLK_DIVIDER_CONF == 0) +/** + * Custom configuration + * It does not support 1Hz calendar + * It divides the RTC CLK by 16 + */ +#define CFG_RTCCLK_DIV (16) +#define CFG_RTC_WUCKSEL_DIVIDER (0) +#define CFG_RTC_ASYNCH_PRESCALER (CFG_RTCCLK_DIV - 1) +#define CFG_RTC_SYNCH_PRESCALER (0x7FFF) + +#else + +#if (CFG_RTCCLK_DIVIDER_CONF == 2) +/** + * It divides the RTC CLK by 2 + */ +#define CFG_RTC_WUCKSEL_DIVIDER (3) +#endif + +#if (CFG_RTCCLK_DIVIDER_CONF == 4) +/** + * It divides the RTC CLK by 4 + */ +#define CFG_RTC_WUCKSEL_DIVIDER (2) +#endif + +#if (CFG_RTCCLK_DIVIDER_CONF == 8) +/** + * It divides the RTC CLK by 8 + */ +#define CFG_RTC_WUCKSEL_DIVIDER (1) +#endif + +#if (CFG_RTCCLK_DIVIDER_CONF == 16) +/** + * It divides the RTC CLK by 16 + */ +#define CFG_RTC_WUCKSEL_DIVIDER (0) +#endif + +#define CFG_RTCCLK_DIV CFG_RTCCLK_DIVIDER_CONF +#define CFG_RTC_ASYNCH_PRESCALER (CFG_RTCCLK_DIV - 1) +#define CFG_RTC_SYNCH_PRESCALER (DIVR( LSE_VALUE, (CFG_RTC_ASYNCH_PRESCALER+1) ) - 1 ) + +#endif + +/** tick timer value in us */ +#define CFG_TS_TICK_VAL DIVR( (CFG_RTCCLK_DIV * 1000000), LSE_VALUE ) + +typedef enum +{ + CFG_TIM_PROC_ID_ISR, + /* USER CODE BEGIN CFG_TimProcID_t */ + + /* USER CODE END CFG_TimProcID_t */ +} CFG_TimProcID_t; + +/****************************************************************************** + * Debug + ******************************************************************************/ +/** + * When set, this resets some hw resources to set the device in the same state than the power up + * The FW resets only register that may prevent the FW to run properly + * + * This shall be set to 0 in a final product + * + */ +#define CFG_HW_RESET_BY_FW 0 + +/** + * keep debugger enabled while in any low power mode when set to 1 + * should be set to 0 in production + */ +#define CFG_DEBUGGER_SUPPORTED 0 + +/** + * When set to 1, the traces are enabled in the BLE services + */ +#define CFG_DEBUG_BLE_TRACE 1 + +/** + * Enable or Disable traces in application + */ +#define CFG_DEBUG_APP_TRACE 1 + +#if (CFG_DEBUG_APP_TRACE != 0) +#define APP_DBG_MSG PRINT_MESG_DBG +#else +#define APP_DBG_MSG PRINT_NO_MESG +#endif + +#if ( (CFG_DEBUG_BLE_TRACE != 0) || (CFG_DEBUG_APP_TRACE != 0) ) +#define CFG_DEBUG_TRACE 1 +#endif + +#if (CFG_DEBUG_TRACE != 0) +#undef CFG_LPM_SUPPORTED +#undef CFG_DEBUGGER_SUPPORTED +#define CFG_LPM_SUPPORTED 0 +#define CFG_DEBUGGER_SUPPORTED 1 +#endif + +/** + * When CFG_DEBUG_TRACE_FULL is set to 1, the trace are output with the API name, the file name and the line number + * When CFG_DEBUG_TRACE_LIGHT is set to 1, only the debug message is output + * + * When both are set to 0, no trace are output + * When both are set to 1, CFG_DEBUG_TRACE_FULL is selected + */ +#define CFG_DEBUG_TRACE_LIGHT 0 +#define CFG_DEBUG_TRACE_FULL 0 + +#if (( CFG_DEBUG_TRACE != 0 ) && ( CFG_DEBUG_TRACE_LIGHT == 0 ) && (CFG_DEBUG_TRACE_FULL == 0)) +#undef CFG_DEBUG_TRACE_FULL +#undef CFG_DEBUG_TRACE_LIGHT +#define CFG_DEBUG_TRACE_FULL 0 +#define CFG_DEBUG_TRACE_LIGHT 1 +#endif + +#if ( CFG_DEBUG_TRACE == 0 ) +#undef CFG_DEBUG_TRACE_FULL +#undef CFG_DEBUG_TRACE_LIGHT +#define CFG_DEBUG_TRACE_FULL 0 +#define CFG_DEBUG_TRACE_LIGHT 0 +#endif + +/** + * When not set, the traces is looping on sending the trace over UART + */ +#define DBG_TRACE_USE_CIRCULAR_QUEUE 0 + +/** + * max buffer Size to queue data traces and max data trace allowed. + * Only Used if DBG_TRACE_USE_CIRCULAR_QUEUE is defined + */ +#define DBG_TRACE_MSG_QUEUE_SIZE 4096 +#define MAX_DBG_TRACE_MSG_SIZE 1024 + +#define CFG_LED_SUPPORTED 0 +#define CFG_BUTTON_SUPPORTED 0 + +/****************************************************************************** + * FreeRTOS + ******************************************************************************/ +#define CFG_SHCI_USER_EVT_PROCESS_NAME "ble_shci_evt" +#define CFG_SHCI_USER_EVT_PROCESS_ATTR_BITS (0) +#define CFG_SHCI_USER_EVT_PROCESS_CB_MEM (0) +#define CFG_SHCI_USER_EVT_PROCESS_CB_SIZE (0) +#define CFG_SHCI_USER_EVT_PROCESS_STACK_MEM (0) +#define CFG_SHCI_USER_EVT_PROCESS_PRIORITY osPriorityNone +#define CFG_SHCI_USER_EVT_PROCESS_STACK_SIZE (128 * 7) + +#define CFG_HCI_USER_EVT_PROCESS_NAME "ble_hci_evt" +#define CFG_HCI_USER_EVT_PROCESS_ATTR_BITS (0) +#define CFG_HCI_USER_EVT_PROCESS_CB_MEM (0) +#define CFG_HCI_USER_EVT_PROCESS_CB_SIZE (0) +#define CFG_HCI_USER_EVT_PROCESS_STACK_MEM (0) +#define CFG_HCI_USER_EVT_PROCESS_PRIORITY osPriorityNone +#define CFG_HCI_USER_EVT_PROCESS_STACK_SIZE (128 * 8) + +#define CFG_ADV_UPDATE_PROCESS_NAME "ble_adv_upd" +#define CFG_ADV_UPDATE_PROCESS_ATTR_BITS (0) +#define CFG_ADV_UPDATE_PROCESS_CB_MEM (0) +#define CFG_ADV_UPDATE_PROCESS_CB_SIZE (0) +#define CFG_ADV_UPDATE_PROCESS_STACK_MEM (0) +#define CFG_ADV_UPDATE_PROCESS_PRIORITY osPriorityNone +#define CFG_ADV_UPDATE_PROCESS_STACK_SIZE (128 * 6) + +#define CFG_HRS_PROCESS_NAME "hrs" +#define CFG_HRS_PROCESS_ATTR_BITS (0) +#define CFG_HRS_PROCESS_CB_MEM (0) +#define CFG_HRS_PROCESS_CB_SIZE (0) +#define CFG_HRS_PROCESS_STACK_MEM (0) +#define CFG_HRS_PROCESS_PRIORITY osPriorityNone +#define CFG_HRS_PROCESS_STACK_SIZE (128 * 8) + +typedef enum { + CFG_LPM_APP, + CFG_LPM_APP_BLE, +} CFG_LPM_Id_t; + +#define CFG_OTP_BASE_ADDRESS OTP_AREA_BASE +#define CFG_OTP_END_ADRESS OTP_AREA_END_ADDR diff --git a/firmware/targets/f7/ble-glue/app_entry.c b/firmware/targets/f7/ble-glue/app_entry.c new file mode 100644 index 00000000..f2367263 --- /dev/null +++ b/firmware/targets/f7/ble-glue/app_entry.c @@ -0,0 +1,192 @@ +#include "app_common.h" +#include "main.h" +#include "app_entry.h" +#include "app_ble.h" +#include "ble.h" +#include "tl.h" +#include "cmsis_os.h" +#include "shci_tl.h" +#include + +extern RTC_HandleTypeDef hrtc; + +#define POOL_SIZE (CFG_TLBLE_EVT_QUEUE_LENGTH*4U*DIVC(( sizeof(TL_PacketHeader_t) + TL_BLE_EVENT_FRAME_SIZE ), 4U)) + +PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static uint8_t EvtPool[POOL_SIZE]; +PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static TL_CmdPacket_t SystemCmdBuffer; +PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static uint8_t SystemSpareEvtBuffer[sizeof(TL_PacketHeader_t) + TL_EVT_HDR_SIZE + 255U]; +PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static uint8_t BleSpareEvtBuffer[sizeof(TL_PacketHeader_t) + TL_EVT_HDR_SIZE + 255]; + +osMutexId_t MtxShciId; +osSemaphoreId_t SemShciId; +osThreadId_t ShciUserEvtProcessId; + +volatile static BleGlueStatus ble_glue_status = BleGlueStatusUninitialized; + +const osThreadAttr_t ShciUserEvtProcess_attr = { + .name = CFG_SHCI_USER_EVT_PROCESS_NAME, + .attr_bits = CFG_SHCI_USER_EVT_PROCESS_ATTR_BITS, + .cb_mem = CFG_SHCI_USER_EVT_PROCESS_CB_MEM, + .cb_size = CFG_SHCI_USER_EVT_PROCESS_CB_SIZE, + .stack_mem = CFG_SHCI_USER_EVT_PROCESS_STACK_MEM, + .priority = CFG_SHCI_USER_EVT_PROCESS_PRIORITY, + .stack_size = CFG_SHCI_USER_EVT_PROCESS_STACK_SIZE +}; + +static void ShciUserEvtProcess(void *argument); +static void SystemPower_Config( void ); +static void appe_Tl_Init( void ); +static void APPE_SysStatusNot( SHCI_TL_CmdStatus_t status ); +static void APPE_SysUserEvtRx( void * pPayload ); + +BleGlueStatus APPE_Status() { + return ble_glue_status; +} + +void APPE_Init() { + ble_glue_status = BleGlueStatusStartup; + SystemPower_Config(); /**< Configure the system Power Mode */ + + HW_TS_Init(hw_ts_InitMode_Full, &hrtc); /**< Initialize the TimerServer */ + + // APPD_Init(); + furi_hal_power_insomnia_enter(); + + appe_Tl_Init(); /* Initialize all transport layers */ + + /** + * From now, the application is waiting for the ready event ( VS_HCI_C2_Ready ) + * received on the system channel before starting the Stack + * This system event is received with APPE_SysUserEvtRx() + */ +} + +/************************************************************* + * + * LOCAL FUNCTIONS + * + *************************************************************/ + +/** + * @brief Configure the system for power optimization + * + * @note This API configures the system to be ready for low power mode + * + * @param None + * @retval None + */ +static void SystemPower_Config(void) { + // Select HSI as system clock source after Wake Up from Stop mode + LL_RCC_SetClkAfterWakeFromStop(LL_RCC_STOP_WAKEUPCLOCK_HSI); + + /* Initialize the CPU2 reset value before starting CPU2 with C2BOOT */ + LL_C2_PWR_SetPowerMode(LL_PWR_MODE_SHUTDOWN); +} + +static void appe_Tl_Init( void ) { + TL_MM_Config_t tl_mm_config; + SHCI_TL_HciInitConf_t SHci_Tl_Init_Conf; + /**< Reference table initialization */ + TL_Init(); + + MtxShciId = osMutexNew( NULL ); + SemShciId = osSemaphoreNew( 1, 0, NULL ); /*< Create the semaphore and make it busy at initialization */ + + /** FreeRTOS system task creation */ + ShciUserEvtProcessId = osThreadNew(ShciUserEvtProcess, NULL, &ShciUserEvtProcess_attr); + + /**< System channel initialization */ + SHci_Tl_Init_Conf.p_cmdbuffer = (uint8_t*)&SystemCmdBuffer; + SHci_Tl_Init_Conf.StatusNotCallBack = APPE_SysStatusNot; + shci_init(APPE_SysUserEvtRx, (void*) &SHci_Tl_Init_Conf); + + /**< Memory Manager channel initialization */ + tl_mm_config.p_BleSpareEvtBuffer = BleSpareEvtBuffer; + tl_mm_config.p_SystemSpareEvtBuffer = SystemSpareEvtBuffer; + tl_mm_config.p_AsynchEvtPool = EvtPool; + tl_mm_config.AsynchEvtPoolSize = POOL_SIZE; + TL_MM_Init( &tl_mm_config ); + + TL_Enable(); +} + +static void APPE_SysStatusNot( SHCI_TL_CmdStatus_t status ) { + switch (status) { + case SHCI_TL_CmdBusy: + osMutexAcquire( MtxShciId, osWaitForever ); + break; + case SHCI_TL_CmdAvailable: + osMutexRelease( MtxShciId ); + break; + default: + break; + } +} + +/** + * The type of the payload for a system user event is tSHCI_UserEvtRxParam + * When the system event is both : + * - a ready event (subevtcode = SHCI_SUB_EVT_CODE_READY) + * - reported by the FUS (sysevt_ready_rsp == FUS_FW_RUNNING) + * The buffer shall not be released + * ( eg ((tSHCI_UserEvtRxParam*)pPayload)->status shall be set to SHCI_TL_UserEventFlow_Disable ) + * When the status is not filled, the buffer is released by default + */ +static void APPE_SysUserEvtRx( void * pPayload ) { + UNUSED(pPayload); + /* Traces channel initialization */ + // APPD_EnableCPU2( ); + + if (APP_BLE_Init()) { + ble_glue_status = BleGlueStatusStarted; + } else { + ble_glue_status = BleGlueStatusBroken; + } + furi_hal_power_insomnia_exit(); +} + +/************************************************************* + * + * FREERTOS WRAPPER FUNCTIONS + * +*************************************************************/ +static void ShciUserEvtProcess(void *argument) { + UNUSED(argument); + for(;;) { + osThreadFlagsWait(1, osFlagsWaitAny, osWaitForever); + shci_user_evt_proc(); + } +} + +/************************************************************* + * + * WRAP FUNCTIONS + * + *************************************************************/ +void shci_notify_asynch_evt(void* pdata) { + UNUSED(pdata); + osThreadFlagsSet( ShciUserEvtProcessId, 1 ); +} + +void shci_cmd_resp_release(uint32_t flag) { + UNUSED(flag); + osSemaphoreRelease( SemShciId ); +} + +void shci_cmd_resp_wait(uint32_t timeout) { + UNUSED(timeout); + osSemaphoreAcquire( SemShciId, osWaitForever ); +} + +#if(CFG_DEBUG_TRACE != 0) +void DbgOutputInit( void ) +{ +} + +void DbgOutputTraces( uint8_t *p_data, uint16_t size, void (*cb)(void) ) +{ + furi_hal_console_tx(p_data, size); + cb(); +} +#endif + diff --git a/firmware/targets/f7/ble-glue/app_entry.h b/firmware/targets/f7/ble-glue/app_entry.h new file mode 100644 index 00000000..f1ce6038 --- /dev/null +++ b/firmware/targets/f7/ble-glue/app_entry.h @@ -0,0 +1,20 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + BleGlueStatusUninitialized, + BleGlueStatusStartup, + BleGlueStatusBroken, + BleGlueStatusStarted +} BleGlueStatus; + +void APPE_Init(); + +BleGlueStatus APPE_Status(); + +#ifdef __cplusplus +} /* extern "C" */ +#endif diff --git a/firmware/targets/f7/ble-glue/battery_service.c b/firmware/targets/f7/ble-glue/battery_service.c new file mode 100644 index 00000000..bcf54049 --- /dev/null +++ b/firmware/targets/f7/ble-glue/battery_service.c @@ -0,0 +1,55 @@ +#include "battery_service.h" +#include "app_common.h" +#include "ble.h" + +#include + +#define BATTERY_SERVICE_TAG "battery service" + +typedef struct { + uint16_t svc_handle; + uint16_t char_level_handle; +} BatterySvc; + +static BatterySvc battery_svc; + +bool battery_svc_init() { + tBleStatus status; + const uint16_t service_uuid = BATTERY_SERVICE_UUID; + const uint16_t char_battery_level_uuid = BATTERY_LEVEL_CHAR_UUID; + + // Add Battery service + status = aci_gatt_add_service(UUID_TYPE_16, (Service_UUID_t*)&service_uuid, PRIMARY_SERVICE, 4, &battery_svc.svc_handle); + if(status) { + FURI_LOG_E(BATTERY_SERVICE_TAG, "Failed to add Battery service: %d", status); + } + + // Add Battery level characteristic + status = aci_gatt_add_char(battery_svc.svc_handle, + UUID_TYPE_16, + (Char_UUID_t *) &char_battery_level_uuid, + 1, + CHAR_PROP_READ | CHAR_PROP_NOTIFY, + ATTR_PERMISSION_NONE, + GATT_DONT_NOTIFY_EVENTS, + 10, + CHAR_VALUE_LEN_CONSTANT, + &battery_svc.char_level_handle); + if(status) { + FURI_LOG_E(BATTERY_SERVICE_TAG, "Failed to add Battery level characteristic: %d", status); + } + return status != BLE_STATUS_SUCCESS; +} + +bool battery_svc_update_level(uint8_t battery_charge) { + FURI_LOG_I(BATTERY_SERVICE_TAG, "Updating battery level characteristic"); + tBleStatus result = aci_gatt_update_char_value(battery_svc.svc_handle, + battery_svc.char_level_handle, + 0, + 1, + &battery_charge); + if(result) { + FURI_LOG_E(BATTERY_SERVICE_TAG, "Failed updating RX characteristic: %d", result); + } + return result != BLE_STATUS_SUCCESS; +} diff --git a/firmware/targets/f7/ble-glue/battery_service.h b/firmware/targets/f7/ble-glue/battery_service.h new file mode 100644 index 00000000..82445d2c --- /dev/null +++ b/firmware/targets/f7/ble-glue/battery_service.h @@ -0,0 +1,16 @@ +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +bool battery_svc_init(); + +bool battery_svc_update_level(uint8_t battery_level); + +#ifdef __cplusplus +} +#endif diff --git a/firmware/targets/f7/ble-glue/ble_conf.h b/firmware/targets/f7/ble-glue/ble_conf.h new file mode 100644 index 00000000..0acd8860 --- /dev/null +++ b/firmware/targets/f7/ble-glue/ble_conf.h @@ -0,0 +1,69 @@ +/** + ****************************************************************************** + * File Name : App/ble_conf.h + * Description : Configuration file for BLE Middleware. + * + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2020 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef BLE_CONF_H +#define BLE_CONF_H + +#include "app_conf.h" + +/****************************************************************************** + * + * BLE SERVICES CONFIGURATION + * blesvc + * + ******************************************************************************/ + + /** + * This setting shall be set to '1' if the device needs to support the Peripheral Role + * In the MS configuration, both BLE_CFG_PERIPHERAL and BLE_CFG_CENTRAL shall be set to '1' + */ +#define BLE_CFG_PERIPHERAL 1 + +/** + * This setting shall be set to '1' if the device needs to support the Central Role + * In the MS configuration, both BLE_CFG_PERIPHERAL and BLE_CFG_CENTRAL shall be set to '1' + */ +#define BLE_CFG_CENTRAL 0 + +/** + * There is one handler per service enabled + * Note: There is no handler for the Device Information Service + * + * This shall take into account all registered handlers + * (from either the provided services or the custom services) + */ +#define BLE_CFG_SVC_MAX_NBR_CB 7 + +#define BLE_CFG_CLT_MAX_NBR_CB 0 + +/****************************************************************************** + * GAP Service - Apprearance + ******************************************************************************/ + +#define BLE_CFG_UNKNOWN_APPEARANCE (0) +#define BLE_CFG_GAP_APPEARANCE (0x0086) + +/****************************************************************************** + * Over The Air Feature (OTA) - STM Proprietary + ******************************************************************************/ +#define BLE_CFG_OTA_REBOOT_CHAR 0/**< REBOOT OTA MODE CHARACTERISTIC */ + +#endif /*BLE_CONF_H */ +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/ble-glue/ble_dbg_conf.h b/firmware/targets/f7/ble-glue/ble_dbg_conf.h new file mode 100644 index 00000000..4eb0239b --- /dev/null +++ b/firmware/targets/f7/ble-glue/ble_dbg_conf.h @@ -0,0 +1,199 @@ +/** + ****************************************************************************** + * File Name : App/ble_dbg_conf.h + * Description : Debug configuration file for BLE Middleware. + * + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2020 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __BLE_DBG_CONF_H +#define __BLE_DBG_CONF_H + +/** + * Enable or Disable traces from BLE + */ + +#define BLE_DBG_APP_EN 0 +#define BLE_DBG_DIS_EN 0 +#define BLE_DBG_HRS_EN 0 +#define BLE_DBG_SVCCTL_EN 0 +#define BLE_DBG_BLS_EN 0 +#define BLE_DBG_HTS_EN 0 +#define BLE_DBG_P2P_STM_EN 0 + +/** + * Macro definition + */ +#if ( BLE_DBG_APP_EN != 0 ) +#define BLE_DBG_APP_MSG PRINT_MESG_DBG +#else +#define BLE_DBG_APP_MSG PRINT_NO_MESG +#endif + +#if ( BLE_DBG_DIS_EN != 0 ) +#define BLE_DBG_DIS_MSG PRINT_MESG_DBG +#else +#define BLE_DBG_DIS_MSG PRINT_NO_MESG +#endif + +#if ( BLE_DBG_HRS_EN != 0 ) +#define BLE_DBG_HRS_MSG PRINT_MESG_DBG +#else +#define BLE_DBG_HRS_MSG PRINT_NO_MESG +#endif + +#if ( BLE_DBG_P2P_STM_EN != 0 ) +#define BLE_DBG_P2P_STM_MSG PRINT_MESG_DBG +#else +#define BLE_DBG_P2P_STM_MSG PRINT_NO_MESG +#endif + +#if ( BLE_DBG_TEMPLATE_STM_EN != 0 ) +#define BLE_DBG_TEMPLATE_STM_MSG PRINT_MESG_DBG +#else +#define BLE_DBG_TEMPLATE_STM_MSG PRINT_NO_MESG +#endif + +#if ( BLE_DBG_EDS_STM_EN != 0 ) +#define BLE_DBG_EDS_STM_MSG PRINT_MESG_DBG +#else +#define BLE_DBG_EDS_STM_MSG PRINT_NO_MESG +#endif + +#if ( BLE_DBG_LBS_STM_EN != 0 ) +#define BLE_DBG_LBS_STM_MSG PRINT_MESG_DBG +#else +#define BLE_DBG_LBS_STM_MSG PRINT_NO_MESG +#endif + +#if ( BLE_DBG_SVCCTL_EN != 0 ) +#define BLE_DBG_SVCCTL_MSG PRINT_MESG_DBG +#else +#define BLE_DBG_SVCCTL_MSG PRINT_NO_MESG +#endif + +#if (BLE_DBG_CTS_EN != 0) +#define BLE_DBG_CTS_MSG PRINT_MESG_DBG +#else +#define BLE_DBG_CTS_MSG PRINT_NO_MESG +#endif + +#if (BLE_DBG_HIDS_EN != 0) +#define BLE_DBG_HIDS_MSG PRINT_MESG_DBG +#else +#define BLE_DBG_HIDS_MSG PRINT_NO_MESG +#endif + +#if (BLE_DBG_PASS_EN != 0) +#define BLE_DBG_PASS_MSG PRINT_MESG_DBG +#else +#define BLE_DBG_PASS_MSG PRINT_NO_MESG +#endif + +#if (BLE_DBG_BLS_EN != 0) +#define BLE_DBG_BLS_MSG PRINT_MESG_DBG +#else +#define BLE_DBG_BLS_MSG PRINT_NO_MESG +#endif + +#if (BLE_DBG_HTS_EN != 0) +#define BLE_DBG_HTS_MSG PRINT_MESG_DBG +#else +#define BLE_DBG_HTS_MSG PRINT_NO_MESG +#endif + +#if (BLE_DBG_ANS_EN != 0) +#define BLE_DBG_ANS_MSG PRINT_MESG_DBG +#else +#define BLE_DBG_ANS_MSG PRINT_NO_MESG +#endif + +#if (BLE_DBG_ESS_EN != 0) +#define BLE_DBG_ESS_MSG PRINT_MESG_DBG +#else +#define BLE_DBG_ESS_MSG PRINT_NO_MESG +#endif + +#if (BLE_DBG_GLS_EN != 0) +#define BLE_DBG_GLS_MSG PRINT_MESG_DBG +#else +#define BLE_DBG_GLS_MSG PRINT_NO_MESG +#endif + +#if (BLE_DBG_BAS_EN != 0) +#define BLE_DBG_BAS_MSG PRINT_MESG_DBG +#else +#define BLE_DBG_BAS_MSG PRINT_NO_MESG +#endif + +#if (BLE_DBG_RTUS_EN != 0) +#define BLE_DBG_RTUS_MSG PRINT_MESG_DBG +#else +#define BLE_DBG_RTUS_MSG PRINT_NO_MESG +#endif + +#if (BLE_DBG_HPS_EN != 0) +#define BLE_DBG_HPS_MSG PRINT_MESG_DBG +#else +#define BLE_DBG_HPS_MSG PRINT_NO_MESG +#endif + +#if (BLE_DBG_TPS_EN != 0) +#define BLE_DBG_TPS_MSG PRINT_MESG_DBG +#else +#define BLE_DBG_TPS_MSG PRINT_NO_MESG +#endif + +#if (BLE_DBG_LLS_EN != 0) +#define BLE_DBG_LLS_MSG PRINT_MESG_DBG +#else +#define BLE_DBG_LLS_MSG PRINT_NO_MESG +#endif + +#if (BLE_DBG_IAS_EN != 0) +#define BLE_DBG_IAS_MSG PRINT_MESG_DBG +#else +#define BLE_DBG_IAS_MSG PRINT_NO_MESG +#endif + +#if (BLE_DBG_WSS_EN != 0) +#define BLE_DBG_WSS_MSG PRINT_MESG_DBG +#else +#define BLE_DBG_WSS_MSG PRINT_NO_MESG +#endif + +#if (BLE_DBG_LNS_EN != 0) +#define BLE_DBG_LNS_MSG PRINT_MESG_DBG +#else +#define BLE_DBG_LNS_MSG PRINT_NO_MESG +#endif + +#if (BLE_DBG_SCPS_EN != 0) +#define BLE_DBG_SCPS_MSG PRINT_MESG_DBG +#else +#define BLE_DBG_SCPS_MSG PRINT_NO_MESG +#endif + +#if (BLE_DBG_DTS_EN != 0) +#define BLE_DBG_DTS_MSG PRINT_MESG_DBG +#define BLE_DBG_DTS_BUF PRINT_LOG_BUFF_DBG +#else +#define BLE_DBG_DTS_MSG PRINT_NO_MESG +#define BLE_DBG_DTS_BUF PRINT_NO_MESG +#endif + +#endif /*__BLE_DBG_CONF_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/ble-glue/dev_info_service.c b/firmware/targets/f7/ble-glue/dev_info_service.c new file mode 100644 index 00000000..d2b60cfd --- /dev/null +++ b/firmware/targets/f7/ble-glue/dev_info_service.c @@ -0,0 +1,121 @@ +#include "dev_info_service.h" +#include "app_common.h" +#include "ble.h" + +#include + +#define DEV_INFO_SERVICE_TAG "dev info service" + +typedef struct { + uint16_t service_handle; + uint16_t man_name_char_handle; + uint16_t serial_num_char_handle; + uint16_t firmware_rev_char_handle; + uint16_t software_rev_char_handle; +} DevInfoSvc; + +bool dev_info_service_init() { + tBleStatus status; + DevInfoSvc dev_info_svc; + + // Add Device Information Service + uint16_t uuid = DEVICE_INFORMATION_SERVICE_UUID; + status = aci_gatt_add_service(UUID_TYPE_16, (Service_UUID_t*)&uuid, PRIMARY_SERVICE, 9, &dev_info_svc.service_handle); + if(status) { + FURI_LOG_E(DEV_INFO_SERVICE_TAG, "Failed to add Device Information Service: %d", status); + } + + // Add characteristics + uuid = MANUFACTURER_NAME_UUID; + status = aci_gatt_add_char(dev_info_svc.service_handle, + UUID_TYPE_16, + (Char_UUID_t*)&uuid, + strlen(DEV_INFO_MANUFACTURER_NAME), + CHAR_PROP_READ, + ATTR_PERMISSION_NONE, + GATT_DONT_NOTIFY_EVENTS, + 10, + CHAR_VALUE_LEN_CONSTANT, + &dev_info_svc.man_name_char_handle); + if(status) { + FURI_LOG_E(DEV_INFO_SERVICE_TAG, "Failed to add manufacturer name char: %d", status); + + } + uuid = SERIAL_NUMBER_UUID; + status = aci_gatt_add_char(dev_info_svc.service_handle, + UUID_TYPE_16, + (Char_UUID_t*)&uuid, + strlen(DEV_INFO_SERIAL_NUMBER), + CHAR_PROP_READ, + ATTR_PERMISSION_NONE, + GATT_DONT_NOTIFY_EVENTS, + 10, + CHAR_VALUE_LEN_CONSTANT, + &dev_info_svc.serial_num_char_handle); + if(status) { + FURI_LOG_E(DEV_INFO_SERVICE_TAG, "Failed to add serial number char: %d", status); + } + uuid = FIRMWARE_REVISION_UUID; + status = aci_gatt_add_char(dev_info_svc.service_handle, + UUID_TYPE_16, + (Char_UUID_t*)&uuid, + strlen(DEV_INFO_FIRMWARE_REVISION_NUMBER), + CHAR_PROP_READ, + ATTR_PERMISSION_NONE, + GATT_DONT_NOTIFY_EVENTS, + 10, + CHAR_VALUE_LEN_CONSTANT, + &dev_info_svc.firmware_rev_char_handle); + if(status) { + FURI_LOG_E(DEV_INFO_SERVICE_TAG, "Failed to add firmware revision char: %d", status); + } + uuid = SOFTWARE_REVISION_UUID; + status = aci_gatt_add_char(dev_info_svc.service_handle, + UUID_TYPE_16, + (Char_UUID_t*)&uuid, + strlen(DEV_INFO_SOFTWARE_REVISION_NUMBER), + CHAR_PROP_READ, + ATTR_PERMISSION_NONE, + GATT_DONT_NOTIFY_EVENTS, + 10, + CHAR_VALUE_LEN_CONSTANT, + &dev_info_svc.software_rev_char_handle); + if(status) { + FURI_LOG_E(DEV_INFO_SERVICE_TAG, "Failed to add software revision char: %d", status); + } + + // Update characteristics + status = aci_gatt_update_char_value(dev_info_svc.service_handle, + dev_info_svc.man_name_char_handle, + 0, + strlen(DEV_INFO_MANUFACTURER_NAME), + (uint8_t*)DEV_INFO_MANUFACTURER_NAME); + if(status) { + FURI_LOG_E(DEV_INFO_SERVICE_TAG, "Failed to update manufacturer name char: %d", status); + } + status = aci_gatt_update_char_value(dev_info_svc.service_handle, + dev_info_svc.serial_num_char_handle, + 0, + strlen(DEV_INFO_SERIAL_NUMBER), + (uint8_t*)DEV_INFO_SERIAL_NUMBER); + if(status) { + FURI_LOG_E(DEV_INFO_SERVICE_TAG, "Failed to update serial number char: %d", status); + } + status = aci_gatt_update_char_value(dev_info_svc.service_handle, + dev_info_svc.firmware_rev_char_handle, + 0, + strlen(DEV_INFO_FIRMWARE_REVISION_NUMBER), + (uint8_t*)DEV_INFO_FIRMWARE_REVISION_NUMBER); + if(status) { + FURI_LOG_E(DEV_INFO_SERVICE_TAG, "Failed to update firmware revision char: %d", status); + } + status = aci_gatt_update_char_value(dev_info_svc.service_handle, + dev_info_svc.software_rev_char_handle, + 0, + strlen(DEV_INFO_SOFTWARE_REVISION_NUMBER), + (uint8_t*)DEV_INFO_SOFTWARE_REVISION_NUMBER); + if(status) { + FURI_LOG_E(DEV_INFO_SERVICE_TAG, "Failed to update software revision char: %d", status); + } + return status != BLE_STATUS_SUCCESS; +} diff --git a/firmware/targets/f7/ble-glue/dev_info_service.h b/firmware/targets/f7/ble-glue/dev_info_service.h new file mode 100644 index 00000000..b0e08d3f --- /dev/null +++ b/firmware/targets/f7/ble-glue/dev_info_service.h @@ -0,0 +1,20 @@ +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define DEV_INFO_MANUFACTURER_NAME "Flipper Devices Inc." +#define DEV_INFO_SERIAL_NUMBER "1.0" +#define DEV_INFO_FIRMWARE_REVISION_NUMBER TARGET +#define DEV_INFO_SOFTWARE_REVISION_NUMBER GIT_COMMIT " " GIT_BRANCH " " GIT_BRANCH_NUM " " BUILD_DATE + + +bool dev_info_service_init(); + +#ifdef __cplusplus +} +#endif diff --git a/firmware/targets/f7/ble-glue/hw_conf.h b/firmware/targets/f7/ble-glue/hw_conf.h new file mode 100644 index 00000000..dcda0176 --- /dev/null +++ b/firmware/targets/f7/ble-glue/hw_conf.h @@ -0,0 +1,199 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file hw_conf.h + * @author MCD Application Team + * @brief Configuration of hardware interface + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2019 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef HW_CONF_H +#define HW_CONF_H + +#include "FreeRTOSConfig.h" + +/****************************************************************************** + * Semaphores + * THIS SHALL NO BE CHANGED AS THESE SEMAPHORES ARE USED AS WELL ON THE CM0+ + *****************************************************************************/ +/** +* Index of the semaphore used by CPU2 to prevent the CPU1 to either write or erase data in flash +* The CPU1 shall not either write or erase in flash when this semaphore is taken by the CPU2 +* When the CPU1 needs to either write or erase in flash, it shall first get the semaphore and release it just +* after writing a raw (64bits data) or erasing one sector. +* Once the Semaphore has been released, there shall be at least 1us before it can be taken again. This is required +* to give the opportunity to CPU2 to take it. +* On v1.4.0 and older CPU2 wireless firmware, this semaphore is unused and CPU2 is using PES bit. +* By default, CPU2 is using the PES bit to protect its timing. The CPU1 may request the CPU2 to use the semaphore +* instead of the PES bit by sending the system command SHCI_C2_SetFlashActivityControl() +*/ +#define CFG_HW_BLOCK_FLASH_REQ_BY_CPU2_SEMID 7 + +/** +* Index of the semaphore used by CPU1 to prevent the CPU2 to either write or erase data in flash +* In order to protect its timing, the CPU1 may get this semaphore to prevent the CPU2 to either +* write or erase in flash (as this will stall both CPUs) +* The PES bit shall not be used as this may stall the CPU2 in some cases. +*/ +#define CFG_HW_BLOCK_FLASH_REQ_BY_CPU1_SEMID 6 + +/** +* Index of the semaphore used to manage the CLK48 clock configuration +* When the USB is required, this semaphore shall be taken before configuring te CLK48 for USB +* and should be released after the application switch OFF the clock when the USB is not used anymore +* When using the RNG, it is good enough to use CFG_HW_RNG_SEMID to control CLK48. +* More details in AN5289 +*/ +#define CFG_HW_CLK48_CONFIG_SEMID 5 + +/* Index of the semaphore used to manage the entry Stop Mode procedure */ +#define CFG_HW_ENTRY_STOP_MODE_SEMID 4 + +/* Index of the semaphore used to access the RCC */ +#define CFG_HW_RCC_SEMID 3 + +/* Index of the semaphore used to access the FLASH */ +#define CFG_HW_FLASH_SEMID 2 + +/* Index of the semaphore used to access the PKA */ +#define CFG_HW_PKA_SEMID 1 + +/* Index of the semaphore used to access the RNG */ +#define CFG_HW_RNG_SEMID 0 + +/****************************************************************************** + * HW TIMER SERVER + *****************************************************************************/ +/** + * The user may define the maximum number of virtual timers supported. + * It shall not exceed 255 + */ +#define CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER 6 + +/** + * The user may define the priority in the NVIC of the RTC_WKUP interrupt handler that is used to manage the + * wakeup timer. + * This setting is the preemptpriority part of the NVIC. + */ +#define CFG_HW_TS_NVIC_RTC_WAKEUP_IT_PREEMPTPRIO (configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY + 1) /* FreeRTOS requirement */ + +/** + * The user may define the priority in the NVIC of the RTC_WKUP interrupt handler that is used to manage the + * wakeup timer. + * This setting is the subpriority part of the NVIC. It does not exist on all processors. When it is not supported + * on the CPU, the setting is ignored + */ +#define CFG_HW_TS_NVIC_RTC_WAKEUP_IT_SUBPRIO 0 + +/** + * Define a critical section in the Timer server + * The Timer server does not support the API to be nested + * The Application shall either: + * a) Ensure this will never happen + * b) Define the critical section + * The default implementations is masking all interrupts using the PRIMASK bit + * The TimerServer driver uses critical sections to avoid context corruption. This is achieved with the macro + * TIMER_ENTER_CRITICAL_SECTION and TIMER_EXIT_CRITICAL_SECTION. When CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION is set + * to 1, all STM32 interrupts are masked with the PRIMASK bit of the CortexM CPU. It is possible to use the BASEPRI + * register of the CortexM CPU to keep allowed some interrupts with high priority. In that case, the user shall + * re-implement TIMER_ENTER_CRITICAL_SECTION and TIMER_EXIT_CRITICAL_SECTION and shall make sure that no TimerServer + * API are called when the TIMER critical section is entered + */ +#define CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION 1 + +/** + * This value shall reflect the maximum delay there could be in the application between the time the RTC interrupt + * is generated by the Hardware and the time when the RTC interrupt handler is called. This time is measured in + * number of RTCCLK ticks. + * A relaxed timing would be 10ms + * When the value is too short, the timerserver will not be able to count properly and all timeout may be random. + * When the value is too long, the device may wake up more often than the most optimal configuration. However, the + * impact on power consumption would be marginal (unless the value selected is extremely too long). It is strongly + * recommended to select a value large enough to make sure it is not too short to ensure reliability of the system + * as this will have marginal impact on low power mode + */ +#define CFG_HW_TS_RTC_HANDLER_MAX_DELAY ( 10 * (LSI_VALUE/1000) ) + + /** + * Interrupt ID in the NVIC of the RTC Wakeup interrupt handler + * It shall be type of IRQn_Type + */ +#define CFG_HW_TS_RTC_WAKEUP_HANDLER_ID RTC_WKUP_IRQn + +/****************************************************************************** + * HW UART + *****************************************************************************/ +#define CFG_HW_LPUART1_ENABLED 0 +#define CFG_HW_LPUART1_DMA_TX_SUPPORTED 0 + +#define CFG_HW_USART1_ENABLED 1 +#define CFG_HW_USART1_DMA_TX_SUPPORTED 1 + +/** + * UART1 + */ +#define CFG_HW_USART1_PREEMPTPRIORITY 0x0F +#define CFG_HW_USART1_SUBPRIORITY 0 + +/** < The application shall check the selected source clock is enable */ +#define CFG_HW_USART1_SOURCE_CLOCK RCC_USART1CLKSOURCE_SYSCLK + +#define CFG_HW_USART1_BAUDRATE 115200 +#define CFG_HW_USART1_WORDLENGTH UART_WORDLENGTH_8B +#define CFG_HW_USART1_STOPBITS UART_STOPBITS_1 +#define CFG_HW_USART1_PARITY UART_PARITY_NONE +#define CFG_HW_USART1_HWFLOWCTL UART_HWCONTROL_NONE +#define CFG_HW_USART1_MODE UART_MODE_TX_RX +#define CFG_HW_USART1_ADVFEATUREINIT UART_ADVFEATURE_NO_INIT +#define CFG_HW_USART1_OVERSAMPLING UART_OVERSAMPLING_8 + +#define CFG_HW_USART1_TX_PORT_CLK_ENABLE __HAL_RCC_GPIOB_CLK_ENABLE +#define CFG_HW_USART1_TX_PORT GPIOB +#define CFG_HW_USART1_TX_PIN GPIO_PIN_6 +#define CFG_HW_USART1_TX_MODE GPIO_MODE_AF_PP +#define CFG_HW_USART1_TX_PULL GPIO_NOPULL +#define CFG_HW_USART1_TX_SPEED GPIO_SPEED_FREQ_VERY_HIGH +#define CFG_HW_USART1_TX_ALTERNATE GPIO_AF7_USART1 + +#define CFG_HW_USART1_RX_PORT_CLK_ENABLE __HAL_RCC_GPIOB_CLK_ENABLE +#define CFG_HW_USART1_RX_PORT GPIOB +#define CFG_HW_USART1_RX_PIN GPIO_PIN_7 +#define CFG_HW_USART1_RX_MODE GPIO_MODE_AF_PP +#define CFG_HW_USART1_RX_PULL GPIO_NOPULL +#define CFG_HW_USART1_RX_SPEED GPIO_SPEED_FREQ_VERY_HIGH +#define CFG_HW_USART1_RX_ALTERNATE GPIO_AF7_USART1 + +#define CFG_HW_USART1_CTS_PORT_CLK_ENABLE __HAL_RCC_GPIOA_CLK_ENABLE +#define CFG_HW_USART1_CTS_PORT GPIOA +#define CFG_HW_USART1_CTS_PIN GPIO_PIN_11 +#define CFG_HW_USART1_CTS_MODE GPIO_MODE_AF_PP +#define CFG_HW_USART1_CTS_PULL GPIO_PULLDOWN +#define CFG_HW_USART1_CTS_SPEED GPIO_SPEED_FREQ_VERY_HIGH +#define CFG_HW_USART1_CTS_ALTERNATE GPIO_AF7_USART1 + +#define CFG_HW_USART1_DMA_TX_PREEMPTPRIORITY 0x0F +#define CFG_HW_USART1_DMA_TX_SUBPRIORITY 0 + +#define CFG_HW_USART1_DMAMUX_CLK_ENABLE __HAL_RCC_DMAMUX1_CLK_ENABLE +#define CFG_HW_USART1_DMA_CLK_ENABLE __HAL_RCC_DMA2_CLK_ENABLE +#define CFG_HW_USART1_TX_DMA_REQ DMA_REQUEST_USART1_TX +#define CFG_HW_USART1_TX_DMA_CHANNEL DMA2_Channel4 +#define CFG_HW_USART1_TX_DMA_IRQn DMA2_Channel4_IRQn +#define CFG_HW_USART1_DMA_TX_IRQHandler DMA2_Channel4_IRQHandler + +#endif /*HW_CONF_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/ble-glue/hw_if.h b/firmware/targets/f7/ble-glue/hw_if.h new file mode 100644 index 00000000..271a222a --- /dev/null +++ b/firmware/targets/f7/ble-glue/hw_if.h @@ -0,0 +1,250 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file hw_if.h + * @author MCD Application Team + * @brief Hardware Interface + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2019 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef HW_IF_H +#define HW_IF_H + +#ifdef __cplusplus +extern "C" { +#endif + + /* Includes ------------------------------------------------------------------*/ +#include "stm32wbxx.h" +#include "stm32wbxx_ll_exti.h" +#include "stm32wbxx_ll_system.h" +#include "stm32wbxx_ll_rcc.h" +#include "stm32wbxx_ll_ipcc.h" +#include "stm32wbxx_ll_bus.h" +#include "stm32wbxx_ll_pwr.h" +#include "stm32wbxx_ll_cortex.h" +#include "stm32wbxx_ll_utils.h" +#include "stm32wbxx_ll_hsem.h" +#include "stm32wbxx_ll_gpio.h" +#include "stm32wbxx_ll_rtc.h" + +#ifdef USE_STM32WBXX_USB_DONGLE +#include "stm32wbxx_usb_dongle.h" +#endif +#ifdef USE_STM32WBXX_NUCLEO +#include "stm32wbxx_nucleo.h" +#endif +#ifdef USE_X_NUCLEO_EPD +#include "x_nucleo_epd.h" +#endif + +/* Private includes ----------------------------------------------------------*/ +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + + /****************************************************************************** + * HW UART + ******************************************************************************/ + typedef enum + { + hw_uart1, + hw_uart2, + hw_lpuart1, + } hw_uart_id_t; + + typedef enum + { + hw_uart_ok, + hw_uart_error, + hw_uart_busy, + hw_uart_to, + } hw_status_t; + + void HW_UART_Init(hw_uart_id_t hw_uart_id); + void HW_UART_Receive_IT(hw_uart_id_t hw_uart_id, uint8_t *pData, uint16_t Size, void (*Callback)(void)); + void HW_UART_Transmit_IT(hw_uart_id_t hw_uart_id, uint8_t *pData, uint16_t Size, void (*Callback)(void)); + hw_status_t HW_UART_Transmit(hw_uart_id_t hw_uart_id, uint8_t *p_data, uint16_t size, uint32_t timeout); + hw_status_t HW_UART_Transmit_DMA(hw_uart_id_t hw_uart_id, uint8_t *p_data, uint16_t size, void (*Callback)(void)); + void HW_UART_Interrupt_Handler(hw_uart_id_t hw_uart_id); + void HW_UART_DMA_Interrupt_Handler(hw_uart_id_t hw_uart_id); + + /****************************************************************************** + * HW TimerServer + ******************************************************************************/ + /* Exported types ------------------------------------------------------------*/ + /** + * This setting is used when standby mode is supported. + * hw_ts_InitMode_Limited should be used when the device restarts from Standby Mode. In that case, the Timer Server does + * not re-initialized its context. Only the Hardware register which content has been lost is reconfigured + * Otherwise, hw_ts_InitMode_Full should be requested (Start from Power ON) and everything is re-initialized. + */ + typedef enum + { + hw_ts_InitMode_Full, + hw_ts_InitMode_Limited, + } HW_TS_InitMode_t; + + /** + * When a Timer is created as a SingleShot timer, it is not automatically restarted when the timeout occurs. However, + * the timer is kept reserved in the list and could be restarted at anytime with HW_TS_Start() + * + * When a Timer is created as a Repeated timer, it is automatically restarted when the timeout occurs. + */ + typedef enum + { + hw_ts_SingleShot, + hw_ts_Repeated + } HW_TS_Mode_t; + + /** + * hw_ts_Successful is returned when a Timer has been successfully created with HW_TS_Create(). Otherwise, hw_ts_Failed + * is returned. When hw_ts_Failed is returned, that means there are not enough free slots in the list to create a + * Timer. In that case, CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER should be increased + */ + typedef enum + { + hw_ts_Successful, + hw_ts_Failed, + }HW_TS_ReturnStatus_t; + + typedef void (*HW_TS_pTimerCb_t)(void); + + /** + * @brief Initialize the timer server + * This API shall be called by the application before any timer is requested to the timer server. It + * configures the RTC module to be connected to the LSI input clock. + * + * @param TimerInitMode: When the device restarts from Standby, it should request hw_ts_InitMode_Limited so that the + * Timer context is not re-initialized. Otherwise, hw_ts_InitMode_Full should be requested + * @param hrtc: RTC Handle + * @retval None + */ + void HW_TS_Init(HW_TS_InitMode_t TimerInitMode, RTC_HandleTypeDef *hrtc); + + /** + * @brief Interface to create a virtual timer + * The user shall call this API to create a timer. Once created, the timer is reserved to the module until it + * has been deleted. When creating a timer, the user shall specify the mode (single shot or repeated), the + * callback to be notified when the timer expires and a module ID to identify in the timer interrupt handler + * which module is concerned. In return, the user gets a timer ID to handle it. + * + * @param TimerProcessID: This is an identifier provided by the user and returned in the callback to allow + * identification of the requester + * @param pTimerId: Timer Id returned to the user to request operation (start, stop, delete) + * @param TimerMode: Mode of the virtual timer (Single shot or repeated) + * @param pTimerCallBack: Callback when the virtual timer expires + * @retval HW_TS_ReturnStatus_t: Return whether the creation is sucessfull or not + */ + HW_TS_ReturnStatus_t HW_TS_Create(uint32_t TimerProcessID, uint8_t *pTimerId, HW_TS_Mode_t TimerMode, HW_TS_pTimerCb_t pTimerCallBack); + + /** + * @brief Stop a virtual timer + * This API may be used to stop a running timer. A timer which is stopped is move to the pending state. + * A pending timer may be restarted at any time with a different timeout value but the mode cannot be changed. + * Nothing is done when it is called to stop a timer which has been already stopped + * + * @param TimerID: Id of the timer to stop + * @retval None + */ + void HW_TS_Stop(uint8_t TimerID); + + /** + * @brief Start a virtual timer + * This API shall be used to start a timer. The timeout value is specified and may be different each time. + * When the timer is in the single shot mode, it will move to the pending state when it expires. The user may + * restart it at any time with a different timeout value. When the timer is in the repeated mode, it always + * stay in the running state. When the timer expires, it will be restarted with the same timeout value. + * This API shall not be called on a running timer. + * + * @param TimerID: The ID Id of the timer to start + * @param timeout_ticks: Number of ticks of the virtual timer (Maximum value is (0xFFFFFFFF-0xFFFF = 0xFFFF0000) + * @retval None + */ + void HW_TS_Start(uint8_t TimerID, uint32_t timeout_ticks); + + /** + * @brief Delete a virtual timer from the list + * This API should be used when a timer is not needed anymore by the user. A deleted timer is removed from + * the timer list managed by the timer server. It cannot be restarted again. The user has to go with the + * creation of a new timer if required and may get a different timer id + * + * @param TimerID: The ID of the timer to remove from the list + * @retval None + */ + void HW_TS_Delete(uint8_t TimerID); + + /** + * @brief Schedule the timer list on the timer interrupt handler + * This interrupt handler shall be called by the application in the RTC interrupt handler. This handler takes + * care of clearing all status flag required in the RTC and EXTI peripherals + * + * @param None + * @retval None + */ + void HW_TS_RTC_Wakeup_Handler(void); + + /** + * @brief Return the number of ticks to count before the interrupt + * This API returns the number of ticks left to be counted before an interrupt is generated by the + * Timer Server. This API may be used by the application for power management optimization. When the system + * enters low power mode, the mode selection is a tradeoff between the wakeup time where the CPU is running + * and the time while the CPU will be kept in low power mode before next wakeup. The deeper is the + * low power mode used, the longer is the wakeup time. The low power mode management considering wakeup time + * versus time in low power mode is implementation specific + * When the timer is disabled (No timer in the list), it returns 0xFFFF + * + * @param None + * @retval The number of ticks left to count + */ + uint16_t HW_TS_RTC_ReadLeftTicksToCount(void); + + /** + * @brief Notify the application that a registered timer has expired + * This API shall be implemented by the user application. + * This API notifies the application that a timer expires. This API is running in the RTC Wakeup interrupt + * context. The application may implement an Operating System to change the context priority where the timer + * callback may be handled. This API provides the module ID to identify which module is concerned and to allow + * sending the information to the correct task + * + * @param TimerProcessID: The TimerProcessId associated with the timer when it has been created + * @param TimerID: The TimerID of the expired timer + * @param pTimerCallBack: The Callback associated with the timer when it has been created + * @retval None + */ + void HW_TS_RTC_Int_AppNot(uint32_t TimerProcessID, uint8_t TimerID, HW_TS_pTimerCb_t pTimerCallBack); + + /** + * @brief Notify the application that the wakeupcounter has been updated + * This API should be implemented by the user application + * This API notifies the application that the counter has been updated. This is expected to be used along + * with the HW_TS_RTC_ReadLeftTicksToCount () API. It could be that the counter has been updated since the + * last call of HW_TS_RTC_ReadLeftTicksToCount () and before entering low power mode. This notification + * provides a way to the application to solve that race condition to reevaluate the counter value before + * entering low power mode + * + * @param None + * @retval None + */ + void HW_TS_RTC_CountUpdated_AppNot(void); + +#ifdef __cplusplus +} +#endif + +#endif /*HW_IF_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/ble-glue/hw_ipcc.c b/firmware/targets/f7/ble-glue/hw_ipcc.c new file mode 100644 index 00000000..17b5a4d8 --- /dev/null +++ b/firmware/targets/f7/ble-glue/hw_ipcc.c @@ -0,0 +1,675 @@ +/** + ****************************************************************************** + * File Name : Target/hw_ipcc.c + * Description : Hardware IPCC source file for STM32WPAN Middleware. + * + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2020 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "app_common.h" +#include "mbox_def.h" + +/* Global variables ---------------------------------------------------------*/ +/* Private defines -----------------------------------------------------------*/ +#define HW_IPCC_TX_PENDING( channel ) ( !(LL_C1_IPCC_IsActiveFlag_CHx( IPCC, channel )) ) && (((~(IPCC->C1MR)) & (channel << 16U))) +#define HW_IPCC_RX_PENDING( channel ) (LL_C2_IPCC_IsActiveFlag_CHx( IPCC, channel )) && (((~(IPCC->C1MR)) & (channel << 0U))) + +/* Private macros ------------------------------------------------------------*/ +/* Private typedef -----------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +static void (*FreeBufCb)( void ); + +/* Private function prototypes -----------------------------------------------*/ +static void HW_IPCC_BLE_EvtHandler( void ); +static void HW_IPCC_BLE_AclDataEvtHandler( void ); +static void HW_IPCC_MM_FreeBufHandler( void ); +static void HW_IPCC_SYS_CmdEvtHandler( void ); +static void HW_IPCC_SYS_EvtHandler( void ); +static void HW_IPCC_TRACES_EvtHandler( void ); + +#ifdef THREAD_WB +static void HW_IPCC_OT_CmdEvtHandler( void ); +static void HW_IPCC_THREAD_NotEvtHandler( void ); +static void HW_IPCC_THREAD_CliNotEvtHandler( void ); +#endif + +#ifdef LLD_TESTS_WB +static void HW_IPCC_LLDTESTS_ReceiveCliRspHandler( void ); +static void HW_IPCC_LLDTESTS_ReceiveM0CmdHandler( void ); +#endif +#ifdef LLD_BLE_WB +/*static void HW_IPCC_LLD_BLE_ReceiveCliRspHandler( void );*/ +static void HW_IPCC_LLD_BLE_ReceiveRspHandler( void ); +static void HW_IPCC_LLD_BLE_ReceiveM0CmdHandler( void ); +#endif + +#ifdef MAC_802_15_4_WB +static void HW_IPCC_MAC_802_15_4_CmdEvtHandler( void ); +static void HW_IPCC_MAC_802_15_4_NotEvtHandler( void ); +#endif + +#ifdef ZIGBEE_WB +static void HW_IPCC_ZIGBEE_CmdEvtHandler( void ); +static void HW_IPCC_ZIGBEE_StackNotifEvtHandler( void ); +static void HW_IPCC_ZIGBEE_StackM0RequestHandler( void ); +#endif + +/* Public function definition -----------------------------------------------*/ + +/****************************************************************************** + * INTERRUPT HANDLER + ******************************************************************************/ +void HW_IPCC_Rx_Handler( void ) +{ + if (HW_IPCC_RX_PENDING( HW_IPCC_SYSTEM_EVENT_CHANNEL )) + { + HW_IPCC_SYS_EvtHandler(); + } +#ifdef MAC_802_15_4_WB + else if (HW_IPCC_RX_PENDING( HW_IPCC_MAC_802_15_4_NOTIFICATION_ACK_CHANNEL )) + { + HW_IPCC_MAC_802_15_4_NotEvtHandler(); + } +#endif /* MAC_802_15_4_WB */ +#ifdef THREAD_WB + else if (HW_IPCC_RX_PENDING( HW_IPCC_THREAD_NOTIFICATION_ACK_CHANNEL )) + { + HW_IPCC_THREAD_NotEvtHandler(); + } + else if (HW_IPCC_RX_PENDING( HW_IPCC_THREAD_CLI_NOTIFICATION_ACK_CHANNEL )) + { + HW_IPCC_THREAD_CliNotEvtHandler(); + } +#endif /* THREAD_WB */ +#ifdef LLD_TESTS_WB + else if (HW_IPCC_RX_PENDING( HW_IPCC_LLDTESTS_CLI_RSP_CHANNEL )) + { + HW_IPCC_LLDTESTS_ReceiveCliRspHandler(); + } + else if (HW_IPCC_RX_PENDING( HW_IPCC_LLDTESTS_M0_CMD_CHANNEL )) + { + HW_IPCC_LLDTESTS_ReceiveM0CmdHandler(); + } +#endif /* LLD_TESTS_WB */ +#ifdef LLD_BLE_WB + else if (HW_IPCC_RX_PENDING( HW_IPCC_LLD_BLE_RSP_CHANNEL )) + { + HW_IPCC_LLD_BLE_ReceiveRspHandler(); + } + else if (HW_IPCC_RX_PENDING( HW_IPCC_LLD_BLE_M0_CMD_CHANNEL )) + { + HW_IPCC_LLD_BLE_ReceiveM0CmdHandler(); + } +#endif /* LLD_TESTS_WB */ +#ifdef ZIGBEE_WB + else if (HW_IPCC_RX_PENDING( HW_IPCC_ZIGBEE_APPLI_NOTIF_ACK_CHANNEL )) + { + HW_IPCC_ZIGBEE_StackNotifEvtHandler(); + } + else if (HW_IPCC_RX_PENDING( HW_IPCC_ZIGBEE_M0_REQUEST_CHANNEL )) + { + HW_IPCC_ZIGBEE_StackM0RequestHandler(); + } +#endif /* ZIGBEE_WB */ + else if (HW_IPCC_RX_PENDING( HW_IPCC_BLE_EVENT_CHANNEL )) + { + HW_IPCC_BLE_EvtHandler(); + } + else if (HW_IPCC_RX_PENDING( HW_IPCC_TRACES_CHANNEL )) + { + HW_IPCC_TRACES_EvtHandler(); + } + + return; +} + +void HW_IPCC_Tx_Handler( void ) +{ + if (HW_IPCC_TX_PENDING( HW_IPCC_SYSTEM_CMD_RSP_CHANNEL )) + { + HW_IPCC_SYS_CmdEvtHandler(); + } +#ifdef MAC_802_15_4_WB + else if (HW_IPCC_TX_PENDING( HW_IPCC_MAC_802_15_4_CMD_RSP_CHANNEL )) + { + HW_IPCC_MAC_802_15_4_CmdEvtHandler(); + } +#endif /* MAC_802_15_4_WB */ +#ifdef THREAD_WB + else if (HW_IPCC_TX_PENDING( HW_IPCC_THREAD_OT_CMD_RSP_CHANNEL )) + { + HW_IPCC_OT_CmdEvtHandler(); + } +#endif /* THREAD_WB */ +#ifdef LLD_TESTS_WB +// No TX handler for LLD tests +#endif /* LLD_TESTS_WB */ +#ifdef ZIGBEE_WB + if (HW_IPCC_TX_PENDING( HW_IPCC_ZIGBEE_CMD_APPLI_CHANNEL )) + { + HW_IPCC_ZIGBEE_CmdEvtHandler(); + } +#endif /* ZIGBEE_WB */ + else if (HW_IPCC_TX_PENDING( HW_IPCC_SYSTEM_CMD_RSP_CHANNEL )) + { + HW_IPCC_SYS_CmdEvtHandler(); + } + else if (HW_IPCC_TX_PENDING( HW_IPCC_MM_RELEASE_BUFFER_CHANNEL )) + { + HW_IPCC_MM_FreeBufHandler(); + } + else if (HW_IPCC_TX_PENDING( HW_IPCC_HCI_ACL_DATA_CHANNEL )) + { + HW_IPCC_BLE_AclDataEvtHandler(); + } + + return; +} +/****************************************************************************** + * GENERAL + ******************************************************************************/ +void HW_IPCC_Enable( void ) +{ + /** + * Such as IPCC IP available to the CPU2, it is required to keep the IPCC clock running + when FUS is running on CPU2 and CPU1 enters deep sleep mode + */ + LL_C2_AHB3_GRP1_EnableClock(LL_C2_AHB3_GRP1_PERIPH_IPCC); + + /** + * When the device is out of standby, it is required to use the EXTI mechanism to wakeup CPU2 + */ + LL_C2_EXTI_EnableEvent_32_63( LL_EXTI_LINE_41 ); + LL_EXTI_EnableRisingTrig_32_63( LL_EXTI_LINE_41 ); + + /** + * In case the SBSFU is implemented, it may have already set the C2BOOT bit to startup the CPU2. + * In that case, to keep the mechanism transparent to the user application, it shall call the system command + * SHCI_C2_Reinit( ) before jumping to the application. + * When the CPU2 receives that command, it waits for its event input to be set to restart the CPU2 firmware. + * This is required because once C2BOOT has been set once, a clear/set on C2BOOT has no effect. + * When SHCI_C2_Reinit( ) is not called, generating an event to the CPU2 does not have any effect + * So, by default, the application shall both set the event flag and set the C2BOOT bit. + */ + __SEV( ); /* Set the internal event flag and send an event to the CPU2 */ + __WFE( ); /* Clear the internal event flag */ + LL_PWR_EnableBootC2( ); + + return; +} + +void HW_IPCC_Init( void ) +{ + LL_AHB3_GRP1_EnableClock( LL_AHB3_GRP1_PERIPH_IPCC ); + + LL_C1_IPCC_EnableIT_RXO( IPCC ); + LL_C1_IPCC_EnableIT_TXF( IPCC ); + + HAL_NVIC_SetPriority(IPCC_C1_RX_IRQn, 6, 0); + HAL_NVIC_EnableIRQ(IPCC_C1_RX_IRQn); + HAL_NVIC_SetPriority(IPCC_C1_TX_IRQn, 6, 0); + HAL_NVIC_EnableIRQ(IPCC_C1_TX_IRQn); + + return; +} + +/****************************************************************************** + * BLE + ******************************************************************************/ +void HW_IPCC_BLE_Init( void ) +{ + LL_C1_IPCC_EnableReceiveChannel( IPCC, HW_IPCC_BLE_EVENT_CHANNEL ); + + return; +} + +void HW_IPCC_BLE_SendCmd( void ) +{ + LL_C1_IPCC_SetFlag_CHx( IPCC, HW_IPCC_BLE_CMD_CHANNEL ); + + return; +} + +static void HW_IPCC_BLE_EvtHandler( void ) +{ + HW_IPCC_BLE_RxEvtNot(); + + LL_C1_IPCC_ClearFlag_CHx( IPCC, HW_IPCC_BLE_EVENT_CHANNEL ); + + return; +} + +void HW_IPCC_BLE_SendAclData( void ) +{ + LL_C1_IPCC_SetFlag_CHx( IPCC, HW_IPCC_HCI_ACL_DATA_CHANNEL ); + LL_C1_IPCC_EnableTransmitChannel( IPCC, HW_IPCC_HCI_ACL_DATA_CHANNEL ); + + return; +} + +static void HW_IPCC_BLE_AclDataEvtHandler( void ) +{ + LL_C1_IPCC_DisableTransmitChannel( IPCC, HW_IPCC_HCI_ACL_DATA_CHANNEL ); + + HW_IPCC_BLE_AclDataAckNot(); + + return; +} + +__weak void HW_IPCC_BLE_AclDataAckNot( void ){}; +__weak void HW_IPCC_BLE_RxEvtNot( void ){}; + +/****************************************************************************** + * SYSTEM + ******************************************************************************/ +void HW_IPCC_SYS_Init( void ) +{ + LL_C1_IPCC_EnableReceiveChannel( IPCC, HW_IPCC_SYSTEM_EVENT_CHANNEL ); + + return; +} + +void HW_IPCC_SYS_SendCmd( void ) +{ + LL_C1_IPCC_SetFlag_CHx( IPCC, HW_IPCC_SYSTEM_CMD_RSP_CHANNEL ); + LL_C1_IPCC_EnableTransmitChannel( IPCC, HW_IPCC_SYSTEM_CMD_RSP_CHANNEL ); + + return; +} + +static void HW_IPCC_SYS_CmdEvtHandler( void ) +{ + LL_C1_IPCC_DisableTransmitChannel( IPCC, HW_IPCC_SYSTEM_CMD_RSP_CHANNEL ); + + HW_IPCC_SYS_CmdEvtNot(); + + return; +} + +static void HW_IPCC_SYS_EvtHandler( void ) +{ + HW_IPCC_SYS_EvtNot(); + + LL_C1_IPCC_ClearFlag_CHx( IPCC, HW_IPCC_SYSTEM_EVENT_CHANNEL ); + + return; +} + +__weak void HW_IPCC_SYS_CmdEvtNot( void ){}; +__weak void HW_IPCC_SYS_EvtNot( void ){}; + +/****************************************************************************** + * MAC 802.15.4 + ******************************************************************************/ +#ifdef MAC_802_15_4_WB +void HW_IPCC_MAC_802_15_4_Init( void ) +{ + LL_C1_IPCC_EnableReceiveChannel( IPCC, HW_IPCC_MAC_802_15_4_NOTIFICATION_ACK_CHANNEL ); + + return; +} + +void HW_IPCC_MAC_802_15_4_SendCmd( void ) +{ + LL_C1_IPCC_SetFlag_CHx( IPCC, HW_IPCC_MAC_802_15_4_CMD_RSP_CHANNEL ); + LL_C1_IPCC_EnableTransmitChannel( IPCC, HW_IPCC_MAC_802_15_4_CMD_RSP_CHANNEL ); + + return; +} + +void HW_IPCC_MAC_802_15_4_SendAck( void ) +{ + LL_C1_IPCC_ClearFlag_CHx( IPCC, HW_IPCC_MAC_802_15_4_NOTIFICATION_ACK_CHANNEL ); + LL_C1_IPCC_EnableReceiveChannel( IPCC, HW_IPCC_MAC_802_15_4_NOTIFICATION_ACK_CHANNEL ); + + return; +} + +static void HW_IPCC_MAC_802_15_4_CmdEvtHandler( void ) +{ + LL_C1_IPCC_DisableTransmitChannel( IPCC, HW_IPCC_MAC_802_15_4_CMD_RSP_CHANNEL ); + + HW_IPCC_MAC_802_15_4_CmdEvtNot(); + + return; +} + +static void HW_IPCC_MAC_802_15_4_NotEvtHandler( void ) +{ + LL_C1_IPCC_DisableReceiveChannel( IPCC, HW_IPCC_MAC_802_15_4_NOTIFICATION_ACK_CHANNEL ); + + HW_IPCC_MAC_802_15_4_EvtNot(); + + return; +} +__weak void HW_IPCC_MAC_802_15_4_CmdEvtNot( void ){}; +__weak void HW_IPCC_MAC_802_15_4_EvtNot( void ){}; +#endif + +/****************************************************************************** + * THREAD + ******************************************************************************/ +#ifdef THREAD_WB +void HW_IPCC_THREAD_Init( void ) +{ + LL_C1_IPCC_EnableReceiveChannel( IPCC, HW_IPCC_THREAD_NOTIFICATION_ACK_CHANNEL ); + LL_C1_IPCC_EnableReceiveChannel( IPCC, HW_IPCC_THREAD_CLI_NOTIFICATION_ACK_CHANNEL ); + + return; +} + +void HW_IPCC_OT_SendCmd( void ) +{ + LL_C1_IPCC_SetFlag_CHx( IPCC, HW_IPCC_THREAD_OT_CMD_RSP_CHANNEL ); + LL_C1_IPCC_EnableTransmitChannel( IPCC, HW_IPCC_THREAD_OT_CMD_RSP_CHANNEL ); + + return; +} + +void HW_IPCC_CLI_SendCmd( void ) +{ + LL_C1_IPCC_SetFlag_CHx( IPCC, HW_IPCC_THREAD_CLI_CMD_CHANNEL ); + + return; +} + +void HW_IPCC_THREAD_SendAck( void ) +{ + LL_C1_IPCC_ClearFlag_CHx( IPCC, HW_IPCC_THREAD_NOTIFICATION_ACK_CHANNEL ); + LL_C1_IPCC_EnableReceiveChannel( IPCC, HW_IPCC_THREAD_NOTIFICATION_ACK_CHANNEL ); + + return; +} + +void HW_IPCC_THREAD_CliSendAck( void ) +{ + LL_C1_IPCC_ClearFlag_CHx( IPCC, HW_IPCC_THREAD_CLI_NOTIFICATION_ACK_CHANNEL ); + LL_C1_IPCC_EnableReceiveChannel( IPCC, HW_IPCC_THREAD_CLI_NOTIFICATION_ACK_CHANNEL ); + + return; +} + +static void HW_IPCC_OT_CmdEvtHandler( void ) +{ + LL_C1_IPCC_DisableTransmitChannel( IPCC, HW_IPCC_THREAD_OT_CMD_RSP_CHANNEL ); + + HW_IPCC_OT_CmdEvtNot(); + + return; +} + +static void HW_IPCC_THREAD_NotEvtHandler( void ) +{ + LL_C1_IPCC_DisableReceiveChannel( IPCC, HW_IPCC_THREAD_NOTIFICATION_ACK_CHANNEL ); + + HW_IPCC_THREAD_EvtNot(); + + return; +} + +static void HW_IPCC_THREAD_CliNotEvtHandler( void ) +{ + LL_C1_IPCC_DisableReceiveChannel( IPCC, HW_IPCC_THREAD_CLI_NOTIFICATION_ACK_CHANNEL ); + + HW_IPCC_THREAD_CliEvtNot(); + + return; +} + +__weak void HW_IPCC_OT_CmdEvtNot( void ){}; +__weak void HW_IPCC_CLI_CmdEvtNot( void ){}; +__weak void HW_IPCC_THREAD_EvtNot( void ){}; + +#endif /* THREAD_WB */ + +/****************************************************************************** + * LLD TESTS + ******************************************************************************/ +#ifdef LLD_TESTS_WB +void HW_IPCC_LLDTESTS_Init( void ) +{ + LL_C1_IPCC_EnableReceiveChannel( IPCC, HW_IPCC_LLDTESTS_CLI_RSP_CHANNEL ); + LL_C1_IPCC_EnableReceiveChannel( IPCC, HW_IPCC_LLDTESTS_M0_CMD_CHANNEL ); + return; +} + +void HW_IPCC_LLDTESTS_SendCliCmd( void ) +{ + LL_C1_IPCC_SetFlag_CHx( IPCC, HW_IPCC_LLDTESTS_CLI_CMD_CHANNEL ); + return; +} + +static void HW_IPCC_LLDTESTS_ReceiveCliRspHandler( void ) +{ + LL_C1_IPCC_DisableReceiveChannel( IPCC, HW_IPCC_LLDTESTS_CLI_RSP_CHANNEL ); + HW_IPCC_LLDTESTS_ReceiveCliRsp(); + return; +} + +void HW_IPCC_LLDTESTS_SendCliRspAck( void ) +{ + LL_C1_IPCC_ClearFlag_CHx( IPCC, HW_IPCC_LLDTESTS_CLI_RSP_CHANNEL ); + LL_C1_IPCC_EnableReceiveChannel( IPCC, HW_IPCC_LLDTESTS_CLI_RSP_CHANNEL ); + return; +} + +static void HW_IPCC_LLDTESTS_ReceiveM0CmdHandler( void ) +{ + LL_C1_IPCC_DisableReceiveChannel( IPCC, HW_IPCC_LLDTESTS_M0_CMD_CHANNEL ); + HW_IPCC_LLDTESTS_ReceiveM0Cmd(); + return; +} + +void HW_IPCC_LLDTESTS_SendM0CmdAck( void ) +{ + LL_C1_IPCC_ClearFlag_CHx( IPCC, HW_IPCC_LLDTESTS_M0_CMD_CHANNEL ); + LL_C1_IPCC_EnableReceiveChannel( IPCC, HW_IPCC_LLDTESTS_M0_CMD_CHANNEL ); + return; +} +__weak void HW_IPCC_LLDTESTS_ReceiveCliRsp( void ){}; +__weak void HW_IPCC_LLDTESTS_ReceiveM0Cmd( void ){}; +#endif /* LLD_TESTS_WB */ + +/****************************************************************************** + * LLD BLE + ******************************************************************************/ +#ifdef LLD_BLE_WB +void HW_IPCC_LLD_BLE_Init( void ) +{ + LL_C1_IPCC_EnableReceiveChannel( IPCC, HW_IPCC_LLD_BLE_RSP_CHANNEL ); + LL_C1_IPCC_EnableReceiveChannel( IPCC, HW_IPCC_LLD_BLE_M0_CMD_CHANNEL ); + return; +} + +void HW_IPCC_LLD_BLE_SendCliCmd( void ) +{ + LL_C1_IPCC_SetFlag_CHx( IPCC, HW_IPCC_LLD_BLE_CLI_CMD_CHANNEL ); + return; +} + +/*static void HW_IPCC_LLD_BLE_ReceiveCliRspHandler( void ) +{ + LL_C1_IPCC_DisableReceiveChannel( IPCC, HW_IPCC_LLD_BLE_CLI_RSP_CHANNEL ); + HW_IPCC_LLD_BLE_ReceiveCliRsp(); + return; +}*/ + +void HW_IPCC_LLD_BLE_SendCliRspAck( void ) +{ + LL_C1_IPCC_ClearFlag_CHx( IPCC, HW_IPCC_LLD_BLE_CLI_RSP_CHANNEL ); + LL_C1_IPCC_EnableReceiveChannel( IPCC, HW_IPCC_LLD_BLE_CLI_RSP_CHANNEL ); + return; +} + +static void HW_IPCC_LLD_BLE_ReceiveM0CmdHandler( void ) +{ + //LL_C1_IPCC_DisableReceiveChannel( IPCC, HW_IPCC_LLD_BLE_M0_CMD_CHANNEL ); + HW_IPCC_LLD_BLE_ReceiveM0Cmd(); + return; +} + +void HW_IPCC_LLD_BLE_SendM0CmdAck( void ) +{ + LL_C1_IPCC_ClearFlag_CHx( IPCC, HW_IPCC_LLD_BLE_M0_CMD_CHANNEL ); + //LL_C1_IPCC_EnableReceiveChannel( IPCC, HW_IPCC_LLD_BLE_M0_CMD_CHANNEL ); + return; +} +__weak void HW_IPCC_LLD_BLE_ReceiveCliRsp( void ){}; +__weak void HW_IPCC_LLD_BLE_ReceiveM0Cmd( void ){}; + +/* Transparent Mode */ +void HW_IPCC_LLD_BLE_SendCmd( void ) +{ + LL_C1_IPCC_SetFlag_CHx( IPCC, HW_IPCC_LLD_BLE_CMD_CHANNEL ); + return; +} + +static void HW_IPCC_LLD_BLE_ReceiveRspHandler( void ) +{ + LL_C1_IPCC_DisableReceiveChannel( IPCC, HW_IPCC_LLD_BLE_RSP_CHANNEL ); + HW_IPCC_LLD_BLE_ReceiveRsp(); + return; +} + +void HW_IPCC_LLD_BLE_SendRspAck( void ) +{ + LL_C1_IPCC_ClearFlag_CHx( IPCC, HW_IPCC_LLD_BLE_RSP_CHANNEL ); + LL_C1_IPCC_EnableReceiveChannel( IPCC, HW_IPCC_LLD_BLE_RSP_CHANNEL ); + return; +} + +#endif /* LLD_BLE_WB */ + +/****************************************************************************** + * ZIGBEE + ******************************************************************************/ +#ifdef ZIGBEE_WB +void HW_IPCC_ZIGBEE_Init( void ) +{ + LL_C1_IPCC_EnableReceiveChannel( IPCC, HW_IPCC_ZIGBEE_APPLI_NOTIF_ACK_CHANNEL ); + LL_C1_IPCC_EnableReceiveChannel( IPCC, HW_IPCC_ZIGBEE_M0_REQUEST_CHANNEL ); + + return; +} + +void HW_IPCC_ZIGBEE_SendM4RequestToM0( void ) +{ + LL_C1_IPCC_SetFlag_CHx( IPCC, HW_IPCC_ZIGBEE_CMD_APPLI_CHANNEL ); + LL_C1_IPCC_EnableTransmitChannel( IPCC, HW_IPCC_ZIGBEE_CMD_APPLI_CHANNEL ); + + return; +} + +void HW_IPCC_ZIGBEE_SendM4AckToM0Notify( void ) +{ + LL_C1_IPCC_ClearFlag_CHx( IPCC, HW_IPCC_ZIGBEE_APPLI_NOTIF_ACK_CHANNEL ); + LL_C1_IPCC_EnableReceiveChannel( IPCC, HW_IPCC_ZIGBEE_APPLI_NOTIF_ACK_CHANNEL ); + + return; +} + +static void HW_IPCC_ZIGBEE_CmdEvtHandler( void ) +{ + LL_C1_IPCC_DisableTransmitChannel( IPCC, HW_IPCC_ZIGBEE_CMD_APPLI_CHANNEL ); + + HW_IPCC_ZIGBEE_RecvAppliAckFromM0(); + + return; +} + +static void HW_IPCC_ZIGBEE_StackNotifEvtHandler( void ) +{ + LL_C1_IPCC_DisableReceiveChannel( IPCC, HW_IPCC_ZIGBEE_APPLI_NOTIF_ACK_CHANNEL ); + + HW_IPCC_ZIGBEE_RecvM0NotifyToM4(); + + return; +} + +static void HW_IPCC_ZIGBEE_StackM0RequestHandler( void ) +{ + LL_C1_IPCC_DisableReceiveChannel( IPCC, HW_IPCC_ZIGBEE_M0_REQUEST_CHANNEL ); + + HW_IPCC_ZIGBEE_RecvM0RequestToM4(); + + return; +} + +void HW_IPCC_ZIGBEE_SendM4AckToM0Request( void ) +{ + LL_C1_IPCC_ClearFlag_CHx( IPCC, HW_IPCC_ZIGBEE_M0_REQUEST_CHANNEL ); + LL_C1_IPCC_EnableReceiveChannel( IPCC, HW_IPCC_ZIGBEE_M0_REQUEST_CHANNEL ); + + return; +} + +__weak void HW_IPCC_ZIGBEE_RecvAppliAckFromM0( void ){}; +__weak void HW_IPCC_ZIGBEE_RecvM0NotifyToM4( void ){}; +__weak void HW_IPCC_ZIGBEE_RecvM0RequestToM4( void ){}; +#endif /* ZIGBEE_WB */ + +/****************************************************************************** + * MEMORY MANAGER + ******************************************************************************/ +void HW_IPCC_MM_SendFreeBuf( void (*cb)( void ) ) +{ + if ( LL_C1_IPCC_IsActiveFlag_CHx( IPCC, HW_IPCC_MM_RELEASE_BUFFER_CHANNEL ) ) + { + FreeBufCb = cb; + LL_C1_IPCC_EnableTransmitChannel( IPCC, HW_IPCC_MM_RELEASE_BUFFER_CHANNEL ); + } + else + { + cb(); + + LL_C1_IPCC_SetFlag_CHx( IPCC, HW_IPCC_MM_RELEASE_BUFFER_CHANNEL ); + } + + return; +} + +static void HW_IPCC_MM_FreeBufHandler( void ) +{ + LL_C1_IPCC_DisableTransmitChannel( IPCC, HW_IPCC_MM_RELEASE_BUFFER_CHANNEL ); + + FreeBufCb(); + + LL_C1_IPCC_SetFlag_CHx( IPCC, HW_IPCC_MM_RELEASE_BUFFER_CHANNEL ); + + return; +} + +/****************************************************************************** + * TRACES + ******************************************************************************/ +void HW_IPCC_TRACES_Init( void ) +{ + LL_C1_IPCC_EnableReceiveChannel( IPCC, HW_IPCC_TRACES_CHANNEL ); + + return; +} + +static void HW_IPCC_TRACES_EvtHandler( void ) +{ + HW_IPCC_TRACES_EvtNot(); + + LL_C1_IPCC_ClearFlag_CHx( IPCC, HW_IPCC_TRACES_CHANNEL ); + + return; +} + +__weak void HW_IPCC_TRACES_EvtNot( void ){}; + +/******************* (C) COPYRIGHT 2019 STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/ble-glue/hw_timerserver.c b/firmware/targets/f7/ble-glue/hw_timerserver.c new file mode 100644 index 00000000..e0e4fcb5 --- /dev/null +++ b/firmware/targets/f7/ble-glue/hw_timerserver.c @@ -0,0 +1,893 @@ +/** + ****************************************************************************** + * File Name : hw_timerserver.c + * Description : Hardware timerserver source file for STM32WPAN Middleware. + * + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2020 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "app_common.h" +#include "hw_conf.h" + +/* Private typedef -----------------------------------------------------------*/ +typedef enum +{ + TimerID_Free, + TimerID_Created, + TimerID_Running +}TimerIDStatus_t; + +typedef enum +{ + SSR_Read_Requested, + SSR_Read_Not_Requested +}RequestReadSSR_t; + +typedef enum +{ + WakeupTimerValue_Overpassed, + WakeupTimerValue_LargeEnough +}WakeupTimerLimitation_Status_t; + +typedef struct +{ + HW_TS_pTimerCb_t pTimerCallBack; + uint32_t CounterInit; + uint32_t CountLeft; + TimerIDStatus_t TimerIDStatus; + HW_TS_Mode_t TimerMode; + uint32_t TimerProcessID; + uint8_t PreviousID; + uint8_t NextID; +}TimerContext_t; + +/* Private defines -----------------------------------------------------------*/ +#define SSR_FORBIDDEN_VALUE 0xFFFFFFFF +#define TIMER_LIST_EMPTY 0xFFFF + +/* Private macros ------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ + +/** + * START of Section TIMERSERVER_CONTEXT + */ + +PLACE_IN_SECTION("TIMERSERVER_CONTEXT") static volatile TimerContext_t aTimerContext[CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER]; +PLACE_IN_SECTION("TIMERSERVER_CONTEXT") static volatile uint8_t CurrentRunningTimerID; +PLACE_IN_SECTION("TIMERSERVER_CONTEXT") static volatile uint8_t PreviousRunningTimerID; +PLACE_IN_SECTION("TIMERSERVER_CONTEXT") static volatile uint32_t SSRValueOnLastSetup; +PLACE_IN_SECTION("TIMERSERVER_CONTEXT") static volatile WakeupTimerLimitation_Status_t WakeupTimerLimitation; + +/** + * END of Section TIMERSERVER_CONTEXT + */ + +static RTC_HandleTypeDef *phrtc; /**< RTC handle */ +static uint8_t WakeupTimerDivider; +static uint8_t AsynchPrescalerUserConfig; +static uint16_t SynchPrescalerUserConfig; +static volatile uint16_t MaxWakeupTimerSetup; + +/* Global variables ----------------------------------------------------------*/ +/* Private function prototypes -----------------------------------------------*/ +static void RestartWakeupCounter(uint16_t Value); +static uint16_t ReturnTimeElapsed(void); +static void RescheduleTimerList(void); +static void UnlinkTimer(uint8_t TimerID, RequestReadSSR_t RequestReadSSR); +static void LinkTimerBefore(uint8_t TimerID, uint8_t RefTimerID); +static void LinkTimerAfter(uint8_t TimerID, uint8_t RefTimerID); +static uint16_t linkTimer(uint8_t TimerID); +static uint32_t ReadRtcSsrValue(void); + +__weak void HW_TS_RTC_CountUpdated_AppNot(void); + +/* Functions Definition ------------------------------------------------------*/ + +/** + * @brief Read the RTC_SSR value + * As described in the reference manual, the RTC_SSR shall be read twice to ensure + * reliability of the value + * @param None + * @retval SSR value read + */ +static uint32_t ReadRtcSsrValue(void) +{ + uint32_t first_read; + uint32_t second_read; + + first_read = (uint32_t)(READ_BIT(RTC->SSR, RTC_SSR_SS)); + + second_read = (uint32_t)(READ_BIT(RTC->SSR, RTC_SSR_SS)); + + while(first_read != second_read) + { + first_read = second_read; + + second_read = (uint32_t)(READ_BIT(RTC->SSR, RTC_SSR_SS)); + } + + return second_read; +} + +/** + * @brief Insert a Timer in the list after the Timer ID specified + * @param TimerID: The ID of the Timer + * @param RefTimerID: The ID of the Timer to be linked after + * @retval None + */ +static void LinkTimerAfter(uint8_t TimerID, uint8_t RefTimerID) +{ + uint8_t next_id; + + next_id = aTimerContext[RefTimerID].NextID; + + if(next_id != CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER) + { + aTimerContext[next_id].PreviousID = TimerID; + } + aTimerContext[TimerID].NextID = next_id; + aTimerContext[TimerID].PreviousID = RefTimerID ; + aTimerContext[RefTimerID].NextID = TimerID; + + return; +} + +/** + * @brief Insert a Timer in the list before the ID specified + * @param TimerID: The ID of the Timer + * @param RefTimerID: The ID of the Timer to be linked before + * @retval None + */ +static void LinkTimerBefore(uint8_t TimerID, uint8_t RefTimerID) +{ + uint8_t previous_id; + + if(RefTimerID != CurrentRunningTimerID) + { + previous_id = aTimerContext[RefTimerID].PreviousID; + + aTimerContext[previous_id].NextID = TimerID; + aTimerContext[TimerID].NextID = RefTimerID; + aTimerContext[TimerID].PreviousID = previous_id ; + aTimerContext[RefTimerID].PreviousID = TimerID; + } + else + { + aTimerContext[TimerID].NextID = RefTimerID; + aTimerContext[RefTimerID].PreviousID = TimerID; + } + + return; +} + +/** + * @brief Insert a Timer in the list + * @param TimerID: The ID of the Timer + * @retval None + */ +static uint16_t linkTimer(uint8_t TimerID) +{ + uint32_t time_left; + uint16_t time_elapsed; + uint8_t timer_id_lookup; + uint8_t next_id; + + if(CurrentRunningTimerID == CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER) + { + /** + * No timer in the list + */ + PreviousRunningTimerID = CurrentRunningTimerID; + CurrentRunningTimerID = TimerID; + aTimerContext[TimerID].NextID = CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER; + + SSRValueOnLastSetup = SSR_FORBIDDEN_VALUE; + time_elapsed = 0; + } + else + { + time_elapsed = ReturnTimeElapsed(); + + /** + * update count of the timer to be linked + */ + aTimerContext[TimerID].CountLeft += time_elapsed; + time_left = aTimerContext[TimerID].CountLeft; + + /** + * Search for index where the new timer shall be linked + */ + if(aTimerContext[CurrentRunningTimerID].CountLeft <= time_left) + { + /** + * Search for the ID after the first one + */ + timer_id_lookup = CurrentRunningTimerID; + next_id = aTimerContext[timer_id_lookup].NextID; + while((next_id != CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER) && (aTimerContext[next_id].CountLeft <= time_left)) + { + timer_id_lookup = aTimerContext[timer_id_lookup].NextID; + next_id = aTimerContext[timer_id_lookup].NextID; + } + + /** + * Link after the ID + */ + LinkTimerAfter(TimerID, timer_id_lookup); + } + else + { + /** + * Link before the first ID + */ + LinkTimerBefore(TimerID, CurrentRunningTimerID); + PreviousRunningTimerID = CurrentRunningTimerID; + CurrentRunningTimerID = TimerID; + } + } + + return time_elapsed; +} + +/** + * @brief Remove a Timer from the list + * @param TimerID: The ID of the Timer + * @param RequestReadSSR: Request to read the SSR register or not + * @retval None + */ +static void UnlinkTimer(uint8_t TimerID, RequestReadSSR_t RequestReadSSR) +{ + uint8_t previous_id; + uint8_t next_id; + + if(TimerID == CurrentRunningTimerID) + { + PreviousRunningTimerID = CurrentRunningTimerID; + CurrentRunningTimerID = aTimerContext[TimerID].NextID; + } + else + { + previous_id = aTimerContext[TimerID].PreviousID; + next_id = aTimerContext[TimerID].NextID; + + aTimerContext[previous_id].NextID = aTimerContext[TimerID].NextID; + if(next_id != CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER) + { + aTimerContext[next_id].PreviousID = aTimerContext[TimerID].PreviousID; + } + } + + /** + * Timer is out of the list + */ + aTimerContext[TimerID].TimerIDStatus = TimerID_Created; + + if((CurrentRunningTimerID == CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER) && (RequestReadSSR == SSR_Read_Requested)) + { + SSRValueOnLastSetup = SSR_FORBIDDEN_VALUE; + } + + return; +} + +/** + * @brief Return the number of ticks counted by the wakeuptimer since it has been started + * @note The API is reading the SSR register to get how many ticks have been counted + * since the time the timer has been started + * @param None + * @retval Time expired in Ticks + */ +static uint16_t ReturnTimeElapsed(void) +{ + uint32_t return_value; + uint32_t wrap_counter; + + if(SSRValueOnLastSetup != SSR_FORBIDDEN_VALUE) + { + return_value = ReadRtcSsrValue(); /**< Read SSR register first */ + + if (SSRValueOnLastSetup >= return_value) + { + return_value = SSRValueOnLastSetup - return_value; + } + else + { + wrap_counter = SynchPrescalerUserConfig - return_value; + return_value = SSRValueOnLastSetup + wrap_counter; + } + + /** + * At this stage, ReturnValue holds the number of ticks counted by SSR + * Need to translate in number of ticks counted by the Wakeuptimer + */ + return_value = return_value*AsynchPrescalerUserConfig; + return_value = return_value >> WakeupTimerDivider; + } + else + { + return_value = 0; + } + + return (uint16_t)return_value; +} + +/** + * @brief Set the wakeup counter + * @note The API is writing the counter value so that the value is decreased by one to cope with the fact + * the interrupt is generated with 1 extra clock cycle (See RefManuel) + * It assumes all condition are met to be allowed to write the wakeup counter + * @param Value: Value to be written in the counter + * @retval None + */ +static void RestartWakeupCounter(uint16_t Value) +{ + /** + * The wakeuptimer has been disabled in the calling function to reduce the time to poll the WUTWF + * FLAG when the new value will have to be written + * __HAL_RTC_WAKEUPTIMER_DISABLE(phrtc); + */ + + if(Value == 0) + { + SSRValueOnLastSetup = ReadRtcSsrValue(); + + /** + * Simulate that the Timer expired + */ + HAL_NVIC_SetPendingIRQ(CFG_HW_TS_RTC_WAKEUP_HANDLER_ID); + } + else + { + if((Value > 1) ||(WakeupTimerDivider != 1)) + { + Value -= 1; + } + + while(__HAL_RTC_WAKEUPTIMER_GET_FLAG(phrtc, RTC_FLAG_WUTWF) == RESET); + + /** + * make sure to clear the flags after checking the WUTWF. + * It takes 2 RTCCLK between the time the WUTE bit is disabled and the + * time the timer is disabled. The WUTWF bit somehow guarantee the system is stable + * Otherwise, when the timer is periodic with 1 Tick, it may generate an extra interrupt in between + * due to the autoreload feature + */ + __HAL_RTC_WAKEUPTIMER_CLEAR_FLAG(phrtc, RTC_FLAG_WUTF); /**< Clear flag in RTC module */ + __HAL_RTC_WAKEUPTIMER_EXTI_CLEAR_FLAG(); /**< Clear flag in EXTI module */ + HAL_NVIC_ClearPendingIRQ(CFG_HW_TS_RTC_WAKEUP_HANDLER_ID); /**< Clear pending bit in NVIC */ + + MODIFY_REG(RTC->WUTR, RTC_WUTR_WUT, Value); + + /** + * Update the value here after the WUTWF polling that may take some time + */ + SSRValueOnLastSetup = ReadRtcSsrValue(); + + __HAL_RTC_WAKEUPTIMER_ENABLE(phrtc); /**< Enable the Wakeup Timer */ + + HW_TS_RTC_CountUpdated_AppNot(); + } + + return ; +} + +/** + * @brief Reschedule the list of timer + * @note 1) Update the count left for each timer in the list + * 2) Setup the wakeuptimer + * @param None + * @retval None + */ +static void RescheduleTimerList(void) +{ + uint8_t localTimerID; + uint32_t timecountleft; + uint16_t wakeup_timer_value; + uint16_t time_elapsed; + + /** + * The wakeuptimer is disabled now to reduce the time to poll the WUTWF + * FLAG when the new value will have to be written + */ + if((READ_BIT(RTC->CR, RTC_CR_WUTE) == (RTC_CR_WUTE)) == SET) + { + /** + * Wait for the flag to be back to 0 when the wakeup timer is enabled + */ + while(__HAL_RTC_WAKEUPTIMER_GET_FLAG(phrtc, RTC_FLAG_WUTWF) == SET); + } + __HAL_RTC_WAKEUPTIMER_DISABLE(phrtc); /**< Disable the Wakeup Timer */ + + localTimerID = CurrentRunningTimerID; + + /** + * Calculate what will be the value to write in the wakeuptimer + */ + timecountleft = aTimerContext[localTimerID].CountLeft; + + /** + * Read how much has been counted + */ + time_elapsed = ReturnTimeElapsed(); + + if(timecountleft < time_elapsed ) + { + /** + * There is no tick left to count + */ + wakeup_timer_value = 0; + WakeupTimerLimitation = WakeupTimerValue_LargeEnough; + } + else + { + if(timecountleft > (time_elapsed + MaxWakeupTimerSetup)) + { + /** + * The number of tick left is greater than the Wakeuptimer maximum value + */ + wakeup_timer_value = MaxWakeupTimerSetup; + + WakeupTimerLimitation = WakeupTimerValue_Overpassed; + } + else + { + wakeup_timer_value = timecountleft - time_elapsed; + WakeupTimerLimitation = WakeupTimerValue_LargeEnough; + } + + } + + /** + * update ticks left to be counted for each timer + */ + while(localTimerID != CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER) + { + if (aTimerContext[localTimerID].CountLeft < time_elapsed) + { + aTimerContext[localTimerID].CountLeft = 0; + } + else + { + aTimerContext[localTimerID].CountLeft -= time_elapsed; + } + localTimerID = aTimerContext[localTimerID].NextID; + } + + /** + * Write next count + */ + RestartWakeupCounter(wakeup_timer_value); + + return ; +} + +/* Public functions ----------------------------------------------------------*/ + +/** + * For all public interface except that may need write access to the RTC, the RTC + * shall be unlock at the beginning and locked at the output + * In order to ease maintainability, the unlock is done at the top and the lock at then end + * in case some new implementation is coming in the future + */ + +void HW_TS_RTC_Wakeup_Handler(void) +{ + HW_TS_pTimerCb_t ptimer_callback; + uint32_t timer_process_id; + uint8_t local_current_running_timer_id; +#if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1) + uint32_t primask_bit; +#endif + +#if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1) + primask_bit = __get_PRIMASK(); /**< backup PRIMASK bit */ + __disable_irq(); /**< Disable all interrupts by setting PRIMASK bit on Cortex*/ +#endif + +/* Disable the write protection for RTC registers */ + __HAL_RTC_WRITEPROTECTION_DISABLE( phrtc ); + + /** + * Disable the Wakeup Timer + * This may speed up a bit the processing to wait the timer to be disabled + * The timer is still counting 2 RTCCLK + */ + __HAL_RTC_WAKEUPTIMER_DISABLE(phrtc); + + local_current_running_timer_id = CurrentRunningTimerID; + + if(aTimerContext[local_current_running_timer_id].TimerIDStatus == TimerID_Running) + { + ptimer_callback = aTimerContext[local_current_running_timer_id].pTimerCallBack; + timer_process_id = aTimerContext[local_current_running_timer_id].TimerProcessID; + + /** + * It should be good to check whether the TimeElapsed is greater or not than the tick left to be counted + * However, due to the inaccuracy of the reading of the time elapsed, it may return there is 1 tick + * to be left whereas the count is over + * A more secure implementation has been done with a flag to state whereas the full count has been written + * in the wakeuptimer or not + */ + if(WakeupTimerLimitation != WakeupTimerValue_Overpassed) + { + if(aTimerContext[local_current_running_timer_id].TimerMode == hw_ts_Repeated) + { + UnlinkTimer(local_current_running_timer_id, SSR_Read_Not_Requested); +#if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1) + __set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/ +#endif + HW_TS_Start(local_current_running_timer_id, aTimerContext[local_current_running_timer_id].CounterInit); + + /* Disable the write protection for RTC registers */ + __HAL_RTC_WRITEPROTECTION_DISABLE( phrtc ); + } + else + { +#if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1) + __set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/ +#endif + HW_TS_Stop(local_current_running_timer_id); + + /* Disable the write protection for RTC registers */ + __HAL_RTC_WRITEPROTECTION_DISABLE( phrtc ); + } + + HW_TS_RTC_Int_AppNot(timer_process_id, local_current_running_timer_id, ptimer_callback); + } + else + { + RescheduleTimerList(); +#if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1) + __set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/ +#endif + } + } + else + { + /** + * We should never end up in this case + * However, if due to any bug in the timer server this is the case, the mistake may not impact the user. + * We could just clean the interrupt flag and get out from this unexpected interrupt + */ + while(__HAL_RTC_WAKEUPTIMER_GET_FLAG(phrtc, RTC_FLAG_WUTWF) == RESET); + + /** + * make sure to clear the flags after checking the WUTWF. + * It takes 2 RTCCLK between the time the WUTE bit is disabled and the + * time the timer is disabled. The WUTWF bit somehow guarantee the system is stable + * Otherwise, when the timer is periodic with 1 Tick, it may generate an extra interrupt in between + * due to the autoreload feature + */ + __HAL_RTC_WAKEUPTIMER_CLEAR_FLAG(phrtc, RTC_FLAG_WUTF); /**< Clear flag in RTC module */ + __HAL_RTC_WAKEUPTIMER_EXTI_CLEAR_FLAG(); /**< Clear flag in EXTI module */ + +#if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1) + __set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/ +#endif + } + + /* Enable the write protection for RTC registers */ + __HAL_RTC_WRITEPROTECTION_ENABLE( phrtc ); + + return; +} + +void HW_TS_Init(HW_TS_InitMode_t TimerInitMode, RTC_HandleTypeDef *hrtc) +{ + uint8_t loop; + uint32_t localmaxwakeuptimersetup; + + /** + * Get RTC handler + */ + phrtc = hrtc; + + /* Disable the write protection for RTC registers */ + __HAL_RTC_WRITEPROTECTION_DISABLE( phrtc ); + + SET_BIT(RTC->CR, RTC_CR_BYPSHAD); + + /** + * Readout the user config + */ + WakeupTimerDivider = (4 - ((uint32_t)(READ_BIT(RTC->CR, RTC_CR_WUCKSEL)))); + + AsynchPrescalerUserConfig = (uint8_t)(READ_BIT(RTC->PRER, RTC_PRER_PREDIV_A) >> (uint32_t)POSITION_VAL(RTC_PRER_PREDIV_A)) + 1; + + SynchPrescalerUserConfig = (uint16_t)(READ_BIT(RTC->PRER, RTC_PRER_PREDIV_S)) + 1; + + /** + * Margin is taken to avoid wrong calculation when the wrap around is there and some + * application interrupts may have delayed the reading + */ + localmaxwakeuptimersetup = ((((SynchPrescalerUserConfig - 1)*AsynchPrescalerUserConfig) - CFG_HW_TS_RTC_HANDLER_MAX_DELAY) >> WakeupTimerDivider); + + if(localmaxwakeuptimersetup >= 0xFFFF) + { + MaxWakeupTimerSetup = 0xFFFF; + } + else + { + MaxWakeupTimerSetup = (uint16_t)localmaxwakeuptimersetup; + } + + /** + * Configure EXTI module + */ + LL_EXTI_EnableRisingTrig_0_31(RTC_EXTI_LINE_WAKEUPTIMER_EVENT); + LL_EXTI_EnableIT_0_31(RTC_EXTI_LINE_WAKEUPTIMER_EVENT); + + if(TimerInitMode == hw_ts_InitMode_Full) + { + WakeupTimerLimitation = WakeupTimerValue_LargeEnough; + SSRValueOnLastSetup = SSR_FORBIDDEN_VALUE; + + /** + * Initialize the timer server + */ + for(loop = 0; loop < CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER; loop++) + { + aTimerContext[loop].TimerIDStatus = TimerID_Free; + } + + CurrentRunningTimerID = CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER; /**< Set ID to non valid value */ + + __HAL_RTC_WAKEUPTIMER_DISABLE(phrtc); /**< Disable the Wakeup Timer */ + __HAL_RTC_WAKEUPTIMER_CLEAR_FLAG(phrtc, RTC_FLAG_WUTF); /**< Clear flag in RTC module */ + __HAL_RTC_WAKEUPTIMER_EXTI_CLEAR_FLAG(); /**< Clear flag in EXTI module */ + HAL_NVIC_ClearPendingIRQ(CFG_HW_TS_RTC_WAKEUP_HANDLER_ID); /**< Clear pending bit in NVIC */ + __HAL_RTC_WAKEUPTIMER_ENABLE_IT(phrtc, RTC_IT_WUT); /**< Enable interrupt in RTC module */ + } + else + { + if(__HAL_RTC_WAKEUPTIMER_GET_FLAG(phrtc, RTC_FLAG_WUTF) != RESET) + { + /** + * Simulate that the Timer expired + */ + HAL_NVIC_SetPendingIRQ(CFG_HW_TS_RTC_WAKEUP_HANDLER_ID); + } + } + + /* Enable the write protection for RTC registers */ + __HAL_RTC_WRITEPROTECTION_ENABLE( phrtc ); + + HAL_NVIC_SetPriority(CFG_HW_TS_RTC_WAKEUP_HANDLER_ID, CFG_HW_TS_NVIC_RTC_WAKEUP_IT_PREEMPTPRIO, CFG_HW_TS_NVIC_RTC_WAKEUP_IT_SUBPRIO); /**< Set NVIC priority */ + HAL_NVIC_EnableIRQ(CFG_HW_TS_RTC_WAKEUP_HANDLER_ID); /**< Enable NVIC */ + + return; +} + +HW_TS_ReturnStatus_t HW_TS_Create(uint32_t TimerProcessID, uint8_t *pTimerId, HW_TS_Mode_t TimerMode, HW_TS_pTimerCb_t pftimeout_handler) +{ + HW_TS_ReturnStatus_t localreturnstatus; + uint8_t loop = 0; +#if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1) + uint32_t primask_bit; +#endif + +#if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1) + primask_bit = __get_PRIMASK(); /**< backup PRIMASK bit */ + __disable_irq(); /**< Disable all interrupts by setting PRIMASK bit on Cortex*/ +#endif + + while((loop < CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER) && (aTimerContext[loop].TimerIDStatus != TimerID_Free)) + { + loop++; + } + + if(loop != CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER) + { + aTimerContext[loop].TimerIDStatus = TimerID_Created; + +#if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1) + __set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/ +#endif + + aTimerContext[loop].TimerProcessID = TimerProcessID; + aTimerContext[loop].TimerMode = TimerMode; + aTimerContext[loop].pTimerCallBack = pftimeout_handler; + *pTimerId = loop; + + localreturnstatus = hw_ts_Successful; + } + else + { +#if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1) + __set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/ +#endif + + localreturnstatus = hw_ts_Failed; + } + + return(localreturnstatus); +} + +void HW_TS_Delete(uint8_t timer_id) +{ + HW_TS_Stop(timer_id); + + aTimerContext[timer_id].TimerIDStatus = TimerID_Free; /**< release ID */ + + return; +} + +void HW_TS_Stop(uint8_t timer_id) +{ + uint8_t localcurrentrunningtimerid; + +#if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1) + uint32_t primask_bit; +#endif + +#if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1) + primask_bit = __get_PRIMASK(); /**< backup PRIMASK bit */ + __disable_irq(); /**< Disable all interrupts by setting PRIMASK bit on Cortex*/ +#endif + + HAL_NVIC_DisableIRQ(CFG_HW_TS_RTC_WAKEUP_HANDLER_ID); /**< Disable NVIC */ + + /* Disable the write protection for RTC registers */ + __HAL_RTC_WRITEPROTECTION_DISABLE( phrtc ); + + if(aTimerContext[timer_id].TimerIDStatus == TimerID_Running) + { + UnlinkTimer(timer_id, SSR_Read_Requested); + localcurrentrunningtimerid = CurrentRunningTimerID; + + if(localcurrentrunningtimerid == CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER) + { + /** + * List is empty + */ + + /** + * Disable the timer + */ + if((READ_BIT(RTC->CR, RTC_CR_WUTE) == (RTC_CR_WUTE)) == SET) + { + /** + * Wait for the flag to be back to 0 when the wakeup timer is enabled + */ + while(__HAL_RTC_WAKEUPTIMER_GET_FLAG(phrtc, RTC_FLAG_WUTWF) == SET); + } + __HAL_RTC_WAKEUPTIMER_DISABLE(phrtc); /**< Disable the Wakeup Timer */ + + while(__HAL_RTC_WAKEUPTIMER_GET_FLAG(phrtc, RTC_FLAG_WUTWF) == RESET); + + /** + * make sure to clear the flags after checking the WUTWF. + * It takes 2 RTCCLK between the time the WUTE bit is disabled and the + * time the timer is disabled. The WUTWF bit somehow guarantee the system is stable + * Otherwise, when the timer is periodic with 1 Tick, it may generate an extra interrupt in between + * due to the autoreload feature + */ + __HAL_RTC_WAKEUPTIMER_CLEAR_FLAG(phrtc, RTC_FLAG_WUTF); /**< Clear flag in RTC module */ + __HAL_RTC_WAKEUPTIMER_EXTI_CLEAR_FLAG(); /**< Clear flag in EXTI module */ + HAL_NVIC_ClearPendingIRQ(CFG_HW_TS_RTC_WAKEUP_HANDLER_ID); /**< Clear pending bit in NVIC */ + } + else if(PreviousRunningTimerID != localcurrentrunningtimerid) + { + RescheduleTimerList(); + } + } + + /* Enable the write protection for RTC registers */ + __HAL_RTC_WRITEPROTECTION_ENABLE( phrtc ); + + HAL_NVIC_EnableIRQ(CFG_HW_TS_RTC_WAKEUP_HANDLER_ID); /**< Enable NVIC */ + +#if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1) + __set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/ +#endif + + return; +} + +void HW_TS_Start(uint8_t timer_id, uint32_t timeout_ticks) +{ + uint16_t time_elapsed; + uint8_t localcurrentrunningtimerid; + +#if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1) + uint32_t primask_bit; +#endif + + if(aTimerContext[timer_id].TimerIDStatus == TimerID_Running) + { + HW_TS_Stop( timer_id ); + } + +#if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1) + primask_bit = __get_PRIMASK(); /**< backup PRIMASK bit */ + __disable_irq(); /**< Disable all interrupts by setting PRIMASK bit on Cortex*/ +#endif + + HAL_NVIC_DisableIRQ(CFG_HW_TS_RTC_WAKEUP_HANDLER_ID); /**< Disable NVIC */ + + /* Disable the write protection for RTC registers */ + __HAL_RTC_WRITEPROTECTION_DISABLE( phrtc ); + + aTimerContext[timer_id].TimerIDStatus = TimerID_Running; + + aTimerContext[timer_id].CountLeft = timeout_ticks; + aTimerContext[timer_id].CounterInit = timeout_ticks; + + time_elapsed = linkTimer(timer_id); + + localcurrentrunningtimerid = CurrentRunningTimerID; + + if(PreviousRunningTimerID != localcurrentrunningtimerid) + { + RescheduleTimerList(); + } + else + { + aTimerContext[timer_id].CountLeft -= time_elapsed; + } + + /* Enable the write protection for RTC registers */ + __HAL_RTC_WRITEPROTECTION_ENABLE( phrtc ); + + HAL_NVIC_EnableIRQ(CFG_HW_TS_RTC_WAKEUP_HANDLER_ID); /**< Enable NVIC */ + +#if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1) + __set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/ +#endif + + return; +} + +uint16_t HW_TS_RTC_ReadLeftTicksToCount(void) +{ + uint32_t primask_bit; + uint16_t return_value, auro_reload_value, elapsed_time_value; + + primask_bit = __get_PRIMASK(); /**< backup PRIMASK bit */ + __disable_irq(); /**< Disable all interrupts by setting PRIMASK bit on Cortex*/ + + if((READ_BIT(RTC->CR, RTC_CR_WUTE) == (RTC_CR_WUTE)) == SET) + { + auro_reload_value = (uint32_t)(READ_BIT(RTC->WUTR, RTC_WUTR_WUT)); + + elapsed_time_value = ReturnTimeElapsed(); + + if(auro_reload_value > elapsed_time_value) + { + return_value = auro_reload_value - elapsed_time_value; + } + else + { + return_value = 0; + } + } + else + { + return_value = TIMER_LIST_EMPTY; + } + + __set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/ + + return (return_value); +} + +__weak void HW_TS_RTC_Int_AppNot(uint32_t TimerProcessID, uint8_t TimerID, HW_TS_pTimerCb_t pTimerCallBack) +{ + pTimerCallBack(); + + return; +} + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/ble-glue/serial_service.c b/firmware/targets/f7/ble-glue/serial_service.c new file mode 100644 index 00000000..4b0ad402 --- /dev/null +++ b/firmware/targets/f7/ble-glue/serial_service.c @@ -0,0 +1,102 @@ +#include "serial_service.h" +#include "app_common.h" +#include "ble.h" + +#include + +#define SERIAL_SERVICE_TAG "serial service" + +typedef struct { + uint16_t svc_handle; + uint16_t rx_char_handle; + uint16_t tx_char_handle; +} SerialSvc; + +static SerialSvc serial_svc; + +static SVCCTL_EvtAckStatus_t serial_svc_event_handler(void *event) { + SVCCTL_EvtAckStatus_t ret = SVCCTL_EvtNotAck; + hci_event_pckt* event_pckt = (hci_event_pckt *)(((hci_uart_pckt*)event)->data); + evt_blecore_aci* blecore_evt = (evt_blecore_aci*)event_pckt->data; + aci_gatt_attribute_modified_event_rp0* attribute_modified; + if(event_pckt->evt == HCI_VENDOR_SPECIFIC_DEBUG_EVT_CODE) { + if(blecore_evt->ecode == ACI_GATT_ATTRIBUTE_MODIFIED_VSEVT_CODE) { + attribute_modified = (aci_gatt_attribute_modified_event_rp0*)blecore_evt->data; + if(attribute_modified->Attr_Handle == serial_svc.tx_char_handle + 2) { + // Descriptor handle + ret = SVCCTL_EvtAckFlowEnable; + FURI_LOG_D(SERIAL_SERVICE_TAG, "TX descriptor event"); + } else if(attribute_modified->Attr_Handle == serial_svc.tx_char_handle + 1) { + FURI_LOG_I(SERIAL_SERVICE_TAG, "Data len: %d", attribute_modified->Attr_Data_Length); + for(uint8_t i = 0; i < attribute_modified->Attr_Data_Length; i++) { + printf("%02X ", attribute_modified->Attr_Data[i]); + } + printf("\r\n"); + serial_svc_update_rx(attribute_modified->Attr_Data, attribute_modified->Attr_Data_Length); + ret = SVCCTL_EvtAckFlowEnable; + } + } else if(blecore_evt->ecode == ACI_GATT_SERVER_CONFIRMATION_VSEVT_CODE) { + FURI_LOG_I(SERIAL_SERVICE_TAG, "Ack received", blecore_evt->ecode); + ret = SVCCTL_EvtAckFlowEnable; + } + } + return ret; +} + +bool serial_svc_init() { + tBleStatus status; + const uint8_t service_uuid[] = {SERIAL_SVC_UUID_128}; + const uint8_t char_rx_uuid[] = {SERIAL_CHAR_RX_UUID_128}; + const uint8_t char_tx_uuid[] = {SERIAL_CHAR_TX_UUID_128}; + + // Register event handler + SVCCTL_RegisterSvcHandler(serial_svc_event_handler); + + // Add service + status = aci_gatt_add_service(UUID_TYPE_128, (Service_UUID_t *)service_uuid, PRIMARY_SERVICE, 6, &serial_svc.svc_handle); + if(status) { + FURI_LOG_E(SERIAL_SERVICE_TAG, "Failed to add Serial service: %d", status); + } + + // Add TX characteristics + status = aci_gatt_add_char(serial_svc.svc_handle, UUID_TYPE_128, (const Char_UUID_t*)char_tx_uuid , + SERIAL_SVC_DATA_LEN_MAX, + CHAR_PROP_WRITE_WITHOUT_RESP | CHAR_PROP_WRITE | CHAR_PROP_READ, + ATTR_PERMISSION_NONE, + GATT_NOTIFY_ATTRIBUTE_WRITE, + 10, + CHAR_VALUE_LEN_VARIABLE, + &serial_svc.tx_char_handle); + if(status) { + FURI_LOG_E(SERIAL_SERVICE_TAG, "Failed to add TX characteristic: %d", status); + } + + // Add RX characteristic + status = aci_gatt_add_char(serial_svc.svc_handle, UUID_TYPE_128, (const Char_UUID_t*)char_rx_uuid , + SERIAL_SVC_DATA_LEN_MAX, + CHAR_PROP_READ | CHAR_PROP_INDICATE, + ATTR_PERMISSION_NONE, + GATT_DONT_NOTIFY_EVENTS, + 10, + CHAR_VALUE_LEN_VARIABLE, + &serial_svc.rx_char_handle); + if(status) { + FURI_LOG_E(SERIAL_SERVICE_TAG, "Failed to add RX characteristic: %d", status); + } + + return status != BLE_STATUS_SUCCESS; +} + +bool serial_svc_update_rx(uint8_t* data, uint8_t data_len) { + furi_assert(data_len < SERIAL_SVC_DATA_LEN_MAX); + + tBleStatus result = aci_gatt_update_char_value(serial_svc.svc_handle, + serial_svc.rx_char_handle, + 0, + data_len, + data); + if(result) { + FURI_LOG_E(SERIAL_SERVICE_TAG, "Failed updating RX characteristic: %d", result); + } + return result != BLE_STATUS_SUCCESS; +} diff --git a/firmware/targets/f7/ble-glue/serial_service.h b/firmware/targets/f7/ble-glue/serial_service.h new file mode 100644 index 00000000..92b943a0 --- /dev/null +++ b/firmware/targets/f7/ble-glue/serial_service.h @@ -0,0 +1,22 @@ +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define SERIAL_SVC_DATA_LEN_MAX 255 + +#define SERIAL_SVC_UUID_128 0x00, 0x00, 0xfe, 0x60, 0xcc, 0x7a, 0x48, 0x2a, 0x98, 0x4a, 0x7f, 0x2e, 0xd5, 0xb3, 0xe5, 0x8f +#define SERIAL_CHAR_RX_UUID_128 0x00, 0x00, 0xfe, 0x61, 0x8e, 0x22, 0x45, 0x41, 0x9d, 0x4c, 0x21, 0xed, 0xae, 0x82, 0xed, 0x19 +#define SERIAL_CHAR_TX_UUID_128 0x00, 0x00, 0xfe, 0x62, 0x8e, 0x22, 0x45, 0x41, 0x9d, 0x4c, 0x21, 0xed, 0xae, 0x82, 0xed, 0x19 + +bool serial_svc_init(); + +bool serial_svc_update_rx(uint8_t* data, uint8_t data_len); + +#ifdef __cplusplus +} +#endif diff --git a/firmware/targets/f7/ble-glue/tl_dbg_conf.h b/firmware/targets/f7/ble-glue/tl_dbg_conf.h new file mode 100644 index 00000000..4c38cfb5 --- /dev/null +++ b/firmware/targets/f7/ble-glue/tl_dbg_conf.h @@ -0,0 +1,136 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * File Name : App/tl_dbg_conf.h + * Description : Debug configuration file for stm32wpan transport layer interface. + * + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2020 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __TL_DBG_CONF_H +#define __TL_DBG_CONF_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* USER CODE BEGIN Tl_Conf */ + +/* Includes ------------------------------------------------------------------*/ +#include "app_conf.h" /* required as some configuration used in dbg_trace.h are set there */ +#include "dbg_trace.h" +#include "hw_if.h" + +/** + * Enable or Disable traces + * The raw data output is the hci binary packet format as specified by the BT specification * + */ +#define TL_SHCI_CMD_DBG_EN 0 /* Reports System commands sent to CPU2 and the command response */ +#define TL_SHCI_CMD_DBG_RAW_EN 0 /* Reports raw data System commands sent to CPU2 and the command response */ +#define TL_SHCI_EVT_DBG_EN 0 /* Reports System Asynchronous Events received from CPU2 */ +#define TL_SHCI_EVT_DBG_RAW_EN 0 /* Reports raw data System Asynchronous Events received from CPU2 */ + +#define TL_HCI_CMD_DBG_EN 0 /* Reports BLE command sent to CPU2 and the command response */ +#define TL_HCI_CMD_DBG_RAW_EN 0 /* Reports raw data BLE command sent to CPU2 and the command response */ +#define TL_HCI_EVT_DBG_EN 0 /* Reports BLE Asynchronous Events received from CPU2 */ +#define TL_HCI_EVT_DBG_RAW_EN 0 /* Reports raw data BLE Asynchronous Events received from CPU2 */ + +#define TL_MM_DBG_EN 0 /* Reports the informations of the buffer released to CPU2 */ + +/** + * Macro definition + */ + +/** + * System Transport Layer + */ +#if (TL_SHCI_CMD_DBG_EN != 0) +#define TL_SHCI_CMD_DBG_MSG PRINT_MESG_DBG +#define TL_SHCI_CMD_DBG_BUF PRINT_LOG_BUFF_DBG +#else +#define TL_SHCI_CMD_DBG_MSG(...) +#define TL_SHCI_CMD_DBG_BUF(...) +#endif + +#if (TL_SHCI_CMD_DBG_RAW_EN != 0) +#define TL_SHCI_CMD_DBG_RAW(_PDATA_, _SIZE_) furi_hal_console_tx(_PDATA_, _SIZE_) +#else +#define TL_SHCI_CMD_DBG_RAW(...) +#endif + +#if (TL_SHCI_EVT_DBG_EN != 0) +#define TL_SHCI_EVT_DBG_MSG PRINT_MESG_DBG +#define TL_SHCI_EVT_DBG_BUF PRINT_LOG_BUFF_DBG +#else +#define TL_SHCI_EVT_DBG_MSG(...) +#define TL_SHCI_EVT_DBG_BUF(...) +#endif + +#if (TL_SHCI_EVT_DBG_RAW_EN != 0) +#define TL_SHCI_EVT_DBG_RAW(_PDATA_, _SIZE_) furi_hal_console_tx(_PDATA_, _SIZE_) +#else +#define TL_SHCI_EVT_DBG_RAW(...) +#endif + +/** + * BLE Transport Layer + */ +#if (TL_HCI_CMD_DBG_EN != 0) +#define TL_HCI_CMD_DBG_MSG PRINT_MESG_DBG +#define TL_HCI_CMD_DBG_BUF PRINT_LOG_BUFF_DBG +#else +#define TL_HCI_CMD_DBG_MSG(...) +#define TL_HCI_CMD_DBG_BUF(...) +#endif + +#if (TL_HCI_CMD_DBG_RAW_EN != 0) +#define TL_HCI_CMD_DBG_RAW(_PDATA_, _SIZE_) furi_hal_console_tx(_PDATA_, _SIZE_) +#else +#define TL_HCI_CMD_DBG_RAW(...) +#endif + +#if (TL_HCI_EVT_DBG_EN != 0) +#define TL_HCI_EVT_DBG_MSG PRINT_MESG_DBG +#define TL_HCI_EVT_DBG_BUF PRINT_LOG_BUFF_DBG +#else +#define TL_HCI_EVT_DBG_MSG(...) +#define TL_HCI_EVT_DBG_BUF(...) +#endif + +#if (TL_HCI_EVT_DBG_RAW_EN != 0) +#define TL_HCI_EVT_DBG_RAW(_PDATA_, _SIZE_) furi_hal_console_tx(_PDATA_, _SIZE_) +#else +#define TL_HCI_EVT_DBG_RAW(...) +#endif + +/** + * Memory Manager - Released buffer tracing + */ +#if (TL_MM_DBG_EN != 0) +#define TL_MM_DBG_MSG PRINT_MESG_DBG +#else +#define TL_MM_DBG_MSG(...) +#endif + +/* USER CODE END Tl_Conf */ + +#ifdef __cplusplus +} +#endif + +#endif /*__TL_DBG_CONF_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/ble-glue/utilities_conf.h b/firmware/targets/f7/ble-glue/utilities_conf.h new file mode 100644 index 00000000..92a5d07a --- /dev/null +++ b/firmware/targets/f7/ble-glue/utilities_conf.h @@ -0,0 +1,68 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * File Name : utilities_conf.h + * Description : Configuration file for STM32 Utilities. + * + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2019 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef UTILITIES_CONF_H +#define UTILITIES_CONF_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "cmsis_compiler.h" +#include "string.h" + +/****************************************************************************** + * common + ******************************************************************************/ +#define UTILS_ENTER_CRITICAL_SECTION( ) uint32_t primask_bit = __get_PRIMASK( );\ + __disable_irq( ) + +#define UTILS_EXIT_CRITICAL_SECTION( ) __set_PRIMASK( primask_bit ) + +#define UTILS_MEMSET8( dest, value, size ) memset( dest, value, size); + +/****************************************************************************** + * tiny low power manager + * (any macro that does not need to be modified can be removed) + ******************************************************************************/ +#define UTIL_LPM_INIT_CRITICAL_SECTION( ) +#define UTIL_LPM_ENTER_CRITICAL_SECTION( ) UTILS_ENTER_CRITICAL_SECTION( ) +#define UTIL_LPM_EXIT_CRITICAL_SECTION( ) UTILS_EXIT_CRITICAL_SECTION( ) + +/****************************************************************************** + * sequencer + * (any macro that does not need to be modified can be removed) + ******************************************************************************/ +#define UTIL_SEQ_INIT_CRITICAL_SECTION( ) +#define UTIL_SEQ_ENTER_CRITICAL_SECTION( ) UTILS_ENTER_CRITICAL_SECTION( ) +#define UTIL_SEQ_EXIT_CRITICAL_SECTION( ) UTILS_EXIT_CRITICAL_SECTION( ) +#define UTIL_SEQ_CONF_TASK_NBR (32) +#define UTIL_SEQ_CONF_PRIO_NBR (2) +#define UTIL_SEQ_MEMSET8( dest, value, size ) UTILS_MEMSET8( dest, value, size ) + +#ifdef __cplusplus +} +#endif + +#endif /*UTILITIES_CONF_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/cube/Inc/FreeRTOSConfig.h b/firmware/targets/f7/cube/Inc/FreeRTOSConfig.h new file mode 100644 index 00000000..258ab421 --- /dev/null +++ b/firmware/targets/f7/cube/Inc/FreeRTOSConfig.h @@ -0,0 +1,186 @@ +/* USER CODE BEGIN Header */ +/* + * FreeRTOS Kernel V10.3.1 + * Portion Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Portion Copyright (C) 2019 StMicroelectronics, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ +/* USER CODE END Header */ + +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +/*----------------------------------------------------------- + * Application specific definitions. + * + * These definitions should be adjusted for your particular hardware and + * application requirements. + * + * These parameters and more are described within the 'configuration' section of the + * FreeRTOS API documentation available on the FreeRTOS.org web site. + * + * See http://www.freertos.org/a00110.html + *----------------------------------------------------------*/ + +/* USER CODE BEGIN Includes */ +/* Section where include file can be added */ +/* USER CODE END Includes */ + +/* Ensure definitions are only used by the compiler, and not by the assembler. */ +#if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__) + #include + extern uint32_t SystemCoreClock; + void xPortSysTickHandler(void); +/* USER CODE BEGIN 0 */ + extern void configureTimerForRunTimeStats(void); + extern unsigned long getRunTimeCounterValue(void); +/* USER CODE END 0 */ +#endif +#ifndef CMSIS_device_header +#define CMSIS_device_header "stm32wbxx.h" +#endif /* CMSIS_device_header */ + +#define configENABLE_FPU 1 +#define configENABLE_MPU 0 + +#define configUSE_PREEMPTION 1 +#define configSUPPORT_STATIC_ALLOCATION 1 +#define configSUPPORT_DYNAMIC_ALLOCATION 1 +#define configUSE_IDLE_HOOK 1 +#define configUSE_TICK_HOOK 0 +#define configCPU_CLOCK_HZ ( SystemCoreClock ) +#define configTICK_RATE_HZ ((TickType_t)1000) +#define configMAX_PRIORITIES ( 56 ) +#define configMINIMAL_STACK_SIZE ((uint16_t)128) +#define configTOTAL_HEAP_SIZE ((size_t)40960) +#define configMAX_TASK_NAME_LEN ( 16 ) +#define configGENERATE_RUN_TIME_STATS 1 +#define configUSE_TRACE_FACILITY 1 +#define configUSE_16_BIT_TICKS 0 +#define configUSE_MUTEXES 1 +#define configQUEUE_REGISTRY_SIZE 8 +#define configCHECK_FOR_STACK_OVERFLOW 1 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configENABLE_BACKWARD_COMPATIBILITY 0 +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 +#define configUSE_TICKLESS_IDLE 2 +#define configRECORD_STACK_HIGH_ADDRESS 1 +/* USER CODE BEGIN MESSAGE_BUFFER_LENGTH_TYPE */ +/* Defaults to size_t for backward compatibility, but can be changed + if lengths will always be less than the number of bytes in a size_t. */ +#define configMESSAGE_BUFFER_LENGTH_TYPE size_t +/* USER CODE END MESSAGE_BUFFER_LENGTH_TYPE */ + +/* Co-routine definitions. */ +#define configUSE_CO_ROUTINES 0 +#define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) + +/* Software timer definitions. */ +#define configUSE_TIMERS 1 +#define configTIMER_TASK_PRIORITY ( 2 ) +#define configTIMER_QUEUE_LENGTH 10 +#define configTIMER_TASK_STACK_DEPTH 256 + +/* CMSIS-RTOS V2 flags */ +#define configUSE_OS2_THREAD_SUSPEND_RESUME 1 +#define configUSE_OS2_THREAD_ENUMERATE 1 +#define configUSE_OS2_EVENTFLAGS_FROM_ISR 1 +#define configUSE_OS2_THREAD_FLAGS 1 +#define configUSE_OS2_TIMER 1 +#define configUSE_OS2_MUTEX 1 + +/* Set the following definitions to 1 to include the API function, or zero +to exclude the API function. */ +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_uxTaskPriorityGet 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskCleanUpResources 1 +#define INCLUDE_vTaskSuspend 1 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_xTaskGetSchedulerState 1 +#define INCLUDE_xTimerPendFunctionCall 1 +#define INCLUDE_xQueueGetMutexHolder 1 +#define INCLUDE_uxTaskGetStackHighWaterMark 1 +#define INCLUDE_xTaskGetCurrentTaskHandle 1 +#define INCLUDE_eTaskGetState 1 + +/* + * The CMSIS-RTOS V2 FreeRTOS wrapper is dependent on the heap implementation used + * by the application thus the correct define need to be enabled below + */ +#define USE_FreeRTOS_HEAP_4 + +/* Cortex-M specific definitions. */ +#ifdef __NVIC_PRIO_BITS + /* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */ + #define configPRIO_BITS __NVIC_PRIO_BITS +#else + #define configPRIO_BITS 4 +#endif + +/* The lowest interrupt priority that can be used in a call to a "set priority" +function. */ +#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 15 + +/* The highest interrupt priority that can be used by any interrupt service +routine that makes calls to interrupt safe FreeRTOS API functions. DO NOT CALL +INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER +PRIORITY THAN THIS! (higher priorities are lower numeric values. */ +#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5 + +/* Interrupt priorities used by the kernel port layer itself. These are generic +to all Cortex-M ports, and do not rely on any particular library functions. */ +#define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) ) +/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!! +See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */ +#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) ) + +/* Normal assert() semantics without relying on the provision of an assert.h +header file. */ +/* USER CODE BEGIN 1 */ +#define configASSERT( x ) if ((x) == 0) {taskDISABLE_INTERRUPTS(); for( ;; );} +/* USER CODE END 1 */ + +/* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS +standard names. */ +#define vPortSVCHandler SVC_Handler +#define xPortPendSVHandler PendSV_Handler + +/* IMPORTANT: After 10.3.1 update, Systick_Handler comes from NVIC (if SYS timebase = systick), otherwise from cmsis_os2.c */ + +#define USE_CUSTOM_SYSTICK_HANDLER_IMPLEMENTATION 1 + +/* USER CODE BEGIN 2 */ +/* Definitions needed when configGENERATE_RUN_TIME_STATS is on */ +#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS configureTimerForRunTimeStats +#define portGET_RUN_TIME_COUNTER_VALUE getRunTimeCounterValue +/* USER CODE END 2 */ + +/* USER CODE BEGIN Defines */ +/* Section where parameter definitions can be added (for instance, to override default ones in FreeRTOS.h) */ +/* USER CODE END Defines */ + +#endif /* FREERTOS_CONFIG_H */ diff --git a/firmware/targets/f7/cube/Inc/adc.h b/firmware/targets/f7/cube/Inc/adc.h new file mode 100644 index 00000000..5f945644 --- /dev/null +++ b/firmware/targets/f7/cube/Inc/adc.h @@ -0,0 +1,52 @@ +/** + ****************************************************************************** + * @file adc.h + * @brief This file contains all the function prototypes for + * the adc.c file + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __ADC_H__ +#define __ADC_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "main.h" + +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +extern ADC_HandleTypeDef hadc1; + +/* USER CODE BEGIN Private defines */ + +/* USER CODE END Private defines */ + +void MX_ADC1_Init(void); + +/* USER CODE BEGIN Prototypes */ + +/* USER CODE END Prototypes */ + +#ifdef __cplusplus +} +#endif + +#endif /* __ADC_H__ */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/cube/Inc/aes.h b/firmware/targets/f7/cube/Inc/aes.h new file mode 100644 index 00000000..bde8ad5a --- /dev/null +++ b/firmware/targets/f7/cube/Inc/aes.h @@ -0,0 +1,54 @@ +/** + ****************************************************************************** + * @file aes.h + * @brief This file contains all the function prototypes for + * the aes.c file + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __AES_H__ +#define __AES_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "main.h" + +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +extern CRYP_HandleTypeDef hcryp1; +extern CRYP_HandleTypeDef hcryp2; + +/* USER CODE BEGIN Private defines */ + +/* USER CODE END Private defines */ + +void MX_AES1_Init(void); +void MX_AES2_Init(void); + +/* USER CODE BEGIN Prototypes */ + +/* USER CODE END Prototypes */ + +#ifdef __cplusplus +} +#endif + +#endif /* __AES_H__ */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/cube/Inc/comp.h b/firmware/targets/f7/cube/Inc/comp.h new file mode 100644 index 00000000..5cc7f16e --- /dev/null +++ b/firmware/targets/f7/cube/Inc/comp.h @@ -0,0 +1,52 @@ +/** + ****************************************************************************** + * @file comp.h + * @brief This file contains all the function prototypes for + * the comp.c file + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __COMP_H__ +#define __COMP_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "main.h" + +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +extern COMP_HandleTypeDef hcomp1; + +/* USER CODE BEGIN Private defines */ + +/* USER CODE END Private defines */ + +void MX_COMP1_Init(void); + +/* USER CODE BEGIN Prototypes */ + +/* USER CODE END Prototypes */ + +#ifdef __cplusplus +} +#endif + +#endif /* __COMP_H__ */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/cube/Inc/crc.h b/firmware/targets/f7/cube/Inc/crc.h new file mode 100644 index 00000000..d1b47518 --- /dev/null +++ b/firmware/targets/f7/cube/Inc/crc.h @@ -0,0 +1,52 @@ +/** + ****************************************************************************** + * @file crc.h + * @brief This file contains all the function prototypes for + * the crc.c file + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __CRC_H__ +#define __CRC_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "main.h" + +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +extern CRC_HandleTypeDef hcrc; + +/* USER CODE BEGIN Private defines */ + +/* USER CODE END Private defines */ + +void MX_CRC_Init(void); + +/* USER CODE BEGIN Prototypes */ + +/* USER CODE END Prototypes */ + +#ifdef __cplusplus +} +#endif + +#endif /* __CRC_H__ */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/cube/Inc/gpio.h b/firmware/targets/f7/cube/Inc/gpio.h new file mode 100644 index 00000000..6b6fe6fb --- /dev/null +++ b/firmware/targets/f7/cube/Inc/gpio.h @@ -0,0 +1,49 @@ +/** + ****************************************************************************** + * @file gpio.h + * @brief This file contains all the function prototypes for + * the gpio.c file + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __GPIO_H__ +#define __GPIO_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "main.h" + +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +/* USER CODE BEGIN Private defines */ + +/* USER CODE END Private defines */ + +void MX_GPIO_Init(void); + +/* USER CODE BEGIN Prototypes */ + +/* USER CODE END Prototypes */ + +#ifdef __cplusplus +} +#endif +#endif /*__ GPIO_H__ */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/cube/Inc/i2c.h b/firmware/targets/f7/cube/Inc/i2c.h new file mode 100644 index 00000000..d5a09031 --- /dev/null +++ b/firmware/targets/f7/cube/Inc/i2c.h @@ -0,0 +1,50 @@ +/** + ****************************************************************************** + * @file i2c.h + * @brief This file contains all the function prototypes for + * the i2c.c file + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __I2C_H__ +#define __I2C_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "main.h" + +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +/* USER CODE BEGIN Private defines */ + +/* USER CODE END Private defines */ + +void MX_I2C1_Init(void); + +/* USER CODE BEGIN Prototypes */ + +/* USER CODE END Prototypes */ + +#ifdef __cplusplus +} +#endif + +#endif /* __I2C_H__ */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/cube/Inc/main.h b/firmware/targets/f7/cube/Inc/main.h new file mode 100644 index 00000000..bd7b4129 --- /dev/null +++ b/firmware/targets/f7/cube/Inc/main.h @@ -0,0 +1,175 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file : main.h + * @brief : Header for main.c file. + * This file contains the common defines of the application. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __MAIN_H +#define __MAIN_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32wbxx_hal.h" + +#include "stm32wbxx_ll_i2c.h" +#include "stm32wbxx_ll_crs.h" +#include "stm32wbxx_ll_rcc.h" +#include "stm32wbxx_ll_bus.h" +#include "stm32wbxx_ll_system.h" +#include "stm32wbxx_ll_exti.h" +#include "stm32wbxx_ll_cortex.h" +#include "stm32wbxx_ll_utils.h" +#include "stm32wbxx_ll_pwr.h" +#include "stm32wbxx_ll_dma.h" +#include "stm32wbxx_ll_usart.h" +#include "stm32wbxx_ll_gpio.h" + +/* Private includes ----------------------------------------------------------*/ +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +/* Exported types ------------------------------------------------------------*/ +/* USER CODE BEGIN ET */ + +/* USER CODE END ET */ + +/* Exported constants --------------------------------------------------------*/ +/* USER CODE BEGIN EC */ + +/* USER CODE END EC */ + +/* Exported macro ------------------------------------------------------------*/ +/* USER CODE BEGIN EM */ + +/* USER CODE END EM */ + +/* Exported functions prototypes ---------------------------------------------*/ +void Error_Handler(void); + +/* USER CODE BEGIN EFP */ + +/* USER CODE END EFP */ + +/* Private defines -----------------------------------------------------------*/ +#define BUTTON_BACK_Pin GPIO_PIN_13 +#define BUTTON_BACK_GPIO_Port GPIOC +#define BUTTON_BACK_EXTI_IRQn EXTI15_10_IRQn +#define QUARTZ_32MHZ_IN_Pin GPIO_PIN_14 +#define QUARTZ_32MHZ_IN_GPIO_Port GPIOC +#define QUARTZ_32MHZ_OUT_Pin GPIO_PIN_15 +#define QUARTZ_32MHZ_OUT_GPIO_Port GPIOC +#define BUTTON_OK_Pin GPIO_PIN_3 +#define BUTTON_OK_GPIO_Port GPIOH +#define BUTTON_OK_EXTI_IRQn EXTI3_IRQn +#define SPEAKER_Pin GPIO_PIN_8 +#define SPEAKER_GPIO_Port GPIOB +#define IR_TX_Pin GPIO_PIN_9 +#define IR_TX_GPIO_Port GPIOB +#define PC0_Pin GPIO_PIN_0 +#define PC0_GPIO_Port GPIOC +#define PC1_Pin GPIO_PIN_1 +#define PC1_GPIO_Port GPIOC +#define SPI_D_MISO_Pin GPIO_PIN_2 +#define SPI_D_MISO_GPIO_Port GPIOC +#define PC3_Pin GPIO_PIN_3 +#define PC3_GPIO_Port GPIOC +#define IR_RX_Pin GPIO_PIN_0 +#define IR_RX_GPIO_Port GPIOA +#define CC1101_G0_Pin GPIO_PIN_1 +#define CC1101_G0_GPIO_Port GPIOA +#define RFID_PULL_Pin GPIO_PIN_2 +#define RFID_PULL_GPIO_Port GPIOA +#define PERIPH_POWER_Pin GPIO_PIN_3 +#define PERIPH_POWER_GPIO_Port GPIOA +#define PA4_Pin GPIO_PIN_4 +#define PA4_GPIO_Port GPIOA +#define SPI_R_SCK_Pin GPIO_PIN_5 +#define SPI_R_SCK_GPIO_Port GPIOA +#define PA6_Pin GPIO_PIN_6 +#define PA6_GPIO_Port GPIOA +#define PA7_Pin GPIO_PIN_7 +#define PA7_GPIO_Port GPIOA +#define VIBRO_Pin GPIO_PIN_8 +#define VIBRO_GPIO_Port GPIOA +#define I2C_SCL_Pin GPIO_PIN_9 +#define I2C_SCL_GPIO_Port GPIOA +#define RF_SW_0_Pin GPIO_PIN_4 +#define RF_SW_0_GPIO_Port GPIOC +#define RFID_RF_IN_Pin GPIO_PIN_5 +#define RFID_RF_IN_GPIO_Port GPIOC +#define PB2_Pin GPIO_PIN_2 +#define PB2_GPIO_Port GPIOB +#define BUTTON_UP_Pin GPIO_PIN_10 +#define BUTTON_UP_GPIO_Port GPIOB +#define BUTTON_UP_EXTI_IRQn EXTI15_10_IRQn +#define BUTTON_LEFT_Pin GPIO_PIN_11 +#define BUTTON_LEFT_GPIO_Port GPIOB +#define BUTTON_LEFT_EXTI_IRQn EXTI15_10_IRQn +#define DISPLAY_RST_Pin GPIO_PIN_0 +#define DISPLAY_RST_GPIO_Port GPIOB +#define DISPLAY_DI_Pin GPIO_PIN_1 +#define DISPLAY_DI_GPIO_Port GPIOB +#define NFC_CS_Pin GPIO_PIN_4 +#define NFC_CS_GPIO_Port GPIOE +#define BUTTON_RIGHT_Pin GPIO_PIN_12 +#define BUTTON_RIGHT_GPIO_Port GPIOB +#define BUTTON_RIGHT_EXTI_IRQn EXTI15_10_IRQn +#define RFID_OUT_Pin GPIO_PIN_13 +#define RFID_OUT_GPIO_Port GPIOB +#define iBTN_Pin GPIO_PIN_14 +#define iBTN_GPIO_Port GPIOB +#define SPI_D_MOSI_Pin GPIO_PIN_15 +#define SPI_D_MOSI_GPIO_Port GPIOB +#define BUTTON_DOWN_Pin GPIO_PIN_6 +#define BUTTON_DOWN_GPIO_Port GPIOC +#define I2C_SDA_Pin GPIO_PIN_10 +#define I2C_SDA_GPIO_Port GPIOA +#define RFID_CARRIER_Pin GPIO_PIN_15 +#define RFID_CARRIER_GPIO_Port GPIOA +#define SD_CD_Pin GPIO_PIN_10 +#define SD_CD_GPIO_Port GPIOC +#define DISPLAY_CS_Pin GPIO_PIN_11 +#define DISPLAY_CS_GPIO_Port GPIOC +#define SD_CS_Pin GPIO_PIN_12 +#define SD_CS_GPIO_Port GPIOC +#define CC1101_CS_Pin GPIO_PIN_0 +#define CC1101_CS_GPIO_Port GPIOD +#define SPI_D_SCK_Pin GPIO_PIN_1 +#define SPI_D_SCK_GPIO_Port GPIOD +#define PB3_Pin GPIO_PIN_3 +#define PB3_GPIO_Port GPIOB +#define SPI_R_MISO_Pin GPIO_PIN_4 +#define SPI_R_MISO_GPIO_Port GPIOB +#define SPI_R_MOSI_Pin GPIO_PIN_5 +#define SPI_R_MOSI_GPIO_Port GPIOB +/* USER CODE BEGIN Private defines */ + +/* USER CODE END Private defines */ + +#ifdef __cplusplus +} +#endif + +#endif /* __MAIN_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/cube/Inc/pka.h b/firmware/targets/f7/cube/Inc/pka.h new file mode 100644 index 00000000..377ed010 --- /dev/null +++ b/firmware/targets/f7/cube/Inc/pka.h @@ -0,0 +1,52 @@ +/** + ****************************************************************************** + * @file pka.h + * @brief This file contains all the function prototypes for + * the pka.c file + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __PKA_H__ +#define __PKA_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "main.h" + +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +extern PKA_HandleTypeDef hpka; + +/* USER CODE BEGIN Private defines */ + +/* USER CODE END Private defines */ + +void MX_PKA_Init(void); + +/* USER CODE BEGIN Prototypes */ + +/* USER CODE END Prototypes */ + +#ifdef __cplusplus +} +#endif + +#endif /* __PKA_H__ */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/cube/Inc/rf.h b/firmware/targets/f7/cube/Inc/rf.h new file mode 100644 index 00000000..1796e939 --- /dev/null +++ b/firmware/targets/f7/cube/Inc/rf.h @@ -0,0 +1,50 @@ +/** + ****************************************************************************** + * @file rf.h + * @brief This file contains all the function prototypes for + * the rf.c file + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __RF_H__ +#define __RF_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "main.h" + +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +/* USER CODE BEGIN Private defines */ + +/* USER CODE END Private defines */ + +void MX_RF_Init(void); + +/* USER CODE BEGIN Prototypes */ + +/* USER CODE END Prototypes */ + +#ifdef __cplusplus +} +#endif + +#endif /* __RF_H__ */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/cube/Inc/rng.h b/firmware/targets/f7/cube/Inc/rng.h new file mode 100644 index 00000000..fa121ad1 --- /dev/null +++ b/firmware/targets/f7/cube/Inc/rng.h @@ -0,0 +1,52 @@ +/** + ****************************************************************************** + * @file rng.h + * @brief This file contains all the function prototypes for + * the rng.c file + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __RNG_H__ +#define __RNG_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "main.h" + +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +extern RNG_HandleTypeDef hrng; + +/* USER CODE BEGIN Private defines */ + +/* USER CODE END Private defines */ + +void MX_RNG_Init(void); + +/* USER CODE BEGIN Prototypes */ + +/* USER CODE END Prototypes */ + +#ifdef __cplusplus +} +#endif + +#endif /* __RNG_H__ */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/cube/Inc/rtc.h b/firmware/targets/f7/cube/Inc/rtc.h new file mode 100644 index 00000000..3e961b71 --- /dev/null +++ b/firmware/targets/f7/cube/Inc/rtc.h @@ -0,0 +1,52 @@ +/** + ****************************************************************************** + * @file rtc.h + * @brief This file contains all the function prototypes for + * the rtc.c file + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __RTC_H__ +#define __RTC_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "main.h" + +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +extern RTC_HandleTypeDef hrtc; + +/* USER CODE BEGIN Private defines */ + +/* USER CODE END Private defines */ + +void MX_RTC_Init(void); + +/* USER CODE BEGIN Prototypes */ + +/* USER CODE END Prototypes */ + +#ifdef __cplusplus +} +#endif + +#endif /* __RTC_H__ */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/cube/Inc/spi.h b/firmware/targets/f7/cube/Inc/spi.h new file mode 100644 index 00000000..01a2233f --- /dev/null +++ b/firmware/targets/f7/cube/Inc/spi.h @@ -0,0 +1,54 @@ +/** + ****************************************************************************** + * @file spi.h + * @brief This file contains all the function prototypes for + * the spi.c file + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __SPI_H__ +#define __SPI_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "main.h" + +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +extern SPI_HandleTypeDef hspi1; +extern SPI_HandleTypeDef hspi2; + +/* USER CODE BEGIN Private defines */ + +/* USER CODE END Private defines */ + +void MX_SPI1_Init(void); +void MX_SPI2_Init(void); + +/* USER CODE BEGIN Prototypes */ + +/* USER CODE END Prototypes */ + +#ifdef __cplusplus +} +#endif + +#endif /* __SPI_H__ */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/cube/Inc/stm32_assert.h b/firmware/targets/f7/cube/Inc/stm32_assert.h new file mode 100644 index 00000000..734c6558 --- /dev/null +++ b/firmware/targets/f7/cube/Inc/stm32_assert.h @@ -0,0 +1,53 @@ +/** + ****************************************************************************** + * @file stm32_assert.h + * @brief STM32 assert file. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2019 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32_ASSERT_H +#define __STM32_ASSERT_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ +/* Includes ------------------------------------------------------------------*/ +/* Exported macro ------------------------------------------------------------*/ +#ifdef USE_FULL_ASSERT +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr: If expr is false, it calls assert_failed function + * which reports the name of the source file and the source + * line number of the call that failed. + * If expr is true, it returns no value. + * @retval None + */ + #define assert_param(expr) ((expr) ? (void)0U : assert_failed((uint8_t *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ + void assert_failed(uint8_t* file, uint32_t line); +#else + #define assert_param(expr) ((void)0U) +#endif /* USE_FULL_ASSERT */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32_ASSERT_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/cube/Inc/stm32wbxx_hal_conf.h b/firmware/targets/f7/cube/Inc/stm32wbxx_hal_conf.h new file mode 100644 index 00000000..cab30f03 --- /dev/null +++ b/firmware/targets/f7/cube/Inc/stm32wbxx_hal_conf.h @@ -0,0 +1,353 @@ +/** + ****************************************************************************** + * @file stm32wbxx_hal_conf.h + * @author MCD Application Team + * @brief HAL configuration file. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2019 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32WBxx_HAL_CONF_H +#define __STM32WBxx_HAL_CONF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +/* ########################## Module Selection ############################## */ +/** + * @brief This is the list of modules to be used in the HAL driver + */ +#define HAL_MODULE_ENABLED +#define HAL_ADC_MODULE_ENABLED +#define HAL_CRYP_MODULE_ENABLED +#define HAL_COMP_MODULE_ENABLED +#define HAL_CRC_MODULE_ENABLED +#define HAL_HSEM_MODULE_ENABLED +/*#define HAL_I2C_MODULE_ENABLED */ +/*#define HAL_IPCC_MODULE_ENABLED */ +/*#define HAL_IRDA_MODULE_ENABLED */ +/*#define HAL_IWDG_MODULE_ENABLED */ +/*#define HAL_LCD_MODULE_ENABLED */ +/*#define HAL_LPTIM_MODULE_ENABLED */ +#define HAL_PCD_MODULE_ENABLED +#define HAL_PKA_MODULE_ENABLED +/*#define HAL_QSPI_MODULE_ENABLED */ +#define HAL_RNG_MODULE_ENABLED +#define HAL_RTC_MODULE_ENABLED +/*#define HAL_SAI_MODULE_ENABLED */ +/*#define HAL_SMBUS_MODULE_ENABLED */ +/*#define HAL_SMARTCARD_MODULE_ENABLED */ +#define HAL_SPI_MODULE_ENABLED +#define HAL_TIM_MODULE_ENABLED +/*#define HAL_TSC_MODULE_ENABLED */ +/*#define HAL_UART_MODULE_ENABLED */ +/*#define HAL_USART_MODULE_ENABLED */ +/*#define HAL_WWDG_MODULE_ENABLED */ +#define HAL_EXTI_MODULE_ENABLED +#define HAL_CORTEX_MODULE_ENABLED +#define HAL_DMA_MODULE_ENABLED +#define HAL_FLASH_MODULE_ENABLED +#define HAL_GPIO_MODULE_ENABLED +#define HAL_PWR_MODULE_ENABLED +#define HAL_RCC_MODULE_ENABLED + +#define USE_HAL_ADC_REGISTER_CALLBACKS 0u +#define USE_HAL_COMP_REGISTER_CALLBACKS 0u +#define USE_HAL_CRYP_REGISTER_CALLBACKS 0u +#define USE_HAL_I2C_REGISTER_CALLBACKS 0u +#define USE_HAL_IRDA_REGISTER_CALLBACKS 0u +#define USE_HAL_LPTIM_REGISTER_CALLBACKS 0u +#define USE_HAL_PCD_REGISTER_CALLBACKS 0u +#define USE_HAL_PKA_REGISTER_CALLBACKS 0u +#define USE_HAL_QSPI_REGISTER_CALLBACKS 0u +#define USE_HAL_RNG_REGISTER_CALLBACKS 0u +#define USE_HAL_RTC_REGISTER_CALLBACKS 0u +#define USE_HAL_SAI_REGISTER_CALLBACKS 0u +#define USE_HAL_SMARTCARD_REGISTER_CALLBACKS 0u +#define USE_HAL_SMBUS_REGISTER_CALLBACKS 0u +#define USE_HAL_SPI_REGISTER_CALLBACKS 0u +#define USE_HAL_TIM_REGISTER_CALLBACKS 0u +#define USE_HAL_TSC_REGISTER_CALLBACKS 0u +#define USE_HAL_UART_REGISTER_CALLBACKS 0u +#define USE_HAL_USART_REGISTER_CALLBACKS 0u +#define USE_HAL_WWDG_REGISTER_CALLBACKS 0u + +/* ########################## Oscillator Values adaptation ####################*/ +/** + * @brief Adjust the value of External High Speed oscillator (HSE) used in your application. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSE is used as system clock source, directly or through the PLL). + */ +#if !defined (HSE_VALUE) +#define HSE_VALUE 32000000U /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +#if !defined (HSE_STARTUP_TIMEOUT) + #define HSE_STARTUP_TIMEOUT ((uint32_t)100) /*!< Time out for HSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief Internal Multiple Speed oscillator (MSI) default value. + * This value is the default MSI range value after Reset. + */ +#if !defined (MSI_VALUE) + #define MSI_VALUE ((uint32_t)4000000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* MSI_VALUE */ + +/** + * @brief Internal High Speed oscillator (HSI) value. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSI is used as system clock source, directly or through the PLL). + */ +#if !defined (HSI_VALUE) +#define HSI_VALUE 16000000U /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI_VALUE */ + +/** + * @brief Internal Low Speed oscillator (LSI1) value. + */ +#if !defined (LSI1_VALUE) + #define LSI1_VALUE ((uint32_t)32000) /*!< LSI1 Typical Value in Hz*/ +#endif /* LSI1_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz + The real value may vary depending on the variations + in voltage and temperature.*/ +/** + * @brief Internal Low Speed oscillator (LSI2) value. + */ +#if !defined (LSI2_VALUE) + #define LSI2_VALUE ((uint32_t)32000) /*!< LSI2 Typical Value in Hz*/ +#endif /* LSI2_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz + The real value may vary depending on the variations + in voltage and temperature.*/ + +/** + * @brief External Low Speed oscillator (LSE) value. + * This value is used by the UART, RTC HAL module to compute the system frequency + */ +#if !defined (LSE_VALUE) +#define LSE_VALUE 32768U /*!< Value of the External oscillator in Hz*/ +#endif /* LSE_VALUE */ + +/** + * @brief Internal Multiple Speed oscillator (HSI48) default value. + * This value is the default HSI48 range value after Reset. + */ +#if !defined (HSI48_VALUE) + #define HSI48_VALUE ((uint32_t)48000000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI48_VALUE */ + +#if !defined (LSE_STARTUP_TIMEOUT) +#define LSE_STARTUP_TIMEOUT 1000U /*!< Time out for LSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief External clock source for SAI1 peripheral + * This value is used by the RCC HAL module to compute the SAI1 & SAI2 clock source + * frequency. + */ +#if !defined (EXTERNAL_SAI1_CLOCK_VALUE) + #define EXTERNAL_SAI1_CLOCK_VALUE ((uint32_t)2097000) /*!< Value of the SAI1 External clock source in Hz*/ +#endif /* EXTERNAL_SAI1_CLOCK_VALUE */ + +/* Tip: To avoid modifying this file each time you need to use different HSE, + === you can define the HSE value in your toolchain compiler preprocessor. */ + +/* ########################### System Configuration ######################### */ +/** + * @brief This is the HAL system configuration section + */ + +#define VDD_VALUE 3300U /*!< Value of VDD in mv */ +#define TICK_INT_PRIORITY 15U /*!< tick interrupt priority */ +#define USE_RTOS 0U +#define PREFETCH_ENABLE 1U +#define INSTRUCTION_CACHE_ENABLE 1U +#define DATA_CACHE_ENABLE 1U + +/* ########################## Assert Selection ############################## */ +/** + * @brief Uncomment the line below to expanse the "assert_param" macro in the + * HAL drivers code + */ +/* #define USE_FULL_ASSERT 1U */ + +/* ################## SPI peripheral configuration ########################## */ + +/* CRC FEATURE: Use to activate CRC feature inside HAL SPI Driver + * Activated: CRC code is present inside driver + * Deactivated: CRC code cleaned from driver + */ + +#define USE_SPI_CRC 0U + +/* Includes ------------------------------------------------------------------*/ +/** + * @brief Include module's header file + */ +#ifdef HAL_DMA_MODULE_ENABLED + #include "stm32wbxx_hal_dma.h" +#endif /* HAL_DMA_MODULE_ENABLED */ + +#ifdef HAL_ADC_MODULE_ENABLED + #include "stm32wbxx_hal_adc.h" +#endif /* HAL_ADC_MODULE_ENABLED */ + +#ifdef HAL_COMP_MODULE_ENABLED + #include "stm32wbxx_hal_comp.h" +#endif /* HAL_COMP_MODULE_ENABLED */ + +#ifdef HAL_CORTEX_MODULE_ENABLED + #include "stm32wbxx_hal_cortex.h" +#endif /* HAL_CORTEX_MODULE_ENABLED */ + +#ifdef HAL_CRC_MODULE_ENABLED + #include "stm32wbxx_hal_crc.h" +#endif /* HAL_CRC_MODULE_ENABLED */ + +#ifdef HAL_CRYP_MODULE_ENABLED + #include "stm32wbxx_hal_cryp.h" +#endif /* HAL_CRYP_MODULE_ENABLED */ + +#ifdef HAL_EXTI_MODULE_ENABLED + #include "stm32wbxx_hal_exti.h" +#endif /* HAL_EXTI_MODULE_ENABLED */ + +#ifdef HAL_FLASH_MODULE_ENABLED + #include "stm32wbxx_hal_flash.h" +#endif /* HAL_FLASH_MODULE_ENABLED */ + +#ifdef HAL_GPIO_MODULE_ENABLED + #include "stm32wbxx_hal_gpio.h" +#endif /* HAL_GPIO_MODULE_ENABLED */ + +#ifdef HAL_HSEM_MODULE_ENABLED + #include "stm32wbxx_hal_hsem.h" +#endif /* HAL_HSEM_MODULE_ENABLED */ + +#ifdef HAL_I2C_MODULE_ENABLED + #include "stm32wbxx_hal_i2c.h" +#endif /* HAL_I2C_MODULE_ENABLED */ + +#ifdef HAL_IPCC_MODULE_ENABLED + #include "stm32wbxx_hal_ipcc.h" +#endif /* HAL_IPCC_MODULE_ENABLED */ + +#ifdef HAL_IRDA_MODULE_ENABLED + #include "stm32wbxx_hal_irda.h" +#endif /* HAL_IRDA_MODULE_ENABLED */ + +#ifdef HAL_IWDG_MODULE_ENABLED + #include "stm32wbxx_hal_iwdg.h" +#endif /* HAL_IWDG_MODULE_ENABLED */ + +#ifdef HAL_LCD_MODULE_ENABLED + #include "stm32wbxx_hal_lcd.h" +#endif /* HAL_LCD_MODULE_ENABLED */ + +#ifdef HAL_LPTIM_MODULE_ENABLED + #include "stm32wbxx_hal_lptim.h" +#endif /* HAL_LPTIM_MODULE_ENABLED */ + +#ifdef HAL_PCD_MODULE_ENABLED + #include "stm32wbxx_hal_pcd.h" +#endif /* HAL_PCD_MODULE_ENABLED */ + +#ifdef HAL_PKA_MODULE_ENABLED + #include "stm32wbxx_hal_pka.h" +#endif /* HAL_PKA_MODULE_ENABLED */ + +#ifdef HAL_PWR_MODULE_ENABLED + #include "stm32wbxx_hal_pwr.h" +#endif /* HAL_PWR_MODULE_ENABLED */ + +#ifdef HAL_QSPI_MODULE_ENABLED + #include "stm32wbxx_hal_qspi.h" +#endif /* HAL_QSPI_MODULE_ENABLED */ + +#ifdef HAL_RCC_MODULE_ENABLED + #include "stm32wbxx_hal_rcc.h" +#endif /* HAL_RCC_MODULE_ENABLED */ + +#ifdef HAL_RNG_MODULE_ENABLED + #include "stm32wbxx_hal_rng.h" +#endif /* HAL_RNG_MODULE_ENABLED */ + +#ifdef HAL_RTC_MODULE_ENABLED + #include "stm32wbxx_hal_rtc.h" +#endif /* HAL_RTC_MODULE_ENABLED */ + +#ifdef HAL_SAI_MODULE_ENABLED + #include "stm32wbxx_hal_sai.h" +#endif /* HAL_SAI_MODULE_ENABLED */ + +#ifdef HAL_SMARTCARD_MODULE_ENABLED + #include "stm32wbxx_hal_smartcard.h" +#endif /* HAL_SMARTCARD_MODULE_ENABLED */ + +#ifdef HAL_SMBUS_MODULE_ENABLED + #include "stm32wbxx_hal_smbus.h" +#endif /* HAL_SMBUS_MODULE_ENABLED */ + +#ifdef HAL_SPI_MODULE_ENABLED + #include "stm32wbxx_hal_spi.h" +#endif /* HAL_SPI_MODULE_ENABLED */ + +#ifdef HAL_TIM_MODULE_ENABLED + #include "stm32wbxx_hal_tim.h" +#endif /* HAL_TIM_MODULE_ENABLED */ + +#ifdef HAL_TSC_MODULE_ENABLED + #include "stm32wbxx_hal_tsc.h" +#endif /* HAL_TSC_MODULE_ENABLED */ + +#ifdef HAL_UART_MODULE_ENABLED + #include "stm32wbxx_hal_uart.h" +#endif /* HAL_UART_MODULE_ENABLED */ + +#ifdef HAL_USART_MODULE_ENABLED + #include "stm32wbxx_hal_usart.h" +#endif /* HAL_USART_MODULE_ENABLED */ + +#ifdef HAL_WWDG_MODULE_ENABLED + #include "stm32wbxx_hal_wwdg.h" +#endif /* HAL_WWDG_MODULE_ENABLED */ + +/* Exported macro ------------------------------------------------------------*/ +#ifdef USE_FULL_ASSERT +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr If expr is false, it calls assert_failed function + * which reports the name of the source file and the source + * line number of the call that failed. + * If expr is true, it returns no value. + * @retval None + */ + #define assert_param(expr) ((expr) ? (void)0U : assert_failed((uint8_t *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ + void assert_failed(uint8_t* file, uint32_t line); +#else + #define assert_param(expr) ((void)0U) +#endif /* USE_FULL_ASSERT */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32WBxx_HAL_CONF_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/cube/Inc/stm32wbxx_it.h b/firmware/targets/f7/cube/Inc/stm32wbxx_it.h new file mode 100644 index 00000000..953d5a88 --- /dev/null +++ b/firmware/targets/f7/cube/Inc/stm32wbxx_it.h @@ -0,0 +1,77 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file stm32wbxx_it.h + * @brief This file contains the headers of the interrupt handlers. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32WBxx_IT_H +#define __STM32WBxx_IT_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Private includes ----------------------------------------------------------*/ +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +/* Exported types ------------------------------------------------------------*/ +/* USER CODE BEGIN ET */ + +/* USER CODE END ET */ + +/* Exported constants --------------------------------------------------------*/ +/* USER CODE BEGIN EC */ + +/* USER CODE END EC */ + +/* Exported macro ------------------------------------------------------------*/ +/* USER CODE BEGIN EM */ + +/* USER CODE END EM */ + +/* Exported functions prototypes ---------------------------------------------*/ +void NMI_Handler(void); +void HardFault_Handler(void); +void MemManage_Handler(void); +void BusFault_Handler(void); +void UsageFault_Handler(void); +void DebugMon_Handler(void); +void SysTick_Handler(void); +void TAMP_STAMP_LSECSS_IRQHandler(void); +void RCC_IRQHandler(void); +void EXTI3_IRQHandler(void); +void ADC1_IRQHandler(void); +void USB_LP_IRQHandler(void); +void COMP_IRQHandler(void); +void TIM1_TRG_COM_TIM17_IRQHandler(void); +void TIM2_IRQHandler(void); +void EXTI15_10_IRQHandler(void); +void HSEM_IRQHandler(void); +/* USER CODE BEGIN EFP */ + +/* USER CODE END EFP */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32WBxx_IT_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/cube/Inc/tim.h b/firmware/targets/f7/cube/Inc/tim.h new file mode 100644 index 00000000..9d530bce --- /dev/null +++ b/firmware/targets/f7/cube/Inc/tim.h @@ -0,0 +1,58 @@ +/** + ****************************************************************************** + * @file tim.h + * @brief This file contains all the function prototypes for + * the tim.c file + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __TIM_H__ +#define __TIM_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "main.h" + +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +extern TIM_HandleTypeDef htim1; +extern TIM_HandleTypeDef htim2; +extern TIM_HandleTypeDef htim16; + +/* USER CODE BEGIN Private defines */ + +/* USER CODE END Private defines */ + +void MX_TIM1_Init(void); +void MX_TIM2_Init(void); +void MX_TIM16_Init(void); + +void HAL_TIM_MspPostInit(TIM_HandleTypeDef *htim); + +/* USER CODE BEGIN Prototypes */ + +/* USER CODE END Prototypes */ + +#ifdef __cplusplus +} +#endif + +#endif /* __TIM_H__ */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/cube/Inc/usart.h b/firmware/targets/f7/cube/Inc/usart.h new file mode 100644 index 00000000..506e8972 --- /dev/null +++ b/firmware/targets/f7/cube/Inc/usart.h @@ -0,0 +1,50 @@ +/** + ****************************************************************************** + * @file usart.h + * @brief This file contains all the function prototypes for + * the usart.c file + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USART_H__ +#define __USART_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "main.h" + +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +/* USER CODE BEGIN Private defines */ + +/* USER CODE END Private defines */ + +void MX_USART1_UART_Init(void); + +/* USER CODE BEGIN Prototypes */ + +/* USER CODE END Prototypes */ + +#ifdef __cplusplus +} +#endif + +#endif /* __USART_H__ */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/cube/Inc/usb_device.h b/firmware/targets/f7/cube/Inc/usb_device.h new file mode 100644 index 00000000..dc9bbdc6 --- /dev/null +++ b/firmware/targets/f7/cube/Inc/usb_device.h @@ -0,0 +1,105 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file : usb_device.h + * @version : v3.0_Cube + * @brief : Header for usb_device.c file. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USB_DEVICE__H__ +#define __USB_DEVICE__H__ + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32wbxx.h" +#include "stm32wbxx_hal.h" +#include "usbd_def.h" + +/* USER CODE BEGIN INCLUDE */ + +/* USER CODE END INCLUDE */ + +/** @addtogroup USBD_OTG_DRIVER + * @{ + */ + +/** @defgroup USBD_DEVICE USBD_DEVICE + * @brief Device file for Usb otg low level driver. + * @{ + */ + +/** @defgroup USBD_DEVICE_Exported_Variables USBD_DEVICE_Exported_Variables + * @brief Public variables. + * @{ + */ + +/* Private variables ---------------------------------------------------------*/ +/* USER CODE BEGIN PV */ + +/* USER CODE END PV */ + +/* Private function prototypes -----------------------------------------------*/ +/* USER CODE BEGIN PFP */ + +/* USER CODE END PFP */ + +/* + * -- Insert your variables declaration here -- + */ +/* USER CODE BEGIN VARIABLES */ + +/* USER CODE END VARIABLES */ +/** + * @} + */ + +/** @defgroup USBD_DEVICE_Exported_FunctionsPrototype USBD_DEVICE_Exported_FunctionsPrototype + * @brief Declaration of public functions for Usb device. + * @{ + */ + +/** USB Device initialization function. */ +void MX_USB_Device_Init(void); + +/* + * -- Insert functions declaration here -- + */ +/* USER CODE BEGIN FD */ + +/* USER CODE END FD */ +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __USB_DEVICE__H__ */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/cube/Inc/usbd_cdc_if.h b/firmware/targets/f7/cube/Inc/usbd_cdc_if.h new file mode 100644 index 00000000..bbd5af07 --- /dev/null +++ b/firmware/targets/f7/cube/Inc/usbd_cdc_if.h @@ -0,0 +1,133 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file : usbd_cdc_if.h + * @version : v3.0_Cube + * @brief : Header for usbd_cdc_if.c file. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USBD_CDC_IF_H__ +#define __USBD_CDC_IF_H__ + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_cdc.h" + +/* USER CODE BEGIN INCLUDE */ + +/* USER CODE END INCLUDE */ + +/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY + * @brief For Usb device. + * @{ + */ + +/** @defgroup USBD_CDC_IF USBD_CDC_IF + * @brief Usb VCP device module + * @{ + */ + +/** @defgroup USBD_CDC_IF_Exported_Defines USBD_CDC_IF_Exported_Defines + * @brief Defines. + * @{ + */ +/* Define size for the receive and transmit buffer over CDC */ +#define APP_RX_DATA_SIZE 512 +#define APP_TX_DATA_SIZE 512 +/* USER CODE BEGIN EXPORTED_DEFINES */ + +/* USER CODE END EXPORTED_DEFINES */ + +/** + * @} + */ + +/** @defgroup USBD_CDC_IF_Exported_Types USBD_CDC_IF_Exported_Types + * @brief Types. + * @{ + */ + +/* USER CODE BEGIN EXPORTED_TYPES */ + +/* USER CODE END EXPORTED_TYPES */ + +/** + * @} + */ + +/** @defgroup USBD_CDC_IF_Exported_Macros USBD_CDC_IF_Exported_Macros + * @brief Aliases. + * @{ + */ + +/* USER CODE BEGIN EXPORTED_MACRO */ + +/* USER CODE END EXPORTED_MACRO */ + +/** + * @} + */ + +/** @defgroup USBD_CDC_IF_Exported_Variables USBD_CDC_IF_Exported_Variables + * @brief Public variables. + * @{ + */ + +/** CDC Interface callback. */ +extern USBD_CDC_ItfTypeDef USBD_Interface_fops_FS; + +/* USER CODE BEGIN EXPORTED_VARIABLES */ + +/* USER CODE END EXPORTED_VARIABLES */ + +/** + * @} + */ + +/** @defgroup USBD_CDC_IF_Exported_FunctionsPrototype USBD_CDC_IF_Exported_FunctionsPrototype + * @brief Public functions declaration. + * @{ + */ + +uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len); + +/* USER CODE BEGIN EXPORTED_FUNCTIONS */ + +/* USER CODE END EXPORTED_FUNCTIONS */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __USBD_CDC_IF_H__ */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/cube/Inc/usbd_conf.h b/firmware/targets/f7/cube/Inc/usbd_conf.h new file mode 100644 index 00000000..e4aa2fd5 --- /dev/null +++ b/firmware/targets/f7/cube/Inc/usbd_conf.h @@ -0,0 +1,176 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file : usbd_conf.h + * @version : v3.0_Cube + * @brief : Header for usbd_conf.c file. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USBD_CONF__H__ +#define __USBD_CONF__H__ + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include +#include +#include +#include "stm32wbxx.h" +#include "stm32wbxx_hal.h" + +/* USER CODE BEGIN INCLUDE */ + +/* USER CODE END INCLUDE */ + +/** @addtogroup USBD_OTG_DRIVER + * @brief Driver for Usb device. + * @{ + */ + +/** @defgroup USBD_CONF USBD_CONF + * @brief Configuration file for Usb otg low level driver. + * @{ + */ + +/** @defgroup USBD_CONF_Exported_Variables USBD_CONF_Exported_Variables + * @brief Public variables. + * @{ + */ + +/* Private variables ---------------------------------------------------------*/ +/* USER CODE BEGIN PV */ +/* USER CODE END PV */ +/** + * @} + */ + +/** @defgroup USBD_CONF_Exported_Defines USBD_CONF_Exported_Defines + * @brief Defines for configuration of the Usb device. + * @{ + */ + +/*---------- -----------*/ +#define USBD_MAX_NUM_INTERFACES 1U +/*---------- -----------*/ +#define USBD_MAX_NUM_CONFIGURATION 1U +/*---------- -----------*/ +#define USBD_MAX_STR_DESC_SIZ 512U +/*---------- -----------*/ +#define USBD_DEBUG_LEVEL 0U +/*---------- -----------*/ +#define USBD_LPM_ENABLED 1U +/*---------- -----------*/ +#define USBD_SELF_POWERED 1U + +/****************************************/ +/* #define for FS and HS identification */ +#define DEVICE_FS 0 + +/** + * @} + */ + +/** @defgroup USBD_CONF_Exported_Macros USBD_CONF_Exported_Macros + * @brief Aliases. + * @{ + */ + +/* Memory management macros */ + +/** Alias for memory allocation. */ +#define USBD_malloc (void *)USBD_static_malloc + +/** Alias for memory release. */ +#define USBD_free USBD_static_free + +/** Alias for memory set. */ +#define USBD_memset memset + +/** Alias for memory copy. */ +#define USBD_memcpy memcpy + +/** Alias for delay. */ +#define USBD_Delay HAL_Delay +/* DEBUG macros */ + +#if (USBD_DEBUG_LEVEL > 0) +#define USBD_UsrLog(...) printf(__VA_ARGS__);\ + printf("\n"); +#else +#define USBD_UsrLog(...) +#endif + +#if (USBD_DEBUG_LEVEL > 1) + +#define USBD_ErrLog(...) printf("ERROR: ") ;\ + printf(__VA_ARGS__);\ + printf("\n"); +#else +#define USBD_ErrLog(...) +#endif + +#if (USBD_DEBUG_LEVEL > 2) +#define USBD_DbgLog(...) printf("DEBUG : ") ;\ + printf(__VA_ARGS__);\ + printf("\n"); +#else +#define USBD_DbgLog(...) +#endif + +/** + * @} + */ + +/** @defgroup USBD_CONF_Exported_Types USBD_CONF_Exported_Types + * @brief Types. + * @{ + */ + +/** + * @} + */ + +/** @defgroup USBD_CONF_Exported_FunctionsPrototype USBD_CONF_Exported_FunctionsPrototype + * @brief Declaration of public functions for Usb device. + * @{ + */ + +/* Exported functions -------------------------------------------------------*/ +void *USBD_static_malloc(uint32_t size); +void USBD_static_free(void *p); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __USBD_CONF__H__ */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/cube/Inc/usbd_desc.h b/firmware/targets/f7/cube/Inc/usbd_desc.h new file mode 100644 index 00000000..772b538f --- /dev/null +++ b/firmware/targets/f7/cube/Inc/usbd_desc.h @@ -0,0 +1,145 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file : usbd_desc.c + * @version : v3.0_Cube + * @brief : Header for usbd_conf.c file. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USBD_DESC__C__ +#define __USBD_DESC__C__ + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_def.h" + +/* USER CODE BEGIN INCLUDE */ + +/* USER CODE END INCLUDE */ + +/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY + * @{ + */ + +/** @defgroup USBD_DESC USBD_DESC + * @brief Usb device descriptors module. + * @{ + */ + +/** @defgroup USBD_DESC_Exported_Constants USBD_DESC_Exported_Constants + * @brief Constants. + * @{ + */ +#define DEVICE_ID1 (UID_BASE) +#define DEVICE_ID2 (UID_BASE + 0x4) +#define DEVICE_ID3 (UID_BASE + 0x8) + +#define USB_SIZ_STRING_SERIAL 0x1A + +/* USER CODE BEGIN EXPORTED_CONSTANTS */ + +/* USER CODE END EXPORTED_CONSTANTS */ + +/** + * @} + */ + +/** @defgroup USBD_DESC_Exported_Defines USBD_DESC_Exported_Defines + * @brief Defines. + * @{ + */ + +/* USER CODE BEGIN EXPORTED_DEFINES */ + +/* USER CODE END EXPORTED_DEFINES */ + +/** + * @} + */ + +/** @defgroup USBD_DESC_Exported_TypesDefinitions USBD_DESC_Exported_TypesDefinitions + * @brief Types. + * @{ + */ + +/* USER CODE BEGIN EXPORTED_TYPES */ + +/* USER CODE END EXPORTED_TYPES */ + +/** + * @} + */ + +/** @defgroup USBD_DESC_Exported_Macros USBD_DESC_Exported_Macros + * @brief Aliases. + * @{ + */ + +/* USER CODE BEGIN EXPORTED_MACRO */ + +/* USER CODE END EXPORTED_MACRO */ + +/** + * @} + */ + +/** @defgroup USBD_DESC_Exported_Variables USBD_DESC_Exported_Variables + * @brief Public variables. + * @{ + */ + +extern USBD_DescriptorsTypeDef CDC_Desc; + +/* USER CODE BEGIN EXPORTED_VARIABLES */ + +/* USER CODE END EXPORTED_VARIABLES */ + +/** + * @} + */ + +/** @defgroup USBD_DESC_Exported_FunctionsPrototype USBD_DESC_Exported_FunctionsPrototype + * @brief Public functions declaration. + * @{ + */ + +/* USER CODE BEGIN EXPORTED_FUNCTIONS */ + +/* USER CODE END EXPORTED_FUNCTIONS */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __USBD_DESC__C__ */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/cube/Makefile b/firmware/targets/f7/cube/Makefile new file mode 100644 index 00000000..f5e7c874 --- /dev/null +++ b/firmware/targets/f7/cube/Makefile @@ -0,0 +1,253 @@ +########################################################################################################################## +# File automatically-generated by tool: [projectgenerator] version: [3.14.1] date: [Fri Sep 10 04:36:47 MSK 2021] +########################################################################################################################## + +# ------------------------------------------------ +# Generic Makefile (based on gcc) +# +# ChangeLog : +# 2017-02-10 - Several enhancements + project update mode +# 2015-07-22 - first version +# ------------------------------------------------ + +###################################### +# target +###################################### +TARGET = f7 + + +###################################### +# building variables +###################################### +# debug build? +DEBUG = 1 +# optimization +OPT = -Og + + +####################################### +# paths +####################################### +# Build path +BUILD_DIR = build + +###################################### +# source +###################################### +# C sources +C_SOURCES = \ +Src/main.c \ +Src/gpio.c \ +Src/app_freertos.c \ +Src/adc.c \ +Src/aes.c \ +Src/comp.c \ +Src/crc.c \ +Src/i2c.c \ +Src/pka.c \ +Src/rf.c \ +Src/rng.c \ +Src/rtc.c \ +Src/spi.c \ +Src/tim.c \ +Src/usart.c \ +Src/usb_device.c \ +Src/usbd_conf.c \ +Src/usbd_desc.c \ +Src/usbd_cdc_if.c \ +Src/stm32wbxx_it.c \ +Src/stm32wbxx_hal_msp.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_utils.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_exti.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_pcd.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_pcd_ex.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_usb.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_rcc.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_rcc_ex.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_flash.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_flash_ex.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_gpio.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_hsem.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_dma.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_dma_ex.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_pwr.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_pwr_ex.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_cortex.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_exti.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_adc.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_adc_ex.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_adc.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_cryp.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_cryp_ex.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_comp.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_crc.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_crc_ex.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_i2c.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_gpio.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_dma.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_pka.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_rng.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_rtc.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_rtc_ex.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_spi.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_spi_ex.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_tim.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_tim_ex.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_usart.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_rcc.c \ +Src/system_stm32wbxx.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/croutine.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/event_groups.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/list.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/queue.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/stream_buffer.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/tasks.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/timers.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/cmsis_os2.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/portable/MemMang/heap_4.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_core.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_ctlreq.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_ioreq.c \ +/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c + +# ASM sources +ASM_SOURCES = \ +startup_stm32wb55xx_cm4.s + + +####################################### +# binaries +####################################### +PREFIX = arm-none-eabi- +# The gcc compiler bin path can be either defined in make command via GCC_PATH variable (> make GCC_PATH=xxx) +# either it can be added to the PATH environment variable. +ifdef GCC_PATH +CC = $(GCC_PATH)/$(PREFIX)gcc +AS = $(GCC_PATH)/$(PREFIX)gcc -x assembler-with-cpp +CP = $(GCC_PATH)/$(PREFIX)objcopy +SZ = $(GCC_PATH)/$(PREFIX)size +else +CC = $(PREFIX)gcc +AS = $(PREFIX)gcc -x assembler-with-cpp +CP = $(PREFIX)objcopy +SZ = $(PREFIX)size +endif +HEX = $(CP) -O ihex +BIN = $(CP) -O binary -S + +####################################### +# CFLAGS +####################################### +# cpu +CPU = -mcpu=cortex-m4 + +# fpu +FPU = -mfpu=fpv4-sp-d16 + +# float-abi +FLOAT-ABI = -mfloat-abi=hard + +# mcu +MCU = $(CPU) -mthumb $(FPU) $(FLOAT-ABI) + +# macros for gcc +# AS defines +AS_DEFS = + +# C defines +C_DEFS = \ +-DUSE_FULL_LL_DRIVER \ +-DUSE_HAL_DRIVER \ +-DSTM32WB55xx + + +# AS includes +AS_INCLUDES = \ +-IInc + +# C includes +C_INCLUDES = \ +-IInc \ +-I/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc \ +-I/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/Legacy \ +-I/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/include \ +-I/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2 \ +-I/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F \ +-I/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/ST/STM32_USB_Device_Library/Core/Inc \ +-I/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Inc \ +-I/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/CMSIS/Device/ST/STM32WBxx/Include \ +-I/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/CMSIS/Include + + +# compile gcc flags +ASFLAGS = $(MCU) $(AS_DEFS) $(AS_INCLUDES) $(OPT) -Wall -fdata-sections -ffunction-sections + +CFLAGS = $(MCU) $(C_DEFS) $(C_INCLUDES) $(OPT) -Wall -fdata-sections -ffunction-sections + +ifeq ($(DEBUG), 1) +CFLAGS += -g -gdwarf-2 +endif + + +# Generate dependency information +CFLAGS += -MMD -MP -MF"$(@:%.o=%.d)" + + +####################################### +# LDFLAGS +####################################### +# link script +LDSCRIPT = stm32wb55xx_flash_cm4.ld + +# libraries +LIBS = -lc -lm -lnosys +LIBDIR = +LDFLAGS = $(MCU) -specs=nano.specs -T$(LDSCRIPT) $(LIBDIR) $(LIBS) -Wl,-Map=$(BUILD_DIR)/$(TARGET).map,--cref -Wl,--gc-sections + +# default action: build all +all: $(BUILD_DIR)/$(TARGET).elf $(BUILD_DIR)/$(TARGET).hex $(BUILD_DIR)/$(TARGET).bin + + +####################################### +# build the application +####################################### +# list of objects +OBJECTS = $(addprefix $(BUILD_DIR)/,$(notdir $(C_SOURCES:.c=.o))) +vpath %.c $(sort $(dir $(C_SOURCES))) +# list of ASM program objects +OBJECTS += $(addprefix $(BUILD_DIR)/,$(notdir $(ASM_SOURCES:.s=.o))) +vpath %.s $(sort $(dir $(ASM_SOURCES))) + +$(BUILD_DIR)/%.o: %.c Makefile | $(BUILD_DIR) + $(CC) -c $(CFLAGS) -Wa,-a,-ad,-alms=$(BUILD_DIR)/$(notdir $(<:.c=.lst)) $< -o $@ + +$(BUILD_DIR)/%.o: %.s Makefile | $(BUILD_DIR) + $(AS) -c $(CFLAGS) $< -o $@ + +$(BUILD_DIR)/$(TARGET).elf: $(OBJECTS) Makefile + $(CC) $(OBJECTS) $(LDFLAGS) -o $@ + $(SZ) $@ + +$(BUILD_DIR)/%.hex: $(BUILD_DIR)/%.elf | $(BUILD_DIR) + $(HEX) $< $@ + +$(BUILD_DIR)/%.bin: $(BUILD_DIR)/%.elf | $(BUILD_DIR) + $(BIN) $< $@ + +$(BUILD_DIR): + mkdir $@ + +####################################### +# clean up +####################################### +clean: + -rm -fR $(BUILD_DIR) + +####################################### +# dependencies +####################################### +-include $(wildcard $(BUILD_DIR)/*.d) + +# *** EOF *** \ No newline at end of file diff --git a/firmware/targets/f7/cube/Src/adc.c b/firmware/targets/f7/cube/Src/adc.c new file mode 100644 index 00000000..e1294c43 --- /dev/null +++ b/firmware/targets/f7/cube/Src/adc.c @@ -0,0 +1,139 @@ +/** + ****************************************************************************** + * @file adc.c + * @brief This file provides code for the configuration + * of the ADC instances. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "adc.h" + +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ + +ADC_HandleTypeDef hadc1; + +/* ADC1 init function */ +void MX_ADC1_Init(void) +{ + + /* USER CODE BEGIN ADC1_Init 0 */ + + /* USER CODE END ADC1_Init 0 */ + + ADC_ChannelConfTypeDef sConfig = {0}; + + /* USER CODE BEGIN ADC1_Init 1 */ + + /* USER CODE END ADC1_Init 1 */ + /** Common config + */ + hadc1.Instance = ADC1; + hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1; + hadc1.Init.Resolution = ADC_RESOLUTION_12B; + hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT; + hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE; + hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV; + hadc1.Init.LowPowerAutoWait = DISABLE; + hadc1.Init.ContinuousConvMode = DISABLE; + hadc1.Init.NbrOfConversion = 1; + hadc1.Init.DiscontinuousConvMode = DISABLE; + hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START; + hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; + hadc1.Init.DMAContinuousRequests = DISABLE; + hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED; + hadc1.Init.OversamplingMode = DISABLE; + if (HAL_ADC_Init(&hadc1) != HAL_OK) + { + Error_Handler(); + } + /** Configure Regular Channel + */ + sConfig.Channel = ADC_CHANNEL_14; + sConfig.Rank = ADC_REGULAR_RANK_1; + sConfig.SamplingTime = ADC_SAMPLETIME_2CYCLES_5; + sConfig.SingleDiff = ADC_SINGLE_ENDED; + sConfig.OffsetNumber = ADC_OFFSET_NONE; + sConfig.Offset = 0; + if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) + { + Error_Handler(); + } + /* USER CODE BEGIN ADC1_Init 2 */ + + /* USER CODE END ADC1_Init 2 */ + +} + +void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle) +{ + + GPIO_InitTypeDef GPIO_InitStruct = {0}; + if(adcHandle->Instance==ADC1) + { + /* USER CODE BEGIN ADC1_MspInit 0 */ + + /* USER CODE END ADC1_MspInit 0 */ + /* ADC1 clock enable */ + __HAL_RCC_ADC_CLK_ENABLE(); + + __HAL_RCC_GPIOC_CLK_ENABLE(); + /**ADC1 GPIO Configuration + PC5 ------> ADC1_IN14 + */ + GPIO_InitStruct.Pin = RFID_RF_IN_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = GPIO_NOPULL; + HAL_GPIO_Init(RFID_RF_IN_GPIO_Port, &GPIO_InitStruct); + + /* ADC1 interrupt Init */ + HAL_NVIC_SetPriority(ADC1_IRQn, 5, 0); + HAL_NVIC_EnableIRQ(ADC1_IRQn); + /* USER CODE BEGIN ADC1_MspInit 1 */ + + /* USER CODE END ADC1_MspInit 1 */ + } +} + +void HAL_ADC_MspDeInit(ADC_HandleTypeDef* adcHandle) +{ + + if(adcHandle->Instance==ADC1) + { + /* USER CODE BEGIN ADC1_MspDeInit 0 */ + + /* USER CODE END ADC1_MspDeInit 0 */ + /* Peripheral clock disable */ + __HAL_RCC_ADC_CLK_DISABLE(); + + /**ADC1 GPIO Configuration + PC5 ------> ADC1_IN14 + */ + HAL_GPIO_DeInit(RFID_RF_IN_GPIO_Port, RFID_RF_IN_Pin); + + /* ADC1 interrupt Deinit */ + HAL_NVIC_DisableIRQ(ADC1_IRQn); + /* USER CODE BEGIN ADC1_MspDeInit 1 */ + + /* USER CODE END ADC1_MspDeInit 1 */ + } +} + +/* USER CODE BEGIN 1 */ + +/* USER CODE END 1 */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/cube/Src/aes.c b/firmware/targets/f7/cube/Src/aes.c new file mode 100644 index 00000000..06d5aacb --- /dev/null +++ b/firmware/targets/f7/cube/Src/aes.c @@ -0,0 +1,147 @@ +/** + ****************************************************************************** + * @file aes.c + * @brief This file provides code for the configuration + * of the AES instances. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "aes.h" + +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ + +CRYP_HandleTypeDef hcryp1; +__ALIGN_BEGIN static const uint32_t pKeyAES1[4] __ALIGN_END = { + 0x00000000,0x00000000,0x00000000,0x00000000}; +CRYP_HandleTypeDef hcryp2; +__ALIGN_BEGIN static const uint32_t pKeyAES2[4] __ALIGN_END = { + 0x00000000,0x00000000,0x00000000,0x00000000}; + +/* AES1 init function */ +void MX_AES1_Init(void) +{ + + /* USER CODE BEGIN AES1_Init 0 */ + + /* USER CODE END AES1_Init 0 */ + + /* USER CODE BEGIN AES1_Init 1 */ + + /* USER CODE END AES1_Init 1 */ + hcryp1.Instance = AES1; + hcryp1.Init.DataType = CRYP_DATATYPE_32B; + hcryp1.Init.KeySize = CRYP_KEYSIZE_128B; + hcryp1.Init.pKey = (uint32_t *)pKeyAES1; + hcryp1.Init.Algorithm = CRYP_AES_ECB; + hcryp1.Init.DataWidthUnit = CRYP_DATAWIDTHUNIT_WORD; + hcryp1.Init.KeyIVConfigSkip = CRYP_KEYIVCONFIG_ALWAYS; + if (HAL_CRYP_Init(&hcryp1) != HAL_OK) + { + Error_Handler(); + } + /* USER CODE BEGIN AES1_Init 2 */ + + /* USER CODE END AES1_Init 2 */ + +} +/* AES2 init function */ +void MX_AES2_Init(void) +{ + + /* USER CODE BEGIN AES2_Init 0 */ + + /* USER CODE END AES2_Init 0 */ + + /* USER CODE BEGIN AES2_Init 1 */ + + /* USER CODE END AES2_Init 1 */ + hcryp2.Instance = AES2; + hcryp2.Init.DataType = CRYP_DATATYPE_32B; + hcryp2.Init.KeySize = CRYP_KEYSIZE_128B; + hcryp2.Init.pKey = (uint32_t *)pKeyAES2; + hcryp2.Init.Algorithm = CRYP_AES_ECB; + hcryp2.Init.DataWidthUnit = CRYP_DATAWIDTHUNIT_WORD; + hcryp2.Init.KeyIVConfigSkip = CRYP_KEYIVCONFIG_ALWAYS; + if (HAL_CRYP_Init(&hcryp2) != HAL_OK) + { + Error_Handler(); + } + /* USER CODE BEGIN AES2_Init 2 */ + + /* USER CODE END AES2_Init 2 */ + +} + +void HAL_CRYP_MspInit(CRYP_HandleTypeDef* crypHandle) +{ + + if(crypHandle->Instance==AES1) + { + /* USER CODE BEGIN AES1_MspInit 0 */ + + /* USER CODE END AES1_MspInit 0 */ + /* AES1 clock enable */ + __HAL_RCC_AES1_CLK_ENABLE(); + /* USER CODE BEGIN AES1_MspInit 1 */ + + /* USER CODE END AES1_MspInit 1 */ + } + else if(crypHandle->Instance==AES2) + { + /* USER CODE BEGIN AES2_MspInit 0 */ + + /* USER CODE END AES2_MspInit 0 */ + /* AES2 clock enable */ + __HAL_RCC_AES2_CLK_ENABLE(); + /* USER CODE BEGIN AES2_MspInit 1 */ + + /* USER CODE END AES2_MspInit 1 */ + } +} + +void HAL_CRYP_MspDeInit(CRYP_HandleTypeDef* crypHandle) +{ + + if(crypHandle->Instance==AES1) + { + /* USER CODE BEGIN AES1_MspDeInit 0 */ + + /* USER CODE END AES1_MspDeInit 0 */ + /* Peripheral clock disable */ + __HAL_RCC_AES1_CLK_DISABLE(); + /* USER CODE BEGIN AES1_MspDeInit 1 */ + + /* USER CODE END AES1_MspDeInit 1 */ + } + else if(crypHandle->Instance==AES2) + { + /* USER CODE BEGIN AES2_MspDeInit 0 */ + + /* USER CODE END AES2_MspDeInit 0 */ + /* Peripheral clock disable */ + __HAL_RCC_AES2_CLK_DISABLE(); + /* USER CODE BEGIN AES2_MspDeInit 1 */ + + /* USER CODE END AES2_MspDeInit 1 */ + } +} + +/* USER CODE BEGIN 1 */ + +/* USER CODE END 1 */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/cube/Src/app_freertos.c b/firmware/targets/f7/cube/Src/app_freertos.c new file mode 100644 index 00000000..1d39e0a9 --- /dev/null +++ b/firmware/targets/f7/cube/Src/app_freertos.c @@ -0,0 +1,183 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * File Name : app_freertos.c + * Description : Code for freertos applications + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +/* Includes ------------------------------------------------------------------*/ +#include "FreeRTOS.h" +#include "task.h" +#include "main.h" +#include "cmsis_os.h" + +/* Private includes ----------------------------------------------------------*/ +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +/* Private typedef -----------------------------------------------------------*/ +/* USER CODE BEGIN PTD */ + +/* USER CODE END PTD */ + +/* Private define ------------------------------------------------------------*/ +/* USER CODE BEGIN PD */ + +/* USER CODE END PD */ + +/* Private macro -------------------------------------------------------------*/ +/* USER CODE BEGIN PM */ + +/* USER CODE END PM */ + +/* Private variables ---------------------------------------------------------*/ +/* USER CODE BEGIN Variables */ + +/* USER CODE END Variables */ +/* Definitions for app_main */ +osThreadId_t app_mainHandle; +const osThreadAttr_t app_main_attributes = { + .name = "app_main", + .priority = (osPriority_t) osPriorityNormal, + .stack_size = 1024 * 4 +}; + +/* Private function prototypes -----------------------------------------------*/ +/* USER CODE BEGIN FunctionPrototypes */ + +/* USER CODE END FunctionPrototypes */ + +void app(void *argument); + +void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */ + +/* Hook prototypes */ +void configureTimerForRunTimeStats(void); +unsigned long getRunTimeCounterValue(void); +void vApplicationIdleHook(void); +void vApplicationStackOverflowHook(TaskHandle_t xTask, signed char *pcTaskName); + +/* USER CODE BEGIN 1 */ +/* Functions needed when configGENERATE_RUN_TIME_STATS is on */ +__weak void configureTimerForRunTimeStats(void) +{ + +} + +__weak unsigned long getRunTimeCounterValue(void) +{ +return 0; +} +/* USER CODE END 1 */ + +/* USER CODE BEGIN 2 */ +void vApplicationIdleHook( void ) +{ + /* vApplicationIdleHook() will only be called if configUSE_IDLE_HOOK is set + to 1 in FreeRTOSConfig.h. It will be called on each iteration of the idle + task. It is essential that code added to this hook function never attempts + to block in any way (for example, call xQueueReceive() with a block time + specified, or call vTaskDelay()). If the application makes use of the + vTaskDelete() API function (as this demo application does) then it is also + important that vApplicationIdleHook() is permitted to return to its calling + function, because it is the responsibility of the idle task to clean up + memory allocated by the kernel to any task that has since been deleted. */ +} +/* USER CODE END 2 */ + +/* USER CODE BEGIN 4 */ +void vApplicationStackOverflowHook(TaskHandle_t xTask, signed char *pcTaskName) +{ + /* Run time stack overflow checking is performed if + configCHECK_FOR_STACK_OVERFLOW is defined to 1 or 2. This hook function is + called if a stack overflow is detected. */ +} +/* USER CODE END 4 */ + +/* USER CODE BEGIN VPORT_SUPPORT_TICKS_AND_SLEEP */ +__weak void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime ) +{ + // Generated when configUSE_TICKLESS_IDLE == 2. + // Function called in tasks.c (in portTASK_FUNCTION). + // TO BE COMPLETED or TO BE REPLACED by a user one, overriding that weak one. +} +/* USER CODE END VPORT_SUPPORT_TICKS_AND_SLEEP */ + +/** + * @brief FreeRTOS initialization + * @param None + * @retval None + */ +void MX_FREERTOS_Init(void) { + /* USER CODE BEGIN Init */ + + /* USER CODE END Init */ + + /* USER CODE BEGIN RTOS_MUTEX */ + /* add mutexes, ... */ + /* USER CODE END RTOS_MUTEX */ + + /* USER CODE BEGIN RTOS_SEMAPHORES */ + /* add semaphores, ... */ + /* USER CODE END RTOS_SEMAPHORES */ + + /* USER CODE BEGIN RTOS_TIMERS */ + /* start timers, add new ones, ... */ + /* USER CODE END RTOS_TIMERS */ + + /* USER CODE BEGIN RTOS_QUEUES */ + /* add queues, ... */ + /* USER CODE END RTOS_QUEUES */ + + /* Create the thread(s) */ + /* creation of app_main */ + app_mainHandle = osThreadNew(app, NULL, &app_main_attributes); + + /* USER CODE BEGIN RTOS_THREADS */ + /* add threads, ... */ + /* USER CODE END RTOS_THREADS */ + + /* USER CODE BEGIN RTOS_EVENTS */ + /* add events, ... */ + /* USER CODE END RTOS_EVENTS */ + +} + +/* USER CODE BEGIN Header_app */ +/** + * @brief Function implementing the app_main thread. + * @param argument: Not used + * @retval None + */ +/* USER CODE END Header_app */ +__weak void app(void *argument) +{ + /* USER CODE BEGIN app */ + /* Infinite loop */ + for(;;) + { + osDelay(1); + } + /* USER CODE END app */ +} + +/* Private application code --------------------------------------------------*/ +/* USER CODE BEGIN Application */ + +/* USER CODE END Application */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/cube/Src/comp.c b/firmware/targets/f7/cube/Src/comp.c new file mode 100644 index 00000000..00f9fa66 --- /dev/null +++ b/firmware/targets/f7/cube/Src/comp.c @@ -0,0 +1,113 @@ +/** + ****************************************************************************** + * @file comp.c + * @brief This file provides code for the configuration + * of the COMP instances. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "comp.h" + +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ + +COMP_HandleTypeDef hcomp1; + +/* COMP1 init function */ +void MX_COMP1_Init(void) +{ + + /* USER CODE BEGIN COMP1_Init 0 */ + + /* USER CODE END COMP1_Init 0 */ + + /* USER CODE BEGIN COMP1_Init 1 */ + + /* USER CODE END COMP1_Init 1 */ + hcomp1.Instance = COMP1; + hcomp1.Init.InputMinus = COMP_INPUT_MINUS_1_4VREFINT; + hcomp1.Init.InputPlus = COMP_INPUT_PLUS_IO1; + hcomp1.Init.OutputPol = COMP_OUTPUTPOL_NONINVERTED; + hcomp1.Init.Hysteresis = COMP_HYSTERESIS_HIGH; + hcomp1.Init.BlankingSrce = COMP_BLANKINGSRC_NONE; + hcomp1.Init.Mode = COMP_POWERMODE_MEDIUMSPEED; + hcomp1.Init.WindowMode = COMP_WINDOWMODE_DISABLE; + hcomp1.Init.TriggerMode = COMP_TRIGGERMODE_IT_RISING_FALLING; + if (HAL_COMP_Init(&hcomp1) != HAL_OK) + { + Error_Handler(); + } + /* USER CODE BEGIN COMP1_Init 2 */ + + /* USER CODE END COMP1_Init 2 */ + +} + +void HAL_COMP_MspInit(COMP_HandleTypeDef* compHandle) +{ + + GPIO_InitTypeDef GPIO_InitStruct = {0}; + if(compHandle->Instance==COMP1) + { + /* USER CODE BEGIN COMP1_MspInit 0 */ + + /* USER CODE END COMP1_MspInit 0 */ + + __HAL_RCC_GPIOC_CLK_ENABLE(); + /**COMP1 GPIO Configuration + PC5 ------> COMP1_INP + */ + GPIO_InitStruct.Pin = RFID_RF_IN_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = GPIO_NOPULL; + HAL_GPIO_Init(RFID_RF_IN_GPIO_Port, &GPIO_InitStruct); + + /* COMP1 interrupt Init */ + HAL_NVIC_SetPriority(COMP_IRQn, 5, 0); + HAL_NVIC_EnableIRQ(COMP_IRQn); + /* USER CODE BEGIN COMP1_MspInit 1 */ + + /* USER CODE END COMP1_MspInit 1 */ + } +} + +void HAL_COMP_MspDeInit(COMP_HandleTypeDef* compHandle) +{ + + if(compHandle->Instance==COMP1) + { + /* USER CODE BEGIN COMP1_MspDeInit 0 */ + + /* USER CODE END COMP1_MspDeInit 0 */ + + /**COMP1 GPIO Configuration + PC5 ------> COMP1_INP + */ + HAL_GPIO_DeInit(RFID_RF_IN_GPIO_Port, RFID_RF_IN_Pin); + + /* COMP1 interrupt Deinit */ + HAL_NVIC_DisableIRQ(COMP_IRQn); + /* USER CODE BEGIN COMP1_MspDeInit 1 */ + + /* USER CODE END COMP1_MspDeInit 1 */ + } +} + +/* USER CODE BEGIN 1 */ + +/* USER CODE END 1 */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/cube/Src/crc.c b/firmware/targets/f7/cube/Src/crc.c new file mode 100644 index 00000000..be2138ec --- /dev/null +++ b/firmware/targets/f7/cube/Src/crc.c @@ -0,0 +1,92 @@ +/** + ****************************************************************************** + * @file crc.c + * @brief This file provides code for the configuration + * of the CRC instances. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "crc.h" + +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ + +CRC_HandleTypeDef hcrc; + +/* CRC init function */ +void MX_CRC_Init(void) +{ + + /* USER CODE BEGIN CRC_Init 0 */ + + /* USER CODE END CRC_Init 0 */ + + /* USER CODE BEGIN CRC_Init 1 */ + + /* USER CODE END CRC_Init 1 */ + hcrc.Instance = CRC; + hcrc.Init.DefaultPolynomialUse = DEFAULT_POLYNOMIAL_ENABLE; + hcrc.Init.DefaultInitValueUse = DEFAULT_INIT_VALUE_ENABLE; + hcrc.Init.InputDataInversionMode = CRC_INPUTDATA_INVERSION_NONE; + hcrc.Init.OutputDataInversionMode = CRC_OUTPUTDATA_INVERSION_DISABLE; + hcrc.InputDataFormat = CRC_INPUTDATA_FORMAT_BYTES; + if (HAL_CRC_Init(&hcrc) != HAL_OK) + { + Error_Handler(); + } + /* USER CODE BEGIN CRC_Init 2 */ + + /* USER CODE END CRC_Init 2 */ + +} + +void HAL_CRC_MspInit(CRC_HandleTypeDef* crcHandle) +{ + + if(crcHandle->Instance==CRC) + { + /* USER CODE BEGIN CRC_MspInit 0 */ + + /* USER CODE END CRC_MspInit 0 */ + /* CRC clock enable */ + __HAL_RCC_CRC_CLK_ENABLE(); + /* USER CODE BEGIN CRC_MspInit 1 */ + + /* USER CODE END CRC_MspInit 1 */ + } +} + +void HAL_CRC_MspDeInit(CRC_HandleTypeDef* crcHandle) +{ + + if(crcHandle->Instance==CRC) + { + /* USER CODE BEGIN CRC_MspDeInit 0 */ + + /* USER CODE END CRC_MspDeInit 0 */ + /* Peripheral clock disable */ + __HAL_RCC_CRC_CLK_DISABLE(); + /* USER CODE BEGIN CRC_MspDeInit 1 */ + + /* USER CODE END CRC_MspDeInit 1 */ + } +} + +/* USER CODE BEGIN 1 */ + +/* USER CODE END 1 */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/cube/Src/gpio.c b/firmware/targets/f7/cube/Src/gpio.c new file mode 100644 index 00000000..743c1f27 --- /dev/null +++ b/firmware/targets/f7/cube/Src/gpio.c @@ -0,0 +1,181 @@ +/** + ****************************************************************************** + * @file gpio.c + * @brief This file provides code for the configuration + * of all used GPIO pins. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "gpio.h" + +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ + +/*----------------------------------------------------------------------------*/ +/* Configure GPIO */ +/*----------------------------------------------------------------------------*/ +/* USER CODE BEGIN 1 */ + +/* USER CODE END 1 */ + +/** Configure pins as + * Analog + * Input + * Output + * EVENT_OUT + * EXTI +*/ +void MX_GPIO_Init(void) +{ + + GPIO_InitTypeDef GPIO_InitStruct = {0}; + + /* GPIO Ports Clock Enable */ + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOH_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOE_CLK_ENABLE(); + __HAL_RCC_GPIOD_CLK_ENABLE(); + + /*Configure GPIO pin Output Level */ + HAL_GPIO_WritePin(GPIOA, RFID_PULL_Pin|VIBRO_Pin, GPIO_PIN_RESET); + + /*Configure GPIO pin Output Level */ + HAL_GPIO_WritePin(PERIPH_POWER_GPIO_Port, PERIPH_POWER_Pin, GPIO_PIN_SET); + + /*Configure GPIO pin Output Level */ + HAL_GPIO_WritePin(RF_SW_0_GPIO_Port, RF_SW_0_Pin, GPIO_PIN_RESET); + + /*Configure GPIO pin Output Level */ + HAL_GPIO_WritePin(GPIOB, DISPLAY_RST_Pin|DISPLAY_DI_Pin, GPIO_PIN_RESET); + + /*Configure GPIO pin Output Level */ + HAL_GPIO_WritePin(NFC_CS_GPIO_Port, NFC_CS_Pin, GPIO_PIN_SET); + + /*Configure GPIO pin Output Level */ + HAL_GPIO_WritePin(GPIOC, DISPLAY_CS_Pin|SD_CS_Pin, GPIO_PIN_SET); + + /*Configure GPIO pin Output Level */ + HAL_GPIO_WritePin(CC1101_CS_GPIO_Port, CC1101_CS_Pin, GPIO_PIN_SET); + + /*Configure GPIO pin : PtPin */ + GPIO_InitStruct.Pin = BUTTON_BACK_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING; + GPIO_InitStruct.Pull = GPIO_PULLUP; + HAL_GPIO_Init(BUTTON_BACK_GPIO_Port, &GPIO_InitStruct); + + /*Configure GPIO pin : PtPin */ + GPIO_InitStruct.Pin = BUTTON_OK_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING; + GPIO_InitStruct.Pull = GPIO_NOPULL; + HAL_GPIO_Init(BUTTON_OK_GPIO_Port, &GPIO_InitStruct); + + /*Configure GPIO pins : PCPin PCPin PCPin */ + GPIO_InitStruct.Pin = PC0_Pin|PC1_Pin|PC3_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = GPIO_NOPULL; + HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); + + /*Configure GPIO pins : PAPin PAPin PAPin PAPin + PAPin */ + GPIO_InitStruct.Pin = CC1101_G0_Pin|PA4_Pin|PA6_Pin|PA7_Pin + |RFID_CARRIER_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = GPIO_NOPULL; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + /*Configure GPIO pins : PAPin PAPin */ + GPIO_InitStruct.Pin = RFID_PULL_Pin|VIBRO_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + /*Configure GPIO pin : PtPin */ + GPIO_InitStruct.Pin = PERIPH_POWER_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + HAL_GPIO_Init(PERIPH_POWER_GPIO_Port, &GPIO_InitStruct); + + /*Configure GPIO pins : PCPin PCPin */ + GPIO_InitStruct.Pin = RF_SW_0_Pin|DISPLAY_CS_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); + + /*Configure GPIO pins : PBPin PBPin PBPin */ + GPIO_InitStruct.Pin = PB2_Pin|iBTN_Pin|PB3_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = GPIO_NOPULL; + HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); + + /*Configure GPIO pins : PBPin PBPin PBPin */ + GPIO_InitStruct.Pin = BUTTON_UP_Pin|BUTTON_LEFT_Pin|BUTTON_RIGHT_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING; + GPIO_InitStruct.Pull = GPIO_PULLUP; + HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); + + /*Configure GPIO pins : PBPin PBPin */ + GPIO_InitStruct.Pin = DISPLAY_RST_Pin|DISPLAY_DI_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); + + /*Configure GPIO pin : PtPin */ + GPIO_InitStruct.Pin = NFC_CS_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + HAL_GPIO_Init(NFC_CS_GPIO_Port, &GPIO_InitStruct); + + /*Configure GPIO pins : PCPin PCPin */ + GPIO_InitStruct.Pin = BUTTON_DOWN_Pin|SD_CD_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_INPUT; + GPIO_InitStruct.Pull = GPIO_NOPULL; + HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); + + /*Configure GPIO pin : PtPin */ + GPIO_InitStruct.Pin = SD_CS_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + HAL_GPIO_Init(SD_CS_GPIO_Port, &GPIO_InitStruct); + + /*Configure GPIO pin : PtPin */ + GPIO_InitStruct.Pin = CC1101_CS_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + HAL_GPIO_Init(CC1101_CS_GPIO_Port, &GPIO_InitStruct); + + /* EXTI interrupt init*/ + HAL_NVIC_SetPriority(EXTI3_IRQn, 5, 0); + HAL_NVIC_EnableIRQ(EXTI3_IRQn); + + HAL_NVIC_SetPriority(EXTI15_10_IRQn, 5, 0); + HAL_NVIC_EnableIRQ(EXTI15_10_IRQn); + +} + +/* USER CODE BEGIN 2 */ + +/* USER CODE END 2 */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/cube/Src/i2c.c b/firmware/targets/f7/cube/Src/i2c.c new file mode 100644 index 00000000..507de62c --- /dev/null +++ b/firmware/targets/f7/cube/Src/i2c.c @@ -0,0 +1,83 @@ +/** + ****************************************************************************** + * @file i2c.c + * @brief This file provides code for the configuration + * of the I2C instances. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "i2c.h" + +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ + +/* I2C1 init function */ +void MX_I2C1_Init(void) +{ + + /* USER CODE BEGIN I2C1_Init 0 */ + + /* USER CODE END I2C1_Init 0 */ + + LL_I2C_InitTypeDef I2C_InitStruct = {0}; + + LL_GPIO_InitTypeDef GPIO_InitStruct = {0}; + + LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA); + /**I2C1 GPIO Configuration + PA9 ------> I2C1_SCL + PA10 ------> I2C1_SDA + */ + GPIO_InitStruct.Pin = LL_GPIO_PIN_9|LL_GPIO_PIN_10; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE; + GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_OPENDRAIN; + GPIO_InitStruct.Pull = LL_GPIO_PULL_UP; + GPIO_InitStruct.Alternate = LL_GPIO_AF_4; + LL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + /* Peripheral clock enable */ + LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C1); + + /* USER CODE BEGIN I2C1_Init 1 */ + + /* USER CODE END I2C1_Init 1 */ + /** I2C Initialization + */ + I2C_InitStruct.PeripheralMode = LL_I2C_MODE_I2C; + I2C_InitStruct.Timing = 0x10707DBC; + I2C_InitStruct.AnalogFilter = LL_I2C_ANALOGFILTER_ENABLE; + I2C_InitStruct.DigitalFilter = 0; + I2C_InitStruct.OwnAddress1 = 0; + I2C_InitStruct.TypeAcknowledge = LL_I2C_ACK; + I2C_InitStruct.OwnAddrSize = LL_I2C_OWNADDRESS1_7BIT; + LL_I2C_Init(I2C1, &I2C_InitStruct); + LL_I2C_EnableAutoEndMode(I2C1); + LL_I2C_SetOwnAddress2(I2C1, 0, LL_I2C_OWNADDRESS2_NOMASK); + LL_I2C_DisableOwnAddress2(I2C1); + LL_I2C_DisableGeneralCall(I2C1); + LL_I2C_EnableClockStretching(I2C1); + /* USER CODE BEGIN I2C1_Init 2 */ + + /* USER CODE END I2C1_Init 2 */ + +} + +/* USER CODE BEGIN 1 */ + +/* USER CODE END 1 */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/cube/Src/main.c b/firmware/targets/f7/cube/Src/main.c new file mode 100644 index 00000000..c8cada7b --- /dev/null +++ b/firmware/targets/f7/cube/Src/main.c @@ -0,0 +1,290 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file : main.c + * @brief : Main program body + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* USER CODE END Header */ +/* Includes ------------------------------------------------------------------*/ +#include "main.h" +#include "cmsis_os.h" +#include "adc.h" +#include "aes.h" +#include "comp.h" +#include "crc.h" +#include "i2c.h" +#include "pka.h" +#include "rf.h" +#include "rng.h" +#include "rtc.h" +#include "spi.h" +#include "tim.h" +#include "usart.h" +#include "usb_device.h" +#include "gpio.h" + +/* Private includes ----------------------------------------------------------*/ +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +/* Private typedef -----------------------------------------------------------*/ +/* USER CODE BEGIN PTD */ + +/* USER CODE END PTD */ + +/* Private define ------------------------------------------------------------*/ +/* USER CODE BEGIN PD */ +/* USER CODE END PD */ + +/* Private macro -------------------------------------------------------------*/ +/* USER CODE BEGIN PM */ + +/* USER CODE END PM */ + +/* Private variables ---------------------------------------------------------*/ + +/* USER CODE BEGIN PV */ + +/* USER CODE END PV */ + +/* Private function prototypes -----------------------------------------------*/ +void SystemClock_Config(void); +void MX_FREERTOS_Init(void); +/* USER CODE BEGIN PFP */ + +/* USER CODE END PFP */ + +/* Private user code ---------------------------------------------------------*/ +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ + +/** + * @brief The application entry point. + * @retval int + */ +int main(void) +{ + /* USER CODE BEGIN 1 */ + + /* USER CODE END 1 */ + + /* MCU Configuration--------------------------------------------------------*/ + + /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ + HAL_Init(); + + /* USER CODE BEGIN Init */ + + /* USER CODE END Init */ + + /* Configure the system clock */ + SystemClock_Config(); + + /* USER CODE BEGIN SysInit */ + + /* USER CODE END SysInit */ + + /* Initialize all configured peripherals */ + MX_GPIO_Init(); + MX_ADC1_Init(); + MX_I2C1_Init(); + MX_RTC_Init(); + MX_SPI1_Init(); + MX_SPI2_Init(); + MX_USB_Device_Init(); + MX_TIM1_Init(); + MX_TIM2_Init(); + MX_TIM16_Init(); + MX_COMP1_Init(); + MX_RF_Init(); + MX_PKA_Init(); + MX_RNG_Init(); + MX_AES1_Init(); + MX_AES2_Init(); + MX_CRC_Init(); + MX_USART1_UART_Init(); + /* USER CODE BEGIN 2 */ + + /* USER CODE END 2 */ + + /* Init scheduler */ + osKernelInitialize(); /* Call init function for freertos objects (in freertos.c) */ + MX_FREERTOS_Init(); + /* Start scheduler */ + osKernelStart(); + + /* We should never get here as control is now taken by the scheduler */ + /* Infinite loop */ + /* USER CODE BEGIN WHILE */ + while (1) + { + /* USER CODE END WHILE */ + + /* USER CODE BEGIN 3 */ + } + /* USER CODE END 3 */ +} + +/** + * @brief System Clock Configuration + * @retval None + */ +void SystemClock_Config(void) +{ + LL_FLASH_SetLatency(LL_FLASH_LATENCY_3); + while(LL_FLASH_GetLatency() != LL_FLASH_LATENCY_3) + { + } + + /* HSE configuration and activation */ + LL_RCC_HSE_Enable(); + while(LL_RCC_HSE_IsReady() != 1) + { + } + + /* HSI configuration and activation */ + LL_RCC_HSI_Enable(); + while(LL_RCC_HSI_IsReady() != 1) + { + } + + LL_PWR_EnableBkUpAccess(); + if(LL_RCC_GetRTCClockSource() != LL_RCC_RTC_CLKSOURCE_LSE) + { + LL_RCC_ForceBackupDomainReset(); + LL_RCC_ReleaseBackupDomainReset(); + } + LL_RCC_LSE_SetDriveCapability(LL_RCC_LSEDRIVE_MEDIUMLOW); + LL_RCC_LSE_Enable(); + + /* Wait till LSE is ready */ + while(LL_RCC_LSE_IsReady() != 1) + { + } + + LL_RCC_HSE_EnableCSS(); + LL_RCC_LSE_EnableCSS(); + /* Main PLL configuration and activation */ + LL_RCC_PLL_ConfigDomain_SYS(LL_RCC_PLLSOURCE_HSE, LL_RCC_PLLM_DIV_2, 8, LL_RCC_PLLR_DIV_2); + LL_RCC_PLL_Enable(); + LL_RCC_PLL_EnableDomain_SYS(); + while(LL_RCC_PLL_IsReady() != 1) + { + } + + LL_RCC_PLLSAI1_ConfigDomain_48M(LL_RCC_PLLSOURCE_HSE, LL_RCC_PLLM_DIV_2, 6, LL_RCC_PLLSAI1Q_DIV_2); + LL_RCC_PLLSAI1_ConfigDomain_ADC(LL_RCC_PLLSOURCE_HSE, LL_RCC_PLLM_DIV_2, 6, LL_RCC_PLLSAI1R_DIV_2); + LL_RCC_PLLSAI1_Enable(); + LL_RCC_PLLSAI1_EnableDomain_48M(); + LL_RCC_PLLSAI1_EnableDomain_ADC(); + + /* Wait till PLLSAI1 is ready */ + while(LL_RCC_PLLSAI1_IsReady() != 1) + { + } + + /* Sysclk activation on the main PLL */ + /* Set CPU1 prescaler*/ + LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1); + + /* Set CPU2 prescaler*/ + LL_C2_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_2); + + LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL); + while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL) + { + } + + /* Set AHB SHARED prescaler*/ + LL_RCC_SetAHB4Prescaler(LL_RCC_SYSCLK_DIV_1); + + /* Set APB1 prescaler*/ + LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_1); + + /* Set APB2 prescaler*/ + LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_1); + + /* Disable MSI */ + LL_RCC_MSI_Disable(); + while(LL_RCC_MSI_IsReady() != 0) + { + } + + /* Update CMSIS variable (which can be updated also through SystemCoreClockUpdate function) */ + LL_SetSystemCoreClock(64000000); + + /* Update the time base */ + if (HAL_InitTick (TICK_INT_PRIORITY) != HAL_OK) + { + Error_Handler(); + } + if(LL_RCC_GetRTCClockSource() != LL_RCC_RTC_CLKSOURCE_LSE) + { + LL_RCC_SetRTCClockSource(LL_RCC_RTC_CLKSOURCE_LSE); + } + LL_RCC_EnableRTC(); + LL_RCC_SetUSARTClockSource(LL_RCC_USART1_CLKSOURCE_PCLK2); + LL_RCC_SetADCClockSource(LL_RCC_ADC_CLKSOURCE_PLLSAI1); + LL_RCC_SetI2CClockSource(LL_RCC_I2C1_CLKSOURCE_PCLK1); + LL_RCC_SetRNGClockSource(LL_RCC_RNG_CLKSOURCE_CLK48); + LL_RCC_SetUSBClockSource(LL_RCC_USB_CLKSOURCE_PLLSAI1); + LL_RCC_SetCLK48ClockSource(LL_RCC_CLK48_CLKSOURCE_PLLSAI1); + LL_RCC_SetSMPSClockSource(LL_RCC_SMPS_CLKSOURCE_HSE); + LL_RCC_SetSMPSPrescaler(LL_RCC_SMPS_DIV_1); + LL_RCC_SetRFWKPClockSource(LL_RCC_RFWKP_CLKSOURCE_LSE); + /* USER CODE BEGIN Smps */ + + /* USER CODE END Smps */ +} + +/* USER CODE BEGIN 4 */ + +/* USER CODE END 4 */ + +/** + * @brief This function is executed in case of error occurrence. + * @retval None + */ +void Error_Handler(void) +{ + /* USER CODE BEGIN Error_Handler_Debug */ + /* User can add his own implementation to report the HAL error return state */ + __disable_irq(); + while (1) + { + } + /* USER CODE END Error_Handler_Debug */ +} + +#ifdef USE_FULL_ASSERT +/** + * @brief Reports the name of the source file and the source line number + * where the assert_param error has occurred. + * @param file: pointer to the source file name + * @param line: assert_param error line source number + * @retval None + */ +void assert_failed(uint8_t *file, uint32_t line) +{ + /* USER CODE BEGIN 6 */ + /* User can add his own implementation to report the file name and line number, + ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ + /* USER CODE END 6 */ +} +#endif /* USE_FULL_ASSERT */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/cube/Src/pka.c b/firmware/targets/f7/cube/Src/pka.c new file mode 100644 index 00000000..9728cf5e --- /dev/null +++ b/firmware/targets/f7/cube/Src/pka.c @@ -0,0 +1,87 @@ +/** + ****************************************************************************** + * @file pka.c + * @brief This file provides code for the configuration + * of the PKA instances. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "pka.h" + +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ + +PKA_HandleTypeDef hpka; + +/* PKA init function */ +void MX_PKA_Init(void) +{ + + /* USER CODE BEGIN PKA_Init 0 */ + + /* USER CODE END PKA_Init 0 */ + + /* USER CODE BEGIN PKA_Init 1 */ + + /* USER CODE END PKA_Init 1 */ + hpka.Instance = PKA; + if (HAL_PKA_Init(&hpka) != HAL_OK) + { + Error_Handler(); + } + /* USER CODE BEGIN PKA_Init 2 */ + + /* USER CODE END PKA_Init 2 */ + +} + +void HAL_PKA_MspInit(PKA_HandleTypeDef* pkaHandle) +{ + + if(pkaHandle->Instance==PKA) + { + /* USER CODE BEGIN PKA_MspInit 0 */ + + /* USER CODE END PKA_MspInit 0 */ + /* PKA clock enable */ + __HAL_RCC_PKA_CLK_ENABLE(); + /* USER CODE BEGIN PKA_MspInit 1 */ + + /* USER CODE END PKA_MspInit 1 */ + } +} + +void HAL_PKA_MspDeInit(PKA_HandleTypeDef* pkaHandle) +{ + + if(pkaHandle->Instance==PKA) + { + /* USER CODE BEGIN PKA_MspDeInit 0 */ + + /* USER CODE END PKA_MspDeInit 0 */ + /* Peripheral clock disable */ + __HAL_RCC_PKA_CLK_DISABLE(); + /* USER CODE BEGIN PKA_MspDeInit 1 */ + + /* USER CODE END PKA_MspDeInit 1 */ + } +} + +/* USER CODE BEGIN 1 */ + +/* USER CODE END 1 */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/cube/Src/rf.c b/firmware/targets/f7/cube/Src/rf.c new file mode 100644 index 00000000..5682dd9d --- /dev/null +++ b/firmware/targets/f7/cube/Src/rf.c @@ -0,0 +1,48 @@ +/** + ****************************************************************************** + * @file rf.c + * @brief This file provides code for the configuration + * of the RF instances. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "rf.h" + +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ + +/* RF init function */ +void MX_RF_Init(void) +{ + + /* USER CODE BEGIN RF_Init 0 */ + + /* USER CODE END RF_Init 0 */ + + /* USER CODE BEGIN RF_Init 1 */ + + /* USER CODE END RF_Init 1 */ + /* USER CODE BEGIN RF_Init 2 */ + + /* USER CODE END RF_Init 2 */ + +} + +/* USER CODE BEGIN 1 */ + +/* USER CODE END 1 */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/cube/Src/rng.c b/firmware/targets/f7/cube/Src/rng.c new file mode 100644 index 00000000..ba70ae7b --- /dev/null +++ b/firmware/targets/f7/cube/Src/rng.c @@ -0,0 +1,88 @@ +/** + ****************************************************************************** + * @file rng.c + * @brief This file provides code for the configuration + * of the RNG instances. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "rng.h" + +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ + +RNG_HandleTypeDef hrng; + +/* RNG init function */ +void MX_RNG_Init(void) +{ + + /* USER CODE BEGIN RNG_Init 0 */ + + /* USER CODE END RNG_Init 0 */ + + /* USER CODE BEGIN RNG_Init 1 */ + + /* USER CODE END RNG_Init 1 */ + hrng.Instance = RNG; + hrng.Init.ClockErrorDetection = RNG_CED_ENABLE; + if (HAL_RNG_Init(&hrng) != HAL_OK) + { + Error_Handler(); + } + /* USER CODE BEGIN RNG_Init 2 */ + + /* USER CODE END RNG_Init 2 */ + +} + +void HAL_RNG_MspInit(RNG_HandleTypeDef* rngHandle) +{ + + if(rngHandle->Instance==RNG) + { + /* USER CODE BEGIN RNG_MspInit 0 */ + + /* USER CODE END RNG_MspInit 0 */ + /* RNG clock enable */ + __HAL_RCC_RNG_CLK_ENABLE(); + /* USER CODE BEGIN RNG_MspInit 1 */ + + /* USER CODE END RNG_MspInit 1 */ + } +} + +void HAL_RNG_MspDeInit(RNG_HandleTypeDef* rngHandle) +{ + + if(rngHandle->Instance==RNG) + { + /* USER CODE BEGIN RNG_MspDeInit 0 */ + + /* USER CODE END RNG_MspDeInit 0 */ + /* Peripheral clock disable */ + __HAL_RCC_RNG_CLK_DISABLE(); + /* USER CODE BEGIN RNG_MspDeInit 1 */ + + /* USER CODE END RNG_MspDeInit 1 */ + } +} + +/* USER CODE BEGIN 1 */ + +/* USER CODE END 1 */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/cube/Src/rtc.c b/firmware/targets/f7/cube/Src/rtc.c new file mode 100644 index 00000000..2aaa7897 --- /dev/null +++ b/firmware/targets/f7/cube/Src/rtc.c @@ -0,0 +1,134 @@ +/** + ****************************************************************************** + * @file rtc.c + * @brief This file provides code for the configuration + * of the RTC instances. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "rtc.h" + +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ + +RTC_HandleTypeDef hrtc; + +/* RTC init function */ +void MX_RTC_Init(void) +{ + + /* USER CODE BEGIN RTC_Init 0 */ + + /* USER CODE END RTC_Init 0 */ + + RTC_TimeTypeDef sTime = {0}; + RTC_DateTypeDef sDate = {0}; + + /* USER CODE BEGIN RTC_Init 1 */ + + /* USER CODE END RTC_Init 1 */ + /** Initialize RTC Only + */ + hrtc.Instance = RTC; + hrtc.Init.HourFormat = RTC_HOURFORMAT_24; + hrtc.Init.AsynchPrediv = 127; + hrtc.Init.SynchPrediv = 255; + hrtc.Init.OutPut = RTC_OUTPUT_DISABLE; + hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH; + hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN; + hrtc.Init.OutPutRemap = RTC_OUTPUT_REMAP_NONE; + if (HAL_RTC_Init(&hrtc) != HAL_OK) + { + Error_Handler(); + } + + /* USER CODE BEGIN Check_RTC_BKUP */ + + /* USER CODE END Check_RTC_BKUP */ + + /** Initialize RTC and set the Time and Date + */ + sTime.Hours = 0x0; + sTime.Minutes = 0x0; + sTime.Seconds = 0x0; + sTime.SubSeconds = 0x0; + sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE; + sTime.StoreOperation = RTC_STOREOPERATION_RESET; + if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BCD) != HAL_OK) + { + Error_Handler(); + } + sDate.WeekDay = RTC_WEEKDAY_MONDAY; + sDate.Month = RTC_MONTH_JANUARY; + sDate.Date = 0x1; + sDate.Year = 0x0; + + if (HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BCD) != HAL_OK) + { + Error_Handler(); + } + /* USER CODE BEGIN RTC_Init 2 */ + + /* USER CODE END RTC_Init 2 */ + +} + +void HAL_RTC_MspInit(RTC_HandleTypeDef* rtcHandle) +{ + + if(rtcHandle->Instance==RTC) + { + /* USER CODE BEGIN RTC_MspInit 0 */ + + /* USER CODE END RTC_MspInit 0 */ + /* RTC clock enable */ + __HAL_RCC_RTC_ENABLE(); + __HAL_RCC_RTCAPB_CLK_ENABLE(); + + /* RTC interrupt Init */ + HAL_NVIC_SetPriority(TAMP_STAMP_LSECSS_IRQn, 5, 0); + HAL_NVIC_EnableIRQ(TAMP_STAMP_LSECSS_IRQn); + /* USER CODE BEGIN RTC_MspInit 1 */ + + /* USER CODE END RTC_MspInit 1 */ + } +} + +void HAL_RTC_MspDeInit(RTC_HandleTypeDef* rtcHandle) +{ + + if(rtcHandle->Instance==RTC) + { + /* USER CODE BEGIN RTC_MspDeInit 0 */ + + /* USER CODE END RTC_MspDeInit 0 */ + /* Peripheral clock disable */ + __HAL_RCC_RTC_DISABLE(); + __HAL_RCC_RTCAPB_CLK_DISABLE(); + + /* RTC interrupt Deinit */ + HAL_NVIC_DisableIRQ(TAMP_STAMP_LSECSS_IRQn); + /* USER CODE BEGIN RTC_MspDeInit 1 */ + + /* USER CODE END RTC_MspDeInit 1 */ + } +} + +/* USER CODE BEGIN 1 */ + +/* USER CODE END 1 */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/cube/Src/spi.c b/firmware/targets/f7/cube/Src/spi.c new file mode 100644 index 00000000..81864c8b --- /dev/null +++ b/firmware/targets/f7/cube/Src/spi.c @@ -0,0 +1,232 @@ +/** + ****************************************************************************** + * @file spi.c + * @brief This file provides code for the configuration + * of the SPI instances. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "spi.h" + +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ + +SPI_HandleTypeDef hspi1; +SPI_HandleTypeDef hspi2; + +/* SPI1 init function */ +void MX_SPI1_Init(void) +{ + + /* USER CODE BEGIN SPI1_Init 0 */ + + /* USER CODE END SPI1_Init 0 */ + + /* USER CODE BEGIN SPI1_Init 1 */ + + /* USER CODE END SPI1_Init 1 */ + hspi1.Instance = SPI1; + hspi1.Init.Mode = SPI_MODE_MASTER; + hspi1.Init.Direction = SPI_DIRECTION_2LINES; + hspi1.Init.DataSize = SPI_DATASIZE_8BIT; + hspi1.Init.CLKPolarity = SPI_POLARITY_LOW; + hspi1.Init.CLKPhase = SPI_PHASE_2EDGE; + hspi1.Init.NSS = SPI_NSS_SOFT; + hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16; + hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB; + hspi1.Init.TIMode = SPI_TIMODE_DISABLE; + hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; + hspi1.Init.CRCPolynomial = 7; + hspi1.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE; + hspi1.Init.NSSPMode = SPI_NSS_PULSE_DISABLE; + if (HAL_SPI_Init(&hspi1) != HAL_OK) + { + Error_Handler(); + } + /* USER CODE BEGIN SPI1_Init 2 */ + + /* USER CODE END SPI1_Init 2 */ + +} +/* SPI2 init function */ +void MX_SPI2_Init(void) +{ + + /* USER CODE BEGIN SPI2_Init 0 */ + + /* USER CODE END SPI2_Init 0 */ + + /* USER CODE BEGIN SPI2_Init 1 */ + + /* USER CODE END SPI2_Init 1 */ + hspi2.Instance = SPI2; + hspi2.Init.Mode = SPI_MODE_MASTER; + hspi2.Init.Direction = SPI_DIRECTION_2LINES; + hspi2.Init.DataSize = SPI_DATASIZE_8BIT; + hspi2.Init.CLKPolarity = SPI_POLARITY_LOW; + hspi2.Init.CLKPhase = SPI_PHASE_1EDGE; + hspi2.Init.NSS = SPI_NSS_SOFT; + hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16; + hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB; + hspi2.Init.TIMode = SPI_TIMODE_DISABLE; + hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; + hspi2.Init.CRCPolynomial = 7; + hspi2.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE; + hspi2.Init.NSSPMode = SPI_NSS_PULSE_ENABLE; + if (HAL_SPI_Init(&hspi2) != HAL_OK) + { + Error_Handler(); + } + /* USER CODE BEGIN SPI2_Init 2 */ + + /* USER CODE END SPI2_Init 2 */ + +} + +void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle) +{ + + GPIO_InitTypeDef GPIO_InitStruct = {0}; + if(spiHandle->Instance==SPI1) + { + /* USER CODE BEGIN SPI1_MspInit 0 */ + + /* USER CODE END SPI1_MspInit 0 */ + /* SPI1 clock enable */ + __HAL_RCC_SPI1_CLK_ENABLE(); + + __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); + /**SPI1 GPIO Configuration + PA5 ------> SPI1_SCK + PB4 ------> SPI1_MISO + PB5 ------> SPI1_MOSI + */ + GPIO_InitStruct.Pin = SPI_R_SCK_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStruct.Alternate = GPIO_AF5_SPI1; + HAL_GPIO_Init(SPI_R_SCK_GPIO_Port, &GPIO_InitStruct); + + GPIO_InitStruct.Pin = SPI_R_MISO_Pin|SPI_R_MOSI_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStruct.Alternate = GPIO_AF5_SPI1; + HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); + + /* USER CODE BEGIN SPI1_MspInit 1 */ + + /* USER CODE END SPI1_MspInit 1 */ + } + else if(spiHandle->Instance==SPI2) + { + /* USER CODE BEGIN SPI2_MspInit 0 */ + + /* USER CODE END SPI2_MspInit 0 */ + /* SPI2 clock enable */ + __HAL_RCC_SPI2_CLK_ENABLE(); + + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOD_CLK_ENABLE(); + /**SPI2 GPIO Configuration + PC2 ------> SPI2_MISO + PB15 ------> SPI2_MOSI + PD1 ------> SPI2_SCK + */ + GPIO_InitStruct.Pin = SPI_D_MISO_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStruct.Alternate = GPIO_AF5_SPI2; + HAL_GPIO_Init(SPI_D_MISO_GPIO_Port, &GPIO_InitStruct); + + GPIO_InitStruct.Pin = SPI_D_MOSI_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStruct.Alternate = GPIO_AF5_SPI2; + HAL_GPIO_Init(SPI_D_MOSI_GPIO_Port, &GPIO_InitStruct); + + GPIO_InitStruct.Pin = SPI_D_SCK_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStruct.Alternate = GPIO_AF5_SPI2; + HAL_GPIO_Init(SPI_D_SCK_GPIO_Port, &GPIO_InitStruct); + + /* USER CODE BEGIN SPI2_MspInit 1 */ + + /* USER CODE END SPI2_MspInit 1 */ + } +} + +void HAL_SPI_MspDeInit(SPI_HandleTypeDef* spiHandle) +{ + + if(spiHandle->Instance==SPI1) + { + /* USER CODE BEGIN SPI1_MspDeInit 0 */ + + /* USER CODE END SPI1_MspDeInit 0 */ + /* Peripheral clock disable */ + __HAL_RCC_SPI1_CLK_DISABLE(); + + /**SPI1 GPIO Configuration + PA5 ------> SPI1_SCK + PB4 ------> SPI1_MISO + PB5 ------> SPI1_MOSI + */ + HAL_GPIO_DeInit(SPI_R_SCK_GPIO_Port, SPI_R_SCK_Pin); + + HAL_GPIO_DeInit(GPIOB, SPI_R_MISO_Pin|SPI_R_MOSI_Pin); + + /* USER CODE BEGIN SPI1_MspDeInit 1 */ + + /* USER CODE END SPI1_MspDeInit 1 */ + } + else if(spiHandle->Instance==SPI2) + { + /* USER CODE BEGIN SPI2_MspDeInit 0 */ + + /* USER CODE END SPI2_MspDeInit 0 */ + /* Peripheral clock disable */ + __HAL_RCC_SPI2_CLK_DISABLE(); + + /**SPI2 GPIO Configuration + PC2 ------> SPI2_MISO + PB15 ------> SPI2_MOSI + PD1 ------> SPI2_SCK + */ + HAL_GPIO_DeInit(SPI_D_MISO_GPIO_Port, SPI_D_MISO_Pin); + + HAL_GPIO_DeInit(SPI_D_MOSI_GPIO_Port, SPI_D_MOSI_Pin); + + HAL_GPIO_DeInit(SPI_D_SCK_GPIO_Port, SPI_D_SCK_Pin); + + /* USER CODE BEGIN SPI2_MspDeInit 1 */ + + /* USER CODE END SPI2_MspDeInit 1 */ + } +} + +/* USER CODE BEGIN 1 */ + +/* USER CODE END 1 */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/cube/Src/stm32wbxx_hal_msp.c b/firmware/targets/f7/cube/Src/stm32wbxx_hal_msp.c new file mode 100644 index 00000000..48894f2f --- /dev/null +++ b/firmware/targets/f7/cube/Src/stm32wbxx_hal_msp.c @@ -0,0 +1,93 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file stm32wbxx_hal_msp.c + * @brief This file provides code for the MSP Initialization + * and de-Initialization codes. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +/* Includes ------------------------------------------------------------------*/ +#include "main.h" +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +/* Private typedef -----------------------------------------------------------*/ +/* USER CODE BEGIN TD */ + +/* USER CODE END TD */ + +/* Private define ------------------------------------------------------------*/ +/* USER CODE BEGIN Define */ + +/* USER CODE END Define */ + +/* Private macro -------------------------------------------------------------*/ +/* USER CODE BEGIN Macro */ + +/* USER CODE END Macro */ + +/* Private variables ---------------------------------------------------------*/ +/* USER CODE BEGIN PV */ + +/* USER CODE END PV */ + +/* Private function prototypes -----------------------------------------------*/ +/* USER CODE BEGIN PFP */ + +/* USER CODE END PFP */ + +/* External functions --------------------------------------------------------*/ +/* USER CODE BEGIN ExternalFunctions */ + +/* USER CODE END ExternalFunctions */ + +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ +/** + * Initializes the Global MSP. + */ +void HAL_MspInit(void) +{ + /* USER CODE BEGIN MspInit 0 */ + + /* USER CODE END MspInit 0 */ + + __HAL_RCC_HSEM_CLK_ENABLE(); + + /* System interrupt init*/ + /* PendSV_IRQn interrupt configuration */ + HAL_NVIC_SetPriority(PendSV_IRQn, 15, 0); + + /* Peripheral interrupt init */ + /* RCC_IRQn interrupt configuration */ + HAL_NVIC_SetPriority(RCC_IRQn, 5, 0); + HAL_NVIC_EnableIRQ(RCC_IRQn); + /* HSEM_IRQn interrupt configuration */ + HAL_NVIC_SetPriority(HSEM_IRQn, 5, 0); + HAL_NVIC_EnableIRQ(HSEM_IRQn); + + /* USER CODE BEGIN MspInit 1 */ + + /* USER CODE END MspInit 1 */ +} + +/* USER CODE BEGIN 1 */ + +/* USER CODE END 1 */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/cube/Src/stm32wbxx_it.c b/firmware/targets/f7/cube/Src/stm32wbxx_it.c new file mode 100644 index 00000000..707f5e06 --- /dev/null +++ b/firmware/targets/f7/cube/Src/stm32wbxx_it.c @@ -0,0 +1,326 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file stm32wbxx_it.c + * @brief Interrupt Service Routines. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +/* Includes ------------------------------------------------------------------*/ +#include "main.h" +#include "stm32wbxx_it.h" +#include "FreeRTOS.h" +#include "task.h" +/* Private includes ----------------------------------------------------------*/ +/* USER CODE BEGIN Includes */ +/* USER CODE END Includes */ + +/* Private typedef -----------------------------------------------------------*/ +/* USER CODE BEGIN TD */ + +/* USER CODE END TD */ + +/* Private define ------------------------------------------------------------*/ +/* USER CODE BEGIN PD */ + +/* USER CODE END PD */ + +/* Private macro -------------------------------------------------------------*/ +/* USER CODE BEGIN PM */ + +/* USER CODE END PM */ + +/* Private variables ---------------------------------------------------------*/ +/* USER CODE BEGIN PV */ + +/* USER CODE END PV */ + +/* Private function prototypes -----------------------------------------------*/ +/* USER CODE BEGIN PFP */ + +/* USER CODE END PFP */ + +/* Private user code ---------------------------------------------------------*/ +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ + +/* External variables --------------------------------------------------------*/ +extern PCD_HandleTypeDef hpcd_USB_FS; +extern ADC_HandleTypeDef hadc1; +extern COMP_HandleTypeDef hcomp1; +extern RTC_HandleTypeDef hrtc; +extern TIM_HandleTypeDef htim1; +extern TIM_HandleTypeDef htim2; +/* USER CODE BEGIN EV */ + +/* USER CODE END EV */ + +/******************************************************************************/ +/* Cortex Processor Interruption and Exception Handlers */ +/******************************************************************************/ +/** + * @brief This function handles Non maskable interrupt. + */ +void NMI_Handler(void) +{ + /* USER CODE BEGIN NonMaskableInt_IRQn 0 */ + + /* USER CODE END NonMaskableInt_IRQn 0 */ + /* USER CODE BEGIN NonMaskableInt_IRQn 1 */ + while (1) + { + } + /* USER CODE END NonMaskableInt_IRQn 1 */ +} + +/** + * @brief This function handles Hard fault interrupt. + */ +void HardFault_Handler(void) +{ + /* USER CODE BEGIN HardFault_IRQn 0 */ + + /* USER CODE END HardFault_IRQn 0 */ + while (1) + { + /* USER CODE BEGIN W1_HardFault_IRQn 0 */ + /* USER CODE END W1_HardFault_IRQn 0 */ + } +} + +/** + * @brief This function handles Memory management fault. + */ +void MemManage_Handler(void) +{ + /* USER CODE BEGIN MemoryManagement_IRQn 0 */ + + /* USER CODE END MemoryManagement_IRQn 0 */ + while (1) + { + /* USER CODE BEGIN W1_MemoryManagement_IRQn 0 */ + /* USER CODE END W1_MemoryManagement_IRQn 0 */ + } +} + +/** + * @brief This function handles Prefetch fault, memory access fault. + */ +void BusFault_Handler(void) +{ + /* USER CODE BEGIN BusFault_IRQn 0 */ + + /* USER CODE END BusFault_IRQn 0 */ + while (1) + { + /* USER CODE BEGIN W1_BusFault_IRQn 0 */ + /* USER CODE END W1_BusFault_IRQn 0 */ + } +} + +/** + * @brief This function handles Undefined instruction or illegal state. + */ +void UsageFault_Handler(void) +{ + /* USER CODE BEGIN UsageFault_IRQn 0 */ + + /* USER CODE END UsageFault_IRQn 0 */ + while (1) + { + /* USER CODE BEGIN W1_UsageFault_IRQn 0 */ + /* USER CODE END W1_UsageFault_IRQn 0 */ + } +} + +/** + * @brief This function handles Debug monitor. + */ +void DebugMon_Handler(void) +{ + /* USER CODE BEGIN DebugMonitor_IRQn 0 */ + + /* USER CODE END DebugMonitor_IRQn 0 */ + /* USER CODE BEGIN DebugMonitor_IRQn 1 */ + + /* USER CODE END DebugMonitor_IRQn 1 */ +} + +/** + * @brief This function handles System tick timer. + */ +void SysTick_Handler(void) +{ + /* USER CODE BEGIN SysTick_IRQn 0 */ + + /* USER CODE END SysTick_IRQn 0 */ + /* USER CODE BEGIN SysTick_IRQn 1 */ + + /* USER CODE END SysTick_IRQn 1 */ +} + +/******************************************************************************/ +/* STM32WBxx Peripheral Interrupt Handlers */ +/* Add here the Interrupt Handlers for the used peripherals. */ +/* For the available peripheral interrupt handler names, */ +/* please refer to the startup file (startup_stm32wbxx.s). */ +/******************************************************************************/ + +/** + * @brief This function handles RTC tamper and time stamp, CSS on LSE interrupts through EXTI line 18. + */ +void TAMP_STAMP_LSECSS_IRQHandler(void) +{ + /* USER CODE BEGIN TAMP_STAMP_LSECSS_IRQn 0 */ + + /* USER CODE END TAMP_STAMP_LSECSS_IRQn 0 */ + /* USER CODE BEGIN TAMP_STAMP_LSECSS_IRQn 1 */ + + /* USER CODE END TAMP_STAMP_LSECSS_IRQn 1 */ +} + +/** + * @brief This function handles RCC global interrupt. + */ +void RCC_IRQHandler(void) +{ + /* USER CODE BEGIN RCC_IRQn 0 */ + + /* USER CODE END RCC_IRQn 0 */ + /* USER CODE BEGIN RCC_IRQn 1 */ + + /* USER CODE END RCC_IRQn 1 */ +} + +/** + * @brief This function handles EXTI line3 interrupt. + */ +void EXTI3_IRQHandler(void) +{ + /* USER CODE BEGIN EXTI3_IRQn 0 */ + + /* USER CODE END EXTI3_IRQn 0 */ + HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_3); + /* USER CODE BEGIN EXTI3_IRQn 1 */ + + /* USER CODE END EXTI3_IRQn 1 */ +} + +/** + * @brief This function handles ADC1 global interrupt. + */ +void ADC1_IRQHandler(void) +{ + /* USER CODE BEGIN ADC1_IRQn 0 */ + + /* USER CODE END ADC1_IRQn 0 */ + HAL_ADC_IRQHandler(&hadc1); + /* USER CODE BEGIN ADC1_IRQn 1 */ + + /* USER CODE END ADC1_IRQn 1 */ +} + +/** + * @brief This function handles USB low priority interrupt, USB wake-up interrupt through EXTI line 28. + */ +void USB_LP_IRQHandler(void) +{ + /* USER CODE BEGIN USB_LP_IRQn 0 */ + + /* USER CODE END USB_LP_IRQn 0 */ + HAL_PCD_IRQHandler(&hpcd_USB_FS); + /* USER CODE BEGIN USB_LP_IRQn 1 */ + + /* USER CODE END USB_LP_IRQn 1 */ +} + +/** + * @brief This function handles COMP1 and COMP2 interrupts through EXTI lines 20 and 21. + */ +void COMP_IRQHandler(void) +{ + /* USER CODE BEGIN COMP_IRQn 0 */ + + /* USER CODE END COMP_IRQn 0 */ + HAL_COMP_IRQHandler(&hcomp1); + /* USER CODE BEGIN COMP_IRQn 1 */ + + /* USER CODE END COMP_IRQn 1 */ +} + +/** + * @brief This function handles TIM1 trigger and commutation interrupts and TIM17 global interrupt. + */ +void TIM1_TRG_COM_TIM17_IRQHandler(void) +{ + /* USER CODE BEGIN TIM1_TRG_COM_TIM17_IRQn 0 */ + + /* USER CODE END TIM1_TRG_COM_TIM17_IRQn 0 */ + HAL_TIM_IRQHandler(&htim1); + /* USER CODE BEGIN TIM1_TRG_COM_TIM17_IRQn 1 */ + + /* USER CODE END TIM1_TRG_COM_TIM17_IRQn 1 */ +} + +/** + * @brief This function handles TIM2 global interrupt. + */ +void TIM2_IRQHandler(void) +{ + /* USER CODE BEGIN TIM2_IRQn 0 */ + + /* USER CODE END TIM2_IRQn 0 */ + HAL_TIM_IRQHandler(&htim2); + /* USER CODE BEGIN TIM2_IRQn 1 */ + + /* USER CODE END TIM2_IRQn 1 */ +} + +/** + * @brief This function handles EXTI line[15:10] interrupts. + */ +void EXTI15_10_IRQHandler(void) +{ + /* USER CODE BEGIN EXTI15_10_IRQn 0 */ + + /* USER CODE END EXTI15_10_IRQn 0 */ + HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_10); + HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_11); + HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_12); + HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_13); + /* USER CODE BEGIN EXTI15_10_IRQn 1 */ + + /* USER CODE END EXTI15_10_IRQn 1 */ +} + +/** + * @brief This function handles HSEM global interrupt. + */ +void HSEM_IRQHandler(void) +{ + /* USER CODE BEGIN HSEM_IRQn 0 */ + + /* USER CODE END HSEM_IRQn 0 */ + HAL_HSEM_IRQHandler(); + /* USER CODE BEGIN HSEM_IRQn 1 */ + + /* USER CODE END HSEM_IRQn 1 */ +} + +/* USER CODE BEGIN 1 */ + +/* USER CODE END 1 */ +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/cube/Src/system_stm32wbxx.c b/firmware/targets/f7/cube/Src/system_stm32wbxx.c new file mode 100644 index 00000000..d0ff7d2d --- /dev/null +++ b/firmware/targets/f7/cube/Src/system_stm32wbxx.c @@ -0,0 +1,368 @@ +/** + ****************************************************************************** + * @file system_stm32wbxx.c + * @author MCD Application Team + * @brief CMSIS Cortex Device Peripheral Access Layer System Source File + * + * This file provides two functions and one global variable to be called from + * user application: + * - SystemInit(): This function is called at startup just after reset and + * before branch to main program. This call is made inside + * the "startup_stm32wbxx.s" file. + * + * - SystemCoreClock variable: Contains the core clock (HCLK), it can be used + * by the user application to setup the SysTick + * timer or configure other parameters. + * + * - SystemCoreClockUpdate(): Updates the variable SystemCoreClock and must + * be called whenever the core clock is changed + * during program execution. + * + * After each device reset the MSI (4 MHz) is used as system clock source. + * Then SystemInit() function is called, in "startup_stm32wbxx.s" file, to + * configure the system clock before to branch to main program. + * + * This file configures the system clock as follows: + *============================================================================= + *----------------------------------------------------------------------------- + * System Clock source | MSI + *----------------------------------------------------------------------------- + * SYSCLK(Hz) | 4000000 + *----------------------------------------------------------------------------- + * HCLK(Hz) | 4000000 + *----------------------------------------------------------------------------- + * AHB Prescaler | 1 + *----------------------------------------------------------------------------- + * APB1 Prescaler | 1 + *----------------------------------------------------------------------------- + * APB2 Prescaler | 1 + *----------------------------------------------------------------------------- + * PLL_M | 1 + *----------------------------------------------------------------------------- + * PLL_N | 8 + *----------------------------------------------------------------------------- + * PLL_P | 7 + *----------------------------------------------------------------------------- + * PLL_Q | 2 + *----------------------------------------------------------------------------- + * PLL_R | 2 + *----------------------------------------------------------------------------- + * PLLSAI1_P | NA + *----------------------------------------------------------------------------- + * PLLSAI1_Q | NA + *----------------------------------------------------------------------------- + * PLLSAI1_R | NA + *----------------------------------------------------------------------------- + * Require 48MHz for USB OTG FS, | Disabled + * SDIO and RNG clock | + *----------------------------------------------------------------------------- + *============================================================================= + ****************************************************************************** + * @attention + * + * Copyright (c) 2019-2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/** @addtogroup CMSIS + * @{ + */ + +/** @addtogroup stm32WBxx_system + * @{ + */ + +/** @addtogroup stm32WBxx_System_Private_Includes + * @{ + */ + +#include "stm32wbxx.h" + +#if !defined (HSE_VALUE) + #define HSE_VALUE (32000000UL) /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +#if !defined (MSI_VALUE) + #define MSI_VALUE (4000000UL) /*!< Value of the Internal oscillator in Hz*/ +#endif /* MSI_VALUE */ + +#if !defined (HSI_VALUE) + #define HSI_VALUE (16000000UL) /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI_VALUE */ + +#if !defined (LSI_VALUE) + #define LSI_VALUE (32000UL) /*!< Value of LSI in Hz*/ +#endif /* LSI_VALUE */ + +#if !defined (LSE_VALUE) + #define LSE_VALUE (32768UL) /*!< Value of LSE in Hz*/ +#endif /* LSE_VALUE */ + +/** + * @} + */ + +/** @addtogroup STM32WBxx_System_Private_TypesDefinitions + * @{ + */ + +/** + * @} + */ + +/** @addtogroup STM32WBxx_System_Private_Defines + * @{ + */ + +/* Note: Following vector table addresses must be defined in line with linker + configuration. */ +/*!< Uncomment the following line if you need to relocate CPU1 CM4 and/or CPU2 + CM0+ vector table anywhere in Sram or Flash. Else vector table will be kept + at address 0x00 which correspond to automatic remap of boot address selected */ +/* #define USER_VECT_TAB_ADDRESS */ +#if defined(USER_VECT_TAB_ADDRESS) + /*!< Uncomment this line for user vector table remap in Sram else user remap + will be done in Flash. */ +/* #define VECT_TAB_SRAM */ +#if defined(VECT_TAB_SRAM) +#define VECT_TAB_BASE_ADDRESS SRAM1_BASE /*!< Vector Table base address field. + This value must be a multiple of 0x200. */ +#define VECT_TAB_OFFSET 0x00000000U /*!< Vector Table base offset field. + This value must be a multiple of 0x200. */ +#else +#define VECT_TAB_BASE_ADDRESS FLASH_BASE /*!< Vector Table base address field. + This value must be a multiple of 0x200. */ +#define VECT_TAB_OFFSET 0x00000000U /*!< Vector Table base offset field. + This value must be a multiple of 0x200. */ +#endif +#endif + +/** + * @} + */ + +/** @addtogroup STM32WBxx_System_Private_Macros + * @{ + */ + +/** + * @} + */ + +/** @addtogroup STM32WBxx_System_Private_Variables + * @{ + */ + /* The SystemCoreClock variable is updated in three ways: + 1) by calling CMSIS function SystemCoreClockUpdate() + 2) by calling HAL API function HAL_RCC_GetHCLKFreq() + 3) each time HAL_RCC_ClockConfig() is called to configure the system clock frequency + Note: If you use this function to configure the system clock; then there + is no need to call the 2 first functions listed above, since SystemCoreClock + variable is updated automatically. + */ + uint32_t SystemCoreClock = 4000000UL ; /*CPU1: M4 on MSI clock after startup (4MHz)*/ + + const uint32_t AHBPrescTable[16UL] = {1UL, 3UL, 5UL, 1UL, 1UL, 6UL, 10UL, 32UL, 2UL, 4UL, 8UL, 16UL, 64UL, 128UL, 256UL, 512UL}; + + const uint32_t APBPrescTable[8UL] = {0UL, 0UL, 0UL, 0UL, 1UL, 2UL, 3UL, 4UL}; + + const uint32_t MSIRangeTable[16UL] = {100000UL, 200000UL, 400000UL, 800000UL, 1000000UL, 2000000UL, \ + 4000000UL, 8000000UL, 16000000UL, 24000000UL, 32000000UL, 48000000UL, 0UL, 0UL, 0UL, 0UL}; /* 0UL values are incorrect cases */ + +#if defined(STM32WB55xx) || defined(STM32WB5Mxx) || defined(STM32WB35xx) || defined (STM32WB15xx) || defined (STM32WB10xx) + const uint32_t SmpsPrescalerTable[4UL][6UL]={{1UL,3UL,2UL,2UL,1UL,2UL}, \ + {2UL,6UL,4UL,3UL,2UL,4UL}, \ + {4UL,12UL,8UL,6UL,4UL,8UL}, \ + {4UL,12UL,8UL,6UL,4UL,8UL}}; +#endif + +/** + * @} + */ + +/** @addtogroup STM32WBxx_System_Private_FunctionPrototypes + * @{ + */ + +/** + * @} + */ + +/** @addtogroup STM32WBxx_System_Private_Functions + * @{ + */ + +/** + * @brief Setup the microcontroller system. + * @param None + * @retval None + */ +void SystemInit(void) +{ +#if defined(USER_VECT_TAB_ADDRESS) + /* Configure the Vector Table location add offset address ------------------*/ + SCB->VTOR = VECT_TAB_BASE_ADDRESS | VECT_TAB_OFFSET; +#endif + + /* FPU settings ------------------------------------------------------------*/ + #if (__FPU_PRESENT == 1) && (__FPU_USED == 1) + SCB->CPACR |= ((3UL << (10UL*2UL))|(3UL << (11UL*2UL))); /* set CP10 and CP11 Full Access */ + #endif + + /* Reset the RCC clock configuration to the default reset state ------------*/ + /* Set MSION bit */ + RCC->CR |= RCC_CR_MSION; + + /* Reset CFGR register */ + RCC->CFGR = 0x00070000U; + + /* Reset PLLSAI1ON, PLLON, HSECSSON, HSEON, HSION, and MSIPLLON bits */ + RCC->CR &= (uint32_t)0xFAF6FEFBU; + + /*!< Reset LSI1 and LSI2 bits */ + RCC->CSR &= (uint32_t)0xFFFFFFFAU; + + /*!< Reset HSI48ON bit */ + RCC->CRRCR &= (uint32_t)0xFFFFFFFEU; + + /* Reset PLLCFGR register */ + RCC->PLLCFGR = 0x22041000U; + +#if defined(STM32WB55xx) || defined(STM32WB5Mxx) + /* Reset PLLSAI1CFGR register */ + RCC->PLLSAI1CFGR = 0x22041000U; +#endif + + /* Reset HSEBYP bit */ + RCC->CR &= 0xFFFBFFFFU; + + /* Disable all interrupts */ + RCC->CIER = 0x00000000; +} + +/** + * @brief Update SystemCoreClock variable according to Clock Register Values. + * The SystemCoreClock variable contains the core clock (HCLK), it can + * be used by the user application to setup the SysTick timer or configure + * other parameters. + * + * @note Each time the core clock (HCLK) changes, this function must be called + * to update SystemCoreClock variable value. Otherwise, any configuration + * based on this variable will be incorrect. + * + * @note - The system frequency computed by this function is not the real + * frequency in the chip. It is calculated based on the predefined + * constant and the selected clock source: + * + * - If SYSCLK source is MSI, SystemCoreClock will contain the MSI_VALUE(*) + * + * - If SYSCLK source is HSI, SystemCoreClock will contain the HSI_VALUE(**) + * + * - If SYSCLK source is HSE, SystemCoreClock will contain the HSE_VALUE(***) + * + * - If SYSCLK source is PLL, SystemCoreClock will contain the HSE_VALUE(***) + * or HSI_VALUE(*) or MSI_VALUE(*) multiplied/divided by the PLL factors. + * + * (*) MSI_VALUE is a constant defined in stm32wbxx_hal.h file (default value + * 4 MHz) but the real value may vary depending on the variations + * in voltage and temperature. + * + * (**) HSI_VALUE is a constant defined in stm32wbxx_hal_conf.h file (default value + * 16 MHz) but the real value may vary depending on the variations + * in voltage and temperature. + * + * (***) HSE_VALUE is a constant defined in stm32wbxx_hal_conf.h file (default value + * 32 MHz), user has to ensure that HSE_VALUE is same as the real + * frequency of the crystal used. Otherwise, this function may + * have wrong result. + * + * - The result of this function could be not correct when using fractional + * value for HSE crystal. + * + * @param None + * @retval None + */ +void SystemCoreClockUpdate(void) +{ + uint32_t tmp, msirange, pllvco, pllr, pllsource , pllm; + + /* Get MSI Range frequency--------------------------------------------------*/ + + /*MSI frequency range in Hz*/ + msirange = MSIRangeTable[(RCC->CR & RCC_CR_MSIRANGE) >> RCC_CR_MSIRANGE_Pos]; + + /* Get SYSCLK source -------------------------------------------------------*/ + switch (RCC->CFGR & RCC_CFGR_SWS) + { + case 0x00: /* MSI used as system clock source */ + SystemCoreClock = msirange; + break; + + case 0x04: /* HSI used as system clock source */ + /* HSI used as system clock source */ + SystemCoreClock = HSI_VALUE; + break; + + case 0x08: /* HSE used as system clock source */ + SystemCoreClock = HSE_VALUE; + break; + + case 0x0C: /* PLL used as system clock source */ + /* PLL_VCO = (HSE_VALUE or HSI_VALUE or MSI_VALUE/ PLLM) * PLLN + SYSCLK = PLL_VCO / PLLR + */ + pllsource = (RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC); + pllm = ((RCC->PLLCFGR & RCC_PLLCFGR_PLLM) >> RCC_PLLCFGR_PLLM_Pos) + 1UL ; + + if(pllsource == 0x02UL) /* HSI used as PLL clock source */ + { + pllvco = (HSI_VALUE / pllm); + } + else if(pllsource == 0x03UL) /* HSE used as PLL clock source */ + { + pllvco = (HSE_VALUE / pllm); + } + else /* MSI used as PLL clock source */ + { + pllvco = (msirange / pllm); + } + + pllvco = pllvco * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> RCC_PLLCFGR_PLLN_Pos); + pllr = (((RCC->PLLCFGR & RCC_PLLCFGR_PLLR) >> RCC_PLLCFGR_PLLR_Pos) + 1UL); + + SystemCoreClock = pllvco/pllr; + break; + + default: + SystemCoreClock = msirange; + break; + } + + /* Compute HCLK clock frequency --------------------------------------------*/ + /* Get HCLK1 prescaler */ + tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> RCC_CFGR_HPRE_Pos)]; + /* HCLK clock frequency */ + SystemCoreClock = SystemCoreClock / tmp; + +} + + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/cube/Src/tim.c b/firmware/targets/f7/cube/Src/tim.c new file mode 100644 index 00000000..1c38c1d7 --- /dev/null +++ b/firmware/targets/f7/cube/Src/tim.c @@ -0,0 +1,394 @@ +/** + ****************************************************************************** + * @file tim.c + * @brief This file provides code for the configuration + * of the TIM instances. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "tim.h" + +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ + +TIM_HandleTypeDef htim1; +TIM_HandleTypeDef htim2; +TIM_HandleTypeDef htim16; + +/* TIM1 init function */ +void MX_TIM1_Init(void) +{ + + /* USER CODE BEGIN TIM1_Init 0 */ + + /* USER CODE END TIM1_Init 0 */ + + TIM_ClockConfigTypeDef sClockSourceConfig = {0}; + TIM_MasterConfigTypeDef sMasterConfig = {0}; + TIM_OC_InitTypeDef sConfigOC = {0}; + TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0}; + + /* USER CODE BEGIN TIM1_Init 1 */ + + /* USER CODE END TIM1_Init 1 */ + htim1.Instance = TIM1; + htim1.Init.Prescaler = 0; + htim1.Init.CounterMode = TIM_COUNTERMODE_UP; + htim1.Init.Period = 65535; + htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; + htim1.Init.RepetitionCounter = 0; + htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; + if (HAL_TIM_Base_Init(&htim1) != HAL_OK) + { + Error_Handler(); + } + sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; + if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK) + { + Error_Handler(); + } + if (HAL_TIM_OC_Init(&htim1) != HAL_OK) + { + Error_Handler(); + } + if (HAL_TIM_PWM_Init(&htim1) != HAL_OK) + { + Error_Handler(); + } + sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; + sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET; + sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; + if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK) + { + Error_Handler(); + } + sConfigOC.OCMode = TIM_OCMODE_TIMING; + sConfigOC.Pulse = 0; + sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; + sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH; + sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; + sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET; + sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET; + if (HAL_TIM_OC_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1) != HAL_OK) + { + Error_Handler(); + } + sConfigOC.OCMode = TIM_OCMODE_PWM1; + if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_3) != HAL_OK) + { + Error_Handler(); + } + sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE; + sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE; + sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF; + sBreakDeadTimeConfig.DeadTime = 0; + sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE; + sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH; + sBreakDeadTimeConfig.BreakFilter = 0; + sBreakDeadTimeConfig.BreakAFMode = TIM_BREAK_AFMODE_INPUT; + sBreakDeadTimeConfig.Break2State = TIM_BREAK2_DISABLE; + sBreakDeadTimeConfig.Break2Polarity = TIM_BREAK2POLARITY_HIGH; + sBreakDeadTimeConfig.Break2Filter = 0; + sBreakDeadTimeConfig.Break2AFMode = TIM_BREAK_AFMODE_INPUT; + sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE; + if (HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig) != HAL_OK) + { + Error_Handler(); + } + /* USER CODE BEGIN TIM1_Init 2 */ + + /* USER CODE END TIM1_Init 2 */ + HAL_TIM_MspPostInit(&htim1); + +} +/* TIM2 init function */ +void MX_TIM2_Init(void) +{ + + /* USER CODE BEGIN TIM2_Init 0 */ + + /* USER CODE END TIM2_Init 0 */ + + TIM_ClockConfigTypeDef sClockSourceConfig = {0}; + TIM_MasterConfigTypeDef sMasterConfig = {0}; + TIM_IC_InitTypeDef sConfigIC = {0}; + + /* USER CODE BEGIN TIM2_Init 1 */ + + /* USER CODE END TIM2_Init 1 */ + htim2.Instance = TIM2; + htim2.Init.Prescaler = 64-1; + htim2.Init.CounterMode = TIM_COUNTERMODE_UP; + htim2.Init.Period = 4294967295; + htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; + htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; + if (HAL_TIM_Base_Init(&htim2) != HAL_OK) + { + Error_Handler(); + } + sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; + if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK) + { + Error_Handler(); + } + if (HAL_TIM_IC_Init(&htim2) != HAL_OK) + { + Error_Handler(); + } + sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; + sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; + if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK) + { + Error_Handler(); + } + sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_FALLING; + sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI; + sConfigIC.ICPrescaler = TIM_ICPSC_DIV1; + sConfigIC.ICFilter = 0; + if (HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_1) != HAL_OK) + { + Error_Handler(); + } + sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING; + sConfigIC.ICSelection = TIM_ICSELECTION_INDIRECTTI; + if (HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_2) != HAL_OK) + { + Error_Handler(); + } + /* USER CODE BEGIN TIM2_Init 2 */ + + /* USER CODE END TIM2_Init 2 */ + +} +/* TIM16 init function */ +void MX_TIM16_Init(void) +{ + + /* USER CODE BEGIN TIM16_Init 0 */ + + /* USER CODE END TIM16_Init 0 */ + + TIM_OC_InitTypeDef sConfigOC = {0}; + TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0}; + + /* USER CODE BEGIN TIM16_Init 1 */ + + /* USER CODE END TIM16_Init 1 */ + htim16.Instance = TIM16; + htim16.Init.Prescaler = 500 - 1; + htim16.Init.CounterMode = TIM_COUNTERMODE_UP; + htim16.Init.Period = 291; + htim16.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; + htim16.Init.RepetitionCounter = 0; + htim16.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; + if (HAL_TIM_Base_Init(&htim16) != HAL_OK) + { + Error_Handler(); + } + if (HAL_TIM_PWM_Init(&htim16) != HAL_OK) + { + Error_Handler(); + } + sConfigOC.OCMode = TIM_OCMODE_PWM1; + sConfigOC.Pulse = 145; + sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; + sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH; + sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; + sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET; + sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET; + if (HAL_TIM_PWM_ConfigChannel(&htim16, &sConfigOC, TIM_CHANNEL_1) != HAL_OK) + { + Error_Handler(); + } + sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE; + sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE; + sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF; + sBreakDeadTimeConfig.DeadTime = 0; + sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE; + sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH; + sBreakDeadTimeConfig.BreakFilter = 0; + sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE; + if (HAL_TIMEx_ConfigBreakDeadTime(&htim16, &sBreakDeadTimeConfig) != HAL_OK) + { + Error_Handler(); + } + /* USER CODE BEGIN TIM16_Init 2 */ + + /* USER CODE END TIM16_Init 2 */ + HAL_TIM_MspPostInit(&htim16); + +} + +void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle) +{ + + GPIO_InitTypeDef GPIO_InitStruct = {0}; + if(tim_baseHandle->Instance==TIM1) + { + /* USER CODE BEGIN TIM1_MspInit 0 */ + + /* USER CODE END TIM1_MspInit 0 */ + /* TIM1 clock enable */ + __HAL_RCC_TIM1_CLK_ENABLE(); + + /* TIM1 interrupt Init */ + HAL_NVIC_SetPriority(TIM1_TRG_COM_TIM17_IRQn, 5, 0); + HAL_NVIC_EnableIRQ(TIM1_TRG_COM_TIM17_IRQn); + /* USER CODE BEGIN TIM1_MspInit 1 */ + + /* USER CODE END TIM1_MspInit 1 */ + } + else if(tim_baseHandle->Instance==TIM2) + { + /* USER CODE BEGIN TIM2_MspInit 0 */ + + /* USER CODE END TIM2_MspInit 0 */ + /* TIM2 clock enable */ + __HAL_RCC_TIM2_CLK_ENABLE(); + + __HAL_RCC_GPIOA_CLK_ENABLE(); + /**TIM2 GPIO Configuration + PA0 ------> TIM2_CH1 + */ + GPIO_InitStruct.Pin = IR_RX_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStruct.Alternate = GPIO_AF1_TIM2; + HAL_GPIO_Init(IR_RX_GPIO_Port, &GPIO_InitStruct); + + /* TIM2 interrupt Init */ + HAL_NVIC_SetPriority(TIM2_IRQn, 5, 0); + HAL_NVIC_EnableIRQ(TIM2_IRQn); + /* USER CODE BEGIN TIM2_MspInit 1 */ + + /* USER CODE END TIM2_MspInit 1 */ + } + else if(tim_baseHandle->Instance==TIM16) + { + /* USER CODE BEGIN TIM16_MspInit 0 */ + + /* USER CODE END TIM16_MspInit 0 */ + /* TIM16 clock enable */ + __HAL_RCC_TIM16_CLK_ENABLE(); + /* USER CODE BEGIN TIM16_MspInit 1 */ + + /* USER CODE END TIM16_MspInit 1 */ + } +} +void HAL_TIM_MspPostInit(TIM_HandleTypeDef* timHandle) +{ + + GPIO_InitTypeDef GPIO_InitStruct = {0}; + if(timHandle->Instance==TIM1) + { + /* USER CODE BEGIN TIM1_MspPostInit 0 */ + + /* USER CODE END TIM1_MspPostInit 0 */ + __HAL_RCC_GPIOB_CLK_ENABLE(); + /**TIM1 GPIO Configuration + PB9 ------> TIM1_CH3N + PB13 ------> TIM1_CH1N + */ + GPIO_InitStruct.Pin = IR_TX_Pin|RFID_OUT_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStruct.Alternate = GPIO_AF1_TIM1; + HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); + + /* USER CODE BEGIN TIM1_MspPostInit 1 */ + + /* USER CODE END TIM1_MspPostInit 1 */ + } + else if(timHandle->Instance==TIM16) + { + /* USER CODE BEGIN TIM16_MspPostInit 0 */ + + /* USER CODE END TIM16_MspPostInit 0 */ + + __HAL_RCC_GPIOB_CLK_ENABLE(); + /**TIM16 GPIO Configuration + PB8 ------> TIM16_CH1 + */ + GPIO_InitStruct.Pin = SPEAKER_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStruct.Alternate = GPIO_AF14_TIM16; + HAL_GPIO_Init(SPEAKER_GPIO_Port, &GPIO_InitStruct); + + /* USER CODE BEGIN TIM16_MspPostInit 1 */ + + /* USER CODE END TIM16_MspPostInit 1 */ + } + +} + +void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* tim_baseHandle) +{ + + if(tim_baseHandle->Instance==TIM1) + { + /* USER CODE BEGIN TIM1_MspDeInit 0 */ + + /* USER CODE END TIM1_MspDeInit 0 */ + /* Peripheral clock disable */ + __HAL_RCC_TIM1_CLK_DISABLE(); + + /* TIM1 interrupt Deinit */ + HAL_NVIC_DisableIRQ(TIM1_TRG_COM_TIM17_IRQn); + /* USER CODE BEGIN TIM1_MspDeInit 1 */ + + /* USER CODE END TIM1_MspDeInit 1 */ + } + else if(tim_baseHandle->Instance==TIM2) + { + /* USER CODE BEGIN TIM2_MspDeInit 0 */ + + /* USER CODE END TIM2_MspDeInit 0 */ + /* Peripheral clock disable */ + __HAL_RCC_TIM2_CLK_DISABLE(); + + /**TIM2 GPIO Configuration + PA0 ------> TIM2_CH1 + */ + HAL_GPIO_DeInit(IR_RX_GPIO_Port, IR_RX_Pin); + + /* TIM2 interrupt Deinit */ + HAL_NVIC_DisableIRQ(TIM2_IRQn); + /* USER CODE BEGIN TIM2_MspDeInit 1 */ + + /* USER CODE END TIM2_MspDeInit 1 */ + } + else if(tim_baseHandle->Instance==TIM16) + { + /* USER CODE BEGIN TIM16_MspDeInit 0 */ + + /* USER CODE END TIM16_MspDeInit 0 */ + /* Peripheral clock disable */ + __HAL_RCC_TIM16_CLK_DISABLE(); + /* USER CODE BEGIN TIM16_MspDeInit 1 */ + + /* USER CODE END TIM16_MspDeInit 1 */ + } +} + +/* USER CODE BEGIN 1 */ + +/* USER CODE END 1 */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/cube/Src/usart.c b/firmware/targets/f7/cube/Src/usart.c new file mode 100644 index 00000000..0a0466dc --- /dev/null +++ b/firmware/targets/f7/cube/Src/usart.c @@ -0,0 +1,95 @@ +/** + ****************************************************************************** + * @file usart.c + * @brief This file provides code for the configuration + * of the USART instances. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "usart.h" + +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ + +/* USART1 init function */ + +void MX_USART1_UART_Init(void) +{ + + /* USER CODE BEGIN USART1_Init 0 */ + + /* USER CODE END USART1_Init 0 */ + + LL_USART_InitTypeDef USART_InitStruct = {0}; + + LL_GPIO_InitTypeDef GPIO_InitStruct = {0}; + + /* Peripheral clock enable */ + LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_USART1); + + LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB); + /**USART1 GPIO Configuration + PB6 ------> USART1_TX + PB7 ------> USART1_RX + */ + GPIO_InitStruct.Pin = LL_GPIO_PIN_6|LL_GPIO_PIN_7; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE; + GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW; + GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + GPIO_InitStruct.Alternate = LL_GPIO_AF_7; + LL_GPIO_Init(GPIOB, &GPIO_InitStruct); + + /* USER CODE BEGIN USART1_Init 1 */ + + /* USER CODE END USART1_Init 1 */ + USART_InitStruct.PrescalerValue = LL_USART_PRESCALER_DIV1; + USART_InitStruct.BaudRate = 115200; + USART_InitStruct.DataWidth = LL_USART_DATAWIDTH_8B; + USART_InitStruct.StopBits = LL_USART_STOPBITS_1; + USART_InitStruct.Parity = LL_USART_PARITY_NONE; + USART_InitStruct.TransferDirection = LL_USART_DIRECTION_TX; + USART_InitStruct.HardwareFlowControl = LL_USART_HWCONTROL_NONE; + USART_InitStruct.OverSampling = LL_USART_OVERSAMPLING_16; + LL_USART_Init(USART1, &USART_InitStruct); + LL_USART_SetTXFIFOThreshold(USART1, LL_USART_FIFOTHRESHOLD_1_8); + LL_USART_SetRXFIFOThreshold(USART1, LL_USART_FIFOTHRESHOLD_1_8); + LL_USART_DisableFIFO(USART1); + LL_USART_EnableAutoBaudRate(USART1); + LL_USART_SetAutoBaudRateMode(USART1, LL_USART_AUTOBAUD_DETECT_ON_STARTBIT); + LL_USART_ConfigAsyncMode(USART1); + + /* USER CODE BEGIN WKUPType USART1 */ + + /* USER CODE END WKUPType USART1 */ + + LL_USART_Enable(USART1); + + /* Polling USART1 initialisation */ + while(!(LL_USART_IsActiveFlag_TEACK(USART1))) + { + } + /* USER CODE BEGIN USART1_Init 2 */ + + /* USER CODE END USART1_Init 2 */ + +} + +/* USER CODE BEGIN 1 */ + +/* USER CODE END 1 */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/cube/Src/usb_device.c b/firmware/targets/f7/cube/Src/usb_device.c new file mode 100644 index 00000000..8871a778 --- /dev/null +++ b/firmware/targets/f7/cube/Src/usb_device.c @@ -0,0 +1,99 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file : usb_device.c + * @version : v3.0_Cube + * @brief : This file implements the USB Device + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +/* Includes ------------------------------------------------------------------*/ + +#include "usb_device.h" +#include "usbd_core.h" +#include "usbd_desc.h" +#include "usbd_cdc.h" +#include "usbd_cdc_if.h" + +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +/* USER CODE BEGIN PV */ +/* Private variables ---------------------------------------------------------*/ + +/* USER CODE END PV */ + +/* USER CODE BEGIN PFP */ +/* Private function prototypes -----------------------------------------------*/ + +/* USER CODE END PFP */ + +extern void Error_Handler(void); +/* USB Device Core handle declaration. */ +USBD_HandleTypeDef hUsbDeviceFS; +extern USBD_DescriptorsTypeDef CDC_Desc; + +/* + * -- Insert your variables declaration here -- + */ +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ + +/* + * -- Insert your external function declaration here -- + */ +/* USER CODE BEGIN 1 */ + +/* USER CODE END 1 */ + +/** + * Init USB device Library, add supported class and start the library + * @retval None + */ +void MX_USB_Device_Init(void) +{ + /* USER CODE BEGIN USB_Device_Init_PreTreatment */ + + /* USER CODE END USB_Device_Init_PreTreatment */ + + /* Init Device Library, add supported class and start the library. */ + if (USBD_Init(&hUsbDeviceFS, &CDC_Desc, DEVICE_FS) != USBD_OK) { + Error_Handler(); + } + if (USBD_RegisterClass(&hUsbDeviceFS, &USBD_CDC) != USBD_OK) { + Error_Handler(); + } + if (USBD_CDC_RegisterInterface(&hUsbDeviceFS, &USBD_Interface_fops_FS) != USBD_OK) { + Error_Handler(); + } + if (USBD_Start(&hUsbDeviceFS) != USBD_OK) { + Error_Handler(); + } + /* USER CODE BEGIN USB_Device_Init_PostTreatment */ + + /* USER CODE END USB_Device_Init_PostTreatment */ +} + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/cube/Src/usbd_cdc_if.c b/firmware/targets/f7/cube/Src/usbd_cdc_if.c new file mode 100644 index 00000000..d52d1e3e --- /dev/null +++ b/firmware/targets/f7/cube/Src/usbd_cdc_if.c @@ -0,0 +1,331 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file : usbd_cdc_if.c + * @version : v3.0_Cube + * @brief : Usb device for Virtual Com Port. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_cdc_if.h" + +/* USER CODE BEGIN INCLUDE */ + +/* USER CODE END INCLUDE */ + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +/* Private macro -------------------------------------------------------------*/ + +/* USER CODE BEGIN PV */ +/* Private variables ---------------------------------------------------------*/ + +/* USER CODE END PV */ + +/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY + * @brief Usb device library. + * @{ + */ + +/** @addtogroup USBD_CDC_IF + * @{ + */ + +/** @defgroup USBD_CDC_IF_Private_TypesDefinitions USBD_CDC_IF_Private_TypesDefinitions + * @brief Private types. + * @{ + */ + +/* USER CODE BEGIN PRIVATE_TYPES */ + +/* USER CODE END PRIVATE_TYPES */ + +/** + * @} + */ + +/** @defgroup USBD_CDC_IF_Private_Defines USBD_CDC_IF_Private_Defines + * @brief Private defines. + * @{ + */ + +/* USER CODE BEGIN PRIVATE_DEFINES */ +/* USER CODE END PRIVATE_DEFINES */ + +/** + * @} + */ + +/** @defgroup USBD_CDC_IF_Private_Macros USBD_CDC_IF_Private_Macros + * @brief Private macros. + * @{ + */ + +/* USER CODE BEGIN PRIVATE_MACRO */ + +/* USER CODE END PRIVATE_MACRO */ + +/** + * @} + */ + +/** @defgroup USBD_CDC_IF_Private_Variables USBD_CDC_IF_Private_Variables + * @brief Private variables. + * @{ + */ +/* Create buffer for reception and transmission */ +/* It's up to user to redefine and/or remove those define */ +/** Received data over USB are stored in this buffer */ +uint8_t UserRxBufferFS[APP_RX_DATA_SIZE]; + +/** Data to send over USB CDC are stored in this buffer */ +uint8_t UserTxBufferFS[APP_TX_DATA_SIZE]; + +/* USER CODE BEGIN PRIVATE_VARIABLES */ + +/* USER CODE END PRIVATE_VARIABLES */ + +/** + * @} + */ + +/** @defgroup USBD_CDC_IF_Exported_Variables USBD_CDC_IF_Exported_Variables + * @brief Public variables. + * @{ + */ + +extern USBD_HandleTypeDef hUsbDeviceFS; + +/* USER CODE BEGIN EXPORTED_VARIABLES */ + +/* USER CODE END EXPORTED_VARIABLES */ + +/** + * @} + */ + +/** @defgroup USBD_CDC_IF_Private_FunctionPrototypes USBD_CDC_IF_Private_FunctionPrototypes + * @brief Private functions declaration. + * @{ + */ + +static int8_t CDC_Init_FS(void); +static int8_t CDC_DeInit_FS(void); +static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length); +static int8_t CDC_Receive_FS(uint8_t* pbuf, uint32_t *Len); +static int8_t CDC_TransmitCplt_FS(uint8_t *pbuf, uint32_t *Len, uint8_t epnum); + +/* USER CODE BEGIN PRIVATE_FUNCTIONS_DECLARATION */ + +/* USER CODE END PRIVATE_FUNCTIONS_DECLARATION */ + +/** + * @} + */ + +USBD_CDC_ItfTypeDef USBD_Interface_fops_FS = +{ + CDC_Init_FS, + CDC_DeInit_FS, + CDC_Control_FS, + CDC_Receive_FS, + CDC_TransmitCplt_FS +}; + +/* Private functions ---------------------------------------------------------*/ +/** + * @brief Initializes the CDC media low layer over the FS USB IP + * @retval USBD_OK if all operations are OK else USBD_FAIL + */ +static int8_t CDC_Init_FS(void) +{ + /* USER CODE BEGIN 3 */ + /* Set Application Buffers */ + USBD_CDC_SetTxBuffer(&hUsbDeviceFS, UserTxBufferFS, 0); + USBD_CDC_SetRxBuffer(&hUsbDeviceFS, UserRxBufferFS); + return (USBD_OK); + /* USER CODE END 3 */ +} + +/** + * @brief DeInitializes the CDC media low layer + * @retval USBD_OK if all operations are OK else USBD_FAIL + */ +static int8_t CDC_DeInit_FS(void) +{ + /* USER CODE BEGIN 4 */ + return (USBD_OK); + /* USER CODE END 4 */ +} + +/** + * @brief Manage the CDC class requests + * @param cmd: Command code + * @param pbuf: Buffer containing command data (request parameters) + * @param length: Number of data to be sent (in bytes) + * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL + */ +static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length) +{ + /* USER CODE BEGIN 5 */ + switch(cmd) + { + case CDC_SEND_ENCAPSULATED_COMMAND: + + break; + + case CDC_GET_ENCAPSULATED_RESPONSE: + + break; + + case CDC_SET_COMM_FEATURE: + + break; + + case CDC_GET_COMM_FEATURE: + + break; + + case CDC_CLEAR_COMM_FEATURE: + + break; + + /*******************************************************************************/ + /* Line Coding Structure */ + /*-----------------------------------------------------------------------------*/ + /* Offset | Field | Size | Value | Description */ + /* 0 | dwDTERate | 4 | Number |Data terminal rate, in bits per second*/ + /* 4 | bCharFormat | 1 | Number | Stop bits */ + /* 0 - 1 Stop bit */ + /* 1 - 1.5 Stop bits */ + /* 2 - 2 Stop bits */ + /* 5 | bParityType | 1 | Number | Parity */ + /* 0 - None */ + /* 1 - Odd */ + /* 2 - Even */ + /* 3 - Mark */ + /* 4 - Space */ + /* 6 | bDataBits | 1 | Number Data bits (5, 6, 7, 8 or 16). */ + /*******************************************************************************/ + case CDC_SET_LINE_CODING: + + break; + + case CDC_GET_LINE_CODING: + + break; + + case CDC_SET_CONTROL_LINE_STATE: + + break; + + case CDC_SEND_BREAK: + + break; + + default: + break; + } + + return (USBD_OK); + /* USER CODE END 5 */ +} + +/** + * @brief Data received over USB OUT endpoint are sent over CDC interface + * through this function. + * + * @note + * This function will issue a NAK packet on any OUT packet received on + * USB endpoint until exiting this function. If you exit this function + * before transfer is complete on CDC interface (ie. using DMA controller) + * it will result in receiving more data while previous ones are still + * not sent. + * + * @param Buf: Buffer of data to be received + * @param Len: Number of data received (in bytes) + * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL + */ +static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len) +{ + /* USER CODE BEGIN 6 */ + USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]); + USBD_CDC_ReceivePacket(&hUsbDeviceFS); + return (USBD_OK); + /* USER CODE END 6 */ +} + +/** + * @brief CDC_Transmit_FS + * Data to send over USB IN endpoint are sent over CDC interface + * through this function. + * @note + * + * + * @param Buf: Buffer of data to be sent + * @param Len: Number of data to be sent (in bytes) + * @retval USBD_OK if all operations are OK else USBD_FAIL or USBD_BUSY + */ +uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len) +{ + uint8_t result = USBD_OK; + /* USER CODE BEGIN 7 */ + USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*)hUsbDeviceFS.pClassData; + if (hcdc->TxState != 0){ + return USBD_BUSY; + } + USBD_CDC_SetTxBuffer(&hUsbDeviceFS, Buf, Len); + result = USBD_CDC_TransmitPacket(&hUsbDeviceFS); + /* USER CODE END 7 */ + return result; +} + +/** + * @brief CDC_TransmitCplt_FS + * Data transmitted callback + * + * @note + * This function is IN transfer complete callback used to inform user that + * the submitted Data is successfully sent over USB. + * + * @param Buf: Buffer of data to be received + * @param Len: Number of data received (in bytes) + * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL + */ +static int8_t CDC_TransmitCplt_FS(uint8_t *Buf, uint32_t *Len, uint8_t epnum) +{ + uint8_t result = USBD_OK; + /* USER CODE BEGIN 13 */ + UNUSED(Buf); + UNUSED(Len); + UNUSED(epnum); + /* USER CODE END 13 */ + return result; +} + +/* USER CODE BEGIN PRIVATE_FUNCTIONS_IMPLEMENTATION */ + +/* USER CODE END PRIVATE_FUNCTIONS_IMPLEMENTATION */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/cube/Src/usbd_conf.c b/firmware/targets/f7/cube/Src/usbd_conf.c new file mode 100644 index 00000000..033e619a --- /dev/null +++ b/firmware/targets/f7/cube/Src/usbd_conf.c @@ -0,0 +1,810 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file : usbd_conf.c + * @version : v3.0_Cube + * @brief : This file implements the board support package for the USB device library + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32wbxx.h" +#include "stm32wbxx_hal.h" +#include "usbd_def.h" +#include "usbd_core.h" + +#include "usbd_cdc.h" + +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +/* Private macro -------------------------------------------------------------*/ + +/* Private variables ---------------------------------------------------------*/ +/* USER CODE BEGIN PV */ + +/* USER CODE END PV */ + +PCD_HandleTypeDef hpcd_USB_FS; +void Error_Handler(void); + +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ + +/* Exported function prototypes ----------------------------------------------*/ + +/* USER CODE BEGIN PFP */ +/* Private function prototypes -----------------------------------------------*/ + +/* USER CODE END PFP */ + +/* Private functions ---------------------------------------------------------*/ +static USBD_StatusTypeDef USBD_Get_USB_Status(HAL_StatusTypeDef hal_status); +/* USER CODE BEGIN 1 */ +static void SystemClockConfig_Resume(void); + +/* USER CODE END 1 */ +extern void SystemClock_Config(void); + +/******************************************************************************* + LL Driver Callbacks (PCD -> USB Device Library) +*******************************************************************************/ +/* MSP Init */ + +#if (USE_HAL_PCD_REGISTER_CALLBACK == 1U) +static void HAL_PCD_MspInit(PCD_HandleTypeDef* pcdHandle) +#else +void HAL_PCD_MspInit(PCD_HandleTypeDef* pcdHandle) +#endif /* USE_HAL_PCD_REGISTER_CALLBACK */ +{ + GPIO_InitTypeDef GPIO_InitStruct = {0}; + if(pcdHandle->Instance==USB) + { + /* USER CODE BEGIN USB_MspInit 0 */ + + /* USER CODE END USB_MspInit 0 */ + + __HAL_RCC_GPIOA_CLK_ENABLE(); + /**USB GPIO Configuration + PA11 ------> USB_DM + PA12 ------> USB_DP + */ + GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_12; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF10_USB; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + /* Peripheral clock enable */ + __HAL_RCC_USB_CLK_ENABLE(); + + /* Peripheral interrupt init */ + HAL_NVIC_SetPriority(USB_LP_IRQn, 5, 0); + HAL_NVIC_EnableIRQ(USB_LP_IRQn); + /* USER CODE BEGIN USB_MspInit 1 */ + + /* USER CODE END USB_MspInit 1 */ + } +} + +#if (USE_HAL_PCD_REGISTER_CALLBACK == 1U) +static void HAL_PCD_MspDeInit(PCD_HandleTypeDef* pcdHandle) +#else +void HAL_PCD_MspDeInit(PCD_HandleTypeDef* pcdHandle) +#endif /* USE_HAL_PCD_REGISTER_CALLBACK */ +{ + if(pcdHandle->Instance==USB) + { + /* USER CODE BEGIN USB_MspDeInit 0 */ + + /* USER CODE END USB_MspDeInit 0 */ + /* Peripheral clock disable */ + __HAL_RCC_USB_CLK_DISABLE(); + + /**USB GPIO Configuration + PA11 ------> USB_DM + PA12 ------> USB_DP + */ + HAL_GPIO_DeInit(GPIOA, GPIO_PIN_11|GPIO_PIN_12); + + /* Peripheral interrupt Deinit*/ + HAL_NVIC_DisableIRQ(USB_LP_IRQn); + + /* USER CODE BEGIN USB_MspDeInit 1 */ + + /* USER CODE END USB_MspDeInit 1 */ + } +} + +/** + * @brief Setup stage callback + * @param hpcd: PCD handle + * @retval None + */ +#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U) +static void PCD_SetupStageCallback(PCD_HandleTypeDef *hpcd) +#else +void HAL_PCD_SetupStageCallback(PCD_HandleTypeDef *hpcd) +#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */ +{ + /* USER CODE BEGIN HAL_PCD_SetupStageCallback_PreTreatment */ + + /* USER CODE END HAL_PCD_SetupStageCallback_PreTreatment */ + USBD_LL_SetupStage((USBD_HandleTypeDef*)hpcd->pData, (uint8_t *)hpcd->Setup); + /* USER CODE BEGIN HAL_PCD_SetupStageCallback_PostTreatment */ + + /* USER CODE END HAL_PCD_SetupStageCallback_PostTreatment */ +} + +/** + * @brief Data Out stage callback. + * @param hpcd: PCD handle + * @param epnum: Endpoint number + * @retval None + */ +#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U) +static void PCD_DataOutStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) +#else +void HAL_PCD_DataOutStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) +#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */ +{ + /* USER CODE BEGIN HAL_PCD_DataOutStageCallback_PreTreatment */ + + /* USER CODE END HAL_PCD_DataOutStageCallback_PreTreatment */ + USBD_LL_DataOutStage((USBD_HandleTypeDef*)hpcd->pData, epnum, hpcd->OUT_ep[epnum].xfer_buff); + /* USER CODE BEGIN HAL_PCD_DataOutStageCallback_PostTreatment */ + + /* USER CODE END HAL_PCD_DataOutStageCallback_PostTreatment */ +} + +/** + * @brief Data In stage callback. + * @param hpcd: PCD handle + * @param epnum: Endpoint number + * @retval None + */ +#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U) +static void PCD_DataInStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) +#else +void HAL_PCD_DataInStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) +#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */ +{ + /* USER CODE BEGIN HAL_PCD_DataInStageCallback_PreTreatment */ + + /* USER CODE END HAL_PCD_DataInStageCallback_PreTreatment */ + USBD_LL_DataInStage((USBD_HandleTypeDef*)hpcd->pData, epnum, hpcd->IN_ep[epnum].xfer_buff); + /* USER CODE BEGIN HAL_PCD_DataInStageCallback_PostTreatment */ + + /* USER CODE END HAL_PCD_DataInStageCallback_PostTreatment */ +} + +/** + * @brief SOF callback. + * @param hpcd: PCD handle + * @retval None + */ +#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U) +static void PCD_SOFCallback(PCD_HandleTypeDef *hpcd) +#else +void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd) +#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */ +{ + /* USER CODE BEGIN HAL_PCD_SOFCallback_PreTreatment */ + + /* USER CODE END HAL_PCD_SOFCallback_PreTreatment */ + USBD_LL_SOF((USBD_HandleTypeDef*)hpcd->pData); + /* USER CODE BEGIN HAL_PCD_SOFCallback_PostTreatment */ + + /* USER CODE END HAL_PCD_SOFCallback_PostTreatment */ +} + +/** + * @brief Reset callback. + * @param hpcd: PCD handle + * @retval None + */ +#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U) +static void PCD_ResetCallback(PCD_HandleTypeDef *hpcd) +#else +void HAL_PCD_ResetCallback(PCD_HandleTypeDef *hpcd) +#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */ +{ + /* USER CODE BEGIN HAL_PCD_ResetCallback_PreTreatment */ + + /* USER CODE END HAL_PCD_ResetCallback_PreTreatment */ + USBD_SpeedTypeDef speed = USBD_SPEED_FULL; + + if ( hpcd->Init.speed != PCD_SPEED_FULL) + { + Error_Handler(); + } + /* Set Speed. */ + USBD_LL_SetSpeed((USBD_HandleTypeDef*)hpcd->pData, speed); + + /* Reset Device. */ + USBD_LL_Reset((USBD_HandleTypeDef*)hpcd->pData); + /* USER CODE BEGIN HAL_PCD_ResetCallback_PostTreatment */ + + /* USER CODE END HAL_PCD_ResetCallback_PostTreatment */ +} + +/** + * @brief Suspend callback. + * When Low power mode is enabled the debug cannot be used (IAR, Keil doesn't support it) + * @param hpcd: PCD handle + * @retval None + */ +#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U) +static void PCD_SuspendCallback(PCD_HandleTypeDef *hpcd) +#else +void HAL_PCD_SuspendCallback(PCD_HandleTypeDef *hpcd) +#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */ +{ + /* USER CODE BEGIN HAL_PCD_SuspendCallback_PreTreatment */ + + /* USER CODE END HAL_PCD_SuspendCallback_PreTreatment */ + /* Inform USB library that core enters in suspend Mode. */ + USBD_LL_Suspend((USBD_HandleTypeDef*)hpcd->pData); + /* Enter in STOP mode. */ + /* USER CODE BEGIN 2 */ + if (hpcd->Init.low_power_enable) + { + /* Set SLEEPDEEP bit and SleepOnExit of Cortex System Control Register. */ + SCB->SCR |= (uint32_t)((uint32_t)(SCB_SCR_SLEEPDEEP_Msk | SCB_SCR_SLEEPONEXIT_Msk)); + } + /* USER CODE END 2 */ + /* USER CODE BEGIN HAL_PCD_SuspendCallback_PostTreatment */ + + /* USER CODE END HAL_PCD_SuspendCallback_PostTreatment */ +} + +/** + * @brief Resume callback. + * When Low power mode is enabled the debug cannot be used (IAR, Keil doesn't support it) + * @param hpcd: PCD handle + * @retval None + */ +#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U) +static void PCD_ResumeCallback(PCD_HandleTypeDef *hpcd) +#else +void HAL_PCD_ResumeCallback(PCD_HandleTypeDef *hpcd) +#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */ +{ + /* USER CODE BEGIN HAL_PCD_ResumeCallback_PreTreatment */ + + /* USER CODE END HAL_PCD_ResumeCallback_PreTreatment */ + + /* USER CODE BEGIN 3 */ + if (hpcd->Init.low_power_enable) + { + /* Reset SLEEPDEEP bit of Cortex System Control Register. */ + SCB->SCR &= (uint32_t)~((uint32_t)(SCB_SCR_SLEEPDEEP_Msk | SCB_SCR_SLEEPONEXIT_Msk)); + SystemClockConfig_Resume(); + } + /* USER CODE END 3 */ + + USBD_LL_Resume((USBD_HandleTypeDef*)hpcd->pData); + /* USER CODE BEGIN HAL_PCD_ResumeCallback_PostTreatment */ + + /* USER CODE END HAL_PCD_ResumeCallback_PostTreatment */ +} + +/** + * @brief ISOOUTIncomplete callback. + * @param hpcd: PCD handle + * @param epnum: Endpoint number + * @retval None + */ +#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U) +static void PCD_ISOOUTIncompleteCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) +#else +void HAL_PCD_ISOOUTIncompleteCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) +#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */ +{ + /* USER CODE BEGIN HAL_PCD_ISOOUTIncompleteCallback_PreTreatment */ + + /* USER CODE END HAL_PCD_ISOOUTIncompleteCallback_PreTreatment */ + USBD_LL_IsoOUTIncomplete((USBD_HandleTypeDef*)hpcd->pData, epnum); + /* USER CODE BEGIN HAL_PCD_ISOOUTIncompleteCallback_PostTreatment */ + + /* USER CODE END HAL_PCD_ISOOUTIncompleteCallback_PostTreatment */ +} + +/** + * @brief ISOINIncomplete callback. + * @param hpcd: PCD handle + * @param epnum: Endpoint number + * @retval None + */ +#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U) +static void PCD_ISOINIncompleteCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) +#else +void HAL_PCD_ISOINIncompleteCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) +#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */ +{ + /* USER CODE BEGIN HAL_PCD_ISOINIncompleteCallback_PreTreatment */ + + /* USER CODE END HAL_PCD_ISOINIncompleteCallback_PreTreatment */ + USBD_LL_IsoINIncomplete((USBD_HandleTypeDef*)hpcd->pData, epnum); + /* USER CODE BEGIN HAL_PCD_ISOINIncompleteCallback_PostTreatment */ + + /* USER CODE END HAL_PCD_ISOINIncompleteCallback_PostTreatment */ +} + +/** + * @brief Connect callback. + * @param hpcd: PCD handle + * @retval None + */ +#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U) +static void PCD_ConnectCallback(PCD_HandleTypeDef *hpcd) +#else +void HAL_PCD_ConnectCallback(PCD_HandleTypeDef *hpcd) +#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */ +{ + /* USER CODE BEGIN HAL_PCD_ConnectCallback_PreTreatment */ + + /* USER CODE END HAL_PCD_ConnectCallback_PreTreatment */ + USBD_LL_DevConnected((USBD_HandleTypeDef*)hpcd->pData); + /* USER CODE BEGIN HAL_PCD_ConnectCallback_PostTreatment */ + + /* USER CODE END HAL_PCD_ConnectCallback_PostTreatment */ +} + +/** + * @brief Disconnect callback. + * @param hpcd: PCD handle + * @retval None + */ +#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U) +static void PCD_DisconnectCallback(PCD_HandleTypeDef *hpcd) +#else +void HAL_PCD_DisconnectCallback(PCD_HandleTypeDef *hpcd) +#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */ +{ + /* USER CODE BEGIN HAL_PCD_DisconnectCallback_PreTreatment */ + + /* USER CODE END HAL_PCD_DisconnectCallback_PreTreatment */ + USBD_LL_DevDisconnected((USBD_HandleTypeDef*)hpcd->pData); + /* USER CODE BEGIN HAL_PCD_DisconnectCallback_PostTreatment */ + + /* USER CODE END HAL_PCD_DisconnectCallback_PostTreatment */ +} + + /* USER CODE BEGIN LowLevelInterface */ + + /* USER CODE END LowLevelInterface */ + +/******************************************************************************* + LL Driver Interface (USB Device Library --> PCD) +*******************************************************************************/ + +/** + * @brief Initializes the low level portion of the device driver. + * @param pdev: Device handle + * @retval USBD status + */ +USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev) +{ + /* Init USB Ip. */ + hpcd_USB_FS.pData = pdev; + /* Link the driver to the stack. */ + pdev->pData = &hpcd_USB_FS; +/* Enable USB power on Pwrctrl CR2 register. */ + HAL_PWREx_EnableVddUSB(); + + hpcd_USB_FS.Instance = USB; + hpcd_USB_FS.Init.dev_endpoints = 8; + hpcd_USB_FS.Init.speed = PCD_SPEED_FULL; + hpcd_USB_FS.Init.phy_itface = PCD_PHY_EMBEDDED; + hpcd_USB_FS.Init.Sof_enable = DISABLE; + hpcd_USB_FS.Init.low_power_enable = DISABLE; + hpcd_USB_FS.Init.lpm_enable = DISABLE; + hpcd_USB_FS.Init.battery_charging_enable = DISABLE; + + #if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U) + /* register Msp Callbacks (before the Init) */ + HAL_PCD_RegisterCallback(&hpcd_USB_FS, HAL_PCD_MSPINIT_CB_ID, PCD_MspInit); + HAL_PCD_RegisterCallback(&hpcd_USB_FS, HAL_PCD_MSPDEINIT_CB_ID, PCD_MspDeInit); + #endif /* USE_HAL_PCD_REGISTER_CALLBACKS */ + + if (HAL_PCD_Init(&hpcd_USB_FS) != HAL_OK) + { + Error_Handler( ); + } + +#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U) + /* Register USB PCD CallBacks */ + HAL_PCD_RegisterCallback(&hpcd_USB_FS, HAL_PCD_SOF_CB_ID, PCD_SOFCallback); + HAL_PCD_RegisterCallback(&hpcd_USB_FS, HAL_PCD_SETUPSTAGE_CB_ID, PCD_SetupStageCallback); + HAL_PCD_RegisterCallback(&hpcd_USB_FS, HAL_PCD_RESET_CB_ID, PCD_ResetCallback); + HAL_PCD_RegisterCallback(&hpcd_USB_FS, HAL_PCD_SUSPEND_CB_ID, PCD_SuspendCallback); + HAL_PCD_RegisterCallback(&hpcd_USB_FS, HAL_PCD_RESUME_CB_ID, PCD_ResumeCallback); + HAL_PCD_RegisterCallback(&hpcd_USB_FS, HAL_PCD_CONNECT_CB_ID, PCD_ConnectCallback); + HAL_PCD_RegisterCallback(&hpcd_USB_FS, HAL_PCD_DISCONNECT_CB_ID, PCD_DisconnectCallback); + /* USER CODE BEGIN RegisterCallBackFirstPart */ + + /* USER CODE END RegisterCallBackFirstPart */ + HAL_PCD_RegisterLpmCallback(&hpcd_USB_FS, PCDEx_LPM_Callback); + HAL_PCD_RegisterDataOutStageCallback(&hpcd_USB_FS, PCD_DataOutStageCallback); + HAL_PCD_RegisterDataInStageCallback(&hpcd_USB_FS, PCD_DataInStageCallback); + HAL_PCD_RegisterIsoOutIncpltCallback(&hpcd_USB_FS, PCD_ISOOUTIncompleteCallback); + HAL_PCD_RegisterIsoInIncpltCallback(&hpcd_USB_FS, PCD_ISOINIncompleteCallback); + /* USER CODE BEGIN RegisterCallBackSecondPart */ + + /* USER CODE END RegisterCallBackSecondPart */ +#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */ + /* USER CODE BEGIN EndPoint_Configuration */ + HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x00 , PCD_SNG_BUF, 0x18); + HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x80 , PCD_SNG_BUF, 0x58); + /* USER CODE END EndPoint_Configuration */ + /* USER CODE BEGIN EndPoint_Configuration_CDC */ + HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x81 , PCD_SNG_BUF, 0xC0); + HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x01 , PCD_SNG_BUF, 0x110); + HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x82 , PCD_SNG_BUF, 0x100); + /* USER CODE END EndPoint_Configuration_CDC */ + return USBD_OK; +} + +/** + * @brief De-Initializes the low level portion of the device driver. + * @param pdev: Device handle + * @retval USBD status + */ +USBD_StatusTypeDef USBD_LL_DeInit(USBD_HandleTypeDef *pdev) +{ + HAL_StatusTypeDef hal_status = HAL_OK; + USBD_StatusTypeDef usb_status = USBD_OK; + + hal_status = HAL_PCD_DeInit(pdev->pData); + + usb_status = USBD_Get_USB_Status(hal_status); + + return usb_status; +} + +/** + * @brief Starts the low level portion of the device driver. + * @param pdev: Device handle + * @retval USBD status + */ +USBD_StatusTypeDef USBD_LL_Start(USBD_HandleTypeDef *pdev) +{ + HAL_StatusTypeDef hal_status = HAL_OK; + USBD_StatusTypeDef usb_status = USBD_OK; + + hal_status = HAL_PCD_Start(pdev->pData); + + usb_status = USBD_Get_USB_Status(hal_status); + + return usb_status; +} + +/** + * @brief Stops the low level portion of the device driver. + * @param pdev: Device handle + * @retval USBD status + */ +USBD_StatusTypeDef USBD_LL_Stop(USBD_HandleTypeDef *pdev) +{ + HAL_StatusTypeDef hal_status = HAL_OK; + USBD_StatusTypeDef usb_status = USBD_OK; + + hal_status = HAL_PCD_Stop(pdev->pData); + + usb_status = USBD_Get_USB_Status(hal_status); + + return usb_status; +} + +/** + * @brief Opens an endpoint of the low level driver. + * @param pdev: Device handle + * @param ep_addr: Endpoint number + * @param ep_type: Endpoint type + * @param ep_mps: Endpoint max packet size + * @retval USBD status + */ +USBD_StatusTypeDef USBD_LL_OpenEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr, uint8_t ep_type, uint16_t ep_mps) +{ + HAL_StatusTypeDef hal_status = HAL_OK; + USBD_StatusTypeDef usb_status = USBD_OK; + + hal_status = HAL_PCD_EP_Open(pdev->pData, ep_addr, ep_mps, ep_type); + + usb_status = USBD_Get_USB_Status(hal_status); + + return usb_status; +} + +/** + * @brief Closes an endpoint of the low level driver. + * @param pdev: Device handle + * @param ep_addr: Endpoint number + * @retval USBD status + */ +USBD_StatusTypeDef USBD_LL_CloseEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr) +{ + HAL_StatusTypeDef hal_status = HAL_OK; + USBD_StatusTypeDef usb_status = USBD_OK; + + hal_status = HAL_PCD_EP_Close(pdev->pData, ep_addr); + + usb_status = USBD_Get_USB_Status(hal_status); + + return usb_status; +} + +/** + * @brief Flushes an endpoint of the Low Level Driver. + * @param pdev: Device handle + * @param ep_addr: Endpoint number + * @retval USBD status + */ +USBD_StatusTypeDef USBD_LL_FlushEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr) +{ + HAL_StatusTypeDef hal_status = HAL_OK; + USBD_StatusTypeDef usb_status = USBD_OK; + + hal_status = HAL_PCD_EP_Flush(pdev->pData, ep_addr); + + usb_status = USBD_Get_USB_Status(hal_status); + + return usb_status; +} + +/** + * @brief Sets a Stall condition on an endpoint of the Low Level Driver. + * @param pdev: Device handle + * @param ep_addr: Endpoint number + * @retval USBD status + */ +USBD_StatusTypeDef USBD_LL_StallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr) +{ + HAL_StatusTypeDef hal_status = HAL_OK; + USBD_StatusTypeDef usb_status = USBD_OK; + + hal_status = HAL_PCD_EP_SetStall(pdev->pData, ep_addr); + + usb_status = USBD_Get_USB_Status(hal_status); + + return usb_status; +} + +/** + * @brief Clears a Stall condition on an endpoint of the Low Level Driver. + * @param pdev: Device handle + * @param ep_addr: Endpoint number + * @retval USBD status + */ +USBD_StatusTypeDef USBD_LL_ClearStallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr) +{ + HAL_StatusTypeDef hal_status = HAL_OK; + USBD_StatusTypeDef usb_status = USBD_OK; + + hal_status = HAL_PCD_EP_ClrStall(pdev->pData, ep_addr); + + usb_status = USBD_Get_USB_Status(hal_status); + + return usb_status; +} + +/** + * @brief Returns Stall condition. + * @param pdev: Device handle + * @param ep_addr: Endpoint number + * @retval Stall (1: Yes, 0: No) + */ +uint8_t USBD_LL_IsStallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr) +{ + PCD_HandleTypeDef *hpcd = (PCD_HandleTypeDef*) pdev->pData; + + if((ep_addr & 0x80) == 0x80) + { + return hpcd->IN_ep[ep_addr & 0x7F].is_stall; + } + else + { + return hpcd->OUT_ep[ep_addr & 0x7F].is_stall; + } +} + +/** + * @brief Assigns a USB address to the device. + * @param pdev: Device handle + * @param dev_addr: Device address + * @retval USBD status + */ +USBD_StatusTypeDef USBD_LL_SetUSBAddress(USBD_HandleTypeDef *pdev, uint8_t dev_addr) +{ + HAL_StatusTypeDef hal_status = HAL_OK; + USBD_StatusTypeDef usb_status = USBD_OK; + + hal_status = HAL_PCD_SetAddress(pdev->pData, dev_addr); + + usb_status = USBD_Get_USB_Status(hal_status); + + return usb_status; +} + +/** + * @brief Transmits data over an endpoint. + * @param pdev: Device handle + * @param ep_addr: Endpoint number + * @param pbuf: Pointer to data to be sent + * @param size: Data size + * @retval USBD status + */ +USBD_StatusTypeDef USBD_LL_Transmit(USBD_HandleTypeDef *pdev, uint8_t ep_addr, uint8_t *pbuf, uint32_t size) +{ + HAL_StatusTypeDef hal_status = HAL_OK; + USBD_StatusTypeDef usb_status = USBD_OK; + + hal_status = HAL_PCD_EP_Transmit(pdev->pData, ep_addr, pbuf, size); + + usb_status = USBD_Get_USB_Status(hal_status); + + return usb_status; +} + +/** + * @brief Prepares an endpoint for reception. + * @param pdev: Device handle + * @param ep_addr: Endpoint number + * @param pbuf: Pointer to data to be received + * @param size: Data size + * @retval USBD status + */ +USBD_StatusTypeDef USBD_LL_PrepareReceive(USBD_HandleTypeDef *pdev, uint8_t ep_addr, uint8_t *pbuf, uint32_t size) +{ + HAL_StatusTypeDef hal_status = HAL_OK; + USBD_StatusTypeDef usb_status = USBD_OK; + + hal_status = HAL_PCD_EP_Receive(pdev->pData, ep_addr, pbuf, size); + + usb_status = USBD_Get_USB_Status(hal_status); + + return usb_status; +} + +/** + * @brief Returns the last transferred packet size. + * @param pdev: Device handle + * @param ep_addr: Endpoint number + * @retval Received Data Size + */ +uint32_t USBD_LL_GetRxDataSize(USBD_HandleTypeDef *pdev, uint8_t ep_addr) +{ + return HAL_PCD_EP_GetRxCount((PCD_HandleTypeDef*) pdev->pData, ep_addr); +} + +/** + * @brief Send LPM message to user layer + * @param hpcd: PCD handle + * @param msg: LPM message + * @retval None + */ +#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U) +static void PCDEx_LPM_Callback(PCD_HandleTypeDef *hpcd, PCD_LPM_MsgTypeDef msg) +#else +void HAL_PCDEx_LPM_Callback(PCD_HandleTypeDef *hpcd, PCD_LPM_MsgTypeDef msg) +#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */ +{ + /* USER CODE BEGIN LPM_Callback */ + switch (msg) + { + case PCD_LPM_L0_ACTIVE: + if (hpcd->Init.low_power_enable) + { + SystemClockConfig_Resume(); + + /* Reset SLEEPDEEP bit of Cortex System Control Register. */ + SCB->SCR &= (uint32_t)~((uint32_t)(SCB_SCR_SLEEPDEEP_Msk | SCB_SCR_SLEEPONEXIT_Msk)); + } + USBD_LL_Resume(hpcd->pData); + break; + + case PCD_LPM_L1_ACTIVE: + USBD_LL_Suspend(hpcd->pData); + + /* Enter in STOP mode. */ + if (hpcd->Init.low_power_enable) + { + /* Set SLEEPDEEP bit and SleepOnExit of Cortex System Control Register. */ + SCB->SCR |= (uint32_t)((uint32_t)(SCB_SCR_SLEEPDEEP_Msk | SCB_SCR_SLEEPONEXIT_Msk)); + } + break; + } + /* USER CODE END LPM_Callback */ +} + +/** + * @brief Delays routine for the USB Device Library. + * @param Delay: Delay in ms + * @retval None + */ +void USBD_LL_Delay(uint32_t Delay) +{ + HAL_Delay(Delay); +} + +/** + * @brief Static single allocation. + * @param size: Size of allocated memory + * @retval None + */ +void *USBD_static_malloc(uint32_t size) +{ + static uint32_t mem[(sizeof(USBD_CDC_HandleTypeDef)/4)+1];/* On 32-bit boundary */ + return mem; +} + +/** + * @brief Dummy memory free + * @param p: Pointer to allocated memory address + * @retval None + */ +void USBD_static_free(void *p) +{ + +} + +/* USER CODE BEGIN 5 */ +/** + * @brief Configures system clock after wake-up from USB resume callBack: + * enable HSI, PLL and select PLL as system clock source. + * @retval None + */ +static void SystemClockConfig_Resume(void) +{ + SystemClock_Config(); +} +/* USER CODE END 5 */ + +/** + * @brief Returns the USB status depending on the HAL status: + * @param hal_status: HAL status + * @retval USB status + */ +USBD_StatusTypeDef USBD_Get_USB_Status(HAL_StatusTypeDef hal_status) +{ + USBD_StatusTypeDef usb_status = USBD_OK; + + switch (hal_status) + { + case HAL_OK : + usb_status = USBD_OK; + break; + case HAL_ERROR : + usb_status = USBD_FAIL; + break; + case HAL_BUSY : + usb_status = USBD_BUSY; + break; + case HAL_TIMEOUT : + usb_status = USBD_FAIL; + break; + default : + usb_status = USBD_FAIL; + break; + } + return usb_status; +} +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/cube/Src/usbd_desc.c b/firmware/targets/f7/cube/Src/usbd_desc.c new file mode 100644 index 00000000..26f4b7c5 --- /dev/null +++ b/firmware/targets/f7/cube/Src/usbd_desc.c @@ -0,0 +1,396 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file : usbd_desc.c + * @version : v3.0_Cube + * @brief : This file implements the USB device descriptors. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_core.h" +#include "usbd_desc.h" +#include "usbd_conf.h" + +/* USER CODE BEGIN INCLUDE */ + +/* USER CODE END INCLUDE */ + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +/* Private macro -------------------------------------------------------------*/ + +/* USER CODE BEGIN PV */ +/* Private variables ---------------------------------------------------------*/ + +/* USER CODE END PV */ + +/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY + * @{ + */ + +/** @addtogroup USBD_DESC + * @{ + */ + +/** @defgroup USBD_DESC_Private_TypesDefinitions USBD_DESC_Private_TypesDefinitions + * @brief Private types. + * @{ + */ + +/* USER CODE BEGIN PRIVATE_TYPES */ + +/* USER CODE END PRIVATE_TYPES */ + +/** + * @} + */ + +/** @defgroup USBD_DESC_Private_Defines USBD_DESC_Private_Defines + * @brief Private defines. + * @{ + */ + +#define USBD_VID 1155 +#define USBD_LANGID_STRING 1033 +#define USBD_MANUFACTURER_STRING "Flipper" +#define USBD_PID 22336 +#define USBD_PRODUCT_STRING "Flipper Control Virtual ComPort" +#define USBD_CONFIGURATION_STRING "CDC Config" +#define USBD_INTERFACE_STRING "CDC Interface" + +/* USER CODE BEGIN PRIVATE_DEFINES */ + +/* USER CODE END PRIVATE_DEFINES */ + +/** + * @} + */ + +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ + +/** @defgroup USBD_DESC_Private_Macros USBD_DESC_Private_Macros + * @brief Private macros. + * @{ + */ + +/* USER CODE BEGIN PRIVATE_MACRO */ + +/* USER CODE END PRIVATE_MACRO */ + +/** + * @} + */ + +/** @defgroup USBD_DESC_Private_FunctionPrototypes USBD_DESC_Private_FunctionPrototypes + * @brief Private functions declaration. + * @{ + */ + +static void Get_SerialNum(void); +static void IntToUnicode(uint32_t value, uint8_t * pbuf, uint8_t len); + +/** + * @} + */ + +/** @defgroup USBD_DESC_Private_FunctionPrototypes USBD_DESC_Private_FunctionPrototypes + * @brief Private functions declaration. + * @{ + */ + +uint8_t * USBD_CDC_DeviceDescriptor(USBD_SpeedTypeDef speed, uint16_t *length); +uint8_t * USBD_CDC_LangIDStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length); +uint8_t * USBD_CDC_ManufacturerStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length); +uint8_t * USBD_CDC_ProductStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length); +uint8_t * USBD_CDC_SerialStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length); +uint8_t * USBD_CDC_ConfigStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length); +uint8_t * USBD_CDC_InterfaceStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length); + +/** + * @} + */ + +/** @defgroup USBD_DESC_Private_Variables USBD_DESC_Private_Variables + * @brief Private variables. + * @{ + */ + +USBD_DescriptorsTypeDef CDC_Desc = +{ + USBD_CDC_DeviceDescriptor, + USBD_CDC_LangIDStrDescriptor, + USBD_CDC_ManufacturerStrDescriptor, + USBD_CDC_ProductStrDescriptor, + USBD_CDC_SerialStrDescriptor, + USBD_CDC_ConfigStrDescriptor, + USBD_CDC_InterfaceStrDescriptor +}; + +#if defined ( __ICCARM__ ) /* IAR Compiler */ + #pragma data_alignment=4 +#endif /* defined ( __ICCARM__ ) */ +/** USB standard device descriptor. */ +__ALIGN_BEGIN uint8_t USBD_CDC_DeviceDesc[USB_LEN_DEV_DESC] __ALIGN_END = +{ + 0x12, /*bLength */ + USB_DESC_TYPE_DEVICE, /*bDescriptorType*/ + 0x00, /*bcdUSB */ + 0x02, + 0x02, /*bDeviceClass*/ + 0x02, /*bDeviceSubClass*/ + 0x00, /*bDeviceProtocol*/ + USB_MAX_EP0_SIZE, /*bMaxPacketSize*/ + LOBYTE(USBD_VID), /*idVendor*/ + HIBYTE(USBD_VID), /*idVendor*/ + LOBYTE(USBD_PID), /*idProduct*/ + HIBYTE(USBD_PID), /*idProduct*/ + 0x00, /*bcdDevice rel. 2.00*/ + 0x02, + USBD_IDX_MFC_STR, /*Index of manufacturer string*/ + USBD_IDX_PRODUCT_STR, /*Index of product string*/ + USBD_IDX_SERIAL_STR, /*Index of serial number string*/ + USBD_MAX_NUM_CONFIGURATION /*bNumConfigurations*/ +}; + +/* USB_DeviceDescriptor */ + +/** + * @} + */ + +/** @defgroup USBD_DESC_Private_Variables USBD_DESC_Private_Variables + * @brief Private variables. + * @{ + */ + +#if defined ( __ICCARM__ ) /* IAR Compiler */ + #pragma data_alignment=4 +#endif /* defined ( __ICCARM__ ) */ + +/** USB lang identifier descriptor. */ +__ALIGN_BEGIN uint8_t USBD_LangIDDesc[USB_LEN_LANGID_STR_DESC] __ALIGN_END = +{ + USB_LEN_LANGID_STR_DESC, + USB_DESC_TYPE_STRING, + LOBYTE(USBD_LANGID_STRING), + HIBYTE(USBD_LANGID_STRING) +}; + +#if defined ( __ICCARM__ ) /* IAR Compiler */ + #pragma data_alignment=4 +#endif /* defined ( __ICCARM__ ) */ +/* Internal string descriptor. */ +__ALIGN_BEGIN uint8_t USBD_StrDesc[USBD_MAX_STR_DESC_SIZ] __ALIGN_END; + +#if defined ( __ICCARM__ ) /*!< IAR Compiler */ + #pragma data_alignment=4 +#endif +__ALIGN_BEGIN uint8_t USBD_StringSerial[USB_SIZ_STRING_SERIAL] __ALIGN_END = { + USB_SIZ_STRING_SERIAL, + USB_DESC_TYPE_STRING, +}; + +/** + * @} + */ + +/** @defgroup USBD_DESC_Private_Functions USBD_DESC_Private_Functions + * @brief Private functions. + * @{ + */ + +/** + * @brief Return the device descriptor + * @param speed : Current device speed + * @param length : Pointer to data length variable + * @retval Pointer to descriptor buffer + */ +uint8_t * USBD_CDC_DeviceDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) +{ + UNUSED(speed); + *length = sizeof(USBD_CDC_DeviceDesc); + return USBD_CDC_DeviceDesc; +} + +/** + * @brief Return the LangID string descriptor + * @param speed : Current device speed + * @param length : Pointer to data length variable + * @retval Pointer to descriptor buffer + */ +uint8_t * USBD_CDC_LangIDStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) +{ + UNUSED(speed); + *length = sizeof(USBD_LangIDDesc); + return USBD_LangIDDesc; +} + +/** + * @brief Return the product string descriptor + * @param speed : Current device speed + * @param length : Pointer to data length variable + * @retval Pointer to descriptor buffer + */ +uint8_t * USBD_CDC_ProductStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) +{ + if(speed == 0) + { + USBD_GetString((uint8_t *)USBD_PRODUCT_STRING, USBD_StrDesc, length); + } + else + { + USBD_GetString((uint8_t *)USBD_PRODUCT_STRING, USBD_StrDesc, length); + } + return USBD_StrDesc; +} + +/** + * @brief Return the manufacturer string descriptor + * @param speed : Current device speed + * @param length : Pointer to data length variable + * @retval Pointer to descriptor buffer + */ +uint8_t * USBD_CDC_ManufacturerStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) +{ + UNUSED(speed); + USBD_GetString((uint8_t *)USBD_MANUFACTURER_STRING, USBD_StrDesc, length); + return USBD_StrDesc; +} + +/** + * @brief Return the serial number string descriptor + * @param speed : Current device speed + * @param length : Pointer to data length variable + * @retval Pointer to descriptor buffer + */ +uint8_t * USBD_CDC_SerialStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) +{ + UNUSED(speed); + *length = USB_SIZ_STRING_SERIAL; + + /* Update the serial number string descriptor with the data from the unique + * ID */ + Get_SerialNum(); + + /* USER CODE BEGIN USBD_CDC_SerialStrDescriptor */ + + /* USER CODE END USBD_CDC_SerialStrDescriptor */ + + return (uint8_t *) USBD_StringSerial; +} + +/** + * @brief Return the configuration string descriptor + * @param speed : Current device speed + * @param length : Pointer to data length variable + * @retval Pointer to descriptor buffer + */ +uint8_t * USBD_CDC_ConfigStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) +{ + if(speed == USBD_SPEED_HIGH) + { + USBD_GetString((uint8_t *)USBD_CONFIGURATION_STRING, USBD_StrDesc, length); + } + else + { + USBD_GetString((uint8_t *)USBD_CONFIGURATION_STRING, USBD_StrDesc, length); + } + return USBD_StrDesc; +} + +/** + * @brief Return the interface string descriptor + * @param speed : Current device speed + * @param length : Pointer to data length variable + * @retval Pointer to descriptor buffer + */ +uint8_t * USBD_CDC_InterfaceStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) +{ + if(speed == 0) + { + USBD_GetString((uint8_t *)USBD_INTERFACE_STRING, USBD_StrDesc, length); + } + else + { + USBD_GetString((uint8_t *)USBD_INTERFACE_STRING, USBD_StrDesc, length); + } + return USBD_StrDesc; +} + +/** + * @brief Create the serial number string descriptor + * @param None + * @retval None + */ +static void Get_SerialNum(void) +{ + uint32_t deviceserial0, deviceserial1, deviceserial2; + + deviceserial0 = *(uint32_t *) DEVICE_ID1; + deviceserial1 = *(uint32_t *) DEVICE_ID2; + deviceserial2 = *(uint32_t *) DEVICE_ID3; + + deviceserial0 += deviceserial2; + + if (deviceserial0 != 0) + { + IntToUnicode(deviceserial0, &USBD_StringSerial[2], 8); + IntToUnicode(deviceserial1, &USBD_StringSerial[18], 4); + } +} + +/** + * @brief Convert Hex 32Bits value into char + * @param value: value to convert + * @param pbuf: pointer to the buffer + * @param len: buffer length + * @retval None + */ +static void IntToUnicode(uint32_t value, uint8_t * pbuf, uint8_t len) +{ + uint8_t idx = 0; + + for (idx = 0; idx < len; idx++) + { + if (((value >> 28)) < 0xA) + { + pbuf[2 * idx] = (value >> 28) + '0'; + } + else + { + pbuf[2 * idx] = (value >> 28) + 'A' - 10; + } + + value = value << 4; + + pbuf[2 * idx + 1] = 0; + } +} +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/cube/f7.ioc b/firmware/targets/f7/cube/f7.ioc new file mode 100644 index 00000000..e55ecca4 --- /dev/null +++ b/firmware/targets/f7/cube/f7.ioc @@ -0,0 +1,598 @@ +#MicroXplorer Configuration settings - do not modify +ADC1.Channel-0\#ChannelRegularConversion=ADC_CHANNEL_14 +ADC1.ContinuousConvMode=DISABLE +ADC1.EnableAnalogWatchDog1=false +ADC1.IPParameters=Rank-0\#ChannelRegularConversion,Channel-0\#ChannelRegularConversion,SamplingTime-0\#ChannelRegularConversion,OffsetNumber-0\#ChannelRegularConversion,NbrOfConversionFlag,master,EnableAnalogWatchDog1,ContinuousConvMode +ADC1.NbrOfConversionFlag=1 +ADC1.OffsetNumber-0\#ChannelRegularConversion=ADC_OFFSET_NONE +ADC1.Rank-0\#ChannelRegularConversion=1 +ADC1.SamplingTime-0\#ChannelRegularConversion=ADC_SAMPLETIME_2CYCLES_5 +ADC1.master=1 +COMP1.Hysteresis=COMP_HYSTERESIS_HIGH +COMP1.IPParameters=TriggerMode,Hysteresis,Mode +COMP1.Mode=COMP_POWERMODE_MEDIUMSPEED +COMP1.TriggerMode=COMP_TRIGGERMODE_IT_RISING_FALLING +FREERTOS.FootprintOK=true +FREERTOS.HEAP_NUMBER=4 +FREERTOS.INCLUDE_vTaskCleanUpResources=1 +FREERTOS.IPParameters=Tasks01,configTOTAL_HEAP_SIZE,HEAP_NUMBER,configUSE_TIMERS,configUSE_IDLE_HOOK,FootprintOK,configCHECK_FOR_STACK_OVERFLOW,configRECORD_STACK_HIGH_ADDRESS,configGENERATE_RUN_TIME_STATS,configENABLE_FPU,configUSE_TICKLESS_IDLE,configENABLE_BACKWARD_COMPATIBILITY,INCLUDE_vTaskCleanUpResources,configTICK_RATE_HZ +FREERTOS.Tasks01=app_main,24,1024,app,As weak,NULL,Dynamic,NULL,NULL +FREERTOS.configCHECK_FOR_STACK_OVERFLOW=1 +FREERTOS.configENABLE_BACKWARD_COMPATIBILITY=0 +FREERTOS.configENABLE_FPU=1 +FREERTOS.configGENERATE_RUN_TIME_STATS=1 +FREERTOS.configRECORD_STACK_HIGH_ADDRESS=1 +FREERTOS.configTICK_RATE_HZ=1000 +FREERTOS.configTOTAL_HEAP_SIZE=40960 +FREERTOS.configUSE_IDLE_HOOK=1 +FREERTOS.configUSE_TICKLESS_IDLE=2 +FREERTOS.configUSE_TIMERS=1 +File.Version=6 +GPIO.groupedBy=Show All +I2C1.CustomTiming=Disabled +I2C1.I2C_Fall_Time=0 +I2C1.I2C_Rise_Time=0 +I2C1.IPParameters=Timing,CustomTiming,I2C_Rise_Time,I2C_Fall_Time +I2C1.Timing=0x10707DBC +KeepUserPlacement=false +Mcu.Family=STM32WB +Mcu.IP0=ADC1 +Mcu.IP1=AES1 +Mcu.IP10=RCC +Mcu.IP11=RF +Mcu.IP12=RNG +Mcu.IP13=RTC +Mcu.IP14=SPI1 +Mcu.IP15=SPI2 +Mcu.IP16=SYS +Mcu.IP17=TIM1 +Mcu.IP18=TIM2 +Mcu.IP19=TIM16 +Mcu.IP2=AES2 +Mcu.IP20=USART1 +Mcu.IP21=USB +Mcu.IP22=USB_DEVICE +Mcu.IP3=COMP1 +Mcu.IP4=CRC +Mcu.IP5=FREERTOS +Mcu.IP6=HSEM +Mcu.IP7=I2C1 +Mcu.IP8=NVIC +Mcu.IP9=PKA +Mcu.IPNb=23 +Mcu.Name=STM32WB55RGVx +Mcu.Package=VFQFPN68 +Mcu.Pin0=PC13 +Mcu.Pin1=PC14-OSC32_IN +Mcu.Pin10=PA0 +Mcu.Pin11=PA1 +Mcu.Pin12=PA2 +Mcu.Pin13=PA3 +Mcu.Pin14=PA4 +Mcu.Pin15=PA5 +Mcu.Pin16=PA6 +Mcu.Pin17=PA7 +Mcu.Pin18=PA8 +Mcu.Pin19=PA9 +Mcu.Pin2=PC15-OSC32_OUT +Mcu.Pin20=PC4 +Mcu.Pin21=PC5 +Mcu.Pin22=PB2 +Mcu.Pin23=PB10 +Mcu.Pin24=PB11 +Mcu.Pin25=RF1 +Mcu.Pin26=OSC_OUT +Mcu.Pin27=OSC_IN +Mcu.Pin28=PB0 +Mcu.Pin29=PB1 +Mcu.Pin3=PH3-BOOT0 +Mcu.Pin30=PE4 +Mcu.Pin31=PB12 +Mcu.Pin32=PB13 +Mcu.Pin33=PB14 +Mcu.Pin34=PB15 +Mcu.Pin35=PC6 +Mcu.Pin36=PA10 +Mcu.Pin37=PA11 +Mcu.Pin38=PA12 +Mcu.Pin39=PA13 +Mcu.Pin4=PB8 +Mcu.Pin40=PA14 +Mcu.Pin41=PA15 +Mcu.Pin42=PC10 +Mcu.Pin43=PC11 +Mcu.Pin44=PC12 +Mcu.Pin45=PD0 +Mcu.Pin46=PD1 +Mcu.Pin47=PB3 +Mcu.Pin48=PB4 +Mcu.Pin49=PB5 +Mcu.Pin5=PB9 +Mcu.Pin50=PB6 +Mcu.Pin51=PB7 +Mcu.Pin52=VP_ADC1_TempSens_Input +Mcu.Pin53=VP_ADC1_Vref_Input +Mcu.Pin54=VP_AES1_VS_AES +Mcu.Pin55=VP_AES2_VS_AES +Mcu.Pin56=VP_COMP1_VS_VREFINT14 +Mcu.Pin57=VP_CRC_VS_CRC +Mcu.Pin58=VP_FREERTOS_VS_CMSIS_V2 +Mcu.Pin59=VP_HSEM_VS_HSEM +Mcu.Pin6=PC0 +Mcu.Pin60=VP_PKA_VS_PKA +Mcu.Pin61=VP_RNG_VS_RNG +Mcu.Pin62=VP_RTC_VS_RTC_Activate +Mcu.Pin63=VP_RTC_VS_RTC_Calendar +Mcu.Pin64=VP_SYS_VS_Systick +Mcu.Pin65=VP_TIM1_VS_ClockSourceINT +Mcu.Pin66=VP_TIM2_VS_ClockSourceINT +Mcu.Pin67=VP_TIM16_VS_ClockSourceINT +Mcu.Pin68=VP_USB_DEVICE_VS_USB_DEVICE_CDC_FS +Mcu.Pin7=PC1 +Mcu.Pin8=PC2 +Mcu.Pin9=PC3 +Mcu.PinsNb=69 +Mcu.ThirdPartyNb=0 +Mcu.UserConstants= +Mcu.UserName=STM32WB55RGVx +MxCube.Version=6.3.0 +MxDb.Version=DB.6.0.30 +NVIC.ADC1_IRQn=true\:5\:0\:true\:false\:true\:false\:true\:true +NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC.COMP_IRQn=true\:5\:0\:true\:false\:true\:false\:false\:true +NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC.EXTI15_10_IRQn=true\:5\:0\:true\:false\:true\:false\:true\:true +NVIC.EXTI3_IRQn=true\:5\:0\:true\:false\:true\:false\:true\:true +NVIC.ForceEnableDMAVector=true +NVIC.HSEM_IRQn=true\:5\:0\:true\:false\:true\:false\:false\:true +NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:true +NVIC.PendSV_IRQn=true\:15\:0\:false\:false\:false\:true\:false\:false +NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4 +NVIC.RCC_IRQn=true\:5\:0\:false\:false\:true\:true\:true\:false +NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:false\:false\:false\:false +NVIC.SavedPendsvIrqHandlerGenerated=false +NVIC.SavedSvcallIrqHandlerGenerated=false +NVIC.SavedSystickIrqHandlerGenerated=true +NVIC.SysTick_IRQn=true\:15\:0\:false\:false\:true\:true\:false\:false +NVIC.TAMP_STAMP_LSECSS_IRQn=true\:5\:0\:false\:false\:true\:true\:true\:true +NVIC.TIM1_TRG_COM_TIM17_IRQn=true\:5\:0\:false\:false\:true\:false\:false\:true +NVIC.TIM2_IRQn=true\:5\:0\:true\:false\:true\:false\:true\:true +NVIC.USB_LP_IRQn=true\:5\:0\:true\:false\:true\:false\:false\:true +NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +OSC_IN.GPIOParameters=GPIO_Label +OSC_IN.GPIO_Label=QUARTZ_32KHZ_IN +OSC_IN.Locked=true +OSC_IN.Mode=HSE-External-Oscillator +OSC_IN.Signal=RCC_OSC_IN +OSC_OUT.GPIOParameters=GPIO_Label +OSC_OUT.GPIO_Label=QUARTZ_32KHZ_OUT +OSC_OUT.Locked=true +OSC_OUT.Mode=HSE-External-Oscillator +OSC_OUT.Signal=RCC_OSC_OUT +PA0.GPIOParameters=GPIO_Label +PA0.GPIO_Label=IR_RX +PA0.Signal=S_TIM2_CH1 +PA1.GPIOParameters=GPIO_Label +PA1.GPIO_Label=CC1101_G0 +PA1.Locked=true +PA1.Signal=GPIO_Analog +PA10.GPIOParameters=GPIO_Speed,GPIO_Label,GPIO_Pu +PA10.GPIO_Label=I2C_SDA +PA10.GPIO_Pu=GPIO_PULLUP +PA10.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH +PA10.Locked=true +PA10.Mode=I2C +PA10.Signal=I2C1_SDA +PA11.GPIOParameters=GPIO_Speed +PA11.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH +PA11.Locked=true +PA11.Mode=Device +PA11.Signal=USB_DM +PA12.GPIOParameters=GPIO_Speed +PA12.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH +PA12.Locked=true +PA12.Mode=Device +PA12.Signal=USB_DP +PA13.Locked=true +PA13.Mode=Serial_Wire +PA13.Signal=SYS_JTMS-SWDIO +PA14.Locked=true +PA14.Mode=Serial_Wire +PA14.Signal=SYS_JTCK-SWCLK +PA15.GPIOParameters=GPIO_Label +PA15.GPIO_Label=RFID_CARRIER +PA15.Locked=true +PA15.Signal=GPIO_Analog +PA2.GPIOParameters=GPIO_Label +PA2.GPIO_Label=RFID_PULL +PA2.Locked=true +PA2.Signal=GPIO_Output +PA3.GPIOParameters=GPIO_Speed,PinState,GPIO_Label,GPIO_ModeDefaultOutputPP +PA3.GPIO_Label=PERIPH_POWER +PA3.GPIO_ModeDefaultOutputPP=GPIO_MODE_OUTPUT_OD +PA3.GPIO_Speed=GPIO_SPEED_FREQ_LOW +PA3.Locked=true +PA3.PinState=GPIO_PIN_SET +PA3.Signal=GPIO_Output +PA4.GPIOParameters=GPIO_Label +PA4.GPIO_Label=PA4 +PA4.Signal=GPIO_Analog +PA5.GPIOParameters=GPIO_Label +PA5.GPIO_Label=SPI_R_SCK +PA5.Locked=true +PA5.Mode=Full_Duplex_Master +PA5.Signal=SPI1_SCK +PA6.GPIOParameters=GPIO_Label +PA6.GPIO_Label=PA6 +PA6.Signal=GPIO_Analog +PA7.GPIOParameters=GPIO_Label +PA7.GPIO_Label=PA7 +PA7.Signal=GPIO_Analog +PA8.GPIOParameters=GPIO_Label +PA8.GPIO_Label=VIBRO +PA8.Locked=true +PA8.Signal=GPIO_Output +PA9.GPIOParameters=GPIO_Speed,GPIO_Label,GPIO_Pu +PA9.GPIO_Label=I2C_SCL +PA9.GPIO_Pu=GPIO_PULLUP +PA9.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH +PA9.Locked=true +PA9.Mode=I2C +PA9.Signal=I2C1_SCL +PB0.GPIOParameters=GPIO_Label +PB0.GPIO_Label=DISPLAY_RST +PB0.Locked=true +PB0.Signal=GPIO_Output +PB1.GPIOParameters=GPIO_Label +PB1.GPIO_Label=DISPLAY_DI +PB1.Locked=true +PB1.Signal=GPIO_Output +PB10.GPIOParameters=GPIO_PuPd,GPIO_Label,GPIO_ModeDefaultEXTI +PB10.GPIO_Label=BUTTON_UP +PB10.GPIO_ModeDefaultEXTI=GPIO_MODE_IT_RISING_FALLING +PB10.GPIO_PuPd=GPIO_PULLUP +PB10.Locked=true +PB10.Signal=GPXTI10 +PB11.GPIOParameters=GPIO_PuPd,GPIO_Label,GPIO_ModeDefaultEXTI +PB11.GPIO_Label=BUTTON_LEFT +PB11.GPIO_ModeDefaultEXTI=GPIO_MODE_IT_RISING_FALLING +PB11.GPIO_PuPd=GPIO_PULLUP +PB11.Locked=true +PB11.Signal=GPXTI11 +PB12.GPIOParameters=GPIO_PuPd,GPIO_Label,GPIO_ModeDefaultEXTI +PB12.GPIO_Label=BUTTON_RIGHT +PB12.GPIO_ModeDefaultEXTI=GPIO_MODE_IT_RISING_FALLING +PB12.GPIO_PuPd=GPIO_PULLUP +PB12.Locked=true +PB12.Signal=GPXTI12 +PB13.GPIOParameters=GPIO_Label +PB13.GPIO_Label=RFID_OUT +PB13.Locked=true +PB13.Mode=Output Compare1 CH1N +PB13.Signal=TIM1_CH1N +PB14.GPIOParameters=GPIO_Label +PB14.GPIO_Label=iBTN +PB14.Signal=GPIO_Analog +PB15.GPIOParameters=GPIO_Label +PB15.GPIO_Label=SPI_D_MOSI +PB15.Locked=true +PB15.Mode=Full_Duplex_Master +PB15.Signal=SPI2_MOSI +PB2.GPIOParameters=GPIO_Label +PB2.GPIO_Label=PB2 +PB2.Signal=GPIO_Analog +PB3.GPIOParameters=GPIO_Label +PB3.GPIO_Label=PB3 +PB3.Locked=true +PB3.Signal=GPIO_Analog +PB4.GPIOParameters=GPIO_Label +PB4.GPIO_Label=SPI_R_MISO +PB4.Locked=true +PB4.Mode=Full_Duplex_Master +PB4.Signal=SPI1_MISO +PB5.GPIOParameters=GPIO_Label +PB5.GPIO_Label=SPI_R_MOSI +PB5.Locked=true +PB5.Mode=Full_Duplex_Master +PB5.Signal=SPI1_MOSI +PB6.Locked=true +PB6.Mode=Asynchronous +PB6.Signal=USART1_TX +PB7.Locked=true +PB7.Mode=Asynchronous +PB7.Signal=USART1_RX +PB8.GPIOParameters=GPIO_Label +PB8.GPIO_Label=SPEAKER +PB8.Locked=true +PB8.Signal=S_TIM16_CH1 +PB9.GPIOParameters=GPIO_Label +PB9.GPIO_Label=IR_TX +PB9.Locked=true +PB9.Mode=PWM Generation3 CH3N +PB9.Signal=TIM1_CH3N +PC0.GPIOParameters=GPIO_Label +PC0.GPIO_Label=PC0 +PC0.Locked=true +PC0.Signal=GPIO_Analog +PC1.GPIOParameters=GPIO_Label +PC1.GPIO_Label=PC1 +PC1.Locked=true +PC1.Signal=GPIO_Analog +PC10.GPIOParameters=GPIO_Label +PC10.GPIO_Label=SD_CD +PC10.Locked=true +PC10.Signal=GPIO_Input +PC11.GPIOParameters=PinState,GPIO_Label +PC11.GPIO_Label=DISPLAY_CS +PC11.Locked=true +PC11.PinState=GPIO_PIN_SET +PC11.Signal=GPIO_Output +PC12.GPIOParameters=GPIO_Speed,PinState,GPIO_Label +PC12.GPIO_Label=SD_CS +PC12.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH +PC12.Locked=true +PC12.PinState=GPIO_PIN_SET +PC12.Signal=GPIO_Output +PC13.GPIOParameters=GPIO_PuPd,GPIO_Label,GPIO_ModeDefaultEXTI +PC13.GPIO_Label=BUTTON_BACK +PC13.GPIO_ModeDefaultEXTI=GPIO_MODE_IT_RISING_FALLING +PC13.GPIO_PuPd=GPIO_PULLUP +PC13.Locked=true +PC13.Signal=GPXTI13 +PC14-OSC32_IN.GPIOParameters=GPIO_Label +PC14-OSC32_IN.GPIO_Label=QUARTZ_32MHZ_IN +PC14-OSC32_IN.Locked=true +PC14-OSC32_IN.Mode=LSE-External-Oscillator +PC14-OSC32_IN.Signal=RCC_OSC32_IN +PC15-OSC32_OUT.GPIOParameters=GPIO_Label +PC15-OSC32_OUT.GPIO_Label=QUARTZ_32MHZ_OUT +PC15-OSC32_OUT.Locked=true +PC15-OSC32_OUT.Mode=LSE-External-Oscillator +PC15-OSC32_OUT.Signal=RCC_OSC32_OUT +PC2.GPIOParameters=GPIO_Label +PC2.GPIO_Label=SPI_D_MISO +PC2.Locked=true +PC2.Mode=Full_Duplex_Master +PC2.Signal=SPI2_MISO +PC3.GPIOParameters=GPIO_Label +PC3.GPIO_Label=PC3 +PC3.Signal=GPIO_Analog +PC4.GPIOParameters=GPIO_Label +PC4.GPIO_Label=RF_SW_0 +PC4.Locked=true +PC4.Signal=GPIO_Output +PC5.GPIOParameters=GPIO_Label +PC5.GPIO_Label=RFID_RF_IN +PC5.Locked=true +PC5.Signal=SharedAnalog_PC5 +PC6.GPIOParameters=GPIO_Label +PC6.GPIO_Label=BUTTON_DOWN +PC6.Locked=true +PC6.Signal=GPIO_Input +PCC.Ble.ConnectionInterval=1000.0 +PCC.Ble.DataLength=6 +PCC.Ble.IsUsed=false +PCC.Ble.Mode=NOT_SELECTED +PCC.Ble.PowerLevel=Min +PCC.Zigbee.IsUsed=false +PCC.Zigbee.Mode=Sleepy End Device +PCC.Zigbee.Payload=15 +PCC.Zigbee.PoolPeriodicity=480.0 +PCC.Zigbee.PowerLevel=Min +PCC.Zigbee.RequestPeriodicity=1500.0 +PD0.GPIOParameters=GPIO_Speed,PinState,GPIO_Label +PD0.GPIO_Label=CC1101_CS +PD0.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH +PD0.Locked=true +PD0.PinState=GPIO_PIN_SET +PD0.Signal=GPIO_Output +PD1.GPIOParameters=GPIO_Label +PD1.GPIO_Label=SPI_D_SCK +PD1.Locked=true +PD1.Mode=Full_Duplex_Master +PD1.Signal=SPI2_SCK +PE4.GPIOParameters=GPIO_Speed,PinState,GPIO_Label +PE4.GPIO_Label=NFC_CS +PE4.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH +PE4.Locked=true +PE4.PinState=GPIO_PIN_SET +PE4.Signal=GPIO_Output +PH3-BOOT0.GPIOParameters=GPIO_Label,GPIO_ModeDefaultEXTI +PH3-BOOT0.GPIO_Label=BUTTON_OK +PH3-BOOT0.GPIO_ModeDefaultEXTI=GPIO_MODE_IT_RISING_FALLING +PH3-BOOT0.Locked=true +PH3-BOOT0.Signal=GPXTI3 +PinOutPanel.RotationAngle=0 +ProjectManager.AskForMigrate=true +ProjectManager.BackupPrevious=false +ProjectManager.CompilerOptimize=6 +ProjectManager.ComputerToolchain=false +ProjectManager.CoupleFile=true +ProjectManager.CustomerFirmwarePackage=../../../../lib/STM32CubeWB +ProjectManager.DefaultFWLocation=false +ProjectManager.DeletePrevious=true +ProjectManager.DeviceId=STM32WB55RGVx +ProjectManager.FirmwarePackage=STM32Cube FW_WB V1.12.1 +ProjectManager.FreePins=false +ProjectManager.HalAssertFull=false +ProjectManager.HeapSize=0x400 +ProjectManager.KeepUserCode=true +ProjectManager.LastFirmware=true +ProjectManager.LibraryCopy=2 +ProjectManager.MainLocation=Src +ProjectManager.NoMain=false +ProjectManager.PreviousToolchain= +ProjectManager.ProjectBuild=false +ProjectManager.ProjectFileName=f7.ioc +ProjectManager.ProjectName=f7 +ProjectManager.RegisterCallBack= +ProjectManager.StackSize=0x1000 +ProjectManager.TargetToolchain=Makefile +ProjectManager.ToolChainLocation= +ProjectManager.UnderRoot=false +ProjectManager.functionlistsort=1-MX_GPIO_Init-GPIO-false-HAL-true,2-SystemClock_Config-RCC-false-LL-false,3-MX_ADC1_Init-ADC1-false-HAL-true,4-MX_I2C1_Init-I2C1-false-LL-true,5-MX_RTC_Init-RTC-false-HAL-true,6-MX_SPI1_Init-SPI1-false-HAL-true,7-MX_SPI2_Init-SPI2-false-HAL-true,8-MX_USB_Device_Init-USB_DEVICE-false-HAL-false,9-MX_TIM1_Init-TIM1-false-HAL-true,10-MX_TIM2_Init-TIM2-false-HAL-true,11-MX_TIM16_Init-TIM16-false-HAL-true,12-MX_COMP1_Init-COMP1-false-HAL-true,13-MX_RF_Init-RF-false-HAL-true,14-MX_PKA_Init-PKA-false-HAL-true,15-MX_RNG_Init-RNG-false-HAL-true,16-MX_AES1_Init-AES1-false-HAL-true,17-MX_AES2_Init-AES2-false-HAL-true,18-MX_CRC_Init-CRC-false-HAL-true,19-MX_USART1_UART_Init-USART1-false-LL-true,0-MX_HSEM_Init-HSEM-false-HAL-true +RCC.ADCFreq_Value=48000000 +RCC.AHB2CLKDivider=RCC_SYSCLK_DIV2 +RCC.AHBFreq_Value=64000000 +RCC.APB1Freq_Value=64000000 +RCC.APB1TimFreq_Value=64000000 +RCC.APB2Freq_Value=64000000 +RCC.APB2TimFreq_Value=64000000 +RCC.APB3Freq_Value=16000000 +RCC.Cortex2Freq_Value=32000000 +RCC.CortexFreq_Value=64000000 +RCC.EnableCSSLSE=true +RCC.EnbaleCSS=true +RCC.FCLK2Freq_Value=32000000 +RCC.FCLKCortexFreq_Value=64000000 +RCC.FamilyName=M +RCC.HCLK2Freq_Value=32000000 +RCC.HCLK3Freq_Value=64000000 +RCC.HCLKFreq_Value=64000000 +RCC.HCLKRFFreq_Value=16000000 +RCC.HSE_VALUE=32000000 +RCC.HSI48_VALUE=48000000 +RCC.HSI_VALUE=16000000 +RCC.I2C1Freq_Value=64000000 +RCC.I2C3Freq_Value=64000000 +RCC.IPParameters=ADCFreq_Value,AHB2CLKDivider,AHBFreq_Value,APB1Freq_Value,APB1TimFreq_Value,APB2Freq_Value,APB2TimFreq_Value,APB3Freq_Value,Cortex2Freq_Value,CortexFreq_Value,EnableCSSLSE,EnbaleCSS,FCLK2Freq_Value,FCLKCortexFreq_Value,FamilyName,HCLK2Freq_Value,HCLK3Freq_Value,HCLKFreq_Value,HCLKRFFreq_Value,HSE_VALUE,HSI48_VALUE,HSI_VALUE,I2C1Freq_Value,I2C3Freq_Value,LCDFreq_Value,LPTIM1CLockSelection,LPTIM1Freq_Value,LPTIM2Freq_Value,LPUART1Freq_Value,LSCOPinFreq_Value,LSE_Drive_Capability,LSE_Timout,LSI_VALUE,MCO1PinFreq_Value,MSIOscState,PLLM,PLLPoutputFreq_Value,PLLQoutputFreq_Value,PLLRCLKFreq_Value,PLLSAI1N,PLLSAI1PoutputFreq_Value,PLLSAI1QoutputFreq_Value,PLLSAI1RoutputFreq_Value,PLLSourceVirtual,PREFETCH_ENABLE,PWRFreq_Value,RFWKPClockSelection,RFWKPFreq_Value,RNGCLockSelection,RNGFreq_Value,RTCClockSelection,RTCFreq_Value,SAI1Freq_Value,SMPS1Freq_Value,SMPSCLockSelectionVirtual,SMPSDivider,SMPSFreq_Value,SYSCLKFreq_VALUE,SYSCLKSource,USART1Freq_Value,USBFreq_Value,VCOInputFreq_Value,VCOOutputFreq_Value,VCOSAI1OutputFreq_Value +RCC.LCDFreq_Value=32768 +RCC.LPTIM1CLockSelection=RCC_LPTIM1CLKSOURCE_LSE +RCC.LPTIM1Freq_Value=32768 +RCC.LPTIM2Freq_Value=64000000 +RCC.LPUART1Freq_Value=64000000 +RCC.LSCOPinFreq_Value=32000 +RCC.LSE_Drive_Capability=RCC_LSEDRIVE_MEDIUMLOW +RCC.LSE_Timout=1000 +RCC.LSI_VALUE=32000 +RCC.MCO1PinFreq_Value=64000000 +RCC.MSIOscState=DISABLED +RCC.PLLM=RCC_PLLM_DIV2 +RCC.PLLPoutputFreq_Value=64000000 +RCC.PLLQoutputFreq_Value=64000000 +RCC.PLLRCLKFreq_Value=64000000 +RCC.PLLSAI1N=6 +RCC.PLLSAI1PoutputFreq_Value=48000000 +RCC.PLLSAI1QoutputFreq_Value=48000000 +RCC.PLLSAI1RoutputFreq_Value=48000000 +RCC.PLLSourceVirtual=RCC_PLLSOURCE_HSE +RCC.PREFETCH_ENABLE=1 +RCC.PWRFreq_Value=64000000 +RCC.RFWKPClockSelection=RCC_RFWKPCLKSOURCE_LSE +RCC.RFWKPFreq_Value=32768 +RCC.RNGCLockSelection=RCC_RNGCLKSOURCE_CLK48 +RCC.RNGFreq_Value=16000000 +RCC.RTCClockSelection=RCC_RTCCLKSOURCE_LSE +RCC.RTCFreq_Value=32768 +RCC.SAI1Freq_Value=48000000 +RCC.SMPS1Freq_Value=8000000 +RCC.SMPSCLockSelectionVirtual=RCC_SMPSCLKSOURCE_HSE +RCC.SMPSDivider=4 +RCC.SMPSFreq_Value=4000000 +RCC.SYSCLKFreq_VALUE=64000000 +RCC.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK +RCC.USART1Freq_Value=64000000 +RCC.USBFreq_Value=48000000 +RCC.VCOInputFreq_Value=16000000 +RCC.VCOOutputFreq_Value=128000000 +RCC.VCOSAI1OutputFreq_Value=96000000 +RF1.Locked=true +RF1.Mode=RF1_Activate +RF1.Signal=RF_RF1 +SH.GPXTI10.0=GPIO_EXTI10 +SH.GPXTI10.ConfNb=1 +SH.GPXTI11.0=GPIO_EXTI11 +SH.GPXTI11.ConfNb=1 +SH.GPXTI12.0=GPIO_EXTI12 +SH.GPXTI12.ConfNb=1 +SH.GPXTI13.0=GPIO_EXTI13 +SH.GPXTI13.ConfNb=1 +SH.GPXTI3.0=GPIO_EXTI3 +SH.GPXTI3.ConfNb=1 +SH.S_TIM16_CH1.0=TIM16_CH1,PWM Generation1 CH1 +SH.S_TIM16_CH1.ConfNb=1 +SH.S_TIM2_CH1.0=TIM2_CH1,Input_Capture1_from_TI1 +SH.S_TIM2_CH1.1=TIM2_CH1,Input_Capture2_from_TI1 +SH.S_TIM2_CH1.ConfNb=2 +SH.SharedAnalog_PC5.0=COMP1_INP,INP +SH.SharedAnalog_PC5.1=ADC1_IN14,IN14-Single-Ended +SH.SharedAnalog_PC5.ConfNb=2 +SPI1.BaudRatePrescaler=SPI_BAUDRATEPRESCALER_16 +SPI1.CLKPhase=SPI_PHASE_2EDGE +SPI1.CalculateBaudRate=4.0 MBits/s +SPI1.DataSize=SPI_DATASIZE_8BIT +SPI1.Direction=SPI_DIRECTION_2LINES +SPI1.IPParameters=VirtualType,Mode,Direction,CalculateBaudRate,DataSize,CLKPhase,BaudRatePrescaler +SPI1.Mode=SPI_MODE_MASTER +SPI1.VirtualType=VM_MASTER +SPI2.BaudRatePrescaler=SPI_BAUDRATEPRESCALER_16 +SPI2.CLKPhase=SPI_PHASE_1EDGE +SPI2.CalculateBaudRate=4.0 MBits/s +SPI2.DataSize=SPI_DATASIZE_8BIT +SPI2.Direction=SPI_DIRECTION_2LINES +SPI2.IPParameters=VirtualType,Mode,Direction,CalculateBaudRate,DataSize,BaudRatePrescaler,CLKPhase +SPI2.Mode=SPI_MODE_MASTER +SPI2.VirtualType=VM_MASTER +TIM1.Channel-Output\ Compare1\ CH1N=TIM_CHANNEL_1 +TIM1.Channel-PWM\ Generation3\ CH3N=TIM_CHANNEL_3 +TIM1.IPParameters=Channel-Output Compare1 CH1N,Channel-PWM Generation3 CH3N +TIM16.Channel=TIM_CHANNEL_1 +TIM16.IPParameters=Channel,Pulse,Prescaler,Period +TIM16.Period=291 +TIM16.Prescaler=500 - 1 +TIM16.Pulse=145 +TIM2.AutoReloadPreload=TIM_AUTORELOAD_PRELOAD_ENABLE +TIM2.Channel-Input_Capture1_from_TI1=TIM_CHANNEL_1 +TIM2.Channel-Input_Capture2_from_TI1=TIM_CHANNEL_2 +TIM2.ICPolarity_CH1=TIM_INPUTCHANNELPOLARITY_FALLING +TIM2.IPParameters=Channel-Input_Capture1_from_TI1,ICPolarity_CH1,AutoReloadPreload,Prescaler,Channel-Input_Capture2_from_TI1 +TIM2.Prescaler=64-1 +USART1.AutoBaudRateEnableParam=UART_ADVFEATURE_AUTOBAUDRATE_ENABLE +USART1.IPParameters=VirtualMode-Asynchronous,Mode,AutoBaudRateEnableParam +USART1.Mode=MODE_TX +USART1.VirtualMode-Asynchronous=VM_ASYNC +USB_DEVICE.APP_RX_DATA_SIZE=512 +USB_DEVICE.APP_TX_DATA_SIZE=512 +USB_DEVICE.CLASS_NAME_FS=CDC +USB_DEVICE.IPParameters=VirtualMode,VirtualModeFS,CLASS_NAME_FS,MANUFACTURER_STRING,PRODUCT_STRING_CDC_FS,APP_RX_DATA_SIZE,APP_TX_DATA_SIZE +USB_DEVICE.MANUFACTURER_STRING=Flipper +USB_DEVICE.PRODUCT_STRING_CDC_FS=Flipper Control Virtual ComPort +USB_DEVICE.VirtualMode=Cdc +USB_DEVICE.VirtualModeFS=Cdc_FS +VP_ADC1_TempSens_Input.Mode=IN-TempSens +VP_ADC1_TempSens_Input.Signal=ADC1_TempSens_Input +VP_ADC1_Vref_Input.Mode=IN-Vrefint +VP_ADC1_Vref_Input.Signal=ADC1_Vref_Input +VP_AES1_VS_AES.Mode=AES_Activate +VP_AES1_VS_AES.Signal=AES1_VS_AES +VP_AES2_VS_AES.Mode=AES_Activate +VP_AES2_VS_AES.Signal=AES2_VS_AES +VP_COMP1_VS_VREFINT14.Mode=VREFINT_14 +VP_COMP1_VS_VREFINT14.Signal=COMP1_VS_VREFINT14 +VP_CRC_VS_CRC.Mode=CRC_Activate +VP_CRC_VS_CRC.Signal=CRC_VS_CRC +VP_FREERTOS_VS_CMSIS_V2.Mode=CMSIS_V2 +VP_FREERTOS_VS_CMSIS_V2.Signal=FREERTOS_VS_CMSIS_V2 +VP_HSEM_VS_HSEM.Mode=HSEM_Activate +VP_HSEM_VS_HSEM.Signal=HSEM_VS_HSEM +VP_PKA_VS_PKA.Mode=PKA_Activate +VP_PKA_VS_PKA.Signal=PKA_VS_PKA +VP_RNG_VS_RNG.Mode=RNG_Activate +VP_RNG_VS_RNG.Signal=RNG_VS_RNG +VP_RTC_VS_RTC_Activate.Mode=RTC_Enabled +VP_RTC_VS_RTC_Activate.Signal=RTC_VS_RTC_Activate +VP_RTC_VS_RTC_Calendar.Mode=RTC_Calendar +VP_RTC_VS_RTC_Calendar.Signal=RTC_VS_RTC_Calendar +VP_SYS_VS_Systick.Mode=SysTick +VP_SYS_VS_Systick.Signal=SYS_VS_Systick +VP_TIM16_VS_ClockSourceINT.Mode=Enable_Timer +VP_TIM16_VS_ClockSourceINT.Signal=TIM16_VS_ClockSourceINT +VP_TIM1_VS_ClockSourceINT.Mode=Internal +VP_TIM1_VS_ClockSourceINT.Signal=TIM1_VS_ClockSourceINT +VP_TIM2_VS_ClockSourceINT.Mode=Internal +VP_TIM2_VS_ClockSourceINT.Signal=TIM2_VS_ClockSourceINT +VP_USB_DEVICE_VS_USB_DEVICE_CDC_FS.Mode=CDC_FS +VP_USB_DEVICE_VS_USB_DEVICE_CDC_FS.Signal=USB_DEVICE_VS_USB_DEVICE_CDC_FS +board=custom diff --git a/firmware/targets/f7/cube/startup_stm32wb55xx_cm4.s b/firmware/targets/f7/cube/startup_stm32wb55xx_cm4.s new file mode 100644 index 00000000..c5c2b3fc --- /dev/null +++ b/firmware/targets/f7/cube/startup_stm32wb55xx_cm4.s @@ -0,0 +1,444 @@ +/** + ****************************************************************************** + * @file startup_stm32wb55xx_cm4.s + * @author MCD Application Team + * @brief STM32WB55xx devices vector table GCC toolchain. + * This module performs: + * - Set the initial SP + * - Set the initial PC == Reset_Handler, + * - Set the vector table entries with the exceptions ISR address + * - Branches to main in the C library (which eventually + * calls main()). + * After Reset the Cortex-M4 processor is in Thread mode, + * priority is Privileged, and the Stack is set to Main. + ****************************************************************************** + * @attention + * + * Copyright (c) 2019-2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + + .syntax unified + .cpu cortex-m4 + .fpu softvfp + .thumb + +.global g_pfnVectors +.global Default_Handler + +/* start address for the initialization values of the .data section. +defined in linker script */ +.word _sidata +/* start address for the .data section. defined in linker script */ +.word _sdata +/* end address for the .data section. defined in linker script */ +.word _edata +/* start address for the .bss section. defined in linker script */ +.word _sbss +/* end address for the .bss section. defined in linker script */ +.word _ebss +/* start address for the .MB_MEM2 section. defined in linker script */ +.word _sMB_MEM2 +/* end address for the .MB_MEM2 section. defined in linker script */ +.word _eMB_MEM2 + +/* INIT_BSS macro is used to fill the specified region [start : end] with zeros */ +.macro INIT_BSS start, end + ldr r0, =\start + ldr r1, =\end + movs r3, #0 + bl LoopFillZerobss +.endm + +/* INIT_DATA macro is used to copy data in the region [start : end] starting from 'src' */ +.macro INIT_DATA start, end, src + ldr r0, =\start + ldr r1, =\end + ldr r2, =\src + movs r3, #0 + bl LoopCopyDataInit +.endm + +.section .text.data_initializers +CopyDataInit: + ldr r4, [r2, r3] + str r4, [r0, r3] + adds r3, r3, #4 + +LoopCopyDataInit: + adds r4, r0, r3 + cmp r4, r1 + bcc CopyDataInit + bx lr + +FillZerobss: + str r3, [r0] + adds r0, r0, #4 + +LoopFillZerobss: + cmp r0, r1 + bcc FillZerobss + bx lr + + .section .text.Reset_Handler + .weak Reset_Handler + .type Reset_Handler, %function +Reset_Handler: + ldr r0, =_estack + mov sp, r0 /* set stack pointer */ +/* Call the clock system intitialization function.*/ + bl SystemInit + +/* Copy the data segment initializers from flash to SRAM */ + INIT_DATA _sdata, _edata, _sidata + +/* Zero fill the bss segments. */ + INIT_BSS _sbss, _ebss + INIT_BSS _sMB_MEM2, _eMB_MEM2 + +/* Call static constructors */ + bl __libc_init_array +/* Call the application s entry point.*/ + bl main + +LoopForever: + b LoopForever + +.size Reset_Handler, .-Reset_Handler + +/** + * @brief This is the code that gets called when the processor receives an + * unexpected interrupt. This simply enters an infinite loop, preserving + * the system state for examination by a debugger. + * + * @param None + * @retval None +*/ + .section .text.Default_Handler,"ax",%progbits +Default_Handler: +Infinite_Loop: + b Infinite_Loop + .size Default_Handler, .-Default_Handler +/****************************************************************************** +* +* The minimal vector table for a Cortex-M4. Note that the proper constructs +* must be placed on this to ensure that it ends up at physical address +* 0x0000.0000. +* +******************************************************************************/ + .section .isr_vector,"a",%progbits + .type g_pfnVectors, %object + .size g_pfnVectors, .-g_pfnVectors + + +g_pfnVectors: + .word _estack + .word Reset_Handler + .word NMI_Handler + .word HardFault_Handler + .word MemManage_Handler + .word BusFault_Handler + .word UsageFault_Handler + .word 0 + .word 0 + .word 0 + .word 0 + .word SVC_Handler + .word DebugMon_Handler + .word 0 + .word PendSV_Handler + .word SysTick_Handler + .word WWDG_IRQHandler + .word PVD_PVM_IRQHandler + .word TAMP_STAMP_LSECSS_IRQHandler + .word RTC_WKUP_IRQHandler + .word FLASH_IRQHandler + .word RCC_IRQHandler + .word EXTI0_IRQHandler + .word EXTI1_IRQHandler + .word EXTI2_IRQHandler + .word EXTI3_IRQHandler + .word EXTI4_IRQHandler + .word DMA1_Channel1_IRQHandler + .word DMA1_Channel2_IRQHandler + .word DMA1_Channel3_IRQHandler + .word DMA1_Channel4_IRQHandler + .word DMA1_Channel5_IRQHandler + .word DMA1_Channel6_IRQHandler + .word DMA1_Channel7_IRQHandler + .word ADC1_IRQHandler + .word USB_HP_IRQHandler + .word USB_LP_IRQHandler + .word C2SEV_PWR_C2H_IRQHandler + .word COMP_IRQHandler + .word EXTI9_5_IRQHandler + .word TIM1_BRK_IRQHandler + .word TIM1_UP_TIM16_IRQHandler + .word TIM1_TRG_COM_TIM17_IRQHandler + .word TIM1_CC_IRQHandler + .word TIM2_IRQHandler + .word PKA_IRQHandler + .word I2C1_EV_IRQHandler + .word I2C1_ER_IRQHandler + .word I2C3_EV_IRQHandler + .word I2C3_ER_IRQHandler + .word SPI1_IRQHandler + .word SPI2_IRQHandler + .word USART1_IRQHandler + .word LPUART1_IRQHandler + .word SAI1_IRQHandler + .word TSC_IRQHandler + .word EXTI15_10_IRQHandler + .word RTC_Alarm_IRQHandler + .word CRS_IRQHandler + .word PWR_SOTF_BLEACT_802ACT_RFPHASE_IRQHandler + .word IPCC_C1_RX_IRQHandler + .word IPCC_C1_TX_IRQHandler + .word HSEM_IRQHandler + .word LPTIM1_IRQHandler + .word LPTIM2_IRQHandler + .word LCD_IRQHandler + .word QUADSPI_IRQHandler + .word AES1_IRQHandler + .word AES2_IRQHandler + .word RNG_IRQHandler + .word FPU_IRQHandler + .word DMA2_Channel1_IRQHandler + .word DMA2_Channel2_IRQHandler + .word DMA2_Channel3_IRQHandler + .word DMA2_Channel4_IRQHandler + .word DMA2_Channel5_IRQHandler + .word DMA2_Channel6_IRQHandler + .word DMA2_Channel7_IRQHandler + .word DMAMUX1_OVR_IRQHandler + +/******************************************************************************* +* +* Provide weak aliases for each Exception handler to the Default_Handler. +* As they are weak aliases, any function with the same name will override +* this definition. +* +*******************************************************************************/ + .weak NMI_Handler + .thumb_set NMI_Handler,Default_Handler + + .weak HardFault_Handler + .thumb_set HardFault_Handler,Default_Handler + + .weak MemManage_Handler + .thumb_set MemManage_Handler,Default_Handler + + .weak BusFault_Handler + .thumb_set BusFault_Handler,Default_Handler + + .weak UsageFault_Handler + .thumb_set UsageFault_Handler,Default_Handler + + .weak SVC_Handler + .thumb_set SVC_Handler,Default_Handler + + .weak DebugMon_Handler + .thumb_set DebugMon_Handler,Default_Handler + + .weak PendSV_Handler + .thumb_set PendSV_Handler,Default_Handler + + .weak SysTick_Handler + .thumb_set SysTick_Handler,Default_Handler + + .weak WWDG_IRQHandler + .thumb_set WWDG_IRQHandler,Default_Handler + + .weak PVD_PVM_IRQHandler + .thumb_set PVD_PVM_IRQHandler,Default_Handler + + .weak TAMP_STAMP_LSECSS_IRQHandler + .thumb_set TAMP_STAMP_LSECSS_IRQHandler,Default_Handler + + .weak RTC_WKUP_IRQHandler + .thumb_set RTC_WKUP_IRQHandler,Default_Handler + + .weak FLASH_IRQHandler + .thumb_set FLASH_IRQHandler,Default_Handler + + .weak RCC_IRQHandler + .thumb_set RCC_IRQHandler,Default_Handler + + .weak EXTI0_IRQHandler + .thumb_set EXTI0_IRQHandler,Default_Handler + + .weak EXTI1_IRQHandler + .thumb_set EXTI1_IRQHandler,Default_Handler + + .weak EXTI2_IRQHandler + .thumb_set EXTI2_IRQHandler,Default_Handler + + .weak EXTI3_IRQHandler + .thumb_set EXTI3_IRQHandler,Default_Handler + + .weak EXTI4_IRQHandler + .thumb_set EXTI4_IRQHandler,Default_Handler + + .weak DMA1_Channel1_IRQHandler + .thumb_set DMA1_Channel1_IRQHandler,Default_Handler + + .weak DMA1_Channel2_IRQHandler + .thumb_set DMA1_Channel2_IRQHandler,Default_Handler + + .weak DMA1_Channel3_IRQHandler + .thumb_set DMA1_Channel3_IRQHandler,Default_Handler + + .weak DMA1_Channel4_IRQHandler + .thumb_set DMA1_Channel4_IRQHandler,Default_Handler + + .weak DMA1_Channel5_IRQHandler + .thumb_set DMA1_Channel5_IRQHandler,Default_Handler + + .weak DMA1_Channel6_IRQHandler + .thumb_set DMA1_Channel6_IRQHandler,Default_Handler + + .weak DMA1_Channel7_IRQHandler + .thumb_set DMA1_Channel7_IRQHandler,Default_Handler + + .weak ADC1_IRQHandler + .thumb_set ADC1_IRQHandler,Default_Handler + + .weak USB_HP_IRQHandler + .thumb_set USB_HP_IRQHandler,Default_Handler + + .weak USB_LP_IRQHandler + .thumb_set USB_LP_IRQHandler,Default_Handler + + .weak C2SEV_PWR_C2H_IRQHandler + .thumb_set C2SEV_PWR_C2H_IRQHandler,Default_Handler + + .weak COMP_IRQHandler + .thumb_set COMP_IRQHandler,Default_Handler + + .weak EXTI9_5_IRQHandler + .thumb_set EXTI9_5_IRQHandler,Default_Handler + + .weak TIM1_BRK_IRQHandler + .thumb_set TIM1_BRK_IRQHandler,Default_Handler + + .weak TIM1_UP_TIM16_IRQHandler + .thumb_set TIM1_UP_TIM16_IRQHandler,Default_Handler + + .weak TIM1_TRG_COM_TIM17_IRQHandler + .thumb_set TIM1_TRG_COM_TIM17_IRQHandler,Default_Handler + + .weak TIM1_CC_IRQHandler + .thumb_set TIM1_CC_IRQHandler,Default_Handler + + .weak TIM2_IRQHandler + .thumb_set TIM2_IRQHandler,Default_Handler + + .weak PKA_IRQHandler + .thumb_set PKA_IRQHandler,Default_Handler + + .weak I2C1_EV_IRQHandler + .thumb_set I2C1_EV_IRQHandler,Default_Handler + + .weak I2C1_ER_IRQHandler + .thumb_set I2C1_ER_IRQHandler,Default_Handler + + .weak I2C3_EV_IRQHandler + .thumb_set I2C3_EV_IRQHandler,Default_Handler + + .weak I2C3_ER_IRQHandler + .thumb_set I2C3_ER_IRQHandler,Default_Handler + + .weak SPI1_IRQHandler + .thumb_set SPI1_IRQHandler,Default_Handler + + .weak SPI2_IRQHandler + .thumb_set SPI2_IRQHandler,Default_Handler + + .weak USART1_IRQHandler + .thumb_set USART1_IRQHandler,Default_Handler + + .weak LPUART1_IRQHandler + .thumb_set LPUART1_IRQHandler,Default_Handler + + .weak SAI1_IRQHandler + .thumb_set SAI1_IRQHandler,Default_Handler + + .weak TSC_IRQHandler + .thumb_set TSC_IRQHandler,Default_Handler + + .weak EXTI15_10_IRQHandler + .thumb_set EXTI15_10_IRQHandler,Default_Handler + + .weak RTC_Alarm_IRQHandler + .thumb_set RTC_Alarm_IRQHandler,Default_Handler + + .weak CRS_IRQHandler + .thumb_set CRS_IRQHandler,Default_Handler + + .weak PWR_SOTF_BLEACT_802ACT_RFPHASE_IRQHandler + .thumb_set PWR_SOTF_BLEACT_802ACT_RFPHASE_IRQHandler,Default_Handler + + .weak IPCC_C1_RX_IRQHandler + .thumb_set IPCC_C1_RX_IRQHandler,Default_Handler + + .weak IPCC_C1_TX_IRQHandler + .thumb_set IPCC_C1_TX_IRQHandler,Default_Handler + + .weak HSEM_IRQHandler + .thumb_set HSEM_IRQHandler,Default_Handler + + .weak LPTIM1_IRQHandler + .thumb_set LPTIM1_IRQHandler,Default_Handler + + .weak LPTIM2_IRQHandler + .thumb_set LPTIM2_IRQHandler,Default_Handler + + .weak LCD_IRQHandler + .thumb_set LCD_IRQHandler,Default_Handler + + .weak QUADSPI_IRQHandler + .thumb_set QUADSPI_IRQHandler,Default_Handler + + .weak AES1_IRQHandler + .thumb_set AES1_IRQHandler,Default_Handler + + .weak AES2_IRQHandler + .thumb_set AES2_IRQHandler,Default_Handler + + .weak RNG_IRQHandler + .thumb_set RNG_IRQHandler,Default_Handler + + .weak FPU_IRQHandler + .thumb_set FPU_IRQHandler,Default_Handler + + .weak DMA2_Channel1_IRQHandler + .thumb_set DMA2_Channel1_IRQHandler,Default_Handler + + .weak DMA2_Channel2_IRQHandler + .thumb_set DMA2_Channel2_IRQHandler,Default_Handler + + .weak DMA2_Channel3_IRQHandler + .thumb_set DMA2_Channel3_IRQHandler,Default_Handler + + .weak DMA2_Channel4_IRQHandler + .thumb_set DMA2_Channel4_IRQHandler,Default_Handler + + .weak DMA2_Channel5_IRQHandler + .thumb_set DMA2_Channel5_IRQHandler,Default_Handler + + .weak DMA2_Channel6_IRQHandler + .thumb_set DMA2_Channel6_IRQHandler,Default_Handler + + .weak DMA2_Channel7_IRQHandler + .thumb_set DMA2_Channel7_IRQHandler,Default_Handler + + .weak DMAMUX1_OVR_IRQHandler + .thumb_set DMAMUX1_OVR_IRQHandler,Default_Handler + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/cube/stm32wb55xx_flash_cm4.ld b/firmware/targets/f7/cube/stm32wb55xx_flash_cm4.ld new file mode 100644 index 00000000..fc975f4a --- /dev/null +++ b/firmware/targets/f7/cube/stm32wb55xx_flash_cm4.ld @@ -0,0 +1,187 @@ +/** +***************************************************************************** +** +** File : stm32wb55xx_flash_cm4.ld +** +** Abstract : System Workbench Minimal System calls file +** +** For more information about which c-functions +** need which of these lowlevel functions +** please consult the Newlib libc-manual +** +** Environment : System Workbench for MCU +** +** Distribution: The file is distributed “as is,” without any warranty +** of any kind. +** +***************************************************************************** +** +**

© COPYRIGHT(c) 2019 Ac6

+** +** Redistribution and use in source and binary forms, with or without modification, +** are permitted provided that the following conditions are met: +** 1. Redistributions of source code must retain the above copyright notice, +** this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright notice, +** this list of conditions and the following disclaimer in the documentation +** and/or other materials provided with the distribution. +** 3. Neither the name of Ac6 nor the names of its contributors +** may be used to endorse or promote products derived from this software +** without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +** +***************************************************************************** +*/ + +/* Entry Point */ +ENTRY(Reset_Handler) + +/* Highest address of the user mode stack */ +_estack = 0x20030000; /* end of RAM */ +/* Generate a link error if heap and stack don't fit into RAM */ +_Min_Heap_Size = 0x400; /* required amount of heap */ +_Min_Stack_Size = 0x1000; /* required amount of stack */ + +/* Specify the memory areas */ +MEMORY +{ +FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K +RAM1 (xrw) : ORIGIN = 0x20000008, LENGTH = 0x2FFF8 +RAM_SHARED (xrw) : ORIGIN = 0x20030000, LENGTH = 10K +} + +/* Define output sections */ +SECTIONS +{ + /* The startup code goes first into FLASH */ + .isr_vector : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) /* Startup code */ + . = ALIGN(4); + } >FLASH + + /* The program code and other data goes into FLASH */ + .text : + { + . = ALIGN(4); + *(.text) /* .text sections (code) */ + *(.text*) /* .text* sections (code) */ + *(.glue_7) /* glue arm to thumb code */ + *(.glue_7t) /* glue thumb to arm code */ + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + . = ALIGN(4); + _etext = .; /* define a global symbols at end of code */ + } >FLASH + + /* Constant data goes into FLASH */ + .rodata : + { + . = ALIGN(4); + *(.rodata) /* .rodata sections (constants, strings, etc.) */ + *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ + . = ALIGN(4); + } >FLASH + + .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH + .ARM : { + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + } >FLASH + + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array*)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } >FLASH + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array*)) + PROVIDE_HIDDEN (__init_array_end = .); + } >FLASH + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT(.fini_array.*))) + KEEP (*(.fini_array*)) + PROVIDE_HIDDEN (__fini_array_end = .); + } >FLASH + + /* used by the startup to initialize data */ + _sidata = LOADADDR(.data); + + /* Initialized data sections goes into RAM, load LMA copy after code */ + .data : + { + . = ALIGN(4); + _sdata = .; /* create a global symbol at data start */ + *(.data) /* .data sections */ + *(.data*) /* .data* sections */ + + . = ALIGN(4); + _edata = .; /* define a global symbol at data end */ + } >RAM1 AT> FLASH + + + /* Uninitialized data section */ + . = ALIGN(4); + .bss : + { + /* This is used by the startup in order to initialize the .bss secion */ + _sbss = .; /* define a global symbol at bss start */ + __bss_start__ = _sbss; + *(.bss) + *(.bss*) + *(COMMON) + + . = ALIGN(4); + _ebss = .; /* define a global symbol at bss end */ + __bss_end__ = _ebss; + } >RAM1 + + /* User_heap_stack section, used to check that there is enough RAM left */ + ._user_heap_stack : + { + . = ALIGN(8); + PROVIDE ( end = . ); + PROVIDE ( _end = . ); + . = . + _Min_Heap_Size; + . = . + _Min_Stack_Size; + . = ALIGN(8); + } >RAM1 + + + + /* Remove information from the standard libraries */ + /DISCARD/ : + { + libc.a ( * ) + libm.a ( * ) + libgcc.a ( * ) + } + + .ARM.attributes 0 : { *(.ARM.attributes) } + MAPPING_TABLE (NOLOAD) : { *(MAPPING_TABLE) } >RAM_SHARED + MB_MEM1 (NOLOAD) : { *(MB_MEM1) } >RAM_SHARED + MB_MEM2 (NOLOAD) : { _sMB_MEM2 = . ; *(MB_MEM2) ; _eMB_MEM2 = . ; } >RAM_SHARED +} + + diff --git a/firmware/targets/f7/furi-hal/furi-hal-boot.c b/firmware/targets/f7/furi-hal/furi-hal-boot.c new file mode 100644 index 00000000..978711c5 --- /dev/null +++ b/firmware/targets/f7/furi-hal/furi-hal-boot.c @@ -0,0 +1,31 @@ +#include +#include +#include + +// Boot request enum +#define BOOT_REQUEST_TAINTED 0x00000000 +#define BOOT_REQUEST_CLEAN 0xDADEDADE +#define BOOT_REQUEST_DFU 0xDF00B000 + +void furi_hal_boot_init() { +#ifndef DEBUG + LL_RTC_BAK_SetRegister(RTC, LL_RTC_BKP_DR0, BOOT_REQUEST_TAINTED); +#endif + FURI_LOG_I("FuriHalBoot", "Init OK"); +} + +void furi_hal_boot_set_mode(FuriHalBootMode mode) { + if (mode == FuriHalBootModeNormal) { + LL_RTC_BAK_SetRegister(RTC, LL_RTC_BKP_DR0, BOOT_REQUEST_CLEAN); + } else if (mode == FuriHalBootModeDFU) { + LL_RTC_BAK_SetRegister(RTC, LL_RTC_BKP_DR0, BOOT_REQUEST_DFU); + } +} + +void furi_hal_boot_set_flags(FuriHalBootFlag flags) { + LL_RTC_BAK_SetRegister(RTC, LL_RTC_BKP_DR2, flags); +} + +FuriHalBootFlag furi_hal_boot_get_flags() { + return LL_RTC_BAK_GetRegister(RTC, LL_RTC_BKP_DR2); +} \ No newline at end of file diff --git a/firmware/targets/f7/furi-hal/furi-hal-bt.c b/firmware/targets/f7/furi-hal/furi-hal-bt.c new file mode 100644 index 00000000..f40f9601 --- /dev/null +++ b/firmware/targets/f7/furi-hal/furi-hal-bt.c @@ -0,0 +1,144 @@ +#include +#include +#include +#include +#include +#include +#include + +void furi_hal_bt_init() { + // Explicitly tell that we are in charge of CLK48 domain + HAL_HSEM_FastTake(CFG_HW_CLK48_CONFIG_SEMID); + // Start Core2, init HCI and start GAP/GATT + APPE_Init(); +} + +bool furi_hal_bt_start_app() { + return APP_BLE_Start(); +} + +void furi_hal_bt_dump_state(string_t buffer) { + BleGlueStatus status = APPE_Status(); + if (status == BleGlueStatusStarted) { + uint8_t HCI_Version; + uint16_t HCI_Revision; + uint8_t LMP_PAL_Version; + uint16_t Manufacturer_Name; + uint16_t LMP_PAL_Subversion; + + tBleStatus ret = hci_read_local_version_information( + &HCI_Version, &HCI_Revision, &LMP_PAL_Version, &Manufacturer_Name, &LMP_PAL_Subversion + ); + + string_cat_printf(buffer, + "Ret: %d, HCI_Version: %d, HCI_Revision: %d, LMP_PAL_Version: %d, Manufacturer_Name: %d, LMP_PAL_Subversion: %d", + ret, HCI_Version, HCI_Revision, LMP_PAL_Version, Manufacturer_Name, LMP_PAL_Subversion + ); + } else { + string_cat_printf(buffer, "BLE not ready"); + } +} + +bool furi_hal_bt_is_alive() { + return APPE_Status() == BleGlueStatusStarted; +} + +bool furi_hal_bt_wait_startup() { + uint8_t counter = 0; + while (APPE_Status() == BleGlueStatusStartup) { + osDelay(10); + counter++; + if (counter > 1000) { + return false; + } + } + return true; +} + +bool furi_hal_bt_lock_flash() { + if (!furi_hal_bt_wait_startup()) { + return false; + } + if (APPE_Status() == BleGlueStatusUninitialized) { + HAL_FLASH_Unlock(); + } else { + while (HAL_HSEM_FastTake(CFG_HW_FLASH_SEMID) != HAL_OK) { + osDelay(1); + } + SHCI_C2_FLASH_EraseActivity(ERASE_ACTIVITY_ON); + HAL_FLASH_Unlock(); + while(LL_FLASH_IsOperationSuspended()) {}; + } + return true; +} + +void furi_hal_bt_unlock_flash() { + if (APPE_Status() == BleGlueStatusUninitialized) { + HAL_FLASH_Lock(); + } else { + SHCI_C2_FLASH_EraseActivity(ERASE_ACTIVITY_OFF); + HAL_FLASH_Lock(); + HAL_HSEM_Release(CFG_HW_FLASH_SEMID, HSEM_CPU1_COREID); + } +} + +void furi_hal_bt_start_tone_tx(uint8_t channel, uint8_t power) { + aci_hal_set_tx_power_level(0, power); + aci_hal_tone_start(channel, 0); +} + +void furi_hal_bt_stop_tone_tx() { + aci_hal_tone_stop(); +} + +void furi_hal_bt_start_packet_tx(uint8_t channel, uint8_t pattern, uint8_t datarate) { + hci_le_enhanced_transmitter_test(channel, 0x25, pattern, datarate); +} + +void furi_hal_bt_start_packet_rx(uint8_t channel, uint8_t datarate) { + hci_le_enhanced_receiver_test(channel, datarate, 0); +} + +uint16_t furi_hal_bt_stop_packet_test() { + uint16_t num_of_packets = 0; + hci_le_test_end(&num_of_packets); + return num_of_packets; +} + +void furi_hal_bt_start_rx(uint8_t channel) { + aci_hal_rx_start(channel); +} + +float furi_hal_bt_get_rssi() { + float val; + uint8_t rssi_raw[3]; + + if (aci_hal_read_raw_rssi(rssi_raw) != BLE_STATUS_SUCCESS) { + return 0.0f; + } + + // Some ST magic with rssi + uint8_t agc = rssi_raw[2] & 0xFF; + int rssi = (((int)rssi_raw[1] << 8) & 0xFF00) + (rssi_raw[0] & 0xFF); + if(rssi == 0 || agc > 11) { + val = -127.0; + } else { + val = agc * 6.0f - 127.0f; + while(rssi > 30) { + val += 6.0; + rssi >>=1; + } + val += (417 * rssi + 18080) >> 10; + } + return val; +} + +uint32_t furi_hal_bt_get_transmitted_packets() { + uint32_t packets = 0; + aci_hal_le_tx_test_packet_number(&packets); + return packets; +} + +void furi_hal_bt_stop_rx() { + aci_hal_rx_stop(); +} diff --git a/firmware/targets/f7/furi-hal/furi-hal-clock.c b/firmware/targets/f7/furi-hal/furi-hal-clock.c new file mode 100644 index 00000000..0ed918e3 --- /dev/null +++ b/firmware/targets/f7/furi-hal/furi-hal-clock.c @@ -0,0 +1,141 @@ +#include + +#include +#include +#include +#include + +#define HS_CLOCK_IS_READY() (LL_RCC_HSE_IsReady() && LL_RCC_HSI_IsReady()) +#define LS_CLOCK_IS_READY() (LL_RCC_LSE_IsReady() && LL_RCC_LSI1_IsReady()) + +void furi_hal_clock_init() { + /* Prepare Flash memory for 64mHz system clock */ + LL_FLASH_SetLatency(LL_FLASH_LATENCY_3); + while(LL_FLASH_GetLatency() != LL_FLASH_LATENCY_3); + + /* HSE and HSI configuration and activation */ + LL_RCC_HSE_SetCapacitorTuning(0x26); + LL_RCC_HSE_Enable(); + LL_RCC_HSI_Enable(); + while(!HS_CLOCK_IS_READY()); + LL_RCC_HSE_EnableCSS(); + + /* LSE and LSI1 configuration and activation */ + LL_PWR_EnableBkUpAccess(); + LL_RCC_LSE_SetDriveCapability(LL_RCC_LSEDRIVE_HIGH); + LL_RCC_LSE_Enable(); + LL_RCC_LSI1_Enable(); + while(!LS_CLOCK_IS_READY()); + LL_EXTI_EnableIT_0_31(LL_EXTI_LINE_18); /* Why? Because that's why. See RM0434, Table 61. CPU1 vector table. */ + LL_EXTI_EnableRisingTrig_0_31(LL_EXTI_LINE_18); + LL_RCC_EnableIT_LSECSS(); + LL_RCC_LSE_EnableCSS(); + + /* Main PLL configuration and activation */ + LL_RCC_PLL_ConfigDomain_SYS(LL_RCC_PLLSOURCE_HSE, LL_RCC_PLLM_DIV_2, 8, LL_RCC_PLLR_DIV_2); + LL_RCC_PLL_Enable(); + LL_RCC_PLL_EnableDomain_SYS(); + while(LL_RCC_PLL_IsReady() != 1); + + LL_RCC_PLLSAI1_ConfigDomain_48M(LL_RCC_PLLSOURCE_HSE, LL_RCC_PLLM_DIV_2, 6, LL_RCC_PLLSAI1Q_DIV_2); + LL_RCC_PLLSAI1_ConfigDomain_ADC(LL_RCC_PLLSOURCE_HSE, LL_RCC_PLLM_DIV_2, 6, LL_RCC_PLLSAI1R_DIV_2); + LL_RCC_PLLSAI1_Enable(); + LL_RCC_PLLSAI1_EnableDomain_48M(); + LL_RCC_PLLSAI1_EnableDomain_ADC(); + while(LL_RCC_PLLSAI1_IsReady() != 1); + + /* Sysclk activation on the main PLL */ + /* Set CPU1 prescaler*/ + LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1); + + /* Set CPU2 prescaler*/ + LL_C2_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_2); + + LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL); + while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL); + + /* Set AHB SHARED prescaler*/ + LL_RCC_SetAHB4Prescaler(LL_RCC_SYSCLK_DIV_1); + + /* Set APB1 prescaler*/ + LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_1); + + /* Set APB2 prescaler*/ + LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_1); + + /* Disable MSI */ + LL_RCC_MSI_Disable(); + while(LL_RCC_MSI_IsReady() != 0); + + /* Update CMSIS variable (which can be updated also through SystemCoreClockUpdate function) */ + LL_SetSystemCoreClock(64000000); + + /* Update the time base */ + if (HAL_InitTick (TICK_INT_PRIORITY) != HAL_OK) { + Error_Handler(); + } + + if(LL_RCC_GetRTCClockSource() != LL_RCC_RTC_CLKSOURCE_LSE) { + LL_RCC_ForceBackupDomainReset(); + LL_RCC_ReleaseBackupDomainReset(); + LL_RCC_SetRTCClockSource(LL_RCC_RTC_CLKSOURCE_LSE); + } + + LL_RCC_EnableRTC(); + + LL_RCC_SetUSARTClockSource(LL_RCC_USART1_CLKSOURCE_PCLK2); + LL_RCC_SetADCClockSource(LL_RCC_ADC_CLKSOURCE_PLLSAI1); + LL_RCC_SetI2CClockSource(LL_RCC_I2C1_CLKSOURCE_PCLK1); + LL_RCC_SetRNGClockSource(LL_RCC_RNG_CLKSOURCE_CLK48); + LL_RCC_SetUSBClockSource(LL_RCC_USB_CLKSOURCE_PLLSAI1); + LL_RCC_SetCLK48ClockSource(LL_RCC_CLK48_CLKSOURCE_PLLSAI1); + LL_RCC_SetSMPSClockSource(LL_RCC_SMPS_CLKSOURCE_HSE); + LL_RCC_SetSMPSPrescaler(LL_RCC_SMPS_DIV_1); + LL_RCC_SetRFWKPClockSource(LL_RCC_RFWKP_CLKSOURCE_LSE); + + // AHB1 + LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMAMUX1); + LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA1); + LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C1); + LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_SPI2); + + // AHB2 + LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA); + LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB); + LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOC); + LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOD); + LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOE); + LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOH); + LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SPI1); + + // APB1 + LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_RTCAPB); + LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM2); + + // APB2 + LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_USART1); +} + +void furi_hal_clock_switch_to_hsi() { + LL_RCC_HSI_Enable( ); + + while(!LL_RCC_HSI_IsReady()); + + LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_HSI); + LL_RCC_SetSMPSClockSource(LL_RCC_SMPS_CLKSOURCE_HSI); + + while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_HSI); +} + +void furi_hal_clock_switch_to_pll() { + LL_RCC_HSE_Enable(); + LL_RCC_PLL_Enable(); + + while(!LL_RCC_HSE_IsReady()); + while(!LL_RCC_PLL_IsReady()); + + LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL); + LL_RCC_SetSMPSClockSource(LL_RCC_SMPS_CLKSOURCE_HSE); + + while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL); +} diff --git a/firmware/targets/f7/furi-hal/furi-hal-clock.h b/firmware/targets/f7/furi-hal/furi-hal-clock.h new file mode 100644 index 00000000..3ec59205 --- /dev/null +++ b/firmware/targets/f7/furi-hal/furi-hal-clock.h @@ -0,0 +1,10 @@ +#pragma once + +/** Initialize clocks */ +void furi_hal_clock_init(); + +/** Switch to HSI clock */ +void furi_hal_clock_switch_to_hsi(); + +/** Switch to PLL clock */ +void furi_hal_clock_switch_to_pll(); diff --git a/firmware/targets/f7/furi-hal/furi-hal-console.c b/firmware/targets/f7/furi-hal/furi-hal-console.c new file mode 100644 index 00000000..6c67e0c8 --- /dev/null +++ b/firmware/targets/f7/furi-hal/furi-hal-console.c @@ -0,0 +1,73 @@ +#include + +#include +#include +#include +#include + +#include + +volatile bool furi_hal_console_alive = false; + +void furi_hal_console_init() { + LL_GPIO_InitTypeDef GPIO_InitStruct = {0}; + GPIO_InitStruct.Pin = LL_GPIO_PIN_6|LL_GPIO_PIN_7; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE; + GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW; + GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + GPIO_InitStruct.Alternate = LL_GPIO_AF_7; + LL_GPIO_Init(GPIOB, &GPIO_InitStruct); + + LL_USART_InitTypeDef USART_InitStruct = {0}; + USART_InitStruct.PrescalerValue = LL_USART_PRESCALER_DIV1; + USART_InitStruct.BaudRate = 230400; + USART_InitStruct.DataWidth = LL_USART_DATAWIDTH_8B; + USART_InitStruct.StopBits = LL_USART_STOPBITS_1; + USART_InitStruct.Parity = LL_USART_PARITY_NONE; + USART_InitStruct.TransferDirection = LL_USART_DIRECTION_TX; + USART_InitStruct.HardwareFlowControl = LL_USART_HWCONTROL_NONE; + USART_InitStruct.OverSampling = LL_USART_OVERSAMPLING_16; + LL_USART_Init(USART1, &USART_InitStruct); + LL_USART_SetTXFIFOThreshold(USART1, LL_USART_FIFOTHRESHOLD_1_2); + LL_USART_EnableFIFO(USART1); + LL_USART_ConfigAsyncMode(USART1); + + LL_USART_Enable(USART1); + + while(!LL_USART_IsActiveFlag_TEACK(USART1)) ; + furi_hal_console_alive = true; + + FURI_LOG_I("FuriHalConsole", "Init OK"); +} + +void furi_hal_console_tx(const uint8_t* buffer, size_t buffer_size) { + if (!furi_hal_console_alive) + return; + + while(buffer_size > 0) { + while (!LL_USART_IsActiveFlag_TXE(USART1)); + + LL_USART_TransmitData8(USART1, *buffer); + + buffer++; + buffer_size--; + } + + /* Wait for TC flag to be raised for last char */ + while (!LL_USART_IsActiveFlag_TC(USART1)); +} + +void furi_hal_console_printf(const char format[], ...) { + string_t string; + va_list args; + va_start(args, format); + string_init_vprintf(string, format, args); + va_end(args); + furi_hal_console_tx((const uint8_t*)string_get_cstr(string), string_size(string)); + string_clear(string); +} + +void furi_hal_console_puts(const char *data) { + furi_hal_console_tx((const uint8_t*)data, strlen(data)); +} \ No newline at end of file diff --git a/firmware/targets/f7/furi-hal/furi-hal-console.h b/firmware/targets/f7/furi-hal/furi-hal-console.h new file mode 100644 index 00000000..26ca4540 --- /dev/null +++ b/firmware/targets/f7/furi-hal/furi-hal-console.h @@ -0,0 +1,26 @@ +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void furi_hal_console_init(); + +void furi_hal_console_tx(const uint8_t* buffer, size_t buffer_size); + +/** + * Printf-like plain uart interface + * @warning Will not work in ISR context + * @param format + * @param ... + */ +void furi_hal_console_printf(const char format[], ...); + +void furi_hal_console_puts(const char* data); + +#ifdef __cplusplus +} +#endif diff --git a/firmware/targets/f7/furi-hal/furi-hal-delay.c b/firmware/targets/f7/furi-hal/furi-hal-delay.c new file mode 100644 index 00000000..52de8715 --- /dev/null +++ b/firmware/targets/f7/furi-hal/furi-hal-delay.c @@ -0,0 +1,34 @@ +#include "furi-hal-delay.h" + +#include +#include + +static uint32_t clk_per_microsecond; + +void furi_hal_delay_init(void) { + CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; + DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; + DWT->CYCCNT = 0U; + clk_per_microsecond = SystemCoreClock / 1000000.0f; + FURI_LOG_I("FuriHalDelay", "Init OK"); +} + +void delay_us(float microseconds) { + uint32_t start = DWT->CYCCNT; + uint32_t time_ticks = microseconds * clk_per_microsecond; + while((DWT->CYCCNT - start) < time_ticks) { + }; +} + +// cannot be used in ISR +// TODO add delay_ISR variant +void delay(float milliseconds) { + uint32_t ticks = milliseconds / (1000.0f / osKernelGetTickFreq()); + osStatus_t result = osDelay(ticks); + (void)result; + furi_assert(result == osOK); +} + +uint32_t millis(void){ + return HAL_GetTick(); +} diff --git a/firmware/targets/f7/furi-hal/furi-hal-flash.c b/firmware/targets/f7/furi-hal/furi-hal-flash.c new file mode 100644 index 00000000..5346965f --- /dev/null +++ b/firmware/targets/f7/furi-hal/furi-hal-flash.c @@ -0,0 +1,89 @@ +#include +#include +#include +#include + +/* Free flash space borders, exported by linker */ +extern const void __free_flash_start__; + +#define FURI_HAL_FLASH_READ_BLOCK 8 +#define FURI_HAL_FLASH_WRITE_BLOCK 8 +#define FURI_HAL_FLASH_PAGE_SIZE 4096 +#define FURI_HAL_FLASH_CYCLES_COUNT 10000 + +size_t furi_hal_flash_get_base() { + return FLASH_BASE; +} + +size_t furi_hal_flash_get_read_block_size() { + return FURI_HAL_FLASH_READ_BLOCK; +} + +size_t furi_hal_flash_get_write_block_size() { + return FURI_HAL_FLASH_WRITE_BLOCK; +} + +size_t furi_hal_flash_get_page_size() { + return FURI_HAL_FLASH_PAGE_SIZE; +} + +size_t furi_hal_flash_get_cycles_count() { + return FURI_HAL_FLASH_CYCLES_COUNT; +} + +const void* furi_hal_flash_get_free_start_address() { + return &__free_flash_start__; +} + +const void* furi_hal_flash_get_free_end_address() { + FLASH_OBProgramInitTypeDef pOBInit; + HAL_FLASHEx_OBGetConfig(&pOBInit); + return (const void *)pOBInit.SecureFlashStartAddr; +} + +size_t furi_hal_flash_get_free_page_start_address() { + size_t start = (size_t)furi_hal_flash_get_free_start_address(); + size_t page_start = start - start % FURI_HAL_FLASH_PAGE_SIZE; + if (page_start != start) { + page_start += FURI_HAL_FLASH_PAGE_SIZE; + } + return page_start; +} + +size_t furi_hal_flash_get_free_page_count() { + size_t end = (size_t)furi_hal_flash_get_free_end_address(); + size_t page_start = (size_t)furi_hal_flash_get_free_page_start_address(); + return (end-page_start) / FURI_HAL_FLASH_PAGE_SIZE; +} + +bool furi_hal_flash_erase(uint8_t page, uint8_t count) { + if (!furi_hal_bt_lock_flash()) { + return false; + } + FLASH_EraseInitTypeDef erase; + erase.TypeErase = FLASH_TYPEERASE_PAGES; + erase.Page = page; + erase.NbPages = count; + uint32_t error; + HAL_StatusTypeDef status = HAL_FLASHEx_Erase(&erase, &error); + furi_hal_bt_unlock_flash(); + return status == HAL_OK; +} + +bool furi_hal_flash_write_dword(size_t address, uint64_t data) { + if (!furi_hal_bt_lock_flash()) { + return false; + } + HAL_StatusTypeDef status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, address, data); + furi_hal_bt_unlock_flash(); + return status == HAL_OK; +} + +bool furi_hal_flash_write_dword_from(size_t address, size_t source_address) { + if (!furi_hal_bt_lock_flash()) { + return false; + } + HAL_StatusTypeDef status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_FAST, address, source_address); + furi_hal_bt_unlock_flash(); + return status == HAL_OK; +} diff --git a/firmware/targets/f7/furi-hal/furi-hal-flash.h b/firmware/targets/f7/furi-hal/furi-hal-flash.h new file mode 100644 index 00000000..3ef9b730 --- /dev/null +++ b/firmware/targets/f7/furi-hal/furi-hal-flash.h @@ -0,0 +1,74 @@ +#pragma once + +#include +#include +#include + +/** Get flash base address + * @return pointer to flash base + */ +size_t furi_hal_flash_get_base(); + +/** Get flash read block size + * @return size in bytes + */ +size_t furi_hal_flash_get_read_block_size(); + +/** Get flash write block size + * @return size in bytes + */ +size_t furi_hal_flash_get_write_block_size(); + +/** Get flash page size + * @return size in bytes + */ +size_t furi_hal_flash_get_page_size(); + +/** Get expected flash cycles count + * @return count of erase-write operations + */ +size_t furi_hal_flash_get_cycles_count(); + +/** Get free flash start address + * @return pointer to free region start + */ +const void* furi_hal_flash_get_free_start_address(); + +/** Get free flash end address + * @return pointer to free region end + */ +const void* furi_hal_flash_get_free_end_address(); + +/** Get first free page start address + * @return first free page memory address + */ +size_t furi_hal_flash_get_free_page_start_address(); + +/** Get free page count + * @return free page count + */ +size_t furi_hal_flash_get_free_page_count(); + +/* + * Erase Flash + * Locking operation, uses HSEM to manage shared access. + * @param page, page number + * @param count, page count to erase + */ +bool furi_hal_flash_erase(uint8_t page, uint8_t count); + +/* + * Write double word (64 bits) + * Locking operation, uses HSEM to manage shared access. + * @param address - destination address, must be double word aligned. + * @param data - data to write + */ +bool furi_hal_flash_write_dword(size_t address, uint64_t data); + +/* + * Write double word (64 bits) from address + * Locking operation, uses HSEM to manage shared access. + * @param address - destination address, must be block aligned + * @param source_address - source address + */ +bool furi_hal_flash_write_dword_from(size_t address, size_t source_address); diff --git a/firmware/targets/f7/furi-hal/furi-hal-gpio.c b/firmware/targets/f7/furi-hal/furi-hal-gpio.c new file mode 100644 index 00000000..1de1657f --- /dev/null +++ b/firmware/targets/f7/furi-hal/furi-hal-gpio.c @@ -0,0 +1,299 @@ +#include +#include +#include + +#define GET_SYSCFG_EXTI_PORT(gpio) \ + (((gpio) == (GPIOA)) ? LL_SYSCFG_EXTI_PORTA : \ + ((gpio) == (GPIOB)) ? LL_SYSCFG_EXTI_PORTB : \ + ((gpio) == (GPIOC)) ? LL_SYSCFG_EXTI_PORTC : \ + ((gpio) == (GPIOD)) ? LL_SYSCFG_EXTI_PORTD : \ + ((gpio) == (GPIOE)) ? LL_SYSCFG_EXTI_PORTE : \ + LL_SYSCFG_EXTI_PORTH) + +#define GPIO_PIN_MAP(pin, prefix) \ + (((pin) == (LL_GPIO_PIN_0)) ? prefix##0 : \ + ((pin) == (LL_GPIO_PIN_1)) ? prefix##1 : \ + ((pin) == (LL_GPIO_PIN_2)) ? prefix##2 : \ + ((pin) == (LL_GPIO_PIN_3)) ? prefix##3 : \ + ((pin) == (LL_GPIO_PIN_4)) ? prefix##4 : \ + ((pin) == (LL_GPIO_PIN_5)) ? prefix##5 : \ + ((pin) == (LL_GPIO_PIN_6)) ? prefix##6 : \ + ((pin) == (LL_GPIO_PIN_7)) ? prefix##7 : \ + ((pin) == (LL_GPIO_PIN_8)) ? prefix##8 : \ + ((pin) == (LL_GPIO_PIN_9)) ? prefix##9 : \ + ((pin) == (LL_GPIO_PIN_10)) ? prefix##10 : \ + ((pin) == (LL_GPIO_PIN_11)) ? prefix##11 : \ + ((pin) == (LL_GPIO_PIN_12)) ? prefix##12 : \ + ((pin) == (LL_GPIO_PIN_13)) ? prefix##13 : \ + ((pin) == (LL_GPIO_PIN_14)) ? prefix##14 : \ + prefix##15) + +#define GET_SYSCFG_EXTI_LINE(pin) GPIO_PIN_MAP(pin, LL_SYSCFG_EXTI_LINE) +#define GET_EXTI_LINE(pin) GPIO_PIN_MAP(pin, LL_EXTI_LINE_) + +static volatile GpioInterrupt gpio_interrupt[GPIO_NUMBER]; + +static uint8_t hal_gpio_get_pin_num(const GpioPin* gpio) { + uint8_t pin_num = 0; + for(pin_num = 0; pin_num < GPIO_NUMBER; pin_num++) { + if(gpio->pin & (1 << pin_num)) break; + } + return pin_num; +} + +void hal_gpio_init_simple(const GpioPin* gpio, const GpioMode mode) { + hal_gpio_init(gpio, mode, GpioPullNo, GpioSpeedLow); +} + +void hal_gpio_init( + const GpioPin* gpio, + const GpioMode mode, + const GpioPull pull, + const GpioSpeed speed) { + // we cannot set alternate mode in this function + furi_assert(mode != GpioModeAltFunctionPushPull); + furi_assert(mode != GpioModeAltFunctionOpenDrain); + + hal_gpio_init_ex(gpio, mode, pull, speed, GpioAltFnUnused); +} + +void hal_gpio_init_ex( + const GpioPin* gpio, + const GpioMode mode, + const GpioPull pull, + const GpioSpeed speed, + const GpioAltFn alt_fn) { + uint32_t sys_exti_port = GET_SYSCFG_EXTI_PORT(gpio->port); + uint32_t sys_exti_line = GET_SYSCFG_EXTI_LINE(gpio->pin); + uint32_t exti_line = GET_EXTI_LINE(gpio->pin); + + // Configure gpio with interrupts disabled + __disable_irq(); + // Set gpio speed + if(speed == GpioSpeedLow) { + LL_GPIO_SetPinSpeed(gpio->port, gpio->pin, LL_GPIO_SPEED_FREQ_LOW); + } else if(speed == GpioSpeedMedium) { + LL_GPIO_SetPinSpeed(gpio->port, gpio->pin, LL_GPIO_SPEED_FREQ_MEDIUM); + } else if(speed == GpioSpeedHigh) { + LL_GPIO_SetPinSpeed(gpio->port, gpio->pin, LL_GPIO_SPEED_FREQ_HIGH); + } else { + LL_GPIO_SetPinSpeed(gpio->port, gpio->pin, LL_GPIO_SPEED_FREQ_VERY_HIGH); + } + // Set gpio pull mode + if(pull == GpioPullNo) { + LL_GPIO_SetPinPull(gpio->port, gpio->pin, LL_GPIO_PULL_NO); + } else if(pull == GpioPullUp) { + LL_GPIO_SetPinPull(gpio->port, gpio->pin, LL_GPIO_PULL_UP); + } else { + LL_GPIO_SetPinPull(gpio->port, gpio->pin, LL_GPIO_PULL_DOWN); + } + // Set gpio mode + if(mode >= GpioModeInterruptRise) { + // Set pin in interrupt mode + LL_GPIO_SetPinMode(gpio->port, gpio->pin, LL_GPIO_MODE_INPUT); + LL_SYSCFG_SetEXTISource(sys_exti_port, sys_exti_line); + if(mode == GpioModeInterruptRise || mode == GpioModeInterruptRiseFall) { + LL_EXTI_EnableIT_0_31(exti_line); + LL_EXTI_EnableRisingTrig_0_31(exti_line); + } + if(mode == GpioModeInterruptFall || mode == GpioModeInterruptRiseFall) { + LL_EXTI_EnableIT_0_31(exti_line); + LL_EXTI_EnableFallingTrig_0_31(exti_line); + } + if(mode == GpioModeEventRise || mode == GpioModeInterruptRiseFall) { + LL_EXTI_EnableEvent_0_31(exti_line); + LL_EXTI_EnableRisingTrig_0_31(exti_line); + } + if(mode == GpioModeEventFall || mode == GpioModeInterruptRiseFall) { + LL_EXTI_EnableEvent_0_31(exti_line); + LL_EXTI_EnableFallingTrig_0_31(exti_line); + } + } else { + // Disable interrupt if it was set + if(LL_SYSCFG_GetEXTISource(sys_exti_line) == sys_exti_port && + LL_EXTI_IsEnabledIT_0_31(exti_line)) { + LL_EXTI_DisableIT_0_31(exti_line); + LL_EXTI_DisableRisingTrig_0_31(exti_line); + LL_EXTI_DisableFallingTrig_0_31(exti_line); + } + // Set not interrupt pin modes + if(mode == GpioModeInput) { + LL_GPIO_SetPinMode(gpio->port, gpio->pin, LL_GPIO_MODE_INPUT); + } else if(mode == GpioModeOutputPushPull || mode == GpioModeAltFunctionPushPull) { + LL_GPIO_SetPinMode(gpio->port, gpio->pin, LL_GPIO_MODE_OUTPUT); + LL_GPIO_SetPinOutputType(gpio->port, gpio->pin, LL_GPIO_OUTPUT_PUSHPULL); + } else if(mode == GpioModeOutputOpenDrain || mode == GpioModeAltFunctionOpenDrain) { + LL_GPIO_SetPinMode(gpio->port, gpio->pin, LL_GPIO_MODE_OUTPUT); + LL_GPIO_SetPinOutputType(gpio->port, gpio->pin, LL_GPIO_OUTPUT_OPENDRAIN); + } else if(mode == GpioModeAnalog) { + LL_GPIO_SetPinMode(gpio->port, gpio->pin, LL_GPIO_MODE_ANALOG); + } + } + + if(mode == GpioModeAltFunctionPushPull || mode == GpioModeAltFunctionOpenDrain) { + // enable alternate mode + LL_GPIO_SetPinMode(gpio->port, gpio->pin, LL_GPIO_MODE_ALTERNATE); + + // set alternate function + if(hal_gpio_get_pin_num(gpio) < 8) { + LL_GPIO_SetAFPin_0_7(gpio->port, gpio->pin, alt_fn); + } else { + LL_GPIO_SetAFPin_8_15(gpio->port, gpio->pin, alt_fn); + } + } + + __enable_irq(); +} + +void hal_gpio_add_int_callback(const GpioPin* gpio, GpioExtiCallback cb, void* ctx) { + furi_assert(gpio); + furi_assert(cb); + + __disable_irq(); + uint8_t pin_num = hal_gpio_get_pin_num(gpio); + furi_assert(gpio_interrupt[pin_num].callback == NULL); + gpio_interrupt[pin_num].callback = cb; + gpio_interrupt[pin_num].context = ctx; + gpio_interrupt[pin_num].ready = true; + __enable_irq(); +} + +void hal_gpio_enable_int_callback(const GpioPin* gpio) { + furi_assert(gpio); + + __disable_irq(); + uint8_t pin_num = hal_gpio_get_pin_num(gpio); + if(gpio_interrupt[pin_num].callback) { + gpio_interrupt[pin_num].ready = true; + } + __enable_irq(); +} + +void hal_gpio_disable_int_callback(const GpioPin* gpio) { + furi_assert(gpio); + + __disable_irq(); + uint8_t pin_num = hal_gpio_get_pin_num(gpio); + gpio_interrupt[pin_num].ready = false; + __enable_irq(); +} + +void hal_gpio_remove_int_callback(const GpioPin* gpio) { + furi_assert(gpio); + + __disable_irq(); + uint8_t pin_num = hal_gpio_get_pin_num(gpio); + gpio_interrupt[pin_num].callback = NULL; + gpio_interrupt[pin_num].context = NULL; + gpio_interrupt[pin_num].ready = false; + __enable_irq(); +} + +static void hal_gpio_int_call(uint16_t pin_num) { + if(gpio_interrupt[pin_num].callback && gpio_interrupt[pin_num].ready) { + gpio_interrupt[pin_num].callback(gpio_interrupt[pin_num].context); + } +} + +/* Interrupt handlers */ +void EXTI0_IRQHandler(void) { + if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_0)) { + LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_0); + hal_gpio_int_call(0); + } +} + +void EXTI1_IRQHandler(void) { + if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_1)) { + LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_1); + hal_gpio_int_call(1); + } +} + +void EXTI2_IRQHandler(void) { + if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_2)) { + LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_2); + hal_gpio_int_call(2); + } +} + +void EXTI3_IRQHandler(void) { + if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_3)) { + LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_3); + hal_gpio_int_call(3); + } +} + +void EXTI4_IRQHandler(void) { + if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_4)) { + LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_4); + hal_gpio_int_call(4); + } +} + +void EXTI9_5_IRQHandler(void) { + if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_5)) { + LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_5); + hal_gpio_int_call(5); + } + if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_6)) { + LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_6); + hal_gpio_int_call(6); + } + if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_7)) { + LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_7); + hal_gpio_int_call(7); + } + if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_8)) { + LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_8); + hal_gpio_int_call(8); + } + if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_9)) { + LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_9); + hal_gpio_int_call(9); + } +} + +void EXTI15_10_IRQHandler(void) { + if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_10)) { + LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_10); + hal_gpio_int_call(10); + } + if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_11)) { + LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_11); + hal_gpio_int_call(11); + } + if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_12)) { + LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_12); + hal_gpio_int_call(12); + } + if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_13)) { + LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_13); + hal_gpio_int_call(13); + } + if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_14)) { + LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_14); + hal_gpio_int_call(14); + } + if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_15)) { + LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_15); + hal_gpio_int_call(15); + } +} + +extern COMP_HandleTypeDef hcomp1; + +bool hal_gpio_get_rfid_in_level() { + bool value = false; + if(furi_hal_version_get_hw_version() > 7) { + value = (HAL_COMP_GetOutputLevel(&hcomp1) == COMP_OUTPUT_LEVEL_LOW); + } else { + value = (HAL_COMP_GetOutputLevel(&hcomp1) == COMP_OUTPUT_LEVEL_HIGH); + } + +#ifdef INVERT_RFID_IN + return !value; +#else + return value; +#endif +} diff --git a/firmware/targets/f7/furi-hal/furi-hal-gpio.h b/firmware/targets/f7/furi-hal/furi-hal-gpio.h new file mode 100644 index 00000000..a81afb39 --- /dev/null +++ b/firmware/targets/f7/furi-hal/furi-hal-gpio.h @@ -0,0 +1,264 @@ +#pragma once +#include "main.h" +#include "stdbool.h" +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Number of gpio on one port + */ +#define GPIO_NUMBER (16U) + +/** + * Interrupt callback prototype + */ +typedef void (*GpioExtiCallback)(void* ctx); + +/** + * Gpio interrupt type + */ +typedef struct { + GpioExtiCallback callback; + void* context; + volatile bool ready; +} GpioInterrupt; + +/** + * Gpio modes + */ +typedef enum { + GpioModeInput, + GpioModeOutputPushPull, + GpioModeOutputOpenDrain, + GpioModeAltFunctionPushPull, + GpioModeAltFunctionOpenDrain, + GpioModeAnalog, + GpioModeInterruptRise, + GpioModeInterruptFall, + GpioModeInterruptRiseFall, + GpioModeEventRise, + GpioModeEventFall, + GpioModeEventRiseFall, +} GpioMode; + +/** + * Gpio pull modes + */ +typedef enum { + GpioPullNo, + GpioPullUp, + GpioPullDown, +} GpioPull; + +/** + * Gpio speed modes + */ +typedef enum { + GpioSpeedLow, + GpioSpeedMedium, + GpioSpeedHigh, + GpioSpeedVeryHigh, +} GpioSpeed; + +/** + * Gpio alternate functions + */ +typedef enum { + GpioAltFn0MCO = 0, /*!< MCO Alternate Function mapping */ + GpioAltFn0LSCO = 0, /*!< LSCO Alternate Function mapping */ + GpioAltFn0JTMS_SWDIO = 0, /*!< JTMS-SWDIO Alternate Function mapping */ + GpioAltFn0JTCK_SWCLK = 0, /*!< JTCK-SWCLK Alternate Function mapping */ + GpioAltFn0JTDI = 0, /*!< JTDI Alternate Function mapping */ + GpioAltFn0RTC_OUT = 0, /*!< RCT_OUT Alternate Function mapping */ + GpioAltFn0JTD_TRACE = 0, /*!< JTDO-TRACESWO Alternate Function mapping */ + GpioAltFn0NJTRST = 0, /*!< NJTRST Alternate Function mapping */ + GpioAltFn0RTC_REFIN = 0, /*!< RTC_REFIN Alternate Function mapping */ + GpioAltFn0TRACED0 = 0, /*!< TRACED0 Alternate Function mapping */ + GpioAltFn0TRACED1 = 0, /*!< TRACED1 Alternate Function mapping */ + GpioAltFn0TRACED2 = 0, /*!< TRACED2 Alternate Function mapping */ + GpioAltFn0TRACED3 = 0, /*!< TRACED3 Alternate Function mapping */ + GpioAltFn0TRIG_INOUT = 0, /*!< TRIG_INOUT Alternate Function mapping */ + GpioAltFn0TRACECK = 0, /*!< TRACECK Alternate Function mapping */ + GpioAltFn0SYS = 0, /*!< System Function mapping */ + + GpioAltFn1TIM1 = 1, /*!< TIM1 Alternate Function mapping */ + GpioAltFn1TIM2 = 1, /*!< TIM2 Alternate Function mapping */ + GpioAltFn1LPTIM1 = 1, /*!< LPTIM1 Alternate Function mapping */ + + GpioAltFn2TIM2 = 2, /*!< TIM2 Alternate Function mapping */ + GpioAltFn2TIM1 = 2, /*!< TIM1 Alternate Function mapping */ + + GpioAltFn3SAI1 = 3, /*!< SAI1_CK1 Alternate Function mapping */ + GpioAltFn3SPI2 = 3, /*!< SPI2 Alternate Function mapping */ + GpioAltFn3TIM1 = 3, /*!< TIM1 Alternate Function mapping */ + + GpioAltFn4I2C1 = 4, /*!< I2C1 Alternate Function mapping */ + GpioAltFn4I2C3 = 4, /*!< I2C3 Alternate Function mapping */ + + GpioAltFn5SPI1 = 5, /*!< SPI1 Alternate Function mapping */ + GpioAltFn5SPI2 = 5, /*!< SPI2 Alternate Function mapping */ + + GpioAltFn6MCO = 6, /*!< MCO Alternate Function mapping */ + GpioAltFn6LSCO = 6, /*!< LSCO Alternate Function mapping */ + GpioAltFn6RF_DTB0 = 6, /*!< RF_DTB0 Alternate Function mapping */ + GpioAltFn6RF_DTB1 = 6, /*!< RF_DTB1 Alternate Function mapping */ + GpioAltFn6RF_DTB2 = 6, /*!< RF_DTB2 Alternate Function mapping */ + GpioAltFn6RF_DTB3 = 6, /*!< RF_DTB3 Alternate Function mapping */ + GpioAltFn6RF_DTB4 = 6, /*!< RF_DTB4 Alternate Function mapping */ + GpioAltFn6RF_DTB5 = 6, /*!< RF_DTB5 Alternate Function mapping */ + GpioAltFn6RF_DTB6 = 6, /*!< RF_DTB6 Alternate Function mapping */ + GpioAltFn6RF_DTB7 = 6, /*!< RF_DTB7 Alternate Function mapping */ + GpioAltFn6RF_DTB8 = 6, /*!< RF_DTB8 Alternate Function mapping */ + GpioAltFn6RF_DTB9 = 6, /*!< RF_DTB9 Alternate Function mapping */ + GpioAltFn6RF_DTB10 = 6, /*!< RF_DTB10 Alternate Function mapping */ + GpioAltFn6RF_DTB11 = 6, /*!< RF_DTB11 Alternate Function mapping */ + GpioAltFn6RF_DTB12 = 6, /*!< RF_DTB12 Alternate Function mapping */ + GpioAltFn6RF_DTB13 = 6, /*!< RF_DTB13 Alternate Function mapping */ + GpioAltFn6RF_DTB14 = 6, /*!< RF_DTB14 Alternate Function mapping */ + GpioAltFn6RF_DTB15 = 6, /*!< RF_DTB15 Alternate Function mapping */ + GpioAltFn6RF_DTB16 = 6, /*!< RF_DTB16 Alternate Function mapping */ + GpioAltFn6RF_DTB17 = 6, /*!< RF_DTB17 Alternate Function mapping */ + GpioAltFn6RF_DTB18 = 6, /*!< RF_DTB18 Alternate Function mapping */ + GpioAltFn6RF_MISO = 6, /*!< RF_MISO Alternate Function mapping */ + GpioAltFn6RF_MOSI = 6, /*!< RF_MOSI Alternate Function mapping */ + GpioAltFn6RF_SCK = 6, /*!< RF_SCK Alternate Function mapping */ + GpioAltFn6RF_NSS = 6, /*!< RF_NSS Alternate Function mapping */ + + GpioAltFn7USART1 = 7, /*!< USART1 Alternate Function mapping */ + + GpioAltFn8LPUART1 = 8, /*!< LPUART1 Alternate Function mapping */ + GpioAltFn8IR = 8, /*!< IR Alternate Function mapping */ + + GpioAltFn9TSC = 9, /*!< TSC Alternate Function mapping */ + + GpioAltFn10QUADSPI = 10, /*!< QUADSPI Alternate Function mapping */ + GpioAltFn10USB = 10, /*!< USB Alternate Function mapping */ + + GpioAltFn11LCD = 11, /*!< LCD Alternate Function mapping */ + + GpioAltFn12COMP1 = 12, /*!< COMP1 Alternate Function mapping */ + GpioAltFn12COMP2 = 12, /*!< COMP2 Alternate Function mapping */ + GpioAltFn12TIM1 = 12, /*!< TIM1 Alternate Function mapping */ + + GpioAltFn13SAI1 = 13, /*!< SAI1 Alternate Function mapping */ + + GpioAltFn14TIM2 = 14, /*!< TIM2 Alternate Function mapping */ + GpioAltFn14TIM16 = 14, /*!< TIM16 Alternate Function mapping */ + GpioAltFn14TIM17 = 14, /*!< TIM17 Alternate Function mapping */ + GpioAltFn14LPTIM2 = 14, /*!< LPTIM2 Alternate Function mapping */ + + GpioAltFn15EVENTOUT = 15, /*!< EVENTOUT Alternate Function mapping */ + + GpioAltFnUnused = 16, /*!< just dummy value */ +} GpioAltFn; + +/** + * Gpio structure + */ +typedef struct { + GPIO_TypeDef* port; + uint16_t pin; +} GpioPin; + +/** + * GPIO initialization function, simple version + * @param gpio GpioPin + * @param mode GpioMode + */ +void hal_gpio_init_simple(const GpioPin* gpio, const GpioMode mode); + +/** + * GPIO initialization function, normal version + * @param gpio GpioPin + * @param mode GpioMode + * @param pull GpioPull + * @param speed GpioSpeed + */ +void hal_gpio_init( + const GpioPin* gpio, + const GpioMode mode, + const GpioPull pull, + const GpioSpeed speed); + +/** + * GPIO initialization function, extended version + * @param gpio GpioPin + * @param mode GpioMode + * @param pull GpioPull + * @param speed GpioSpeed + * @param alt_fn GpioAltFn + */ +void hal_gpio_init_ex( + const GpioPin* gpio, + const GpioMode mode, + const GpioPull pull, + const GpioSpeed speed, + const GpioAltFn alt_fn); + +/** + * Add and enable interrupt + * @param gpio GpioPin + * @param cb GpioExtiCallback + * @param ctx context for callback + */ +void hal_gpio_add_int_callback(const GpioPin* gpio, GpioExtiCallback cb, void* ctx); + +/** + * Enable interrupt + * @param gpio GpioPin + */ +void hal_gpio_enable_int_callback(const GpioPin* gpio); + +/** + * Disable interrupt + * @param gpio GpioPin + */ +void hal_gpio_disable_int_callback(const GpioPin* gpio); + +/** + * Remove interrupt + * @param gpio GpioPin + */ +void hal_gpio_remove_int_callback(const GpioPin* gpio); + +/** + * GPIO write pin + * @param gpio GpioPin + * @param state true / false + */ +static inline void hal_gpio_write(const GpioPin* gpio, const bool state) { + // writing to BSSR is an atomic operation + if(state == true) { + gpio->port->BSRR = gpio->pin; + } else { + gpio->port->BSRR = (uint32_t)gpio->pin << GPIO_NUMBER; + } +} + +/** + * GPIO read pin + * @param gpio GpioPin + * @return true / false + */ +static inline bool hal_gpio_read(const GpioPin* gpio) { + if((gpio->port->IDR & gpio->pin) != 0x00U) { + return true; + } else { + return false; + } +} + +/** + * Get RFID IN level + * @return false = LOW, true = HIGH + */ +bool hal_gpio_get_rfid_in_level(); + +#ifdef __cplusplus +} +#endif diff --git a/firmware/targets/f7/furi-hal/furi-hal-i2c.c b/firmware/targets/f7/furi-hal/furi-hal-i2c.c new file mode 100644 index 00000000..196a2a7b --- /dev/null +++ b/firmware/targets/f7/furi-hal/furi-hal-i2c.c @@ -0,0 +1,152 @@ +#include +#include + +#include +#include +#include +#include + +osMutexId_t furi_hal_i2c_mutex = NULL; + +void furi_hal_i2c_init() { + furi_hal_i2c_mutex = osMutexNew(NULL); + furi_check(furi_hal_i2c_mutex); + + LL_I2C_InitTypeDef I2C_InitStruct = {0}; + LL_GPIO_InitTypeDef GPIO_InitStruct = {0}; + + LL_RCC_SetI2CClockSource(LL_RCC_I2C1_CLKSOURCE_PCLK1); + + GPIO_InitStruct.Pin = POWER_I2C_SCL_Pin | POWER_I2C_SDA_Pin; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE; + GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW; + GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_OPENDRAIN; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + GPIO_InitStruct.Alternate = LL_GPIO_AF_4; + LL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + I2C_InitStruct.PeripheralMode = LL_I2C_MODE_I2C; + I2C_InitStruct.AnalogFilter = LL_I2C_ANALOGFILTER_ENABLE; + I2C_InitStruct.DigitalFilter = 0; + I2C_InitStruct.OwnAddress1 = 0; + I2C_InitStruct.TypeAcknowledge = LL_I2C_ACK; + I2C_InitStruct.OwnAddrSize = LL_I2C_OWNADDRESS1_7BIT; + if (furi_hal_version_get_hw_version() > 10) { + I2C_InitStruct.Timing = POWER_I2C_TIMINGS_400; + } else { + I2C_InitStruct.Timing = POWER_I2C_TIMINGS_100; + } + LL_I2C_Init(POWER_I2C, &I2C_InitStruct); + LL_I2C_EnableAutoEndMode(POWER_I2C); + LL_I2C_SetOwnAddress2(POWER_I2C, 0, LL_I2C_OWNADDRESS2_NOMASK); + LL_I2C_DisableOwnAddress2(POWER_I2C); + LL_I2C_DisableGeneralCall(POWER_I2C); + LL_I2C_EnableClockStretching(POWER_I2C); + FURI_LOG_I("FuriHalI2C", "Init OK"); +} + +bool furi_hal_i2c_tx( + I2C_TypeDef* instance, + uint8_t address, + const uint8_t* data, + uint8_t size, + uint32_t timeout) { + uint32_t time_left = timeout; + bool ret = true; + + while(LL_I2C_IsActiveFlag_BUSY(instance)) + ; + + LL_I2C_HandleTransfer( + instance, + address, + LL_I2C_ADDRSLAVE_7BIT, + size, + LL_I2C_MODE_AUTOEND, + LL_I2C_GENERATE_START_WRITE); + + while(!LL_I2C_IsActiveFlag_STOP(instance) || size > 0) { + if(LL_I2C_IsActiveFlag_TXIS(instance)) { + LL_I2C_TransmitData8(instance, (*data)); + data++; + size--; + time_left = timeout; + } + + if(LL_SYSTICK_IsActiveCounterFlag()) { + if(--time_left == 0) { + ret = false; + break; + } + } + } + + LL_I2C_ClearFlag_STOP(instance); + + return ret; +} + +bool furi_hal_i2c_rx( + I2C_TypeDef* instance, + uint8_t address, + uint8_t* data, + uint8_t size, + uint32_t timeout) { + uint32_t time_left = timeout; + bool ret = true; + + while(LL_I2C_IsActiveFlag_BUSY(instance)) + ; + + LL_I2C_HandleTransfer( + instance, + address, + LL_I2C_ADDRSLAVE_7BIT, + size, + LL_I2C_MODE_AUTOEND, + LL_I2C_GENERATE_START_READ); + + while(!LL_I2C_IsActiveFlag_STOP(instance) || size > 0) { + if(LL_I2C_IsActiveFlag_RXNE(instance)) { + *data = LL_I2C_ReceiveData8(instance); + data++; + size--; + time_left = timeout; + } + + if(LL_SYSTICK_IsActiveCounterFlag()) { + if(--time_left == 0) { + ret = false; + break; + } + } + } + + LL_I2C_ClearFlag_STOP(instance); + + return ret; +} + +bool furi_hal_i2c_trx( + I2C_TypeDef* instance, + uint8_t address, + const uint8_t* tx_data, + uint8_t tx_size, + uint8_t* rx_data, + uint8_t rx_size, + uint32_t timeout) { + if(furi_hal_i2c_tx(instance, address, tx_data, tx_size, timeout) && + furi_hal_i2c_rx(instance, address, rx_data, rx_size, timeout)) { + return true; + } else { + return false; + } +} + +void furi_hal_i2c_lock() { + furi_check(osMutexAcquire(furi_hal_i2c_mutex, osWaitForever) == osOK); +} + +void furi_hal_i2c_unlock() { + furi_check(osMutexRelease(furi_hal_i2c_mutex) == osOK); +} diff --git a/firmware/targets/f7/furi-hal/furi-hal-ibutton.c b/firmware/targets/f7/furi-hal/furi-hal-ibutton.c new file mode 100644 index 00000000..6e3c8bee --- /dev/null +++ b/firmware/targets/f7/furi-hal/furi-hal-ibutton.c @@ -0,0 +1,24 @@ +#include +#include + +void furi_hal_ibutton_start() { + furi_hal_ibutton_pin_high(); + hal_gpio_init(&ibutton_gpio, GpioModeOutputOpenDrain, GpioSpeedLow, GpioPullNo); +} + +void furi_hal_ibutton_stop() { + furi_hal_ibutton_pin_high(); + hal_gpio_init(&ibutton_gpio, GpioModeAnalog, GpioSpeedLow, GpioPullNo); +} + +void furi_hal_ibutton_pin_low() { + hal_gpio_write(&ibutton_gpio, false); +} + +void furi_hal_ibutton_pin_high() { + hal_gpio_write(&ibutton_gpio, true); +} + +bool furi_hal_ibutton_pin_get_level() { + return hal_gpio_read(&ibutton_gpio); +} diff --git a/firmware/targets/f7/furi-hal/furi-hal-interrupt.c b/firmware/targets/f7/furi-hal/furi-hal-interrupt.c new file mode 100644 index 00000000..69cdc4b6 --- /dev/null +++ b/firmware/targets/f7/furi-hal/furi-hal-interrupt.c @@ -0,0 +1,208 @@ +#include "furi-hal-interrupt.h" + +#include +#include +#include + +volatile FuriHalInterruptISR furi_hal_tim_tim2_isr = NULL; +volatile FuriHalInterruptISR furi_hal_tim_tim1_isr = NULL; + +#define FURI_HAL_INTERRUPT_DMA_COUNT 2 +#define FURI_HAL_INTERRUPT_DMA_CHANNELS_COUNT 8 + +volatile FuriHalInterruptISR furi_hal_dma_channel_isr[FURI_HAL_INTERRUPT_DMA_COUNT][FURI_HAL_INTERRUPT_DMA_CHANNELS_COUNT] = {0}; + +void furi_hal_interrupt_init() { + NVIC_SetPriority(RCC_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 0, 0)); + NVIC_EnableIRQ(RCC_IRQn); + + NVIC_SetPriority(TAMP_STAMP_LSECSS_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 0, 0)); + NVIC_EnableIRQ(TAMP_STAMP_LSECSS_IRQn); + + NVIC_SetPriority(DMA1_Channel1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 5, 0)); + NVIC_EnableIRQ(DMA1_Channel1_IRQn); + + FURI_LOG_I("FuriHalInterrupt", "Init OK"); +} + +void furi_hal_interrupt_set_timer_isr(TIM_TypeDef* timer, FuriHalInterruptISR isr) { + if (timer == TIM2) { + if (isr) { + furi_assert(furi_hal_tim_tim2_isr == NULL); + } else { + furi_assert(furi_hal_tim_tim2_isr != NULL); + } + furi_hal_tim_tim2_isr = isr; + } else if (timer == TIM1) { + if (isr) { + furi_assert(furi_hal_tim_tim1_isr == NULL); + } else { + furi_assert(furi_hal_tim_tim1_isr != NULL); + } + furi_hal_tim_tim1_isr = isr; + } else { + furi_check(0); + } +} + +void furi_hal_interrupt_set_dma_channel_isr(DMA_TypeDef* dma, uint32_t channel, FuriHalInterruptISR isr) { + --channel; // Pascal + furi_check(dma); + furi_check(channel < FURI_HAL_INTERRUPT_DMA_CHANNELS_COUNT); + if (dma == DMA1) { + furi_hal_dma_channel_isr[0][channel] = isr; + } else if (dma == DMA2) { + furi_hal_dma_channel_isr[1][channel] = isr; + } else { + furi_check(0); + } +} + +extern void api_interrupt_call(InterruptType type, void* hw); + +/* ST HAL symbols */ + +/* Comparator trigger event */ +void HAL_COMP_TriggerCallback(COMP_HandleTypeDef* hcomp) { + api_interrupt_call(InterruptTypeComparatorTrigger, hcomp); +} + +/* Timer update event */ +void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef* htim) { + api_interrupt_call(InterruptTypeTimerUpdate, htim); +} + +/* Timer 2 */ +void TIM2_IRQHandler(void) { + if (furi_hal_tim_tim2_isr) { + furi_hal_tim_tim2_isr(); + } else { + HAL_TIM_IRQHandler(&htim2); + } +} + +/* Timer 1 Update */ +void TIM1_UP_TIM16_IRQHandler(void) { + if (furi_hal_tim_tim1_isr) { + furi_hal_tim_tim1_isr(); + } else { + HAL_TIM_IRQHandler(&htim1); + } +} + +/* DMA 1 */ +void DMA1_Channel1_IRQHandler(void) { + if (furi_hal_dma_channel_isr[0][0]) furi_hal_dma_channel_isr[0][0](); +} + +void DMA1_Channel2_IRQHandler(void) { + if (furi_hal_dma_channel_isr[0][1]) furi_hal_dma_channel_isr[0][1](); +} + +void DMA1_Channel3_IRQHandler(void) { + if (furi_hal_dma_channel_isr[0][2]) furi_hal_dma_channel_isr[0][2](); +} + +void DMA1_Channel4_IRQHandler(void) { + if (furi_hal_dma_channel_isr[0][3]) furi_hal_dma_channel_isr[0][3](); +} + +void DMA1_Channel5_IRQHandler(void) { + if (furi_hal_dma_channel_isr[0][4]) furi_hal_dma_channel_isr[0][4](); +} + +void DMA1_Channel6_IRQHandler(void) { + if (furi_hal_dma_channel_isr[0][5]) furi_hal_dma_channel_isr[0][5](); +} + +void DMA1_Channel7_IRQHandler(void) { + if (furi_hal_dma_channel_isr[0][6]) furi_hal_dma_channel_isr[0][6](); +} + +void DMA1_Channel8_IRQHandler(void) { + if (furi_hal_dma_channel_isr[0][7]) furi_hal_dma_channel_isr[0][7](); +} + +/* DMA 2 */ +void DMA2_Channel1_IRQHandler(void) { + if (furi_hal_dma_channel_isr[1][0]) furi_hal_dma_channel_isr[1][0](); +} + +void DMA2_Channel2_IRQHandler(void) { + if (furi_hal_dma_channel_isr[1][1]) furi_hal_dma_channel_isr[1][1](); +} + +void DMA2_Channel3_IRQHandler(void) { + if (furi_hal_dma_channel_isr[1][2]) furi_hal_dma_channel_isr[1][2](); +} + +void DMA2_Channel4_IRQHandler(void) { + if (furi_hal_dma_channel_isr[1][3]) furi_hal_dma_channel_isr[1][3](); +} + +void DMA2_Channel5_IRQHandler(void) { + if (furi_hal_dma_channel_isr[1][4]) furi_hal_dma_channel_isr[1][4](); +} + +void DMA2_Channel6_IRQHandler(void) { + if (furi_hal_dma_channel_isr[1][5]) furi_hal_dma_channel_isr[1][5](); +} + +void DMA2_Channel7_IRQHandler(void) { + if (furi_hal_dma_channel_isr[1][6]) furi_hal_dma_channel_isr[1][6](); +} + +void DMA2_Channel8_IRQHandler(void) { + if (furi_hal_dma_channel_isr[1][7]) furi_hal_dma_channel_isr[1][7](); +} + + +void TAMP_STAMP_LSECSS_IRQHandler(void) { + if (LL_RCC_IsActiveFlag_LSECSS()) { + LL_RCC_ClearFlag_LSECSS(); + if (!LL_RCC_LSE_IsReady()) { + FURI_LOG_E("FuriHalInterrupt", "LSE CSS fired: resetting system"); + NVIC_SystemReset(); + } else { + FURI_LOG_E("FuriHalInterrupt", "LSE CSS fired: but LSE is alive"); + } + } +} + +void RCC_IRQHandler(void) { +} + + +void NMI_Handler(void) { + if (LL_RCC_IsActiveFlag_HSECSS()) { + LL_RCC_ClearFlag_HSECSS(); + FURI_LOG_E("FuriHalInterrupt", "HSE CSS fired: resetting system"); + NVIC_SystemReset(); + } +} + +void HardFault_Handler(void) { + if ((*(volatile uint32_t *)CoreDebug_BASE) & (1 << 0)) { + __asm("bkpt 1"); + } + while (1) {} +} + +void MemManage_Handler(void) { + __asm("bkpt 1"); + while (1) {} +} + +void BusFault_Handler(void) { + __asm("bkpt 1"); + while (1) {} +} + +void UsageFault_Handler(void) { + __asm("bkpt 1"); + while (1) {} +} + +void DebugMon_Handler(void) { + +} diff --git a/firmware/targets/f7/furi-hal/furi-hal-interrupt.h b/firmware/targets/f7/furi-hal/furi-hal-interrupt.h new file mode 100644 index 00000000..693924e6 --- /dev/null +++ b/firmware/targets/f7/furi-hal/furi-hal-interrupt.h @@ -0,0 +1,34 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** Timer ISR */ +typedef void (*FuriHalInterruptISR)(); + +/** Initialize interrupt subsystem */ +void furi_hal_interrupt_init(); + +/** Set DMA Channel ISR + * We don't clear interrupt flags for you, do it by your self. + * @param dma - DMA instance + * @param channel - DMA channel + * @param isr - your interrupt service routine or use NULL to clear + */ +void furi_hal_interrupt_set_dma_channel_isr(DMA_TypeDef* dma, uint32_t channel, FuriHalInterruptISR isr); + +/** Set Timer ISR + * By default ISR is serviced by ST HAL. Use this function to override it. + * We don't clear interrupt flags for you, do it by your self. + * @param timer - timer instance + * @param isr - your interrupt service routine or use NULL to clear + */ +void furi_hal_interrupt_set_timer_isr(TIM_TypeDef *timer, FuriHalInterruptISR isr); + + +#ifdef __cplusplus +} +#endif diff --git a/firmware/targets/f7/furi-hal/furi-hal-irda.c b/firmware/targets/f7/furi-hal/furi-hal-irda.c new file mode 100644 index 00000000..a148b44a --- /dev/null +++ b/firmware/targets/f7/furi-hal/furi-hal-irda.c @@ -0,0 +1,639 @@ +#include "furi-hal-irda.h" +#include "furi-hal-delay.h" +#include "furi/check.h" +#include "stm32wbxx_ll_dma.h" +#include "sys/_stdint.h" +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#define IRDA_TX_DEBUG 0 + +#if IRDA_TX_DEBUG == 1 +#define gpio_irda_tx gpio_irda_tx_debug +const GpioPin gpio_irda_tx_debug = {.port = GPIOA, .pin = GPIO_PIN_7}; +#endif + +#define IRDA_TIM_TX_DMA_BUFFER_SIZE 200 +#define IRDA_POLARITY_SHIFT 1 + +#define IRDA_TX_CCMR_HIGH (TIM_CCMR2_OC3PE | LL_TIM_OCMODE_PWM2) /* Mark time - enable PWM2 mode */ +#define IRDA_TX_CCMR_LOW (TIM_CCMR2_OC3PE | LL_TIM_OCMODE_FORCED_INACTIVE) /* Space time - force low */ + +typedef struct{ + FuriHalIrdaRxCaptureCallback capture_callback; + void *capture_context; + FuriHalIrdaRxTimeoutCallback timeout_callback; + void *timeout_context; +} IrdaTimRx; + +typedef struct{ + uint8_t* polarity; + uint16_t* data; + size_t size; + bool packet_end; + bool last_packet_end; +} IrdaTxBuf; + +typedef struct { + float cycle_duration; + FuriHalIrdaTxGetDataISRCallback data_callback; + FuriHalIrdaTxSignalSentISRCallback signal_sent_callback; + void* data_context; + void* signal_sent_context; + IrdaTxBuf buffer[2]; + osSemaphoreId_t stop_semaphore; + uint32_t tx_timing_rest_duration; /** if timing is too long (> 0xFFFF), send it in few iterations */ + bool tx_timing_rest_level; + FuriHalIrdaTxGetDataState tx_timing_rest_status; +} IrdaTimTx; + +typedef enum { + IrdaStateIdle, /** Furi Hal Irda is ready to start RX or TX */ + IrdaStateAsyncRx, /** Async RX started */ + IrdaStateAsyncTx, /** Async TX started, DMA and timer is on */ + IrdaStateAsyncTxStopReq, /** Async TX started, async stop request received */ + IrdaStateAsyncTxStopInProgress, /** Async TX started, stop request is processed and we wait for last data to be sent */ + IrdaStateAsyncTxStopped, /** Async TX complete, cleanup needed */ + IrdaStateMAX, +} IrdaState; + +static volatile IrdaState furi_hal_irda_state = IrdaStateIdle; +static IrdaTimTx irda_tim_tx; +static IrdaTimRx irda_tim_rx; + +static void furi_hal_irda_tx_fill_buffer(uint8_t buf_num, uint8_t polarity_shift); +static void furi_hal_irda_async_tx_free_resources(void); +static void furi_hal_irda_tx_dma_set_polarity(uint8_t buf_num, uint8_t polarity_shift); +static void furi_hal_irda_tx_dma_set_buffer(uint8_t buf_num); +static void furi_hal_irda_tx_fill_buffer_last(uint8_t buf_num); +static uint8_t furi_hal_irda_get_current_dma_tx_buffer(void); +static void furi_hal_irda_tx_dma_polarity_isr(); +static void furi_hal_irda_tx_dma_isr(); + +static void furi_hal_irda_tim_rx_isr() { + static uint32_t previous_captured_ch2 = 0; + + /* Timeout */ + if(LL_TIM_IsActiveFlag_CC3(TIM2)) { + LL_TIM_ClearFlag_CC3(TIM2); + furi_assert(furi_hal_irda_state == IrdaStateAsyncRx); + + /* Timers CNT register starts to counting from 0 to ARR, but it is + * reseted when Channel 1 catches interrupt. It is not reseted by + * channel 2, though, so we have to distract it's values (see TimerIRQSourceCCI1 ISR). + * This can cause false timeout: when time is over, but we started + * receiving new signal few microseconds ago, because CNT register + * is reseted once per period, not per sample. */ + if (LL_GPIO_IsInputPinSet(gpio_irda_rx.port, gpio_irda_rx.pin) != 0) { + if (irda_tim_rx.timeout_callback) + irda_tim_rx.timeout_callback(irda_tim_rx.timeout_context); + } + } + + /* Rising Edge */ + if(LL_TIM_IsActiveFlag_CC1(TIM2)) { + LL_TIM_ClearFlag_CC1(TIM2); + furi_assert(furi_hal_irda_state == IrdaStateAsyncRx); + + if(READ_BIT(TIM2->CCMR1, TIM_CCMR1_CC1S)) { + /* Low pin level is a Mark state of IRDA signal. Invert level for further processing. */ + uint32_t duration = LL_TIM_IC_GetCaptureCH1(TIM2) - previous_captured_ch2; + if (irda_tim_rx.capture_callback) + irda_tim_rx.capture_callback(irda_tim_rx.capture_context, 1, duration); + } else { + furi_assert(0); + } + } + + /* Falling Edge */ + if(LL_TIM_IsActiveFlag_CC2(TIM2)) { + LL_TIM_ClearFlag_CC2(TIM2); + furi_assert(furi_hal_irda_state == IrdaStateAsyncRx); + + if(READ_BIT(TIM2->CCMR1, TIM_CCMR1_CC2S)) { + /* High pin level is a Space state of IRDA signal. Invert level for further processing. */ + uint32_t duration = LL_TIM_IC_GetCaptureCH2(TIM2); + previous_captured_ch2 = duration; + if (irda_tim_rx.capture_callback) + irda_tim_rx.capture_callback(irda_tim_rx.capture_context, 0, duration); + } else { + furi_assert(0); + } + } +} + +void furi_hal_irda_async_rx_start(void) { + furi_assert(furi_hal_irda_state == IrdaStateIdle); + + LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM2); + LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA); + + hal_gpio_init_ex(&gpio_irda_rx, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedLow, GpioAltFn1TIM2); + + LL_TIM_InitTypeDef TIM_InitStruct = {0}; + TIM_InitStruct.Prescaler = 64 - 1; + TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP; + TIM_InitStruct.Autoreload = 0x7FFFFFFE; + TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1; + LL_TIM_Init(TIM2, &TIM_InitStruct); + + LL_TIM_SetClockSource(TIM2, LL_TIM_CLOCKSOURCE_INTERNAL); + LL_TIM_DisableARRPreload(TIM2); + LL_TIM_SetTriggerInput(TIM2, LL_TIM_TS_TI1FP1); + LL_TIM_SetSlaveMode(TIM2, LL_TIM_SLAVEMODE_RESET); + LL_TIM_CC_DisableChannel(TIM2, LL_TIM_CHANNEL_CH2); + LL_TIM_IC_SetFilter(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_IC_FILTER_FDIV1); + LL_TIM_IC_SetPolarity(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_IC_POLARITY_FALLING); + LL_TIM_DisableIT_TRIG(TIM2); + LL_TIM_DisableDMAReq_TRIG(TIM2); + LL_TIM_SetTriggerOutput(TIM2, LL_TIM_TRGO_RESET); + LL_TIM_EnableMasterSlaveMode(TIM2); + LL_TIM_IC_SetActiveInput(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_ACTIVEINPUT_DIRECTTI); + LL_TIM_IC_SetPrescaler(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_ICPSC_DIV1); + LL_TIM_IC_SetFilter(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_IC_FILTER_FDIV1); + LL_TIM_IC_SetPolarity(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_IC_POLARITY_RISING); + LL_TIM_IC_SetActiveInput(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_ACTIVEINPUT_INDIRECTTI); + LL_TIM_IC_SetPrescaler(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_ICPSC_DIV1); + + furi_hal_interrupt_set_timer_isr(TIM2, furi_hal_irda_tim_rx_isr); + furi_hal_irda_state = IrdaStateAsyncRx; + + LL_TIM_EnableIT_CC1(TIM2); + LL_TIM_EnableIT_CC2(TIM2); + LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH1); + LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH2); + + LL_TIM_SetCounter(TIM2, 0); + LL_TIM_EnableCounter(TIM2); + + NVIC_SetPriority(TIM2_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 5, 0)); + NVIC_EnableIRQ(TIM2_IRQn); +} + +void furi_hal_irda_async_rx_stop(void) { + furi_assert(furi_hal_irda_state == IrdaStateAsyncRx); + LL_TIM_DeInit(TIM2); + furi_hal_interrupt_set_timer_isr(TIM2, NULL); + LL_APB1_GRP1_DisableClock(LL_APB1_GRP1_PERIPH_TIM2); + furi_hal_irda_state = IrdaStateIdle; +} + +void furi_hal_irda_async_rx_set_timeout(uint32_t timeout_us) { + furi_assert(LL_APB1_GRP1_IsEnabledClock(LL_APB1_GRP1_PERIPH_TIM2)); + + LL_TIM_OC_SetCompareCH3(TIM2, timeout_us); + LL_TIM_OC_SetMode(TIM2, LL_TIM_CHANNEL_CH3, LL_TIM_OCMODE_ACTIVE); + LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH3); + LL_TIM_EnableIT_CC3(TIM2); +} + +bool furi_hal_irda_is_busy(void) { + return furi_hal_irda_state != IrdaStateIdle; +} + +void furi_hal_irda_async_rx_set_capture_isr_callback(FuriHalIrdaRxCaptureCallback callback, void *ctx) { + irda_tim_rx.capture_callback = callback; + irda_tim_rx.capture_context = ctx; +} + +void furi_hal_irda_async_rx_set_timeout_isr_callback(FuriHalIrdaRxTimeoutCallback callback, void *ctx) { + irda_tim_rx.timeout_callback = callback; + irda_tim_rx.timeout_context = ctx; +} + +static void furi_hal_irda_tx_dma_terminate(void) { + LL_DMA_DisableIT_TC(DMA1, LL_DMA_CHANNEL_1); + LL_DMA_DisableIT_HT(DMA1, LL_DMA_CHANNEL_2); + LL_DMA_DisableIT_TC(DMA1, LL_DMA_CHANNEL_2); + + furi_assert(furi_hal_irda_state == IrdaStateAsyncTxStopInProgress); + + LL_DMA_DisableIT_TC(DMA1, LL_DMA_CHANNEL_1); + LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_2); + LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_1); + LL_TIM_DisableCounter(TIM1); + osStatus_t status = osSemaphoreRelease(irda_tim_tx.stop_semaphore); + furi_check(status == osOK); + furi_hal_irda_state = IrdaStateAsyncTxStopped; +} + +static uint8_t furi_hal_irda_get_current_dma_tx_buffer(void) { + uint8_t buf_num = 0; + uint32_t buffer_adr = LL_DMA_GetMemoryAddress(DMA1, LL_DMA_CHANNEL_2); + if (buffer_adr == (uint32_t) irda_tim_tx.buffer[0].data) { + buf_num = 0; + } else if (buffer_adr == (uint32_t) irda_tim_tx.buffer[1].data) { + buf_num = 1; + } else { + furi_assert(0); + } + return buf_num; +} + +static void furi_hal_irda_tx_dma_polarity_isr() { + if (LL_DMA_IsActiveFlag_TE1(DMA1)) { + LL_DMA_ClearFlag_TE1(DMA1); + furi_check(0); + } + if (LL_DMA_IsActiveFlag_TC1(DMA1) && LL_DMA_IsEnabledIT_TC(DMA1, LL_DMA_CHANNEL_1)) { + LL_DMA_ClearFlag_TC1(DMA1); + + furi_check((furi_hal_irda_state == IrdaStateAsyncTx) + || (furi_hal_irda_state == IrdaStateAsyncTxStopReq) + || (furi_hal_irda_state == IrdaStateAsyncTxStopInProgress)); + /* actually TC2 is processed and buffer is next buffer */ + uint8_t next_buf_num = furi_hal_irda_get_current_dma_tx_buffer(); + furi_hal_irda_tx_dma_set_polarity(next_buf_num, 0); + } +} + +static void furi_hal_irda_tx_dma_isr() { + if (LL_DMA_IsActiveFlag_TE2(DMA1)) { + LL_DMA_ClearFlag_TE2(DMA1); + furi_check(0); + } + if (LL_DMA_IsActiveFlag_HT2(DMA1) && LL_DMA_IsEnabledIT_HT(DMA1, LL_DMA_CHANNEL_2)) { + LL_DMA_ClearFlag_HT2(DMA1); + uint8_t buf_num = furi_hal_irda_get_current_dma_tx_buffer(); + uint8_t next_buf_num = !buf_num; + if (irda_tim_tx.buffer[buf_num].last_packet_end) { + LL_DMA_DisableIT_HT(DMA1, LL_DMA_CHANNEL_2); + } else if (!irda_tim_tx.buffer[buf_num].packet_end || (furi_hal_irda_state == IrdaStateAsyncTx)) { + furi_hal_irda_tx_fill_buffer(next_buf_num, 0); + if (irda_tim_tx.buffer[next_buf_num].last_packet_end) { + LL_DMA_DisableIT_HT(DMA1, LL_DMA_CHANNEL_2); + } + } else if (furi_hal_irda_state == IrdaStateAsyncTxStopReq) { + /* fallthrough */ + } else { + furi_check(0); + } + } + if (LL_DMA_IsActiveFlag_TC2(DMA1) && LL_DMA_IsEnabledIT_TC(DMA1, LL_DMA_CHANNEL_2)) { + LL_DMA_ClearFlag_TC2(DMA1); + furi_check((furi_hal_irda_state == IrdaStateAsyncTxStopInProgress) + || (furi_hal_irda_state == IrdaStateAsyncTxStopReq) + || (furi_hal_irda_state == IrdaStateAsyncTx)); + + uint8_t buf_num = furi_hal_irda_get_current_dma_tx_buffer(); + uint8_t next_buf_num = !buf_num; + if (furi_hal_irda_state == IrdaStateAsyncTxStopInProgress) { + furi_hal_irda_tx_dma_terminate(); + } else if (irda_tim_tx.buffer[buf_num].last_packet_end + || (irda_tim_tx.buffer[buf_num].packet_end && (furi_hal_irda_state == IrdaStateAsyncTxStopReq))) { + furi_hal_irda_state = IrdaStateAsyncTxStopInProgress; + furi_hal_irda_tx_fill_buffer_last(next_buf_num); + furi_hal_irda_tx_dma_set_buffer(next_buf_num); + } else { + /* if it's not end of the packet - continue receiving */ + furi_hal_irda_tx_dma_set_buffer(next_buf_num); + } + if (irda_tim_tx.signal_sent_callback && irda_tim_tx.buffer[buf_num].packet_end && (furi_hal_irda_state != IrdaStateAsyncTxStopped)) { + irda_tim_tx.signal_sent_callback(irda_tim_tx.signal_sent_context); + } + } +} + +static void furi_hal_irda_configure_tim_pwm_tx(uint32_t freq, float duty_cycle) +{ + LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_TIM1); +/* LL_DBGMCU_APB2_GRP1_FreezePeriph(LL_DBGMCU_APB2_GRP1_TIM1_STOP); */ + + LL_TIM_DisableCounter(TIM1); + LL_TIM_SetRepetitionCounter(TIM1, 0); + LL_TIM_SetCounter(TIM1, 0); + LL_TIM_SetPrescaler(TIM1, 0); + LL_TIM_SetCounterMode(TIM1, LL_TIM_COUNTERMODE_UP); + LL_TIM_EnableARRPreload(TIM1); + LL_TIM_SetAutoReload(TIM1, __LL_TIM_CALC_ARR(SystemCoreClock, LL_TIM_GetPrescaler(TIM1), freq)); +#if IRDA_TX_DEBUG == 1 + LL_TIM_OC_SetCompareCH1(TIM1, ( (LL_TIM_GetAutoReload(TIM1) + 1 ) * (1 - duty_cycle))); + LL_TIM_OC_EnablePreload(TIM1, LL_TIM_CHANNEL_CH1); + /* LL_TIM_OCMODE_PWM2 set by DMA */ + LL_TIM_OC_SetMode(TIM1, LL_TIM_CHANNEL_CH1, LL_TIM_OCMODE_FORCED_INACTIVE); + LL_TIM_OC_SetPolarity(TIM1, LL_TIM_CHANNEL_CH1N, LL_TIM_OCPOLARITY_HIGH); + LL_TIM_OC_DisableFast(TIM1, LL_TIM_CHANNEL_CH1); + LL_TIM_CC_EnableChannel(TIM1, LL_TIM_CHANNEL_CH1N); + LL_TIM_DisableIT_CC1(TIM1); +#else + LL_TIM_OC_SetCompareCH3(TIM1, ( (LL_TIM_GetAutoReload(TIM1) + 1 ) * (1 - duty_cycle))); + LL_TIM_OC_EnablePreload(TIM1, LL_TIM_CHANNEL_CH3); + /* LL_TIM_OCMODE_PWM2 set by DMA */ + LL_TIM_OC_SetMode(TIM1, LL_TIM_CHANNEL_CH3, LL_TIM_OCMODE_FORCED_INACTIVE); + LL_TIM_OC_SetPolarity(TIM1, LL_TIM_CHANNEL_CH3N, LL_TIM_OCPOLARITY_HIGH); + LL_TIM_OC_DisableFast(TIM1, LL_TIM_CHANNEL_CH3); + LL_TIM_CC_EnableChannel(TIM1, LL_TIM_CHANNEL_CH3N); + LL_TIM_DisableIT_CC3(TIM1); +#endif + LL_TIM_DisableMasterSlaveMode(TIM1); + LL_TIM_EnableAllOutputs(TIM1); + LL_TIM_DisableIT_UPDATE(TIM1); + LL_TIM_EnableDMAReq_UPDATE(TIM1); + + NVIC_SetPriority(TIM1_UP_TIM16_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 5, 0)); + NVIC_EnableIRQ(TIM1_UP_TIM16_IRQn); +} + +static void furi_hal_irda_configure_tim_cmgr2_dma_tx(void) { + LL_C2_AHB1_GRP1_EnableClock(LL_C2_AHB1_GRP1_PERIPH_DMA1); + + LL_DMA_InitTypeDef dma_config = {0}; +#if IRDA_TX_DEBUG == 1 + dma_config.PeriphOrM2MSrcAddress = (uint32_t)&(TIM1->CCMR1); +#else + dma_config.PeriphOrM2MSrcAddress = (uint32_t)&(TIM1->CCMR2); +#endif + dma_config.MemoryOrM2MDstAddress = (uint32_t) NULL; + dma_config.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; + dma_config.Mode = LL_DMA_MODE_NORMAL; + dma_config.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; + dma_config.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; + /* fill word to have other bits set to 0 */ + dma_config.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; + dma_config.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_BYTE; + dma_config.NbData = 0; + dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM1_UP; + dma_config.Priority = LL_DMA_PRIORITY_VERYHIGH; + LL_DMA_Init(DMA1, LL_DMA_CHANNEL_1, &dma_config); + furi_hal_interrupt_set_dma_channel_isr(DMA1, LL_DMA_CHANNEL_1, furi_hal_irda_tx_dma_polarity_isr); + LL_DMA_ClearFlag_TE1(DMA1); + LL_DMA_ClearFlag_TC1(DMA1); + LL_DMA_EnableIT_TE(DMA1, LL_DMA_CHANNEL_1); + LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_1); + + NVIC_SetPriority(DMA1_Channel1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 4, 0)); + NVIC_EnableIRQ(DMA1_Channel1_IRQn); +} + +static void furi_hal_irda_configure_tim_rcr_dma_tx(void) { + LL_C2_AHB1_GRP1_EnableClock(LL_C2_AHB1_GRP1_PERIPH_DMA1); + + LL_DMA_InitTypeDef dma_config = {0}; + dma_config.PeriphOrM2MSrcAddress = (uint32_t)&(TIM1->RCR); + dma_config.MemoryOrM2MDstAddress = (uint32_t) NULL; + dma_config.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; + dma_config.Mode = LL_DMA_MODE_NORMAL; + dma_config.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; + dma_config.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; + dma_config.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_HALFWORD; + dma_config.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_HALFWORD; + dma_config.NbData = 0; + dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM1_UP; + dma_config.Priority = LL_DMA_PRIORITY_MEDIUM; + LL_DMA_Init(DMA1, LL_DMA_CHANNEL_2, &dma_config); + furi_hal_interrupt_set_dma_channel_isr(DMA1, LL_DMA_CHANNEL_2, furi_hal_irda_tx_dma_isr); + LL_DMA_ClearFlag_TC2(DMA1); + LL_DMA_ClearFlag_HT2(DMA1); + LL_DMA_ClearFlag_TE2(DMA1); + LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_2); + LL_DMA_EnableIT_HT(DMA1, LL_DMA_CHANNEL_2); + LL_DMA_EnableIT_TE(DMA1, LL_DMA_CHANNEL_2); + + NVIC_SetPriority(DMA1_Channel2_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 5, 0)); + NVIC_EnableIRQ(DMA1_Channel2_IRQn); +} + +static void furi_hal_irda_tx_fill_buffer_last(uint8_t buf_num) { + furi_assert(buf_num < 2); + furi_assert(furi_hal_irda_state != IrdaStateAsyncRx); + furi_assert(furi_hal_irda_state < IrdaStateMAX); + furi_assert(irda_tim_tx.data_callback); + IrdaTxBuf* buffer = &irda_tim_tx.buffer[buf_num]; + furi_assert(buffer->data != NULL); + (void)buffer->data; + furi_assert(buffer->polarity != NULL); + (void)buffer->polarity; + + irda_tim_tx.buffer[buf_num].data[0] = 0; // 1 pulse + irda_tim_tx.buffer[buf_num].polarity[0] = IRDA_TX_CCMR_LOW; + irda_tim_tx.buffer[buf_num].data[1] = 0; // 1 pulse + irda_tim_tx.buffer[buf_num].polarity[1] = IRDA_TX_CCMR_LOW; + irda_tim_tx.buffer[buf_num].size = 2; + irda_tim_tx.buffer[buf_num].last_packet_end = true; + irda_tim_tx.buffer[buf_num].packet_end = true; +} + +static void furi_hal_irda_tx_fill_buffer(uint8_t buf_num, uint8_t polarity_shift) { + furi_assert(buf_num < 2); + furi_assert(furi_hal_irda_state != IrdaStateAsyncRx); + furi_assert(furi_hal_irda_state < IrdaStateMAX); + furi_assert(irda_tim_tx.data_callback); + IrdaTxBuf* buffer = &irda_tim_tx.buffer[buf_num]; + furi_assert(buffer->data != NULL); + furi_assert(buffer->polarity != NULL); + + FuriHalIrdaTxGetDataState status = FuriHalIrdaTxGetDataStateOk; + uint32_t duration = 0; + bool level = 0; + size_t *size = &buffer->size; + size_t polarity_counter = 0; + while (polarity_shift--) { + buffer->polarity[polarity_counter++] = IRDA_TX_CCMR_LOW; + } + + for (*size = 0; (*size < IRDA_TIM_TX_DMA_BUFFER_SIZE) && (status == FuriHalIrdaTxGetDataStateOk);) { + if (irda_tim_tx.tx_timing_rest_duration > 0) { + if (irda_tim_tx.tx_timing_rest_duration > 0xFFFF) { + buffer->data[*size] = 0xFFFF; + status = FuriHalIrdaTxGetDataStateOk; + } else { + buffer->data[*size] = irda_tim_tx.tx_timing_rest_duration; + status = irda_tim_tx.tx_timing_rest_status; + } + irda_tim_tx.tx_timing_rest_duration -= buffer->data[*size]; + buffer->polarity[polarity_counter] = irda_tim_tx.tx_timing_rest_level ? IRDA_TX_CCMR_HIGH : IRDA_TX_CCMR_LOW; + ++(*size); + ++polarity_counter; + continue; + } + + status = irda_tim_tx.data_callback(irda_tim_tx.data_context, &duration, &level); + + uint32_t num_of_impulses = roundf(duration / irda_tim_tx.cycle_duration); + + if (num_of_impulses == 0) { + if ((*size == 0) && (status == FuriHalIrdaTxGetDataStateDone)) { + /* if this is one sample in current buffer, but we + * have more to send - continue + */ + status = FuriHalIrdaTxGetDataStateOk; + } + } else if ((num_of_impulses - 1) > 0xFFFF) { + irda_tim_tx.tx_timing_rest_duration = num_of_impulses - 1; + irda_tim_tx.tx_timing_rest_status = status; + irda_tim_tx.tx_timing_rest_level = level; + status = FuriHalIrdaTxGetDataStateOk; + } else { + buffer->polarity[polarity_counter] = level ? IRDA_TX_CCMR_HIGH : IRDA_TX_CCMR_LOW; + buffer->data[*size] = num_of_impulses - 1; + ++(*size); + ++polarity_counter; + } + } + + buffer->last_packet_end = (status == FuriHalIrdaTxGetDataStateLastDone); + buffer->packet_end = buffer->last_packet_end || (status == FuriHalIrdaTxGetDataStateDone); + + if (*size == 0) { + buffer->data[0] = 0; // 1 pulse + buffer->polarity[0] = IRDA_TX_CCMR_LOW; + buffer->size = 1; + } +} + +static void furi_hal_irda_tx_dma_set_polarity(uint8_t buf_num, uint8_t polarity_shift) { + furi_assert(buf_num < 2); + furi_assert(furi_hal_irda_state < IrdaStateMAX); + IrdaTxBuf* buffer = &irda_tim_tx.buffer[buf_num]; + furi_assert(buffer->polarity != NULL); + + __disable_irq(); + bool channel_enabled = LL_DMA_IsEnabledChannel(DMA1, LL_DMA_CHANNEL_1); + if (channel_enabled) { + LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_1); + } + LL_DMA_SetMemoryAddress(DMA1, LL_DMA_CHANNEL_1, (uint32_t) buffer->polarity); + LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_1, buffer->size + polarity_shift); + if (channel_enabled) { + LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1); + } + __enable_irq(); +} + +static void furi_hal_irda_tx_dma_set_buffer(uint8_t buf_num) { + furi_assert(buf_num < 2); + furi_assert(furi_hal_irda_state < IrdaStateMAX); + IrdaTxBuf* buffer = &irda_tim_tx.buffer[buf_num]; + furi_assert(buffer->data != NULL); + + /* non-circular mode requires disabled channel before setup */ + __disable_irq(); + bool channel_enabled = LL_DMA_IsEnabledChannel(DMA1, LL_DMA_CHANNEL_2); + if (channel_enabled) { + LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_2); + } + LL_DMA_SetMemoryAddress(DMA1, LL_DMA_CHANNEL_2, (uint32_t)buffer->data); + LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_2, buffer->size); + if (channel_enabled) { + LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_2); + } + __enable_irq(); +} + +static void furi_hal_irda_async_tx_free_resources(void) { + furi_assert((furi_hal_irda_state == IrdaStateIdle) || (furi_hal_irda_state == IrdaStateAsyncTxStopped)); + osStatus_t status; + + hal_gpio_init(&gpio_irda_tx, GpioModeOutputOpenDrain, GpioPullDown, GpioSpeedLow); + furi_hal_interrupt_set_dma_channel_isr(DMA1, LL_DMA_CHANNEL_1, NULL); + furi_hal_interrupt_set_dma_channel_isr(DMA1, LL_DMA_CHANNEL_2, NULL); + LL_TIM_DeInit(TIM1); + LL_APB2_GRP1_DisableClock(LL_APB2_GRP1_PERIPH_TIM1); + LL_C2_AHB1_GRP1_DisableClock(LL_C2_AHB1_GRP1_PERIPH_DMA1); + + status = osSemaphoreDelete(irda_tim_tx.stop_semaphore); + furi_check(status == osOK); + free(irda_tim_tx.buffer[0].data); + free(irda_tim_tx.buffer[1].data); + free(irda_tim_tx.buffer[0].polarity); + free(irda_tim_tx.buffer[1].polarity); + + irda_tim_tx.buffer[0].data = NULL; + irda_tim_tx.buffer[1].data = NULL; + irda_tim_tx.buffer[0].polarity = NULL; + irda_tim_tx.buffer[1].polarity = NULL; +} + +void furi_hal_irda_async_tx_start(uint32_t freq, float duty_cycle) { + if ((duty_cycle > 1) || (duty_cycle <= 0) || (freq > IRDA_MAX_FREQUENCY) || (freq < IRDA_MIN_FREQUENCY) || (irda_tim_tx.data_callback == NULL)) { + furi_check(0); + } + + furi_assert(furi_hal_irda_state == IrdaStateIdle); + furi_assert(irda_tim_tx.buffer[0].data == NULL); + furi_assert(irda_tim_tx.buffer[1].data == NULL); + furi_assert(irda_tim_tx.buffer[0].polarity == NULL); + furi_assert(irda_tim_tx.buffer[1].polarity == NULL); + + size_t alloc_size_data = IRDA_TIM_TX_DMA_BUFFER_SIZE * sizeof(uint16_t); + irda_tim_tx.buffer[0].data = furi_alloc(alloc_size_data); + irda_tim_tx.buffer[1].data = furi_alloc(alloc_size_data); + + size_t alloc_size_polarity = (IRDA_TIM_TX_DMA_BUFFER_SIZE + IRDA_POLARITY_SHIFT) * sizeof(uint8_t); + irda_tim_tx.buffer[0].polarity = furi_alloc(alloc_size_polarity); + irda_tim_tx.buffer[1].polarity = furi_alloc(alloc_size_polarity); + + irda_tim_tx.stop_semaphore = osSemaphoreNew(1, 0, NULL); + irda_tim_tx.cycle_duration = 1000000.0 / freq; + irda_tim_tx.tx_timing_rest_duration = 0; + + furi_hal_irda_tx_fill_buffer(0, IRDA_POLARITY_SHIFT); + + furi_hal_irda_configure_tim_pwm_tx(freq, duty_cycle); + furi_hal_irda_configure_tim_cmgr2_dma_tx(); + furi_hal_irda_configure_tim_rcr_dma_tx(); + furi_hal_irda_tx_dma_set_polarity(0, IRDA_POLARITY_SHIFT); + furi_hal_irda_tx_dma_set_buffer(0); + + furi_hal_irda_state = IrdaStateAsyncTx; + + LL_TIM_ClearFlag_UPDATE(TIM1); + LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1); + LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_2); + delay_us(5); + LL_TIM_GenerateEvent_UPDATE(TIM1); /* DMA -> TIMx_RCR */ + delay_us(5); + LL_GPIO_ResetOutputPin(gpio_irda_tx.port, gpio_irda_tx.pin); /* when disable it prevents false pulse */ + hal_gpio_init_ex(&gpio_irda_tx, GpioModeAltFunctionPushPull, GpioPullUp, GpioSpeedHigh, GpioAltFn1TIM1); + + __disable_irq(); + LL_TIM_GenerateEvent_UPDATE(TIM1); /* TIMx_RCR -> Repetition counter */ + LL_TIM_EnableCounter(TIM1); + __enable_irq(); +} + +void furi_hal_irda_async_tx_wait_termination(void) { + furi_assert(furi_hal_irda_state >= IrdaStateAsyncTx); + furi_assert(furi_hal_irda_state < IrdaStateMAX); + + osStatus_t status; + status = osSemaphoreAcquire(irda_tim_tx.stop_semaphore, osWaitForever); + furi_check(status == osOK); + furi_hal_irda_async_tx_free_resources(); + furi_hal_irda_state = IrdaStateIdle; +} + +void furi_hal_irda_async_tx_stop(void) { + furi_assert(furi_hal_irda_state >= IrdaStateAsyncTx); + furi_assert(furi_hal_irda_state < IrdaStateMAX); + + __disable_irq(); + if (furi_hal_irda_state == IrdaStateAsyncTx) + furi_hal_irda_state = IrdaStateAsyncTxStopReq; + __enable_irq(); + + furi_hal_irda_async_tx_wait_termination(); +} + +void furi_hal_irda_async_tx_set_data_isr_callback(FuriHalIrdaTxGetDataISRCallback callback, void* context) { + furi_assert(furi_hal_irda_state == IrdaStateIdle); + irda_tim_tx.data_callback = callback; + irda_tim_tx.data_context = context; +} + +void furi_hal_irda_async_tx_set_signal_sent_isr_callback(FuriHalIrdaTxSignalSentISRCallback callback, void* context) { + irda_tim_tx.signal_sent_callback = callback; + irda_tim_tx.signal_sent_context = context; +} + diff --git a/firmware/targets/f7/furi-hal/furi-hal-light.c b/firmware/targets/f7/furi-hal/furi-hal-light.c new file mode 100644 index 00000000..fba1bec4 --- /dev/null +++ b/firmware/targets/f7/furi-hal/furi-hal-light.c @@ -0,0 +1,44 @@ +#include +#include + +#define LED_CURRENT_RED 50 +#define LED_CURRENT_GREEN 50 +#define LED_CURRENT_BLUE 50 +#define LED_CURRENT_WHITE 150 + +void furi_hal_light_init() { + lp5562_reset(); + + lp5562_set_channel_current(LP5562ChannelRed, LED_CURRENT_RED); + lp5562_set_channel_current(LP5562ChannelGreen, LED_CURRENT_GREEN); + lp5562_set_channel_current(LP5562ChannelBlue, LED_CURRENT_BLUE); + lp5562_set_channel_current(LP5562ChannelWhite, LED_CURRENT_WHITE); + + lp5562_set_channel_value(LP5562ChannelRed, 0x00); + lp5562_set_channel_value(LP5562ChannelGreen, 0x00); + lp5562_set_channel_value(LP5562ChannelBlue, 0x00); + lp5562_set_channel_value(LP5562ChannelWhite, 0x00); + + lp5562_enable(); + lp5562_configure(); + FURI_LOG_I("FuriHalLight", "Init OK"); +} + +void furi_hal_light_set(Light light, uint8_t value) { + switch(light) { + case LightRed: + lp5562_set_channel_value(LP5562ChannelRed, value); + break; + case LightGreen: + lp5562_set_channel_value(LP5562ChannelGreen, value); + break; + case LightBlue: + lp5562_set_channel_value(LP5562ChannelBlue, value); + break; + case LightBacklight: + lp5562_set_channel_value(LP5562ChannelWhite, value); + break; + default: + break; + } +} \ No newline at end of file diff --git a/firmware/targets/f7/furi-hal/furi-hal-nfc.c b/firmware/targets/f7/furi-hal/furi-hal-nfc.c new file mode 100644 index 00000000..d92e2cad --- /dev/null +++ b/firmware/targets/f7/furi-hal/furi-hal-nfc.c @@ -0,0 +1,174 @@ +#include "furi-hal-nfc.h" +#include + +static const uint32_t clocks_in_ms = 64 * 1000; + +void furi_hal_nfc_init() { + ReturnCode ret = rfalNfcInitialize(); + if(ret == ERR_NONE) { + furi_hal_nfc_start_sleep(); + FURI_LOG_I("FuriHalNfc", "Init OK"); + } else { + FURI_LOG_W("FuriHalNfc", "Initialization failed, RFAL returned: %d", ret); + } +} + +bool furi_hal_nfc_is_busy() { + return rfalNfcGetState() != RFAL_NFC_STATE_IDLE; +} + +void furi_hal_nfc_field_on() { + furi_hal_nfc_exit_sleep(); + st25r3916TxRxOn(); +} + +void furi_hal_nfc_field_off() { + st25r3916TxRxOff(); + furi_hal_nfc_start_sleep(); +} + +void furi_hal_nfc_start_sleep() { + rfalLowPowerModeStart(); +} + +void furi_hal_nfc_exit_sleep() { + rfalLowPowerModeStop(); +} + +bool furi_hal_nfc_detect(rfalNfcDevice **dev_list, uint8_t* dev_cnt, uint32_t timeout, bool deactivate) { + furi_assert(dev_list); + furi_assert(dev_cnt); + + rfalLowPowerModeStop(); + rfalNfcState state = rfalNfcGetState(); + if(state == RFAL_NFC_STATE_NOTINIT) { + rfalNfcInitialize(); + } + rfalNfcDiscoverParam params; + params.compMode = RFAL_COMPLIANCE_MODE_EMV; + params.techs2Find = RFAL_NFC_POLL_TECH_A | RFAL_NFC_POLL_TECH_B | RFAL_NFC_POLL_TECH_F | + RFAL_NFC_POLL_TECH_V | RFAL_NFC_POLL_TECH_AP2P | RFAL_NFC_POLL_TECH_ST25TB; + params.totalDuration = 1000; + params.devLimit = 3; + params.wakeupEnabled = false; + params.wakeupConfigDefault = true; + params.nfcfBR = RFAL_BR_212; + params.ap2pBR = RFAL_BR_424; + params.maxBR = RFAL_BR_KEEP; + params.GBLen = RFAL_NFCDEP_GB_MAX_LEN; + params.notifyCb = NULL; + + uint32_t start = DWT->CYCCNT; + rfalNfcDiscover(¶ms); + while(state != RFAL_NFC_STATE_ACTIVATED) { + rfalNfcWorker(); + state = rfalNfcGetState(); + FURI_LOG_D("HAL NFC", "Current state %d", state); + if(state == RFAL_NFC_STATE_POLL_ACTIVATION) { + start = DWT->CYCCNT; + continue; + } + if(state == RFAL_NFC_STATE_POLL_SELECT) { + rfalNfcSelect(0); + } + if(DWT->CYCCNT - start > timeout * clocks_in_ms) { + rfalNfcDeactivate(true); + FURI_LOG_D("HAL NFC", "Timeout"); + return false; + } + osThreadYield(); + } + rfalNfcGetDevicesFound(dev_list, dev_cnt); + if(deactivate) { + rfalNfcDeactivate(false); + rfalLowPowerModeStart(); + } + return true; +} + +bool furi_hal_nfc_listen(uint8_t* uid, uint8_t uid_len, uint8_t* atqa, uint8_t sak, bool activate_after_sak, uint32_t timeout) { + rfalNfcState state = rfalNfcGetState(); + if(state == RFAL_NFC_STATE_NOTINIT) { + rfalNfcInitialize(); + } else if(state >= RFAL_NFC_STATE_ACTIVATED) { + rfalNfcDeactivate(false); + } + rfalLowPowerModeStop(); + rfalNfcDiscoverParam params = { + .compMode = RFAL_COMPLIANCE_MODE_NFC, + .techs2Find = RFAL_NFC_LISTEN_TECH_A, + .totalDuration = 1000, + .devLimit = 1, + .wakeupEnabled = false, + .wakeupConfigDefault = true, + .nfcfBR = RFAL_BR_212, + .ap2pBR = RFAL_BR_424, + .maxBR = RFAL_BR_KEEP, + .GBLen = RFAL_NFCDEP_GB_MAX_LEN, + .notifyCb = NULL, + .activate_after_sak = activate_after_sak, + }; + params.lmConfigPA.nfcidLen = uid_len; + memcpy(params.lmConfigPA.nfcid, uid, uid_len); + params.lmConfigPA.SENS_RES[0] = atqa[0]; + params.lmConfigPA.SENS_RES[1] = atqa[1]; + params.lmConfigPA.SEL_RES = sak; + rfalNfcDiscover(¶ms); + + uint32_t start = DWT->CYCCNT; + while(state != RFAL_NFC_STATE_ACTIVATED) { + rfalNfcWorker(); + state = rfalNfcGetState(); + if(DWT->CYCCNT - start > timeout * clocks_in_ms) { + rfalNfcDeactivate(true); + return false; + } + osThreadYield(); + } + return true; +} + +bool furi_hal_nfc_get_first_frame(uint8_t** rx_buff, uint16_t** rx_len) { + ReturnCode ret = rfalNfcDataExchangeStart(NULL, 0, rx_buff, rx_len, 0); + return ret == ERR_NONE; +} + +ReturnCode furi_hal_nfc_data_exchange(uint8_t* tx_buff, uint16_t tx_len, uint8_t** rx_buff, uint16_t** rx_len, bool deactivate) { + furi_assert(rx_buff); + furi_assert(rx_len); + + ReturnCode ret; + rfalNfcState state = RFAL_NFC_STATE_ACTIVATED; + ret = rfalNfcDataExchangeStart(tx_buff, tx_len, rx_buff, rx_len, 0); + if(ret != ERR_NONE) { + return ret; + } + uint32_t start = DWT->CYCCNT; + while(state != RFAL_NFC_STATE_DATAEXCHANGE_DONE) { + rfalNfcWorker(); + state = rfalNfcGetState(); + ret = rfalNfcDataExchangeGetStatus(); + if(ret > ERR_SLEEP_REQ) { + return ret; + } + if(ret == ERR_BUSY) { + if(DWT->CYCCNT - start > 1000 * clocks_in_ms) { + return ERR_TIMEOUT; + } + continue; + } else { + start = DWT->CYCCNT; + } + taskYIELD(); + } + if(deactivate) { + rfalNfcDeactivate(false); + rfalLowPowerModeStart(); + } + return ERR_NONE; +} + +void furi_hal_nfc_deactivate() { + rfalNfcDeactivate(false); + rfalLowPowerModeStart(); +} diff --git a/firmware/targets/f7/furi-hal/furi-hal-os-timer.h b/firmware/targets/f7/furi-hal/furi-hal-os-timer.h new file mode 100644 index 00000000..f210b539 --- /dev/null +++ b/firmware/targets/f7/furi-hal/furi-hal-os-timer.h @@ -0,0 +1,64 @@ +#pragma once + +#include +#include +#include + +// Timer used for system ticks +#define FURI_HAL_OS_TIMER_MAX 0xFFFF +#define FURI_HAL_OS_TIMER_REG_LOAD_DLY 0x1 +#define FURI_HAL_OS_TIMER LPTIM2 +#define FURI_HAL_OS_TIMER_IRQ LPTIM2_IRQn + +static inline void furi_hal_os_timer_init() { + // Configure clock source + LL_RCC_SetLPTIMClockSource(LL_RCC_LPTIM2_CLKSOURCE_LSE); + LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_LPTIM2); + // Set interrupt priority and enable them + NVIC_SetPriority(FURI_HAL_OS_TIMER_IRQ, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 15, 0)); + NVIC_EnableIRQ(FURI_HAL_OS_TIMER_IRQ); +} + +static inline void furi_hal_os_timer_continuous(uint32_t count) { + // Enable timer + LL_LPTIM_Enable(FURI_HAL_OS_TIMER); + while(!LL_LPTIM_IsEnabled(FURI_HAL_OS_TIMER)); + + // Enable rutoreload match interrupt + LL_LPTIM_EnableIT_ARRM(FURI_HAL_OS_TIMER); + + // Set autoreload and start counter + LL_LPTIM_SetAutoReload(FURI_HAL_OS_TIMER, count); + LL_LPTIM_StartCounter(FURI_HAL_OS_TIMER, LL_LPTIM_OPERATING_MODE_CONTINUOUS); +} + +static inline void furi_hal_os_timer_single(uint32_t count) { + // Enable timer + LL_LPTIM_Enable(FURI_HAL_OS_TIMER); + while(!LL_LPTIM_IsEnabled(FURI_HAL_OS_TIMER)); + + // Enable compare match interrupt + LL_LPTIM_EnableIT_CMPM(FURI_HAL_OS_TIMER); + + // Set compare, autoreload and start counter + // Include some marging to workaround ARRM behaviour + LL_LPTIM_SetCompare(FURI_HAL_OS_TIMER, count-3); + LL_LPTIM_SetAutoReload(FURI_HAL_OS_TIMER, count); + LL_LPTIM_StartCounter(FURI_HAL_OS_TIMER, LL_LPTIM_OPERATING_MODE_ONESHOT); +} + +static inline void furi_hal_os_timer_reset() { + // Hard reset timer + // THE ONLY RELIABLEWAY to stop it according to errata + LL_LPTIM_DeInit(FURI_HAL_OS_TIMER); +} + +static inline uint32_t furi_hal_os_timer_get_cnt() { + uint32_t counter = LL_LPTIM_GetCounter(FURI_HAL_OS_TIMER); + uint32_t counter_shadow = LL_LPTIM_GetCounter(FURI_HAL_OS_TIMER); + while(counter != counter_shadow) { + counter = counter_shadow; + counter_shadow = LL_LPTIM_GetCounter(FURI_HAL_OS_TIMER); + } + return counter; +} diff --git a/firmware/targets/f7/furi-hal/furi-hal-os.c b/firmware/targets/f7/furi-hal/furi-hal-os.c new file mode 100644 index 00000000..eb1811b6 --- /dev/null +++ b/firmware/targets/f7/furi-hal/furi-hal-os.c @@ -0,0 +1,143 @@ +#include +#include +#include +#include + +#include + +#define FURI_HAL_OS_CLK_FREQUENCY 32768 +#define FURI_HAL_OS_TICK_PER_SECOND 1024 +#define FURI_HAL_OS_CLK_PER_TICK (FURI_HAL_OS_CLK_FREQUENCY / FURI_HAL_OS_TICK_PER_SECOND) +#define FURI_HAL_OS_TICK_PER_EPOCH (FURI_HAL_OS_TIMER_MAX / FURI_HAL_OS_CLK_PER_TICK) +#define FURI_HAL_OS_MAX_SLEEP (FURI_HAL_OS_TICK_PER_EPOCH - 1) + +#ifdef FURI_HAL_OS_DEBUG +#include + +#define LED_SLEEP_PORT GPIOA +#define LED_SLEEP_PIN LL_GPIO_PIN_7 +#define LED_TICK_PORT GPIOA +#define LED_TICK_PIN LL_GPIO_PIN_6 +#define LED_SECOND_PORT GPIOA +#define LED_SECOND_PIN LL_GPIO_PIN_4 + +void furi_hal_os_timer_callback() { + LL_GPIO_TogglePin(LED_SECOND_PORT, LED_SECOND_PIN); +} +#endif + +extern void xPortSysTickHandler(); + +volatile uint32_t furi_hal_os_skew = 0; + +void furi_hal_os_init() { + LL_DBGMCU_APB1_GRP2_FreezePeriph(LL_DBGMCU_APB1_GRP2_LPTIM2_STOP); + + furi_hal_os_timer_init(); + furi_hal_os_timer_continuous(FURI_HAL_OS_CLK_PER_TICK); + +#ifdef FURI_HAL_OS_DEBUG + LL_GPIO_SetPinMode(LED_SLEEP_PORT, LED_SLEEP_PIN, LL_GPIO_MODE_OUTPUT); + LL_GPIO_SetPinMode(LED_TICK_PORT, LED_TICK_PIN, LL_GPIO_MODE_OUTPUT); + LL_GPIO_SetPinMode(LED_SECOND_PORT, LED_SECOND_PIN, LL_GPIO_MODE_OUTPUT); + osTimerId_t second_timer = osTimerNew(furi_hal_os_timer_callback, osTimerPeriodic, NULL, NULL); + osTimerStart(second_timer, 1024); +#endif + + FURI_LOG_I("FuriHalOs", "Init OK"); +} + +void LPTIM2_IRQHandler(void) { + // Autoreload + if(LL_LPTIM_IsActiveFlag_ARRM(FURI_HAL_OS_TIMER)) { + LL_LPTIM_ClearFLAG_ARRM(FURI_HAL_OS_TIMER); + if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) { + #ifdef FURI_HAL_OS_DEBUG + LL_GPIO_TogglePin(LED_TICK_PORT, LED_TICK_PIN); + #endif + xPortSysTickHandler(); + } + } + if(LL_LPTIM_IsActiveFlag_CMPM(FURI_HAL_OS_TIMER)) { + LL_LPTIM_ClearFLAG_CMPM(FURI_HAL_OS_TIMER); + } +} + +static inline uint32_t furi_hal_os_sleep(TickType_t expected_idle_ticks) { + // Stop ticks + furi_hal_os_timer_reset(); + LL_SYSTICK_DisableIT(); + + // Start wakeup timer + furi_hal_os_timer_single(expected_idle_ticks * FURI_HAL_OS_CLK_PER_TICK); + +#ifdef FURI_HAL_OS_DEBUG + LL_GPIO_ResetOutputPin(LED_SLEEP_PORT, LED_SLEEP_PIN); +#endif + + // Go to sleep mode + furi_hal_power_sleep(); + +#ifdef FURI_HAL_OS_DEBUG + LL_GPIO_SetOutputPin(LED_SLEEP_PORT, LED_SLEEP_PIN); +#endif + + // Calculate how much time we spent in the sleep + uint32_t after_cnt = furi_hal_os_timer_get_cnt() + furi_hal_os_skew; + uint32_t after_tick = after_cnt / FURI_HAL_OS_CLK_PER_TICK; + furi_hal_os_skew = after_cnt % FURI_HAL_OS_CLK_PER_TICK; + + bool cmpm = LL_LPTIM_IsActiveFlag_CMPM(FURI_HAL_OS_TIMER); + bool arrm = LL_LPTIM_IsActiveFlag_ARRM(FURI_HAL_OS_TIMER); + if (cmpm && arrm) after_tick += expected_idle_ticks; + + // Prepare tick timer for new round + furi_hal_os_timer_reset(); + + // Resume ticks + LL_SYSTICK_EnableIT(); + furi_hal_os_timer_continuous(FURI_HAL_OS_CLK_PER_TICK); + + return after_tick; +} + +void vPortSuppressTicksAndSleep(TickType_t expected_idle_ticks) { + if(!furi_hal_power_sleep_available()) { + __WFI(); + return; + } + + // Limit mount of ticks to maximum that timer can count + if (expected_idle_ticks > FURI_HAL_OS_MAX_SLEEP) { + expected_idle_ticks = FURI_HAL_OS_MAX_SLEEP; + } + + // Stop IRQ handling, no one should disturb us till we finish + __disable_irq(); + + // Confirm OS that sleep is still possible + if (eTaskConfirmSleepModeStatus() == eAbortSleep) { + __enable_irq(); + return; + } + + // Sleep and track how much ticks we spent sleeping + uint32_t completed_ticks = furi_hal_os_sleep(expected_idle_ticks); + + // Notify system about time spent in sleep + if (completed_ticks > 0) { + if (completed_ticks > expected_idle_ticks) { + vTaskStepTick(expected_idle_ticks); + } else { + vTaskStepTick(completed_ticks); + } + } + + // Reenable IRQ + __enable_irq(); +} + +void vApplicationStackOverflowHook(TaskHandle_t xTask, signed char *pcTaskName) { + asm("bkpt 1"); + while(1) {}; +} diff --git a/firmware/targets/f7/furi-hal/furi-hal-os.h b/firmware/targets/f7/furi-hal/furi-hal-os.h new file mode 100644 index 00000000..72ae74fc --- /dev/null +++ b/firmware/targets/f7/furi-hal/furi-hal-os.h @@ -0,0 +1,17 @@ +#pragma once + +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Initialize OS helpers + * Configure and start tick timer + */ +void furi_hal_os_init(); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/firmware/targets/f7/furi-hal/furi-hal-power.c b/firmware/targets/f7/furi-hal/furi-hal-power.c new file mode 100644 index 00000000..4dd0127f --- /dev/null +++ b/firmware/targets/f7/furi-hal/furi-hal-power.c @@ -0,0 +1,280 @@ +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +typedef struct { + volatile uint32_t insomnia; + volatile uint32_t deep_insomnia; +} FuriHalPower; + +static volatile FuriHalPower furi_hal_power = { + .insomnia = 0, + .deep_insomnia = 1, +}; + +const ParamCEDV cedv = { + .cedv_conf.gauge_conf = { + .CCT = 1, + .CSYNC = 0, + .EDV_CMP = 0, + .SC = 1, + .FIXED_EDV0 = 1, + .FCC_LIM = 1, + .FC_FOR_VDQ = 1, + .IGNORE_SD = 1, + .SME0 = 0, + }, + .full_charge_cap = 2100, + .design_cap = 2100, + .EDV0 = 3300, + .EDV1 = 3321, + .EDV2 = 3355, + .EMF = 3679, + .C0 = 430, + .C1 = 0, + .R1 = 408, + .R0 = 334, + .T0 = 4626, + .TC = 11, + .DOD0 = 4044, + .DOD10 = 3905, + .DOD20 = 3807, + .DOD30 = 3718, + .DOD40 = 3642, + .DOD50 = 3585, + .DOD60 = 3546, + .DOD70 = 3514, + .DOD80 = 3477, + .DOD90 = 3411, + .DOD100 = 3299, +}; + +void HAL_RCC_CSSCallback(void) { + // TODO: notify user about issue with HSE + furi_hal_power_reset(); +} + +void furi_hal_power_init() { + LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1); + LL_PWR_SMPS_SetMode(LL_PWR_SMPS_STEP_DOWN); + bq27220_init(&cedv); + bq25896_init(); + FURI_LOG_I("FuriHalPower", "Init OK"); +} + +uint16_t furi_hal_power_insomnia_level() { + return furi_hal_power.insomnia; +} + +void furi_hal_power_insomnia_enter() { + furi_hal_power.insomnia++; +} + +void furi_hal_power_insomnia_exit() { + furi_hal_power.insomnia--; +} + +bool furi_hal_power_sleep_available() { + return furi_hal_power.insomnia == 0; +} + +bool furi_hal_power_deep_sleep_available() { + return furi_hal_bt_is_alive() && furi_hal_power.deep_insomnia == 0; +} + +void furi_hal_power_light_sleep() { + __WFI(); +} + +void furi_hal_power_deep_sleep() { + while( LL_HSEM_1StepLock(HSEM, CFG_HW_RCC_SEMID)); + + if (!LL_HSEM_1StepLock(HSEM, CFG_HW_ENTRY_STOP_MODE_SEMID)) { + if(LL_PWR_IsActiveFlag_C2DS()) { + // Release ENTRY_STOP_MODE semaphore + LL_HSEM_ReleaseLock(HSEM, CFG_HW_ENTRY_STOP_MODE_SEMID, 0); + + // The switch on HSI before entering Stop Mode is required + furi_hal_clock_switch_to_hsi(); + } + } else { + /** + * The switch on HSI before entering Stop Mode is required + */ + furi_hal_clock_switch_to_hsi(); + } + + /* Release RCC semaphore */ + LL_HSEM_ReleaseLock(HSEM, CFG_HW_RCC_SEMID, 0); + + // Prepare deep sleep + LL_PWR_SetPowerMode(LL_PWR_MODE_STOP1); + LL_LPM_EnableDeepSleep(); + +#if defined ( __CC_ARM) + // Force store operations + __force_stores(); +#endif + + __WFI(); + + /* Release ENTRY_STOP_MODE semaphore */ + LL_HSEM_ReleaseLock(HSEM, CFG_HW_ENTRY_STOP_MODE_SEMID, 0); + + while(LL_HSEM_1StepLock(HSEM, CFG_HW_RCC_SEMID)); + + if(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL) { + furi_hal_clock_switch_to_pll(); + } + + LL_HSEM_ReleaseLock(HSEM, CFG_HW_RCC_SEMID, 0); +} + +void furi_hal_power_sleep() { + if(furi_hal_power_deep_sleep_available()) { + furi_hal_power_deep_sleep(); + } else { + furi_hal_power_light_sleep(); + } +} + + +uint8_t furi_hal_power_get_pct() { + return bq27220_get_state_of_charge(); +} + +uint8_t furi_hal_power_get_bat_health_pct() { + return bq27220_get_state_of_health(); +} + +bool furi_hal_power_is_charging() { + return bq25896_is_charging(); +} + +void furi_hal_power_off() { + bq25896_poweroff(); +} + +void furi_hal_power_reset() { + NVIC_SystemReset(); +} + +void furi_hal_power_enable_otg() { + bq25896_enable_otg(); +} + +void furi_hal_power_disable_otg() { + bq25896_disable_otg(); +} + +uint32_t furi_hal_power_get_battery_remaining_capacity() { + return bq27220_get_remaining_capacity(); +} + +uint32_t furi_hal_power_get_battery_full_capacity() { + return bq27220_get_full_charge_capacity(); +} + +float furi_hal_power_get_battery_voltage(FuriHalPowerIC ic) { + if (ic == FuriHalPowerICCharger) { + return (float)bq25896_get_vbat_voltage() / 1000.0f; + } else if (ic == FuriHalPowerICFuelGauge) { + return (float)bq27220_get_voltage() / 1000.0f; + } else { + return 0.0f; + } +} + +float furi_hal_power_get_battery_current(FuriHalPowerIC ic) { + if (ic == FuriHalPowerICCharger) { + return (float)bq25896_get_vbat_current() / 1000.0f; + } else if (ic == FuriHalPowerICFuelGauge) { + return (float)bq27220_get_current() / 1000.0f; + } else { + return 0.0f; + } +} + +float furi_hal_power_get_battery_temperature(FuriHalPowerIC ic) { + if (ic == FuriHalPowerICCharger) { + // Linear approximation, +/- 5 C + return (71.0f - (float)bq25896_get_ntc_mpct()/1000) / 0.6f; + } else if (ic == FuriHalPowerICFuelGauge) { + return ((float)bq27220_get_temperature() - 2731.0f) / 10.0f; + } else { + return 0.0f; + } + +} + +float furi_hal_power_get_usb_voltage(){ + return (float)bq25896_get_vbus_voltage() / 1000.0f; +} + +void furi_hal_power_dump_state() { + BatteryStatus battery_status; + OperationStatus operation_status; + if (bq27220_get_battery_status(&battery_status) == BQ27220_ERROR + || bq27220_get_operation_status(&operation_status) == BQ27220_ERROR) { + printf("Failed to get bq27220 status. Communication error.\r\n"); + } else { + printf( + "bq27220: CALMD: %d, SEC0: %d, SEC1: %d, EDV2: %d, VDQ: %d, INITCOMP: %d, SMTH: %d, BTPINT: %d, CFGUPDATE: %d\r\n", + operation_status.CALMD, operation_status.SEC0, operation_status.SEC1, + operation_status.EDV2, operation_status.VDQ, operation_status.INITCOMP, + operation_status.SMTH, operation_status.BTPINT, operation_status.CFGUPDATE + ); + // Battery status register, part 1 + printf( + "bq27220: CHGINH: %d, FC: %d, OTD: %d, OTC: %d, SLEEP: %d, OCVFAIL: %d, OCVCOMP: %d, FD: %d\r\n", + battery_status.CHGINH, battery_status.FC, battery_status.OTD, + battery_status.OTC, battery_status.SLEEP, battery_status.OCVFAIL, + battery_status.OCVCOMP, battery_status.FD + ); + // Battery status register, part 2 + printf( + "bq27220: DSG: %d, SYSDWN: %d, TDA: %d, BATTPRES: %d, AUTH_GD: %d, OCVGD: %d, TCA: %d, RSVD: %d\r\n", + battery_status.DSG, battery_status.SYSDWN, battery_status.TDA, + battery_status.BATTPRES, battery_status.AUTH_GD, battery_status.OCVGD, + battery_status.TCA, battery_status.RSVD + ); + // Voltage and current info + printf( + "bq27220: Full capacity: %dmAh, Design capacity: %dmAh, Remaining capacity: %dmAh, State of Charge: %d%%, State of health: %d%%\r\n", + bq27220_get_full_charge_capacity(), bq27220_get_design_capacity(), bq27220_get_remaining_capacity(), + bq27220_get_state_of_charge(), bq27220_get_state_of_health() + ); + printf( + "bq27220: Voltage: %dmV, Current: %dmA, Temperature: %dC\r\n", + bq27220_get_voltage(), bq27220_get_current(), (int)furi_hal_power_get_battery_temperature(FuriHalPowerICFuelGauge) + ); + } + + printf( + "bq25896: VBUS: %d, VSYS: %d, VBAT: %d, Current: %d, NTC: %ldm%%\r\n", + bq25896_get_vbus_voltage(), bq25896_get_vsys_voltage(), + bq25896_get_vbat_voltage(), bq25896_get_vbat_current(), + bq25896_get_ntc_mpct() + ); +} + +void furi_hal_power_enable_external_3_3v(){ + LL_GPIO_SetOutputPin(PERIPH_POWER_GPIO_Port, PERIPH_POWER_Pin); +} + +void furi_hal_power_disable_external_3_3v(){ + LL_GPIO_ResetOutputPin(PERIPH_POWER_GPIO_Port, PERIPH_POWER_Pin); +} diff --git a/firmware/targets/f7/furi-hal/furi-hal-pwm.c b/firmware/targets/f7/furi-hal/furi-hal-pwm.c new file mode 100644 index 00000000..972d28ba --- /dev/null +++ b/firmware/targets/f7/furi-hal/furi-hal-pwm.c @@ -0,0 +1,50 @@ +#include "furi-hal-pwm.h" + +void hal_pwm_set(float value, float freq, TIM_HandleTypeDef* tim, uint32_t channel) { + tim->Init.CounterMode = TIM_COUNTERMODE_UP; + tim->Init.Period = (uint32_t)((SystemCoreClock / (tim->Init.Prescaler + 1)) / freq) - 1; + tim->Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; + tim->Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; + HAL_TIM_PWM_Init(tim); + + TIM_OC_InitTypeDef sConfigOC; + + sConfigOC.OCMode = TIM_OCMODE_PWM1; + sConfigOC.Pulse = (uint16_t)(tim->Init.Period * value); + sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; + sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH; + sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; + sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET; + sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET; + HAL_TIM_PWM_ConfigChannel(tim, &sConfigOC, channel); + HAL_TIM_PWM_Start(tim, channel); +} + +void hal_pwmn_set(float value, float freq, TIM_HandleTypeDef* tim, uint32_t channel) { + tim->Init.CounterMode = TIM_COUNTERMODE_UP; + tim->Init.Period = (uint32_t)((SystemCoreClock / (tim->Init.Prescaler + 1)) / freq) - 1; + tim->Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; + tim->Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; + HAL_TIM_PWM_Init(tim); + + TIM_OC_InitTypeDef sConfigOC; + + sConfigOC.OCMode = TIM_OCMODE_PWM1; + sConfigOC.Pulse = (uint16_t)(tim->Init.Period * value); + sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; + sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH; + sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; + sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET; + sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET; + HAL_TIM_PWM_ConfigChannel(tim, &sConfigOC, channel); + HAL_TIMEx_PWMN_Start(tim, channel); +} + +void hal_pwm_stop(TIM_HandleTypeDef* tim, uint32_t channel) { + HAL_TIM_PWM_Stop(tim, channel); +} + +void hal_pwmn_stop(TIM_HandleTypeDef* tim, uint32_t channel) { + HAL_TIMEx_PWMN_Stop(tim, channel); +} + diff --git a/firmware/targets/f7/furi-hal/furi-hal-pwm.h b/firmware/targets/f7/furi-hal/furi-hal-pwm.h new file mode 100644 index 00000000..58b5701e --- /dev/null +++ b/firmware/targets/f7/furi-hal/furi-hal-pwm.h @@ -0,0 +1,16 @@ +#pragma once +#include "main.h" +#include "stdbool.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void hal_pwm_set(float value, float freq, TIM_HandleTypeDef* tim, uint32_t channel); +void hal_pwmn_set(float value, float freq, TIM_HandleTypeDef* tim, uint32_t channel); +void hal_pwm_stop(TIM_HandleTypeDef* tim, uint32_t channel); +void hal_pwmn_stop(TIM_HandleTypeDef* tim, uint32_t channel); + +#ifdef __cplusplus +} +#endif diff --git a/firmware/targets/f7/furi-hal/furi-hal-resources.c b/firmware/targets/f7/furi-hal/furi-hal-resources.c new file mode 100644 index 00000000..52ea3cf7 --- /dev/null +++ b/firmware/targets/f7/furi-hal/furi-hal-resources.c @@ -0,0 +1,57 @@ +#include +#include "main.h" +#include + +const InputPin input_pins[] = { + {.port = BUTTON_UP_GPIO_Port, .pin = BUTTON_UP_Pin, .key = InputKeyUp, .inverted = true, .name="Up"}, + {.port = BUTTON_DOWN_GPIO_Port, .pin = BUTTON_DOWN_Pin, .key = InputKeyDown, .inverted = true, .name="Down"}, + {.port = BUTTON_RIGHT_GPIO_Port, + .pin = BUTTON_RIGHT_Pin, + .key = InputKeyRight, + .inverted = true, .name="Right"}, + {.port = BUTTON_LEFT_GPIO_Port, .pin = BUTTON_LEFT_Pin, .key = InputKeyLeft, .inverted = true, .name="Left"}, + {.port = BUTTON_OK_GPIO_Port, .pin = BUTTON_OK_Pin, .key = InputKeyOk, .inverted = false, .name="Ok"}, + {.port = BUTTON_BACK_GPIO_Port, .pin = BUTTON_BACK_Pin, .key = InputKeyBack, .inverted = true, .name="Back"}, +}; + +const size_t input_pins_count = sizeof(input_pins) / sizeof(InputPin); + +const GpioPin vibro_gpio = {.port = VIBRO_GPIO_Port, .pin = VIBRO_Pin}; +const GpioPin ibutton_gpio = {.port = iBTN_GPIO_Port, .pin = iBTN_Pin}; + +const GpioPin gpio_cc1101_g0 = {.port = CC1101_G0_GPIO_Port, .pin = CC1101_G0_Pin}; +const GpioPin gpio_rf_sw_0 = {.port = RF_SW_0_GPIO_Port, .pin = RF_SW_0_Pin}; + +const GpioPin gpio_subghz_cs = {.port = CC1101_CS_GPIO_Port, .pin = CC1101_CS_Pin}; +const GpioPin gpio_display_cs = {.port = DISPLAY_CS_GPIO_Port, .pin = DISPLAY_CS_Pin}; +const GpioPin gpio_display_rst = {.port = DISPLAY_RST_GPIO_Port, .pin = DISPLAY_RST_Pin}; +const GpioPin gpio_display_di = {.port = DISPLAY_DI_GPIO_Port, .pin = DISPLAY_DI_Pin}; +const GpioPin gpio_sdcard_cs = {.port = SD_CS_GPIO_Port, .pin = SD_CS_Pin}; +const GpioPin gpio_nfc_cs = {.port = NFC_CS_GPIO_Port, .pin = NFC_CS_Pin}; + +const GpioPin gpio_spi_d_miso = {.port = SPI_D_MISO_GPIO_Port, .pin = SPI_D_MISO_Pin}; +const GpioPin gpio_spi_d_mosi = {.port = SPI_D_MOSI_GPIO_Port, .pin = SPI_D_MOSI_Pin}; +const GpioPin gpio_spi_d_sck = {.port = SPI_D_SCK_GPIO_Port, .pin = SPI_D_SCK_Pin}; +const GpioPin gpio_spi_r_miso = {.port = SPI_R_MISO_GPIO_Port, .pin = SPI_R_MISO_Pin}; +const GpioPin gpio_spi_r_mosi = {.port = SPI_R_MOSI_GPIO_Port, .pin = SPI_R_MOSI_Pin}; +const GpioPin gpio_spi_r_sck = {.port = SPI_R_SCK_GPIO_Port, .pin = SPI_R_SCK_Pin}; + +const GpioPin gpio_ext_pc0 = {.port = GPIOC, .pin = GPIO_PIN_0}; +const GpioPin gpio_ext_pc1 = {.port = GPIOC, .pin = GPIO_PIN_1}; +const GpioPin gpio_ext_pc3 = {.port = GPIOC, .pin = GPIO_PIN_3}; +const GpioPin gpio_ext_pb2 = {.port = GPIOB, .pin = GPIO_PIN_2}; +const GpioPin gpio_ext_pb3 = {.port = GPIOB, .pin = GPIO_PIN_3}; +const GpioPin gpio_ext_pa4 = {.port = GPIOA, .pin = GPIO_PIN_4}; +const GpioPin gpio_ext_pa6 = {.port = GPIOA, .pin = GPIO_PIN_6}; +const GpioPin gpio_ext_pa7 = {.port = GPIOA, .pin = GPIO_PIN_7}; + +const GpioPin gpio_rfid_pull = {.port = RFID_PULL_GPIO_Port, .pin = RFID_PULL_Pin}; +const GpioPin gpio_rfid_carrier_out = {.port = RFID_OUT_GPIO_Port, .pin = RFID_OUT_Pin}; +const GpioPin gpio_rfid_data_in = {.port = RFID_RF_IN_GPIO_Port, .pin = RFID_RF_IN_Pin}; +const GpioPin gpio_rfid_carrier = {.port = RFID_CARRIER_GPIO_Port, .pin = RFID_CARRIER_Pin}; + +const GpioPin gpio_irda_rx = {.port = IR_RX_GPIO_Port, .pin = IR_RX_Pin}; +const GpioPin gpio_irda_tx = {.port = IR_TX_GPIO_Port, .pin = IR_TX_Pin}; + +const GpioPin gpio_usart_tx = {.port = USART1_TX_Port, .pin = USART1_TX_Pin}; +const GpioPin gpio_usart_rx = {.port = USART1_RX_Port, .pin = USART1_RX_Pin}; diff --git a/firmware/targets/f7/furi-hal/furi-hal-resources.h b/firmware/targets/f7/furi-hal/furi-hal-resources.h new file mode 100644 index 00000000..09af7532 --- /dev/null +++ b/firmware/targets/f7/furi-hal/furi-hal-resources.h @@ -0,0 +1,105 @@ +#pragma once + +#include "main.h" +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define POWER_I2C_SCL_Pin LL_GPIO_PIN_9 +#define POWER_I2C_SCL_GPIO_Port GPIOA +#define POWER_I2C_SDA_Pin LL_GPIO_PIN_10 +#define POWER_I2C_SDA_GPIO_Port GPIOA + +#define POWER_I2C I2C1 +/** Timing register value is computed with the STM32CubeMX Tool, + * Standard Mode @100kHz with I2CCLK = 64 MHz, + * rise time = 0ns, fall time = 0ns + */ +#define POWER_I2C_TIMINGS_100 0x10707DBC + +/** Timing register value is computed with the STM32CubeMX Tool, + * Fast Mode @400kHz with I2CCLK = 64 MHz, + * rise time = 0ns, fall time = 0ns + */ +#define POWER_I2C_TIMINGS_400 0x00602173 + +/* Input Related Constants */ +#define INPUT_DEBOUNCE_TICKS 20 + +/* Input Keys */ +typedef enum { + InputKeyUp, + InputKeyDown, + InputKeyRight, + InputKeyLeft, + InputKeyOk, + InputKeyBack, +} InputKey; + +/* Light */ +typedef enum { + LightRed, + LightGreen, + LightBlue, + LightBacklight, +} Light; + +typedef struct { + const GPIO_TypeDef* port; + const uint16_t pin; + const InputKey key; + const bool inverted; + const char* name; +} InputPin; + +extern const InputPin input_pins[]; +extern const size_t input_pins_count; + +extern const GpioPin vibro_gpio; +extern const GpioPin ibutton_gpio; + +extern const GpioPin gpio_cc1101_g0; +extern const GpioPin gpio_rf_sw_0; + +extern const GpioPin gpio_subghz_cs; +extern const GpioPin gpio_display_cs; +extern const GpioPin gpio_display_rst; +extern const GpioPin gpio_display_di; +extern const GpioPin gpio_sdcard_cs; +extern const GpioPin gpio_nfc_cs; + +extern const GpioPin gpio_spi_d_miso; +extern const GpioPin gpio_spi_d_mosi; +extern const GpioPin gpio_spi_d_sck; +extern const GpioPin gpio_spi_r_miso; +extern const GpioPin gpio_spi_r_mosi; +extern const GpioPin gpio_spi_r_sck; + +extern const GpioPin gpio_ext_pc0; +extern const GpioPin gpio_ext_pc1; +extern const GpioPin gpio_ext_pc3; +extern const GpioPin gpio_ext_pb2; +extern const GpioPin gpio_ext_pb3; +extern const GpioPin gpio_ext_pa4; +extern const GpioPin gpio_ext_pa6; +extern const GpioPin gpio_ext_pa7; + +extern const GpioPin gpio_rfid_pull; +extern const GpioPin gpio_rfid_carrier_out; +extern const GpioPin gpio_rfid_data_in; +extern const GpioPin gpio_rfid_carrier; + +extern const GpioPin gpio_irda_rx; +extern const GpioPin gpio_irda_tx; + +extern const GpioPin gpio_usart_tx; +extern const GpioPin gpio_usart_rx; + +#ifdef __cplusplus +} +#endif diff --git a/firmware/targets/f7/furi-hal/furi-hal-rfid.c b/firmware/targets/f7/furi-hal/furi-hal-rfid.c new file mode 100644 index 00000000..b4ec96fc --- /dev/null +++ b/firmware/targets/f7/furi-hal/furi-hal-rfid.c @@ -0,0 +1,297 @@ +#include +#include +#include + +#include + +#define LFRFID_READ_TIM htim1 +#define LFRFID_READ_CHANNEL TIM_CHANNEL_1 +#define LFRFID_EMULATE_TIM htim2 +#define LFRFID_EMULATE_CHANNEL TIM_CHANNEL_3 + +void furi_hal_rfid_init() { + furi_hal_rfid_pins_reset(); +} + +void furi_hal_rfid_pins_reset() { + // ibutton bus disable + furi_hal_ibutton_stop(); + + // pulldown rfid antenna + hal_gpio_init(&gpio_rfid_carrier_out, GpioModeOutputPushPull, GpioSpeedLow, GpioPullNo); + hal_gpio_write(&gpio_rfid_carrier_out, false); + + // from both sides + hal_gpio_init(&gpio_rfid_pull, GpioModeOutputPushPull, GpioSpeedLow, GpioPullNo); + hal_gpio_write(&gpio_rfid_pull, true); + + hal_gpio_init_simple(&gpio_rfid_carrier, GpioModeAnalog); +} + +void furi_hal_rfid_pins_emulate() { + // ibutton low + furi_hal_ibutton_start(); + furi_hal_ibutton_pin_low(); + + // pull pin to timer out + hal_gpio_init_ex( + &gpio_rfid_pull, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedLow, GpioAltFn1TIM2); + + // pull rfid antenna from carrier side + hal_gpio_init(&gpio_rfid_carrier_out, GpioModeOutputPushPull, GpioSpeedLow, GpioPullNo); + hal_gpio_write(&gpio_rfid_carrier_out, false); + + hal_gpio_init_ex( + &gpio_rfid_carrier, GpioModeAltFunctionPushPull, GpioSpeedLow, GpioPullUp, GpioAltFn2TIM2); +} + +void furi_hal_rfid_pins_read() { + // ibutton low + furi_hal_ibutton_start(); + furi_hal_ibutton_pin_low(); + + // dont pull rfid antenna + hal_gpio_init(&gpio_rfid_pull, GpioModeOutputPushPull, GpioSpeedLow, GpioPullNo); + hal_gpio_write(&gpio_rfid_pull, false); + + // carrier pin to timer out + hal_gpio_init_ex( + &gpio_rfid_carrier_out, + GpioModeAltFunctionPushPull, + GpioPullNo, + GpioSpeedLow, + GpioAltFn1TIM1); + + // comparator in + hal_gpio_init(&gpio_rfid_data_in, GpioModeAnalog, GpioSpeedLow, GpioPullNo); +} + +void furi_hal_rfid_tim_read(float freq, float duty_cycle) { + // TODO LL init + uint32_t period = (uint32_t)((SystemCoreClock) / freq) - 1; + + TIM_ClockConfigTypeDef sClockSourceConfig = {0}; + TIM_MasterConfigTypeDef sMasterConfig = {0}; + TIM_OC_InitTypeDef sConfigOC = {0}; + TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0}; + + // basic PWM setup with needed freq and internal clock + LFRFID_READ_TIM.Init.Prescaler = 0; + LFRFID_READ_TIM.Init.CounterMode = TIM_COUNTERMODE_UP; + LFRFID_READ_TIM.Init.Period = period; + LFRFID_READ_TIM.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; + LFRFID_READ_TIM.Init.RepetitionCounter = 0; + LFRFID_READ_TIM.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; + if(HAL_TIM_Base_Init(&LFRFID_READ_TIM) != HAL_OK) { + Error_Handler(); + } + sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; + if(HAL_TIM_ConfigClockSource(&LFRFID_READ_TIM, &sClockSourceConfig) != HAL_OK) { + Error_Handler(); + } + if(HAL_TIM_PWM_Init(&LFRFID_READ_TIM) != HAL_OK) { + Error_Handler(); + } + + // no master-slave mode + sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; + sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET; + sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; + if(HAL_TIMEx_MasterConfigSynchronization(&LFRFID_READ_TIM, &sMasterConfig) != HAL_OK) { + Error_Handler(); + } + + // pwm config + sConfigOC.OCMode = TIM_OCMODE_PWM1; + sConfigOC.Pulse = (uint32_t)(LFRFID_READ_TIM.Init.Period * duty_cycle); + sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; + sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH; + sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; + sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET; + sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET; + if(HAL_TIM_OC_ConfigChannel(&LFRFID_READ_TIM, &sConfigOC, LFRFID_READ_CHANNEL) != HAL_OK) { + Error_Handler(); + } + + // no deadtime + sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE; + sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE; + sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF; + sBreakDeadTimeConfig.DeadTime = 0; + sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE; + sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH; + sBreakDeadTimeConfig.BreakFilter = 0; + sBreakDeadTimeConfig.BreakAFMode = TIM_BREAK_AFMODE_INPUT; + sBreakDeadTimeConfig.Break2State = TIM_BREAK2_DISABLE; + sBreakDeadTimeConfig.Break2Polarity = TIM_BREAK2POLARITY_HIGH; + sBreakDeadTimeConfig.Break2Filter = 0; + sBreakDeadTimeConfig.Break2AFMode = TIM_BREAK_AFMODE_INPUT; + sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE; + if(HAL_TIMEx_ConfigBreakDeadTime(&LFRFID_READ_TIM, &sBreakDeadTimeConfig) != HAL_OK) { + Error_Handler(); + } +} + +void furi_hal_rfid_tim_read_start() { + HAL_TIMEx_PWMN_Start(&LFRFID_READ_TIM, LFRFID_READ_CHANNEL); +} + +void furi_hal_rfid_tim_read_stop() { + HAL_TIMEx_PWMN_Stop(&LFRFID_READ_TIM, LFRFID_READ_CHANNEL); +} + +void furi_hal_rfid_tim_emulate(float freq) { + // TODO LL init + // uint32_t prescaler = (uint32_t)((SystemCoreClock) / freq) - 1; + + TIM_ClockConfigTypeDef sClockSourceConfig = {0}; + TIM_MasterConfigTypeDef sMasterConfig = {0}; + TIM_OC_InitTypeDef sConfigOC = {0}; + TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0}; + + // basic PWM setup with needed freq and internal clock + LFRFID_EMULATE_TIM.Init.Prescaler = 0; + LFRFID_EMULATE_TIM.Init.CounterMode = TIM_COUNTERMODE_UP; + LFRFID_EMULATE_TIM.Init.Period = 1; + LFRFID_EMULATE_TIM.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; + LFRFID_EMULATE_TIM.Init.RepetitionCounter = 0; + LFRFID_EMULATE_TIM.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; + if(HAL_TIM_Base_Init(&LFRFID_EMULATE_TIM) != HAL_OK) { + Error_Handler(); + } + + sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_ETRMODE2; + sClockSourceConfig.ClockPolarity = TIM_ETRPOLARITY_INVERTED; + sClockSourceConfig.ClockPrescaler = TIM_CLOCKPRESCALER_DIV1; + sClockSourceConfig.ClockFilter = 0; + if(HAL_TIM_ConfigClockSource(&LFRFID_EMULATE_TIM, &sClockSourceConfig) != HAL_OK) { + Error_Handler(); + } + if(HAL_TIM_PWM_Init(&LFRFID_EMULATE_TIM) != HAL_OK) { + Error_Handler(); + } + + // no master-slave mode + sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; + sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET; + sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; + if(HAL_TIMEx_MasterConfigSynchronization(&LFRFID_EMULATE_TIM, &sMasterConfig) != HAL_OK) { + Error_Handler(); + } + + // pwm config + sConfigOC.OCMode = TIM_OCMODE_PWM1; + sConfigOC.Pulse = 1; + sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; + sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH; + sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; + sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET; + sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET; + if(HAL_TIM_PWM_ConfigChannel(&LFRFID_EMULATE_TIM, &sConfigOC, LFRFID_EMULATE_CHANNEL) != + HAL_OK) { + Error_Handler(); + } + + // no deadtime + sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE; + sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE; + sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF; + sBreakDeadTimeConfig.DeadTime = 0; + sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE; + sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH; + sBreakDeadTimeConfig.BreakFilter = 0; + sBreakDeadTimeConfig.BreakAFMode = TIM_BREAK_AFMODE_INPUT; + sBreakDeadTimeConfig.Break2State = TIM_BREAK2_DISABLE; + sBreakDeadTimeConfig.Break2Polarity = TIM_BREAK2POLARITY_HIGH; + sBreakDeadTimeConfig.Break2Filter = 0; + sBreakDeadTimeConfig.Break2AFMode = TIM_BREAK_AFMODE_INPUT; + sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE; + if(HAL_TIMEx_ConfigBreakDeadTime(&LFRFID_EMULATE_TIM, &sBreakDeadTimeConfig) != HAL_OK) { + Error_Handler(); + } +} + +void furi_hal_rfid_tim_emulate_start() { + // TODO make api for interrupts priority + for(size_t i = WWDG_IRQn; i <= DMAMUX1_OVR_IRQn; i++) { + HAL_NVIC_SetPriority(i, 15, 0); + } + + HAL_NVIC_SetPriority(TIM2_IRQn, 5, 0); + HAL_NVIC_EnableIRQ(TIM2_IRQn); + + HAL_TIM_PWM_Start_IT(&LFRFID_EMULATE_TIM, LFRFID_EMULATE_CHANNEL); + HAL_TIM_Base_Start_IT(&LFRFID_EMULATE_TIM); +} + +void furi_hal_rfid_tim_emulate_stop() { + HAL_TIM_Base_Stop(&LFRFID_EMULATE_TIM); + HAL_TIM_PWM_Stop(&LFRFID_EMULATE_TIM, LFRFID_EMULATE_CHANNEL); +} + +void furi_hal_rfid_tim_reset() { + HAL_TIM_Base_DeInit(&LFRFID_READ_TIM); + LL_TIM_DeInit(TIM1); + LL_APB2_GRP1_DisableClock(LL_APB2_GRP1_PERIPH_TIM1); + HAL_TIM_Base_DeInit(&LFRFID_EMULATE_TIM); + LL_TIM_DeInit(TIM2); + LL_APB1_GRP1_DisableClock(LL_APB1_GRP1_PERIPH_TIM2); +} + +bool furi_hal_rfid_is_tim_emulate(TIM_HandleTypeDef* hw) { + return (hw == &LFRFID_EMULATE_TIM); +} + +void furi_hal_rfid_set_emulate_period(uint32_t period) { + LFRFID_EMULATE_TIM.Instance->ARR = period; +} + +void furi_hal_rfid_set_emulate_pulse(uint32_t pulse) { + switch(LFRFID_EMULATE_CHANNEL) { + case TIM_CHANNEL_1: + LFRFID_EMULATE_TIM.Instance->CCR1 = pulse; + break; + case TIM_CHANNEL_2: + LFRFID_EMULATE_TIM.Instance->CCR2 = pulse; + break; + case TIM_CHANNEL_3: + LFRFID_EMULATE_TIM.Instance->CCR3 = pulse; + break; + case TIM_CHANNEL_4: + LFRFID_EMULATE_TIM.Instance->CCR4 = pulse; + break; + default: + furi_check(0); + break; + } +} + +void furi_hal_rfid_set_read_period(uint32_t period) { + LFRFID_TIM.Instance->ARR = period; +} + +void furi_hal_rfid_set_read_pulse(uint32_t pulse) { + switch(LFRFID_READ_CHANNEL) { + case TIM_CHANNEL_1: + LFRFID_TIM.Instance->CCR1 = pulse; + break; + case TIM_CHANNEL_2: + LFRFID_TIM.Instance->CCR2 = pulse; + break; + case TIM_CHANNEL_3: + LFRFID_TIM.Instance->CCR3 = pulse; + break; + case TIM_CHANNEL_4: + LFRFID_TIM.Instance->CCR4 = pulse; + break; + default: + furi_check(0); + break; + } +} + +void furi_hal_rfid_change_read_config(float freq, float duty_cycle) { + uint32_t period = (uint32_t)((SystemCoreClock) / freq) - 1; + furi_hal_rfid_set_read_period(period); + furi_hal_rfid_set_read_pulse(period * duty_cycle); +} diff --git a/firmware/targets/f7/furi-hal/furi-hal-sd.c b/firmware/targets/f7/furi-hal/furi-hal-sd.c new file mode 100644 index 00000000..01cf9339 --- /dev/null +++ b/firmware/targets/f7/furi-hal/furi-hal-sd.c @@ -0,0 +1,22 @@ +#include "furi-hal-sd.h" +#include +#include + +void hal_sd_detect_init(void) { + // low speed input with pullup + LL_GPIO_SetPinMode(SD_CD_GPIO_Port, SD_CD_Pin, LL_GPIO_MODE_INPUT); + LL_GPIO_SetPinSpeed(SD_CD_GPIO_Port, SD_CD_Pin, LL_GPIO_SPEED_FREQ_LOW); + LL_GPIO_SetPinPull(SD_CD_GPIO_Port, SD_CD_Pin, LL_GPIO_PULL_UP); +} + +void hal_sd_detect_set_low(void) { + // low speed input with pullup + LL_GPIO_SetPinMode(SD_CD_GPIO_Port, SD_CD_Pin, LL_GPIO_MODE_OUTPUT); + LL_GPIO_SetPinOutputType(SD_CD_GPIO_Port, SD_CD_Pin, LL_GPIO_OUTPUT_OPENDRAIN); + LL_GPIO_ResetOutputPin(SD_CD_GPIO_Port, SD_CD_Pin); +} + +bool hal_sd_detect(void) { + bool result = !(LL_GPIO_IsInputPinSet(SD_CD_GPIO_Port, SD_CD_Pin)); + return result; +} \ No newline at end of file diff --git a/firmware/targets/f7/furi-hal/furi-hal-spi-config.c b/firmware/targets/f7/furi-hal/furi-hal-spi-config.c new file mode 100644 index 00000000..315d82a2 --- /dev/null +++ b/firmware/targets/f7/furi-hal/furi-hal-spi-config.c @@ -0,0 +1,103 @@ +#include +#include + +#define SPI_R SPI1 +#define SPI_D SPI2 + +const LL_SPI_InitTypeDef furi_hal_spi_config_nfc = { + .Mode = LL_SPI_MODE_MASTER, + .TransferDirection = LL_SPI_FULL_DUPLEX, + .DataWidth = LL_SPI_DATAWIDTH_8BIT, + .ClockPolarity = LL_SPI_POLARITY_LOW, + .ClockPhase = LL_SPI_PHASE_2EDGE, + .NSS = LL_SPI_NSS_SOFT, + .BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV8, + .BitOrder = LL_SPI_MSB_FIRST, + .CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE, + .CRCPoly = 7, +}; + +const LL_SPI_InitTypeDef furi_hal_spi_config_subghz = { + .Mode = LL_SPI_MODE_MASTER, + .TransferDirection = LL_SPI_FULL_DUPLEX, + .DataWidth = LL_SPI_DATAWIDTH_8BIT, + .ClockPolarity = LL_SPI_POLARITY_LOW, + .ClockPhase = LL_SPI_PHASE_1EDGE, + .NSS = LL_SPI_NSS_SOFT, + .BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV8, + .BitOrder = LL_SPI_MSB_FIRST, + .CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE, + .CRCPoly = 7, +}; + +const LL_SPI_InitTypeDef furi_hal_spi_config_display = { + .Mode = LL_SPI_MODE_MASTER, + .TransferDirection = LL_SPI_FULL_DUPLEX, + .DataWidth = LL_SPI_DATAWIDTH_8BIT, + .ClockPolarity = LL_SPI_POLARITY_LOW, + .ClockPhase = LL_SPI_PHASE_1EDGE, + .NSS = LL_SPI_NSS_SOFT, + .BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV16, + .BitOrder = LL_SPI_MSB_FIRST, + .CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE, + .CRCPoly = 7, +}; + +/** + * SD Card in fast mode (after init) + */ +const LL_SPI_InitTypeDef furi_hal_spi_config_sd_fast = { + .Mode = LL_SPI_MODE_MASTER, + .TransferDirection = LL_SPI_FULL_DUPLEX, + .DataWidth = LL_SPI_DATAWIDTH_8BIT, + .ClockPolarity = LL_SPI_POLARITY_LOW, + .ClockPhase = LL_SPI_PHASE_1EDGE, + .NSS = LL_SPI_NSS_SOFT, + .BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV2, + .BitOrder = LL_SPI_MSB_FIRST, + .CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE, + .CRCPoly = 7, +}; + +/** + * SD Card in slow mode (before init) + */ +const LL_SPI_InitTypeDef furi_hal_spi_config_sd_slow = { + .Mode = LL_SPI_MODE_MASTER, + .TransferDirection = LL_SPI_FULL_DUPLEX, + .DataWidth = LL_SPI_DATAWIDTH_8BIT, + .ClockPolarity = LL_SPI_POLARITY_LOW, + .ClockPhase = LL_SPI_PHASE_1EDGE, + .NSS = LL_SPI_NSS_SOFT, + .BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV32, + .BitOrder = LL_SPI_MSB_FIRST, + .CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE, + .CRCPoly = 7, +}; + +osMutexId_t spi_mutex_d = NULL; +osMutexId_t spi_mutex_r = NULL; + +const FuriHalSpiBus spi_r = { + .spi=SPI_R, + .mutex=&spi_mutex_r, + .miso=&gpio_spi_r_miso, + .mosi=&gpio_spi_r_mosi, + .clk=&gpio_spi_r_sck, +}; + +const FuriHalSpiBus spi_d = { + .spi=SPI_D, + .mutex=&spi_mutex_d, + .miso=&gpio_spi_d_miso, + .mosi=&gpio_spi_d_mosi, + .clk=&gpio_spi_d_sck, +}; + +const FuriHalSpiDevice furi_hal_spi_devices[FuriHalSpiDeviceIdMax] = { + { .bus=&spi_r, .config=&furi_hal_spi_config_subghz, .chip_select=&gpio_subghz_cs, }, + { .bus=&spi_d, .config=&furi_hal_spi_config_display, .chip_select=&gpio_display_cs, }, + { .bus=&spi_d, .config=&furi_hal_spi_config_sd_fast, .chip_select=&gpio_sdcard_cs, }, + { .bus=&spi_d, .config=&furi_hal_spi_config_sd_slow, .chip_select=&gpio_sdcard_cs, }, + { .bus=&spi_r, .config=&furi_hal_spi_config_nfc, .chip_select=&gpio_nfc_cs }, +}; diff --git a/firmware/targets/f7/furi-hal/furi-hal-spi-config.h b/firmware/targets/f7/furi-hal/furi-hal-spi-config.h new file mode 100644 index 00000000..3398474a --- /dev/null +++ b/firmware/targets/f7/furi-hal/furi-hal-spi-config.h @@ -0,0 +1,63 @@ +#pragma once + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern const LL_SPI_InitTypeDef furi_hal_spi_config_nfc; +extern const LL_SPI_InitTypeDef furi_hal_spi_config_subghz; +extern const LL_SPI_InitTypeDef furi_hal_spi_config_display; +extern const LL_SPI_InitTypeDef furi_hal_spi_config_sd_fast; +extern const LL_SPI_InitTypeDef furi_hal_spi_config_sd_slow; + +/** FURI HAL SPI BUS handler + * Structure content may change at some point + */ +typedef struct { + const SPI_TypeDef* spi; + const osMutexId_t* mutex; + const GpioPin* miso; + const GpioPin* mosi; + const GpioPin* clk; +} FuriHalSpiBus; + +/** FURI HAL SPI Device handler + * Structure content may change at some point + */ +typedef struct { + const FuriHalSpiBus* bus; + const LL_SPI_InitTypeDef* config; + const GpioPin* chip_select; +} FuriHalSpiDevice; + +/** FURI HAL SPI Standard Device IDs */ +typedef enum { + FuriHalSpiDeviceIdSubGhz, /** SubGhz: CC1101, non-standard SPI usage */ + FuriHalSpiDeviceIdDisplay, /** Display: ERC12864, only have MOSI */ + FuriHalSpiDeviceIdSdCardFast, /** SDCARD: fast mode, after initialization */ + FuriHalSpiDeviceIdSdCardSlow, /** SDCARD: slow mode, before initialization */ + FuriHalSpiDeviceIdNfc, /** NFC: ST25R3916, pretty standard, but RFAL makes it complex */ + + FuriHalSpiDeviceIdMax, /** Service Value, do not use */ +} FuriHalSpiDeviceId; + +/** Furi Hal Spi Bus R + * CC1101, Nfc + */ +extern const FuriHalSpiBus spi_r; + +/** Furi Hal Spi Bus D + * Display, SdCard + */ +extern const FuriHalSpiBus spi_d; + +/** Furi Hal Spi devices */ +extern const FuriHalSpiDevice furi_hal_spi_devices[FuriHalSpiDeviceIdMax]; + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/firmware/targets/f7/furi-hal/furi-hal-spi.c b/firmware/targets/f7/furi-hal/furi-hal-spi.c new file mode 100644 index 00000000..c925abee --- /dev/null +++ b/firmware/targets/f7/furi-hal/furi-hal-spi.c @@ -0,0 +1,200 @@ +#include "furi-hal-spi.h" +#include "furi-hal-resources.h" + +#include +#include +#include + +#include +#include +#include + +void furi_hal_spi_init() { + // Spi structure is const, but mutex is not + // Need some hell-ish casting to make it work + *(osMutexId_t*)spi_r.mutex = osMutexNew(NULL); + *(osMutexId_t*)spi_d.mutex = osMutexNew(NULL); + // + for (size_t i=0; imutex, osWaitForever) == osOK); +} + +void furi_hal_spi_bus_unlock(const FuriHalSpiBus* bus) { + furi_assert(bus); + furi_check(osMutexRelease(*bus->mutex) == osOK); +} + +void furi_hal_spi_bus_configure(const FuriHalSpiBus* bus, const LL_SPI_InitTypeDef* config) { + furi_assert(bus); + + LL_SPI_DeInit((SPI_TypeDef*)bus->spi); + LL_SPI_Init((SPI_TypeDef*)bus->spi, (LL_SPI_InitTypeDef*)config); + LL_SPI_SetRxFIFOThreshold((SPI_TypeDef*)bus->spi, LL_SPI_RX_FIFO_TH_QUARTER); + LL_SPI_Enable((SPI_TypeDef*)bus->spi); +} + +void furi_hal_spi_bus_end_txrx(const FuriHalSpiBus* bus, uint32_t timeout) { + while(LL_SPI_GetTxFIFOLevel((SPI_TypeDef *)bus->spi) != LL_SPI_TX_FIFO_EMPTY); + while(LL_SPI_IsActiveFlag_BSY((SPI_TypeDef *)bus->spi)); + while(LL_SPI_GetRxFIFOLevel((SPI_TypeDef *)bus->spi) != LL_SPI_RX_FIFO_EMPTY) { + LL_SPI_ReceiveData8((SPI_TypeDef *)bus->spi); + } +} + +bool furi_hal_spi_bus_rx(const FuriHalSpiBus* bus, uint8_t* buffer, size_t size, uint32_t timeout) { + furi_assert(bus); + furi_assert(buffer); + furi_assert(size > 0); + + return furi_hal_spi_bus_trx(bus, buffer, buffer, size, timeout); +} + +bool furi_hal_spi_bus_tx(const FuriHalSpiBus* bus, uint8_t* buffer, size_t size, uint32_t timeout) { + furi_assert(bus); + furi_assert(buffer); + furi_assert(size > 0); + bool ret = true; + + while(size > 0) { + if (LL_SPI_IsActiveFlag_TXE((SPI_TypeDef *)bus->spi)) { + LL_SPI_TransmitData8((SPI_TypeDef *)bus->spi, *buffer); + buffer++; + size--; + } + } + + furi_hal_spi_bus_end_txrx(bus, timeout); + LL_SPI_ClearFlag_OVR((SPI_TypeDef *)bus->spi); + + return ret; +} + +bool furi_hal_spi_bus_trx(const FuriHalSpiBus* bus, uint8_t* tx_buffer, uint8_t* rx_buffer, size_t size, uint32_t timeout) { + furi_assert(bus); + furi_assert(tx_buffer); + furi_assert(rx_buffer); + furi_assert(size > 0); + + bool ret = true; + size_t tx_size = size; + bool tx_allowed = true; + + while(size > 0) { + if(tx_size > 0 && LL_SPI_IsActiveFlag_TXE((SPI_TypeDef *)bus->spi) && tx_allowed) { + LL_SPI_TransmitData8((SPI_TypeDef *)bus->spi, *tx_buffer); + tx_buffer++; + tx_size--; + tx_allowed = false; + } + + if(LL_SPI_IsActiveFlag_RXNE((SPI_TypeDef *)bus->spi)) { + *rx_buffer = LL_SPI_ReceiveData8((SPI_TypeDef *)bus->spi); + rx_buffer++; + size--; + tx_allowed = true; + } + } + + furi_hal_spi_bus_end_txrx(bus, timeout); + + return ret; +} + +void furi_hal_spi_device_configure(const FuriHalSpiDevice* device) { + furi_assert(device); + furi_assert(device->config); + + furi_hal_spi_bus_configure(device->bus, device->config); +} + +const FuriHalSpiDevice* furi_hal_spi_device_get(FuriHalSpiDeviceId device_id) { + furi_assert(device_id < FuriHalSpiDeviceIdMax); + + const FuriHalSpiDevice* device = &furi_hal_spi_devices[device_id]; + assert(device); + furi_hal_spi_bus_lock(device->bus); + furi_hal_spi_device_configure(device); + + return device; +} + +void furi_hal_spi_device_return(const FuriHalSpiDevice* device) { + furi_hal_spi_bus_unlock(device->bus); +} + +bool furi_hal_spi_device_rx(const FuriHalSpiDevice* device, uint8_t* buffer, size_t size, uint32_t timeout) { + furi_assert(device); + furi_assert(buffer); + furi_assert(size > 0); + + if (device->chip_select) { + hal_gpio_write(device->chip_select, false); + } + + bool ret = furi_hal_spi_bus_rx(device->bus, buffer, size, timeout); + + if (device->chip_select) { + hal_gpio_write(device->chip_select, true); + } + + return ret; +} + +bool furi_hal_spi_device_tx(const FuriHalSpiDevice* device, uint8_t* buffer, size_t size, uint32_t timeout) { + furi_assert(device); + furi_assert(buffer); + furi_assert(size > 0); + + if (device->chip_select) { + hal_gpio_write(device->chip_select, false); + } + + bool ret = furi_hal_spi_bus_tx(device->bus, buffer, size, timeout); + + if (device->chip_select) { + hal_gpio_write(device->chip_select, true); + } + + return ret; +} + +bool furi_hal_spi_device_trx(const FuriHalSpiDevice* device, uint8_t* tx_buffer, uint8_t* rx_buffer, size_t size, uint32_t timeout) { + furi_assert(device); + furi_assert(tx_buffer); + furi_assert(rx_buffer); + furi_assert(size > 0); + + if (device->chip_select) { + hal_gpio_write(device->chip_select, false); + } + + bool ret = furi_hal_spi_bus_trx(device->bus, tx_buffer, rx_buffer, size, timeout); + + if (device->chip_select) { + hal_gpio_write(device->chip_select, true); + } + + return ret; +} diff --git a/firmware/targets/f7/furi-hal/furi-hal-spi.h b/firmware/targets/f7/furi-hal/furi-hal-spi.h new file mode 100644 index 00000000..638e713a --- /dev/null +++ b/firmware/targets/f7/furi-hal/furi-hal-spi.h @@ -0,0 +1,108 @@ +#pragma once +#include "main.h" +#include "furi-hal-spi-config.h" +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Init SPI API + */ +void furi_hal_spi_init(); + +/* Bus Level API */ + +/** Lock SPI bus + * Takes bus mutex, if used + */ +void furi_hal_spi_bus_lock(const FuriHalSpiBus* bus); + +/** Unlock SPI bus + * Releases BUS mutex, if used + */ +void furi_hal_spi_bus_unlock(const FuriHalSpiBus* bus); + +/** + * Configure SPI bus + * @param bus - spi bus handler + * @param config - spi configuration structure + */ +void furi_hal_spi_bus_configure(const FuriHalSpiBus* bus, const LL_SPI_InitTypeDef* config); + +/** SPI Receive + * @param bus - spi bus handler + * @param buffer - receive buffer + * @param size - transaction size + * @param timeout - bus operation timeout in ms + */ +bool furi_hal_spi_bus_rx(const FuriHalSpiBus* bus, uint8_t* buffer, size_t size, uint32_t timeout); + +/** SPI Transmit + * @param bus - spi bus handler + * @param buffer - transmit buffer + * @param size - transaction size + * @param timeout - bus operation timeout in ms + */ +bool furi_hal_spi_bus_tx(const FuriHalSpiBus* bus, uint8_t* buffer, size_t size, uint32_t timeout); + +/** SPI Transmit and Receive + * @param bus - spi bus handlere + * @param tx_buffer - device handle + * @param rx_buffer - device handle + * @param size - transaction size + * @param timeout - bus operation timeout in ms + */ +bool furi_hal_spi_bus_trx(const FuriHalSpiBus* bus, uint8_t* tx_buffer, uint8_t* rx_buffer, size_t size, uint32_t timeout); + +/* Device Level API */ + +/** Reconfigure SPI bus for device + * @param device - device description + */ +void furi_hal_spi_device_configure(const FuriHalSpiDevice* device); + +/** Get Device handle + * And lock access to the corresponding SPI BUS + * @param device_id - device identifier + * @return device handle + */ +const FuriHalSpiDevice* furi_hal_spi_device_get(FuriHalSpiDeviceId device_id); + +/** Return Device handle + * And unlock access to the corresponding SPI BUS + * @param device - device handle + */ +void furi_hal_spi_device_return(const FuriHalSpiDevice* device); + +/** SPI Recieve + * @param device - device handle + * @param buffer - receive buffer + * @param size - transaction size + * @param timeout - bus operation timeout in ms + */ +bool furi_hal_spi_device_rx(const FuriHalSpiDevice* device, uint8_t* buffer, size_t size, uint32_t timeout); + +/** SPI Transmit + * @param device - device handle + * @param buffer - transmit buffer + * @param size - transaction size + * @param timeout - bus operation timeout in ms + */ +bool furi_hal_spi_device_tx(const FuriHalSpiDevice* device, uint8_t* buffer, size_t size, uint32_t timeout); + +/** SPI Transmit and Receive + * @param device - device handle + * @param tx_buffer - device handle + * @param rx_buffer - device handle + * @param size - transaction size + * @param timeout - bus operation timeout in ms + */ +bool furi_hal_spi_device_trx(const FuriHalSpiDevice* device, uint8_t* tx_buffer, uint8_t* rx_buffer, size_t size, uint32_t timeout); + + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/firmware/targets/f7/furi-hal/furi-hal-subghz.c b/firmware/targets/f7/furi-hal/furi-hal-subghz.c new file mode 100644 index 00000000..679eea74 --- /dev/null +++ b/firmware/targets/f7/furi-hal/furi-hal-subghz.c @@ -0,0 +1,714 @@ +#include "furi-hal-subghz.h" + +#include +#include +#include +#include + +#include +#include +#include + +static volatile SubGhzState furi_hal_subghz_state = SubGhzStateInit; + +static const uint8_t furi_hal_subghz_preset_ook_270khz_async_regs[][2] = { + // https://e2e.ti.com/support/wireless-connectivity/sub-1-ghz-group/sub-1-ghz/f/sub-1-ghz-forum/382066/cc1101---don-t-know-the-correct-registers-configuration + + /* GPIO GD0 */ + { CC1101_IOCFG0, 0x0D }, // GD0 as async serial data output/input + + /* FIFO and internals */ + { CC1101_FIFOTHR, 0x47 }, // The only important bit is ADC_RETENTION, FIFO Tx=33 Rx=32 + + /* Packet engine */ + { CC1101_PKTCTRL0, 0x32 }, // Async, continious, no whitening + + /* Frequency Synthesizer Control */ + { CC1101_FSCTRL1, 0x06 }, // IF = (26*10^6) / (2^10) * 0x06 = 152343.75Hz + + // Modem Configuration + { CC1101_MDMCFG0, 0x00 }, // Channel spacing is 25kHz + { CC1101_MDMCFG1, 0x00 }, // Channel spacing is 25kHz + { CC1101_MDMCFG2, 0x30 }, // Format ASK/OOK, No preamble/sync + { CC1101_MDMCFG3, 0x32 }, // Data rate is 3.79372 kBaud + { CC1101_MDMCFG4, 0x67 }, // Rx BW filter is 270.833333kHz + + /* Main Radio Control State Machine */ + { CC1101_MCSM0, 0x18 }, // Autocalibrate on idle-to-rx/tx, PO_TIMEOUT is 64 cycles(149-155us) + + /* Frequency Offset Compensation Configuration */ + { CC1101_FOCCFG, 0x18 }, // no frequency offset compensation, POST_K same as PRE_K, PRE_K is 4K, GATE is off + + /* Automatic Gain Control */ + { CC1101_AGCTRL0, 0x40 }, // 01 - Low hysteresis, small asymmetric dead zone, medium gain; 00 - 8 samples agc; 00 - Normal AGC, 00 - 4dB boundary + { CC1101_AGCTRL1, 0x00 }, // 0; 0 - LNA 2 gain is decreased to minimum before decreasing LNA gain; 00 - Relative carrier sense threshold disabled; 0000 - RSSI to MAIN_TARGET + { CC1101_AGCTRL2, 0x03 }, // 00 - DVGA all; 000 - MAX LNA+LNA2; 011 - MAIN_TARGET 24 dB + + /* Wake on radio and timeouts control */ + { CC1101_WORCTRL, 0xFB }, // WOR_RES is 2^15 periods (0.91 - 0.94 s) 16.5 - 17.2 hours + + /* Frontend configuration */ + { CC1101_FREND0, 0x11 }, // Adjusts current TX LO buffer + high is PATABLE[1] + { CC1101_FREND1, 0xB6 }, // + + /* Frequency Synthesizer Calibration, valid for 433.92 */ + { CC1101_FSCAL3, 0xE9 }, + { CC1101_FSCAL2, 0x2A }, + { CC1101_FSCAL1, 0x00 }, + { CC1101_FSCAL0, 0x1F }, + + /* Magic f4ckery */ + { CC1101_TEST2, 0x81 }, // FIFOTHR ADC_RETENTION=1 matched value + { CC1101_TEST1, 0x35 }, // FIFOTHR ADC_RETENTION=1 matched value + { CC1101_TEST0, 0x09 }, // VCO selection calibration stage is disabled + + /* End */ + { 0, 0 }, +}; + +static const uint8_t furi_hal_subghz_preset_ook_650khz_async_regs[][2] = { + // https://e2e.ti.com/support/wireless-connectivity/sub-1-ghz-group/sub-1-ghz/f/sub-1-ghz-forum/382066/cc1101---don-t-know-the-correct-registers-configuration + + /* GPIO GD0 */ + { CC1101_IOCFG0, 0x0D }, // GD0 as async serial data output/input + + /* FIFO and internals */ + { CC1101_FIFOTHR, 0x07 }, // The only important bit is ADC_RETENTION + + /* Packet engine */ + { CC1101_PKTCTRL0, 0x32 }, // Async, continious, no whitening + + /* Frequency Synthesizer Control */ + { CC1101_FSCTRL1, 0x06 }, // IF = (26*10^6) / (2^10) * 0x06 = 152343.75Hz + + // Modem Configuration + { CC1101_MDMCFG0, 0x00 }, // Channel spacing is 25kHz + { CC1101_MDMCFG1, 0x00 }, // Channel spacing is 25kHz + { CC1101_MDMCFG2, 0x30 }, // Format ASK/OOK, No preamble/sync + { CC1101_MDMCFG3, 0x32 }, // Data rate is 3.79372 kBaud + { CC1101_MDMCFG4, 0x17 }, // Rx BW filter is 650.000kHz + + /* Main Radio Control State Machine */ + { CC1101_MCSM0, 0x18 }, // Autocalibrate on idle-to-rx/tx, PO_TIMEOUT is 64 cycles(149-155us) + + /* Frequency Offset Compensation Configuration */ + { CC1101_FOCCFG, 0x18 }, // no frequency offset compensation, POST_K same as PRE_K, PRE_K is 4K, GATE is off + + /* Automatic Gain Control */ + { CC1101_AGCTRL0, 0x40 }, // 01 - Low hysteresis, small asymmetric dead zone, medium gain; 00 - 8 samples agc; 00 - Normal AGC, 00 - 4dB boundary + { CC1101_AGCTRL1, 0x00 }, // 0; 0 - LNA 2 gain is decreased to minimum before decreasing LNA gain; 00 - Relative carrier sense threshold disabled; 0000 - RSSI to MAIN_TARGET + { CC1101_AGCTRL2, 0x03 }, // 00 - DVGA all; 000 - MAX LNA+LNA2; 011 - MAIN_TARGET 24 dB + + /* Wake on radio and timeouts control */ + { CC1101_WORCTRL, 0xFB }, // WOR_RES is 2^15 periods (0.91 - 0.94 s) 16.5 - 17.2 hours + + /* Frontend configuration */ + { CC1101_FREND0, 0x11 }, // Adjusts current TX LO buffer + high is PATABLE[1] + { CC1101_FREND1, 0xB6 }, // + + /* Frequency Synthesizer Calibration, valid for 433.92 */ + { CC1101_FSCAL3, 0xE9 }, + { CC1101_FSCAL2, 0x2A }, + { CC1101_FSCAL1, 0x00 }, + { CC1101_FSCAL0, 0x1F }, + + /* Magic f4ckery */ + { CC1101_TEST2, 0x88 }, + { CC1101_TEST1, 0x31 }, + { CC1101_TEST0, 0x09 }, // VCO selection calibration stage is disabled + + /* End */ + { 0, 0 }, +}; +static const uint8_t furi_hal_subghz_preset_2fsk_async_regs[][2] = { + // https://e2e.ti.com/support/wireless-connectivity/sub-1-ghz-group/sub-1-ghz/f/sub-1-ghz-forum/382066/cc1101---don-t-know-the-correct-registers-configuration + + /* GPIO GD0 */ + { CC1101_IOCFG0, 0x0D }, // GD0 as async serial data output/input + + /* FIFO and internals */ + { CC1101_FIFOTHR, 0x47 }, // The only important bit is ADC_RETENTION + + /* Packet engine */ + { CC1101_PKTCTRL0, 0x32 }, // Async, continious, no whitening + + /* Frequency Synthesizer Control */ + { CC1101_FSCTRL1, 0x06 }, // IF = (26*10^6) / (2^10) * 0x06 = 152343.75Hz + + // Modem Configuration + { CC1101_MDMCFG0, 0xF8 }, + { CC1101_MDMCFG1, 0x00 }, // No preamble/sync + { CC1101_MDMCFG2, 0x80 }, // Format 2-FSK/FM, No preamble/sync, Disable (current optimized) + { CC1101_MDMCFG3, 0x83 }, // Data rate is 9.59587 kBaud + { CC1101_MDMCFG4, 0x88 }, // Rx BW filter is 203.125000kHz + + { CC1101_DEVIATN, 0x14}, //Deviation 4.760742 khz + + /* Main Radio Control State Machine */ + { CC1101_MCSM0, 0x18 }, // Autocalibrate on idle-to-rx/tx, PO_TIMEOUT is 64 cycles(149-155us) + + /* Frequency Offset Compensation Configuration */ + { CC1101_FOCCFG, 0x18 }, // no frequency offset compensation, POST_K same as PRE_K, PRE_K is 4K, GATE is off + + /* Automatic Gain Control */ + { CC1101_AGCTRL0, 0x40 }, // 01 - Low hysteresis, small asymmetric dead zone, medium gain; 00 - 8 samples agc; 00 - Normal AGC, 00 - 4dB boundary + { CC1101_AGCTRL1, 0x00 }, // 0; 0 - LNA 2 gain is decreased to minimum before decreasing LNA gain; 00 - Relative carrier sense threshold disabled; 0000 - RSSI to MAIN_TARGET + { CC1101_AGCTRL2, 0x03 }, // 00 - DVGA all; 000 - MAX LNA+LNA2; 011 - MAIN_TARGET 24 dB + + /* Wake on radio and timeouts control */ + { CC1101_WORCTRL, 0xFB }, // WOR_RES is 2^15 periods (0.91 - 0.94 s) 16.5 - 17.2 hours + + /* Frontend configuration */ + { CC1101_FREND0, 0x10 }, // Adjusts current TX LO buffer + { CC1101_FREND1, 0xB6 }, // + + /* Frequency Synthesizer Calibration, valid for 433.92 */ + { CC1101_FSCAL3, 0xE9 }, + { CC1101_FSCAL2, 0x2A }, + { CC1101_FSCAL1, 0x00 }, + { CC1101_FSCAL0, 0x1F }, + + /* Magic f4ckery */ + { CC1101_TEST2, 0x81 }, // FIFOTHR ADC_RETENTION=1 matched value + { CC1101_TEST1, 0x35 }, // FIFOTHR ADC_RETENTION=1 matched value + { CC1101_TEST0, 0x09 }, // VCO selection calibration stage is disabled + + /* End */ + { 0, 0 }, +}; +static const uint8_t furi_hal_subghz_preset_ook_async_patable[8] = { + 0x00, + 0xC0, // 10dBm 0xC0, 7dBm 0xC8, 5dBm 0x84, 0dBm 0x60, -10dBm 0x34, -15dBm 0x1D, -20dBm 0x0E, -30dBm 0x12 + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00 +}; +static const uint8_t furi_hal_subghz_preset_2fsk_async_patable[8] = { + 0xC0, // 10dBm 0xC0, 7dBm 0xC8, 5dBm 0x84, 0dBm 0x60, -10dBm 0x34, -15dBm 0x1D, -20dBm 0x0E, -30dBm 0x12 + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00 +}; + +void furi_hal_subghz_init() { + furi_assert(furi_hal_subghz_state == SubGhzStateInit); + furi_hal_subghz_state = SubGhzStateIdle; + + const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz); + +#ifdef FURI_HAL_SUBGHZ_TX_GPIO + hal_gpio_init(&FURI_HAL_SUBGHZ_TX_GPIO, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); +#endif + + // Reset + hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow); + cc1101_reset(device); + cc1101_write_reg(device, CC1101_IOCFG0, CC1101IocfgHighImpedance); + + // Prepare GD0 for power on self test + hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); + + // GD0 low + cc1101_write_reg(device, CC1101_IOCFG0, CC1101IocfgHW); + while(hal_gpio_read(&gpio_cc1101_g0) != false); + + // GD0 high + cc1101_write_reg(device, CC1101_IOCFG0, CC1101IocfgHW | CC1101_IOCFG_INV); + while(hal_gpio_read(&gpio_cc1101_g0) != true); + + // Reset GD0 to floating state + cc1101_write_reg(device, CC1101_IOCFG0, CC1101IocfgHighImpedance); + hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow); + + // RF switches + hal_gpio_init(&gpio_rf_sw_0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); + cc1101_write_reg(device, CC1101_IOCFG2, CC1101IocfgHW); + + // Go to sleep + cc1101_shutdown(device); + + furi_hal_spi_device_return(device); + FURI_LOG_I("FuriHalSubGhz", "Init OK"); +} + +void furi_hal_subghz_sleep() { + furi_assert(furi_hal_subghz_state == SubGhzStateIdle); + const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz); + + cc1101_switch_to_idle(device); + + cc1101_write_reg(device, CC1101_IOCFG0, CC1101IocfgHighImpedance); + hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow); + + cc1101_shutdown(device); + + furi_hal_spi_device_return(device); +} + +void furi_hal_subghz_dump_state() { + const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz); + printf( + "[furi_hal_subghz] cc1101 chip %d, version %d\r\n", + cc1101_get_partnumber(device), + cc1101_get_version(device) + ); + furi_hal_spi_device_return(device); +} + +void furi_hal_subghz_load_preset(FuriHalSubGhzPreset preset) { + if(preset == FuriHalSubGhzPresetOok650Async) { + furi_hal_subghz_load_registers(furi_hal_subghz_preset_ook_650khz_async_regs); + furi_hal_subghz_load_patable(furi_hal_subghz_preset_ook_async_patable); + } else if(preset == FuriHalSubGhzPresetOok270Async){ + furi_hal_subghz_load_registers(furi_hal_subghz_preset_ook_270khz_async_regs); + furi_hal_subghz_load_patable(furi_hal_subghz_preset_ook_async_patable); + } else if(preset == FuriHalSubGhzPreset2FSKAsync){ + furi_hal_subghz_load_registers(furi_hal_subghz_preset_2fsk_async_regs); + furi_hal_subghz_load_patable(furi_hal_subghz_preset_2fsk_async_patable); + }else { + furi_check(0); + } +} + +uint8_t furi_hal_subghz_get_status() { + const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz); + CC1101StatusRaw st; + st.status = cc1101_get_status(device); + furi_hal_spi_device_return(device); + return st.status_raw; +} + +void furi_hal_subghz_load_registers(const uint8_t data[][2]) { + const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz); + cc1101_reset(device); + uint32_t i = 0; + while (data[i][0]) { + cc1101_write_reg(device, data[i][0], data[i][1]); + i++; + } + furi_hal_spi_device_return(device); +} + +void furi_hal_subghz_load_patable(const uint8_t data[8]) { + const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz); + cc1101_set_pa_table(device, data); + furi_hal_spi_device_return(device); +} + +void furi_hal_subghz_write_packet(const uint8_t* data, uint8_t size) { + const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz); + cc1101_flush_tx(device); + cc1101_write_fifo(device, data, size); + furi_hal_spi_device_return(device); +} + +void furi_hal_subghz_flush_rx() { + const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz); + cc1101_flush_rx(device); + furi_hal_spi_device_return(device); +} + +void furi_hal_subghz_read_packet(uint8_t* data, uint8_t* size) { + const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz); + cc1101_read_fifo(device, data, size); + furi_hal_spi_device_return(device); +} + +void furi_hal_subghz_shutdown() { + const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz); + // Reset and shutdown + cc1101_shutdown(device); + furi_hal_spi_device_return(device); +} + +void furi_hal_subghz_reset() { + const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz); + hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow); + cc1101_switch_to_idle(device); + cc1101_reset(device); + cc1101_write_reg(device, CC1101_IOCFG0, CC1101IocfgHighImpedance); + furi_hal_spi_device_return(device); +} + +void furi_hal_subghz_idle() { + const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz); + cc1101_switch_to_idle(device); + furi_hal_spi_device_return(device); +} + +void furi_hal_subghz_rx() { + const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz); + cc1101_switch_to_rx(device); + furi_hal_spi_device_return(device); +} + +void furi_hal_subghz_tx() { + const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz); + cc1101_switch_to_tx(device); + furi_hal_spi_device_return(device); +} + +float furi_hal_subghz_get_rssi() { + const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz); + int32_t rssi_dec = cc1101_get_rssi(device); + furi_hal_spi_device_return(device); + + float rssi = rssi_dec; + if(rssi_dec >= 128) { + rssi = ((rssi - 256.0f) / 2.0f) - 74.0f; + } else { + rssi = (rssi / 2.0f) - 74.0f; + } + + return rssi; +} + +bool furi_hal_subghz_is_frequency_valid(uint32_t value) { + if(!(value >= 299999755 && value <= 348000335) && + !(value >= 386999938 && value <= 464000000) && + !(value >= 778999847 && value <= 928000000)) { + return false; + } + return true; +} + +uint32_t furi_hal_subghz_set_frequency_and_path(uint32_t value) { + value = furi_hal_subghz_set_frequency(value); + if(value >= 299999755 && value <= 348000335) { + furi_hal_subghz_set_path(FuriHalSubGhzPath315); + } else if(value >= 386999938 && value <= 464000000) { + furi_hal_subghz_set_path(FuriHalSubGhzPath433); + } else if(value >= 778999847 && value <= 928000000) { + furi_hal_subghz_set_path(FuriHalSubGhzPath868); + } else { + furi_check(0); + } + return value; +} + +uint32_t furi_hal_subghz_set_frequency(uint32_t value) { + const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz); + + uint32_t real_frequency = cc1101_set_frequency(device, value); + cc1101_calibrate(device); + + while(true) { + CC1101Status status = cc1101_get_status(device); + if (status.STATE == CC1101StateIDLE) break; + } + + furi_hal_spi_device_return(device); + + return real_frequency; +} + +void furi_hal_subghz_set_path(FuriHalSubGhzPath path) { + const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz); + if (path == FuriHalSubGhzPath433) { + hal_gpio_write(&gpio_rf_sw_0, 0); + cc1101_write_reg(device, CC1101_IOCFG2, CC1101IocfgHW | CC1101_IOCFG_INV); + } else if (path == FuriHalSubGhzPath315) { + hal_gpio_write(&gpio_rf_sw_0, 1); + cc1101_write_reg(device, CC1101_IOCFG2, CC1101IocfgHW); + } else if (path == FuriHalSubGhzPath868) { + hal_gpio_write(&gpio_rf_sw_0, 1); + cc1101_write_reg(device, CC1101_IOCFG2, CC1101IocfgHW | CC1101_IOCFG_INV); + } else if (path == FuriHalSubGhzPathIsolate) { + hal_gpio_write(&gpio_rf_sw_0, 0); + cc1101_write_reg(device, CC1101_IOCFG2, CC1101IocfgHW); + } else { + furi_check(0); + } + furi_hal_spi_device_return(device); +} + +volatile uint32_t furi_hal_subghz_capture_delta_duration = 0; +volatile FuriHalSubGhzCaptureCallback furi_hal_subghz_capture_callback = NULL; +volatile void* furi_hal_subghz_capture_callback_context = NULL; + +static void furi_hal_subghz_capture_ISR() { + // Channel 1 + if(LL_TIM_IsActiveFlag_CC1(TIM2)) { + LL_TIM_ClearFlag_CC1(TIM2); + furi_hal_subghz_capture_delta_duration = LL_TIM_IC_GetCaptureCH1(TIM2); + if (furi_hal_subghz_capture_callback) { + furi_hal_subghz_capture_callback(true, furi_hal_subghz_capture_delta_duration, + (void*)furi_hal_subghz_capture_callback_context + ); + } + } + // Channel 2 + if(LL_TIM_IsActiveFlag_CC2(TIM2)) { + LL_TIM_ClearFlag_CC2(TIM2); + if (furi_hal_subghz_capture_callback) { + furi_hal_subghz_capture_callback(false, LL_TIM_IC_GetCaptureCH2(TIM2) - furi_hal_subghz_capture_delta_duration, + (void*)furi_hal_subghz_capture_callback_context + ); + } + } +} + + +void furi_hal_subghz_start_async_rx(FuriHalSubGhzCaptureCallback callback, void* context) { + furi_assert(furi_hal_subghz_state == SubGhzStateIdle); + furi_hal_subghz_state = SubGhzStateAsyncRx; + + furi_hal_subghz_capture_callback = callback; + furi_hal_subghz_capture_callback_context = context; + + hal_gpio_init_ex(&gpio_cc1101_g0, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedLow, GpioAltFn1TIM2); + + // Timer: base + LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM2); + LL_TIM_InitTypeDef TIM_InitStruct = {0}; + TIM_InitStruct.Prescaler = 64-1; + TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP; + TIM_InitStruct.Autoreload = 0x7FFFFFFE; + TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1; + LL_TIM_Init(TIM2, &TIM_InitStruct); + + // Timer: advanced + LL_TIM_SetClockSource(TIM2, LL_TIM_CLOCKSOURCE_INTERNAL); + LL_TIM_DisableARRPreload(TIM2); + LL_TIM_SetTriggerInput(TIM2, LL_TIM_TS_TI2FP2); + LL_TIM_SetSlaveMode(TIM2, LL_TIM_SLAVEMODE_RESET); + LL_TIM_SetTriggerOutput(TIM2, LL_TIM_TRGO_RESET); + LL_TIM_EnableMasterSlaveMode(TIM2); + LL_TIM_DisableDMAReq_TRIG(TIM2); + LL_TIM_DisableIT_TRIG(TIM2); + + // Timer: channel 1 indirect + LL_TIM_IC_SetActiveInput(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_ACTIVEINPUT_INDIRECTTI); + LL_TIM_IC_SetPrescaler(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_ICPSC_DIV1); + LL_TIM_IC_SetPolarity(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_IC_POLARITY_FALLING); + LL_TIM_IC_SetFilter(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_IC_FILTER_FDIV1); + + // Timer: channel 2 direct + LL_TIM_IC_SetActiveInput(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_ACTIVEINPUT_DIRECTTI); + LL_TIM_IC_SetPrescaler(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_ICPSC_DIV1); + LL_TIM_IC_SetPolarity(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_IC_POLARITY_RISING); + LL_TIM_IC_SetFilter(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_IC_FILTER_FDIV1); + + // ISR setup + furi_hal_interrupt_set_timer_isr(TIM2, furi_hal_subghz_capture_ISR); + NVIC_SetPriority(TIM2_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),5, 0)); + NVIC_EnableIRQ(TIM2_IRQn); + + // Interrupts and channels + LL_TIM_EnableIT_CC1(TIM2); + LL_TIM_EnableIT_CC2(TIM2); + LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH1); + LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH2); + + // Enable NVIC + NVIC_SetPriority(TIM2_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),5, 0)); + NVIC_EnableIRQ(TIM2_IRQn); + + // Start timer + LL_TIM_SetCounter(TIM2, 0); + LL_TIM_EnableCounter(TIM2); + + // Switch to RX + furi_hal_subghz_rx(); +} + +void furi_hal_subghz_stop_async_rx() { + furi_assert(furi_hal_subghz_state == SubGhzStateAsyncRx); + furi_hal_subghz_state = SubGhzStateIdle; + + // Shutdown radio + furi_hal_subghz_idle(); + + LL_TIM_DeInit(TIM2); + LL_APB1_GRP1_DisableClock(LL_APB1_GRP1_PERIPH_TIM2); + furi_hal_interrupt_set_timer_isr(TIM2, NULL); + + hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow); +} + +#define API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL (256) +#define API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF (API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL/2) +#define API_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME 333 + +typedef struct { + uint32_t* buffer; + bool flip_flop; + FuriHalSubGhzAsyncTxCallback callback; + void* callback_context; +} FuriHalSubGhzAsyncTx; + +static FuriHalSubGhzAsyncTx furi_hal_subghz_async_tx = {0}; + +static void furi_hal_subghz_async_tx_refill(uint32_t* buffer, size_t samples) { + while (samples > 0) { + bool is_odd = samples % 2; + LevelDuration ld = furi_hal_subghz_async_tx.callback(furi_hal_subghz_async_tx.callback_context); + if (level_duration_is_reset(ld)) { + // One more even sample required to end at low level + if (is_odd) { + *buffer = API_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME; + buffer++; + samples--; + } + break; + } else { + // Inject guard time if level is incorrect + if (is_odd == level_duration_get_level(ld)) { + *buffer = API_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME; + buffer++; + samples--; + } + + uint32_t duration = level_duration_get_duration(ld); + assert(duration > 0); + *buffer = duration; + buffer++; + samples--; + } + } + + memset(buffer, 0, samples * sizeof(uint32_t)); +} + +static void furi_hal_subghz_async_tx_dma_isr() { + furi_assert(furi_hal_subghz_state == SubGhzStateAsyncTx); + if (LL_DMA_IsActiveFlag_HT1(DMA1)) { + LL_DMA_ClearFlag_HT1(DMA1); + furi_hal_subghz_async_tx_refill(furi_hal_subghz_async_tx.buffer, API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF); + } + if (LL_DMA_IsActiveFlag_TC1(DMA1)) { + LL_DMA_ClearFlag_TC1(DMA1); + furi_hal_subghz_async_tx_refill(furi_hal_subghz_async_tx.buffer+API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF, API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF); + } +} + +static void furi_hal_subghz_async_tx_timer_isr() { + if(LL_TIM_IsActiveFlag_UPDATE(TIM2)) { + LL_TIM_ClearFlag_UPDATE(TIM2); + if (LL_TIM_GetAutoReload(TIM2) == 0) { + if (furi_hal_subghz_state == SubGhzStateAsyncTx) { + furi_hal_subghz_state = SubGhzStateAsyncTxLast; + } else { + furi_hal_subghz_state = SubGhzStateAsyncTxEnd; + LL_TIM_DisableCounter(TIM2); + } + } + } +} + +void furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void* context) { + furi_assert(furi_hal_subghz_state == SubGhzStateIdle); + furi_assert(callback); + + furi_hal_subghz_async_tx.callback = callback; + furi_hal_subghz_async_tx.callback_context = context; + + furi_hal_subghz_state = SubGhzStateAsyncTx; + + furi_hal_subghz_async_tx.buffer = furi_alloc(API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * sizeof(uint32_t)); + furi_hal_subghz_async_tx_refill(furi_hal_subghz_async_tx.buffer, API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL); + + // Connect CC1101_GD0 to TIM2 as output + hal_gpio_init_ex(&gpio_cc1101_g0, GpioModeAltFunctionPushPull, GpioPullDown, GpioSpeedLow, GpioAltFn1TIM2); + + // Configure DMA + LL_DMA_InitTypeDef dma_config = {0}; + dma_config.PeriphOrM2MSrcAddress = (uint32_t)&(TIM2->ARR); + dma_config.MemoryOrM2MDstAddress = (uint32_t)furi_hal_subghz_async_tx.buffer; + dma_config.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; + dma_config.Mode = LL_DMA_MODE_CIRCULAR; + dma_config.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; + dma_config.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; + dma_config.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; + dma_config.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD; + dma_config.NbData = API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL; + dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP; + dma_config.Priority = LL_DMA_MODE_NORMAL; + LL_DMA_Init(DMA1, LL_DMA_CHANNEL_1, &dma_config); + furi_hal_interrupt_set_dma_channel_isr(DMA1, LL_DMA_CHANNEL_1, furi_hal_subghz_async_tx_dma_isr); + LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_1); + LL_DMA_EnableIT_HT(DMA1, LL_DMA_CHANNEL_1); + LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1); + + // Configure TIM2 + LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM2); + LL_TIM_InitTypeDef TIM_InitStruct = {0}; + TIM_InitStruct.Prescaler = 64-1; + TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP; + TIM_InitStruct.Autoreload = 1000; + TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1; + LL_TIM_Init(TIM2, &TIM_InitStruct); + LL_TIM_SetClockSource(TIM2, LL_TIM_CLOCKSOURCE_INTERNAL); + LL_TIM_EnableARRPreload(TIM2); + + // Configure TIM2 CH2 + LL_TIM_OC_InitTypeDef TIM_OC_InitStruct = {0}; + TIM_OC_InitStruct.OCMode = LL_TIM_OCMODE_TOGGLE; + TIM_OC_InitStruct.OCState = LL_TIM_OCSTATE_DISABLE; + TIM_OC_InitStruct.OCNState = LL_TIM_OCSTATE_DISABLE; + TIM_OC_InitStruct.CompareValue = 0; + TIM_OC_InitStruct.OCPolarity = LL_TIM_OCPOLARITY_HIGH; + LL_TIM_OC_Init(TIM2, LL_TIM_CHANNEL_CH2, &TIM_OC_InitStruct); + LL_TIM_OC_DisableFast(TIM2, LL_TIM_CHANNEL_CH2); + LL_TIM_DisableMasterSlaveMode(TIM2); + + furi_hal_interrupt_set_timer_isr(TIM2, furi_hal_subghz_async_tx_timer_isr); + LL_TIM_EnableIT_UPDATE(TIM2); + LL_TIM_EnableDMAReq_UPDATE(TIM2); + LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH2); + + // Start counter + LL_TIM_GenerateEvent_UPDATE(TIM2); +#ifdef FURI_HAL_SUBGHZ_TX_GPIO + hal_gpio_write(&FURI_HAL_SUBGHZ_TX_GPIO, true); +#endif + furi_hal_subghz_tx(); + + // Enable NVIC + NVIC_SetPriority(TIM2_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),5, 0)); + NVIC_EnableIRQ(TIM2_IRQn); + + LL_TIM_SetCounter(TIM2, 0); + LL_TIM_EnableCounter(TIM2); +} + +bool furi_hal_subghz_is_async_tx_complete() { + return furi_hal_subghz_state == SubGhzStateAsyncTxEnd; +} + +void furi_hal_subghz_stop_async_tx() { + furi_assert( + furi_hal_subghz_state == SubGhzStateAsyncTx + || furi_hal_subghz_state == SubGhzStateAsyncTxLast + || furi_hal_subghz_state == SubGhzStateAsyncTxEnd + ); + + // Shutdown radio + furi_hal_subghz_idle(); +#ifdef FURI_HAL_SUBGHZ_TX_GPIO + hal_gpio_write(&FURI_HAL_SUBGHZ_TX_GPIO, false); +#endif + + // Deinitialize Timer + LL_TIM_DeInit(TIM2); + LL_APB1_GRP1_DisableClock(LL_APB1_GRP1_PERIPH_TIM2); + furi_hal_interrupt_set_timer_isr(TIM2, NULL); + + // Deinitialize DMA + LL_DMA_DeInit(DMA1, LL_DMA_CHANNEL_1); + furi_hal_interrupt_set_dma_channel_isr(DMA1, LL_DMA_CHANNEL_1, NULL); + + // Deinitialize GPIO + hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow); + + free(furi_hal_subghz_async_tx.buffer); + + furi_hal_subghz_state = SubGhzStateIdle; +} diff --git a/firmware/targets/f7/furi-hal/furi-hal-task.c b/firmware/targets/f7/furi-hal/furi-hal-task.c new file mode 100644 index 00000000..aca197a4 --- /dev/null +++ b/firmware/targets/f7/furi-hal/furi-hal-task.c @@ -0,0 +1,54 @@ +#include "cmsis_os.h" +#include "furi-hal-task.h" + +//-----------------------------cmsis_os2.c------------------------------- +// helpers to get isr context +// get arch +#ifndef __ARM_ARCH_6M__ +#define __ARM_ARCH_6M__ 0 +#endif +#ifndef __ARM_ARCH_7M__ +#define __ARM_ARCH_7M__ 0 +#endif +#ifndef __ARM_ARCH_7EM__ +#define __ARM_ARCH_7EM__ 0 +#endif +#ifndef __ARM_ARCH_8M_MAIN__ +#define __ARM_ARCH_8M_MAIN__ 0 +#endif +#ifndef __ARM_ARCH_7A__ +#define __ARM_ARCH_7A__ 0 +#endif + +// get masks +#if((__ARM_ARCH_7M__ == 1U) || (__ARM_ARCH_7EM__ == 1U) || (__ARM_ARCH_8M_MAIN__ == 1U)) +#define IS_IRQ_MASKED() ((__get_PRIMASK() != 0U) || (__get_BASEPRI() != 0U)) +#elif(__ARM_ARCH_6M__ == 1U) +#define IS_IRQ_MASKED() (__get_PRIMASK() != 0U) +#elif(__ARM_ARCH_7A__ == 1U) +/* CPSR mask bits */ +#define CPSR_MASKBIT_I 0x80U + +#define IS_IRQ_MASKED() ((__get_CPSR() & CPSR_MASKBIT_I) != 0U) +#else +#define IS_IRQ_MASKED() (__get_PRIMASK() != 0U) +#endif + +// get is irq mode +#if(__ARM_ARCH_7A__ == 1U) +/* CPSR mode bitmasks */ +#define CPSR_MODE_USER 0x10U +#define CPSR_MODE_SYSTEM 0x1FU + +#define IS_IRQ_MODE() ((__get_mode() != CPSR_MODE_USER) && (__get_mode() != CPSR_MODE_SYSTEM)) +#else +#define IS_IRQ_MODE() (__get_IPSR() != 0U) +#endif + +// added osKernelGetState(), because KernelState is a static var +#define IS_IRQ() (IS_IRQ_MODE() || (IS_IRQ_MASKED() && (osKernelGetState() == osKernelRunning))) +//-------------------------end of cmsis_os2.c---------------------------- + +bool task_is_isr_context(void) { + return IS_IRQ(); +} diff --git a/firmware/targets/f7/furi-hal/furi-hal-task.h b/firmware/targets/f7/furi-hal/furi-hal-task.h new file mode 100644 index 00000000..8b157233 --- /dev/null +++ b/firmware/targets/f7/furi-hal/furi-hal-task.h @@ -0,0 +1,12 @@ +#pragma once +#include "main.h" +#include +#include + +// Task stack size in bytes +#define DEFAULT_STACK_SIZE 4096 + +// Max system tasks count +#define MAX_TASK_COUNT 14 + +bool task_is_isr_context(void); diff --git a/firmware/targets/f7/furi-hal/furi-hal-vcp.c b/firmware/targets/f7/furi-hal/furi-hal-vcp.c new file mode 100644 index 00000000..88de32b5 --- /dev/null +++ b/firmware/targets/f7/furi-hal/furi-hal-vcp.c @@ -0,0 +1,128 @@ +#include + +#include +#include +#include + +#define FURI_HAL_VCP_RX_BUFFER_SIZE (APP_RX_DATA_SIZE * 5) + +extern USBD_HandleTypeDef hUsbDeviceFS; + +typedef struct { + volatile bool connected; + + StreamBufferHandle_t rx_stream; + volatile bool rx_stream_full; + + osSemaphoreId_t tx_semaphore; +} FuriHalVcp; + +static FuriHalVcp* furi_hal_vcp = NULL; + +static const uint8_t ascii_soh = 0x01; +static const uint8_t ascii_eot = 0x04; + +void furi_hal_vcp_init() { + furi_hal_vcp = furi_alloc(sizeof(FuriHalVcp)); + furi_hal_vcp->connected = false; + + furi_hal_vcp->rx_stream = xStreamBufferCreate(FURI_HAL_VCP_RX_BUFFER_SIZE, 1); + furi_hal_vcp->rx_stream_full = false; + + furi_hal_vcp->tx_semaphore = osSemaphoreNew(1, 1, NULL); + + FURI_LOG_I("FuriHalVcp", "Init OK"); +} + +size_t furi_hal_vcp_rx(uint8_t* buffer, size_t size) { + furi_assert(furi_hal_vcp); + + size_t received = xStreamBufferReceive(furi_hal_vcp->rx_stream, buffer, size, portMAX_DELAY); + + if(furi_hal_vcp->rx_stream_full + &&xStreamBufferSpacesAvailable(furi_hal_vcp->rx_stream) >= APP_RX_DATA_SIZE) { + furi_hal_vcp->rx_stream_full = false; + // data accepted, start waiting for next packet + USBD_CDC_ReceivePacket(&hUsbDeviceFS); + } + + return received; +} + +size_t furi_hal_vcp_rx_with_timeout(uint8_t* buffer, size_t size, uint32_t timeout) { + furi_assert(furi_hal_vcp); + return xStreamBufferReceive(furi_hal_vcp->rx_stream, buffer, size, timeout); +} + +void furi_hal_vcp_tx(const uint8_t* buffer, size_t size) { + furi_assert(furi_hal_vcp); + + while (size > 0 && furi_hal_vcp->connected) { + furi_check(osSemaphoreAcquire(furi_hal_vcp->tx_semaphore, osWaitForever) == osOK); + if (!furi_hal_vcp->connected) + break; + + size_t batch_size = size; + if (batch_size > APP_TX_DATA_SIZE) { + batch_size = APP_TX_DATA_SIZE; + } + + if (CDC_Transmit_FS((uint8_t*)buffer, batch_size) == USBD_OK) { + size -= batch_size; + buffer += batch_size; + } else { + FURI_LOG_E("FuriHalVcp", "CDC_Transmit_FS failed"); + osDelay(50); + } + } +} + +void furi_hal_vcp_on_usb_resume() { + osSemaphoreRelease(furi_hal_vcp->tx_semaphore); +} + +void furi_hal_vcp_on_usb_suspend() { + if (furi_hal_vcp->connected) { + furi_hal_vcp->connected = false; + osSemaphoreRelease(furi_hal_vcp->tx_semaphore); + } +} + +void furi_hal_vcp_on_cdc_control_line(uint8_t state) { + // bit 0: DTR state, bit 1: RTS state + // bool dtr = state & 0b01; + bool dtr = state & 0b1; + + if (dtr) { + if (!furi_hal_vcp->connected) { + furi_hal_vcp->connected = true; + furi_hal_vcp_on_cdc_rx(&ascii_soh, 1); // SOH + } + } else { + if (furi_hal_vcp->connected) { + furi_hal_vcp_on_cdc_rx(&ascii_eot, 1); // EOT + furi_hal_vcp->connected = false; + } + } + + osSemaphoreRelease(furi_hal_vcp->tx_semaphore); +} + +void furi_hal_vcp_on_cdc_rx(const uint8_t* buffer, size_t size) { + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + size_t ret = xStreamBufferSendFromISR(furi_hal_vcp->rx_stream, buffer, size, &xHigherPriorityTaskWoken); + furi_check(ret == size); + + if (xStreamBufferSpacesAvailable(furi_hal_vcp->rx_stream) >= APP_RX_DATA_SIZE) { + USBD_CDC_ReceivePacket(&hUsbDeviceFS); + } else { + furi_hal_vcp->rx_stream_full = true; + } + + portYIELD_FROM_ISR(xHigherPriorityTaskWoken); +} + +void furi_hal_vcp_on_cdc_tx_complete(size_t size) { + osSemaphoreRelease(furi_hal_vcp->tx_semaphore); +} + diff --git a/firmware/targets/f7/furi-hal/furi-hal-vcp_i.h b/firmware/targets/f7/furi-hal/furi-hal-vcp_i.h new file mode 100644 index 00000000..05ddc6ad --- /dev/null +++ b/firmware/targets/f7/furi-hal/furi-hal-vcp_i.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +void furi_hal_vcp_on_usb_resume(); + +void furi_hal_vcp_on_usb_suspend(); + +void furi_hal_vcp_on_cdc_control_line(uint8_t state); + +void furi_hal_vcp_on_cdc_rx(const uint8_t* buffer, size_t size); + +void furi_hal_vcp_on_cdc_tx_complete(size_t size); diff --git a/firmware/targets/f7/furi-hal/furi-hal-version.c b/firmware/targets/f7/furi-hal/furi-hal-version.c new file mode 100644 index 00000000..d2f50039 --- /dev/null +++ b/firmware/targets/f7/furi-hal/furi-hal-version.c @@ -0,0 +1,242 @@ +#include + +#include +#include +#include + +#include +#include "ble.h" + +#define FURI_HAL_VERSION_OTP_HEADER_MAGIC 0xBABE +#define FURI_HAL_VERSION_NAME_LENGTH 8 +#define FURI_HAL_VERSION_ARRAY_NAME_LENGTH (FURI_HAL_VERSION_NAME_LENGTH + 1) +/** BLE symbol + "Flipper " + name */ +#define FURI_HAL_VERSION_DEVICE_NAME_LENGTH (1 + 8 + FURI_HAL_VERSION_ARRAY_NAME_LENGTH) +#define FURI_HAL_VERSION_OTP_ADDRESS OTP_AREA_BASE + +/** OTP Versions enum */ +typedef enum { + FuriHalVersionOtpVersion0=0x00, + FuriHalVersionOtpVersion1=0x01, + FuriHalVersionOtpVersionEmpty=0xFFFFFFFE, + FuriHalVersionOtpVersionUnknown=0xFFFFFFFF, +} FuriHalVersionOtpVersion; + +/** OTP V0 Structure: prototypes and early EVT */ +typedef struct { + uint8_t board_version; + uint8_t board_target; + uint8_t board_body; + uint8_t board_connect; + uint32_t header_timestamp; + char name[FURI_HAL_VERSION_NAME_LENGTH]; +} FuriHalVersionOTPv0; + +/** OTP V1 Structure: late EVT, DVT, PVT, Production */ +typedef struct { + /* First 64 bits: header */ + uint16_t header_magic; + uint8_t header_version; + uint8_t header_reserved; + uint32_t header_timestamp; + + /* Second 64 bits: board info */ + uint8_t board_version; /** Board version */ + uint8_t board_target; /** Board target firmware */ + uint8_t board_body; /** Board body */ + uint8_t board_connect; /** Board interconnect */ + uint8_t board_color; /** Board color */ + uint8_t board_region; /** Board region */ + uint16_t board_reserved; /** Reserved for future use, 0x0000 */ + + /* Third 64 bits: Unique Device Name */ + char name[FURI_HAL_VERSION_NAME_LENGTH]; /** Unique Device Name */ +} FuriHalVersionOTPv1; + +/** Represenation Model: */ +typedef struct { + FuriHalVersionOtpVersion otp_version; + + uint32_t timestamp; + + uint8_t board_version; /** Board version */ + uint8_t board_target; /** Board target firmware */ + uint8_t board_body; /** Board body */ + uint8_t board_connect; /** Board interconnect */ + uint8_t board_color; /** Board color */ + uint8_t board_region; /** Board region */ + + char name[FURI_HAL_VERSION_ARRAY_NAME_LENGTH]; /** \0 terminated name */ + char device_name[FURI_HAL_VERSION_DEVICE_NAME_LENGTH]; /** device name for special needs */ + uint8_t ble_mac[6]; +} FuriHalVersion; + +static FuriHalVersion furi_hal_version = {0}; + +static FuriHalVersionOtpVersion furi_hal_version_get_otp_version() { + if (*(uint64_t*)FURI_HAL_VERSION_OTP_ADDRESS == 0xFFFFFFFF) { + return FuriHalVersionOtpVersionEmpty; + } else { + if (((FuriHalVersionOTPv1*)FURI_HAL_VERSION_OTP_ADDRESS)->header_magic == FURI_HAL_VERSION_OTP_HEADER_MAGIC) { + return FuriHalVersionOtpVersion1; + } else if (((FuriHalVersionOTPv0*)FURI_HAL_VERSION_OTP_ADDRESS)->board_version <= 10) { + return FuriHalVersionOtpVersion0; + } else { + return FuriHalVersionOtpVersionUnknown; + } + } +} + +static void furi_hal_version_set_name(const char* name) { + if(name != NULL) { + strlcpy(furi_hal_version.name, name, FURI_HAL_VERSION_ARRAY_NAME_LENGTH); + snprintf( + furi_hal_version.device_name, + FURI_HAL_VERSION_DEVICE_NAME_LENGTH, + "xFlipper %s", + furi_hal_version.name); + } else { + snprintf( + furi_hal_version.device_name, + FURI_HAL_VERSION_DEVICE_NAME_LENGTH, + "xFlipper"); + } + + furi_hal_version.device_name[0] = AD_TYPE_COMPLETE_LOCAL_NAME; + + // BLE Mac address + uint32_t udn = LL_FLASH_GetUDN(); + uint32_t company_id = LL_FLASH_GetSTCompanyID(); + uint32_t device_id = LL_FLASH_GetDeviceID(); + furi_hal_version.ble_mac[0] = (uint8_t)(udn & 0x000000FF); + furi_hal_version.ble_mac[1] = (uint8_t)( (udn & 0x0000FF00) >> 8 ); + furi_hal_version.ble_mac[2] = (uint8_t)( (udn & 0x00FF0000) >> 16 ); + furi_hal_version.ble_mac[3] = (uint8_t)device_id; + furi_hal_version.ble_mac[4] = (uint8_t)(company_id & 0x000000FF); + furi_hal_version.ble_mac[5] = (uint8_t)( (company_id & 0x0000FF00) >> 8 ); +} + +static void furi_hal_version_load_otp_default() { + furi_hal_version_set_name(NULL); +} + +static void furi_hal_version_load_otp_v0() { + const FuriHalVersionOTPv0* otp = (FuriHalVersionOTPv0*)FURI_HAL_VERSION_OTP_ADDRESS; + + furi_hal_version.timestamp = otp->header_timestamp; + furi_hal_version.board_version = otp->board_version; + furi_hal_version.board_target = otp->board_target; + furi_hal_version.board_body = otp->board_body; + furi_hal_version.board_connect = otp->board_connect; + furi_hal_version.board_color = 0; + furi_hal_version.board_region = 0; + + furi_hal_version_set_name(otp->name); +} + +static void furi_hal_version_load_otp_v1() { + const FuriHalVersionOTPv1* otp = (FuriHalVersionOTPv1*)FURI_HAL_VERSION_OTP_ADDRESS; + + furi_hal_version.timestamp = otp->header_timestamp; + furi_hal_version.board_version = otp->board_version; + furi_hal_version.board_target = otp->board_target; + furi_hal_version.board_body = otp->board_body; + furi_hal_version.board_connect = otp->board_connect; + furi_hal_version.board_color = otp->board_color; + furi_hal_version.board_region = otp->board_region; + + furi_hal_version_set_name(otp->name); +} + +void furi_hal_version_init() { + furi_hal_version.otp_version = furi_hal_version_get_otp_version(); + switch(furi_hal_version.otp_version) { + case FuriHalVersionOtpVersionUnknown: + furi_hal_version_load_otp_default(); + break; + case FuriHalVersionOtpVersionEmpty: + furi_hal_version_load_otp_default(); + break; + case FuriHalVersionOtpVersion0: + furi_hal_version_load_otp_v0(); + break; + case FuriHalVersionOtpVersion1: + furi_hal_version_load_otp_v1(); + break; + default: furi_check(0); + } + FURI_LOG_I("FuriHalVersion", "Init OK"); +} + +bool furi_hal_version_do_i_belong_here() { + return furi_hal_version_get_hw_target() == 7; +} + +const char* furi_hal_version_get_model_name() { + return "Flipper Zero"; +} + +const uint8_t furi_hal_version_get_hw_version() { + return furi_hal_version.board_version; +} + +const uint8_t furi_hal_version_get_hw_target() { + return furi_hal_version.board_target; +} + +const uint8_t furi_hal_version_get_hw_body() { + return furi_hal_version.board_body; +} + +const FuriHalVersionColor furi_hal_version_get_hw_color() { + return furi_hal_version.board_color; +} + +const uint8_t furi_hal_version_get_hw_connect() { + return furi_hal_version.board_connect; +} + +const FuriHalVersionRegion furi_hal_version_get_hw_region() { + return furi_hal_version.board_region; +} + +const uint32_t furi_hal_version_get_hw_timestamp() { + return furi_hal_version.timestamp; +} + +const char* furi_hal_version_get_name_ptr() { + return *furi_hal_version.name == 0x00 ? NULL : furi_hal_version.name; +} + +const char* furi_hal_version_get_device_name_ptr() { + return furi_hal_version.device_name + 1; +} + +const char* furi_hal_version_get_ble_local_device_name_ptr() { + return furi_hal_version.device_name; +} + +const uint8_t* furi_hal_version_get_ble_mac() { + return furi_hal_version.ble_mac; +} + +const struct Version* furi_hal_version_get_firmware_version(void) { + return version_get(); +} + +const struct Version* furi_hal_version_get_boot_version(void) { +#ifdef NO_BOOTLOADER + return 0; +#else + /* Backup register which points to structure in flash memory */ + return (const struct Version*)LL_RTC_BAK_GetRegister(RTC, LL_RTC_BKP_DR1); +#endif +} + +size_t furi_hal_version_uid_size() { + return 64/8; +} + +const uint8_t* furi_hal_version_uid() { + return (const uint8_t *)UID64_BASE; +} diff --git a/firmware/targets/f7/furi-hal/furi-hal-vibro.c b/firmware/targets/f7/furi-hal/furi-hal-vibro.c new file mode 100644 index 00000000..7dfddd42 --- /dev/null +++ b/firmware/targets/f7/furi-hal/furi-hal-vibro.c @@ -0,0 +1,13 @@ +#include +#include + +void furi_hal_vibro_init() { + hal_gpio_init(&vibro_gpio, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); + hal_gpio_write(&vibro_gpio, false); + FURI_LOG_I("FuriHalVibro", "Init OK"); + +} + +void furi_hal_vibro_on(bool value) { + hal_gpio_write(&vibro_gpio, value); +} diff --git a/firmware/targets/f7/furi-hal/furi-hal.c b/firmware/targets/f7/furi-hal/furi-hal.c new file mode 100644 index 00000000..eebe1423 --- /dev/null +++ b/firmware/targets/f7/furi-hal/furi-hal.c @@ -0,0 +1,65 @@ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void furi_hal_init() { + furi_hal_clock_init(); + furi_hal_console_init(); + furi_hal_interrupt_init(); + furi_hal_delay_init(); + + MX_GPIO_Init(); + FURI_LOG_I("HAL", "GPIO OK"); + + MX_RTC_Init(); + FURI_LOG_I("HAL", "RTC OK"); + furi_hal_boot_init(); + furi_hal_version_init(); + + furi_hal_spi_init(); + + MX_TIM1_Init(); + FURI_LOG_I("HAL", "TIM1 OK"); + MX_TIM2_Init(); + FURI_LOG_I("HAL", "TIM2 OK"); + MX_TIM16_Init(); + FURI_LOG_I("HAL", "TIM16 OK"); + MX_COMP1_Init(); + FURI_LOG_I("HAL", "COMP1 OK"); + MX_RF_Init(); + FURI_LOG_I("HAL", "RF OK"); + MX_PKA_Init(); + FURI_LOG_I("HAL", "PKA OK"); + MX_RNG_Init(); + FURI_LOG_I("HAL", "RNG OK"); + MX_AES1_Init(); + FURI_LOG_I("HAL", "AES1 OK"); + MX_AES2_Init(); + FURI_LOG_I("HAL", "AES2 OK"); + + // VCP + USB + furi_hal_vcp_init(); + MX_USB_Device_Init(); + FURI_LOG_I("HAL", "USB OK"); + + furi_hal_i2c_init(); + + // High Level + furi_hal_power_init(); + furi_hal_light_init(); + furi_hal_vibro_init(); + furi_hal_subghz_init(); + furi_hal_nfc_init(); + furi_hal_rfid_init(); + + // FreeRTOS glue + furi_hal_os_init(); +} diff --git a/firmware/targets/f7/startup_stm32wb55xx_cm4.s b/firmware/targets/f7/startup_stm32wb55xx_cm4.s new file mode 100644 index 00000000..c5c2b3fc --- /dev/null +++ b/firmware/targets/f7/startup_stm32wb55xx_cm4.s @@ -0,0 +1,444 @@ +/** + ****************************************************************************** + * @file startup_stm32wb55xx_cm4.s + * @author MCD Application Team + * @brief STM32WB55xx devices vector table GCC toolchain. + * This module performs: + * - Set the initial SP + * - Set the initial PC == Reset_Handler, + * - Set the vector table entries with the exceptions ISR address + * - Branches to main in the C library (which eventually + * calls main()). + * After Reset the Cortex-M4 processor is in Thread mode, + * priority is Privileged, and the Stack is set to Main. + ****************************************************************************** + * @attention + * + * Copyright (c) 2019-2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + + .syntax unified + .cpu cortex-m4 + .fpu softvfp + .thumb + +.global g_pfnVectors +.global Default_Handler + +/* start address for the initialization values of the .data section. +defined in linker script */ +.word _sidata +/* start address for the .data section. defined in linker script */ +.word _sdata +/* end address for the .data section. defined in linker script */ +.word _edata +/* start address for the .bss section. defined in linker script */ +.word _sbss +/* end address for the .bss section. defined in linker script */ +.word _ebss +/* start address for the .MB_MEM2 section. defined in linker script */ +.word _sMB_MEM2 +/* end address for the .MB_MEM2 section. defined in linker script */ +.word _eMB_MEM2 + +/* INIT_BSS macro is used to fill the specified region [start : end] with zeros */ +.macro INIT_BSS start, end + ldr r0, =\start + ldr r1, =\end + movs r3, #0 + bl LoopFillZerobss +.endm + +/* INIT_DATA macro is used to copy data in the region [start : end] starting from 'src' */ +.macro INIT_DATA start, end, src + ldr r0, =\start + ldr r1, =\end + ldr r2, =\src + movs r3, #0 + bl LoopCopyDataInit +.endm + +.section .text.data_initializers +CopyDataInit: + ldr r4, [r2, r3] + str r4, [r0, r3] + adds r3, r3, #4 + +LoopCopyDataInit: + adds r4, r0, r3 + cmp r4, r1 + bcc CopyDataInit + bx lr + +FillZerobss: + str r3, [r0] + adds r0, r0, #4 + +LoopFillZerobss: + cmp r0, r1 + bcc FillZerobss + bx lr + + .section .text.Reset_Handler + .weak Reset_Handler + .type Reset_Handler, %function +Reset_Handler: + ldr r0, =_estack + mov sp, r0 /* set stack pointer */ +/* Call the clock system intitialization function.*/ + bl SystemInit + +/* Copy the data segment initializers from flash to SRAM */ + INIT_DATA _sdata, _edata, _sidata + +/* Zero fill the bss segments. */ + INIT_BSS _sbss, _ebss + INIT_BSS _sMB_MEM2, _eMB_MEM2 + +/* Call static constructors */ + bl __libc_init_array +/* Call the application s entry point.*/ + bl main + +LoopForever: + b LoopForever + +.size Reset_Handler, .-Reset_Handler + +/** + * @brief This is the code that gets called when the processor receives an + * unexpected interrupt. This simply enters an infinite loop, preserving + * the system state for examination by a debugger. + * + * @param None + * @retval None +*/ + .section .text.Default_Handler,"ax",%progbits +Default_Handler: +Infinite_Loop: + b Infinite_Loop + .size Default_Handler, .-Default_Handler +/****************************************************************************** +* +* The minimal vector table for a Cortex-M4. Note that the proper constructs +* must be placed on this to ensure that it ends up at physical address +* 0x0000.0000. +* +******************************************************************************/ + .section .isr_vector,"a",%progbits + .type g_pfnVectors, %object + .size g_pfnVectors, .-g_pfnVectors + + +g_pfnVectors: + .word _estack + .word Reset_Handler + .word NMI_Handler + .word HardFault_Handler + .word MemManage_Handler + .word BusFault_Handler + .word UsageFault_Handler + .word 0 + .word 0 + .word 0 + .word 0 + .word SVC_Handler + .word DebugMon_Handler + .word 0 + .word PendSV_Handler + .word SysTick_Handler + .word WWDG_IRQHandler + .word PVD_PVM_IRQHandler + .word TAMP_STAMP_LSECSS_IRQHandler + .word RTC_WKUP_IRQHandler + .word FLASH_IRQHandler + .word RCC_IRQHandler + .word EXTI0_IRQHandler + .word EXTI1_IRQHandler + .word EXTI2_IRQHandler + .word EXTI3_IRQHandler + .word EXTI4_IRQHandler + .word DMA1_Channel1_IRQHandler + .word DMA1_Channel2_IRQHandler + .word DMA1_Channel3_IRQHandler + .word DMA1_Channel4_IRQHandler + .word DMA1_Channel5_IRQHandler + .word DMA1_Channel6_IRQHandler + .word DMA1_Channel7_IRQHandler + .word ADC1_IRQHandler + .word USB_HP_IRQHandler + .word USB_LP_IRQHandler + .word C2SEV_PWR_C2H_IRQHandler + .word COMP_IRQHandler + .word EXTI9_5_IRQHandler + .word TIM1_BRK_IRQHandler + .word TIM1_UP_TIM16_IRQHandler + .word TIM1_TRG_COM_TIM17_IRQHandler + .word TIM1_CC_IRQHandler + .word TIM2_IRQHandler + .word PKA_IRQHandler + .word I2C1_EV_IRQHandler + .word I2C1_ER_IRQHandler + .word I2C3_EV_IRQHandler + .word I2C3_ER_IRQHandler + .word SPI1_IRQHandler + .word SPI2_IRQHandler + .word USART1_IRQHandler + .word LPUART1_IRQHandler + .word SAI1_IRQHandler + .word TSC_IRQHandler + .word EXTI15_10_IRQHandler + .word RTC_Alarm_IRQHandler + .word CRS_IRQHandler + .word PWR_SOTF_BLEACT_802ACT_RFPHASE_IRQHandler + .word IPCC_C1_RX_IRQHandler + .word IPCC_C1_TX_IRQHandler + .word HSEM_IRQHandler + .word LPTIM1_IRQHandler + .word LPTIM2_IRQHandler + .word LCD_IRQHandler + .word QUADSPI_IRQHandler + .word AES1_IRQHandler + .word AES2_IRQHandler + .word RNG_IRQHandler + .word FPU_IRQHandler + .word DMA2_Channel1_IRQHandler + .word DMA2_Channel2_IRQHandler + .word DMA2_Channel3_IRQHandler + .word DMA2_Channel4_IRQHandler + .word DMA2_Channel5_IRQHandler + .word DMA2_Channel6_IRQHandler + .word DMA2_Channel7_IRQHandler + .word DMAMUX1_OVR_IRQHandler + +/******************************************************************************* +* +* Provide weak aliases for each Exception handler to the Default_Handler. +* As they are weak aliases, any function with the same name will override +* this definition. +* +*******************************************************************************/ + .weak NMI_Handler + .thumb_set NMI_Handler,Default_Handler + + .weak HardFault_Handler + .thumb_set HardFault_Handler,Default_Handler + + .weak MemManage_Handler + .thumb_set MemManage_Handler,Default_Handler + + .weak BusFault_Handler + .thumb_set BusFault_Handler,Default_Handler + + .weak UsageFault_Handler + .thumb_set UsageFault_Handler,Default_Handler + + .weak SVC_Handler + .thumb_set SVC_Handler,Default_Handler + + .weak DebugMon_Handler + .thumb_set DebugMon_Handler,Default_Handler + + .weak PendSV_Handler + .thumb_set PendSV_Handler,Default_Handler + + .weak SysTick_Handler + .thumb_set SysTick_Handler,Default_Handler + + .weak WWDG_IRQHandler + .thumb_set WWDG_IRQHandler,Default_Handler + + .weak PVD_PVM_IRQHandler + .thumb_set PVD_PVM_IRQHandler,Default_Handler + + .weak TAMP_STAMP_LSECSS_IRQHandler + .thumb_set TAMP_STAMP_LSECSS_IRQHandler,Default_Handler + + .weak RTC_WKUP_IRQHandler + .thumb_set RTC_WKUP_IRQHandler,Default_Handler + + .weak FLASH_IRQHandler + .thumb_set FLASH_IRQHandler,Default_Handler + + .weak RCC_IRQHandler + .thumb_set RCC_IRQHandler,Default_Handler + + .weak EXTI0_IRQHandler + .thumb_set EXTI0_IRQHandler,Default_Handler + + .weak EXTI1_IRQHandler + .thumb_set EXTI1_IRQHandler,Default_Handler + + .weak EXTI2_IRQHandler + .thumb_set EXTI2_IRQHandler,Default_Handler + + .weak EXTI3_IRQHandler + .thumb_set EXTI3_IRQHandler,Default_Handler + + .weak EXTI4_IRQHandler + .thumb_set EXTI4_IRQHandler,Default_Handler + + .weak DMA1_Channel1_IRQHandler + .thumb_set DMA1_Channel1_IRQHandler,Default_Handler + + .weak DMA1_Channel2_IRQHandler + .thumb_set DMA1_Channel2_IRQHandler,Default_Handler + + .weak DMA1_Channel3_IRQHandler + .thumb_set DMA1_Channel3_IRQHandler,Default_Handler + + .weak DMA1_Channel4_IRQHandler + .thumb_set DMA1_Channel4_IRQHandler,Default_Handler + + .weak DMA1_Channel5_IRQHandler + .thumb_set DMA1_Channel5_IRQHandler,Default_Handler + + .weak DMA1_Channel6_IRQHandler + .thumb_set DMA1_Channel6_IRQHandler,Default_Handler + + .weak DMA1_Channel7_IRQHandler + .thumb_set DMA1_Channel7_IRQHandler,Default_Handler + + .weak ADC1_IRQHandler + .thumb_set ADC1_IRQHandler,Default_Handler + + .weak USB_HP_IRQHandler + .thumb_set USB_HP_IRQHandler,Default_Handler + + .weak USB_LP_IRQHandler + .thumb_set USB_LP_IRQHandler,Default_Handler + + .weak C2SEV_PWR_C2H_IRQHandler + .thumb_set C2SEV_PWR_C2H_IRQHandler,Default_Handler + + .weak COMP_IRQHandler + .thumb_set COMP_IRQHandler,Default_Handler + + .weak EXTI9_5_IRQHandler + .thumb_set EXTI9_5_IRQHandler,Default_Handler + + .weak TIM1_BRK_IRQHandler + .thumb_set TIM1_BRK_IRQHandler,Default_Handler + + .weak TIM1_UP_TIM16_IRQHandler + .thumb_set TIM1_UP_TIM16_IRQHandler,Default_Handler + + .weak TIM1_TRG_COM_TIM17_IRQHandler + .thumb_set TIM1_TRG_COM_TIM17_IRQHandler,Default_Handler + + .weak TIM1_CC_IRQHandler + .thumb_set TIM1_CC_IRQHandler,Default_Handler + + .weak TIM2_IRQHandler + .thumb_set TIM2_IRQHandler,Default_Handler + + .weak PKA_IRQHandler + .thumb_set PKA_IRQHandler,Default_Handler + + .weak I2C1_EV_IRQHandler + .thumb_set I2C1_EV_IRQHandler,Default_Handler + + .weak I2C1_ER_IRQHandler + .thumb_set I2C1_ER_IRQHandler,Default_Handler + + .weak I2C3_EV_IRQHandler + .thumb_set I2C3_EV_IRQHandler,Default_Handler + + .weak I2C3_ER_IRQHandler + .thumb_set I2C3_ER_IRQHandler,Default_Handler + + .weak SPI1_IRQHandler + .thumb_set SPI1_IRQHandler,Default_Handler + + .weak SPI2_IRQHandler + .thumb_set SPI2_IRQHandler,Default_Handler + + .weak USART1_IRQHandler + .thumb_set USART1_IRQHandler,Default_Handler + + .weak LPUART1_IRQHandler + .thumb_set LPUART1_IRQHandler,Default_Handler + + .weak SAI1_IRQHandler + .thumb_set SAI1_IRQHandler,Default_Handler + + .weak TSC_IRQHandler + .thumb_set TSC_IRQHandler,Default_Handler + + .weak EXTI15_10_IRQHandler + .thumb_set EXTI15_10_IRQHandler,Default_Handler + + .weak RTC_Alarm_IRQHandler + .thumb_set RTC_Alarm_IRQHandler,Default_Handler + + .weak CRS_IRQHandler + .thumb_set CRS_IRQHandler,Default_Handler + + .weak PWR_SOTF_BLEACT_802ACT_RFPHASE_IRQHandler + .thumb_set PWR_SOTF_BLEACT_802ACT_RFPHASE_IRQHandler,Default_Handler + + .weak IPCC_C1_RX_IRQHandler + .thumb_set IPCC_C1_RX_IRQHandler,Default_Handler + + .weak IPCC_C1_TX_IRQHandler + .thumb_set IPCC_C1_TX_IRQHandler,Default_Handler + + .weak HSEM_IRQHandler + .thumb_set HSEM_IRQHandler,Default_Handler + + .weak LPTIM1_IRQHandler + .thumb_set LPTIM1_IRQHandler,Default_Handler + + .weak LPTIM2_IRQHandler + .thumb_set LPTIM2_IRQHandler,Default_Handler + + .weak LCD_IRQHandler + .thumb_set LCD_IRQHandler,Default_Handler + + .weak QUADSPI_IRQHandler + .thumb_set QUADSPI_IRQHandler,Default_Handler + + .weak AES1_IRQHandler + .thumb_set AES1_IRQHandler,Default_Handler + + .weak AES2_IRQHandler + .thumb_set AES2_IRQHandler,Default_Handler + + .weak RNG_IRQHandler + .thumb_set RNG_IRQHandler,Default_Handler + + .weak FPU_IRQHandler + .thumb_set FPU_IRQHandler,Default_Handler + + .weak DMA2_Channel1_IRQHandler + .thumb_set DMA2_Channel1_IRQHandler,Default_Handler + + .weak DMA2_Channel2_IRQHandler + .thumb_set DMA2_Channel2_IRQHandler,Default_Handler + + .weak DMA2_Channel3_IRQHandler + .thumb_set DMA2_Channel3_IRQHandler,Default_Handler + + .weak DMA2_Channel4_IRQHandler + .thumb_set DMA2_Channel4_IRQHandler,Default_Handler + + .weak DMA2_Channel5_IRQHandler + .thumb_set DMA2_Channel5_IRQHandler,Default_Handler + + .weak DMA2_Channel6_IRQHandler + .thumb_set DMA2_Channel6_IRQHandler,Default_Handler + + .weak DMA2_Channel7_IRQHandler + .thumb_set DMA2_Channel7_IRQHandler,Default_Handler + + .weak DMAMUX1_OVR_IRQHandler + .thumb_set DMAMUX1_OVR_IRQHandler,Default_Handler + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/stm32wb55xx_flash_cm4_boot.ld b/firmware/targets/f7/stm32wb55xx_flash_cm4_boot.ld new file mode 100644 index 00000000..6d55107e --- /dev/null +++ b/firmware/targets/f7/stm32wb55xx_flash_cm4_boot.ld @@ -0,0 +1,192 @@ +/** +***************************************************************************** +** +** File : stm32wb55xx_flash_cm4.ld +** +** Abstract : System Workbench Minimal System calls file +** +** For more information about which c-functions +** need which of these lowlevel functions +** please consult the Newlib libc-manual +** +** Environment : System Workbench for MCU +** +** Distribution: The file is distributed “as is,” without any warranty +** of any kind. +** +***************************************************************************** +** +**

© COPYRIGHT(c) 2019 Ac6

+** +** Redistribution and use in source and binary forms, with or without modification, +** are permitted provided that the following conditions are met: +** 1. Redistributions of source code must retain the above copyright notice, +** this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright notice, +** this list of conditions and the following disclaimer in the documentation +** and/or other materials provided with the distribution. +** 3. Neither the name of Ac6 nor the names of its contributors +** may be used to endorse or promote products derived from this software +** without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +** +***************************************************************************** +*/ + +/* Entry Point */ +ENTRY(Reset_Handler) + +/* Highest address of the user mode stack */ +_estack = 0x20030000; /* end of RAM */ +/* Generate a link error if heap and stack don't fit into RAM */ +_Min_Heap_Size = 0x400; /* required amount of heap */ +_Min_Stack_Size = 0x1000; /* required amount of stack */ + +/* Specify the memory areas */ +MEMORY +{ +FLASH (rx) : ORIGIN = 0x08008000, LENGTH = 992K +RAM1 (xrw) : ORIGIN = 0x20000008, LENGTH = 0x2FFF8 +RAM_SHARED (xrw) : ORIGIN = 0x20030000, LENGTH = 10K +} + +/* Define output sections */ +SECTIONS +{ + /* The startup code goes first into FLASH */ + .isr_vector : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) /* Startup code */ + . = ALIGN(4); + } >FLASH + + /* The program code and other data goes into FLASH */ + .text : + { + . = ALIGN(4); + *(.text) /* .text sections (code) */ + *(.text*) /* .text* sections (code) */ + *(.glue_7) /* glue arm to thumb code */ + *(.glue_7t) /* glue thumb to arm code */ + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + . = ALIGN(4); + _etext = .; /* define a global symbols at end of code */ + } >FLASH + + /* Constant data goes into FLASH */ + .rodata : + { + . = ALIGN(4); + *(.rodata) /* .rodata sections (constants, strings, etc.) */ + *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ + . = ALIGN(4); + } >FLASH + + .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH + .ARM : { + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + } >FLASH + + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array*)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } >FLASH + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array*)) + PROVIDE_HIDDEN (__init_array_end = .); + } >FLASH + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT(.fini_array.*))) + KEEP (*(.fini_array*)) + PROVIDE_HIDDEN (__fini_array_end = .); + } >FLASH + + /* used by the startup to initialize data */ + _sidata = LOADADDR(.data); + + /* Initialized data sections goes into RAM, load LMA copy after code */ + .data : + { + . = ALIGN(4); + _sdata = .; /* create a global symbol at data start */ + *(.data) /* .data sections */ + *(.data*) /* .data* sections */ + + . = ALIGN(4); + _edata = .; /* define a global symbol at data end */ + } >RAM1 AT> FLASH + + + /* Uninitialized data section */ + . = ALIGN(4); + .bss : + { + /* This is used by the startup in order to initialize the .bss secion */ + _sbss = .; /* define a global symbol at bss start */ + __bss_start__ = _sbss; + *(.bss) + *(.bss*) + *(COMMON) + + . = ALIGN(4); + _ebss = .; /* define a global symbol at bss end */ + __bss_end__ = _ebss; + } >RAM1 + + /* User_heap_stack section, used to check that there is enough RAM left */ + ._user_heap_stack : + { + . = ALIGN(8); + __heap_start__ = .; + . = ORIGIN(RAM1) + LENGTH(RAM1) - _Min_Stack_Size; + __heap_end__ = .; + . = . + _Min_Stack_Size; + . = ALIGN(8); + } >RAM1 + + /* Free Flash space, that can be used for internal storage */ + .free_flash(NOLOAD): + { + __free_flash_start__ = .; + . = ORIGIN(FLASH) + LENGTH(FLASH); + } >FLASH + + /* Remove information from the standard libraries */ + /DISCARD/ : + { + libc.a ( * ) + libm.a ( * ) + libgcc.a ( * ) + } + + .ARM.attributes 0 : { *(.ARM.attributes) } + MAPPING_TABLE (NOLOAD) : { *(MAPPING_TABLE) } >RAM_SHARED + MB_MEM1 (NOLOAD) : { *(MB_MEM1) } >RAM_SHARED + MB_MEM2 (NOLOAD) : { _sMB_MEM2 = . ; *(MB_MEM2) ; _eMB_MEM2 = . ; } >RAM_SHARED +} + + diff --git a/firmware/targets/f7/stm32wb55xx_flash_cm4_no_boot.ld b/firmware/targets/f7/stm32wb55xx_flash_cm4_no_boot.ld new file mode 100644 index 00000000..c03809f3 --- /dev/null +++ b/firmware/targets/f7/stm32wb55xx_flash_cm4_no_boot.ld @@ -0,0 +1,192 @@ +/** +***************************************************************************** +** +** File : stm32wb55xx_flash_cm4.ld +** +** Abstract : System Workbench Minimal System calls file +** +** For more information about which c-functions +** need which of these lowlevel functions +** please consult the Newlib libc-manual +** +** Environment : System Workbench for MCU +** +** Distribution: The file is distributed “as is,” without any warranty +** of any kind. +** +***************************************************************************** +** +**

© COPYRIGHT(c) 2019 Ac6

+** +** Redistribution and use in source and binary forms, with or without modification, +** are permitted provided that the following conditions are met: +** 1. Redistributions of source code must retain the above copyright notice, +** this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright notice, +** this list of conditions and the following disclaimer in the documentation +** and/or other materials provided with the distribution. +** 3. Neither the name of Ac6 nor the names of its contributors +** may be used to endorse or promote products derived from this software +** without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +** +***************************************************************************** +*/ + +/* Entry Point */ +ENTRY(Reset_Handler) + +/* Highest address of the user mode stack */ +_estack = 0x20030000; /* end of RAM */ +/* Generate a link error if heap and stack don't fit into RAM */ +_Min_Heap_Size = 0x400; /* required amount of heap */ +_Min_Stack_Size = 0x1000; /* required amount of stack */ + +/* Specify the memory areas */ +MEMORY +{ +FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K +RAM1 (xrw) : ORIGIN = 0x20000008, LENGTH = 0x2FFF8 +RAM_SHARED (xrw) : ORIGIN = 0x20030000, LENGTH = 10K +} + +/* Define output sections */ +SECTIONS +{ + /* The startup code goes first into FLASH */ + .isr_vector : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) /* Startup code */ + . = ALIGN(4); + } >FLASH + + /* The program code and other data goes into FLASH */ + .text : + { + . = ALIGN(4); + *(.text) /* .text sections (code) */ + *(.text*) /* .text* sections (code) */ + *(.glue_7) /* glue arm to thumb code */ + *(.glue_7t) /* glue thumb to arm code */ + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + . = ALIGN(4); + _etext = .; /* define a global symbols at end of code */ + } >FLASH + + /* Constant data goes into FLASH */ + .rodata : + { + . = ALIGN(4); + *(.rodata) /* .rodata sections (constants, strings, etc.) */ + *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ + . = ALIGN(4); + } >FLASH + + .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH + .ARM : { + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + } >FLASH + + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array*)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } >FLASH + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array*)) + PROVIDE_HIDDEN (__init_array_end = .); + } >FLASH + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT(.fini_array.*))) + KEEP (*(.fini_array*)) + PROVIDE_HIDDEN (__fini_array_end = .); + } >FLASH + + /* used by the startup to initialize data */ + _sidata = LOADADDR(.data); + + /* Initialized data sections goes into RAM, load LMA copy after code */ + .data : + { + . = ALIGN(4); + _sdata = .; /* create a global symbol at data start */ + *(.data) /* .data sections */ + *(.data*) /* .data* sections */ + + . = ALIGN(4); + _edata = .; /* define a global symbol at data end */ + } >RAM1 AT> FLASH + + + /* Uninitialized data section */ + . = ALIGN(4); + .bss : + { + /* This is used by the startup in order to initialize the .bss secion */ + _sbss = .; /* define a global symbol at bss start */ + __bss_start__ = _sbss; + *(.bss) + *(.bss*) + *(COMMON) + + . = ALIGN(4); + _ebss = .; /* define a global symbol at bss end */ + __bss_end__ = _ebss; + } >RAM1 + + /* User_heap_stack section, used to check that there is enough RAM left */ + ._user_heap_stack : + { + . = ALIGN(8); + __heap_start__ = .; + . = ORIGIN(RAM1) + LENGTH(RAM1) - _Min_Stack_Size; + __heap_end__ = .; + . = . + _Min_Stack_Size; + . = ALIGN(8); + } >RAM1 + + /* Free Flash space, that can be used for internal storage */ + .free_flash(NOLOAD): + { + __free_flash_start__ = .; + . = ORIGIN(FLASH) + LENGTH(FLASH); + } >FLASH + + /* Remove information from the standard libraries */ + /DISCARD/ : + { + libc.a ( * ) + libm.a ( * ) + libgcc.a ( * ) + } + + .ARM.attributes 0 : { *(.ARM.attributes) } + MAPPING_TABLE (NOLOAD) : { *(MAPPING_TABLE) } >RAM_SHARED + MB_MEM1 (NOLOAD) : { *(MB_MEM1) } >RAM_SHARED + MB_MEM2 (NOLOAD) : { _sMB_MEM2 = . ; *(MB_MEM2) ; _eMB_MEM2 = . ; } >RAM_SHARED +} + + diff --git a/firmware/targets/f7/target.mk b/firmware/targets/f7/target.mk new file mode 100644 index 00000000..d020c155 --- /dev/null +++ b/firmware/targets/f7/target.mk @@ -0,0 +1,169 @@ +TOOLCHAIN = arm + +BOOT_ADDRESS = 0x08000000 +FW_ADDRESS = 0x08008000 +OS_OFFSET = 0x00008000 +FLASH_ADDRESS = 0x08008000 + +NO_BOOTLOADER ?= 0 +ifeq ($(NO_BOOTLOADER), 1) +BOOT_ADDRESS = 0x08000000 +FW_ADDRESS = 0x08000000 +OS_OFFSET = 0x00000000 +FLASH_ADDRESS = 0x08000000 +CFLAGS += -DNO_BOOTLOADER +endif + +OPENOCD_OPTS = -f interface/stlink.cfg -c "transport select hla_swd" -f ../debug/stm32wbx.cfg -c "stm32wbx.cpu configure -rtos auto" -c "init" +BOOT_CFLAGS = -DBOOT_ADDRESS=$(BOOT_ADDRESS) -DFW_ADDRESS=$(FW_ADDRESS) -DOS_OFFSET=$(OS_OFFSET) +MCU_FLAGS = -mcpu=cortex-m4 -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard + +CFLAGS += $(MCU_FLAGS) $(BOOT_CFLAGS) -DSTM32WB55xx -Wall -fdata-sections -ffunction-sections +LDFLAGS += $(MCU_FLAGS) -specs=nosys.specs -specs=nano.specs + +CPPFLAGS += -fno-rtti -fno-use-cxa-atexit -fno-exceptions +LDFLAGS += -Wl,--start-group -lstdc++ -lsupc++ -Wl,--end-group + +MXPROJECT_DIR = $(TARGET_DIR) + +# Entry Point +ASM_SOURCES += $(MXPROJECT_DIR)/startup_stm32wb55xx_cm4.s + +# STM32WB HAL +CUBE_DIR = ../lib/STM32CubeWB +CFLAGS += \ + -DUSE_FULL_LL_DRIVER \ + -DUSE_HAL_DRIVER \ + -DHAVE_FREERTOS +CFLAGS += \ + -I$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Inc \ + -I$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Inc/Legacy \ + -I$(CUBE_DIR)/Drivers/CMSIS/Device/ST/STM32WBxx/Include \ + -I$(CUBE_DIR)/Drivers/CMSIS/Include +C_SOURCES += \ + $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal.c \ + $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_comp.c \ + $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_cortex.c \ + $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_cryp.c \ + $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_exti.c \ + $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_flash.c \ + $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_flash_ex.c \ + $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_gpio.c \ + $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_hsem.c \ + $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_ipcc.c \ + $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_pcd.c \ + $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_pcd_ex.c \ + $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_pka.c \ + $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_pwr.c \ + $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_pwr_ex.c \ + $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_rcc.c \ + $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_rcc_ex.c \ + $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_rng.c \ + $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_rtc.c \ + $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_rtc_ex.c \ + $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_tim.c \ + $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_tim_ex.c \ + $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_adc.c \ + $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_dma.c \ + $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_gpio.c \ + $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_i2c.c \ + $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_lptim.c \ + $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_rcc.c \ + $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_spi.c \ + $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_tim.c \ + $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_usart.c \ + $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_usb.c \ + $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_utils.c + +# FreeRTOS +CFLAGS += \ + -I$(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/include \ + -I$(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2 \ + -I$(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F +C_SOURCES += \ + $(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/croutine.c \ + $(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/event_groups.c \ + $(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/list.c \ + $(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/queue.c \ + $(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/stream_buffer.c \ + $(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/tasks.c \ + $(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/timers.c \ + $(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/cmsis_os2.c \ + $(CUBE_DIR)/Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c + +# BLE glue +CFLAGS += \ + -I$(TARGET_DIR)/ble-glue \ + -I$(CUBE_DIR)/Middlewares/ST/STM32_WPAN \ + -I$(CUBE_DIR)/Middlewares/ST/STM32_WPAN/ble \ + -I$(CUBE_DIR)/Middlewares/ST/STM32_WPAN/ble/core \ + -I$(CUBE_DIR)/Middlewares/ST/STM32_WPAN/ble/core/template \ + -I$(CUBE_DIR)/Middlewares/ST/STM32_WPAN/utilities \ + -I$(CUBE_DIR)/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread \ + -I$(CUBE_DIR)/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl \ + -I$(CUBE_DIR)/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/shci +C_SOURCES += \ + $(wildcard $(TARGET_DIR)/ble-glue/*.c) \ + $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/utilities/otp.c \ + $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/utilities/stm_list.c \ + $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/utilities/dbg_trace.c \ + $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/ble/svc/Src/svc_ctl.c \ + $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/ble/core/template/osal.c \ + $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_hci_le.c \ + $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_gap_aci.c \ + $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_gatt_aci.c \ + $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/ble/core/auto/ble_hal_aci.c \ + $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl/tl_mbox.c \ + $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl/hci_tl.c \ + $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl/hci_tl_if.c \ + $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl/shci_tl.c \ + $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl/shci_tl_if.c \ + $(CUBE_DIR)/Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/shci/shci.c + +# USB glue +CFLAGS += \ + -I$(TARGET_DIR)/usb-glue \ + -I$(CUBE_DIR)/Middlewares/ST/STM32_USB_Device_Library/Core/Inc \ + -I$(CUBE_DIR)/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Inc +C_SOURCES += \ + $(wildcard $(TARGET_DIR)/usb-glue/*.c) \ + $(CUBE_DIR)/Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_core.c \ + $(CUBE_DIR)/Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_ctlreq.c \ + $(CUBE_DIR)/Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_ioreq.c \ + $(CUBE_DIR)/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c + +# Furi HAL +FURI_HAL_OS_DEBUG ?= 0 +ifeq ($(FURI_HAL_OS_DEBUG), 1) +CFLAGS += -DFURI_HAL_OS_DEBUG +endif + +FURI_HAL_SUBGHZ_TX_GPIO ?= 0 +ifneq ($(FURI_HAL_SUBGHZ_TX_GPIO), 0) +CFLAGS += -DFURI_HAL_SUBGHZ_TX_GPIO=$(FURI_HAL_SUBGHZ_TX_GPIO) +endif + +ifeq ($(INVERT_RFID_IN), 1) +CFLAGS += -DINVERT_RFID_IN +endif + +FURI_HAL_DIR = $(TARGET_DIR)/furi-hal +CFLAGS += -I$(FURI_HAL_DIR) +C_SOURCES += $(wildcard $(FURI_HAL_DIR)/*.c) + +# Other +CFLAGS += \ + -I$(MXPROJECT_DIR)/Inc \ + -I$(MXPROJECT_DIR)/Src/fatfs +C_SOURCES += \ + $(wildcard $(MXPROJECT_DIR)/Src/*.c) \ + $(wildcard $(MXPROJECT_DIR)/Src/fatfs/*.c) + +# Linker options +ifeq ($(NO_BOOTLOADER), 1) +LDFLAGS += -T$(MXPROJECT_DIR)/stm32wb55xx_flash_cm4_no_boot.ld +else +LDFLAGS += -T$(MXPROJECT_DIR)/stm32wb55xx_flash_cm4_boot.ld +endif + +SVD_FILE = ../debug/STM32WB55_CM4.svd diff --git a/firmware/targets/f7/usb-glue/usb_device.c b/firmware/targets/f7/usb-glue/usb_device.c new file mode 100644 index 00000000..84e9143d --- /dev/null +++ b/firmware/targets/f7/usb-glue/usb_device.c @@ -0,0 +1,34 @@ +#include "usb_device.h" + +#include "stm32wbxx.h" +#include "stm32wbxx_hal.h" + +#include "usbd_def.h" +#include "usbd_core.h" +#include "usbd_desc.h" +#include "usbd_cdc.h" +#include "usbd_cdc_if.h" + +extern void Error_Handler(void); + +/* USB Device Core handle declaration. */ +USBD_HandleTypeDef hUsbDeviceFS; + +extern USBD_DescriptorsTypeDef CDC_Desc; + +/** Init USB device Library, add supported class and start the library */ +void MX_USB_Device_Init(void) { + /* Init Device Library, add supported class and start the library. */ + if (USBD_Init(&hUsbDeviceFS, &CDC_Desc, DEVICE_FS) != USBD_OK) { + Error_Handler(); + } + if (USBD_RegisterClass(&hUsbDeviceFS, &USBD_CDC) != USBD_OK) { + Error_Handler(); + } + if (USBD_CDC_RegisterInterface(&hUsbDeviceFS, &USBD_Interface_fops_FS) != USBD_OK) { + Error_Handler(); + } + if (USBD_Start(&hUsbDeviceFS) != USBD_OK) { + Error_Handler(); + } +} diff --git a/firmware/targets/f7/usb-glue/usb_device.h b/firmware/targets/f7/usb-glue/usb_device.h new file mode 100644 index 00000000..7d80e348 --- /dev/null +++ b/firmware/targets/f7/usb-glue/usb_device.h @@ -0,0 +1,11 @@ +#pragma once + +#ifdef __cplusplus + extern "C" { +#endif + +void MX_USB_Device_Init(); + +#ifdef __cplusplus +} +#endif diff --git a/firmware/targets/f7/usb-glue/usbd_cdc_if.c b/firmware/targets/f7/usb-glue/usbd_cdc_if.c new file mode 100644 index 00000000..6b905c84 --- /dev/null +++ b/firmware/targets/f7/usb-glue/usbd_cdc_if.c @@ -0,0 +1,142 @@ +#include "usbd_cdc_if.h" +#include + +extern USBD_HandleTypeDef hUsbDeviceFS; + +static int8_t CDC_Init_FS(void); +static int8_t CDC_DeInit_FS(void); +static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length); +static int8_t CDC_Receive_FS(uint8_t* pbuf, uint32_t *Len); +static int8_t CDC_TransmitCplt_FS(uint8_t *pbuf, uint32_t *Len, uint8_t epnum); + +USBD_CDC_ItfTypeDef USBD_Interface_fops_FS = +{ + CDC_Init_FS, + CDC_DeInit_FS, + CDC_Control_FS, + CDC_Receive_FS, + CDC_TransmitCplt_FS +}; + +uint8_t UserRxBufferFS[APP_RX_DATA_SIZE]; +uint8_t UserTxBufferFS[APP_TX_DATA_SIZE]; + +/** Initializes the CDC media low layer over the FS USB IP + * @retval USBD_OK if all operations are OK else USBD_FAIL + */ +static int8_t CDC_Init_FS(void) { + /* Set Application Buffers */ + USBD_CDC_SetTxBuffer(&hUsbDeviceFS, UserTxBufferFS, 0); + USBD_CDC_SetRxBuffer(&hUsbDeviceFS, UserRxBufferFS); + return (USBD_OK); +} + +/** + * @brief DeInitializes the CDC media low layer + * @retval USBD_OK if all operations are OK else USBD_FAIL + */ +static int8_t CDC_DeInit_FS(void) { + return (USBD_OK); +} + +/** Manage the CDC class requests + * @param cmd: Command code + * @param pbuf: Buffer containing command data (request parameters) + * @param length: Number of data to be sent (in bytes) + * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL + */ +static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length) { + if (cmd == CDC_SEND_ENCAPSULATED_COMMAND) { + } else if (cmd == CDC_GET_ENCAPSULATED_RESPONSE) { + } else if (cmd == CDC_SET_COMM_FEATURE) { + } else if (cmd == CDC_GET_COMM_FEATURE) { + } else if (cmd == CDC_CLEAR_COMM_FEATURE) { + } else if (cmd == CDC_SET_LINE_CODING) { + /*******************************************************************************/ + /* Line Coding Structure */ + /*-----------------------------------------------------------------------------*/ + /* Offset | Field | Size | Value | Description */ + /* 0 | dwDTERate | 4 | Number |Data terminal rate, in bits per second*/ + /* 4 | bCharFormat | 1 | Number | Stop bits */ + /* 0 - 1 Stop bit */ + /* 1 - 1.5 Stop bits */ + /* 2 - 2 Stop bits */ + /* 5 | bParityType | 1 | Number | Parity */ + /* 0 - None */ + /* 1 - Odd */ + /* 2 - Even */ + /* 3 - Mark */ + /* 4 - Space */ + /* 6 | bDataBits | 1 | Number Data bits (5, 6, 7, 8 or 16). */ + /*******************************************************************************/ + } else if (cmd == CDC_GET_LINE_CODING) { + } else if (cmd == CDC_SET_CONTROL_LINE_STATE) { + furi_hal_vcp_on_cdc_control_line(((USBD_SetupReqTypedef*)pbuf)->wValue); + } else if (cmd == CDC_SEND_BREAK) { + } else { + } + + return (USBD_OK); +} + +/** Data received over USB OUT endpoint are sent over CDC interface through this function. + * + * @note + * This function will issue a NAK packet on any OUT packet received on + * USB endpoint until exiting this function. If you exit this function + * before transfer is complete on CDC interface (ie. using DMA controller) + * it will result in receiving more data while previous ones are still + * not sent. + * + * @param Buf: Buffer of data to be received + * @param Len: Number of data received (in bytes) + * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL + */ +static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len) { + if (*Len) { + furi_hal_vcp_on_cdc_rx(Buf, *Len); + } else { + USBD_CDC_ReceivePacket(&hUsbDeviceFS); + } + + return (USBD_OK); +} + +/** CDC_Transmit_FS Data to send over USB IN endpoint are sent over CDC interface + * through this function. + * @param Buf: Buffer of data to be sent + * @param Len: Number of data to be sent (in bytes) + * @retval USBD_OK if all operations are OK else USBD_FAIL or USBD_BUSY + */ +uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len) +{ + uint8_t result = USBD_OK; + + USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*)hUsbDeviceFS.pClassData; + if (hcdc->TxState != 0){ + return USBD_BUSY; + } + memcpy(UserTxBufferFS, Buf, Len); + USBD_CDC_SetTxBuffer(&hUsbDeviceFS, UserTxBufferFS, Len); + result = USBD_CDC_TransmitPacket(&hUsbDeviceFS); + + return result; +} + +/** CDC_TransmitCplt_FS Data transmited callback + * + * @note + * This function is IN transfer complete callback used to inform user that + * the submitted Data is successfully sent over USB. + * + * @param Buf: Buffer of data to be received + * @param Len: Number of data received (in bytes) + * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL + */ +static int8_t CDC_TransmitCplt_FS(uint8_t *Buf, uint32_t *Len, uint8_t epnum) { + uint8_t result = USBD_OK; + + furi_hal_vcp_on_cdc_tx_complete(*Len); + + return result; +} diff --git a/firmware/targets/f7/usb-glue/usbd_cdc_if.h b/firmware/targets/f7/usb-glue/usbd_cdc_if.h new file mode 100644 index 00000000..fc0aefbe --- /dev/null +++ b/firmware/targets/f7/usb-glue/usbd_cdc_if.h @@ -0,0 +1,22 @@ +#pragma once + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_cdc.h" + +/* Define size for the receive and transmit buffer over CDC */ +/* It's up to user to redefine and/or remove those define */ +#define APP_RX_DATA_SIZE CDC_DATA_FS_MAX_PACKET_SIZE +#define APP_TX_DATA_SIZE CDC_DATA_FS_MAX_PACKET_SIZE + +/** CDC Interface callback. */ +extern USBD_CDC_ItfTypeDef USBD_Interface_fops_FS; + +uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len); + +#ifdef __cplusplus +} +#endif diff --git a/firmware/targets/f7/usb-glue/usbd_conf.c b/firmware/targets/f7/usb-glue/usbd_conf.c new file mode 100644 index 00000000..cbc137e5 --- /dev/null +++ b/firmware/targets/f7/usb-glue/usbd_conf.c @@ -0,0 +1,506 @@ +#include "stm32wbxx.h" +#include "stm32wbxx_hal.h" + +#include + +#include "usbd_def.h" +#include "usbd_core.h" +#include "usbd_cdc.h" + +PCD_HandleTypeDef hpcd_USB_FS; +void Error_Handler(void); + +static USBD_StatusTypeDef USBD_Get_USB_Status(HAL_StatusTypeDef hal_status); + +static void SystemClockConfig_Resume(void); + +void HAL_PCD_MspInit(PCD_HandleTypeDef* pcdHandle) { + GPIO_InitTypeDef GPIO_InitStruct = {0}; + if(pcdHandle->Instance==USB) { + __HAL_RCC_GPIOA_CLK_ENABLE(); + /**USB GPIO Configuration + PA11 ------> USB_DM + PA12 ------> USB_DP + */ + GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_12; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF10_USB; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + /* Peripheral clock enable */ + __HAL_RCC_USB_CLK_ENABLE(); + + /* Peripheral interrupt init */ + HAL_NVIC_SetPriority(USB_LP_IRQn, 5, 0); + HAL_NVIC_EnableIRQ(USB_LP_IRQn); + } +} + +void HAL_PCD_MspDeInit(PCD_HandleTypeDef* pcdHandle) { + if(pcdHandle->Instance==USB) { + /* Peripheral clock disable */ + __HAL_RCC_USB_CLK_DISABLE(); + + /**USB GPIO Configuration + PA11 ------> USB_DM + PA12 ------> USB_DP + */ + HAL_GPIO_DeInit(GPIOA, GPIO_PIN_11|GPIO_PIN_12); + + /* Peripheral interrupt Deinit*/ + HAL_NVIC_DisableIRQ(USB_LP_IRQn); + } +} + +/** Setup stage callback + * @param hpcd: PCD handle + * @retval None + */ +void HAL_PCD_SetupStageCallback(PCD_HandleTypeDef *hpcd) { + USBD_LL_SetupStage((USBD_HandleTypeDef*)hpcd->pData, (uint8_t *)hpcd->Setup); +} + +/** Data Out stage callback. + * @param hpcd: PCD handle + * @param epnum: Endpoint number + * @retval None + */ +void HAL_PCD_DataOutStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) { + USBD_LL_DataOutStage((USBD_HandleTypeDef*)hpcd->pData, epnum, hpcd->OUT_ep[epnum].xfer_buff); +} + +/** Data In stage callback. + * @param hpcd: PCD handle + * @param epnum: Endpoint number + * @retval None + */ +void HAL_PCD_DataInStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) { + USBD_LL_DataInStage((USBD_HandleTypeDef*)hpcd->pData, epnum, hpcd->IN_ep[epnum].xfer_buff); +} + +/** SOF callback. + * @param hpcd: PCD handle + * @retval None + */ +void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd) { + USBD_LL_SOF((USBD_HandleTypeDef*)hpcd->pData); +} + +/** Reset callback. + * @param hpcd: PCD handle + * @retval None + */ +void HAL_PCD_ResetCallback(PCD_HandleTypeDef *hpcd) { + USBD_SpeedTypeDef speed = USBD_SPEED_FULL; + + if ( hpcd->Init.speed != PCD_SPEED_FULL) { + Error_Handler(); + } + + /* Set Speed. */ + USBD_LL_SetSpeed((USBD_HandleTypeDef*)hpcd->pData, speed); + + /* Reset Device. */ + USBD_LL_Reset((USBD_HandleTypeDef*)hpcd->pData); +} + +/** Suspend callback. + * When Low power mode is enabled the debug cannot be used (IAR, Keil doesn't support it) + * @param hpcd: PCD handle + * @retval None + */ +void HAL_PCD_SuspendCallback(PCD_HandleTypeDef *hpcd) { + USBD_LL_Suspend((USBD_HandleTypeDef*)hpcd->pData); + + furi_hal_vcp_on_usb_suspend(); + + if (hpcd->Init.low_power_enable) { + /* Set SLEEPDEEP bit and SleepOnExit of Cortex System Control Register. */ + SCB->SCR |= (uint32_t)((uint32_t)(SCB_SCR_SLEEPDEEP_Msk | SCB_SCR_SLEEPONEXIT_Msk)); + } +} + +/** Resume callback. + * When Low power mode is enabled the debug cannot be used (IAR, Keil doesn't support it) + * @param hpcd: PCD handle + * @retval None + */ +void HAL_PCD_ResumeCallback(PCD_HandleTypeDef *hpcd) { + if (hpcd->Init.low_power_enable) { + /* Reset SLEEPDEEP bit of Cortex System Control Register. */ + SCB->SCR &= (uint32_t)~((uint32_t)(SCB_SCR_SLEEPDEEP_Msk | SCB_SCR_SLEEPONEXIT_Msk)); + SystemClockConfig_Resume(); + } + + furi_hal_vcp_on_usb_resume(); + + USBD_LL_Resume((USBD_HandleTypeDef*)hpcd->pData); +} + +/** ISOOUTIncomplete callback. + * @param hpcd: PCD handle + * @param epnum: Endpoint number + * @retval None + */ +void HAL_PCD_ISOOUTIncompleteCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) { + USBD_LL_IsoOUTIncomplete((USBD_HandleTypeDef*)hpcd->pData, epnum); +} + +/** ISOINIncomplete callback. + * @param hpcd: PCD handle + * @param epnum: Endpoint number + * @retval None + */ +void HAL_PCD_ISOINIncompleteCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) { + USBD_LL_IsoINIncomplete((USBD_HandleTypeDef*)hpcd->pData, epnum); +} + +/** Connect callback. + * @param hpcd: PCD handle + * @retval None + */ +void HAL_PCD_ConnectCallback(PCD_HandleTypeDef *hpcd) { + USBD_LL_DevConnected((USBD_HandleTypeDef*)hpcd->pData); +} + +/** Disconnect callback. + * @param hpcd: PCD handle + * @retval None + */ +void HAL_PCD_DisconnectCallback(PCD_HandleTypeDef *hpcd) { + USBD_LL_DevDisconnected((USBD_HandleTypeDef*)hpcd->pData); +} + +/** Initializes the low level portion of the device driver. + * @param pdev: Device handle + * @retval USBD status + */ +USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev) { + /* Init USB Ip. */ + hpcd_USB_FS.pData = pdev; + + /* Link the driver to the stack. */ + pdev->pData = &hpcd_USB_FS; + + /* Enable USB power on Pwrctrl CR2 register. */ + HAL_PWREx_EnableVddUSB(); + + hpcd_USB_FS.Instance = USB; + hpcd_USB_FS.Init.dev_endpoints = 8; + hpcd_USB_FS.Init.speed = PCD_SPEED_FULL; + hpcd_USB_FS.Init.phy_itface = PCD_PHY_EMBEDDED; + hpcd_USB_FS.Init.Sof_enable = DISABLE; + hpcd_USB_FS.Init.low_power_enable = DISABLE; + hpcd_USB_FS.Init.lpm_enable = DISABLE; + hpcd_USB_FS.Init.battery_charging_enable = DISABLE; + + if (HAL_PCD_Init(&hpcd_USB_FS) != HAL_OK) { + Error_Handler(); + } + + HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x00 , PCD_SNG_BUF, 0x18); + HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x80 , PCD_SNG_BUF, 0x58); + + HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x81 , PCD_SNG_BUF, 0xC0); + HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x01 , PCD_SNG_BUF, 0x110); + HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x82 , PCD_SNG_BUF, 0x100); + + return USBD_OK; +} + +/** De-Initializes the low level portion of the device driver. + * @param pdev: Device handle + * @retval USBD status + */ +USBD_StatusTypeDef USBD_LL_DeInit(USBD_HandleTypeDef *pdev) +{ + HAL_StatusTypeDef hal_status = HAL_OK; + USBD_StatusTypeDef usb_status = USBD_OK; + + hal_status = HAL_PCD_DeInit(pdev->pData); + + usb_status = USBD_Get_USB_Status(hal_status); + + return usb_status; +} + +/** Starts the low level portion of the device driver. + * @param pdev: Device handle + * @retval USBD status + */ +USBD_StatusTypeDef USBD_LL_Start(USBD_HandleTypeDef *pdev) { + HAL_StatusTypeDef hal_status = HAL_OK; + USBD_StatusTypeDef usb_status = USBD_OK; + + hal_status = HAL_PCD_Start(pdev->pData); + + usb_status = USBD_Get_USB_Status(hal_status); + + return usb_status; +} + +/** Stops the low level portion of the device driver. + * @param pdev: Device handle + * @retval USBD status + */ +USBD_StatusTypeDef USBD_LL_Stop(USBD_HandleTypeDef *pdev) { + HAL_StatusTypeDef hal_status = HAL_OK; + USBD_StatusTypeDef usb_status = USBD_OK; + + hal_status = HAL_PCD_Stop(pdev->pData); + + usb_status = USBD_Get_USB_Status(hal_status); + + return usb_status; +} + +/** Opens an endpoint of the low level driver. + * @param pdev: Device handle + * @param ep_addr: Endpoint number + * @param ep_type: Endpoint type + * @param ep_mps: Endpoint max packet size + * @retval USBD status + */ +USBD_StatusTypeDef USBD_LL_OpenEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr, uint8_t ep_type, uint16_t ep_mps) { + HAL_StatusTypeDef hal_status = HAL_OK; + USBD_StatusTypeDef usb_status = USBD_OK; + + hal_status = HAL_PCD_EP_Open(pdev->pData, ep_addr, ep_mps, ep_type); + + usb_status = USBD_Get_USB_Status(hal_status); + + return usb_status; +} + +/** Closes an endpoint of the low level driver. + * @param pdev: Device handle + * @param ep_addr: Endpoint number + * @retval USBD status + */ +USBD_StatusTypeDef USBD_LL_CloseEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr) { + HAL_StatusTypeDef hal_status = HAL_OK; + USBD_StatusTypeDef usb_status = USBD_OK; + + hal_status = HAL_PCD_EP_Close(pdev->pData, ep_addr); + + usb_status = USBD_Get_USB_Status(hal_status); + + return usb_status; +} + +/** + * @brief Flushes an endpoint of the Low Level Driver. + * @param pdev: Device handle + * @param ep_addr: Endpoint number + * @retval USBD status + */ +USBD_StatusTypeDef USBD_LL_FlushEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr) { + HAL_StatusTypeDef hal_status = HAL_OK; + USBD_StatusTypeDef usb_status = USBD_OK; + + hal_status = HAL_PCD_EP_Flush(pdev->pData, ep_addr); + + usb_status = USBD_Get_USB_Status(hal_status); + + return usb_status; +} + +/** Sets a Stall condition on an endpoint of the Low Level Driver. + * @param pdev: Device handle + * @param ep_addr: Endpoint number + * @retval USBD status + */ +USBD_StatusTypeDef USBD_LL_StallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr) { + HAL_StatusTypeDef hal_status = HAL_OK; + USBD_StatusTypeDef usb_status = USBD_OK; + + hal_status = HAL_PCD_EP_SetStall(pdev->pData, ep_addr); + + usb_status = USBD_Get_USB_Status(hal_status); + + return usb_status; +} + +/** Clears a Stall condition on an endpoint of the Low Level Driver. + * @param pdev: Device handle + * @param ep_addr: Endpoint number + * @retval USBD status + */ +USBD_StatusTypeDef USBD_LL_ClearStallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr) { + HAL_StatusTypeDef hal_status = HAL_OK; + USBD_StatusTypeDef usb_status = USBD_OK; + + hal_status = HAL_PCD_EP_ClrStall(pdev->pData, ep_addr); + + usb_status = USBD_Get_USB_Status(hal_status); + + return usb_status; +} + +/** Returns Stall condition. + * @param pdev: Device handle + * @param ep_addr: Endpoint number + * @retval Stall (1: Yes, 0: No) + */ +uint8_t USBD_LL_IsStallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr) { + PCD_HandleTypeDef *hpcd = (PCD_HandleTypeDef*) pdev->pData; + + if((ep_addr & 0x80) == 0x80) + { + return hpcd->IN_ep[ep_addr & 0x7F].is_stall; + } + else + { + return hpcd->OUT_ep[ep_addr & 0x7F].is_stall; + } +} + +/** Assigns a USB address to the device. + * @param pdev: Device handle + * @param dev_addr: Device address + * @retval USBD status + */ +USBD_StatusTypeDef USBD_LL_SetUSBAddress(USBD_HandleTypeDef *pdev, uint8_t dev_addr) { + HAL_StatusTypeDef hal_status = HAL_OK; + USBD_StatusTypeDef usb_status = USBD_OK; + + hal_status = HAL_PCD_SetAddress(pdev->pData, dev_addr); + + usb_status = USBD_Get_USB_Status(hal_status); + + return usb_status; +} + +/** Transmits data over an endpoint. + * @param pdev: Device handle + * @param ep_addr: Endpoint number + * @param pbuf: Pointer to data to be sent + * @param size: Data size + * @retval USBD status + */ +USBD_StatusTypeDef USBD_LL_Transmit(USBD_HandleTypeDef *pdev, uint8_t ep_addr, uint8_t *pbuf, uint32_t size) { + HAL_StatusTypeDef hal_status = HAL_OK; + USBD_StatusTypeDef usb_status = USBD_OK; + + hal_status = HAL_PCD_EP_Transmit(pdev->pData, ep_addr, pbuf, size); + + usb_status = USBD_Get_USB_Status(hal_status); + + return usb_status; +} + +/** Prepares an endpoint for reception. + * @param pdev: Device handle + * @param ep_addr: Endpoint number + * @param pbuf: Pointer to data to be received + * @param size: Data size + * @retval USBD status + */ +USBD_StatusTypeDef USBD_LL_PrepareReceive(USBD_HandleTypeDef *pdev, uint8_t ep_addr, uint8_t *pbuf, uint32_t size) { + HAL_StatusTypeDef hal_status = HAL_OK; + USBD_StatusTypeDef usb_status = USBD_OK; + + hal_status = HAL_PCD_EP_Receive(pdev->pData, ep_addr, pbuf, size); + + usb_status = USBD_Get_USB_Status(hal_status); + + return usb_status; +} + +/** Returns the last transfered packet size. + * @param pdev: Device handle + * @param ep_addr: Endpoint number + * @retval Recived Data Size + */ +uint32_t USBD_LL_GetRxDataSize(USBD_HandleTypeDef *pdev, uint8_t ep_addr) { + return HAL_PCD_EP_GetRxCount((PCD_HandleTypeDef*) pdev->pData, ep_addr); +} + +/** Send LPM message to user layer + * @param hpcd: PCD handle + * @param msg: LPM message + * @retval None + */ +void HAL_PCDEx_LPM_Callback(PCD_HandleTypeDef *hpcd, PCD_LPM_MsgTypeDef msg) { + switch (msg) { + case PCD_LPM_L0_ACTIVE: + if (hpcd->Init.low_power_enable) { + SystemClockConfig_Resume(); + /* Reset SLEEPDEEP bit of Cortex System Control Register. */ + SCB->SCR &= (uint32_t)~((uint32_t)(SCB_SCR_SLEEPDEEP_Msk | SCB_SCR_SLEEPONEXIT_Msk)); + } + USBD_LL_Resume(hpcd->pData); + break; + + case PCD_LPM_L1_ACTIVE: + USBD_LL_Suspend(hpcd->pData); + + /* Enter in STOP mode. */ + if (hpcd->Init.low_power_enable) { + /* Set SLEEPDEEP bit and SleepOnExit of Cortex System Control Register. */ + SCB->SCR |= (uint32_t)((uint32_t)(SCB_SCR_SLEEPDEEP_Msk | SCB_SCR_SLEEPONEXIT_Msk)); + } + break; + } +} + +/** Delays routine for the USB Device Library. + * @param Delay: Delay in ms + * @retval None + */ +void USBD_LL_Delay(uint32_t Delay) { + HAL_Delay(Delay); +} + +/** Static single allocation. + * @param size: Size of allocated memory + * @retval None + */ +void *USBD_static_malloc(uint32_t size) { + static uint32_t mem[(sizeof(USBD_CDC_HandleTypeDef)/4)+1];/* On 32-bit boundary */ + return mem; +} + +/** Dummy memory free + * @param p: Pointer to allocated memory address + * @retval None + */ +void USBD_static_free(void *p) { +} + +/** Configures system clock after wake-up from USB resume callBack: + * enable HSI, PLL and select PLL as system clock source. + * @retval None + */ +static void SystemClockConfig_Resume(void) { +} + +/** Retuns the USB status depending on the HAL status: + * @param hal_status: HAL status + * @retval USB status + */ +USBD_StatusTypeDef USBD_Get_USB_Status(HAL_StatusTypeDef hal_status) { + USBD_StatusTypeDef usb_status = USBD_OK; + + switch (hal_status) + { + case HAL_OK : + usb_status = USBD_OK; + break; + case HAL_ERROR : + usb_status = USBD_FAIL; + break; + case HAL_BUSY : + usb_status = USBD_BUSY; + break; + case HAL_TIMEOUT : + usb_status = USBD_FAIL; + break; + default : + usb_status = USBD_FAIL; + break; + } + return usb_status; +} diff --git a/firmware/targets/f7/usb-glue/usbd_conf.h b/firmware/targets/f7/usb-glue/usbd_conf.h new file mode 100644 index 00000000..9e2a86f2 --- /dev/null +++ b/firmware/targets/f7/usb-glue/usbd_conf.h @@ -0,0 +1,73 @@ +#pragma once + +#include +#include +#include +#include "stm32wbxx.h" +#include "stm32wbxx_hal.h" + +#ifdef __cplusplus + extern "C" { +#endif + +#define USBD_MAX_NUM_INTERFACES 1U +#define USBD_MAX_NUM_CONFIGURATION 1U +#define USBD_MAX_STR_DESC_SIZ 512U +#define USBD_DEBUG_LEVEL 0U +#define USBD_LPM_ENABLED 0U +#define USBD_SELF_POWERED 0U + +/****************************************/ +/* #define for FS and HS identification */ +#define DEVICE_FS 0 + +/* Memory management macros */ + +/** Alias for memory allocation. */ +#define USBD_malloc (void *)USBD_static_malloc + +/** Alias for memory release. */ +#define USBD_free USBD_static_free + +/** Alias for memory set. */ +#define USBD_memset memset + +/** Alias for memory copy. */ +#define USBD_memcpy memcpy + +/** Alias for delay. */ +#define USBD_Delay HAL_Delay + +/* DEBUG macros */ + +#if (USBD_DEBUG_LEVEL > 0) +#define USBD_UsrLog(...) printf(__VA_ARGS__);\ + printf("\n"); +#else +#define USBD_UsrLog(...) +#endif + +#if (USBD_DEBUG_LEVEL > 1) + +#define USBD_ErrLog(...) printf("ERROR: ") ;\ + printf(__VA_ARGS__);\ + printf("\n"); +#else +#define USBD_ErrLog(...) +#endif + +#if (USBD_DEBUG_LEVEL > 2) +#define USBD_DbgLog(...) printf("DEBUG : ") ;\ + printf(__VA_ARGS__);\ + printf("\n"); +#else +#define USBD_DbgLog(...) +#endif + +void *USBD_static_malloc(uint32_t size); +void USBD_static_free(void *p); + + +#ifdef __cplusplus +} +#endif diff --git a/firmware/targets/f7/usb-glue/usbd_desc.c b/firmware/targets/f7/usb-glue/usbd_desc.c new file mode 100644 index 00000000..96cc2cda --- /dev/null +++ b/firmware/targets/f7/usb-glue/usbd_desc.c @@ -0,0 +1,206 @@ +#include "usbd_core.h" +#include "usbd_desc.h" +#include "usbd_conf.h" +#include "furi-hal-version.h" + +#define USBD_VID 1155 +#define USBD_LANGID_STRING 1033 +#define USBD_MANUFACTURER_STRING "Flipper Devices Inc." +#define USBD_PID 22336 +#define USBD_CONFIGURATION_STRING "CDC Config" +#define USBD_INTERFACE_STRING "CDC Interface" + +static void Get_SerialNum(void); +static void IntToUnicode(uint32_t value, uint8_t * pbuf, uint8_t len); + +uint8_t* USBD_CDC_DeviceDescriptor(USBD_SpeedTypeDef speed, uint16_t *length); +uint8_t* USBD_CDC_LangIDStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length); +uint8_t* USBD_CDC_ManufacturerStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length); +uint8_t* USBD_CDC_ProductStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length); +uint8_t* USBD_CDC_SerialStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length); +uint8_t* USBD_CDC_ConfigStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length); +uint8_t* USBD_CDC_InterfaceStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length); + +USBD_DescriptorsTypeDef CDC_Desc = { + USBD_CDC_DeviceDescriptor, + USBD_CDC_LangIDStrDescriptor, + USBD_CDC_ManufacturerStrDescriptor, + USBD_CDC_ProductStrDescriptor, + USBD_CDC_SerialStrDescriptor, + USBD_CDC_ConfigStrDescriptor, + USBD_CDC_InterfaceStrDescriptor +}; + +/** USB standard device descriptor. */ +__ALIGN_BEGIN uint8_t USBD_CDC_DeviceDesc[USB_LEN_DEV_DESC] __ALIGN_END = { + 0x12, /*bLength */ + USB_DESC_TYPE_DEVICE, /*bDescriptorType*/ + 0x00, /*bcdUSB */ + 0x02, + 0x02, /*bDeviceClass*/ + 0x02, /*bDeviceSubClass*/ + 0x00, /*bDeviceProtocol*/ + USB_MAX_EP0_SIZE, /*bMaxPacketSize*/ + LOBYTE(USBD_VID), /*idVendor*/ + HIBYTE(USBD_VID), /*idVendor*/ + LOBYTE(USBD_PID), /*idProduct*/ + HIBYTE(USBD_PID), /*idProduct*/ + 0x00, /*bcdDevice rel. 2.00*/ + 0x02, + USBD_IDX_MFC_STR, /*Index of manufacturer string*/ + USBD_IDX_PRODUCT_STR, /*Index of product string*/ + USBD_IDX_SERIAL_STR, /*Index of serial number string*/ + USBD_MAX_NUM_CONFIGURATION /*bNumConfigurations*/ +}; + +/* USB_DeviceDescriptor */ + +/** USB lang indentifier descriptor. */ +__ALIGN_BEGIN uint8_t USBD_LangIDDesc[USB_LEN_LANGID_STR_DESC] __ALIGN_END = { + USB_LEN_LANGID_STR_DESC, + USB_DESC_TYPE_STRING, + LOBYTE(USBD_LANGID_STRING), + HIBYTE(USBD_LANGID_STRING) +}; + +/* Internal string descriptor. */ +__ALIGN_BEGIN uint8_t USBD_StrDesc[USBD_MAX_STR_DESC_SIZ] __ALIGN_END; + +__ALIGN_BEGIN uint8_t USBD_StringSerial[USB_SIZ_STRING_SERIAL] __ALIGN_END = { + USB_SIZ_STRING_SERIAL, + USB_DESC_TYPE_STRING, +}; + +/** Return the device descriptor + * @param speed : Current device speed + * @param length : Pointer to data length variable + * @retval Pointer to descriptor buffer + */ +uint8_t * USBD_CDC_DeviceDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) { + UNUSED(speed); + *length = sizeof(USBD_CDC_DeviceDesc); + return USBD_CDC_DeviceDesc; +} + +/** Return the LangID string descriptor + * @param speed : Current device speed + * @param length : Pointer to data length variable + * @retval Pointer to descriptor buffer + */ +uint8_t * USBD_CDC_LangIDStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) { + UNUSED(speed); + *length = sizeof(USBD_LangIDDesc); + return USBD_LangIDDesc; +} + +/** Return the product string descriptor + * @param speed : Current device speed + * @param length : Pointer to data length variable + * @retval Pointer to descriptor buffer + */ +uint8_t * USBD_CDC_ProductStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) { + USBD_GetString((uint8_t*)furi_hal_version_get_device_name_ptr(), USBD_StrDesc, length); + return USBD_StrDesc; +} + +/** Return the manufacturer string descriptor + * @param speed : Current device speed + * @param length : Pointer to data length variable + * @retval Pointer to descriptor buffer + */ +uint8_t * USBD_CDC_ManufacturerStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) { + UNUSED(speed); + USBD_GetString((uint8_t *)USBD_MANUFACTURER_STRING, USBD_StrDesc, length); + return USBD_StrDesc; +} + +/** Return the serial number string descriptor + * @param speed : Current device speed + * @param length : Pointer to data length variable + * @retval Pointer to descriptor buffer + */ +uint8_t * USBD_CDC_SerialStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) { + UNUSED(speed); + *length = USB_SIZ_STRING_SERIAL; + + /* Update the serial number string descriptor with the data from the unique + * ID */ + if(furi_hal_version_get_name_ptr()){ + char buffer[14] = "flip_"; + strncat(buffer, furi_hal_version_get_name_ptr(), 8); + USBD_GetString((uint8_t*) buffer, USBD_StringSerial, length); + } else { + Get_SerialNum(); + } + + return (uint8_t *) USBD_StringSerial; +} + +/** Return the configuration string descriptor + * @param speed : Current device speed + * @param length : Pointer to data length variable + * @retval Pointer to descriptor buffer + */ +uint8_t * USBD_CDC_ConfigStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) { + if(speed == USBD_SPEED_HIGH) { + USBD_GetString((uint8_t *)USBD_CONFIGURATION_STRING, USBD_StrDesc, length); + } else { + USBD_GetString((uint8_t *)USBD_CONFIGURATION_STRING, USBD_StrDesc, length); + } + return USBD_StrDesc; +} + +/** Return the interface string descriptor + * @param speed : Current device speed + * @param length : Pointer to data length variable + * @retval Pointer to descriptor buffer + */ +uint8_t * USBD_CDC_InterfaceStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) { + if(speed == 0) { + USBD_GetString((uint8_t *)USBD_INTERFACE_STRING, USBD_StrDesc, length); + } else { + USBD_GetString((uint8_t *)USBD_INTERFACE_STRING, USBD_StrDesc, length); + } + return USBD_StrDesc; +} + +/** Create the serial number string descriptor + * @param None + * @retval None + */ +static void Get_SerialNum(void) { + uint32_t deviceserial0, deviceserial1, deviceserial2; + + deviceserial0 = *(uint32_t *) DEVICE_ID1; + deviceserial1 = *(uint32_t *) DEVICE_ID2; + deviceserial2 = *(uint32_t *) DEVICE_ID3; + + deviceserial0 += deviceserial2; + + if (deviceserial0 != 0) { + IntToUnicode(deviceserial0, &USBD_StringSerial[2], 8); + IntToUnicode(deviceserial1, &USBD_StringSerial[18], 4); + } +} + +/** Convert Hex 32Bits value into char + * @param value: value to convert + * @param pbuf: pointer to the buffer + * @param len: buffer length + * @retval None + */ +static void IntToUnicode(uint32_t value, uint8_t * pbuf, uint8_t len) { + uint8_t idx = 0; + + for (idx = 0; idx < len; idx++) { + if (((value >> 28)) < 0xA) { + pbuf[2 * idx] = (value >> 28) + '0'; + } else { + pbuf[2 * idx] = (value >> 28) + 'A' - 10; + } + + value = value << 4; + + pbuf[2 * idx + 1] = 0; + } +} diff --git a/firmware/targets/f7/usb-glue/usbd_desc.h b/firmware/targets/f7/usb-glue/usbd_desc.h new file mode 100644 index 00000000..795b33e4 --- /dev/null +++ b/firmware/targets/f7/usb-glue/usbd_desc.h @@ -0,0 +1,19 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include "usbd_def.h" + +#define DEVICE_ID1 (UID_BASE) +#define DEVICE_ID2 (UID_BASE + 0x4) +#define DEVICE_ID3 (UID_BASE + 0x8) + +#define USB_SIZ_STRING_SERIAL 0x1E + +extern USBD_DescriptorsTypeDef CDC_Desc; + +#ifdef __cplusplus +} +#endif diff --git a/firmware/targets/furi-hal-include/furi-hal-rfid.h b/firmware/targets/furi-hal-include/furi-hal-rfid.h index d0a6aeaa..8c76d66d 100644 --- a/firmware/targets/furi-hal-include/furi-hal-rfid.h +++ b/firmware/targets/furi-hal-include/furi-hal-rfid.h @@ -7,6 +7,9 @@ extern "C" { #endif +/** Initialize RFID subsystem */ +void furi_hal_rfid_init(); + /** * @brief config rfid pins to reset state * diff --git a/scripts/otp.py b/scripts/otp.py index 999e2766..4b42f636 100755 --- a/scripts/otp.py +++ b/scripts/otp.py @@ -70,10 +70,10 @@ class Main: self.args.func() def _add_args(self, parser): - parser.add_argument("--version", type=int, help="Version", default=10) - parser.add_argument("--firmware", type=int, help="Firmware", default=6) - parser.add_argument("--body", type=int, help="Body", default=8) - parser.add_argument("--connect", type=int, help="Connect", default=5) + parser.add_argument("--version", type=int, help="Version", default=11) + parser.add_argument("--firmware", type=int, help="Firmware", default=7) + parser.add_argument("--body", type=int, help="Body", default=9) + parser.add_argument("--connect", type=int, help="Connect", default=6) parser.add_argument("--color", type=str, help="Color", default="unknown") parser.add_argument("--region", type=str, help="Region", default="unknown") parser.add_argument("--name", type=str, help="Name", required=True) From a0d2e4c6a40635b5f51e9ed235939d2a30b1a396 Mon Sep 17 00:00:00 2001 From: Anna Prosvetova Date: Fri, 10 Sep 2021 15:05:09 +0300 Subject: [PATCH 08/13] CI: Fix quick flash link (#697) * CI: Fix quick flash link * CI: Fix default target var --- .github/workflows/build.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 722c7711..70d7e6b9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,6 +11,7 @@ on: env: TARGETS: f6 f7 + DEFAULT_TARGET: f6 jobs: build: @@ -69,7 +70,7 @@ jobs: echo "::set-output name=artifacts-path::${BRANCH_OR_TAG}" echo "::set-output name=suffix::${SUFFIX}" echo "::set-output name=short-hash::${SHA}" - echo "::set-output name=latest-target::${TARGETS[${#TARGETS[@]}-1]}" + echo "::set-output name=default-target::${DEFAULT_TARGET}" - name: 'Build bootloader in docker' uses: ./.github/actions/docker @@ -205,7 +206,7 @@ jobs: with: args: -X POST -F 'key=${{ secrets.REINDEX_KEY }}' ${{ secrets.REINDEX_URL }} - - name: Find Previous Comment + - name: 'Find Previous Comment' if: ${{ !github.event.pull_request.head.repo.fork && github.event.pull_request }} uses: peter-evans/find-comment@v1 id: fc @@ -214,12 +215,12 @@ jobs: comment-author: 'github-actions[bot]' body-includes: 'to flash the' - - name: Create or update comment + - name: 'Create or update comment' if: ${{ !github.event.pull_request.head.repo.fork && github.event.pull_request}} uses: peter-evans/create-or-update-comment@v1 with: comment-id: ${{ steps.fc.outputs.comment-id }} issue-number: ${{ github.event.pull_request.number }} body: | - [Click here](https://update.flipperzero.one/?url=https://update.flipperzero.one/builds/firmware/${{steps.names.outputs.artifacts-path}}/flipper-z-${{steps.names.outputs.latest-target}}-full-${{steps.names.outputs.suffix}}.dfu&channel=${{steps.names.outputs.artifacts-path}}&version=${{steps.names.outputs.short-hash}}) to flash the `${{steps.names.outputs.short-hash}}` version of this branch via WebUSB. + [Click here](https://update.flipperzero.one/?url=https://update.flipperzero.one/builds/firmware/${{steps.names.outputs.artifacts-path}}/flipper-z-${{steps.names.outputs.default-target}}-full-${{steps.names.outputs.suffix}}.dfu&channel=${{steps.names.outputs.artifacts-path}}&version=${{steps.names.outputs.short-hash}}) to flash the `${{steps.names.outputs.short-hash}}` version of this branch via WebUSB. edit-mode: replace From a4dae290e24ac8323a55cfc5c389184e425005b9 Mon Sep 17 00:00:00 2001 From: its your bedtime <23366927+itsyourbedtime@users.noreply.github.com> Date: Fri, 10 Sep 2021 20:06:34 +0300 Subject: [PATCH 09/13] [FL-1803] Archive: fix update_offset logic #695 --- applications/archive/views/archive_main_view.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/applications/archive/views/archive_main_view.c b/applications/archive/views/archive_main_view.c index 826a7483..ab2e11d7 100644 --- a/applications/archive/views/archive_main_view.c +++ b/applications/archive/views/archive_main_view.c @@ -41,7 +41,6 @@ void archive_browser_set_callback( void update_offset(ArchiveMainView* main_view) { furi_assert(main_view); - with_view_model( main_view->view, (ArchiveMainViewModel * model) { size_t array_size = files_array_size(model->files); @@ -50,7 +49,7 @@ void update_offset(ArchiveMainView* main_view) { if(array_size > 3 && model->idx >= array_size - 1) { model->list_offset = model->idx - 3; } else if(model->list_offset < model->idx - bounds) { - model->list_offset = CLAMP(model->list_offset + 1, array_size - bounds, 0); + model->list_offset = CLAMP(model->idx - 2, array_size - bounds, 0); } else if(model->list_offset > model->idx - bounds) { model->list_offset = CLAMP(model->idx - 1, array_size - bounds, 0); } From 202c1d4b0ecf4c352c0db937e676ec6af80b51af Mon Sep 17 00:00:00 2001 From: rusdacent <57439765+rusdacent@users.noreply.github.com> Date: Mon, 13 Sep 2021 04:44:02 +0300 Subject: [PATCH 10/13] Improved reliability of shell scripts (#699) * Add double quotes for shell variables * Added exit for cd command. Prevent run commands after incorrect change directory. --- docker/syntax_check.sh | 4 ++-- scripts/flash_core1_main_swd.sh | 8 ++++---- scripts/flash_core2_ble_swd.sh | 6 +++--- scripts/flash_otp_version_dfu.sh | 4 ++-- scripts/flash_otp_version_swd.sh | 4 ++-- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/docker/syntax_check.sh b/docker/syntax_check.sh index 0bd3466a..47fb095a 100755 --- a/docker/syntax_check.sh +++ b/docker/syntax_check.sh @@ -6,7 +6,7 @@ CLANG_FORMAT_BIN="/usr/bin/clang-format-12" PROJECT_DIR=$(pwd) -cd $PROJECT_DIR +cd "$PROJECT_DIR" || exit echo "RUN C\C++ SYNTAX CHECK" C_FILES=$(find . \ @@ -34,7 +34,7 @@ fi read -p "Do you want fix syntax? (y/n): " confirm && [[ $confirm == [yY] || $confirm == [yY][eE][sS] ]] || exit 1 -cd $PROJECT_DIR +cd "$PROJECT_DIR" || exit # We use root in container and clang-format rewriting files. We'll need change owner to original local_user=$(stat -c '%u' .clang-format) diff --git a/scripts/flash_core1_main_swd.sh b/scripts/flash_core1_main_swd.sh index 9e54e6e9..8a159df9 100755 --- a/scripts/flash_core1_main_swd.sh +++ b/scripts/flash_core1_main_swd.sh @@ -5,8 +5,8 @@ set -x -e SCRIPT_DIR="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" PROJECT_DIR="$(dirname "$SCRIPT_DIR")" -rm $PROJECT_DIR/bootloader/.obj/f*/flash || true -make -C $PROJECT_DIR/bootloader -j9 flash +rm "$PROJECT_DIR"/bootloader/.obj/f*/flash || true +make -C "$PROJECT_DIR"/bootloader -j9 flash -rm $PROJECT_DIR/firmware/.obj/f*/flash || true -make -C $PROJECT_DIR/firmware -j9 flash +rm "$PROJECT_DIR"/firmware/.obj/f*/flash || true +make -C "$PROJECT_DIR"/firmware -j9 flash diff --git a/scripts/flash_core2_ble_swd.sh b/scripts/flash_core2_ble_swd.sh index 1f04ba81..71ea713f 100755 --- a/scripts/flash_core2_ble_swd.sh +++ b/scripts/flash_core2_ble_swd.sh @@ -6,15 +6,15 @@ SCRIPT_DIR="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" PROJECT_DIR="$(dirname "$SCRIPT_DIR")" COPRO_DIR="$PROJECT_DIR/lib/STM32CubeWB/Projects/STM32WB_Copro_Wireless_Binaries/STM32WB5x" -STM32_Programmer_CLI -c port=swd -fwupgrade $COPRO_DIR/stm32wb5x_FUS_fw_for_fus_0_5_3.bin 0x080EC000 || true +STM32_Programmer_CLI -c port=swd -fwupgrade "$COPRO_DIR"/stm32wb5x_FUS_fw_for_fus_0_5_3.bin 0x080EC000 || true STM32_Programmer_CLI -c port=swd -STM32_Programmer_CLI -c port=swd -fwupgrade $COPRO_DIR/stm32wb5x_FUS_fw.bin 0x080EC000 || true +STM32_Programmer_CLI -c port=swd -fwupgrade "$COPRO_DIR"/stm32wb5x_FUS_fw.bin 0x080EC000 || true STM32_Programmer_CLI -c port=swd STM32_Programmer_CLI -c port=swd -fwdelete -STM32_Programmer_CLI -c port=swd -fwupgrade $COPRO_DIR/stm32wb5x_BLE_Stack_full_fw.bin 0x080CA000 firstinstall=0 +STM32_Programmer_CLI -c port=swd -fwupgrade "$COPRO_DIR"/stm32wb5x_BLE_Stack_full_fw.bin 0x080CA000 firstinstall=0 STM32_Programmer_CLI -c port=swd -ob nSWBOOT0=1 nBOOT0=1 diff --git a/scripts/flash_otp_version_dfu.sh b/scripts/flash_otp_version_dfu.sh index 0a9526d4..014f8883 100755 --- a/scripts/flash_otp_version_dfu.sh +++ b/scripts/flash_otp_version_dfu.sh @@ -7,11 +7,11 @@ if [ "$#" -ne 1 ]; then exit fi -if [ ! -f $1 ]; then +if [ ! -f "$1" ]; then echo "Unable to open OTP file" exit fi -STM32_Programmer_CLI -c port=usb1 -d $1 0x1FFF7000 +STM32_Programmer_CLI -c port=usb1 -d "$1" 0x1FFF7000 STM32_Programmer_CLI -c port=usb1 -r8 0x1FFF7000 8 diff --git a/scripts/flash_otp_version_swd.sh b/scripts/flash_otp_version_swd.sh index 1bfe1411..84e8dd71 100755 --- a/scripts/flash_otp_version_swd.sh +++ b/scripts/flash_otp_version_swd.sh @@ -7,11 +7,11 @@ if [ "$#" -ne 1 ]; then exit fi -if [ ! -f $1 ]; then +if [ ! -f "$1" ]; then echo "Unable to open OTP file" exit fi -STM32_Programmer_CLI -c port=swd -d $1 0x1FFF7000 +STM32_Programmer_CLI -c port=swd -d "$1" 0x1FFF7000 STM32_Programmer_CLI -c port=swd -r8 0x1FFF7000 8 From 4456982e2767f6754587e5981bd87d28bfcded42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Mon, 13 Sep 2021 12:52:50 +0300 Subject: [PATCH 11/13] [FL-1699, FL-1700] Scripts: new radio firmware bundling scheme, manifest for resources. (#700) * Scripts: new radio firmware bundling scheme, manifest for resources. * Scripts: add destination address for copro binaries. * Bootloader: update linker scripts * Scripts: resource manifest FsTree. --- .github/workflows/build.yml | 8 +- assets/Makefile | 2 +- .../targets/f6/stm32wb55xx_flash_cm4.ld | 2 +- .../targets/f7/stm32wb55xx_flash_cm4.ld | 2 +- scripts/assets.py | 59 +++++- scripts/flipper/copro.py | 95 ++++++++++ scripts/flipper/fstree.py | 76 ++++++++ scripts/flipper/manifest.py | 168 ++++++++++++++++++ scripts/flipper/utils.py | 27 +++ 9 files changed, 424 insertions(+), 15 deletions(-) create mode 100644 scripts/flipper/copro.py create mode 100644 scripts/flipper/fstree.py create mode 100644 scripts/flipper/manifest.py create mode 100644 scripts/flipper/utils.py diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 70d7e6b9..1bd8c243 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -170,12 +170,7 @@ jobs: run: | test -d core2_firmware && rm -rf core2_firmware || true mkdir core2_firmware - cp \ - lib/STM32CubeWB/package.xml \ - lib/STM32CubeWB/Projects/STM32WB_Copro_Wireless_Binaries/STM32WB5x/stm32wb5x_FUS_fw.bin \ - lib/STM32CubeWB/Projects/STM32WB_Copro_Wireless_Binaries/STM32WB5x/stm32wb5x_FUS_fw_for_fus_0_5_3.bin \ - lib/STM32CubeWB/Projects/STM32WB_Copro_Wireless_Binaries/STM32WB5x/stm32wb5x_BLE_Stack_full_fw.bin \ - core2_firmware + ./scripts/assets.py copro lib/STM32CubeWB core2_firmware STM32WB5x tar czpf artifacts/flipper-z-any-core2_firmware-${{steps.names.outputs.suffix}}.tgz core2_firmware - name: 'Bundle scripts' @@ -186,6 +181,7 @@ jobs: - name: 'Bundle resources' if: ${{ !github.event.pull_request.head.repo.fork }} run: | + ./scripts/assets.py manifest assets/resources tar czpf artifacts/flipper-z-any-resources-${{steps.names.outputs.suffix}}.tgz -C assets resources - name: 'Upload artifacts to update server' diff --git a/assets/Makefile b/assets/Makefile index ab6fe4f3..1a379af5 100644 --- a/assets/Makefile +++ b/assets/Makefile @@ -4,7 +4,7 @@ include $(PROJECT_ROOT)/assets/assets.mk $(ASSETS): $(ASSETS_SOURCES) $(ASSETS_COMPILLER) @echo "\tASSETS\t" $@ - @$(ASSETS_COMPILLER) icons -s $(ASSETS_SOURCE_DIR) -o $(ASSETS_COMPILED_DIR) + @$(ASSETS_COMPILLER) icons "$(ASSETS_SOURCE_DIR)" "$(ASSETS_COMPILED_DIR)" clean: @echo "\tCLEAN\t" diff --git a/bootloader/targets/f6/stm32wb55xx_flash_cm4.ld b/bootloader/targets/f6/stm32wb55xx_flash_cm4.ld index 41d36b11..fdcda4ac 100644 --- a/bootloader/targets/f6/stm32wb55xx_flash_cm4.ld +++ b/bootloader/targets/f6/stm32wb55xx_flash_cm4.ld @@ -56,7 +56,7 @@ _Min_Stack_Size = 0x400; /* required amount of stack */ MEMORY { FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 32K -RAM1 (xrw) : ORIGIN = 0x20000004, LENGTH = 0x2FFFC +RAM1 (xrw) : ORIGIN = 0x20000008, LENGTH = 0x2FFF8 RAM_SHARED (xrw) : ORIGIN = 0x20030000, LENGTH = 10K } diff --git a/bootloader/targets/f7/stm32wb55xx_flash_cm4.ld b/bootloader/targets/f7/stm32wb55xx_flash_cm4.ld index 41d36b11..fdcda4ac 100644 --- a/bootloader/targets/f7/stm32wb55xx_flash_cm4.ld +++ b/bootloader/targets/f7/stm32wb55xx_flash_cm4.ld @@ -56,7 +56,7 @@ _Min_Stack_Size = 0x400; /* required amount of stack */ MEMORY { FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 32K -RAM1 (xrw) : ORIGIN = 0x20000004, LENGTH = 0x2FFFC +RAM1 (xrw) : ORIGIN = 0x20000008, LENGTH = 0x2FFF8 RAM_SHARED (xrw) : ORIGIN = 0x20030000, LENGTH = 10K } diff --git a/scripts/assets.py b/scripts/assets.py index 154c360f..bb8f9724 100755 --- a/scripts/assets.py +++ b/scripts/assets.py @@ -34,13 +34,24 @@ class Main: self.parser_icons = self.subparsers.add_parser( "icons", help="Process icons and build icon registry" ) - self.parser_icons.add_argument( - "-s", "--source-directory", help="Source directory" - ) - self.parser_icons.add_argument( - "-o", "--output-directory", help="Output directory" - ) + self.parser_icons.add_argument("source_directory", help="Source directory") + self.parser_icons.add_argument("output_directory", help="Output directory") self.parser_icons.set_defaults(func=self.icons) + + self.parser_manifest = self.subparsers.add_parser( + "manifest", help="Create directory Manifest" + ) + self.parser_manifest.add_argument("local_path", help="local_path") + self.parser_manifest.set_defaults(func=self.manifest) + + self.parser_copro = self.subparsers.add_parser( + "copro", help="Gather copro binaries for packaging" + ) + self.parser_copro.add_argument("cube_dir", help="Path to Cube folder") + self.parser_copro.add_argument("output_dir", help="Path to output folder") + self.parser_copro.add_argument("mcu", help="MCU series as in copro folder") + self.parser_copro.set_defaults(func=self.copro) + # logging self.logger = logging.getLogger() @@ -163,6 +174,42 @@ class Main: extension = filename.lower().split(".")[-1] return extension in ICONS_SUPPORTED_FORMATS + def manifest(self): + from flipper.manifest import Manifest + + directory_path = os.path.normpath(self.args.local_path) + if not os.path.isdir(directory_path): + self.logger.error(f'"{directory_path}" is not a directory') + exit(255) + manifest_file = os.path.join(directory_path, "Manifest") + old_manifest = Manifest() + if os.path.exists(manifest_file): + self.logger.info( + f"old manifest is present, loading for compare and removing file" + ) + old_manifest.load(manifest_file) + os.unlink(manifest_file) + self.logger.info(f'Creating new Manifest for directory "{directory_path}"') + new_manifest = Manifest() + new_manifest.create(directory_path) + new_manifest.save(manifest_file) + self.logger.info(f"Comparing new manifest with old") + only_in_old, changed, only_in_new = Manifest.compare(old_manifest, new_manifest) + for record in only_in_old: + self.logger.info(f"Only in old: {record}") + for record in changed: + self.logger.info(f"Changed: {record}") + for record in only_in_new: + self.logger.info(f"Only in new: {record}") + self.logger.info(f"Complete") + + def copro(self): + from flipper.copro import Copro + + copro = Copro(self.args.mcu) + copro.loadCubeInfo(self.args.cube_dir) + copro.bundle(self.args.output_dir) + if __name__ == "__main__": Main()() diff --git a/scripts/flipper/copro.py b/scripts/flipper/copro.py new file mode 100644 index 00000000..bb1b40f7 --- /dev/null +++ b/scripts/flipper/copro.py @@ -0,0 +1,95 @@ +import logging +import datetime +import shutil +import json + +import xml.etree.ElementTree as ET +from .utils import * + +CUBE_COPRO_PATH = "Projects/STM32WB_Copro_Wireless_Binaries" + +MANIFEST_TEMPLATE = { + "manifest": {"version": 0, "timestamp": 0}, + "copro": { + "fus": {"version": {"major": 1, "minor": 2, "sub": 0}, "files": []}, + "radio": { + "version": { + "type": 1, + "major": 1, + "minor": 12, + "sub": 0, + "branch": 0, + "release": 7, + }, + "files": [], + }, + }, +} + + +class Copro: + def __init__(self, mcu): + self.mcu = mcu + self.version = None + self.cube_dir = None + self.mcu_copro = None + self.logger = logging.getLogger(self.__class__.__name__) + + def loadCubeInfo(self, cube_dir): + if not os.path.isdir(cube_dir): + raise Exception(f'"{cube_dir}" doesn\'t exists') + self.cube_dir = cube_dir + self.mcu_copro = os.path.join(self.cube_dir, CUBE_COPRO_PATH, self.mcu) + if not os.path.isdir(self.mcu_copro): + raise Exception(f'"{self.mcu_copro}" doesn\'t exists') + cube_manifest_file = os.path.join(self.cube_dir, "package.xml") + cube_manifest = ET.parse(cube_manifest_file) + cube_version = cube_manifest.find("PackDescription") + if not cube_version: + raise Exception(f"Unknown Cube manifest format") + cube_version = cube_version.get("Release") + if not cube_version or not cube_version.startswith("FW.WB"): + raise Exception(f"Incorrect Cube package or version info") + cube_version = cube_version.replace("FW.WB.", "", 1) + if cube_version != "1.12.0": + raise Exception(f"Unknonwn cube version") + self.version = cube_version + + def addFile(self, array, filename, **kwargs): + source_file = os.path.join(self.mcu_copro, filename) + destination_file = os.path.join(self.output_dir, filename) + shutil.copyfile(source_file, destination_file) + array.append( + {"name": filename, "sha256": file_sha256(destination_file), **kwargs} + ) + + def bundle(self, output_dir): + if not os.path.isdir(output_dir): + raise Exception(f'"{output_dir}" doesn\'t exists') + self.output_dir = output_dir + manifest_file = os.path.join(self.output_dir, "Manifest.json") + # Form Manifest + manifest = dict(MANIFEST_TEMPLATE) + manifest["manifest"]["timestamp"] = timestamp() + # Old FUS Update + self.addFile( + manifest["copro"]["fus"]["files"], + "stm32wb5x_FUS_fw_for_fus_0_5_3.bin", + condition="==0.5.3", + address="0x080EC000", + ) + # New FUS Update + self.addFile( + manifest["copro"]["fus"]["files"], + "stm32wb5x_FUS_fw.bin", + condition=">0.5.3", + address="0x080EC000", + ) + # BLE Full Stack + self.addFile( + manifest["copro"]["radio"]["files"], + "stm32wb5x_BLE_Stack_full_fw.bin", + address="0x080CA000", + ) + # Save manifest to + json.dump(manifest, open(manifest_file, "w")) diff --git a/scripts/flipper/fstree.py b/scripts/flipper/fstree.py new file mode 100644 index 00000000..c42b4aa6 --- /dev/null +++ b/scripts/flipper/fstree.py @@ -0,0 +1,76 @@ +from enum import Enum +from collections import OrderedDict + + +class FsNode: + class Type(Enum): + File = 0 + Directory = 1 + + def __init__(self, name: str, type: "FsNode.Type", **kwargs): + self.name = name + self.type = type + self.data = kwargs + self.parent = None + self.children = OrderedDict() + + def addChild(self, node: "FsNode"): + self.children[node.name] = node + node.parent = self + + def addDirectory(self, path): + fragments = path.split("/") + name = fragments[-1] + fragments = fragments[:-1] + parent_node = self.traverse(fragments) + if not parent_node: + raise Exception(f"No parent node found for: {path}") + parent_node.addChild(FsNode(name, FsNode.Type.Directory)) + + def addFile(self, path, md5, size): + fragments = path.split("/") + name = fragments[-1] + fragments = fragments[:-1] + parent_node = self.traverse(fragments) + if not parent_node: + raise Exception(f"No parent node found for: {path}") + parent_node.addChild(FsNode(name, FsNode.Type.File, md5=md5, size=size)) + + def getChild(self, name): + return self.children[name] + + def traverse(self, fragments): + current = self + for fragment in fragments: + current = current.getChild(fragment) + if not current: + break + return current + + def getPath(self): + fragments = [] + current = self + while current.parent: + fragments.append(current.name) + current = current.parent + return "/".join(reversed(fragments)) + + def dump(self): + ret = {} + ret["name"] = (self.name,) + ret["type"] = (self.type,) + ret["path"] = (self.getPath(),) + if len(self.children): + ret["children"] = [node.dump() for node in self.children.values()] + return ret + + +def compare_fs_trees(left: FsNode, right: FsNode): + # import pprint + # pprint.pprint(left.dump()) + # pprint.pprint(right.dump()) + + only_in_left = [] + changed = [] + only_in_right = [] + return [], [], [] diff --git a/scripts/flipper/manifest.py b/scripts/flipper/manifest.py new file mode 100644 index 00000000..878e4c02 --- /dev/null +++ b/scripts/flipper/manifest.py @@ -0,0 +1,168 @@ +import datetime +import logging +import os + +from .utils import * +from .fstree import * + +MANIFEST_VERSION = 0 + + +class ManifestRecord: + tag = None + + @staticmethod + def fromLine(line): + raise NotImplementedError + + def toLine(self): + raise NotImplementedError + + def _unpack(self, manifest, key, type): + key, value = manifest.readline().split(":", 1) + assert key == key + return type(value) + + +MANIFEST_TAGS_RECORDS = {} + + +def addManifestRecord(record: ManifestRecord): + assert record.tag + MANIFEST_TAGS_RECORDS[record.tag] = record + + +class ManifestRecordVersion(ManifestRecord): + tag = "V" + + def __init__(self, version): + self.version = version + + @staticmethod + def fromLine(line): + return ManifestRecordVersion(int(line)) + + def toLine(self): + return f"{self.tag}:{self.version}\n" + + +addManifestRecord(ManifestRecordVersion) + + +class ManifestRecordTimestamp(ManifestRecord): + tag = "T" + + def __init__(self, timestamp: int): + self.timestamp = int(timestamp) + + @staticmethod + def fromLine(line): + return ManifestRecordTimestamp(int(line)) + + def toLine(self): + return f"{self.tag}:{self.timestamp}\n" + + +addManifestRecord(ManifestRecordTimestamp) + + +class ManifestRecordDirectory(ManifestRecord): + tag = "D" + + def __init__(self, path: str): + self.path = path + + @staticmethod + def fromLine(line): + return ManifestRecordDirectory(line) + + def toLine(self): + return f"{self.tag}:{self.path}\n" + + +addManifestRecord(ManifestRecordDirectory) + + +class ManifestRecordFile(ManifestRecord): + tag = "F" + + def __init__(self, path: str, md5: str, size: int): + self.path = path + self.md5 = md5 + self.size = size + + @staticmethod + def fromLine(line): + data = line.split(":", 3) + return ManifestRecordFile(data[2], data[0], data[1]) + + def toLine(self): + return f"{self.tag}:{self.md5}:{self.size}:{self.path}\n" + + +addManifestRecord(ManifestRecordFile) + + +class Manifest: + def __init__(self): + self.version = None + self.records = [] + self.records.append(ManifestRecordVersion(MANIFEST_VERSION)) + self.records.append(ManifestRecordTimestamp(timestamp())) + self.logger = logging.getLogger(self.__class__.__name__) + + def load(self, filename): + manifest = open(filename, "r") + for line in manifest.readlines(): + line = line.strip() + if len(line) == 0: + continue + tag, line = line.split(":", 1) + record = MANIFEST_TAGS_RECORDS[tag].fromLine(line) + self.records.append(record) + + def save(self, filename): + manifest = open(filename, "w+") + for record in self.records: + manifest.write(record.toLine()) + manifest.close() + + def addDirectory(self, path): + self.records.append(ManifestRecordDirectory(path)) + + def addFile(self, path, md5, size): + self.records.append(ManifestRecordFile(path, md5, size)) + + def create(self, directory_path): + for root, dirs, files in os.walk(directory_path): + relative_root = root.replace(directory_path, "", 1) + if relative_root.startswith("/"): + relative_root = relative_root[1:] + # process directories + for dir in dirs: + relative_dir_path = os.path.join(relative_root, dir) + self.logger.info(f'Adding directory: "{relative_dir_path}"') + self.addDirectory(relative_dir_path) + # Process files + for file in files: + relative_file_path = os.path.join(relative_root, file) + full_file_path = os.path.join(root, file) + self.logger.info(f'Adding file: "{relative_file_path}"') + self.addFile( + relative_file_path, + file_md5(full_file_path), + os.path.getsize(full_file_path), + ) + + def toFsTree(self): + root = FsNode("", FsNode.Type.Directory) + for record in self.records: + if isinstance(record, ManifestRecordDirectory): + root.addDirectory(record.path) + elif isinstance(record, ManifestRecordFile): + root.addFile(record.path, record.md5, record.size) + return root + + @staticmethod + def compare(left: "Manifest", right: "Manifest"): + return compare_fs_trees(left.toFsTree(), right.toFsTree()) diff --git a/scripts/flipper/utils.py b/scripts/flipper/utils.py new file mode 100644 index 00000000..056d4502 --- /dev/null +++ b/scripts/flipper/utils.py @@ -0,0 +1,27 @@ +import datetime +import hashlib +import os + + +def timestamp(): + return int(datetime.datetime.now().timestamp()) + + +def file_hash(path: str, algo: str, block_size: int = 4096): + fd = open(path, "rb") + h = hashlib.new(algo) + while True: + data = fd.read(block_size) + if len(data) > 0: + h.update(data) + else: + break + return h.hexdigest() + + +def file_md5(path, block_size=4096): + return file_hash(path, "md5", block_size) + + +def file_sha256(path, block_size=4096): + return file_hash(path, "sha256", block_size) From 95d9140d2458b1fd471627c49ef0ecc1faf9c68e Mon Sep 17 00:00:00 2001 From: gornekich Date: Mon, 13 Sep 2021 14:25:37 +0300 Subject: [PATCH 12/13] [FL-1795] BLE GAP refactoring (#694) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ble: remove heart rate profile * ble-glue: delete dead code * ble-glue: dis refactoring * ble-glue: add battery service * broken ble_common refactoring * ble-glue: advertise 128 bit service uid * ble-glue: remove dead code * ble: advertise service 16 bit uid depending on flipper color * ble-glue: remove debug * ble: intriduce serial service * ble: serial over ble * bt: serial echo server * bt: serial service process indicate acknowledge * bt: serial service event handler update * bt: refactore battery service * bt: add battery level apdate API * power: update battery level on change * bt: refactore device information service * app_ble: pairing configuration * bt: display pin code * bt: refactor battery service * bt: refactor device info service * bt: change advertise timer to freertos one * bt: separate app_ble to hci and gap * bt: increase max ble packet size * gap: refactoring * bt: refactor serial service * bt: support f7 target * bt: not blocking pin code show request Co-authored-by: Anna Prosvetova Co-authored-by: あく --- applications/bt/bt_service/bt.c | 25 +- applications/bt/bt_service/bt.h | 4 +- applications/bt/bt_service/bt_api.c | 15 + applications/bt/bt_service/bt_i.h | 6 + firmware/targets/f6/ble-glue/app_ble.c | 642 +----------------- firmware/targets/f6/ble-glue/app_ble.h | 13 - firmware/targets/f6/ble-glue/app_conf.h | 2 +- .../targets/f6/ble-glue/battery_service.c | 45 +- .../targets/f6/ble-glue/battery_service.h | 4 +- .../targets/f6/ble-glue/dev_info_service.c | 121 ++-- .../targets/f6/ble-glue/dev_info_service.h | 3 +- firmware/targets/f6/ble-glue/gap.c | 387 +++++++++++ firmware/targets/f6/ble-glue/gap.h | 22 + firmware/targets/f6/ble-glue/serial_service.c | 66 +- firmware/targets/f6/ble-glue/serial_service.h | 8 +- firmware/targets/f6/furi-hal/furi-hal-bt.c | 3 +- firmware/targets/f7/ble-glue/app_ble.c | 642 +----------------- firmware/targets/f7/ble-glue/app_ble.h | 13 - firmware/targets/f7/ble-glue/app_conf.h | 2 +- .../targets/f7/ble-glue/battery_service.c | 45 +- .../targets/f7/ble-glue/battery_service.h | 4 +- .../targets/f7/ble-glue/dev_info_service.c | 121 ++-- .../targets/f7/ble-glue/dev_info_service.h | 3 +- firmware/targets/f7/ble-glue/gap.c | 387 +++++++++++ firmware/targets/f7/ble-glue/gap.h | 22 + firmware/targets/f7/ble-glue/serial_service.c | 66 +- firmware/targets/f7/ble-glue/serial_service.h | 8 +- firmware/targets/f7/furi-hal/furi-hal-bt.c | 3 +- 28 files changed, 1197 insertions(+), 1485 deletions(-) create mode 100755 applications/bt/bt_service/bt_api.c create mode 100644 firmware/targets/f6/ble-glue/gap.c create mode 100644 firmware/targets/f6/ble-glue/gap.h create mode 100644 firmware/targets/f7/ble-glue/gap.c create mode 100644 firmware/targets/f7/ble-glue/gap.h 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) { From 3db456da9851db40b2096c3538a2db9cfec08e7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Wed, 15 Sep 2021 17:40:09 +0300 Subject: [PATCH 13/13] [FL-1811] FuriHal: move core2 startup to hal init stage, prevent working with flash controller till core2 startup finish. #704 --- applications/bt/bt_service/bt.c | 1 - firmware/targets/f6/ble-glue/app_entry.c | 2 ++ firmware/targets/f6/furi-hal/furi-hal-bt.c | 30 ++++++++++------------ firmware/targets/f6/furi-hal/furi-hal.c | 1 + firmware/targets/f7/ble-glue/app_entry.c | 2 ++ firmware/targets/f7/furi-hal/furi-hal-bt.c | 30 ++++++++++------------ firmware/targets/f7/furi-hal/furi-hal.c | 1 + 7 files changed, 32 insertions(+), 35 deletions(-) diff --git a/applications/bt/bt_service/bt.c b/applications/bt/bt_service/bt.c index 0c7dac90..09094d17 100755 --- a/applications/bt/bt_service/bt.c +++ b/applications/bt/bt_service/bt.c @@ -62,7 +62,6 @@ Bt* bt_alloc() { int32_t bt_srv() { Bt* bt = bt_alloc(); furi_record_create("bt", bt); - furi_hal_bt_init(); if(!furi_hal_bt_wait_startup()) { FURI_LOG_E(BT_SERVICE_TAG, "Core2 startup failed"); diff --git a/firmware/targets/f6/ble-glue/app_entry.c b/firmware/targets/f6/ble-glue/app_entry.c index f2367263..431fed6a 100644 --- a/firmware/targets/f6/ble-glue/app_entry.c +++ b/firmware/targets/f6/ble-glue/app_entry.c @@ -138,8 +138,10 @@ static void APPE_SysUserEvtRx( void * pPayload ) { // APPD_EnableCPU2( ); if (APP_BLE_Init()) { + FURI_LOG_I("Core2", "BLE stack started"); ble_glue_status = BleGlueStatusStarted; } else { + FURI_LOG_E("Core2", "BLE stack startup failed"); ble_glue_status = BleGlueStatusBroken; } furi_hal_power_insomnia_exit(); diff --git a/firmware/targets/f6/furi-hal/furi-hal-bt.c b/firmware/targets/f6/furi-hal/furi-hal-bt.c index 36bd1fa2..4d5e0674 100644 --- a/firmware/targets/f6/furi-hal/furi-hal-bt.c +++ b/firmware/targets/f6/furi-hal/furi-hal-bt.c @@ -46,7 +46,7 @@ bool furi_hal_bt_is_alive() { bool furi_hal_bt_wait_startup() { uint8_t counter = 0; - while (APPE_Status() == BleGlueStatusStartup) { + while (!(APPE_Status() == BleGlueStatusStarted || APPE_Status() == BleGlueStatusBroken)) { osDelay(10); counter++; if (counter > 1000) { @@ -60,27 +60,23 @@ bool furi_hal_bt_lock_flash() { if (!furi_hal_bt_wait_startup()) { return false; } - if (APPE_Status() == BleGlueStatusUninitialized) { - HAL_FLASH_Unlock(); - } else { - while (HAL_HSEM_FastTake(CFG_HW_FLASH_SEMID) != HAL_OK) { - osDelay(1); - } - SHCI_C2_FLASH_EraseActivity(ERASE_ACTIVITY_ON); - HAL_FLASH_Unlock(); - while(LL_FLASH_IsOperationSuspended()) {}; + + while (HAL_HSEM_FastTake(CFG_HW_FLASH_SEMID) != HAL_OK) { + osDelay(1); } + + SHCI_C2_FLASH_EraseActivity(ERASE_ACTIVITY_ON); + HAL_FLASH_Unlock(); + + while(LL_FLASH_IsOperationSuspended()) {}; + return true; } void furi_hal_bt_unlock_flash() { - if (APPE_Status() == BleGlueStatusUninitialized) { - HAL_FLASH_Lock(); - } else { - SHCI_C2_FLASH_EraseActivity(ERASE_ACTIVITY_OFF); - HAL_FLASH_Lock(); - HAL_HSEM_Release(CFG_HW_FLASH_SEMID, HSEM_CPU1_COREID); - } + SHCI_C2_FLASH_EraseActivity(ERASE_ACTIVITY_OFF); + HAL_FLASH_Lock(); + HAL_HSEM_Release(CFG_HW_FLASH_SEMID, HSEM_CPU1_COREID); } void furi_hal_bt_start_tone_tx(uint8_t channel, uint8_t power) { diff --git a/firmware/targets/f6/furi-hal/furi-hal.c b/firmware/targets/f6/furi-hal/furi-hal.c index eebe1423..2f0d850b 100644 --- a/firmware/targets/f6/furi-hal/furi-hal.c +++ b/firmware/targets/f6/furi-hal/furi-hal.c @@ -59,6 +59,7 @@ void furi_hal_init() { furi_hal_subghz_init(); furi_hal_nfc_init(); furi_hal_rfid_init(); + furi_hal_bt_init(); // FreeRTOS glue furi_hal_os_init(); diff --git a/firmware/targets/f7/ble-glue/app_entry.c b/firmware/targets/f7/ble-glue/app_entry.c index f2367263..431fed6a 100644 --- a/firmware/targets/f7/ble-glue/app_entry.c +++ b/firmware/targets/f7/ble-glue/app_entry.c @@ -138,8 +138,10 @@ static void APPE_SysUserEvtRx( void * pPayload ) { // APPD_EnableCPU2( ); if (APP_BLE_Init()) { + FURI_LOG_I("Core2", "BLE stack started"); ble_glue_status = BleGlueStatusStarted; } else { + FURI_LOG_E("Core2", "BLE stack startup failed"); ble_glue_status = BleGlueStatusBroken; } furi_hal_power_insomnia_exit(); diff --git a/firmware/targets/f7/furi-hal/furi-hal-bt.c b/firmware/targets/f7/furi-hal/furi-hal-bt.c index 36bd1fa2..4d5e0674 100644 --- a/firmware/targets/f7/furi-hal/furi-hal-bt.c +++ b/firmware/targets/f7/furi-hal/furi-hal-bt.c @@ -46,7 +46,7 @@ bool furi_hal_bt_is_alive() { bool furi_hal_bt_wait_startup() { uint8_t counter = 0; - while (APPE_Status() == BleGlueStatusStartup) { + while (!(APPE_Status() == BleGlueStatusStarted || APPE_Status() == BleGlueStatusBroken)) { osDelay(10); counter++; if (counter > 1000) { @@ -60,27 +60,23 @@ bool furi_hal_bt_lock_flash() { if (!furi_hal_bt_wait_startup()) { return false; } - if (APPE_Status() == BleGlueStatusUninitialized) { - HAL_FLASH_Unlock(); - } else { - while (HAL_HSEM_FastTake(CFG_HW_FLASH_SEMID) != HAL_OK) { - osDelay(1); - } - SHCI_C2_FLASH_EraseActivity(ERASE_ACTIVITY_ON); - HAL_FLASH_Unlock(); - while(LL_FLASH_IsOperationSuspended()) {}; + + while (HAL_HSEM_FastTake(CFG_HW_FLASH_SEMID) != HAL_OK) { + osDelay(1); } + + SHCI_C2_FLASH_EraseActivity(ERASE_ACTIVITY_ON); + HAL_FLASH_Unlock(); + + while(LL_FLASH_IsOperationSuspended()) {}; + return true; } void furi_hal_bt_unlock_flash() { - if (APPE_Status() == BleGlueStatusUninitialized) { - HAL_FLASH_Lock(); - } else { - SHCI_C2_FLASH_EraseActivity(ERASE_ACTIVITY_OFF); - HAL_FLASH_Lock(); - HAL_HSEM_Release(CFG_HW_FLASH_SEMID, HSEM_CPU1_COREID); - } + SHCI_C2_FLASH_EraseActivity(ERASE_ACTIVITY_OFF); + HAL_FLASH_Lock(); + HAL_HSEM_Release(CFG_HW_FLASH_SEMID, HSEM_CPU1_COREID); } void furi_hal_bt_start_tone_tx(uint8_t channel, uint8_t power) { diff --git a/firmware/targets/f7/furi-hal/furi-hal.c b/firmware/targets/f7/furi-hal/furi-hal.c index eebe1423..2f0d850b 100644 --- a/firmware/targets/f7/furi-hal/furi-hal.c +++ b/firmware/targets/f7/furi-hal/furi-hal.c @@ -59,6 +59,7 @@ void furi_hal_init() { furi_hal_subghz_init(); furi_hal_nfc_init(); furi_hal_rfid_init(); + furi_hal_bt_init(); // FreeRTOS glue furi_hal_os_init();