Furi: core refactoring and CMSIS removal part 2 (#1410)

* Furi: rename and move core
* Furi: drop CMSIS_OS header and unused api, partially refactor and cleanup the rest
* Furi: CMSIS_OS drop and refactoring.
* Furi: refactoring, remove cmsis legacy
* Furi: fix incorrect assert on queue deallocation, cleanup timer
* Furi: improve delay api, get rid of floats
* hal: dropped furi_hal_crc
* Furi: move DWT based delay to cortex HAL
* Furi: update core documentation

Co-authored-by: hedger <hedger@nanode.su>
This commit is contained in:
あく
2022-07-20 13:56:33 +03:00
committed by GitHub
parent f9c2287ea7
commit e3c7201a20
264 changed files with 2569 additions and 3883 deletions

View File

@@ -19,7 +19,8 @@ extern uint32_t SystemCoreClock;
#define configUSE_IDLE_HOOK 0
#define configUSE_TICK_HOOK 0
#define configCPU_CLOCK_HZ (SystemCoreClock)
#define configTICK_RATE_HZ ((TickType_t)1000)
#define configTICK_RATE_HZ_RAW 1000
#define configTICK_RATE_HZ ((TickType_t)configTICK_RATE_HZ_RAW)
#define configMAX_PRIORITIES (32)
#define configMINIMAL_STACK_SIZE ((uint16_t)128)
@@ -30,7 +31,7 @@ extern uint32_t SystemCoreClock;
#define configUSE_TRACE_FACILITY 1
#define configUSE_16_BIT_TICKS 0
#define configUSE_MUTEXES 1
#define configQUEUE_REGISTRY_SIZE 8
#define configQUEUE_REGISTRY_SIZE 0
#define configCHECK_FOR_STACK_OVERFLOW 2
#define configUSE_RECURSIVE_MUTEXES 1
#define configUSE_COUNTING_SEMAPHORES 1
@@ -129,7 +130,7 @@ See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
/* Normal assert() semantics without relying on the provision of an assert.h
header file. */
#ifdef DEBUG
#include <furi/check.h>
#include <core/check.h>
#define configASSERT(x) \
if((x) == 0) { \
furi_crash("FreeRTOS Assert"); \

View File

@@ -22,7 +22,7 @@
#ifndef STM32_ASSERT_H
#define STM32_ASSERT_H
#include <furi/check.h>
#include <core/check.h>
#ifdef __cplusplus
extern "C" {
@@ -49,4 +49,4 @@ extern "C" {
}
#endif
#endif /* STM32_ASSERT_H */
#endif /* STM32_ASSERT_H */

View File

@@ -37,7 +37,7 @@ int main() {
furi_hal_light_sequence("RGB");
// Delay is for button sampling
furi_hal_delay_ms(100);
furi_delay_ms(100);
FuriHalRtcBootMode boot_mode = furi_hal_rtc_get_boot_mode();
if(boot_mode == FuriHalRtcBootModeDfu || !furi_hal_gpio_read(&gpio_button_left)) {

View File

@@ -27,7 +27,6 @@ static bool flipper_update_init() {
furi_hal_clock_init();
furi_hal_rtc_init();
furi_hal_interrupt_init();
furi_hal_delay_init();
furi_hal_spi_init();

View File

@@ -32,7 +32,7 @@ extern "C" {
#include <stdlib.h>
#include <stdarg.h>
#include <furi/common_defines.h>
#include <core/common_defines.h>
#include "app_conf.h"

View File

@@ -22,8 +22,8 @@ _Static_assert(
"Ble stack config structure size mismatch");
typedef struct {
osMutexId_t hci_mtx;
osSemaphoreId_t hci_sem;
FuriMutex* hci_mtx;
FuriSemaphore* hci_sem;
FuriThread* thread;
} BleApp;
@@ -37,8 +37,8 @@ bool ble_app_init() {
SHCI_CmdStatus_t status;
ble_app = malloc(sizeof(BleApp));
// Allocate semafore and mutex for ble command buffer access
ble_app->hci_mtx = osMutexNew(NULL);
ble_app->hci_sem = osSemaphoreNew(1, 0, NULL);
ble_app->hci_mtx = furi_mutex_alloc(FuriMutexTypeNormal);
ble_app->hci_sem = furi_semaphore_alloc(1, 0);
// HCI transport layer thread to handle user asynch events
ble_app->thread = furi_thread_alloc();
furi_thread_set_name(ble_app->thread, "BleHciDriver");
@@ -113,8 +113,8 @@ void ble_app_thread_stop() {
furi_thread_join(ble_app->thread);
furi_thread_free(ble_app->thread);
// Free resources
osMutexDelete(ble_app->hci_mtx);
osSemaphoreDelete(ble_app->hci_sem);
furi_mutex_free(ble_app->hci_mtx);
furi_semaphore_free(ble_app->hci_sem);
free(ble_app);
ble_app = NULL;
memset(&ble_app_cmd_buffer, 0, sizeof(ble_app_cmd_buffer));
@@ -126,7 +126,7 @@ static int32_t ble_app_hci_thread(void* arg) {
uint32_t flags = 0;
while(1) {
flags = furi_thread_flags_wait(BLE_APP_FLAG_ALL, osFlagsWaitAny, osWaitForever);
flags = furi_thread_flags_wait(BLE_APP_FLAG_ALL, FuriFlagWaitAny, FuriWaitForever);
if(flags & BLE_APP_FLAG_KILL_THREAD) {
break;
}
@@ -151,14 +151,14 @@ void hci_notify_asynch_evt(void* pdata) {
void hci_cmd_resp_release(uint32_t flag) {
UNUSED(flag);
if(ble_app) {
osSemaphoreRelease(ble_app->hci_sem);
furi_semaphore_release(ble_app->hci_sem);
}
}
void hci_cmd_resp_wait(uint32_t timeout) {
UNUSED(timeout);
if(ble_app) {
osSemaphoreAcquire(ble_app->hci_sem, osWaitForever);
furi_semaphore_acquire(ble_app->hci_sem, FuriWaitForever);
}
}
@@ -178,9 +178,9 @@ static void ble_app_hci_event_handler(void* pPayload) {
static void ble_app_hci_status_not_handler(HCI_TL_CmdStatus_t status) {
if(status == HCI_TL_CmdBusy) {
osMutexAcquire(ble_app->hci_mtx, osWaitForever);
furi_mutex_acquire(ble_app->hci_mtx, FuriWaitForever);
} else if(status == HCI_TL_CmdAvailable) {
osMutexRelease(ble_app->hci_mtx);
furi_mutex_release(ble_app->hci_mtx);
}
}

View File

@@ -30,8 +30,8 @@ ALIGN(4)
static uint8_t ble_glue_ble_spare_event_buff[sizeof(TL_PacketHeader_t) + TL_EVT_HDR_SIZE + 255];
typedef struct {
osMutexId_t shci_mtx;
osSemaphoreId_t shci_sem;
FuriMutex* shci_mtx;
FuriSemaphore* shci_sem;
FuriThread* thread;
BleGlueStatus status;
BleGlueKeyStorageChangedCallback callback;
@@ -74,8 +74,8 @@ void ble_glue_init() {
// Reference table initialization
TL_Init();
ble_glue->shci_mtx = osMutexNew(NULL);
ble_glue->shci_sem = osSemaphoreNew(1, 0, NULL);
ble_glue->shci_mtx = furi_mutex_alloc(FuriMutexTypeNormal);
ble_glue->shci_sem = furi_semaphore_alloc(1, 0);
// FreeRTOS system task creation
ble_glue->thread = furi_thread_alloc();
@@ -201,7 +201,7 @@ bool ble_glue_wait_for_c2_start(int32_t timeout) {
started = ble_glue->status == BleGlueStatusC2Started;
if(!started) {
timeout--;
osDelay(1);
furi_delay_tick(1);
}
} while(!started && (timeout > 0));
@@ -300,10 +300,10 @@ BleGlueCommandResult ble_glue_force_c2_mode(BleGlueC2Mode desired_mode) {
static void ble_glue_sys_status_not_callback(SHCI_TL_CmdStatus_t status) {
switch(status) {
case SHCI_TL_CmdBusy:
osMutexAcquire(ble_glue->shci_mtx, osWaitForever);
furi_mutex_acquire(ble_glue->shci_mtx, FuriWaitForever);
break;
case SHCI_TL_CmdAvailable:
osMutexRelease(ble_glue->shci_mtx);
furi_mutex_release(ble_glue->shci_mtx);
break;
default:
break;
@@ -368,8 +368,8 @@ void ble_glue_thread_stop() {
furi_thread_join(ble_glue->thread);
furi_thread_free(ble_glue->thread);
// Free resources
osMutexDelete(ble_glue->shci_mtx);
osSemaphoreDelete(ble_glue->shci_sem);
furi_mutex_free(ble_glue->shci_mtx);
furi_semaphore_free(ble_glue->shci_sem);
ble_glue_clear_shared_memory();
free(ble_glue);
ble_glue = NULL;
@@ -382,7 +382,7 @@ static int32_t ble_glue_shci_thread(void* context) {
uint32_t flags = 0;
while(true) {
flags = furi_thread_flags_wait(BLE_GLUE_FLAG_ALL, osFlagsWaitAny, osWaitForever);
flags = furi_thread_flags_wait(BLE_GLUE_FLAG_ALL, FuriFlagWaitAny, FuriWaitForever);
if(flags & BLE_GLUE_FLAG_SHCI_EVENT) {
shci_user_evt_proc();
}
@@ -406,14 +406,14 @@ void shci_notify_asynch_evt(void* pdata) {
void shci_cmd_resp_release(uint32_t flag) {
UNUSED(flag);
if(ble_glue) {
osSemaphoreRelease(ble_glue->shci_sem);
furi_semaphore_release(ble_glue->shci_sem);
}
}
void shci_cmd_resp_wait(uint32_t timeout) {
UNUSED(timeout);
if(ble_glue) {
osSemaphoreAcquire(ble_glue->shci_sem, osWaitForever);
furi_semaphore_acquire(ble_glue->shci_sem, FuriWaitForever);
}
}
@@ -468,7 +468,7 @@ BleGlueCommandResult ble_glue_fus_wait_operation() {
}
wip = fus_status == BleGlueCommandResultOperationOngoing;
if(wip) {
osDelay(20);
furi_delay_ms(20);
}
} while(wip);

View File

@@ -27,12 +27,12 @@ typedef struct {
GapConfig* config;
GapConnectionParams connection_params;
GapState state;
osMutexId_t state_mutex;
FuriMutex* state_mutex;
GapEventCallback on_event_cb;
void* context;
osTimerId_t advertise_timer;
FuriTimer* advertise_timer;
FuriThread* thread;
osMessageQueueId_t command_queue;
FuriMessageQueue* command_queue;
bool enable_adv;
} Gap;
@@ -94,7 +94,7 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) {
event_pckt = (hci_event_pckt*)((hci_uart_pckt*)pckt)->data;
if(gap) {
osMutexAcquire(gap->state_mutex, osWaitForever);
furi_mutex_acquire(gap->state_mutex, FuriWaitForever);
}
switch(event_pckt->evt) {
case EVT_DISCONN_COMPLETE: {
@@ -152,7 +152,7 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) {
gap->connection_params.supervisor_timeout = event->Supervision_Timeout;
// Stop advertising as connection completed
osTimerStop(gap->advertise_timer);
furi_timer_stop(gap->advertise_timer);
// Update connection status and handle
gap->state = GapStateConnected;
@@ -268,7 +268,7 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) {
break;
}
if(gap) {
osMutexRelease(gap->state_mutex);
furi_mutex_release(gap->state_mutex);
}
return SVCCTL_UserEvtFlowEnable;
}
@@ -382,7 +382,7 @@ static void gap_advertise_start(GapState new_state) {
max_interval = 0x0fa0; // 2.5 s
}
// Stop advertising timer
osTimerStop(gap->advertise_timer);
furi_timer_stop(gap->advertise_timer);
if((new_state == GapStateAdvLowPower) &&
((gap->state == GapStateAdvFast) || (gap->state == GapStateAdvLowPower))) {
@@ -413,7 +413,7 @@ static void gap_advertise_start(GapState new_state) {
gap->state = new_state;
GapEvent event = {.type = GapEventTypeStartAdvertising};
gap->on_event_cb(event, gap->context);
osTimerStart(gap->advertise_timer, INITIAL_ADV_TIMEOUT);
furi_timer_start(gap->advertise_timer, INITIAL_ADV_TIMEOUT);
}
static void gap_advertise_stop() {
@@ -429,7 +429,7 @@ static void gap_advertise_stop() {
}
}
// Stop advertising
osTimerStop(gap->advertise_timer);
furi_timer_stop(gap->advertise_timer);
ret = aci_gap_set_non_discoverable();
if(ret != BLE_STATUS_SUCCESS) {
FURI_LOG_E(TAG, "set_non_discoverable failed %d", ret);
@@ -443,32 +443,32 @@ static void gap_advertise_stop() {
}
void gap_start_advertising() {
osMutexAcquire(gap->state_mutex, osWaitForever);
furi_mutex_acquire(gap->state_mutex, FuriWaitForever);
if(gap->state == GapStateIdle) {
gap->state = GapStateStartingAdv;
FURI_LOG_I(TAG, "Start advertising");
gap->enable_adv = true;
GapCommand command = GapCommandAdvFast;
furi_check(osMessageQueuePut(gap->command_queue, &command, 0, 0) == osOK);
furi_check(furi_message_queue_put(gap->command_queue, &command, 0) == FuriStatusOk);
}
osMutexRelease(gap->state_mutex);
furi_mutex_release(gap->state_mutex);
}
void gap_stop_advertising() {
osMutexAcquire(gap->state_mutex, osWaitForever);
furi_mutex_acquire(gap->state_mutex, FuriWaitForever);
if(gap->state > GapStateIdle) {
FURI_LOG_I(TAG, "Stop advertising");
gap->enable_adv = false;
GapCommand command = GapCommandAdvStop;
furi_check(osMessageQueuePut(gap->command_queue, &command, 0, 0) == osOK);
furi_check(furi_message_queue_put(gap->command_queue, &command, 0) == FuriStatusOk);
}
osMutexRelease(gap->state_mutex);
furi_mutex_release(gap->state_mutex);
}
static void gap_advetise_timer_callback(void* context) {
UNUSED(context);
GapCommand command = GapCommandAdvLowPower;
furi_check(osMessageQueuePut(gap->command_queue, &command, 0, 0) == osOK);
furi_check(furi_message_queue_put(gap->command_queue, &command, 0) == FuriStatusOk);
}
bool gap_init(GapConfig* config, GapEventCallback on_event_cb, void* context) {
@@ -480,14 +480,14 @@ bool gap_init(GapConfig* config, GapEventCallback on_event_cb, void* context) {
gap->config = config;
srand(DWT->CYCCNT);
// Create advertising timer
gap->advertise_timer = osTimerNew(gap_advetise_timer_callback, osTimerOnce, NULL, NULL);
gap->advertise_timer = furi_timer_alloc(gap_advetise_timer_callback, FuriTimerTypeOnce, NULL);
// Initialization of GATT & GAP layer
gap->service.adv_name = config->adv_name;
gap_init_svc(gap);
// Initialization of the BLE Services
SVCCTL_Init();
// Initialization of the GAP state
gap->state_mutex = osMutexNew(NULL);
gap->state_mutex = furi_mutex_alloc(FuriMutexTypeNormal);
gap->state = GapStateIdle;
gap->service.connection_handle = 0xFFFF;
gap->enable_adv = true;
@@ -501,7 +501,7 @@ bool gap_init(GapConfig* config, GapEventCallback on_event_cb, void* context) {
furi_thread_start(gap->thread);
// Command queue allocation
gap->command_queue = osMessageQueueNew(8, sizeof(GapCommand), NULL);
gap->command_queue = furi_message_queue_alloc(8, sizeof(GapCommand));
uint8_t adv_service_uid[2];
gap->service.adv_svc_uuid_len = 1;
@@ -518,9 +518,9 @@ bool gap_init(GapConfig* config, GapEventCallback on_event_cb, void* context) {
GapState gap_get_state() {
GapState state;
if(gap) {
osMutexAcquire(gap->state_mutex, osWaitForever);
furi_mutex_acquire(gap->state_mutex, FuriWaitForever);
state = gap->state;
osMutexRelease(gap->state_mutex);
furi_mutex_release(gap->state_mutex);
} else {
state = GapStateUninitialized;
}
@@ -529,19 +529,19 @@ GapState gap_get_state() {
void gap_thread_stop() {
if(gap) {
osMutexAcquire(gap->state_mutex, osWaitForever);
furi_mutex_acquire(gap->state_mutex, FuriWaitForever);
gap->enable_adv = false;
GapCommand command = GapCommandKillThread;
osMessageQueuePut(gap->command_queue, &command, 0, osWaitForever);
osMutexRelease(gap->state_mutex);
furi_message_queue_put(gap->command_queue, &command, FuriWaitForever);
furi_mutex_release(gap->state_mutex);
furi_thread_join(gap->thread);
furi_thread_free(gap->thread);
// Free resources
osMutexDelete(gap->state_mutex);
osMessageQueueDelete(gap->command_queue);
osTimerStop(gap->advertise_timer);
while(xTimerIsTimerActive(gap->advertise_timer) == pdTRUE) osDelay(1);
furi_check(osTimerDelete(gap->advertise_timer) == osOK);
furi_mutex_free(gap->state_mutex);
furi_message_queue_free(gap->command_queue);
furi_timer_stop(gap->advertise_timer);
while(xTimerIsTimerActive(gap->advertise_timer) == pdTRUE) furi_delay_tick(1);
furi_timer_free(gap->advertise_timer);
free(gap);
gap = NULL;
}
@@ -551,12 +551,12 @@ static int32_t gap_app(void* context) {
UNUSED(context);
GapCommand command;
while(1) {
osStatus_t status = osMessageQueueGet(gap->command_queue, &command, NULL, osWaitForever);
if(status != osOK) {
FuriStatus status = furi_message_queue_get(gap->command_queue, &command, FuriWaitForever);
if(status != FuriStatusOk) {
FURI_LOG_E(TAG, "Message queue get error: %d", status);
continue;
}
osMutexAcquire(gap->state_mutex, osWaitForever);
furi_mutex_acquire(gap->state_mutex, FuriWaitForever);
if(command == GapCommandKillThread) {
break;
}
@@ -567,7 +567,7 @@ static int32_t gap_app(void* context) {
} else if(command == GapCommandAdvStop) {
gap_advertise_stop();
}
osMutexRelease(gap->state_mutex);
furi_mutex_release(gap->state_mutex);
}
return 0;

View File

@@ -11,7 +11,7 @@ typedef struct {
uint16_t rx_char_handle;
uint16_t tx_char_handle;
uint16_t flow_ctrl_char_handle;
osMutexId_t buff_size_mtx;
FuriMutex* buff_size_mtx;
uint32_t buff_size;
uint16_t bytes_ready_to_receive;
SerialServiceEventCallback callback;
@@ -44,7 +44,9 @@ static SVCCTL_EvtAckStatus_t serial_svc_event_handler(void* event) {
} else if(attribute_modified->Attr_Handle == serial_svc->rx_char_handle + 1) {
FURI_LOG_D(TAG, "Received %d bytes", attribute_modified->Attr_Data_Length);
if(serial_svc->callback) {
furi_check(osMutexAcquire(serial_svc->buff_size_mtx, osWaitForever) == osOK);
furi_check(
furi_mutex_acquire(serial_svc->buff_size_mtx, FuriWaitForever) ==
FuriStatusOk);
if(attribute_modified->Attr_Data_Length > serial_svc->bytes_ready_to_receive) {
FURI_LOG_W(
TAG,
@@ -62,7 +64,7 @@ static SVCCTL_EvtAckStatus_t serial_svc_event_handler(void* event) {
}};
uint32_t buff_free_size = serial_svc->callback(event, serial_svc->context);
FURI_LOG_D(TAG, "Available buff size: %d", buff_free_size);
furi_check(osMutexRelease(serial_svc->buff_size_mtx) == osOK);
furi_check(furi_mutex_release(serial_svc->buff_size_mtx) == FuriStatusOk);
}
ret = SVCCTL_EvtAckFlowEnable;
}
@@ -140,7 +142,7 @@ void serial_svc_start() {
FURI_LOG_E(TAG, "Failed to add Flow Control characteristic: %d", status);
}
// Allocate buffer size mutex
serial_svc->buff_size_mtx = osMutexNew(NULL);
serial_svc->buff_size_mtx = furi_mutex_alloc(FuriMutexTypeNormal);
}
void serial_svc_set_callbacks(
@@ -165,7 +167,7 @@ void serial_svc_notify_buffer_is_empty() {
furi_assert(serial_svc);
furi_assert(serial_svc->buff_size_mtx);
furi_check(osMutexAcquire(serial_svc->buff_size_mtx, osWaitForever) == osOK);
furi_check(furi_mutex_acquire(serial_svc->buff_size_mtx, FuriWaitForever) == FuriStatusOk);
if(serial_svc->bytes_ready_to_receive == 0) {
FURI_LOG_D(TAG, "Buffer is empty. Notifying client");
serial_svc->bytes_ready_to_receive = serial_svc->buff_size;
@@ -177,7 +179,7 @@ void serial_svc_notify_buffer_is_empty() {
sizeof(uint32_t),
(uint8_t*)&buff_size_reversed);
}
furi_check(osMutexRelease(serial_svc->buff_size_mtx) == osOK);
furi_check(furi_mutex_release(serial_svc->buff_size_mtx) == FuriStatusOk);
}
void serial_svc_stop() {
@@ -202,7 +204,7 @@ void serial_svc_stop() {
FURI_LOG_E(TAG, "Failed to delete Serial service: %d", status);
}
// Delete buffer size mutex
osMutexDelete(serial_svc->buff_size_mtx);
furi_mutex_free(serial_svc->buff_size_mtx);
free(serial_svc);
serial_svc = NULL;
}

View File

@@ -245,7 +245,7 @@
#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
#define _SYNC_t FuriMutex*
/* 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()

View File

@@ -46,7 +46,7 @@ void SD_IO_Init(void) {
/* SD chip select high */
furi_hal_gpio_write(furi_hal_sd_spi_handle->cs, true);
furi_hal_delay_us(10);
furi_delay_us(10);
/* Send dummy byte 0xFF, 10 times with CS high */
/* Rise CS and MOSI for 80 clocks cycles */
@@ -64,11 +64,11 @@ void SD_IO_Init(void) {
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) {
furi_hal_delay_us(10); // Exit guard time for some SD cards
furi_delay_us(10); // Exit guard time for some SD cards
furi_hal_gpio_write(furi_hal_sd_spi_handle->cs, true);
} else {
furi_hal_gpio_write(furi_hal_sd_spi_handle->cs, false);
furi_hal_delay_us(10); // Entry guard time for some SD cards
furi_delay_us(10); // Entry guard time for some SD cards
}
}

View File

@@ -349,13 +349,13 @@ uint8_t BSP_SD_Init(bool reset_card) {
furi_hal_power_disable_external_3_3v();
SD_SPI_Bus_To_Down_State();
hal_sd_detect_set_low();
furi_hal_delay_ms(250);
furi_delay_ms(250);
/* reinit bus and enable power */
SD_SPI_Bus_To_Normal_State();
hal_sd_detect_init();
furi_hal_power_enable_external_3_3v();
furi_hal_delay_ms(100);
furi_delay_ms(100);
}
/* Configure IO functionalities for SD pin */
@@ -869,7 +869,7 @@ SD_CmdAnswer_typedef SD_SendCmd(uint8_t Cmd, uint32_t Arg, uint8_t Crc, uint8_t
retr.r2 = SD_IO_WriteByte(SD_DUMMY_BYTE);
/* Set CS High */
SD_IO_CSState(1);
furi_hal_delay_us(1000);
furi_delay_us(1000);
/* Set CS Low */
SD_IO_CSState(0);

View File

@@ -38,7 +38,7 @@ int ff_cre_syncobj(/* 1:Function succeeded, 0:Could not create the sync object *
//osSemaphoreDef(SEM);
//*sobj = osSemaphoreCreate(osSemaphore(SEM), 1);
*sobj = osMutexNew(NULL);
*sobj = furi_mutex_alloc(FuriMutexTypeNormal);
ret = (*sobj != NULL);
return ret;
@@ -55,7 +55,7 @@ int ff_cre_syncobj(/* 1:Function succeeded, 0:Could not create the sync object *
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);
furi_mutex_free(sobj);
return 1;
}
@@ -71,7 +71,7 @@ int ff_req_grant(/* 1:Got a grant to access the volume, 0:Could not get a grant
) {
int ret = 0;
if(osMutexAcquire(sobj, _FS_TIMEOUT) == osOK) {
if(furi_mutex_acquire(sobj, _FS_TIMEOUT) == FuriStatusOk) {
ret = 1;
}
@@ -86,7 +86,7 @@ int ff_req_grant(/* 1:Got a grant to access the volume, 0:Could not get a grant
void ff_rel_grant(_SYNC_t sobj /* Sync object to be signaled */
) {
osMutexRelease(sobj);
furi_mutex_release(sobj);
}
#endif

View File

@@ -7,8 +7,9 @@
#define TAG "FuriHal"
void furi_hal_init_early() {
furi_hal_cortex_init_early();
furi_hal_clock_init_early();
furi_hal_delay_init();
furi_hal_resources_init_early();

View File

@@ -2,7 +2,6 @@
#include <ble.h>
#include <stm32wbxx.h>
#include <shci.h>
#include <cmsis_os2.h>
#include <furi_hal_version.h>
#include <furi_hal_bt_hid.h>
@@ -19,7 +18,7 @@
/* Time, in ms, to wait for mode transition before crashing */
#define C2_MODE_SWITCH_TIMEOUT 10000
osMutexId_t furi_hal_bt_core2_mtx = NULL;
FuriMutex* furi_hal_bt_core2_mtx = NULL;
static FuriHalBtStack furi_hal_bt_stack = FuriHalBtStackUnknown;
typedef void (*FuriHalBtProfileStart)(void);
@@ -79,7 +78,7 @@ FuriHalBtProfileConfig* current_profile = NULL;
void furi_hal_bt_init() {
if(!furi_hal_bt_core2_mtx) {
furi_hal_bt_core2_mtx = osMutexNew(NULL);
furi_hal_bt_core2_mtx = furi_mutex_alloc(FuriMutexTypeNormal);
furi_assert(furi_hal_bt_core2_mtx);
}
@@ -94,12 +93,12 @@ void furi_hal_bt_init() {
void furi_hal_bt_lock_core2() {
furi_assert(furi_hal_bt_core2_mtx);
furi_check(osMutexAcquire(furi_hal_bt_core2_mtx, osWaitForever) == osOK);
furi_check(furi_mutex_acquire(furi_hal_bt_core2_mtx, FuriWaitForever) == FuriStatusOk);
}
void furi_hal_bt_unlock_core2() {
furi_assert(furi_hal_bt_core2_mtx);
furi_check(osMutexRelease(furi_hal_bt_core2_mtx) == osOK);
furi_check(furi_mutex_release(furi_hal_bt_core2_mtx) == FuriStatusOk);
}
static bool furi_hal_bt_radio_stack_is_supported(const BleGlueC2Info* info) {
@@ -126,7 +125,7 @@ bool furi_hal_bt_start_radio_stack() {
bool res = false;
furi_assert(furi_hal_bt_core2_mtx);
osMutexAcquire(furi_hal_bt_core2_mtx, osWaitForever);
furi_mutex_acquire(furi_hal_bt_core2_mtx, FuriWaitForever);
// Explicitly tell that we are in charge of CLK48 domain
if(!LL_HSEM_IsSemaphoreLocked(HSEM, CFG_HW_CLK48_CONFIG_SEMID)) {
@@ -162,7 +161,7 @@ bool furi_hal_bt_start_radio_stack() {
}
res = true;
} while(false);
osMutexRelease(furi_hal_bt_core2_mtx);
furi_mutex_release(furi_hal_bt_core2_mtx);
return res;
}
@@ -255,7 +254,7 @@ void furi_hal_bt_reinit() {
FURI_LOG_I(TAG, "Reset SHCI");
furi_check(ble_glue_reinit_c2());
osDelay(100);
furi_delay_ms(100);
ble_glue_thread_stop();
FURI_LOG_I(TAG, "Start BT initialization");
@@ -292,7 +291,7 @@ void furi_hal_bt_stop_advertising() {
if(furi_hal_bt_is_active()) {
gap_stop_advertising();
while(furi_hal_bt_is_active()) {
osDelay(1);
furi_delay_tick(1);
}
}
}
@@ -436,7 +435,7 @@ bool furi_hal_bt_ensure_c2_mode(BleGlueC2Mode mode) {
return true;
} else if(fw_start_res == BleGlueCommandResultRestartPending) {
// Do nothing and wait for system reset
osDelay(C2_MODE_SWITCH_TIMEOUT);
furi_delay_ms(C2_MODE_SWITCH_TIMEOUT);
furi_crash("Waiting for FUS->radio stack transition");
return true;
}

View File

@@ -0,0 +1,20 @@
#include "furi_hal_cortex.h"
#include <stm32wbxx.h>
void furi_hal_cortex_init_early() {
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
DWT->CYCCNT = 0U;
}
void furi_hal_cortex_delay_us(uint32_t microseconds) {
uint32_t start = DWT->CYCCNT;
uint32_t time_ticks = SystemCoreClock / 1000000 * microseconds;
while((DWT->CYCCNT - start) < time_ticks) {
};
}
uint32_t furi_hal_cortex_instructions_per_microsecond() {
return SystemCoreClock / 1000000;
}

View File

@@ -1,93 +0,0 @@
#include <furi_hal.h>
#include <stm32wbxx_ll_crc.h>
typedef enum {
CRC_State_Reset,
CRC_State_Ready,
CRC_State_Busy,
} CRC_State;
typedef struct {
CRC_State state;
osMutexId_t mtx;
} HAL_CRC_Control;
static volatile HAL_CRC_Control hal_crc_control = {
.state = CRC_State_Reset,
.mtx = NULL,
};
void furi_hal_crc_init(bool synchronize) {
/* initialize peripheral with default generating polynomial */
LL_CRC_SetInputDataReverseMode(CRC, LL_CRC_INDATA_REVERSE_BYTE);
LL_CRC_SetOutputDataReverseMode(CRC, LL_CRC_OUTDATA_REVERSE_BIT);
LL_CRC_SetPolynomialCoef(CRC, LL_CRC_DEFAULT_CRC32_POLY);
LL_CRC_SetPolynomialSize(CRC, LL_CRC_POLYLENGTH_32B);
LL_CRC_SetInitialData(CRC, LL_CRC_DEFAULT_CRC_INITVALUE);
if(synchronize) {
hal_crc_control.mtx = osMutexNew(NULL);
}
hal_crc_control.state = CRC_State_Ready;
}
void furi_hal_crc_reset() {
furi_check(hal_crc_control.state == CRC_State_Ready);
if(hal_crc_control.mtx) {
furi_check(osMutexGetOwner(hal_crc_control.mtx) == furi_thread_get_current_id());
osMutexRelease(hal_crc_control.mtx);
}
LL_CRC_ResetCRCCalculationUnit(CRC);
}
static uint32_t furi_hal_crc_handle_8(uint8_t pBuffer[], uint32_t BufferLength) {
uint32_t i; /* input data buffer index */
hal_crc_control.state = CRC_State_Busy;
/* Processing time optimization: 4 bytes are entered in a row with a single word write,
* last bytes must be carefully fed to the CRC calculator to ensure a correct type
* handling by the peripheral */
for(i = 0U; i < (BufferLength / 4U); i++) {
LL_CRC_FeedData32(
CRC,
((uint32_t)pBuffer[4U * i] << 24U) | ((uint32_t)pBuffer[(4U * i) + 1U] << 16U) |
((uint32_t)pBuffer[(4U * i) + 2U] << 8U) | (uint32_t)pBuffer[(4U * i) + 3U]);
}
/* last bytes specific handling */
if((BufferLength % 4U) != 0U) {
if((BufferLength % 4U) == 1U) {
LL_CRC_FeedData8(CRC, pBuffer[4U * i]);
} else if((BufferLength % 4U) == 2U) {
LL_CRC_FeedData16(
CRC, ((uint16_t)(pBuffer[4U * i]) << 8U) | (uint16_t)pBuffer[(4U * i) + 1U]);
} else if((BufferLength % 4U) == 3U) {
LL_CRC_FeedData16(
CRC, ((uint16_t)(pBuffer[4U * i]) << 8U) | (uint16_t)pBuffer[(4U * i) + 1U]);
LL_CRC_FeedData8(CRC, pBuffer[(4U * i) + 2U]);
}
}
hal_crc_control.state = CRC_State_Ready;
/* Return the CRC computed value */
return LL_CRC_ReadData32(CRC);
}
static uint32_t furi_hal_crc_accumulate(uint32_t pBuffer[], uint32_t BufferLength) {
furi_check(hal_crc_control.state == CRC_State_Ready);
if(hal_crc_control.mtx) {
furi_check(osMutexGetOwner(hal_crc_control.mtx) != NULL);
}
return furi_hal_crc_handle_8((uint8_t*)pBuffer, BufferLength);
}
uint32_t furi_hal_crc_feed(void* data, uint16_t length) {
return ~furi_hal_crc_accumulate(data, length);
}
bool furi_hal_crc_acquire(uint32_t timeout) {
furi_assert(hal_crc_control.mtx);
if(osMutexAcquire(hal_crc_control.mtx, timeout) == osOK) {
LL_CRC_ResetCRCCalculationUnit(CRC);
return true;
}
return false;
}

View File

@@ -1,35 +0,0 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
/** Configure for CRC32 calculation
* @param synchronize enforce acquisition & release in multithreaded environment
*/
void furi_hal_crc_init(bool synchronize);
/** Blocking call to get control of CRC block. Mandatory while RTOS is running
* @param timeout time to wait for CRC to be available. Can be osWaitForever
* @return bool acquisition success
*/
bool furi_hal_crc_acquire(uint32_t timeout);
/** Reset current calculation state and release CRC block
*/
void furi_hal_crc_reset();
/** Process data block. Does not reset current state,
* allowing to process arbitrary data lengths
* @param data pointer to data
* @param length data length
* @return uint32_t CRC32 value
*/
uint32_t furi_hal_crc_feed(void* data, uint16_t length);
#ifdef __cplusplus
}
#endif

View File

@@ -23,7 +23,7 @@
#define CRYPTO_KEYSIZE_256B (AES_CR_KEYSIZE)
#define CRYPTO_AES_CBC (AES_CR_CHMOD_0)
static osMutexId_t furi_hal_crypto_mutex = NULL;
static FuriMutex* furi_hal_crypto_mutex = NULL;
static bool furi_hal_crypto_mode_init_done = false;
static const uint8_t enclave_signature_iv[ENCLAVE_FACTORY_KEY_SLOTS][16] = {
@@ -66,7 +66,7 @@ static const uint8_t enclave_signature_expected[ENCLAVE_FACTORY_KEY_SLOTS][ENCLA
};
void furi_hal_crypto_init() {
furi_hal_crypto_mutex = osMutexNew(NULL);
furi_hal_crypto_mutex = furi_mutex_alloc(FuriMutexTypeNormal);
FURI_LOG_I(TAG, "Init OK");
}
@@ -143,7 +143,7 @@ bool furi_hal_crypto_store_add_key(FuriHalCryptoKey* key, uint8_t* slot) {
furi_assert(key);
furi_assert(slot);
furi_check(osMutexAcquire(furi_hal_crypto_mutex, osWaitForever) == osOK);
furi_check(furi_mutex_acquire(furi_hal_crypto_mutex, FuriWaitForever) == FuriStatusOk);
if(!furi_hal_bt_is_alive()) {
return false;
@@ -176,7 +176,7 @@ bool furi_hal_crypto_store_add_key(FuriHalCryptoKey* key, uint8_t* slot) {
memcpy(pParam.KeyData, key->data, key_data_size);
SHCI_CmdStatus_t shci_state = SHCI_C2_FUS_StoreUsrKey(&pParam, slot);
furi_check(osMutexRelease(furi_hal_crypto_mutex) == osOK);
furi_check(furi_mutex_release(furi_hal_crypto_mutex) == FuriStatusOk);
return (shci_state == SHCI_Success);
}
@@ -239,7 +239,7 @@ static bool crypto_process_block(uint32_t* in, uint32_t* out, uint8_t blk_len) {
bool furi_hal_crypto_store_load_key(uint8_t slot, const uint8_t* iv) {
furi_assert(slot > 0 && slot <= 100);
furi_assert(furi_hal_crypto_mutex);
furi_check(osMutexAcquire(furi_hal_crypto_mutex, osWaitForever) == osOK);
furi_check(furi_mutex_acquire(furi_hal_crypto_mutex, FuriWaitForever) == FuriStatusOk);
if(!furi_hal_bt_is_alive()) {
return false;
@@ -252,7 +252,7 @@ bool furi_hal_crypto_store_load_key(uint8_t slot, const uint8_t* iv) {
return true;
} else {
CLEAR_BIT(AES1->CR, AES_CR_EN);
furi_check(osMutexRelease(furi_hal_crypto_mutex) == osOK);
furi_check(furi_mutex_release(furi_hal_crypto_mutex) == FuriStatusOk);
return false;
}
}
@@ -272,7 +272,7 @@ bool furi_hal_crypto_store_unload_key(uint8_t slot) {
LL_AHB2_GRP1_ReleaseReset(LL_AHB2_GRP1_PERIPH_AES1);
FURI_CRITICAL_EXIT();
furi_check(osMutexRelease(furi_hal_crypto_mutex) == osOK);
furi_check(furi_mutex_release(furi_hal_crypto_mutex) == FuriStatusOk);
return (shci_state == SHCI_Success);
}

View File

@@ -1,45 +0,0 @@
#include "furi_hal_delay.h"
#include <furi.h>
#include <cmsis_os2.h>
#include <stm32wbxx_ll_utils.h>
#define TAG "FuriHalDelay"
void furi_hal_delay_init() {
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
DWT->CYCCNT = 0U;
}
uint32_t furi_hal_delay_instructions_per_microsecond() {
return SystemCoreClock / 1000000;
}
uint32_t furi_hal_get_tick(void) {
return osKernelGetTickCount();
}
uint32_t furi_hal_ms_to_ticks(float milliseconds) {
return milliseconds / (1000.0f / osKernelGetTickFreq());
}
void furi_hal_delay_us(float microseconds) {
uint32_t start = DWT->CYCCNT;
uint32_t time_ticks = microseconds * furi_hal_delay_instructions_per_microsecond();
while((DWT->CYCCNT - start) < time_ticks) {
};
}
// cannot be used in ISR
// TODO add delay_ISR variant
void furi_hal_delay_ms(float milliseconds) {
if(!FURI_IS_ISR() && osKernelGetState() == osKernelRunning) {
uint32_t ticks = milliseconds / (1000.0f / osKernelGetTickFreq());
osStatus_t result = osDelay(ticks);
(void)result;
furi_assert(result == osOK);
} else {
furi_hal_delay_us(milliseconds * 1000);
}
}

View File

@@ -1,5 +1,4 @@
#include <furi_hal_i2c.h>
#include <furi_hal_delay.h>
#include <furi_hal_version.h>
#include <furi_hal_power.h>
@@ -61,11 +60,11 @@ bool furi_hal_i2c_tx(
furi_assert(timeout > 0);
bool ret = true;
uint32_t timeout_tick = furi_hal_get_tick() + timeout;
uint32_t timeout_tick = furi_get_tick() + timeout;
do {
while(LL_I2C_IsActiveFlag_BUSY(handle->bus->i2c)) {
if(furi_hal_get_tick() >= timeout_tick) {
if(furi_get_tick() >= timeout_tick) {
ret = false;
break;
}
@@ -90,7 +89,7 @@ bool furi_hal_i2c_tx(
size--;
}
if(furi_hal_get_tick() >= timeout_tick) {
if(furi_get_tick() >= timeout_tick) {
ret = false;
break;
}
@@ -112,11 +111,11 @@ bool furi_hal_i2c_rx(
furi_assert(timeout > 0);
bool ret = true;
uint32_t timeout_tick = furi_hal_get_tick() + timeout;
uint32_t timeout_tick = furi_get_tick() + timeout;
do {
while(LL_I2C_IsActiveFlag_BUSY(handle->bus->i2c)) {
if(furi_hal_get_tick() >= timeout_tick) {
if(furi_get_tick() >= timeout_tick) {
ret = false;
break;
}
@@ -141,7 +140,7 @@ bool furi_hal_i2c_rx(
size--;
}
if(furi_hal_get_tick() >= timeout_tick) {
if(furi_get_tick() >= timeout_tick) {
ret = false;
break;
}
@@ -176,11 +175,11 @@ bool furi_hal_i2c_is_device_ready(FuriHalI2cBusHandle* handle, uint8_t i2c_addr,
furi_assert(timeout > 0);
bool ret = true;
uint32_t timeout_tick = furi_hal_get_tick() + timeout;
uint32_t timeout_tick = furi_get_tick() + timeout;
do {
while(LL_I2C_IsActiveFlag_BUSY(handle->bus->i2c)) {
if(furi_hal_get_tick() >= timeout_tick) {
if(furi_get_tick() >= timeout_tick) {
return false;
}
}
@@ -191,14 +190,14 @@ bool furi_hal_i2c_is_device_ready(FuriHalI2cBusHandle* handle, uint8_t i2c_addr,
while((!LL_I2C_IsActiveFlag_NACK(handle->bus->i2c)) &&
(!LL_I2C_IsActiveFlag_STOP(handle->bus->i2c))) {
if(furi_hal_get_tick() >= timeout_tick) {
if(furi_get_tick() >= timeout_tick) {
return false;
}
}
if(LL_I2C_IsActiveFlag_NACK(handle->bus->i2c)) {
while(!LL_I2C_IsActiveFlag_STOP(handle->bus->i2c)) {
if(furi_hal_get_tick() >= timeout_tick) {
if(furi_get_tick() >= timeout_tick) {
return false;
}
}
@@ -215,7 +214,7 @@ bool furi_hal_i2c_is_device_ready(FuriHalI2cBusHandle* handle, uint8_t i2c_addr,
}
while(!LL_I2C_IsActiveFlag_STOP(handle->bus->i2c)) {
if(furi_hal_get_tick() >= timeout_tick) {
if(furi_get_tick() >= timeout_tick) {
return false;
}
}
@@ -309,11 +308,11 @@ bool furi_hal_i2c_write_mem(
bool ret = true;
uint8_t size = len + 1;
uint32_t timeout_tick = furi_hal_get_tick() + timeout;
uint32_t timeout_tick = furi_get_tick() + timeout;
do {
while(LL_I2C_IsActiveFlag_BUSY(handle->bus->i2c)) {
if(furi_hal_get_tick() >= timeout_tick) {
if(furi_get_tick() >= timeout_tick) {
ret = false;
break;
}
@@ -342,7 +341,7 @@ bool furi_hal_i2c_write_mem(
size--;
}
if(furi_hal_get_tick() >= timeout_tick) {
if(furi_get_tick() >= timeout_tick) {
ret = false;
break;
}

View File

@@ -16,26 +16,27 @@
*/
#define FURI_HAL_I2C_CONFIG_POWER_I2C_TIMINGS_400 0x00602173
osMutexId_t furi_hal_i2c_bus_power_mutex = NULL;
FuriMutex* furi_hal_i2c_bus_power_mutex = NULL;
static void furi_hal_i2c_bus_power_event(FuriHalI2cBus* bus, FuriHalI2cBusEvent event) {
if(event == FuriHalI2cBusEventInit) {
furi_hal_i2c_bus_power_mutex = osMutexNew(NULL);
furi_hal_i2c_bus_power_mutex = furi_mutex_alloc(FuriMutexTypeNormal);
FURI_CRITICAL_ENTER();
LL_RCC_SetI2CClockSource(LL_RCC_I2C1_CLKSOURCE_PCLK1);
LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_I2C1);
FURI_CRITICAL_EXIT();
bus->current_handle = NULL;
} else if(event == FuriHalI2cBusEventDeinit) {
furi_check(osMutexDelete(furi_hal_i2c_bus_power_mutex) == osOK);
furi_mutex_free(furi_hal_i2c_bus_power_mutex);
FURI_CRITICAL_ENTER();
LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_I2C1);
LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_I2C1);
FURI_CRITICAL_EXIT();
} else if(event == FuriHalI2cBusEventLock) {
furi_check(osMutexAcquire(furi_hal_i2c_bus_power_mutex, osWaitForever) == osOK);
furi_check(
furi_mutex_acquire(furi_hal_i2c_bus_power_mutex, FuriWaitForever) == FuriStatusOk);
} else if(event == FuriHalI2cBusEventUnlock) {
furi_check(osMutexRelease(furi_hal_i2c_bus_power_mutex) == osOK);
furi_check(furi_mutex_release(furi_hal_i2c_bus_power_mutex) == FuriStatusOk);
} else if(event == FuriHalI2cBusEventActivate) {
FURI_CRITICAL_ENTER();
LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_I2C1);
@@ -52,26 +53,27 @@ FuriHalI2cBus furi_hal_i2c_bus_power = {
.callback = furi_hal_i2c_bus_power_event,
};
osMutexId_t furi_hal_i2c_bus_external_mutex = NULL;
FuriMutex* furi_hal_i2c_bus_external_mutex = NULL;
static void furi_hal_i2c_bus_external_event(FuriHalI2cBus* bus, FuriHalI2cBusEvent event) {
if(event == FuriHalI2cBusEventInit) {
furi_hal_i2c_bus_external_mutex = osMutexNew(NULL);
furi_hal_i2c_bus_external_mutex = furi_mutex_alloc(FuriMutexTypeNormal);
FURI_CRITICAL_ENTER();
LL_RCC_SetI2CClockSource(LL_RCC_I2C3_CLKSOURCE_PCLK1);
LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_I2C3);
FURI_CRITICAL_EXIT();
bus->current_handle = NULL;
} else if(event == FuriHalI2cBusEventDeinit) {
furi_check(osMutexDelete(furi_hal_i2c_bus_external_mutex) == osOK);
furi_mutex_free(furi_hal_i2c_bus_external_mutex);
FURI_CRITICAL_ENTER();
LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_I2C3);
LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_I2C3);
FURI_CRITICAL_EXIT();
} else if(event == FuriHalI2cBusEventLock) {
furi_check(osMutexAcquire(furi_hal_i2c_bus_external_mutex, osWaitForever) == osOK);
furi_check(
furi_mutex_acquire(furi_hal_i2c_bus_external_mutex, FuriWaitForever) == FuriStatusOk);
} else if(event == FuriHalI2cBusEventUnlock) {
furi_check(osMutexRelease(furi_hal_i2c_bus_external_mutex) == osOK);
furi_check(furi_mutex_release(furi_hal_i2c_bus_external_mutex) == FuriStatusOk);
} else if(event == FuriHalI2cBusEventActivate) {
FURI_CRITICAL_ENTER();
LL_RCC_SetI2CClockSource(LL_RCC_I2C3_CLKSOURCE_PCLK1);

View File

@@ -1,9 +1,7 @@
#include "furi_hal_infrared.h"
#include "furi_hal_delay.h"
#include "furi/check.h"
#include <core/check.h>
#include "stm32wbxx_ll_dma.h"
#include "sys/_stdint.h"
#include <cmsis_os2.h>
#include <furi_hal_interrupt.h>
#include <furi_hal_resources.h>
@@ -52,7 +50,7 @@ typedef struct {
void* data_context;
void* signal_sent_context;
InfraredTxBuf buffer[2];
osSemaphoreId_t stop_semaphore;
FuriSemaphore* stop_semaphore;
uint32_t
tx_timing_rest_duration; /** if timing is too long (> 0xFFFF), send it in few iterations */
bool tx_timing_rest_level;
@@ -225,8 +223,8 @@ static void furi_hal_infrared_tx_dma_terminate(void) {
LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_2);
LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_1);
LL_TIM_DisableCounter(TIM1);
osStatus_t status = osSemaphoreRelease(infrared_tim_tx.stop_semaphore);
furi_check(status == osOK);
FuriStatus status = furi_semaphore_release(infrared_tim_tx.stop_semaphore);
furi_check(status == FuriStatusOk);
furi_hal_infrared_state = InfraredStateAsyncTxStopped;
}
@@ -545,15 +543,13 @@ static void furi_hal_infrared_async_tx_free_resources(void) {
furi_assert(
(furi_hal_infrared_state == InfraredStateIdle) ||
(furi_hal_infrared_state == InfraredStateAsyncTxStopped));
osStatus_t status;
furi_hal_gpio_init(&gpio_infrared_tx, GpioModeOutputOpenDrain, GpioPullDown, GpioSpeedLow);
furi_hal_interrupt_set_isr(FuriHalInterruptIdDma1Ch1, NULL, NULL);
furi_hal_interrupt_set_isr(FuriHalInterruptIdDma1Ch2, NULL, NULL);
LL_TIM_DeInit(TIM1);
status = osSemaphoreDelete(infrared_tim_tx.stop_semaphore);
furi_check(status == osOK);
furi_semaphore_free(infrared_tim_tx.stop_semaphore);
free(infrared_tim_tx.buffer[0].data);
free(infrared_tim_tx.buffer[1].data);
free(infrared_tim_tx.buffer[0].polarity);
@@ -586,7 +582,7 @@ void furi_hal_infrared_async_tx_start(uint32_t freq, float duty_cycle) {
infrared_tim_tx.buffer[0].polarity = malloc(alloc_size_polarity);
infrared_tim_tx.buffer[1].polarity = malloc(alloc_size_polarity);
infrared_tim_tx.stop_semaphore = osSemaphoreNew(1, 0, NULL);
infrared_tim_tx.stop_semaphore = furi_semaphore_alloc(1, 0);
infrared_tim_tx.cycle_duration = 1000000.0 / freq;
infrared_tim_tx.tx_timing_rest_duration = 0;
@@ -603,9 +599,9 @@ void furi_hal_infrared_async_tx_start(uint32_t freq, float duty_cycle) {
LL_TIM_ClearFlag_UPDATE(TIM1);
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1);
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_2);
furi_hal_delay_us(5);
furi_delay_us(5);
LL_TIM_GenerateEvent_UPDATE(TIM1); /* DMA -> TIMx_RCR */
furi_hal_delay_us(5);
furi_delay_us(5);
LL_GPIO_ResetOutputPin(
gpio_infrared_tx.port, gpio_infrared_tx.pin); /* when disable it prevents false pulse */
furi_hal_gpio_init_ex(
@@ -621,9 +617,9 @@ void furi_hal_infrared_async_tx_wait_termination(void) {
furi_assert(furi_hal_infrared_state >= InfraredStateAsyncTx);
furi_assert(furi_hal_infrared_state < InfraredStateMAX);
osStatus_t status;
status = osSemaphoreAcquire(infrared_tim_tx.stop_semaphore, osWaitForever);
furi_check(status == osOK);
FuriStatus status;
status = furi_semaphore_acquire(infrared_tim_tx.stop_semaphore, FuriWaitForever);
furi_check(status == FuriStatusOk);
furi_hal_infrared_async_tx_free_resources();
furi_hal_infrared_state = InfraredStateIdle;
}

View File

@@ -1,5 +1,4 @@
#include "furi_hal_interrupt.h"
#include "furi_hal_delay.h"
#include "furi_hal_os.h"
#include <furi.h>

View File

@@ -1,7 +1,6 @@
#include "furi/common_defines.h"
#include <core/common_defines.h>
#include "furi_hal_resources.h"
#include <furi_hal_light.h>
#include <furi_hal_delay.h>
#include <lp5562.h>
#include <stdint.h>
@@ -108,9 +107,9 @@ void furi_hal_light_sequence(const char* sequence) {
} else if(*sequence == 'w') {
furi_hal_light_set(LightBacklight, 0x00);
} else if(*sequence == '.') {
furi_hal_delay_ms(250);
furi_delay_ms(250);
} else if(*sequence == '-') {
furi_hal_delay_ms(500);
furi_delay_ms(500);
}
sequence++;
} while(*sequence != 0);

View File

@@ -7,16 +7,16 @@
#include <m-string.h>
#include <lib/digital_signal/digital_signal.h>
#include <furi_hal_delay.h>
#include <furi_hal_spi.h>
#include <furi_hal_gpio.h>
#include <furi_hal_cortex.h>
#include <furi_hal_resources.h>
#define TAG "FuriHalNfc"
static const uint32_t clocks_in_ms = 64 * 1000;
osEventFlagsId_t event = NULL;
FuriEventFlag* event = NULL;
#define EVENT_FLAG_INTERRUPT (1UL << 0)
#define EVENT_FLAG_STATE_CHANGED (1UL << 1)
#define EVENT_FLAG_STOP (1UL << 2)
@@ -28,7 +28,7 @@ void furi_hal_nfc_init() {
ReturnCode ret = rfalNfcInitialize();
if(ret == ERR_NONE) {
furi_hal_nfc_start_sleep();
event = osEventFlagsNew(NULL);
event = furi_event_flag_alloc();
FURI_LOG_I(TAG, "Init OK");
} else {
FURI_LOG_W(TAG, "Initialization failed, RFAL returned: %d", ret);
@@ -109,7 +109,7 @@ bool furi_hal_nfc_detect(FuriHalNfcDevData* nfc_data, uint32_t timeout) {
FURI_LOG_T(TAG, "Timeout");
break;
}
osDelay(1);
furi_delay_tick(1);
}
rfalNfcGetDevicesFound(&dev_list, &dev_cnt);
if(detected) {
@@ -243,7 +243,7 @@ bool furi_hal_nfc_listen(
rfalNfcDeactivate(true);
return false;
}
osDelay(1);
furi_delay_tick(1);
}
return true;
}
@@ -273,7 +273,7 @@ bool furi_hal_nfc_listen_rx(FuriHalNfcTxRxContext* tx_rx, uint32_t timeout_ms) {
furi_assert(tx_rx);
// Wait for interrupts
uint32_t start = osKernelGetTickCount();
uint32_t start = furi_get_tick();
bool data_received = false;
while(true) {
if(furi_hal_gpio_read(&gpio_nfc_irq_rfid_pull) == true) {
@@ -285,9 +285,9 @@ bool furi_hal_nfc_listen_rx(FuriHalNfcTxRxContext* tx_rx, uint32_t timeout_ms) {
}
continue;
}
if(osKernelGetTickCount() - start > timeout_ms) {
if(furi_get_tick() - start > timeout_ms) {
FURI_LOG_T(TAG, "Interrupt waiting timeout");
osDelay(1);
furi_delay_tick(1);
break;
}
}
@@ -352,17 +352,17 @@ void furi_hal_nfc_listen_start(FuriHalNfcDevData* nfc_data) {
}
void rfal_interrupt_callback_handler() {
osEventFlagsSet(event, EVENT_FLAG_INTERRUPT);
furi_event_flag_set(event, EVENT_FLAG_INTERRUPT);
}
void rfal_state_changed_callback(void* context) {
UNUSED(context);
osEventFlagsSet(event, EVENT_FLAG_STATE_CHANGED);
furi_event_flag_set(event, EVENT_FLAG_STATE_CHANGED);
}
void furi_hal_nfc_stop() {
if(event) {
osEventFlagsSet(event, EVENT_FLAG_STOP);
furi_event_flag_set(event, EVENT_FLAG_STOP);
}
}
@@ -405,8 +405,8 @@ bool furi_hal_nfc_emulate_nfca(
while(true) {
buff_rx_len = 0;
buff_tx_len = 0;
uint32_t flag = osEventFlagsWait(event, EVENT_FLAG_ALL, osFlagsWaitAny, timeout);
if(flag == osFlagsErrorTimeout || flag == EVENT_FLAG_STOP) {
uint32_t flag = furi_event_flag_wait(event, EVENT_FLAG_ALL, FuriFlagWaitAny, timeout);
if(flag == FuriFlagErrorTimeout || flag == EVENT_FLAG_STOP) {
break;
}
bool data_received = false;
@@ -515,7 +515,7 @@ static bool furi_hal_nfc_transparent_tx_rx(FuriHalNfcTxRxContext* tx_rx, uint16_
}
}
uint32_t timeout = DWT->CYCCNT - start;
if(timeout / furi_hal_delay_instructions_per_microsecond() > timeout_ms * 1000) {
if(timeout / furi_hal_cortex_instructions_per_microsecond() > timeout_ms * 1000) {
FURI_LOG_D(TAG, "Interrupt waiting timeout");
break;
}
@@ -668,7 +668,7 @@ bool furi_hal_nfc_tx_rx(FuriHalNfcTxRxContext* tx_rx, uint16_t timeout_ms) {
} else {
start = DWT->CYCCNT;
}
osDelay(1);
furi_delay_tick(1);
}
if(tx_rx->tx_rx_type == FuriHalNfcTxRxTypeRaw ||

View File

@@ -47,8 +47,9 @@ void furi_hal_os_init() {
furi_hal_gpio_init_simple(&gpio_ext_pa7, GpioModeOutputPushPull);
furi_hal_gpio_init_simple(&gpio_ext_pa6, GpioModeOutputPushPull);
furi_hal_gpio_init_simple(&gpio_ext_pa4, GpioModeOutputPushPull);
osTimerId_t second_timer = osTimerNew(furi_hal_os_timer_callback, osTimerPeriodic, NULL, NULL);
osTimerStart(second_timer, FURI_HAL_OS_TICK_HZ);
FuriTimer* second_timer =
furi_timer_alloc(furi_hal_os_timer_callback, FuriTimerTypePeriodic, NULL);
furi_timer_start(second_timer, FURI_HAL_OS_TICK_HZ);
#endif
FURI_LOG_I(TAG, "Init OK");

View File

@@ -1,6 +1,5 @@
#include <furi_hal_power.h>
#include <furi_hal_clock.h>
#include <furi_hal_delay.h>
#include <furi_hal_bt.h>
#include <furi_hal_resources.h>
#include <furi_hal_uart.h>
@@ -302,7 +301,7 @@ void furi_hal_power_shutdown() {
void furi_hal_power_off() {
// Crutch: shutting down with ext 3V3 off is causing LSE to stop
furi_hal_power_enable_external_3_3v();
furi_hal_delay_us(1000);
furi_delay_us(1000);
// Send poweroff to charger
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
bq25896_poweroff(&furi_hal_i2c_handle_power);

View File

@@ -1,5 +1,4 @@
#include <furi_hal_resources.h>
#include <furi_hal_delay.h>
#include <furi.h>
#include <stm32wbxx_ll_rcc.h>
@@ -98,7 +97,7 @@ void furi_hal_resources_init_early() {
furi_hal_gpio_init_simple(&gpio_usb_dp, GpioModeOutputOpenDrain);
furi_hal_gpio_write(&gpio_usb_dm, 0);
furi_hal_gpio_write(&gpio_usb_dp, 0);
furi_hal_delay_us(5); // Device Driven disconnect: 2.5us + extra to compensate cables
furi_delay_us(5); // Device Driven disconnect: 2.5us + extra to compensate cables
furi_hal_gpio_write(&gpio_usb_dm, 1);
furi_hal_gpio_write(&gpio_usb_dp, 1);
furi_hal_gpio_init_simple(&gpio_usb_dm, GpioModeAnalog);

View File

@@ -70,25 +70,25 @@ const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_2m = {
/* SPI Buses */
osMutexId_t furi_hal_spi_bus_r_mutex = NULL;
FuriMutex* furi_hal_spi_bus_r_mutex = NULL;
static void furi_hal_spi_bus_r_event_callback(FuriHalSpiBus* bus, FuriHalSpiBusEvent event) {
if(event == FuriHalSpiBusEventInit) {
furi_hal_spi_bus_r_mutex = osMutexNew(NULL);
furi_hal_spi_bus_r_mutex = furi_mutex_alloc(FuriMutexTypeNormal);
FURI_CRITICAL_ENTER();
LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_SPI1);
FURI_CRITICAL_EXIT();
bus->current_handle = NULL;
} else if(event == FuriHalSpiBusEventDeinit) {
furi_check(osMutexDelete(furi_hal_spi_bus_r_mutex) == osOK);
furi_mutex_free(furi_hal_spi_bus_r_mutex);
FURI_CRITICAL_ENTER();
LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_SPI1);
LL_APB2_GRP1_ReleaseReset(LL_APB2_GRP1_PERIPH_SPI1);
FURI_CRITICAL_EXIT();
} else if(event == FuriHalSpiBusEventLock) {
furi_check(osMutexAcquire(furi_hal_spi_bus_r_mutex, osWaitForever) == osOK);
furi_check(furi_mutex_acquire(furi_hal_spi_bus_r_mutex, FuriWaitForever) == FuriStatusOk);
} else if(event == FuriHalSpiBusEventUnlock) {
furi_check(osMutexRelease(furi_hal_spi_bus_r_mutex) == osOK);
furi_check(furi_mutex_release(furi_hal_spi_bus_r_mutex) == FuriStatusOk);
} else if(event == FuriHalSpiBusEventActivate) {
FURI_CRITICAL_ENTER();
LL_APB2_GRP1_ReleaseReset(LL_APB2_GRP1_PERIPH_SPI1);
@@ -105,25 +105,25 @@ FuriHalSpiBus furi_hal_spi_bus_r = {
.callback = furi_hal_spi_bus_r_event_callback,
};
osMutexId_t furi_hal_spi_bus_d_mutex = NULL;
FuriMutex* furi_hal_spi_bus_d_mutex = NULL;
static void furi_hal_spi_bus_d_event_callback(FuriHalSpiBus* bus, FuriHalSpiBusEvent event) {
if(event == FuriHalSpiBusEventInit) {
furi_hal_spi_bus_d_mutex = osMutexNew(NULL);
furi_hal_spi_bus_d_mutex = furi_mutex_alloc(FuriMutexTypeNormal);
FURI_CRITICAL_ENTER();
LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_SPI2);
FURI_CRITICAL_EXIT();
bus->current_handle = NULL;
} else if(event == FuriHalSpiBusEventDeinit) {
furi_check(osMutexDelete(furi_hal_spi_bus_d_mutex) == osOK);
furi_mutex_free(furi_hal_spi_bus_d_mutex);
FURI_CRITICAL_ENTER();
LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_SPI2);
LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_SPI2);
FURI_CRITICAL_EXIT();
} else if(event == FuriHalSpiBusEventLock) {
furi_check(osMutexAcquire(furi_hal_spi_bus_d_mutex, osWaitForever) == osOK);
furi_check(furi_mutex_acquire(furi_hal_spi_bus_d_mutex, FuriWaitForever) == FuriStatusOk);
} else if(event == FuriHalSpiBusEventUnlock) {
furi_check(osMutexRelease(furi_hal_spi_bus_d_mutex) == osOK);
furi_check(furi_mutex_release(furi_hal_spi_bus_d_mutex) == FuriStatusOk);
} else if(event == FuriHalSpiBusEventActivate) {
FURI_CRITICAL_ENTER();
LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_SPI2);

View File

@@ -6,7 +6,6 @@
#include <furi_hal_resources.h>
#include <furi.h>
#include <furi_hal_delay.h>
static bool furi_hal_usart_prev_enabled[2];

View File

@@ -240,8 +240,8 @@ static int32_t furi_hal_usb_thread(void* context) {
}
while(true) {
uint32_t flags = furi_thread_flags_wait(USB_SRV_ALL_EVENTS, osFlagsWaitAny, 500);
if((flags & osFlagsError) == 0) {
uint32_t flags = furi_thread_flags_wait(USB_SRV_ALL_EVENTS, FuriFlagWaitAny, 500);
if((flags & FuriFlagError) == 0) {
if(flags & EventModeChange) {
if(usb.if_next != usb.if_cur) {
if_new = usb.if_next;
@@ -250,7 +250,7 @@ static int32_t furi_hal_usb_thread(void* context) {
susp_evt(&udev, 0, 0);
usbd_connect(&udev, false);
usb.enabled = false;
osDelay(USB_RECONNECT_DELAY);
furi_delay_ms(USB_RECONNECT_DELAY);
}
flags |= EventModeChangeStart;
}
@@ -267,7 +267,7 @@ static int32_t furi_hal_usb_thread(void* context) {
usbd_enable(&udev, true);
if_new = usb.if_cur;
osDelay(USB_RECONNECT_DELAY);
furi_delay_ms(USB_RECONNECT_DELAY);
flags |= EventModeChangeStart;
}
if(flags & EventModeChangeStart) { // Second stage of mode change process

View File

@@ -254,7 +254,7 @@ static bool hid_send_report(uint8_t report_id);
static usbd_respond hid_ep_config(usbd_device* dev, uint8_t cfg);
static usbd_respond hid_control(usbd_device* dev, usbd_ctlreq* req, usbd_rqc_callback* callback);
static usbd_device* usb_dev;
static osSemaphoreId_t hid_semaphore = NULL;
static FuriSemaphore* hid_semaphore = NULL;
static bool hid_connected = false;
static HidStateCallback callback;
static void* cb_ctx;
@@ -372,7 +372,7 @@ static void* hid_set_string_descr(char* str) {
static void hid_init(usbd_device* dev, FuriHalUsbInterface* intf, void* ctx) {
UNUSED(intf);
FuriHalUsbHidConfig* cfg = (FuriHalUsbHidConfig*)ctx;
if(hid_semaphore == NULL) hid_semaphore = osSemaphoreNew(1, 1, NULL);
if(hid_semaphore == NULL) hid_semaphore = furi_semaphore_alloc(1, 1);
usb_dev = dev;
hid_report.keyboard.report_id = ReportIdKeyboard;
hid_report.mouse.report_id = ReportIdMouse;
@@ -428,7 +428,7 @@ static void hid_on_suspend(usbd_device* dev) {
UNUSED(dev);
if(hid_connected) {
hid_connected = false;
osSemaphoreRelease(hid_semaphore);
furi_semaphore_release(hid_semaphore);
if(callback != NULL) {
callback(false, cb_ctx);
}
@@ -438,7 +438,7 @@ static void hid_on_suspend(usbd_device* dev) {
static bool hid_send_report(uint8_t report_id) {
if((hid_semaphore == NULL) || (hid_connected == false)) return false;
furi_check(osSemaphoreAcquire(hid_semaphore, osWaitForever) == osOK);
furi_check(furi_semaphore_acquire(hid_semaphore, FuriWaitForever) == FuriStatusOk);
if(hid_connected == true) {
if(report_id == ReportIdKeyboard)
usbd_ep_write(usb_dev, HID_EP_IN, &hid_report.keyboard, sizeof(hid_report.keyboard));
@@ -454,7 +454,7 @@ static bool hid_send_report(uint8_t report_id) {
static void hid_txrx_ep_callback(usbd_device* dev, uint8_t event, uint8_t ep) {
UNUSED(dev);
if(event == usbd_evt_eptx) {
osSemaphoreRelease(hid_semaphore);
furi_semaphore_release(hid_semaphore);
} else {
struct HidReportLED leds;
usbd_ep_read(usb_dev, ep, &leds, 2);

View File

@@ -147,7 +147,7 @@ static usbd_respond hid_u2f_ep_config(usbd_device* dev, uint8_t cfg);
static usbd_respond
hid_u2f_control(usbd_device* dev, usbd_ctlreq* req, usbd_rqc_callback* callback);
static usbd_device* usb_dev;
static osSemaphoreId_t hid_u2f_semaphore = NULL;
static FuriSemaphore* hid_u2f_semaphore = NULL;
static bool hid_u2f_connected = false;
static HidU2fCallback callback;
@@ -193,7 +193,7 @@ static void hid_u2f_init(usbd_device* dev, FuriHalUsbInterface* intf, void* ctx)
UNUSED(intf);
UNUSED(ctx);
if(hid_u2f_semaphore == NULL) {
hid_u2f_semaphore = osSemaphoreNew(1, 1, NULL);
hid_u2f_semaphore = furi_semaphore_alloc(1, 1);
}
usb_dev = dev;
@@ -220,7 +220,7 @@ static void hid_u2f_on_suspend(usbd_device* dev) {
UNUSED(dev);
if(hid_u2f_connected) {
hid_u2f_connected = false;
osSemaphoreRelease(hid_u2f_semaphore);
furi_semaphore_release(hid_u2f_semaphore);
if(callback != NULL) {
callback(HidU2fDisconnected, cb_ctx);
}
@@ -229,7 +229,7 @@ static void hid_u2f_on_suspend(usbd_device* dev) {
void furi_hal_hid_u2f_send_response(uint8_t* data, uint8_t len) {
if((hid_u2f_semaphore == NULL) || (hid_u2f_connected == false)) return;
furi_check(osSemaphoreAcquire(hid_u2f_semaphore, osWaitForever) == osOK);
furi_check(furi_semaphore_acquire(hid_u2f_semaphore, FuriWaitForever) == FuriStatusOk);
if(hid_u2f_connected == true) {
usbd_ep_write(usb_dev, HID_EP_OUT, data, len);
}
@@ -253,7 +253,7 @@ static void hid_u2f_tx_ep_callback(usbd_device* dev, uint8_t event, uint8_t ep)
UNUSED(dev);
UNUSED(event);
UNUSED(ep);
osSemaphoreRelease(hid_u2f_semaphore);
furi_semaphore_release(hid_u2f_semaphore);
}
static void hid_u2f_txrx_ep_callback(usbd_device* dev, uint8_t event, uint8_t ep) {

View File

@@ -9,6 +9,7 @@
template <unsigned int N> struct STOP_EXTERNING_ME {};
#endif
#include "furi_hal_cortex.h"
#include "furi_hal_clock.h"
#include "furi_hal_crypto.h"
#include "furi_hal_console.h"
@@ -21,7 +22,6 @@ template <unsigned int N> struct STOP_EXTERNING_ME {};
#include "furi_hal_speaker.h"
#include "furi_hal_gpio.h"
#include "furi_hal_light.h"
#include "furi_hal_delay.h"
#include "furi_hal_power.h"
#include "furi_hal_interrupt.h"
#include "furi_hal_version.h"

View File

@@ -0,0 +1,32 @@
/**
* @file furi_hal_cortex.h
* ARM Cortex HAL
*/
#pragma once
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/** Early init stage for cortex
*/
void furi_hal_cortex_init_early();
/** Microseconds delay
*
* @param[in] microseconds The microseconds to wait
*/
void furi_hal_cortex_delay_us(uint32_t microseconds);
/** Get instructions per microsecond count
*
* @return instructions per microsecond count
*/
uint32_t furi_hal_cortex_instructions_per_microsecond();
#ifdef __cplusplus
}
#endif

View File

@@ -1,51 +0,0 @@
/**
* @file furi_hal_delay.h
* Delay HAL API
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
/** Init Delay subsystem */
void furi_hal_delay_init();
/** Get instructions per microsecond count */
uint32_t furi_hal_delay_instructions_per_microsecond();
/** Get current tick counter
*
* System uptime, may overflow.
*
* @return Current ticks in milliseconds
*/
uint32_t furi_hal_get_tick(void);
/** Convert milliseconds to ticks
*
* @param[in] milliseconds time in milliseconds
* @return time in ticks
*/
uint32_t furi_hal_ms_to_ticks(float milliseconds);
/** Delay in milliseconds
* @warning Cannot be used from ISR
*
* @param[in] milliseconds milliseconds to wait
*/
void furi_hal_delay_ms(float milliseconds);
/** Delay in microseconds
*
* @param[in] microseconds microseconds to wait
*/
void furi_hal_delay_us(float microseconds);
#ifdef __cplusplus
}
#endif