FuriHal: UART refactoring (#3211)

* FuriHal: UART refactoring
* ApiSymbols: add furi_record_destroy
* FuriHal: cleanup serial API, add logging configuration in RTC
* FuriHal: hide private part in _i header. Toolbox: cleanup value index. SystemSettings: logging device and baudrate.
* FuriHal: RTC logging method documentation
* Synchronize API Symbols
* Furi: mark HEAP_PRINT_DEBUG as broken
* FuriHal: furi_hal_serial, add custom IRQ func
* Fix PR review issues
* FuriHal: UART add reception DMA (#3220)
* FuriHal: add DMA serial rx mode
* usb_uart_bridge: switch to working with DMA
* Sync api symbol versions
* FuriHal: update serial docs and api
* FuriHal: Selial added similar API for simple reception mode as with DMA
* FuriHal: Update API target H18
* API: ver API H7
* FuriHal: Serial error processing
* FuriHal: fix furi_hal_serial set baudrate
* Sync api symbols
* FuriHal: cleanup serial isr and various flag handling procedures
* FuriHal: cleanup and simplify serial API
* Debug: update UART Echo serial related flags
* FuriHal: update serial API symbols naming
* FuriHalSerial: various improvements and PR review fixes
* FuriHal: proper ISR function signatures

---------

Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
Co-authored-by: hedger <hedger@users.noreply.github.com>
Co-authored-by: SkorP <skorpionm@yandex.ru>
Co-authored-by: Skorpionm <85568270+Skorpionm@users.noreply.github.com>
This commit is contained in:
あく 2024-01-16 08:09:37 +09:00 committed by GitHub
parent d73d007797
commit fc043da9c6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
37 changed files with 1966 additions and 759 deletions

View file

@ -1,13 +1,14 @@
#include <furi.h>
#include <furi_hal.h>
#include <gui/gui.h>
#include <notification/notification.h>
#include <notification/notification_messages.h>
#include <gui/elements.h>
#include <furi_hal_uart.h>
#include <furi_hal_console.h>
#include <gui/view_dispatcher.h>
#include <gui/modules/dialog_ex.h>
#include <notification/notification.h>
#include <notification/notification_messages.h>
#define LINES_ON_SCREEN 6
#define COLUMNS_ON_SCREEN 21
#define TAG "UartEcho"
@ -22,6 +23,7 @@ typedef struct {
View* view;
FuriThread* worker_thread;
FuriStreamBuffer* rx_stream;
FuriHalSerialHandle* serial_handle;
} UartEchoApp;
typedef struct {
@ -39,10 +41,16 @@ struct UartDumpModel {
typedef enum {
WorkerEventReserved = (1 << 0), // Reserved for StreamBuffer internal event
WorkerEventStop = (1 << 1),
WorkerEventRx = (1 << 2),
WorkerEventRxData = (1 << 2),
WorkerEventRxIdle = (1 << 3),
WorkerEventRxOverrunError = (1 << 4),
WorkerEventRxFramingError = (1 << 5),
WorkerEventRxNoiseError = (1 << 6),
} WorkerEventFlags;
#define WORKER_EVENTS_MASK (WorkerEventStop | WorkerEventRx)
#define WORKER_EVENTS_MASK \
(WorkerEventStop | WorkerEventRxData | WorkerEventRxIdle | WorkerEventRxOverrunError | \
WorkerEventRxFramingError | WorkerEventRxNoiseError)
const NotificationSequence sequence_notification = {
&message_display_backlight_on,
@ -91,14 +99,39 @@ static uint32_t uart_echo_exit(void* context) {
return VIEW_NONE;
}
static void uart_echo_on_irq_cb(UartIrqEvent ev, uint8_t data, void* context) {
static void
uart_echo_on_irq_cb(FuriHalSerialHandle* handle, FuriHalSerialRxEvent event, void* context) {
furi_assert(context);
UNUSED(handle);
UartEchoApp* app = context;
volatile FuriHalSerialRxEvent event_copy = event;
UNUSED(event_copy);
if(ev == UartIrqEventRXNE) {
WorkerEventFlags flag = 0;
if(event & FuriHalSerialRxEventData) {
uint8_t data = furi_hal_serial_async_rx(handle);
furi_stream_buffer_send(app->rx_stream, &data, 1, 0);
furi_thread_flags_set(furi_thread_get_id(app->worker_thread), WorkerEventRx);
flag |= WorkerEventRxData;
}
if(event & FuriHalSerialRxEventIdle) {
//idle line detected, packet transmission may have ended
flag |= WorkerEventRxIdle;
}
//error detected
if(event & FuriHalSerialRxEventFrameError) {
flag |= WorkerEventRxFramingError;
}
if(event & FuriHalSerialRxEventNoiseError) {
flag |= WorkerEventRxNoiseError;
}
if(event & FuriHalSerialRxEventOverrunError) {
flag |= WorkerEventRxOverrunError;
}
furi_thread_flags_set(furi_thread_get_id(app->worker_thread), flag);
}
static void uart_echo_push_to_list(UartDumpModel* model, const char data) {
@ -153,13 +186,13 @@ static int32_t uart_echo_worker(void* context) {
furi_check((events & FuriFlagError) == 0);
if(events & WorkerEventStop) break;
if(events & WorkerEventRx) {
if(events & WorkerEventRxData) {
size_t length = 0;
do {
uint8_t data[64];
length = furi_stream_buffer_receive(app->rx_stream, data, 64, 0);
if(length > 0) {
furi_hal_uart_tx(FuriHalUartIdUSART1, data, length);
furi_hal_serial_tx(app->serial_handle, data, length);
with_view_model(
app->view,
UartDumpModel * model,
@ -176,6 +209,23 @@ static int32_t uart_echo_worker(void* context) {
with_view_model(
app->view, UartDumpModel * model, { UNUSED(model); }, true);
}
if(events & WorkerEventRxIdle) {
furi_hal_serial_tx(app->serial_handle, (uint8_t*)"\r\nDetect IDLE\r\n", 15);
}
if(events &
(WorkerEventRxOverrunError | WorkerEventRxFramingError | WorkerEventRxNoiseError)) {
if(events & WorkerEventRxOverrunError) {
furi_hal_serial_tx(app->serial_handle, (uint8_t*)"\r\nDetect ORE\r\n", 14);
}
if(events & WorkerEventRxFramingError) {
furi_hal_serial_tx(app->serial_handle, (uint8_t*)"\r\nDetect FE\r\n", 13);
}
if(events & WorkerEventRxNoiseError) {
furi_hal_serial_tx(app->serial_handle, (uint8_t*)"\r\nDetect NE\r\n", 13);
}
}
}
return 0;
@ -221,9 +271,11 @@ static UartEchoApp* uart_echo_app_alloc(uint32_t baudrate) {
furi_thread_start(app->worker_thread);
// Enable uart listener
furi_hal_console_disable();
furi_hal_uart_set_br(FuriHalUartIdUSART1, baudrate);
furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, uart_echo_on_irq_cb, app);
app->serial_handle = furi_hal_serial_control_acquire(FuriHalSerialIdUsart);
furi_check(app->serial_handle);
furi_hal_serial_init(app->serial_handle, baudrate);
furi_hal_serial_async_rx_start(app->serial_handle, uart_echo_on_irq_cb, app, true);
return app;
}
@ -231,12 +283,13 @@ static UartEchoApp* uart_echo_app_alloc(uint32_t baudrate) {
static void uart_echo_app_free(UartEchoApp* app) {
furi_assert(app);
furi_hal_console_enable(); // this will also clear IRQ callback so thread is no longer referenced
furi_thread_flags_set(furi_thread_get_id(app->worker_thread), WorkerEventStop);
furi_thread_join(app->worker_thread);
furi_thread_free(app->worker_thread);
furi_hal_serial_deinit(app->serial_handle);
furi_hal_serial_control_release(app->serial_handle);
// Free views
view_dispatcher_remove_view(app->view_dispatcher, 0);

View file

@ -3,7 +3,7 @@ App(
name="GPIO",
apptype=FlipperAppType.MENUEXTERNAL,
entry_point="gpio_app",
stack_size=1 * 1024,
stack_size=2 * 1024,
icon="A_GPIO_14",
order=50,
fap_libs=["assets"],

View file

@ -46,7 +46,7 @@ void line_ensure_flow_invariant(GpioApp* app) {
// selected. This function enforces that invariant by resetting flow_pins
// to None if it is configured to 16,15 when LPUART is selected.
uint8_t available_flow_pins = app->usb_uart_cfg->uart_ch == FuriHalUartIdLPUART1 ? 3 : 4;
uint8_t available_flow_pins = app->usb_uart_cfg->uart_ch == FuriHalSerialIdLpuart ? 3 : 4;
VariableItem* item = app->var_item_flow;
variable_item_set_values_count(item, available_flow_pins);
@ -77,9 +77,9 @@ static void line_port_cb(VariableItem* item) {
variable_item_set_current_value_text(item, uart_ch[index]);
if(index == 0)
app->usb_uart_cfg->uart_ch = FuriHalUartIdUSART1;
app->usb_uart_cfg->uart_ch = FuriHalSerialIdUsart;
else if(index == 1)
app->usb_uart_cfg->uart_ch = FuriHalUartIdLPUART1;
app->usb_uart_cfg->uart_ch = FuriHalSerialIdLpuart;
line_ensure_flow_invariant(app);
view_dispatcher_send_custom_event(app->view_dispatcher, GpioUsbUartEventConfigSet);

View file

@ -29,17 +29,18 @@ typedef enum {
WorkerEvtTxStop = (1 << 2),
WorkerEvtCdcRx = (1 << 3),
WorkerEvtCdcTxComplete = (1 << 4),
WorkerEvtCfgChange = (1 << 4),
WorkerEvtCfgChange = (1 << 5),
WorkerEvtLineCfgSet = (1 << 5),
WorkerEvtCtrlLineSet = (1 << 6),
WorkerEvtLineCfgSet = (1 << 6),
WorkerEvtCtrlLineSet = (1 << 7),
} WorkerEvtFlags;
#define WORKER_ALL_RX_EVENTS \
(WorkerEvtStop | WorkerEvtRxDone | WorkerEvtCfgChange | WorkerEvtLineCfgSet | \
WorkerEvtCtrlLineSet)
WorkerEvtCtrlLineSet | WorkerEvtCdcTxComplete)
#define WORKER_ALL_TX_EVENTS (WorkerEvtTxStop | WorkerEvtCdcRx)
struct UsbUartBridge {
@ -50,6 +51,7 @@ struct UsbUartBridge {
FuriThread* tx_thread;
FuriStreamBuffer* rx_stream;
FuriHalSerialHandle* serial_handle;
FuriMutex* usb_mutex;
@ -80,11 +82,23 @@ static const CdcCallbacks cdc_cb = {
static int32_t usb_uart_tx_thread(void* context);
static void usb_uart_on_irq_cb(UartIrqEvent ev, uint8_t data, void* context) {
static void usb_uart_on_irq_rx_dma_cb(
FuriHalSerialHandle* handle,
FuriHalSerialRxEvent ev,
size_t size,
void* context) {
UsbUartBridge* usb_uart = (UsbUartBridge*)context;
if(ev == UartIrqEventRXNE) {
furi_stream_buffer_send(usb_uart->rx_stream, &data, 1, 0);
if(ev & (FuriHalSerialRxEventData | FuriHalSerialRxEventIdle)) {
uint8_t data[FURI_HAL_SERIAL_DMA_BUFFER_SIZE] = {0};
while(size) {
size_t ret = furi_hal_serial_dma_rx(
handle,
data,
(size > FURI_HAL_SERIAL_DMA_BUFFER_SIZE) ? FURI_HAL_SERIAL_DMA_BUFFER_SIZE : size);
furi_stream_buffer_send(usb_uart->rx_stream, data, ret, 0);
size -= ret;
};
furi_thread_flags_set(furi_thread_get_id(usb_uart->thread), WorkerEvtRxDone);
}
}
@ -116,32 +130,33 @@ static void usb_uart_vcp_deinit(UsbUartBridge* usb_uart, uint8_t vcp_ch) {
}
static void usb_uart_serial_init(UsbUartBridge* usb_uart, uint8_t uart_ch) {
if(uart_ch == FuriHalUartIdUSART1) {
furi_hal_console_disable();
} else if(uart_ch == FuriHalUartIdLPUART1) {
furi_hal_uart_init(uart_ch, 115200);
}
furi_hal_uart_set_irq_cb(uart_ch, usb_uart_on_irq_cb, usb_uart);
furi_assert(!usb_uart->serial_handle);
usb_uart->serial_handle = furi_hal_serial_control_acquire(uart_ch);
furi_assert(usb_uart->serial_handle);
furi_hal_serial_init(usb_uart->serial_handle, 115200);
furi_hal_serial_dma_rx_start(
usb_uart->serial_handle, usb_uart_on_irq_rx_dma_cb, usb_uart, false);
}
static void usb_uart_serial_deinit(UsbUartBridge* usb_uart, uint8_t uart_ch) {
UNUSED(usb_uart);
furi_hal_uart_set_irq_cb(uart_ch, NULL, NULL);
if(uart_ch == FuriHalUartIdUSART1)
furi_hal_console_enable();
else if(uart_ch == FuriHalUartIdLPUART1)
furi_hal_uart_deinit(uart_ch);
static void usb_uart_serial_deinit(UsbUartBridge* usb_uart) {
furi_assert(usb_uart->serial_handle);
furi_hal_serial_deinit(usb_uart->serial_handle);
furi_hal_serial_control_release(usb_uart->serial_handle);
usb_uart->serial_handle = NULL;
}
static void usb_uart_set_baudrate(UsbUartBridge* usb_uart, uint32_t baudrate) {
if(baudrate != 0) {
furi_hal_uart_set_br(usb_uart->cfg.uart_ch, baudrate);
furi_hal_serial_set_br(usb_uart->serial_handle, baudrate);
usb_uart->st.baudrate_cur = baudrate;
} else {
struct usb_cdc_line_coding* line_cfg =
furi_hal_cdc_get_port_settings(usb_uart->cfg.vcp_ch);
if(line_cfg->dwDTERate > 0) {
furi_hal_uart_set_br(usb_uart->cfg.uart_ch, line_cfg->dwDTERate);
furi_hal_serial_set_br(usb_uart->serial_handle, line_cfg->dwDTERate);
usb_uart->st.baudrate_cur = line_cfg->dwDTERate;
}
}
@ -191,7 +206,7 @@ static int32_t usb_uart_worker(void* context) {
furi_thread_flags_wait(WORKER_ALL_RX_EVENTS, FuriFlagWaitAny, FuriWaitForever);
furi_check(!(events & FuriFlagError));
if(events & WorkerEvtStop) break;
if(events & WorkerEvtRxDone) {
if(events & (WorkerEvtRxDone | WorkerEvtCdcTxComplete)) {
size_t len = furi_stream_buffer_receive(
usb_uart->rx_stream, usb_uart->rx_buf, USB_CDC_PKT_LEN, 0);
if(len > 0) {
@ -223,7 +238,7 @@ static int32_t usb_uart_worker(void* context) {
furi_thread_flags_set(furi_thread_get_id(usb_uart->tx_thread), WorkerEvtTxStop);
furi_thread_join(usb_uart->tx_thread);
usb_uart_serial_deinit(usb_uart, usb_uart->cfg.uart_ch);
usb_uart_serial_deinit(usb_uart);
usb_uart_serial_init(usb_uart, usb_uart->cfg_new.uart_ch);
usb_uart->cfg.uart_ch = usb_uart->cfg_new.uart_ch;
@ -274,7 +289,7 @@ static int32_t usb_uart_worker(void* context) {
}
}
usb_uart_vcp_deinit(usb_uart, usb_uart->cfg.vcp_ch);
usb_uart_serial_deinit(usb_uart, usb_uart->cfg.uart_ch);
usb_uart_serial_deinit(usb_uart);
furi_hal_gpio_init(USB_USART_DE_RE_PIN, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
@ -320,18 +335,10 @@ static int32_t usb_uart_tx_thread(void* context) {
if(usb_uart->cfg.software_de_re != 0)
furi_hal_gpio_write(USB_USART_DE_RE_PIN, false);
furi_hal_uart_tx(usb_uart->cfg.uart_ch, data, len);
furi_hal_serial_tx(usb_uart->serial_handle, data, len);
if(usb_uart->cfg.software_de_re != 0) {
//TODO: FL-3276 port to new USART API
if(usb_uart->cfg.uart_ch == FuriHalUartIdUSART1) {
while(!LL_USART_IsActiveFlag_TC(USART1))
;
} else if(usb_uart->cfg.uart_ch == FuriHalUartIdLPUART1) {
while(!LL_LPUART_IsActiveFlag_TC(LPUART1))
;
}
furi_hal_serial_tx_wait_complete(usb_uart->serial_handle);
furi_hal_gpio_write(USB_USART_DE_RE_PIN, true);
}
}
@ -345,6 +352,7 @@ static int32_t usb_uart_tx_thread(void* context) {
static void vcp_on_cdc_tx_complete(void* context) {
UsbUartBridge* usb_uart = (UsbUartBridge*)context;
furi_semaphore_release(usb_uart->tx_sem);
furi_thread_flags_set(furi_thread_get_id(usb_uart->thread), WorkerEvtCdcTxComplete);
}
static void vcp_on_cdc_rx(void* context) {

View file

@ -8,8 +8,6 @@
#include <furi_hal_usb_hid_u2f.h>
#include <storage/storage.h>
#include <furi_hal_console.h>
#define TAG "U2fHid"
#define WORKER_TAG TAG "Worker"

View file

@ -211,7 +211,12 @@ void cli_command_log(Cli* cli, FuriString* args, void* context) {
furi_log_level_to_string(furi_log_get_level(), &current_level);
printf("Current log level: %s\r\n", current_level);
furi_hal_console_set_tx_callback(cli_command_log_tx_callback, ring);
FuriLogHandler log_handler = {
.callback = cli_command_log_tx_callback,
.context = ring,
};
furi_log_add_handler(log_handler);
printf("Use <log ?> to list available log levels\r\n");
printf("Press CTRL+C to stop...\r\n");
@ -220,7 +225,7 @@ void cli_command_log(Cli* cli, FuriString* args, void* context) {
cli_write(cli, buffer, ret);
}
furi_hal_console_set_tx_callback(NULL, NULL);
furi_log_remove_handler(log_handler);
if(restore_log_level) {
// There will be strange behaviour if log level is set from settings while log command is running

View file

@ -24,12 +24,56 @@ const uint32_t log_level_value[] = {
};
static void log_level_changed(VariableItem* item) {
// SystemSettings* app = variable_item_get_context(item);
uint8_t index = variable_item_get_current_value_index(item);
variable_item_set_current_value_text(item, log_level_text[index]);
furi_hal_rtc_set_log_level(log_level_value[index]);
}
const char* const log_device_text[] = {
"USART",
"LPUART",
"None",
};
const uint32_t log_device_value[] = {
FuriHalRtcLogDeviceUsart,
FuriHalRtcLogDeviceLpuart,
FuriHalRtcLogDeviceNone};
static void log_device_changed(VariableItem* item) {
uint8_t index = variable_item_get_current_value_index(item);
variable_item_set_current_value_text(item, log_device_text[index]);
furi_hal_rtc_set_log_device(log_device_value[index]);
}
const char* const log_baud_rate_text[] = {
"9600",
"38400",
"57600",
"115200",
"230400",
"460800",
"921600",
"1843200",
};
const uint32_t log_baud_rate_value[] = {
FuriHalRtcLogBaudRate9600,
FuriHalRtcLogBaudRate38400,
FuriHalRtcLogBaudRate57600,
FuriHalRtcLogBaudRate115200,
FuriHalRtcLogBaudRate230400,
FuriHalRtcLogBaudRate460800,
FuriHalRtcLogBaudRate921600,
FuriHalRtcLogBaudRate1843200,
};
static void log_baud_rate_changed(VariableItem* item) {
uint8_t index = variable_item_get_current_value_index(item);
variable_item_set_current_value_text(item, log_baud_rate_text[index]);
furi_hal_rtc_set_log_baud_rate(log_baud_rate_value[index]);
}
const char* const debug_text[] = {
"OFF",
"ON",
@ -64,7 +108,6 @@ const uint32_t heap_trace_mode_value[] = {
};
static void heap_trace_mode_changed(VariableItem* item) {
// SystemSettings* app = variable_item_get_context(item);
uint8_t index = variable_item_get_current_value_index(item);
variable_item_set_current_value_text(item, heap_trace_mode_text[index]);
furi_hal_rtc_set_heap_track_mode(heap_trace_mode_value[index]);
@ -81,7 +124,6 @@ const uint32_t mesurement_units_value[] = {
};
static void mesurement_units_changed(VariableItem* item) {
// SystemSettings* app = variable_item_get_context(item);
uint8_t index = variable_item_get_current_value_index(item);
variable_item_set_current_value_text(item, mesurement_units_text[index]);
locale_set_measurement_unit(mesurement_units_value[index]);
@ -98,7 +140,6 @@ const uint32_t time_format_value[] = {
};
static void time_format_changed(VariableItem* item) {
// SystemSettings* app = variable_item_get_context(item);
uint8_t index = variable_item_get_current_value_index(item);
variable_item_set_current_value_text(item, time_format_text[index]);
locale_set_time_format(time_format_value[index]);
@ -117,7 +158,6 @@ const uint32_t date_format_value[] = {
};
static void date_format_changed(VariableItem* item) {
// SystemSettings* app = variable_item_get_context(item);
uint8_t index = variable_item_get_current_value_index(item);
variable_item_set_current_value_text(item, date_format_text[index]);
locale_set_date_format(date_format_value[index]);
@ -227,6 +267,24 @@ SystemSettings* system_settings_alloc() {
variable_item_set_current_value_index(item, value_index);
variable_item_set_current_value_text(item, log_level_text[value_index]);
item = variable_item_list_add(
app->var_item_list, "Log Device", COUNT_OF(log_device_text), log_device_changed, app);
value_index = value_index_uint32(
furi_hal_rtc_get_log_device(), log_device_value, COUNT_OF(log_device_text));
variable_item_set_current_value_index(item, value_index);
variable_item_set_current_value_text(item, log_device_text[value_index]);
item = variable_item_list_add(
app->var_item_list,
"Log Baud Rate",
COUNT_OF(log_baud_rate_text),
log_baud_rate_changed,
app);
value_index = value_index_uint32(
furi_hal_rtc_get_log_baud_rate(), log_baud_rate_value, COUNT_OF(log_baud_rate_text));
variable_item_set_current_value_index(item, value_index);
variable_item_set_current_value_text(item, log_baud_rate_text[value_index]);
item = variable_item_list_add(
app->var_item_list, "Debug", COUNT_OF(debug_text), debug_changed, app);
value_index = furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug) ? 1 : 0;

View file

@ -58,7 +58,7 @@ When not using the API, these peripherals MUST be enabled by the user code and t
| SPI2 | -- |
| I2C1 | `furi_hal_i2c.h` |
| I2C3 | -- |
| USART1 | `furi_hal_uart.h` |
| USART1 | `furi_hal_serial.h` |
| LPUART1 | -- |
| USB | `furi_hal_usb.h` |
@ -102,8 +102,8 @@ Below is the list of DMA channels and their usage by the system.
| -- | 3 | | |
| -- | 4 | yes | pulse reader |
| -- | 5 | | |
| -- | 6 | | |
| -- | 7 | | |
| -- | 6 | yes | USART_Rx |
| -- | 7 | yes | LPUART_Rx |
| DMA2 | 1 | yes | infrared, lfrfid, subghz, |
| -- | 2 | yes | -- |
| -- | 3 | yes | cc1101_ext |

View file

@ -2,7 +2,6 @@
#include "common_defines.h"
#include <stm32wbxx.h>
#include <furi_hal_console.h>
#include <furi_hal_power.h>
#include <furi_hal_rtc.h>
#include <furi_hal_debug.h>
@ -59,69 +58,69 @@ extern size_t xPortGetTotalHeapSize(void);
static void __furi_put_uint32_as_text(uint32_t data) {
char tmp_str[] = "-2147483648";
itoa(data, tmp_str, 10);
furi_hal_console_puts(tmp_str);
furi_log_puts(tmp_str);
}
static void __furi_put_uint32_as_hex(uint32_t data) {
char tmp_str[] = "0xFFFFFFFF";
itoa(data, tmp_str, 16);
furi_hal_console_puts(tmp_str);
furi_log_puts(tmp_str);
}
static void __furi_print_register_info() {
// Print registers
for(uint8_t i = 0; i < 12; i++) {
furi_hal_console_puts("\r\n\tr");
furi_log_puts("\r\n\tr");
__furi_put_uint32_as_text(i);
furi_hal_console_puts(" : ");
furi_log_puts(" : ");
__furi_put_uint32_as_hex(__furi_check_registers[i]);
}
furi_hal_console_puts("\r\n\tlr : ");
furi_log_puts("\r\n\tlr : ");
__furi_put_uint32_as_hex(__furi_check_registers[12]);
}
static void __furi_print_stack_info() {
furi_hal_console_puts("\r\n\tstack watermark: ");
furi_log_puts("\r\n\tstack watermark: ");
__furi_put_uint32_as_text(uxTaskGetStackHighWaterMark(NULL) * 4);
}
static void __furi_print_bt_stack_info() {
const FuriHalBtHardfaultInfo* fault_info = furi_hal_bt_get_hardfault_info();
if(fault_info == NULL) {
furi_hal_console_puts("\r\n\tcore2: not faulted");
furi_log_puts("\r\n\tcore2: not faulted");
} else {
furi_hal_console_puts("\r\n\tcore2: hardfaulted.\r\n\tPC: ");
furi_log_puts("\r\n\tcore2: hardfaulted.\r\n\tPC: ");
__furi_put_uint32_as_hex(fault_info->source_pc);
furi_hal_console_puts("\r\n\tLR: ");
furi_log_puts("\r\n\tLR: ");
__furi_put_uint32_as_hex(fault_info->source_lr);
furi_hal_console_puts("\r\n\tSP: ");
furi_log_puts("\r\n\tSP: ");
__furi_put_uint32_as_hex(fault_info->source_sp);
}
}
static void __furi_print_heap_info() {
furi_hal_console_puts("\r\n\t heap total: ");
furi_log_puts("\r\n\t heap total: ");
__furi_put_uint32_as_text(xPortGetTotalHeapSize());
furi_hal_console_puts("\r\n\t heap free: ");
furi_log_puts("\r\n\t heap free: ");
__furi_put_uint32_as_text(xPortGetFreeHeapSize());
furi_hal_console_puts("\r\n\t heap watermark: ");
furi_log_puts("\r\n\t heap watermark: ");
__furi_put_uint32_as_text(xPortGetMinimumEverFreeHeapSize());
}
static void __furi_print_name(bool isr) {
if(isr) {
furi_hal_console_puts("[ISR ");
furi_log_puts("[ISR ");
__furi_put_uint32_as_text(__get_IPSR());
furi_hal_console_puts("] ");
furi_log_puts("] ");
} else {
const char* name = pcTaskGetName(NULL);
if(name == NULL) {
furi_hal_console_puts("[main] ");
furi_log_puts("[main] ");
} else {
furi_hal_console_puts("[");
furi_hal_console_puts(name);
furi_hal_console_puts("] ");
furi_log_puts("[");
furi_log_puts(name);
furi_log_puts("] ");
}
}
}
@ -140,9 +139,9 @@ FURI_NORETURN void __furi_crash_implementation() {
__furi_check_message = "furi_check failed";
}
furi_hal_console_puts("\r\n\033[0;31m[CRASH]");
furi_log_puts("\r\n\033[0;31m[CRASH]");
__furi_print_name(isr);
furi_hal_console_puts(__furi_check_message);
furi_log_puts(__furi_check_message);
__furi_print_register_info();
if(!isr) {
@ -157,8 +156,8 @@ FURI_NORETURN void __furi_crash_implementation() {
#ifdef FURI_NDEBUG
if(debug) {
#endif
furi_hal_console_puts("\r\nSystem halted. Connect debugger for more info\r\n");
furi_hal_console_puts("\033[0m\r\n");
furi_log_puts("\r\nSystem halted. Connect debugger for more info\r\n");
furi_log_puts("\033[0m\r\n");
furi_hal_debug_enable();
RESTORE_REGISTERS_AND_HALT_MCU(debug);
@ -169,8 +168,8 @@ FURI_NORETURN void __furi_crash_implementation() {
ptr = (uint32_t) "Check serial logs";
}
furi_hal_rtc_set_fault_data(ptr);
furi_hal_console_puts("\r\nRebooting system.\r\n");
furi_hal_console_puts("\033[0m\r\n");
furi_log_puts("\r\nRebooting system.\r\n");
furi_log_puts("\033[0m\r\n");
furi_hal_power_reset();
}
#endif
@ -187,11 +186,11 @@ FURI_NORETURN void __furi_halt_implementation() {
__furi_check_message = "System halt requested.";
}
furi_hal_console_puts("\r\n\033[0;31m[HALT]");
furi_log_puts("\r\n\033[0;31m[HALT]");
__furi_print_name(isr);
furi_hal_console_puts(__furi_check_message);
furi_hal_console_puts("\r\nSystem halted. Bye-bye!\r\n");
furi_hal_console_puts("\033[0m\r\n");
furi_log_puts(__furi_check_message);
furi_log_puts("\r\nSystem halted. Bye-bye!\r\n");
furi_log_puts("\033[0m\r\n");
// Check if debug enabled by DAP
// https://developer.arm.com/documentation/ddi0403/d/Debug-Architecture/ARMv7-M-Debug/Debug-register-support-in-the-SCS/Debug-Halting-Control-and-Status-Register--DHCSR?lang=en

View file

@ -2,17 +2,19 @@
#include "check.h"
#include "mutex.h"
#include <furi_hal.h>
#include <m-list.h>
LIST_DEF(FuriLogHandlersList, FuriLogHandler, M_POD_OPLIST)
#define FURI_LOG_LEVEL_DEFAULT FuriLogLevelInfo
typedef struct {
FuriLogLevel log_level;
FuriLogPuts puts;
FuriLogTimestamp timestamp;
FuriMutex* mutex;
FuriLogHandlersList_t tx_handlers;
} FuriLogParams;
static FuriLogParams furi_log;
static FuriLogParams furi_log = {0};
typedef struct {
const char* str;
@ -32,9 +34,77 @@ static const FuriLogLevelDescription FURI_LOG_LEVEL_DESCRIPTIONS[] = {
void furi_log_init() {
// Set default logging parameters
furi_log.log_level = FURI_LOG_LEVEL_DEFAULT;
furi_log.puts = furi_hal_console_puts;
furi_log.timestamp = furi_get_tick;
furi_log.mutex = furi_mutex_alloc(FuriMutexTypeNormal);
furi_log.mutex = furi_mutex_alloc(FuriMutexTypeRecursive);
FuriLogHandlersList_init(furi_log.tx_handlers);
}
bool furi_log_add_handler(FuriLogHandler handler) {
furi_check(handler.callback);
bool ret = true;
furi_check(furi_mutex_acquire(furi_log.mutex, FuriWaitForever) == FuriStatusOk);
FuriLogHandlersList_it_t it;
FuriLogHandlersList_it(it, furi_log.tx_handlers);
while(!FuriLogHandlersList_end_p(it)) {
if(memcmp(FuriLogHandlersList_ref(it), &handler, sizeof(FuriLogHandler)) == 0) {
ret = false;
} else {
FuriLogHandlersList_next(it);
}
}
if(ret) {
FuriLogHandlersList_push_back(furi_log.tx_handlers, handler);
}
furi_mutex_release(furi_log.mutex);
return ret;
}
bool furi_log_remove_handler(FuriLogHandler handler) {
bool ret = false;
furi_check(furi_mutex_acquire(furi_log.mutex, FuriWaitForever) == FuriStatusOk);
FuriLogHandlersList_it_t it;
FuriLogHandlersList_it(it, furi_log.tx_handlers);
while(!FuriLogHandlersList_end_p(it)) {
if(memcmp(FuriLogHandlersList_ref(it), &handler, sizeof(FuriLogHandler)) == 0) {
FuriLogHandlersList_remove(furi_log.tx_handlers, it);
ret = true;
} else {
FuriLogHandlersList_next(it);
}
}
furi_mutex_release(furi_log.mutex);
return ret;
}
void furi_log_tx(const uint8_t* data, size_t size) {
if(!FURI_IS_ISR()) {
furi_check(furi_mutex_acquire(furi_log.mutex, FuriWaitForever) == FuriStatusOk);
} else {
if(furi_mutex_get_owner(furi_log.mutex)) return;
}
FuriLogHandlersList_it_t it;
FuriLogHandlersList_it(it, furi_log.tx_handlers);
while(!FuriLogHandlersList_end_p(it)) {
FuriLogHandlersList_ref(it)->callback(data, size, FuriLogHandlersList_ref(it)->context);
FuriLogHandlersList_next(it);
}
if(!FURI_IS_ISR()) furi_mutex_release(furi_log.mutex);
}
void furi_log_puts(const char* data) {
furi_check(data);
furi_log_tx((const uint8_t*)data, strlen(data));
}
void furi_log_print_format(FuriLogLevel level, const char* tag, const char* format, ...) {
@ -72,13 +142,8 @@ void furi_log_print_format(FuriLogLevel level, const char* tag, const char* form
// Timestamp
furi_string_printf(
string,
"%lu %s[%s][%s] " _FURI_LOG_CLR_RESET,
furi_log.timestamp(),
color,
log_letter,
tag);
furi_log.puts(furi_string_get_cstr(string));
string, "%lu %s[%s][%s] " _FURI_LOG_CLR_RESET, furi_get_tick(), color, log_letter, tag);
furi_log_puts(furi_string_get_cstr(string));
furi_string_reset(string);
va_list args;
@ -86,10 +151,10 @@ void furi_log_print_format(FuriLogLevel level, const char* tag, const char* form
furi_string_vprintf(string, format, args);
va_end(args);
furi_log.puts(furi_string_get_cstr(string));
furi_log_puts(furi_string_get_cstr(string));
furi_string_free(string);
furi_log.puts("\r\n");
furi_log_puts("\r\n");
furi_mutex_release(furi_log.mutex);
}
@ -105,7 +170,7 @@ void furi_log_print_raw_format(FuriLogLevel level, const char* format, ...) {
furi_string_vprintf(string, format, args);
va_end(args);
furi_log.puts(furi_string_get_cstr(string));
furi_log_puts(furi_string_get_cstr(string));
furi_string_free(string);
furi_mutex_release(furi_log.mutex);
@ -123,16 +188,6 @@ FuriLogLevel furi_log_get_level(void) {
return furi_log.log_level;
}
void furi_log_set_puts(FuriLogPuts puts) {
furi_assert(puts);
furi_log.puts = puts;
}
void furi_log_set_timestamp(FuriLogTimestamp timestamp) {
furi_assert(timestamp);
furi_log.timestamp = timestamp;
}
bool furi_log_level_to_string(FuriLogLevel level, const char** str) {
for(size_t i = 0; i < COUNT_OF(FURI_LOG_LEVEL_DESCRIPTIONS); i++) {
if(level == FURI_LOG_LEVEL_DESCRIPTIONS[i].level) {

View file

@ -39,11 +39,44 @@ typedef enum {
#define _FURI_LOG_CLR_D _FURI_LOG_CLR(_FURI_LOG_CLR_BLUE)
#define _FURI_LOG_CLR_T _FURI_LOG_CLR(_FURI_LOG_CLR_PURPLE)
typedef void (*FuriLogPuts)(const char* data);
typedef uint32_t (*FuriLogTimestamp)(void);
typedef void (*FuriLogHandlerCallback)(const uint8_t* data, size_t size, void* context);
typedef struct {
FuriLogHandlerCallback callback;
void* context;
} FuriLogHandler;
/** Initialize logging */
void furi_log_init();
void furi_log_init(void);
/** Add log TX callback
*
* @param[in] callback The callback
*
* @return true on success, false otherwise
*/
bool furi_log_add_handler(FuriLogHandler handler);
/** Remove log TX callback
*
* @param[in] callback The callback
*
* @return true on success, false otherwise
*/
bool furi_log_remove_handler(FuriLogHandler handler);
/** Transmit data through log IO callbacks
*
* @param[in] data The data
* @param[in] size The size
*/
void furi_log_tx(const uint8_t* data, size_t size);
/** Transmit data through log IO callbacks
*
* @param[in] data The data, null-terminated C-string
*/
void furi_log_puts(const char* data);
/** Print log record
*
@ -74,19 +107,7 @@ void furi_log_set_level(FuriLogLevel level);
*
* @return The furi log level.
*/
FuriLogLevel furi_log_get_level();
/** Set log output callback
*
* @param[in] puts The puts callback
*/
void furi_log_set_puts(FuriLogPuts puts);
/** Set timestamp callback
*
* @param[in] timestamp The timestamp callback
*/
void furi_log_set_timestamp(FuriLogTimestamp timestamp);
FuriLogLevel furi_log_get_level(void);
/** Log level to string
*

View file

@ -39,7 +39,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <stm32wbxx.h>
#include <furi_hal_console.h>
#include <core/log.h>
#include <core/common_defines.h>
/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
@ -52,6 +52,10 @@ task.h is included from an application file. */
#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
#ifdef HEAP_PRINT_DEBUG
#error This feature is broken, logging transport must be replaced with RTT
#endif
#if(configSUPPORT_DYNAMIC_ALLOCATION == 0)
#error This file must not be used if configSUPPORT_DYNAMIC_ALLOCATION is 0
#endif
@ -286,13 +290,13 @@ static void print_heap_init() {
// {PHStart|heap_start|heap_end}
FURI_CRITICAL_ENTER();
furi_hal_console_puts("{PHStart|");
furi_log_puts("{PHStart|");
ultoa(heap_start, tmp_str, 16);
furi_hal_console_puts(tmp_str);
furi_hal_console_puts("|");
furi_log_puts(tmp_str);
furi_log_puts("|");
ultoa(heap_end, tmp_str, 16);
furi_hal_console_puts(tmp_str);
furi_hal_console_puts("}\r\n");
furi_log_puts(tmp_str);
furi_log_puts("}\r\n");
FURI_CRITICAL_EXIT();
}
@ -305,15 +309,15 @@ static void print_heap_malloc(void* ptr, size_t size) {
// {thread name|m|address|size}
FURI_CRITICAL_ENTER();
furi_hal_console_puts("{");
furi_hal_console_puts(name);
furi_hal_console_puts("|m|0x");
furi_log_puts("{");
furi_log_puts(name);
furi_log_puts("|m|0x");
ultoa((unsigned long)ptr, tmp_str, 16);
furi_hal_console_puts(tmp_str);
furi_hal_console_puts("|");
furi_log_puts(tmp_str);
furi_log_puts("|");
utoa(size, tmp_str, 10);
furi_hal_console_puts(tmp_str);
furi_hal_console_puts("}\r\n");
furi_log_puts(tmp_str);
furi_log_puts("}\r\n");
FURI_CRITICAL_EXIT();
}
@ -326,12 +330,12 @@ static void print_heap_free(void* ptr) {
// {thread name|f|address}
FURI_CRITICAL_ENTER();
furi_hal_console_puts("{");
furi_hal_console_puts(name);
furi_hal_console_puts("|f|0x");
furi_log_puts("{");
furi_log_puts(name);
furi_log_puts("|f|0x");
ultoa((unsigned long)ptr, tmp_str, 16);
furi_hal_console_puts(tmp_str);
furi_hal_console_puts("}\r\n");
furi_log_puts(tmp_str);
furi_log_puts("}\r\n");
FURI_CRITICAL_EXIT();
}
#endif

View file

@ -114,8 +114,10 @@ FuriThreadId furi_mutex_get_owner(FuriMutex* instance) {
hMutex = (SemaphoreHandle_t)((uint32_t)instance & ~1U);
if((FURI_IS_IRQ_MODE()) || (hMutex == NULL)) {
if((hMutex == NULL)) {
owner = 0;
} else if(FURI_IS_IRQ_MODE()) {
owner = (FuriThreadId)xSemaphoreGetMutexHolderFromISR(hMutex);
} else {
owner = (FuriThreadId)xSemaphoreGetMutexHolder(hMutex);
}

View file

@ -9,7 +9,6 @@
#include "log.h"
#include <furi_hal_rtc.h>
#include <furi_hal_console.h>
#include <FreeRTOS.h>
#include <task.h>
@ -570,7 +569,7 @@ static size_t __furi_thread_stdout_write(FuriThread* thread, const char* data, s
if(thread->output.write_callback != NULL) {
thread->output.write_callback(data, size);
} else {
furi_hal_console_tx((const uint8_t*)data, size);
furi_log_tx((const uint8_t*)data, size);
}
return size;
}

View file

@ -1,52 +1,55 @@
#include "value_index.h"
#include <math.h>
uint8_t value_index_int32(const int32_t value, const int32_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;
}
size_t value_index_int32(const int32_t value, const int32_t values[], size_t values_count) {
size_t index = 0;
uint8_t value_index_uint32(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 value_index_float(const float value, const float values[], uint8_t values_count) {
const float epsilon = 0.01f;
float last_value = values[0];
uint8_t index = 0;
for(uint8_t i = 0; i < values_count; i++) {
if((value >= last_value - epsilon) && (value <= values[i] + epsilon)) {
index = i;
break;
}
last_value = values[i];
}
return index;
}
uint8_t value_index_bool(const bool value, const bool values[], uint8_t values_count) {
uint8_t index = 0;
for(uint8_t i = 0; i < values_count; i++) {
for(size_t i = 0; i < values_count; i++) {
if(value == values[i]) {
index = i;
break;
}
}
return index;
}
size_t value_index_uint32(const uint32_t value, const uint32_t values[], size_t values_count) {
size_t index = 0;
for(size_t i = 0; i < values_count; i++) {
if(value == values[i]) {
index = i;
break;
}
}
return index;
}
size_t value_index_float(const float value, const float values[], size_t values_count) {
size_t index = 0;
for(size_t i = 0; i < values_count; i++) {
const float epsilon = fabsf(values[i] * 0.01f);
if(fabsf(values[i] - value) <= epsilon) {
index = i;
break;
}
}
return index;
}
size_t value_index_bool(const bool value, const bool values[], size_t values_count) {
size_t index = 0;
for(size_t i = 0; i < values_count; i++) {
if(value == values[i]) {
index = i;
break;
}
}
return index;
}

View file

@ -2,6 +2,7 @@
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
@ -18,7 +19,7 @@ extern "C" {
*
* @return value's index.
*/
uint8_t value_index_int32(const int32_t value, const int32_t values[], uint8_t values_count);
size_t value_index_int32(const int32_t value, const int32_t values[], size_t values_count);
/** Get the index of a uint32_t array element which is closest to the given value.
*
@ -31,7 +32,7 @@ uint8_t value_index_int32(const int32_t value, const int32_t values[], uint8_t v
*
* @return value's index.
*/
uint8_t value_index_uint32(const uint32_t value, const uint32_t values[], uint8_t values_count);
size_t value_index_uint32(const uint32_t value, const uint32_t values[], size_t values_count);
/** Get the index of a float array element which is closest to the given value.
*
@ -44,7 +45,7 @@ uint8_t value_index_uint32(const uint32_t value, const uint32_t values[], uint8_
*
* @return value's index.
*/
uint8_t value_index_float(const float value, const float values[], uint8_t values_count);
size_t value_index_float(const float value, const float values[], size_t values_count);
/** Get the index of a bool array element which is equal to the given value.
*
@ -57,7 +58,7 @@ uint8_t value_index_float(const float value, const float values[], uint8_t value
*
* @return value's index.
*/
uint8_t value_index_bool(const bool value, const bool values[], uint8_t values_count);
size_t value_index_bool(const bool value, const bool values[], size_t values_count);
#ifdef __cplusplus
}

View file

@ -1,5 +1,5 @@
entry,status,name,type,params
Version,+,50.1,,
Version,+,51.0,,
Header,+,applications/services/bt/bt_service/bt.h,,
Header,+,applications/services/cli/cli.h,,
Header,+,applications/services/cli/cli_vcp.h,,
@ -160,7 +160,6 @@ Header,+,targets/f18/furi_hal/furi_hal_spi_config.h,,
Header,+,targets/f18/furi_hal/furi_hal_target_hw.h,,
Header,+,targets/f7/furi_hal/furi_hal_bus.h,,
Header,+,targets/f7/furi_hal/furi_hal_clock.h,,
Header,+,targets/f7/furi_hal/furi_hal_console.h,,
Header,+,targets/f7/furi_hal/furi_hal_dma.h,,
Header,+,targets/f7/furi_hal/furi_hal_flash.h,,
Header,+,targets/f7/furi_hal/furi_hal_gpio.h,,
@ -170,8 +169,11 @@ Header,+,targets/f7/furi_hal/furi_hal_idle_timer.h,,
Header,+,targets/f7/furi_hal/furi_hal_interrupt.h,,
Header,+,targets/f7/furi_hal/furi_hal_os.h,,
Header,+,targets/f7/furi_hal/furi_hal_pwm.h,,
Header,+,targets/f7/furi_hal/furi_hal_rtc.h,,
Header,+,targets/f7/furi_hal/furi_hal_serial.h,,
Header,+,targets/f7/furi_hal/furi_hal_serial_control.h,,
Header,+,targets/f7/furi_hal/furi_hal_serial_types.h,,
Header,+,targets/f7/furi_hal/furi_hal_spi_types.h,,
Header,+,targets/f7/furi_hal/furi_hal_uart.h,,
Header,+,targets/f7/furi_hal/furi_hal_usb_cdc.h,,
Header,+,targets/f7/platform_specific/intrinsic_export.h,,
Header,+,targets/f7/platform_specific/math_wrapper.h,,
@ -190,7 +192,6 @@ Header,+,targets/furi_hal_include/furi_hal_mpu.h,,
Header,+,targets/furi_hal_include/furi_hal_power.h,,
Header,+,targets/furi_hal_include/furi_hal_random.h,,
Header,+,targets/furi_hal_include/furi_hal_region.h,,
Header,+,targets/furi_hal_include/furi_hal_rtc.h,,
Header,+,targets/furi_hal_include/furi_hal_sd.h,,
Header,+,targets/furi_hal_include/furi_hal_speaker.h,,
Header,+,targets/furi_hal_include/furi_hal_spi.h,,
@ -1057,14 +1058,6 @@ Function,-,furi_hal_clock_switch_hse2hsi,void,
Function,-,furi_hal_clock_switch_hse2pll,_Bool,
Function,-,furi_hal_clock_switch_hsi2hse,void,
Function,-,furi_hal_clock_switch_pll2hse,_Bool,
Function,+,furi_hal_console_disable,void,
Function,+,furi_hal_console_enable,void,
Function,+,furi_hal_console_init,void,
Function,+,furi_hal_console_printf,void,"const char[], ..."
Function,+,furi_hal_console_puts,void,const char*
Function,+,furi_hal_console_set_tx_callback,void,"FuriHalConsoleTxCallback, void*"
Function,+,furi_hal_console_tx,void,"const uint8_t*, size_t"
Function,+,furi_hal_console_tx_with_new_line,void,"const uint8_t*, size_t"
Function,+,furi_hal_cortex_comp_enable,void,"FuriHalCortexComp, FuriHalCortexCompFunction, uint32_t, uint32_t, FuriHalCortexCompSize"
Function,+,furi_hal_cortex_comp_reset,void,FuriHalCortexComp
Function,+,furi_hal_cortex_delay_us,void,uint32_t
@ -1239,6 +1232,8 @@ Function,+,furi_hal_rtc_get_heap_track_mode,FuriHalRtcHeapTrackMode,
Function,+,furi_hal_rtc_get_locale_dateformat,FuriHalRtcLocaleDateFormat,
Function,+,furi_hal_rtc_get_locale_timeformat,FuriHalRtcLocaleTimeFormat,
Function,+,furi_hal_rtc_get_locale_units,FuriHalRtcLocaleUnits,
Function,+,furi_hal_rtc_get_log_baud_rate,FuriHalRtcLogBaudRate,
Function,+,furi_hal_rtc_get_log_device,FuriHalRtcLogDevice,
Function,+,furi_hal_rtc_get_log_level,uint8_t,
Function,+,furi_hal_rtc_get_pin_fails,uint32_t,
Function,+,furi_hal_rtc_get_register,uint32_t,FuriHalRtcRegister
@ -1257,6 +1252,8 @@ Function,+,furi_hal_rtc_set_heap_track_mode,void,FuriHalRtcHeapTrackMode
Function,+,furi_hal_rtc_set_locale_dateformat,void,FuriHalRtcLocaleDateFormat
Function,+,furi_hal_rtc_set_locale_timeformat,void,FuriHalRtcLocaleTimeFormat
Function,+,furi_hal_rtc_set_locale_units,void,FuriHalRtcLocaleUnits
Function,+,furi_hal_rtc_set_log_baud_rate,void,FuriHalRtcLogBaudRate
Function,+,furi_hal_rtc_set_log_device,void,FuriHalRtcLogDevice
Function,+,furi_hal_rtc_set_log_level,void,uint8_t
Function,+,furi_hal_rtc_set_pin_fails,void,uint32_t
Function,+,furi_hal_rtc_set_register,void,"FuriHalRtcRegister, uint32_t"
@ -1271,6 +1268,26 @@ Function,+,furi_hal_sd_max_mount_retry_count,uint8_t,
Function,+,furi_hal_sd_presence_init,void,
Function,+,furi_hal_sd_read_blocks,FuriStatus,"uint32_t*, uint32_t, uint32_t"
Function,+,furi_hal_sd_write_blocks,FuriStatus,"const uint32_t*, uint32_t, uint32_t"
Function,+,furi_hal_serial_control_acquire,FuriHalSerialHandle*,FuriHalSerialId
Function,+,furi_hal_serial_control_deinit,void,
Function,+,furi_hal_serial_control_init,void,
Function,+,furi_hal_serial_control_release,void,FuriHalSerialHandle*
Function,+,furi_hal_serial_control_resume,void,
Function,+,furi_hal_serial_control_set_logging_config,void,"FuriHalSerialId, uint32_t"
Function,+,furi_hal_serial_control_suspend,void,
Function,+,furi_hal_serial_deinit,void,FuriHalSerialHandle*
Function,+,furi_hal_serial_dma_rx,size_t,"FuriHalSerialHandle*, uint8_t*, size_t"
Function,+,furi_hal_serial_dma_rx_start,void,"FuriHalSerialHandle*, FuriHalSerialDmaRxCallback, void*, _Bool"
Function,+,furi_hal_serial_dma_rx_stop,void,FuriHalSerialHandle*
Function,+,furi_hal_serial_init,void,"FuriHalSerialHandle*, uint32_t"
Function,+,furi_hal_serial_resume,void,FuriHalSerialHandle*
Function,+,furi_hal_serial_async_rx,uint8_t,FuriHalSerialHandle*
Function,+,furi_hal_serial_async_rx_start,void,"FuriHalSerialHandle*, FuriHalSerialAsyncRxCallback, void*, _Bool"
Function,+,furi_hal_serial_async_rx_stop,void,FuriHalSerialHandle*
Function,+,furi_hal_serial_set_br,void,"FuriHalSerialHandle*, uint32_t"
Function,+,furi_hal_serial_suspend,void,FuriHalSerialHandle*
Function,+,furi_hal_serial_tx,void,"FuriHalSerialHandle*, const uint8_t*, size_t"
Function,+,furi_hal_serial_tx_wait_complete,void,FuriHalSerialHandle*
Function,+,furi_hal_speaker_acquire,_Bool,uint32_t
Function,-,furi_hal_speaker_deinit,void,
Function,-,furi_hal_speaker_init,void,
@ -1294,13 +1311,6 @@ Function,-,furi_hal_spi_config_init_early,void,
Function,-,furi_hal_spi_dma_init,void,
Function,+,furi_hal_spi_release,void,FuriHalSpiBusHandle*
Function,+,furi_hal_switch,void,void*
Function,+,furi_hal_uart_deinit,void,FuriHalUartId
Function,+,furi_hal_uart_init,void,"FuriHalUartId, uint32_t"
Function,+,furi_hal_uart_resume,void,FuriHalUartId
Function,+,furi_hal_uart_set_br,void,"FuriHalUartId, uint32_t"
Function,+,furi_hal_uart_set_irq_cb,void,"FuriHalUartId, void (*)(UartIrqEvent, uint8_t, void*), void*"
Function,+,furi_hal_uart_suspend,void,FuriHalUartId
Function,+,furi_hal_uart_tx,void,"FuriHalUartId, uint8_t*, size_t"
Function,+,furi_hal_usb_disable,void,
Function,+,furi_hal_usb_enable,void,
Function,+,furi_hal_usb_get_config,FuriHalUsbInterface*,
@ -1346,15 +1356,17 @@ Function,+,furi_kernel_is_running,_Bool,
Function,+,furi_kernel_lock,int32_t,
Function,+,furi_kernel_restore_lock,int32_t,int32_t
Function,+,furi_kernel_unlock,int32_t,
Function,+,furi_log_add_handler,_Bool,FuriLogHandler
Function,+,furi_log_get_level,FuriLogLevel,
Function,-,furi_log_init,void,
Function,+,furi_log_level_from_string,_Bool,"const char*, FuriLogLevel*"
Function,+,furi_log_level_to_string,_Bool,"FuriLogLevel, const char**"
Function,+,furi_log_print_format,void,"FuriLogLevel, const char*, const char*, ..."
Function,+,furi_log_print_raw_format,void,"FuriLogLevel, const char*, ..."
Function,+,furi_log_puts,void,const char*
Function,+,furi_log_remove_handler,_Bool,FuriLogHandler
Function,+,furi_log_set_level,void,FuriLogLevel
Function,-,furi_log_set_puts,void,FuriLogPuts
Function,-,furi_log_set_timestamp,void,FuriLogTimestamp
Function,+,furi_log_tx,void,"const uint8_t*, size_t"
Function,+,furi_message_queue_alloc,FuriMessageQueue*,"uint32_t, uint32_t"
Function,+,furi_message_queue_free,void,FuriMessageQueue*
Function,+,furi_message_queue_get,FuriStatus,"FuriMessageQueue*, void*, uint32_t"
@ -2418,10 +2430,10 @@ Function,-,utoa,char*,"unsigned, char*, int"
Function,+,validator_is_file_alloc_init,ValidatorIsFile*,"const char*, const char*, const char*"
Function,+,validator_is_file_callback,_Bool,"const char*, FuriString*, void*"
Function,+,validator_is_file_free,void,ValidatorIsFile*
Function,+,value_index_bool,uint8_t,"const _Bool, const _Bool[], uint8_t"
Function,+,value_index_float,uint8_t,"const float, const float[], uint8_t"
Function,+,value_index_int32,uint8_t,"const int32_t, const int32_t[], uint8_t"
Function,+,value_index_uint32,uint8_t,"const uint32_t, const uint32_t[], uint8_t"
Function,+,value_index_bool,size_t,"const _Bool, const _Bool[], size_t"
Function,+,value_index_float,size_t,"const float, const float[], size_t"
Function,+,value_index_int32,size_t,"const int32_t, const int32_t[], size_t"
Function,+,value_index_uint32,size_t,"const uint32_t, const uint32_t[], size_t"
Function,+,variable_item_get_context,void*,VariableItem*
Function,+,variable_item_get_current_value_index,uint8_t,VariableItem*
Function,+,variable_item_list_add,VariableItem*,"VariableItemList*, const char*, uint8_t, VariableItemChangeCallback, void*"

1 entry status name type params
2 Version + 50.1 51.0
3 Header + applications/services/bt/bt_service/bt.h
4 Header + applications/services/cli/cli.h
5 Header + applications/services/cli/cli_vcp.h
160 Header + targets/f18/furi_hal/furi_hal_target_hw.h
161 Header + targets/f7/furi_hal/furi_hal_bus.h
162 Header + targets/f7/furi_hal/furi_hal_clock.h
Header + targets/f7/furi_hal/furi_hal_console.h
163 Header + targets/f7/furi_hal/furi_hal_dma.h
164 Header + targets/f7/furi_hal/furi_hal_flash.h
165 Header + targets/f7/furi_hal/furi_hal_gpio.h
169 Header + targets/f7/furi_hal/furi_hal_interrupt.h
170 Header + targets/f7/furi_hal/furi_hal_os.h
171 Header + targets/f7/furi_hal/furi_hal_pwm.h
172 Header + targets/f7/furi_hal/furi_hal_rtc.h
173 Header + targets/f7/furi_hal/furi_hal_serial.h
174 Header + targets/f7/furi_hal/furi_hal_serial_control.h
175 Header + targets/f7/furi_hal/furi_hal_serial_types.h
176 Header + targets/f7/furi_hal/furi_hal_spi_types.h
Header + targets/f7/furi_hal/furi_hal_uart.h
177 Header + targets/f7/furi_hal/furi_hal_usb_cdc.h
178 Header + targets/f7/platform_specific/intrinsic_export.h
179 Header + targets/f7/platform_specific/math_wrapper.h
192 Header + targets/furi_hal_include/furi_hal_power.h
193 Header + targets/furi_hal_include/furi_hal_random.h
194 Header + targets/furi_hal_include/furi_hal_region.h
Header + targets/furi_hal_include/furi_hal_rtc.h
195 Header + targets/furi_hal_include/furi_hal_sd.h
196 Header + targets/furi_hal_include/furi_hal_speaker.h
197 Header + targets/furi_hal_include/furi_hal_spi.h
1058 Function - furi_hal_clock_switch_hse2pll _Bool
1059 Function - furi_hal_clock_switch_hsi2hse void
1060 Function - furi_hal_clock_switch_pll2hse _Bool
Function + furi_hal_console_disable void
Function + furi_hal_console_enable void
Function + furi_hal_console_init void
Function + furi_hal_console_printf void const char[], ...
Function + furi_hal_console_puts void const char*
Function + furi_hal_console_set_tx_callback void FuriHalConsoleTxCallback, void*
Function + furi_hal_console_tx void const uint8_t*, size_t
Function + furi_hal_console_tx_with_new_line void const uint8_t*, size_t
1061 Function + furi_hal_cortex_comp_enable void FuriHalCortexComp, FuriHalCortexCompFunction, uint32_t, uint32_t, FuriHalCortexCompSize
1062 Function + furi_hal_cortex_comp_reset void FuriHalCortexComp
1063 Function + furi_hal_cortex_delay_us void uint32_t
1232 Function + furi_hal_rtc_get_locale_dateformat FuriHalRtcLocaleDateFormat
1233 Function + furi_hal_rtc_get_locale_timeformat FuriHalRtcLocaleTimeFormat
1234 Function + furi_hal_rtc_get_locale_units FuriHalRtcLocaleUnits
1235 Function + furi_hal_rtc_get_log_baud_rate FuriHalRtcLogBaudRate
1236 Function + furi_hal_rtc_get_log_device FuriHalRtcLogDevice
1237 Function + furi_hal_rtc_get_log_level uint8_t
1238 Function + furi_hal_rtc_get_pin_fails uint32_t
1239 Function + furi_hal_rtc_get_register uint32_t FuriHalRtcRegister
1252 Function + furi_hal_rtc_set_locale_dateformat void FuriHalRtcLocaleDateFormat
1253 Function + furi_hal_rtc_set_locale_timeformat void FuriHalRtcLocaleTimeFormat
1254 Function + furi_hal_rtc_set_locale_units void FuriHalRtcLocaleUnits
1255 Function + furi_hal_rtc_set_log_baud_rate void FuriHalRtcLogBaudRate
1256 Function + furi_hal_rtc_set_log_device void FuriHalRtcLogDevice
1257 Function + furi_hal_rtc_set_log_level void uint8_t
1258 Function + furi_hal_rtc_set_pin_fails void uint32_t
1259 Function + furi_hal_rtc_set_register void FuriHalRtcRegister, uint32_t
1268 Function + furi_hal_sd_presence_init void
1269 Function + furi_hal_sd_read_blocks FuriStatus uint32_t*, uint32_t, uint32_t
1270 Function + furi_hal_sd_write_blocks FuriStatus const uint32_t*, uint32_t, uint32_t
1271 Function + furi_hal_serial_control_acquire FuriHalSerialHandle* FuriHalSerialId
1272 Function + furi_hal_serial_control_deinit void
1273 Function + furi_hal_serial_control_init void
1274 Function + furi_hal_serial_control_release void FuriHalSerialHandle*
1275 Function + furi_hal_serial_control_resume void
1276 Function + furi_hal_serial_control_set_logging_config void FuriHalSerialId, uint32_t
1277 Function + furi_hal_serial_control_suspend void
1278 Function + furi_hal_serial_deinit void FuriHalSerialHandle*
1279 Function + furi_hal_serial_dma_rx size_t FuriHalSerialHandle*, uint8_t*, size_t
1280 Function + furi_hal_serial_dma_rx_start void FuriHalSerialHandle*, FuriHalSerialDmaRxCallback, void*, _Bool
1281 Function + furi_hal_serial_dma_rx_stop void FuriHalSerialHandle*
1282 Function + furi_hal_serial_init void FuriHalSerialHandle*, uint32_t
1283 Function + furi_hal_serial_resume void FuriHalSerialHandle*
1284 Function + furi_hal_serial_async_rx uint8_t FuriHalSerialHandle*
1285 Function + furi_hal_serial_async_rx_start void FuriHalSerialHandle*, FuriHalSerialAsyncRxCallback, void*, _Bool
1286 Function + furi_hal_serial_async_rx_stop void FuriHalSerialHandle*
1287 Function + furi_hal_serial_set_br void FuriHalSerialHandle*, uint32_t
1288 Function + furi_hal_serial_suspend void FuriHalSerialHandle*
1289 Function + furi_hal_serial_tx void FuriHalSerialHandle*, const uint8_t*, size_t
1290 Function + furi_hal_serial_tx_wait_complete void FuriHalSerialHandle*
1291 Function + furi_hal_speaker_acquire _Bool uint32_t
1292 Function - furi_hal_speaker_deinit void
1293 Function - furi_hal_speaker_init void
1311 Function - furi_hal_spi_dma_init void
1312 Function + furi_hal_spi_release void FuriHalSpiBusHandle*
1313 Function + furi_hal_switch void void*
Function + furi_hal_uart_deinit void FuriHalUartId
Function + furi_hal_uart_init void FuriHalUartId, uint32_t
Function + furi_hal_uart_resume void FuriHalUartId
Function + furi_hal_uart_set_br void FuriHalUartId, uint32_t
Function + furi_hal_uart_set_irq_cb void FuriHalUartId, void (*)(UartIrqEvent, uint8_t, void*), void*
Function + furi_hal_uart_suspend void FuriHalUartId
Function + furi_hal_uart_tx void FuriHalUartId, uint8_t*, size_t
1314 Function + furi_hal_usb_disable void
1315 Function + furi_hal_usb_enable void
1316 Function + furi_hal_usb_get_config FuriHalUsbInterface*
1356 Function + furi_kernel_lock int32_t
1357 Function + furi_kernel_restore_lock int32_t int32_t
1358 Function + furi_kernel_unlock int32_t
1359 Function + furi_log_add_handler _Bool FuriLogHandler
1360 Function + furi_log_get_level FuriLogLevel
1361 Function - furi_log_init void
1362 Function + furi_log_level_from_string _Bool const char*, FuriLogLevel*
1363 Function + furi_log_level_to_string _Bool FuriLogLevel, const char**
1364 Function + furi_log_print_format void FuriLogLevel, const char*, const char*, ...
1365 Function + furi_log_print_raw_format void FuriLogLevel, const char*, ...
1366 Function + furi_log_puts void const char*
1367 Function + furi_log_remove_handler _Bool FuriLogHandler
1368 Function + furi_log_set_level void FuriLogLevel
1369 Function - + furi_log_set_puts furi_log_tx void FuriLogPuts const uint8_t*, size_t
Function - furi_log_set_timestamp void FuriLogTimestamp
1370 Function + furi_message_queue_alloc FuriMessageQueue* uint32_t, uint32_t
1371 Function + furi_message_queue_free void FuriMessageQueue*
1372 Function + furi_message_queue_get FuriStatus FuriMessageQueue*, void*, uint32_t
2430 Function + validator_is_file_alloc_init ValidatorIsFile* const char*, const char*, const char*
2431 Function + validator_is_file_callback _Bool const char*, FuriString*, void*
2432 Function + validator_is_file_free void ValidatorIsFile*
2433 Function + value_index_bool uint8_t size_t const _Bool, const _Bool[], uint8_t const _Bool, const _Bool[], size_t
2434 Function + value_index_float uint8_t size_t const float, const float[], uint8_t const float, const float[], size_t
2435 Function + value_index_int32 uint8_t size_t const int32_t, const int32_t[], uint8_t const int32_t, const int32_t[], size_t
2436 Function + value_index_uint32 uint8_t size_t const uint32_t, const uint32_t[], uint8_t const uint32_t, const uint32_t[], size_t
2437 Function + variable_item_get_context void* VariableItem*
2438 Function + variable_item_get_current_value_index uint8_t VariableItem*
2439 Function + variable_item_list_add VariableItem* VariableItemList*, const char*, uint8_t, VariableItemChangeCallback, void*

View file

@ -33,7 +33,7 @@ void furi_hal_init() {
furi_hal_mpu_init();
furi_hal_clock_init();
furi_hal_random_init();
furi_hal_console_init();
furi_hal_serial_control_init();
furi_hal_rtc_init();
furi_hal_interrupt_init();
furi_hal_flash_init();

View file

@ -1,5 +1,5 @@
entry,status,name,type,params
Version,+,50.1,,
Version,+,51.0,,
Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,,
Header,+,applications/services/bt/bt_service/bt.h,,
Header,+,applications/services/cli/cli.h,,
@ -221,7 +221,6 @@ Header,+,lib/toolbox/value_index.h,,
Header,+,lib/toolbox/version.h,,
Header,+,targets/f7/furi_hal/furi_hal_bus.h,,
Header,+,targets/f7/furi_hal/furi_hal_clock.h,,
Header,+,targets/f7/furi_hal/furi_hal_console.h,,
Header,+,targets/f7/furi_hal/furi_hal_dma.h,,
Header,+,targets/f7/furi_hal/furi_hal_flash.h,,
Header,+,targets/f7/furi_hal/furi_hal_gpio.h,,
@ -234,11 +233,14 @@ Header,+,targets/f7/furi_hal/furi_hal_os.h,,
Header,+,targets/f7/furi_hal/furi_hal_pwm.h,,
Header,+,targets/f7/furi_hal/furi_hal_resources.h,,
Header,+,targets/f7/furi_hal/furi_hal_rfid.h,,
Header,+,targets/f7/furi_hal/furi_hal_rtc.h,,
Header,+,targets/f7/furi_hal/furi_hal_serial.h,,
Header,+,targets/f7/furi_hal/furi_hal_serial_control.h,,
Header,+,targets/f7/furi_hal/furi_hal_serial_types.h,,
Header,+,targets/f7/furi_hal/furi_hal_spi_config.h,,
Header,+,targets/f7/furi_hal/furi_hal_spi_types.h,,
Header,+,targets/f7/furi_hal/furi_hal_subghz.h,,
Header,+,targets/f7/furi_hal/furi_hal_target_hw.h,,
Header,+,targets/f7/furi_hal/furi_hal_uart.h,,
Header,+,targets/f7/furi_hal/furi_hal_usb_cdc.h,,
Header,+,targets/f7/platform_specific/intrinsic_export.h,,
Header,+,targets/f7/platform_specific/math_wrapper.h,,
@ -259,7 +261,6 @@ Header,+,targets/furi_hal_include/furi_hal_nfc.h,,
Header,+,targets/furi_hal_include/furi_hal_power.h,,
Header,+,targets/furi_hal_include/furi_hal_random.h,,
Header,+,targets/furi_hal_include/furi_hal_region.h,,
Header,+,targets/furi_hal_include/furi_hal_rtc.h,,
Header,+,targets/furi_hal_include/furi_hal_sd.h,,
Header,+,targets/furi_hal_include/furi_hal_speaker.h,,
Header,+,targets/furi_hal_include/furi_hal_spi.h,,
@ -1146,14 +1147,6 @@ Function,-,furi_hal_clock_switch_hse2hsi,void,
Function,-,furi_hal_clock_switch_hse2pll,_Bool,
Function,-,furi_hal_clock_switch_hsi2hse,void,
Function,-,furi_hal_clock_switch_pll2hse,_Bool,
Function,+,furi_hal_console_disable,void,
Function,+,furi_hal_console_enable,void,
Function,+,furi_hal_console_init,void,
Function,+,furi_hal_console_printf,void,"const char[], ..."
Function,+,furi_hal_console_puts,void,const char*
Function,+,furi_hal_console_set_tx_callback,void,"FuriHalConsoleTxCallback, void*"
Function,+,furi_hal_console_tx,void,"const uint8_t*, size_t"
Function,+,furi_hal_console_tx_with_new_line,void,"const uint8_t*, size_t"
Function,+,furi_hal_cortex_comp_enable,void,"FuriHalCortexComp, FuriHalCortexCompFunction, uint32_t, uint32_t, FuriHalCortexCompSize"
Function,+,furi_hal_cortex_comp_reset,void,FuriHalCortexComp
Function,+,furi_hal_cortex_delay_us,void,uint32_t
@ -1405,6 +1398,8 @@ Function,+,furi_hal_rtc_get_heap_track_mode,FuriHalRtcHeapTrackMode,
Function,+,furi_hal_rtc_get_locale_dateformat,FuriHalRtcLocaleDateFormat,
Function,+,furi_hal_rtc_get_locale_timeformat,FuriHalRtcLocaleTimeFormat,
Function,+,furi_hal_rtc_get_locale_units,FuriHalRtcLocaleUnits,
Function,+,furi_hal_rtc_get_log_baud_rate,FuriHalRtcLogBaudRate,
Function,+,furi_hal_rtc_get_log_device,FuriHalRtcLogDevice,
Function,+,furi_hal_rtc_get_log_level,uint8_t,
Function,+,furi_hal_rtc_get_pin_fails,uint32_t,
Function,+,furi_hal_rtc_get_register,uint32_t,FuriHalRtcRegister
@ -1423,6 +1418,8 @@ Function,+,furi_hal_rtc_set_heap_track_mode,void,FuriHalRtcHeapTrackMode
Function,+,furi_hal_rtc_set_locale_dateformat,void,FuriHalRtcLocaleDateFormat
Function,+,furi_hal_rtc_set_locale_timeformat,void,FuriHalRtcLocaleTimeFormat
Function,+,furi_hal_rtc_set_locale_units,void,FuriHalRtcLocaleUnits
Function,+,furi_hal_rtc_set_log_baud_rate,void,FuriHalRtcLogBaudRate
Function,+,furi_hal_rtc_set_log_device,void,FuriHalRtcLogDevice
Function,+,furi_hal_rtc_set_log_level,void,uint8_t
Function,+,furi_hal_rtc_set_pin_fails,void,uint32_t
Function,+,furi_hal_rtc_set_register,void,"FuriHalRtcRegister, uint32_t"
@ -1437,6 +1434,26 @@ Function,+,furi_hal_sd_max_mount_retry_count,uint8_t,
Function,+,furi_hal_sd_presence_init,void,
Function,+,furi_hal_sd_read_blocks,FuriStatus,"uint32_t*, uint32_t, uint32_t"
Function,+,furi_hal_sd_write_blocks,FuriStatus,"const uint32_t*, uint32_t, uint32_t"
Function,+,furi_hal_serial_control_acquire,FuriHalSerialHandle*,FuriHalSerialId
Function,+,furi_hal_serial_control_deinit,void,
Function,+,furi_hal_serial_control_init,void,
Function,+,furi_hal_serial_control_release,void,FuriHalSerialHandle*
Function,+,furi_hal_serial_control_resume,void,
Function,+,furi_hal_serial_control_set_logging_config,void,"FuriHalSerialId, uint32_t"
Function,+,furi_hal_serial_control_suspend,void,
Function,+,furi_hal_serial_deinit,void,FuriHalSerialHandle*
Function,+,furi_hal_serial_dma_rx,size_t,"FuriHalSerialHandle*, uint8_t*, size_t"
Function,+,furi_hal_serial_dma_rx_start,void,"FuriHalSerialHandle*, FuriHalSerialDmaRxCallback, void*, _Bool"
Function,+,furi_hal_serial_dma_rx_stop,void,FuriHalSerialHandle*
Function,+,furi_hal_serial_init,void,"FuriHalSerialHandle*, uint32_t"
Function,+,furi_hal_serial_resume,void,FuriHalSerialHandle*
Function,+,furi_hal_serial_async_rx,uint8_t,FuriHalSerialHandle*
Function,+,furi_hal_serial_async_rx_start,void,"FuriHalSerialHandle*, FuriHalSerialAsyncRxCallback, void*, _Bool"
Function,+,furi_hal_serial_async_rx_stop,void,FuriHalSerialHandle*
Function,+,furi_hal_serial_set_br,void,"FuriHalSerialHandle*, uint32_t"
Function,+,furi_hal_serial_suspend,void,FuriHalSerialHandle*
Function,+,furi_hal_serial_tx,void,"FuriHalSerialHandle*, const uint8_t*, size_t"
Function,+,furi_hal_serial_tx_wait_complete,void,FuriHalSerialHandle*
Function,+,furi_hal_speaker_acquire,_Bool,uint32_t
Function,-,furi_hal_speaker_deinit,void,
Function,-,furi_hal_speaker_init,void,
@ -1490,13 +1507,6 @@ Function,+,furi_hal_subghz_stop_async_tx,void,
Function,+,furi_hal_subghz_tx,_Bool,
Function,+,furi_hal_subghz_write_packet,void,"const uint8_t*, uint8_t"
Function,+,furi_hal_switch,void,void*
Function,+,furi_hal_uart_deinit,void,FuriHalUartId
Function,+,furi_hal_uart_init,void,"FuriHalUartId, uint32_t"
Function,+,furi_hal_uart_resume,void,FuriHalUartId
Function,+,furi_hal_uart_set_br,void,"FuriHalUartId, uint32_t"
Function,+,furi_hal_uart_set_irq_cb,void,"FuriHalUartId, void (*)(UartIrqEvent, uint8_t, void*), void*"
Function,+,furi_hal_uart_suspend,void,FuriHalUartId
Function,+,furi_hal_uart_tx,void,"FuriHalUartId, uint8_t*, size_t"
Function,+,furi_hal_usb_disable,void,
Function,+,furi_hal_usb_enable,void,
Function,+,furi_hal_usb_get_config,FuriHalUsbInterface*,
@ -1542,15 +1552,17 @@ Function,+,furi_kernel_is_running,_Bool,
Function,+,furi_kernel_lock,int32_t,
Function,+,furi_kernel_restore_lock,int32_t,int32_t
Function,+,furi_kernel_unlock,int32_t,
Function,+,furi_log_add_handler,_Bool,FuriLogHandler
Function,+,furi_log_get_level,FuriLogLevel,
Function,-,furi_log_init,void,
Function,+,furi_log_level_from_string,_Bool,"const char*, FuriLogLevel*"
Function,+,furi_log_level_to_string,_Bool,"FuriLogLevel, const char**"
Function,+,furi_log_print_format,void,"FuriLogLevel, const char*, const char*, ..."
Function,+,furi_log_print_raw_format,void,"FuriLogLevel, const char*, ..."
Function,+,furi_log_puts,void,const char*
Function,+,furi_log_remove_handler,_Bool,FuriLogHandler
Function,+,furi_log_set_level,void,FuriLogLevel
Function,-,furi_log_set_puts,void,FuriLogPuts
Function,-,furi_log_set_timestamp,void,FuriLogTimestamp
Function,+,furi_log_tx,void,"const uint8_t*, size_t"
Function,+,furi_message_queue_alloc,FuriMessageQueue*,"uint32_t, uint32_t"
Function,+,furi_message_queue_free,void,FuriMessageQueue*
Function,+,furi_message_queue_get,FuriStatus,"FuriMessageQueue*, void*, uint32_t"
@ -3202,10 +3214,10 @@ Function,-,utoa,char*,"unsigned, char*, int"
Function,+,validator_is_file_alloc_init,ValidatorIsFile*,"const char*, const char*, const char*"
Function,+,validator_is_file_callback,_Bool,"const char*, FuriString*, void*"
Function,+,validator_is_file_free,void,ValidatorIsFile*
Function,+,value_index_bool,uint8_t,"const _Bool, const _Bool[], uint8_t"
Function,+,value_index_float,uint8_t,"const float, const float[], uint8_t"
Function,+,value_index_int32,uint8_t,"const int32_t, const int32_t[], uint8_t"
Function,+,value_index_uint32,uint8_t,"const uint32_t, const uint32_t[], uint8_t"
Function,+,value_index_bool,size_t,"const _Bool, const _Bool[], size_t"
Function,+,value_index_float,size_t,"const float, const float[], size_t"
Function,+,value_index_int32,size_t,"const int32_t, const int32_t[], size_t"
Function,+,value_index_uint32,size_t,"const uint32_t, const uint32_t[], size_t"
Function,+,variable_item_get_context,void*,VariableItem*
Function,+,variable_item_get_current_value_index,uint8_t,VariableItem*
Function,+,variable_item_list_add,VariableItem*,"VariableItemList*, const char*, uint8_t, VariableItemChangeCallback, void*"

1 entry status name type params
2 Version + 50.1 51.0
3 Header + applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h
4 Header + applications/services/bt/bt_service/bt.h
5 Header + applications/services/cli/cli.h
221 Header + lib/toolbox/version.h
222 Header + targets/f7/furi_hal/furi_hal_bus.h
223 Header + targets/f7/furi_hal/furi_hal_clock.h
Header + targets/f7/furi_hal/furi_hal_console.h
224 Header + targets/f7/furi_hal/furi_hal_dma.h
225 Header + targets/f7/furi_hal/furi_hal_flash.h
226 Header + targets/f7/furi_hal/furi_hal_gpio.h
233 Header + targets/f7/furi_hal/furi_hal_pwm.h
234 Header + targets/f7/furi_hal/furi_hal_resources.h
235 Header + targets/f7/furi_hal/furi_hal_rfid.h
236 Header + targets/f7/furi_hal/furi_hal_rtc.h
237 Header + targets/f7/furi_hal/furi_hal_serial.h
238 Header + targets/f7/furi_hal/furi_hal_serial_control.h
239 Header + targets/f7/furi_hal/furi_hal_serial_types.h
240 Header + targets/f7/furi_hal/furi_hal_spi_config.h
241 Header + targets/f7/furi_hal/furi_hal_spi_types.h
242 Header + targets/f7/furi_hal/furi_hal_subghz.h
243 Header + targets/f7/furi_hal/furi_hal_target_hw.h
Header + targets/f7/furi_hal/furi_hal_uart.h
244 Header + targets/f7/furi_hal/furi_hal_usb_cdc.h
245 Header + targets/f7/platform_specific/intrinsic_export.h
246 Header + targets/f7/platform_specific/math_wrapper.h
261 Header + targets/furi_hal_include/furi_hal_power.h
262 Header + targets/furi_hal_include/furi_hal_random.h
263 Header + targets/furi_hal_include/furi_hal_region.h
Header + targets/furi_hal_include/furi_hal_rtc.h
264 Header + targets/furi_hal_include/furi_hal_sd.h
265 Header + targets/furi_hal_include/furi_hal_speaker.h
266 Header + targets/furi_hal_include/furi_hal_spi.h
1147 Function - furi_hal_clock_switch_hse2pll _Bool
1148 Function - furi_hal_clock_switch_hsi2hse void
1149 Function - furi_hal_clock_switch_pll2hse _Bool
Function + furi_hal_console_disable void
Function + furi_hal_console_enable void
Function + furi_hal_console_init void
Function + furi_hal_console_printf void const char[], ...
Function + furi_hal_console_puts void const char*
Function + furi_hal_console_set_tx_callback void FuriHalConsoleTxCallback, void*
Function + furi_hal_console_tx void const uint8_t*, size_t
Function + furi_hal_console_tx_with_new_line void const uint8_t*, size_t
1150 Function + furi_hal_cortex_comp_enable void FuriHalCortexComp, FuriHalCortexCompFunction, uint32_t, uint32_t, FuriHalCortexCompSize
1151 Function + furi_hal_cortex_comp_reset void FuriHalCortexComp
1152 Function + furi_hal_cortex_delay_us void uint32_t
1398 Function + furi_hal_rtc_get_locale_dateformat FuriHalRtcLocaleDateFormat
1399 Function + furi_hal_rtc_get_locale_timeformat FuriHalRtcLocaleTimeFormat
1400 Function + furi_hal_rtc_get_locale_units FuriHalRtcLocaleUnits
1401 Function + furi_hal_rtc_get_log_baud_rate FuriHalRtcLogBaudRate
1402 Function + furi_hal_rtc_get_log_device FuriHalRtcLogDevice
1403 Function + furi_hal_rtc_get_log_level uint8_t
1404 Function + furi_hal_rtc_get_pin_fails uint32_t
1405 Function + furi_hal_rtc_get_register uint32_t FuriHalRtcRegister
1418 Function + furi_hal_rtc_set_locale_dateformat void FuriHalRtcLocaleDateFormat
1419 Function + furi_hal_rtc_set_locale_timeformat void FuriHalRtcLocaleTimeFormat
1420 Function + furi_hal_rtc_set_locale_units void FuriHalRtcLocaleUnits
1421 Function + furi_hal_rtc_set_log_baud_rate void FuriHalRtcLogBaudRate
1422 Function + furi_hal_rtc_set_log_device void FuriHalRtcLogDevice
1423 Function + furi_hal_rtc_set_log_level void uint8_t
1424 Function + furi_hal_rtc_set_pin_fails void uint32_t
1425 Function + furi_hal_rtc_set_register void FuriHalRtcRegister, uint32_t
1434 Function + furi_hal_sd_presence_init void
1435 Function + furi_hal_sd_read_blocks FuriStatus uint32_t*, uint32_t, uint32_t
1436 Function + furi_hal_sd_write_blocks FuriStatus const uint32_t*, uint32_t, uint32_t
1437 Function + furi_hal_serial_control_acquire FuriHalSerialHandle* FuriHalSerialId
1438 Function + furi_hal_serial_control_deinit void
1439 Function + furi_hal_serial_control_init void
1440 Function + furi_hal_serial_control_release void FuriHalSerialHandle*
1441 Function + furi_hal_serial_control_resume void
1442 Function + furi_hal_serial_control_set_logging_config void FuriHalSerialId, uint32_t
1443 Function + furi_hal_serial_control_suspend void
1444 Function + furi_hal_serial_deinit void FuriHalSerialHandle*
1445 Function + furi_hal_serial_dma_rx size_t FuriHalSerialHandle*, uint8_t*, size_t
1446 Function + furi_hal_serial_dma_rx_start void FuriHalSerialHandle*, FuriHalSerialDmaRxCallback, void*, _Bool
1447 Function + furi_hal_serial_dma_rx_stop void FuriHalSerialHandle*
1448 Function + furi_hal_serial_init void FuriHalSerialHandle*, uint32_t
1449 Function + furi_hal_serial_resume void FuriHalSerialHandle*
1450 Function + furi_hal_serial_async_rx uint8_t FuriHalSerialHandle*
1451 Function + furi_hal_serial_async_rx_start void FuriHalSerialHandle*, FuriHalSerialAsyncRxCallback, void*, _Bool
1452 Function + furi_hal_serial_async_rx_stop void FuriHalSerialHandle*
1453 Function + furi_hal_serial_set_br void FuriHalSerialHandle*, uint32_t
1454 Function + furi_hal_serial_suspend void FuriHalSerialHandle*
1455 Function + furi_hal_serial_tx void FuriHalSerialHandle*, const uint8_t*, size_t
1456 Function + furi_hal_serial_tx_wait_complete void FuriHalSerialHandle*
1457 Function + furi_hal_speaker_acquire _Bool uint32_t
1458 Function - furi_hal_speaker_deinit void
1459 Function - furi_hal_speaker_init void
1507 Function + furi_hal_subghz_tx _Bool
1508 Function + furi_hal_subghz_write_packet void const uint8_t*, uint8_t
1509 Function + furi_hal_switch void void*
Function + furi_hal_uart_deinit void FuriHalUartId
Function + furi_hal_uart_init void FuriHalUartId, uint32_t
Function + furi_hal_uart_resume void FuriHalUartId
Function + furi_hal_uart_set_br void FuriHalUartId, uint32_t
Function + furi_hal_uart_set_irq_cb void FuriHalUartId, void (*)(UartIrqEvent, uint8_t, void*), void*
Function + furi_hal_uart_suspend void FuriHalUartId
Function + furi_hal_uart_tx void FuriHalUartId, uint8_t*, size_t
1510 Function + furi_hal_usb_disable void
1511 Function + furi_hal_usb_enable void
1512 Function + furi_hal_usb_get_config FuriHalUsbInterface*
1552 Function + furi_kernel_lock int32_t
1553 Function + furi_kernel_restore_lock int32_t int32_t
1554 Function + furi_kernel_unlock int32_t
1555 Function + furi_log_add_handler _Bool FuriLogHandler
1556 Function + furi_log_get_level FuriLogLevel
1557 Function - furi_log_init void
1558 Function + furi_log_level_from_string _Bool const char*, FuriLogLevel*
1559 Function + furi_log_level_to_string _Bool FuriLogLevel, const char**
1560 Function + furi_log_print_format void FuriLogLevel, const char*, const char*, ...
1561 Function + furi_log_print_raw_format void FuriLogLevel, const char*, ...
1562 Function + furi_log_puts void const char*
1563 Function + furi_log_remove_handler _Bool FuriLogHandler
1564 Function + furi_log_set_level void FuriLogLevel
1565 Function - + furi_log_set_puts furi_log_tx void FuriLogPuts const uint8_t*, size_t
Function - furi_log_set_timestamp void FuriLogTimestamp
1566 Function + furi_message_queue_alloc FuriMessageQueue* uint32_t, uint32_t
1567 Function + furi_message_queue_free void FuriMessageQueue*
1568 Function + furi_message_queue_get FuriStatus FuriMessageQueue*, void*, uint32_t
3214 Function + validator_is_file_alloc_init ValidatorIsFile* const char*, const char*, const char*
3215 Function + validator_is_file_callback _Bool const char*, FuriString*, void*
3216 Function + validator_is_file_free void ValidatorIsFile*
3217 Function + value_index_bool uint8_t size_t const _Bool, const _Bool[], uint8_t const _Bool, const _Bool[], size_t
3218 Function + value_index_float uint8_t size_t const float, const float[], uint8_t const float, const float[], size_t
3219 Function + value_index_int32 uint8_t size_t const int32_t, const int32_t[], uint8_t const int32_t, const int32_t[], size_t
3220 Function + value_index_uint32 uint8_t size_t const uint32_t, const uint32_t[], uint8_t const uint32_t, const uint32_t[], size_t
3221 Function + variable_item_get_context void* VariableItem*
3222 Function + variable_item_get_current_value_index uint8_t VariableItem*
3223 Function + variable_item_list_add VariableItem* VariableItemList*, const char*, uint8_t, VariableItemChangeCallback, void*

View file

@ -33,7 +33,7 @@ void furi_hal_init() {
furi_hal_mpu_init();
furi_hal_clock_init();
furi_hal_random_init();
furi_hal_console_init();
furi_hal_serial_control_init();
furi_hal_rtc_init();
furi_hal_interrupt_init();
furi_hal_flash_init();

View file

@ -1,99 +0,0 @@
#include <furi_hal_console.h>
#include <furi_hal_uart.h>
#include <stdbool.h>
#include <stm32wbxx_ll_gpio.h>
#include <stm32wbxx_ll_usart.h>
#include <furi.h>
#define TAG "FuriHalConsole"
#ifdef HEAP_PRINT_DEBUG
#define CONSOLE_BAUDRATE 1843200
#else
#define CONSOLE_BAUDRATE 230400
#endif
typedef struct {
bool alive;
FuriHalConsoleTxCallback tx_callback;
void* tx_callback_context;
} FuriHalConsole;
FuriHalConsole furi_hal_console = {
.alive = false,
.tx_callback = NULL,
.tx_callback_context = NULL,
};
void furi_hal_console_init() {
furi_hal_uart_init(FuriHalUartIdUSART1, CONSOLE_BAUDRATE);
furi_hal_console.alive = true;
}
void furi_hal_console_enable() {
furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, NULL, NULL);
while(!LL_USART_IsActiveFlag_TC(USART1))
;
furi_hal_uart_set_br(FuriHalUartIdUSART1, CONSOLE_BAUDRATE);
furi_hal_console.alive = true;
}
void furi_hal_console_disable() {
while(!LL_USART_IsActiveFlag_TC(USART1))
;
furi_hal_console.alive = false;
}
void furi_hal_console_set_tx_callback(FuriHalConsoleTxCallback callback, void* context) {
FURI_CRITICAL_ENTER();
furi_hal_console.tx_callback = callback;
furi_hal_console.tx_callback_context = context;
FURI_CRITICAL_EXIT();
}
void furi_hal_console_tx(const uint8_t* buffer, size_t buffer_size) {
if(!furi_hal_console.alive) return;
FURI_CRITICAL_ENTER();
// Transmit data
if(furi_hal_console.tx_callback) {
furi_hal_console.tx_callback(buffer, buffer_size, furi_hal_console.tx_callback_context);
}
furi_hal_uart_tx(FuriHalUartIdUSART1, (uint8_t*)buffer, buffer_size);
// Wait for TC flag to be raised for last char
while(!LL_USART_IsActiveFlag_TC(USART1))
;
FURI_CRITICAL_EXIT();
}
void furi_hal_console_tx_with_new_line(const uint8_t* buffer, size_t buffer_size) {
if(!furi_hal_console.alive) return;
FURI_CRITICAL_ENTER();
// Transmit data
furi_hal_uart_tx(FuriHalUartIdUSART1, (uint8_t*)buffer, buffer_size);
// Transmit new line symbols
furi_hal_uart_tx(FuriHalUartIdUSART1, (uint8_t*)"\r\n", 2);
// Wait for TC flag to be raised for last char
while(!LL_USART_IsActiveFlag_TC(USART1))
;
FURI_CRITICAL_EXIT();
}
void furi_hal_console_printf(const char format[], ...) {
FuriString* string;
va_list args;
va_start(args, format);
string = furi_string_alloc_vprintf(format, args);
va_end(args);
furi_hal_console_tx((const uint8_t*)furi_string_get_cstr(string), furi_string_size(string));
furi_string_free(string);
}
void furi_hal_console_puts(const char* data) {
furi_hal_console_tx((const uint8_t*)data, strlen(data));
}

View file

@ -1,37 +0,0 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef void (*FuriHalConsoleTxCallback)(const uint8_t* buffer, size_t size, void* context);
void furi_hal_console_init();
void furi_hal_console_enable();
void furi_hal_console_disable();
void furi_hal_console_set_tx_callback(FuriHalConsoleTxCallback callback, void* context);
void furi_hal_console_tx(const uint8_t* buffer, size_t buffer_size);
void furi_hal_console_tx_with_new_line(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[], ...) _ATTRIBUTE((__format__(__printf__, 1, 2)));
void furi_hal_console_puts(const char* data);
#ifdef __cplusplus
}
#endif

View file

@ -59,6 +59,12 @@ const IRQn_Type furi_hal_interrupt_irqn[FuriHalInterruptIdMax] = {
// LPTIMx
[FuriHalInterruptIdLpTim1] = LPTIM1_IRQn,
[FuriHalInterruptIdLpTim2] = LPTIM2_IRQn,
// UARTx
[FuriHalInterruptIdUart1] = USART1_IRQn,
// LPUARTx
[FuriHalInterruptIdLpUart1] = LPUART1_IRQn,
};
__attribute__((always_inline)) static inline void
@ -329,3 +335,11 @@ void LPTIM1_IRQHandler() {
void LPTIM2_IRQHandler() {
furi_hal_interrupt_call(FuriHalInterruptIdLpTim2);
}
void USART1_IRQHandler(void) {
furi_hal_interrupt_call(FuriHalInterruptIdUart1);
}
void LPUART1_IRQHandler(void) {
furi_hal_interrupt_call(FuriHalInterruptIdLpUart1);
}

View file

@ -49,6 +49,12 @@ typedef enum {
FuriHalInterruptIdLpTim1,
FuriHalInterruptIdLpTim2,
//UARTx
FuriHalInterruptIdUart1,
//LPUARTx
FuriHalInterruptIdLpUart1,
// Service value
FuriHalInterruptIdMax,
} FuriHalInterruptId;

View file

@ -1,6 +1,5 @@
#include <furi_hal_os.h>
#include <furi_hal_clock.h>
#include <furi_hal_console.h>
#include <furi_hal_power.h>
#include <furi_hal_gpio.h>
#include <furi_hal_resources.h>
@ -208,8 +207,8 @@ void vPortSuppressTicksAndSleep(TickType_t expected_idle_ticks) {
void vApplicationStackOverflowHook(TaskHandle_t xTask, char* pcTaskName) {
UNUSED(xTask);
furi_hal_console_puts("\r\n\r\n stack overflow in ");
furi_hal_console_puts(pcTaskName);
furi_hal_console_puts("\r\n\r\n");
furi_log_puts("\r\n\r\n stack overflow in ");
furi_log_puts(pcTaskName);
furi_log_puts("\r\n\r\n");
furi_crash("StackOverflow");
}

View file

@ -3,7 +3,7 @@
#include <furi_hal_bt.h>
#include <furi_hal_vibro.h>
#include <furi_hal_resources.h>
#include <furi_hal_uart.h>
#include <furi_hal_serial_control.h>
#include <furi_hal_rtc.h>
#include <furi_hal_debug.h>
@ -178,14 +178,12 @@ static inline void furi_hal_power_light_sleep() {
static inline void furi_hal_power_suspend_aux_periphs() {
// Disable USART
furi_hal_uart_suspend(FuriHalUartIdUSART1);
furi_hal_uart_suspend(FuriHalUartIdLPUART1);
furi_hal_serial_control_suspend();
}
static inline void furi_hal_power_resume_aux_periphs() {
// Re-enable USART
furi_hal_uart_resume(FuriHalUartIdUSART1);
furi_hal_uart_resume(FuriHalUartIdLPUART1);
furi_hal_serial_control_resume();
}
static inline void furi_hal_power_deep_sleep() {

View file

@ -1,6 +1,7 @@
#include <furi_hal_rtc.h>
#include <furi_hal_light.h>
#include <furi_hal_debug.h>
#include <furi_hal_serial_control.h>
#include <stm32wbxx_ll_pwr.h>
#include <stm32wbxx_ll_bus.h>
@ -34,7 +35,9 @@ typedef struct {
FuriHalRtcLocaleUnits locale_units : 1;
FuriHalRtcLocaleTimeFormat locale_timeformat : 1;
FuriHalRtcLocaleDateFormat locale_dateformat : 2;
uint8_t reserved : 6;
FuriHalRtcLogDevice log_device : 2;
FuriHalRtcLogBaudRate log_baud_rate : 3;
uint8_t reserved : 1;
} SystemReg;
_Static_assert(sizeof(SystemReg) == 4, "SystemReg size mismatch");
@ -51,6 +54,24 @@ static const uint8_t furi_hal_rtc_days_per_month[2][FURI_HAL_RTC_MONTHS_COUNT] =
static const uint16_t furi_hal_rtc_days_per_year[] = {365, 366};
static const FuriHalSerialId furi_hal_rtc_log_devices[] = {
[FuriHalRtcLogDeviceUsart] = FuriHalSerialIdUsart,
[FuriHalRtcLogDeviceLpuart] = FuriHalSerialIdLpuart,
[FuriHalRtcLogDeviceReserved] = FuriHalSerialIdMax,
[FuriHalRtcLogDeviceNone] = FuriHalSerialIdMax,
};
static const uint32_t furi_hal_rtc_log_baud_rates[] = {
[FuriHalRtcLogBaudRate230400] = 230400,
[FuriHalRtcLogBaudRate9600] = 9600,
[FuriHalRtcLogBaudRate38400] = 38400,
[FuriHalRtcLogBaudRate57600] = 57600,
[FuriHalRtcLogBaudRate115200] = 115200,
[FuriHalRtcLogBaudRate460800] = 460800,
[FuriHalRtcLogBaudRate921600] = 921600,
[FuriHalRtcLogBaudRate1843200] = 1843200,
};
static void furi_hal_rtc_reset() {
LL_RCC_ForceBackupDomainReset();
LL_RCC_ReleaseBackupDomainReset();
@ -153,6 +174,9 @@ void furi_hal_rtc_init() {
LL_RTC_Init(RTC, &RTC_InitStruct);
furi_log_set_level(furi_hal_rtc_get_log_level());
furi_hal_serial_control_set_logging_config(
furi_hal_rtc_log_devices[furi_hal_rtc_get_log_device()],
furi_hal_rtc_log_baud_rates[furi_hal_rtc_get_log_baud_rate()]);
FURI_LOG_I(TAG, "Init OK");
}
@ -199,6 +223,40 @@ uint8_t furi_hal_rtc_get_log_level() {
return data->log_level;
}
void furi_hal_rtc_set_log_device(FuriHalRtcLogDevice device) {
uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem);
SystemReg* data = (SystemReg*)&data_reg;
data->log_device = device;
furi_hal_rtc_set_register(FuriHalRtcRegisterSystem, data_reg);
furi_hal_serial_control_set_logging_config(
furi_hal_rtc_log_devices[furi_hal_rtc_get_log_device()],
furi_hal_rtc_log_baud_rates[furi_hal_rtc_get_log_baud_rate()]);
}
FuriHalRtcLogDevice furi_hal_rtc_get_log_device() {
uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem);
SystemReg* data = (SystemReg*)&data_reg;
return data->log_device;
}
void furi_hal_rtc_set_log_baud_rate(FuriHalRtcLogBaudRate baud_rate) {
uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem);
SystemReg* data = (SystemReg*)&data_reg;
data->log_baud_rate = baud_rate;
furi_hal_rtc_set_register(FuriHalRtcRegisterSystem, data_reg);
furi_hal_serial_control_set_logging_config(
furi_hal_rtc_log_devices[furi_hal_rtc_get_log_device()],
furi_hal_rtc_log_baud_rates[furi_hal_rtc_get_log_baud_rate()]);
}
FuriHalRtcLogBaudRate furi_hal_rtc_get_log_baud_rate() {
uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem);
SystemReg* data = (SystemReg*)&data_reg;
return data->log_baud_rate;
}
void furi_hal_rtc_set_flag(FuriHalRtcFlag flag) {
uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem);
SystemReg* data = (SystemReg*)&data_reg;

View file

@ -64,32 +64,50 @@ typedef enum {
} FuriHalRtcRegister;
typedef enum {
FuriHalRtcLocaleUnitsMetric = 0, /**< Metric measurement units */
FuriHalRtcLocaleUnitsImperial = 1, /**< Imperial measurement units */
FuriHalRtcLocaleUnitsMetric = 0x0, /**< Metric measurement units */
FuriHalRtcLocaleUnitsImperial = 0x1, /**< Imperial measurement units */
} FuriHalRtcLocaleUnits;
typedef enum {
FuriHalRtcLocaleTimeFormat24h = 0, /**< 24-hour format */
FuriHalRtcLocaleTimeFormat12h = 1, /**< 12-hour format */
FuriHalRtcLocaleTimeFormat24h = 0x0, /**< 24-hour format */
FuriHalRtcLocaleTimeFormat12h = 0x1, /**< 12-hour format */
} FuriHalRtcLocaleTimeFormat;
typedef enum {
FuriHalRtcLocaleDateFormatDMY = 0, /**< Day/Month/Year */
FuriHalRtcLocaleDateFormatMDY = 1, /**< Month/Day/Year */
FuriHalRtcLocaleDateFormatYMD = 2, /**< Year/Month/Day */
FuriHalRtcLocaleDateFormatDMY = 0x0, /**< Day/Month/Year */
FuriHalRtcLocaleDateFormatMDY = 0x1, /**< Month/Day/Year */
FuriHalRtcLocaleDateFormatYMD = 0x2, /**< Year/Month/Day */
} FuriHalRtcLocaleDateFormat;
typedef enum {
FuriHalRtcLogDeviceUsart = 0x0, /**< Default: USART */
FuriHalRtcLogDeviceLpuart = 0x1, /**< Default: LPUART */
FuriHalRtcLogDeviceReserved = 0x2, /**< Reserved for future use */
FuriHalRtcLogDeviceNone = 0x3, /**< None, disable serial logging */
} FuriHalRtcLogDevice;
typedef enum {
FuriHalRtcLogBaudRate230400 = 0x0, /**< 230400 baud */
FuriHalRtcLogBaudRate9600 = 0x1, /**< 9600 baud */
FuriHalRtcLogBaudRate38400 = 0x2, /**< 38400 baud */
FuriHalRtcLogBaudRate57600 = 0x3, /**< 57600 baud */
FuriHalRtcLogBaudRate115200 = 0x4, /**< 115200 baud */
FuriHalRtcLogBaudRate460800 = 0x5, /**< 460800 baud */
FuriHalRtcLogBaudRate921600 = 0x6, /**< 921600 baud */
FuriHalRtcLogBaudRate1843200 = 0x7, /**< 1843200 baud */
} FuriHalRtcLogBaudRate;
/** Early initialization */
void furi_hal_rtc_init_early();
void furi_hal_rtc_init_early(void);
/** Early de-initialization */
void furi_hal_rtc_deinit_early();
void furi_hal_rtc_deinit_early(void);
/** Initialize RTC subsystem */
void furi_hal_rtc_init();
void furi_hal_rtc_init(void);
/** Force sync shadow registers */
void furi_hal_rtc_sync_shadow();
void furi_hal_rtc_sync_shadow(void);
/** Reset ALL RTC registers content */
void furi_hal_rtc_reset_registers();
@ -119,7 +137,31 @@ void furi_hal_rtc_set_log_level(uint8_t level);
*
* @return The Log Level value
*/
uint8_t furi_hal_rtc_get_log_level();
uint8_t furi_hal_rtc_get_log_level(void);
/** Set logging device
*
* @param[in] device The device
*/
void furi_hal_rtc_set_log_device(FuriHalRtcLogDevice device);
/** Get logging device
*
* @return The furi hal rtc log device.
*/
FuriHalRtcLogDevice furi_hal_rtc_get_log_device(void);
/** Set logging baud rate
*
* @param[in] baud_rate The baud rate
*/
void furi_hal_rtc_set_log_baud_rate(FuriHalRtcLogBaudRate baud_rate);
/** Get logging baud rate
*
* @return The furi hal rtc log baud rate.
*/
FuriHalRtcLogBaudRate furi_hal_rtc_get_log_baud_rate(void);
/** Set RTC Flag
*
@ -151,7 +193,7 @@ void furi_hal_rtc_set_boot_mode(FuriHalRtcBootMode mode);
*
* @return The RTC boot mode.
*/
FuriHalRtcBootMode furi_hal_rtc_get_boot_mode();
FuriHalRtcBootMode furi_hal_rtc_get_boot_mode(void);
/** Set Heap Track mode
*
@ -163,7 +205,7 @@ void furi_hal_rtc_set_heap_track_mode(FuriHalRtcHeapTrackMode mode);
*
* @return The RTC heap track mode.
*/
FuriHalRtcHeapTrackMode furi_hal_rtc_get_heap_track_mode();
FuriHalRtcHeapTrackMode furi_hal_rtc_get_heap_track_mode(void);
/** Set locale units
*
@ -175,7 +217,7 @@ void furi_hal_rtc_set_locale_units(FuriHalRtcLocaleUnits value);
*
* @return The RTC Locale Units.
*/
FuriHalRtcLocaleUnits furi_hal_rtc_get_locale_units();
FuriHalRtcLocaleUnits furi_hal_rtc_get_locale_units(void);
/** Set RTC Locale Time Format
*
@ -187,7 +229,7 @@ void furi_hal_rtc_set_locale_timeformat(FuriHalRtcLocaleTimeFormat value);
*
* @return The RTC Locale Time Format.
*/
FuriHalRtcLocaleTimeFormat furi_hal_rtc_get_locale_timeformat();
FuriHalRtcLocaleTimeFormat furi_hal_rtc_get_locale_timeformat(void);
/** Set RTC Locale Date Format
*
@ -199,7 +241,7 @@ void furi_hal_rtc_set_locale_dateformat(FuriHalRtcLocaleDateFormat value);
*
* @return The RTC Locale Date Format
*/
FuriHalRtcLocaleDateFormat furi_hal_rtc_get_locale_dateformat();
FuriHalRtcLocaleDateFormat furi_hal_rtc_get_locale_dateformat(void);
/** Set RTC Date Time
*
@ -231,7 +273,7 @@ void furi_hal_rtc_set_fault_data(uint32_t value);
*
* @return RTC Fault Data value
*/
uint32_t furi_hal_rtc_get_fault_data();
uint32_t furi_hal_rtc_get_fault_data(void);
/** Set Pin Fails count
*
@ -243,13 +285,13 @@ void furi_hal_rtc_set_pin_fails(uint32_t value);
*
* @return Pin Fails Count
*/
uint32_t furi_hal_rtc_get_pin_fails();
uint32_t furi_hal_rtc_get_pin_fails(void);
/** Get UNIX Timestamp
*
* @return Unix Timestamp in seconds from UNIX epoch start
*/
uint32_t furi_hal_rtc_get_timestamp();
uint32_t furi_hal_rtc_get_timestamp(void);
/** Convert DateTime to UNIX timestamp
*

View file

@ -0,0 +1,838 @@
#include <furi_hal_serial.h>
#include "furi_hal_serial_types_i.h"
#include <stdbool.h>
#include <stm32wbxx_ll_lpuart.h>
#include <stm32wbxx_ll_usart.h>
#include <stm32wbxx_ll_rcc.h>
#include <stm32wbxx_ll_dma.h>
#include <furi_hal_resources.h>
#include <furi_hal_interrupt.h>
#include <furi_hal_bus.h>
#include <furi.h>
#define FURI_HAL_SERIAL_USART_OVERSAMPLING LL_USART_OVERSAMPLING_16
#define FURI_HAL_SERIAL_USART_DMA_INSTANCE (DMA1)
#define FURI_HAL_SERIAL_USART_DMA_CHANNEL (LL_DMA_CHANNEL_6)
#define FURI_HAL_SERIAL_LPUART_DMA_INSTANCE (DMA1)
#define FURI_HAL_SERIAL_LPUART_DMA_CHANNEL (LL_DMA_CHANNEL_7)
typedef struct {
uint8_t* buffer_rx_ptr;
size_t buffer_rx_index_write;
size_t buffer_rx_index_read;
bool enabled;
FuriHalSerialHandle* handle;
FuriHalSerialAsyncRxCallback rx_byte_callback;
FuriHalSerialDmaRxCallback rx_dma_callback;
void* context;
} FuriHalSerial;
static FuriHalSerial furi_hal_serial[FuriHalSerialIdMax] = {0};
static size_t furi_hal_serial_dma_bytes_available(FuriHalSerialId ch);
static void furi_hal_serial_async_rx_configure(
FuriHalSerialHandle* handle,
FuriHalSerialAsyncRxCallback callback,
void* context);
static void furi_hal_serial_usart_irq_callback(void* context) {
UNUSED(context);
FuriHalSerialRxEvent event = 0;
// Notification flags
if(USART1->ISR & USART_ISR_RXNE_RXFNE) {
event |= FuriHalSerialRxEventData;
}
if(USART1->ISR & USART_ISR_IDLE) {
USART1->ICR = USART_ICR_IDLECF;
event |= FuriHalSerialRxEventIdle;
}
// Error flags
if(USART1->ISR & USART_ISR_ORE) {
USART1->ICR = USART_ICR_ORECF;
event |= FuriHalSerialRxEventOverrunError;
}
if(USART1->ISR & USART_ISR_NE) {
USART1->ICR = USART_ICR_NECF;
event |= FuriHalSerialRxEventNoiseError;
}
if(USART1->ISR & USART_ISR_FE) {
USART1->ICR = USART_ICR_FECF;
event |= FuriHalSerialRxEventFrameError;
}
if(USART1->ISR & USART_ISR_PE) {
USART1->ICR = USART_ICR_PECF;
event |= FuriHalSerialRxEventFrameError;
}
if(furi_hal_serial[FuriHalSerialIdUsart].buffer_rx_ptr == NULL) {
if(furi_hal_serial[FuriHalSerialIdUsart].rx_byte_callback) {
furi_hal_serial[FuriHalSerialIdUsart].rx_byte_callback(
furi_hal_serial[FuriHalSerialIdUsart].handle,
event,
furi_hal_serial[FuriHalSerialIdUsart].context);
}
} else {
if(furi_hal_serial[FuriHalSerialIdUsart].rx_dma_callback) {
furi_hal_serial[FuriHalSerialIdUsart].rx_dma_callback(
furi_hal_serial[FuriHalSerialIdUsart].handle,
event,
furi_hal_serial_dma_bytes_available(FuriHalSerialIdUsart),
furi_hal_serial[FuriHalSerialIdUsart].context);
}
}
}
static void furi_hal_serial_usart_dma_rx_isr(void* context) {
UNUSED(context);
#if FURI_HAL_SERIAL_USART_DMA_CHANNEL == LL_DMA_CHANNEL_6
if(LL_DMA_IsActiveFlag_HT6(FURI_HAL_SERIAL_USART_DMA_INSTANCE)) {
LL_DMA_ClearFlag_HT6(FURI_HAL_SERIAL_USART_DMA_INSTANCE);
furi_hal_serial[FuriHalSerialIdUsart].buffer_rx_index_write =
FURI_HAL_SERIAL_DMA_BUFFER_SIZE -
LL_DMA_GetDataLength(
FURI_HAL_SERIAL_USART_DMA_INSTANCE, FURI_HAL_SERIAL_USART_DMA_CHANNEL);
if((furi_hal_serial[FuriHalSerialIdUsart].buffer_rx_index_read >
furi_hal_serial[FuriHalSerialIdUsart].buffer_rx_index_write) ||
(furi_hal_serial[FuriHalSerialIdUsart].buffer_rx_index_read <
FURI_HAL_SERIAL_DMA_BUFFER_SIZE / 4)) {
if(furi_hal_serial[FuriHalSerialIdUsart].rx_dma_callback) {
furi_hal_serial[FuriHalSerialIdUsart].rx_dma_callback(
furi_hal_serial[FuriHalSerialIdUsart].handle,
FuriHalSerialRxEventData,
furi_hal_serial_dma_bytes_available(FuriHalSerialIdUsart),
furi_hal_serial[FuriHalSerialIdUsart].context);
}
}
} else if(LL_DMA_IsActiveFlag_TC6(FURI_HAL_SERIAL_USART_DMA_INSTANCE)) {
LL_DMA_ClearFlag_TC6(FURI_HAL_SERIAL_USART_DMA_INSTANCE);
if(furi_hal_serial[FuriHalSerialIdUsart].buffer_rx_index_read <
FURI_HAL_SERIAL_DMA_BUFFER_SIZE * 3 / 4) {
if(furi_hal_serial[FuriHalSerialIdUsart].rx_dma_callback) {
furi_hal_serial[FuriHalSerialIdUsart].rx_dma_callback(
furi_hal_serial[FuriHalSerialIdUsart].handle,
FuriHalSerialRxEventData,
furi_hal_serial_dma_bytes_available(FuriHalSerialIdUsart),
furi_hal_serial[FuriHalSerialIdUsart].context);
}
}
}
#else
#error Update this code. Would you kindly?
#endif
}
static void furi_hal_serial_usart_init_dma_rx(void) {
/* USART1_RX_DMA Init */
furi_check(furi_hal_serial[FuriHalSerialIdUsart].buffer_rx_ptr == NULL);
furi_hal_serial[FuriHalSerialIdUsart].buffer_rx_index_write = 0;
furi_hal_serial[FuriHalSerialIdUsart].buffer_rx_index_read = 0;
furi_hal_serial[FuriHalSerialIdUsart].buffer_rx_ptr = malloc(FURI_HAL_SERIAL_DMA_BUFFER_SIZE);
LL_DMA_SetMemoryAddress(
FURI_HAL_SERIAL_USART_DMA_INSTANCE,
FURI_HAL_SERIAL_USART_DMA_CHANNEL,
(uint32_t)furi_hal_serial[FuriHalSerialIdUsart].buffer_rx_ptr);
LL_DMA_SetPeriphAddress(
FURI_HAL_SERIAL_USART_DMA_INSTANCE,
FURI_HAL_SERIAL_USART_DMA_CHANNEL,
(uint32_t) & (USART1->RDR));
LL_DMA_ConfigTransfer(
FURI_HAL_SERIAL_USART_DMA_INSTANCE,
FURI_HAL_SERIAL_USART_DMA_CHANNEL,
LL_DMA_DIRECTION_PERIPH_TO_MEMORY | LL_DMA_MODE_CIRCULAR | LL_DMA_PERIPH_NOINCREMENT |
LL_DMA_MEMORY_INCREMENT | LL_DMA_PDATAALIGN_BYTE | LL_DMA_MDATAALIGN_BYTE |
LL_DMA_PRIORITY_HIGH);
LL_DMA_SetDataLength(
FURI_HAL_SERIAL_USART_DMA_INSTANCE,
FURI_HAL_SERIAL_USART_DMA_CHANNEL,
FURI_HAL_SERIAL_DMA_BUFFER_SIZE);
LL_DMA_SetPeriphRequest(
FURI_HAL_SERIAL_USART_DMA_INSTANCE,
FURI_HAL_SERIAL_USART_DMA_CHANNEL,
LL_DMAMUX_REQ_USART1_RX);
furi_hal_interrupt_set_isr(FuriHalInterruptIdDma1Ch6, furi_hal_serial_usart_dma_rx_isr, NULL);
#if FURI_HAL_SERIAL_USART_DMA_CHANNEL == LL_DMA_CHANNEL_6
if(LL_DMA_IsActiveFlag_HT6(FURI_HAL_SERIAL_USART_DMA_INSTANCE))
LL_DMA_ClearFlag_HT6(FURI_HAL_SERIAL_USART_DMA_INSTANCE);
if(LL_DMA_IsActiveFlag_TC6(FURI_HAL_SERIAL_USART_DMA_INSTANCE))
LL_DMA_ClearFlag_TC6(FURI_HAL_SERIAL_USART_DMA_INSTANCE);
if(LL_DMA_IsActiveFlag_TE6(FURI_HAL_SERIAL_USART_DMA_INSTANCE))
LL_DMA_ClearFlag_TE6(FURI_HAL_SERIAL_USART_DMA_INSTANCE);
#else
#error Update this code. Would you kindly?
#endif
LL_DMA_EnableIT_TC(FURI_HAL_SERIAL_USART_DMA_INSTANCE, FURI_HAL_SERIAL_USART_DMA_CHANNEL);
LL_DMA_EnableIT_HT(FURI_HAL_SERIAL_USART_DMA_INSTANCE, FURI_HAL_SERIAL_USART_DMA_CHANNEL);
LL_DMA_EnableChannel(FURI_HAL_SERIAL_USART_DMA_INSTANCE, FURI_HAL_SERIAL_USART_DMA_CHANNEL);
LL_USART_EnableDMAReq_RX(USART1);
LL_USART_EnableIT_IDLE(USART1);
}
static void furi_hal_serial_usart_deinit_dma_rx(void) {
if(furi_hal_serial[FuriHalSerialIdUsart].buffer_rx_ptr != NULL) {
LL_DMA_DisableChannel(
FURI_HAL_SERIAL_USART_DMA_INSTANCE, FURI_HAL_SERIAL_USART_DMA_CHANNEL);
LL_USART_DisableDMAReq_RX(USART1);
LL_USART_DisableIT_IDLE(USART1);
LL_DMA_DisableIT_TC(FURI_HAL_SERIAL_USART_DMA_INSTANCE, FURI_HAL_SERIAL_USART_DMA_CHANNEL);
LL_DMA_DisableIT_HT(FURI_HAL_SERIAL_USART_DMA_INSTANCE, FURI_HAL_SERIAL_USART_DMA_CHANNEL);
LL_DMA_ClearFlag_TC6(FURI_HAL_SERIAL_USART_DMA_INSTANCE);
LL_DMA_ClearFlag_HT6(FURI_HAL_SERIAL_USART_DMA_INSTANCE);
LL_DMA_DeInit(FURI_HAL_SERIAL_USART_DMA_INSTANCE, FURI_HAL_SERIAL_USART_DMA_CHANNEL);
furi_hal_interrupt_set_isr(FuriHalInterruptIdDma1Ch6, NULL, NULL);
free(furi_hal_serial[FuriHalSerialIdUsart].buffer_rx_ptr);
furi_hal_serial[FuriHalSerialIdUsart].buffer_rx_ptr = NULL;
}
}
static void furi_hal_serial_usart_init(FuriHalSerialHandle* handle, uint32_t baud) {
furi_hal_bus_enable(FuriHalBusUSART1);
LL_RCC_SetUSARTClockSource(LL_RCC_USART1_CLKSOURCE_PCLK2);
furi_hal_gpio_init_ex(
&gpio_usart_tx,
GpioModeAltFunctionPushPull,
GpioPullUp,
GpioSpeedVeryHigh,
GpioAltFn7USART1);
furi_hal_gpio_init_ex(
&gpio_usart_rx,
GpioModeAltFunctionPushPull,
GpioPullUp,
GpioSpeedVeryHigh,
GpioAltFn7USART1);
LL_USART_InitTypeDef USART_InitStruct;
USART_InitStruct.PrescalerValue = LL_USART_PRESCALER_DIV1;
USART_InitStruct.BaudRate = baud;
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_RX;
USART_InitStruct.HardwareFlowControl = LL_USART_HWCONTROL_NONE;
USART_InitStruct.OverSampling = FURI_HAL_SERIAL_USART_OVERSAMPLING;
LL_USART_Init(USART1, &USART_InitStruct);
LL_USART_EnableFIFO(USART1);
LL_USART_ConfigAsyncMode(USART1);
LL_USART_Enable(USART1);
while(!LL_USART_IsActiveFlag_TEACK(USART1) || !LL_USART_IsActiveFlag_REACK(USART1))
;
furi_hal_serial_set_br(handle, baud);
LL_USART_DisableIT_ERROR(USART1);
furi_hal_serial[handle->id].enabled = true;
}
static void furi_hal_serial_lpuart_irq_callback(void* context) {
UNUSED(context);
FuriHalSerialRxEvent event = 0;
// Notification flags
if(LPUART1->ISR & USART_ISR_RXNE_RXFNE) {
event |= FuriHalSerialRxEventData;
}
if(LPUART1->ISR & USART_ISR_IDLE) {
LPUART1->ICR = USART_ICR_IDLECF;
event |= FuriHalSerialRxEventIdle;
}
// Error flags
if(LPUART1->ISR & USART_ISR_ORE) {
LPUART1->ICR = USART_ICR_ORECF;
event |= FuriHalSerialRxEventOverrunError;
}
if(LPUART1->ISR & USART_ISR_NE) {
LPUART1->ICR = USART_ICR_NECF;
event |= FuriHalSerialRxEventNoiseError;
}
if(LPUART1->ISR & USART_ISR_FE) {
LPUART1->ICR = USART_ICR_FECF;
event |= FuriHalSerialRxEventFrameError;
}
if(LPUART1->ISR & USART_ISR_PE) {
LPUART1->ICR = USART_ICR_PECF;
event |= FuriHalSerialRxEventFrameError;
}
if(furi_hal_serial[FuriHalSerialIdLpuart].buffer_rx_ptr == NULL) {
if(furi_hal_serial[FuriHalSerialIdLpuart].rx_byte_callback) {
furi_hal_serial[FuriHalSerialIdLpuart].rx_byte_callback(
furi_hal_serial[FuriHalSerialIdLpuart].handle,
event,
furi_hal_serial[FuriHalSerialIdLpuart].context);
}
} else {
if(furi_hal_serial[FuriHalSerialIdLpuart].rx_dma_callback) {
furi_hal_serial[FuriHalSerialIdLpuart].rx_dma_callback(
furi_hal_serial[FuriHalSerialIdLpuart].handle,
event,
furi_hal_serial_dma_bytes_available(FuriHalSerialIdLpuart),
furi_hal_serial[FuriHalSerialIdLpuart].context);
}
}
}
static void furi_hal_serial_lpuart_dma_rx_isr(void* context) {
UNUSED(context);
#if FURI_HAL_SERIAL_LPUART_DMA_CHANNEL == LL_DMA_CHANNEL_7
if(LL_DMA_IsActiveFlag_HT7(FURI_HAL_SERIAL_LPUART_DMA_INSTANCE)) {
LL_DMA_ClearFlag_HT7(FURI_HAL_SERIAL_LPUART_DMA_INSTANCE);
furi_hal_serial[FuriHalSerialIdLpuart].buffer_rx_index_write =
FURI_HAL_SERIAL_DMA_BUFFER_SIZE -
LL_DMA_GetDataLength(
FURI_HAL_SERIAL_LPUART_DMA_INSTANCE, FURI_HAL_SERIAL_LPUART_DMA_CHANNEL);
if((furi_hal_serial[FuriHalSerialIdLpuart].buffer_rx_index_read >
furi_hal_serial[FuriHalSerialIdLpuart].buffer_rx_index_write) ||
(furi_hal_serial[FuriHalSerialIdLpuart].buffer_rx_index_read <
FURI_HAL_SERIAL_DMA_BUFFER_SIZE / 4)) {
if(furi_hal_serial[FuriHalSerialIdLpuart].rx_dma_callback) {
furi_hal_serial[FuriHalSerialIdLpuart].rx_dma_callback(
furi_hal_serial[FuriHalSerialIdLpuart].handle,
FuriHalSerialRxEventData,
furi_hal_serial_dma_bytes_available(FuriHalSerialIdLpuart),
furi_hal_serial[FuriHalSerialIdLpuart].context);
}
}
} else if(LL_DMA_IsActiveFlag_TC7(FURI_HAL_SERIAL_LPUART_DMA_INSTANCE)) {
LL_DMA_ClearFlag_TC7(FURI_HAL_SERIAL_LPUART_DMA_INSTANCE);
if(furi_hal_serial[FuriHalSerialIdLpuart].buffer_rx_index_read <
FURI_HAL_SERIAL_DMA_BUFFER_SIZE * 3 / 4) {
if(furi_hal_serial[FuriHalSerialIdLpuart].rx_dma_callback) {
furi_hal_serial[FuriHalSerialIdLpuart].rx_dma_callback(
furi_hal_serial[FuriHalSerialIdLpuart].handle,
FuriHalSerialRxEventData,
furi_hal_serial_dma_bytes_available(FuriHalSerialIdLpuart),
furi_hal_serial[FuriHalSerialIdLpuart].context);
}
}
}
#else
#error Update this code. Would you kindly?
#endif
}
static void furi_hal_serial_lpuart_init_dma_rx(void) {
/* LPUART1_RX_DMA Init */
furi_check(furi_hal_serial[FuriHalSerialIdLpuart].buffer_rx_ptr == NULL);
furi_hal_serial[FuriHalSerialIdLpuart].buffer_rx_index_write = 0;
furi_hal_serial[FuriHalSerialIdLpuart].buffer_rx_index_read = 0;
furi_hal_serial[FuriHalSerialIdLpuart].buffer_rx_ptr = malloc(FURI_HAL_SERIAL_DMA_BUFFER_SIZE);
LL_DMA_SetMemoryAddress(
FURI_HAL_SERIAL_LPUART_DMA_INSTANCE,
FURI_HAL_SERIAL_LPUART_DMA_CHANNEL,
(uint32_t)furi_hal_serial[FuriHalSerialIdLpuart].buffer_rx_ptr);
LL_DMA_SetPeriphAddress(
FURI_HAL_SERIAL_LPUART_DMA_INSTANCE,
FURI_HAL_SERIAL_LPUART_DMA_CHANNEL,
(uint32_t) & (LPUART1->RDR));
LL_DMA_ConfigTransfer(
FURI_HAL_SERIAL_LPUART_DMA_INSTANCE,
FURI_HAL_SERIAL_LPUART_DMA_CHANNEL,
LL_DMA_DIRECTION_PERIPH_TO_MEMORY | LL_DMA_MODE_CIRCULAR | LL_DMA_PERIPH_NOINCREMENT |
LL_DMA_MEMORY_INCREMENT | LL_DMA_PDATAALIGN_BYTE | LL_DMA_MDATAALIGN_BYTE |
LL_DMA_PRIORITY_HIGH);
LL_DMA_SetDataLength(
FURI_HAL_SERIAL_LPUART_DMA_INSTANCE,
FURI_HAL_SERIAL_LPUART_DMA_CHANNEL,
FURI_HAL_SERIAL_DMA_BUFFER_SIZE);
LL_DMA_SetPeriphRequest(
FURI_HAL_SERIAL_LPUART_DMA_INSTANCE,
FURI_HAL_SERIAL_LPUART_DMA_CHANNEL,
LL_DMAMUX_REQ_LPUART1_RX);
furi_hal_interrupt_set_isr(FuriHalInterruptIdDma1Ch7, furi_hal_serial_lpuart_dma_rx_isr, NULL);
#if FURI_HAL_SERIAL_LPUART_DMA_CHANNEL == LL_DMA_CHANNEL_7
if(LL_DMA_IsActiveFlag_HT7(FURI_HAL_SERIAL_LPUART_DMA_INSTANCE))
LL_DMA_ClearFlag_HT7(FURI_HAL_SERIAL_LPUART_DMA_INSTANCE);
if(LL_DMA_IsActiveFlag_TC7(FURI_HAL_SERIAL_LPUART_DMA_INSTANCE))
LL_DMA_ClearFlag_TC7(FURI_HAL_SERIAL_LPUART_DMA_INSTANCE);
if(LL_DMA_IsActiveFlag_TE7(FURI_HAL_SERIAL_LPUART_DMA_INSTANCE))
LL_DMA_ClearFlag_TE7(FURI_HAL_SERIAL_LPUART_DMA_INSTANCE);
#else
#error Update this code. Would you kindly?
#endif
LL_DMA_EnableIT_TC(FURI_HAL_SERIAL_LPUART_DMA_INSTANCE, FURI_HAL_SERIAL_LPUART_DMA_CHANNEL);
LL_DMA_EnableIT_HT(FURI_HAL_SERIAL_LPUART_DMA_INSTANCE, FURI_HAL_SERIAL_LPUART_DMA_CHANNEL);
LL_DMA_EnableChannel(FURI_HAL_SERIAL_LPUART_DMA_INSTANCE, FURI_HAL_SERIAL_LPUART_DMA_CHANNEL);
LL_USART_EnableDMAReq_RX(LPUART1);
LL_USART_EnableIT_IDLE(LPUART1);
}
static void furi_hal_serial_lpuart_deinit_dma_rx(void) {
if(furi_hal_serial[FuriHalSerialIdLpuart].buffer_rx_ptr != NULL) {
LL_DMA_DisableChannel(
FURI_HAL_SERIAL_LPUART_DMA_INSTANCE, FURI_HAL_SERIAL_LPUART_DMA_CHANNEL);
LL_USART_DisableDMAReq_RX(LPUART1);
LL_USART_DisableIT_IDLE(LPUART1);
LL_DMA_DisableIT_TC(
FURI_HAL_SERIAL_LPUART_DMA_INSTANCE, FURI_HAL_SERIAL_LPUART_DMA_CHANNEL);
LL_DMA_DisableIT_HT(
FURI_HAL_SERIAL_LPUART_DMA_INSTANCE, FURI_HAL_SERIAL_LPUART_DMA_CHANNEL);
LL_DMA_ClearFlag_TC7(FURI_HAL_SERIAL_LPUART_DMA_INSTANCE);
LL_DMA_ClearFlag_HT7(FURI_HAL_SERIAL_LPUART_DMA_INSTANCE);
LL_DMA_DeInit(FURI_HAL_SERIAL_LPUART_DMA_INSTANCE, FURI_HAL_SERIAL_LPUART_DMA_CHANNEL);
furi_hal_interrupt_set_isr(FuriHalInterruptIdDma1Ch7, NULL, NULL);
free(furi_hal_serial[FuriHalSerialIdLpuart].buffer_rx_ptr);
furi_hal_serial[FuriHalSerialIdLpuart].buffer_rx_ptr = NULL;
}
}
static void furi_hal_serial_lpuart_init(FuriHalSerialHandle* handle, uint32_t baud) {
furi_hal_bus_enable(FuriHalBusLPUART1);
LL_RCC_SetLPUARTClockSource(LL_RCC_LPUART1_CLKSOURCE_PCLK1);
furi_hal_gpio_init_ex(
&gpio_ext_pc0,
GpioModeAltFunctionPushPull,
GpioPullUp,
GpioSpeedVeryHigh,
GpioAltFn8LPUART1);
furi_hal_gpio_init_ex(
&gpio_ext_pc1,
GpioModeAltFunctionPushPull,
GpioPullUp,
GpioSpeedVeryHigh,
GpioAltFn8LPUART1);
LL_LPUART_InitTypeDef LPUART_InitStruct;
LPUART_InitStruct.PrescalerValue = LL_LPUART_PRESCALER_DIV1;
LPUART_InitStruct.BaudRate = baud;
LPUART_InitStruct.DataWidth = LL_LPUART_DATAWIDTH_8B;
LPUART_InitStruct.StopBits = LL_LPUART_STOPBITS_1;
LPUART_InitStruct.Parity = LL_LPUART_PARITY_NONE;
LPUART_InitStruct.TransferDirection = LL_LPUART_DIRECTION_TX_RX;
LPUART_InitStruct.HardwareFlowControl = LL_LPUART_HWCONTROL_NONE;
LL_LPUART_Init(LPUART1, &LPUART_InitStruct);
LL_LPUART_EnableFIFO(LPUART1);
LL_LPUART_Enable(LPUART1);
while(!LL_LPUART_IsActiveFlag_TEACK(LPUART1) || !LL_LPUART_IsActiveFlag_REACK(LPUART1))
;
furi_hal_serial_set_br(handle, baud);
LL_LPUART_DisableIT_ERROR(LPUART1);
furi_hal_serial[handle->id].enabled = true;
}
void furi_hal_serial_init(FuriHalSerialHandle* handle, uint32_t baud) {
furi_check(handle);
if(handle->id == FuriHalSerialIdLpuart) {
furi_hal_serial_lpuart_init(handle, baud);
} else if(handle->id == FuriHalSerialIdUsart) {
furi_hal_serial_usart_init(handle, baud);
}
}
static uint32_t furi_hal_serial_get_prescaler(FuriHalSerialHandle* handle, uint32_t baud) {
uint32_t uartclk = LL_RCC_GetUSARTClockFreq(LL_RCC_USART1_CLKSOURCE);
uint32_t divisor = (uartclk / baud);
uint32_t prescaler = 0;
if(handle->id == FuriHalSerialIdUsart) {
if(FURI_HAL_SERIAL_USART_OVERSAMPLING == LL_USART_OVERSAMPLING_16) {
divisor = (divisor / 16) >> 12;
} else {
divisor = (divisor / 8) >> 12;
}
if(divisor < 1) {
prescaler = LL_USART_PRESCALER_DIV1;
} else if(divisor < 2) {
prescaler = LL_USART_PRESCALER_DIV2;
} else if(divisor < 4) {
prescaler = LL_USART_PRESCALER_DIV4;
} else if(divisor < 6) {
prescaler = LL_USART_PRESCALER_DIV6;
} else if(divisor < 8) {
prescaler = LL_USART_PRESCALER_DIV8;
} else if(divisor < 10) {
prescaler = LL_USART_PRESCALER_DIV10;
} else if(divisor < 12) {
prescaler = LL_USART_PRESCALER_DIV12;
} else if(divisor < 16) {
prescaler = LL_USART_PRESCALER_DIV16;
} else if(divisor < 32) {
prescaler = LL_USART_PRESCALER_DIV32;
} else if(divisor < 64) {
prescaler = LL_USART_PRESCALER_DIV64;
} else if(divisor < 128) {
prescaler = LL_USART_PRESCALER_DIV128;
} else {
prescaler = LL_USART_PRESCALER_DIV256;
}
} else if(handle->id == FuriHalSerialIdLpuart) {
divisor >>= 12;
if(divisor < 1) {
prescaler = LL_LPUART_PRESCALER_DIV1;
} else if(divisor < 2) {
prescaler = LL_LPUART_PRESCALER_DIV2;
} else if(divisor < 4) {
prescaler = LL_LPUART_PRESCALER_DIV4;
} else if(divisor < 6) {
prescaler = LL_LPUART_PRESCALER_DIV6;
} else if(divisor < 8) {
prescaler = LL_LPUART_PRESCALER_DIV8;
} else if(divisor < 10) {
prescaler = LL_LPUART_PRESCALER_DIV10;
} else if(divisor < 12) {
prescaler = LL_LPUART_PRESCALER_DIV12;
} else if(divisor < 16) {
prescaler = LL_LPUART_PRESCALER_DIV16;
} else if(divisor < 32) {
prescaler = LL_LPUART_PRESCALER_DIV32;
} else if(divisor < 64) {
prescaler = LL_LPUART_PRESCALER_DIV64;
} else if(divisor < 128) {
prescaler = LL_LPUART_PRESCALER_DIV128;
} else {
prescaler = LL_LPUART_PRESCALER_DIV256;
}
}
return prescaler;
}
void furi_hal_serial_set_br(FuriHalSerialHandle* handle, uint32_t baud) {
furi_check(handle);
uint32_t prescaler = furi_hal_serial_get_prescaler(handle, baud);
if(handle->id == FuriHalSerialIdUsart) {
if(LL_USART_IsEnabled(USART1)) {
// Wait for transfer complete flag
while(!LL_USART_IsActiveFlag_TC(USART1))
;
LL_USART_Disable(USART1);
uint32_t uartclk = LL_RCC_GetUSARTClockFreq(LL_RCC_USART1_CLKSOURCE);
LL_USART_SetPrescaler(USART1, prescaler);
LL_USART_SetBaudRate(
USART1, uartclk, prescaler, FURI_HAL_SERIAL_USART_OVERSAMPLING, baud);
LL_USART_Enable(USART1);
}
} else if(handle->id == FuriHalSerialIdLpuart) {
if(LL_LPUART_IsEnabled(LPUART1)) {
// Wait for transfer complete flag
while(!LL_LPUART_IsActiveFlag_TC(LPUART1))
;
LL_LPUART_Disable(LPUART1);
uint32_t uartclk = LL_RCC_GetLPUARTClockFreq(LL_RCC_LPUART1_CLKSOURCE);
LL_LPUART_SetPrescaler(LPUART1, prescaler);
LL_LPUART_SetBaudRate(LPUART1, uartclk, prescaler, baud);
LL_LPUART_Enable(LPUART1);
}
}
}
void furi_hal_serial_deinit(FuriHalSerialHandle* handle) {
furi_check(handle);
furi_hal_serial_async_rx_configure(handle, NULL, NULL);
if(handle->id == FuriHalSerialIdUsart) {
if(furi_hal_bus_is_enabled(FuriHalBusUSART1)) {
furi_hal_bus_disable(FuriHalBusUSART1);
}
if(LL_USART_IsEnabled(USART1)) {
LL_USART_Disable(USART1);
}
furi_hal_serial_usart_deinit_dma_rx();
furi_hal_gpio_init(&gpio_usart_tx, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
furi_hal_gpio_init(&gpio_usart_rx, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
} else if(handle->id == FuriHalSerialIdLpuart) {
if(furi_hal_bus_is_enabled(FuriHalBusLPUART1)) {
furi_hal_bus_disable(FuriHalBusLPUART1);
}
if(LL_LPUART_IsEnabled(LPUART1)) {
LL_LPUART_Disable(LPUART1);
}
furi_hal_serial_lpuart_deinit_dma_rx();
furi_hal_gpio_init(&gpio_ext_pc0, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
furi_hal_gpio_init(&gpio_ext_pc1, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
} else {
furi_crash();
}
furi_hal_serial[handle->id].enabled = false;
}
void furi_hal_serial_suspend(FuriHalSerialHandle* handle) {
furi_check(handle);
if(handle->id == FuriHalSerialIdLpuart && LL_LPUART_IsEnabled(LPUART1)) {
LL_LPUART_Disable(LPUART1);
} else if(handle->id == FuriHalSerialIdUsart && LL_USART_IsEnabled(USART1)) {
LL_USART_Disable(USART1);
}
furi_hal_serial[handle->id].enabled = false;
}
void furi_hal_serial_resume(FuriHalSerialHandle* handle) {
furi_check(handle);
if(!furi_hal_serial[handle->id].enabled) {
if(handle->id == FuriHalSerialIdLpuart) {
LL_LPUART_Enable(LPUART1);
} else if(handle->id == FuriHalSerialIdUsart) {
LL_USART_Enable(USART1);
}
furi_hal_serial[handle->id].enabled = true;
}
}
void furi_hal_serial_tx(FuriHalSerialHandle* handle, const uint8_t* buffer, size_t buffer_size) {
furi_check(handle);
if(handle->id == FuriHalSerialIdUsart) {
if(LL_USART_IsEnabled(USART1) == 0) return;
while(buffer_size > 0) {
while(!LL_USART_IsActiveFlag_TXE(USART1))
;
LL_USART_TransmitData8(USART1, *buffer);
buffer++;
buffer_size--;
}
} else if(handle->id == FuriHalSerialIdLpuart) {
if(LL_LPUART_IsEnabled(LPUART1) == 0) return;
while(buffer_size > 0) {
while(!LL_LPUART_IsActiveFlag_TXE(LPUART1))
;
LL_LPUART_TransmitData8(LPUART1, *buffer);
buffer++;
buffer_size--;
}
}
}
void furi_hal_serial_tx_wait_complete(FuriHalSerialHandle* handle) {
furi_check(handle);
if(handle->id == FuriHalSerialIdUsart) {
if(LL_USART_IsEnabled(USART1) == 0) return;
while(!LL_USART_IsActiveFlag_TC(USART1))
;
} else if(handle->id == FuriHalSerialIdLpuart) {
if(LL_LPUART_IsEnabled(LPUART1) == 0) return;
while(!LL_LPUART_IsActiveFlag_TC(LPUART1))
;
}
}
static void furi_hal_serial_event_init(FuriHalSerialHandle* handle, bool report_errors) {
if(handle->id == FuriHalSerialIdUsart) {
LL_USART_EnableIT_IDLE(USART1);
} else if(handle->id == FuriHalSerialIdLpuart) {
LL_LPUART_EnableIT_IDLE(LPUART1);
}
if(report_errors) {
if(handle->id == FuriHalSerialIdUsart) {
LL_USART_EnableIT_ERROR(USART1);
} else if(handle->id == FuriHalSerialIdLpuart) {
LL_LPUART_EnableIT_ERROR(LPUART1);
}
}
}
static void furi_hal_serial_event_deinit(FuriHalSerialHandle* handle) {
if(handle->id == FuriHalSerialIdUsart) {
if(LL_USART_IsEnabledIT_IDLE(USART1)) LL_USART_DisableIT_IDLE(USART1);
if(LL_USART_IsEnabledIT_ERROR(USART1)) LL_USART_DisableIT_ERROR(USART1);
} else if(handle->id == FuriHalSerialIdLpuart) {
if(LL_LPUART_IsEnabledIT_IDLE(LPUART1)) LL_LPUART_DisableIT_IDLE(LPUART1);
if(LL_LPUART_IsEnabledIT_ERROR(LPUART1)) LL_LPUART_DisableIT_ERROR(LPUART1);
}
}
static void furi_hal_serial_async_rx_configure(
FuriHalSerialHandle* handle,
FuriHalSerialAsyncRxCallback callback,
void* context) {
if(handle->id == FuriHalSerialIdUsart) {
if(callback) {
furi_hal_serial_usart_deinit_dma_rx();
furi_hal_interrupt_set_isr(
FuriHalInterruptIdUart1, furi_hal_serial_usart_irq_callback, NULL);
LL_USART_EnableIT_RXNE_RXFNE(USART1);
} else {
furi_hal_interrupt_set_isr(FuriHalInterruptIdUart1, NULL, NULL);
furi_hal_serial_usart_deinit_dma_rx();
LL_USART_DisableIT_RXNE_RXFNE(USART1);
}
} else if(handle->id == FuriHalSerialIdLpuart) {
if(callback) {
furi_hal_serial_lpuart_deinit_dma_rx();
furi_hal_interrupt_set_isr(
FuriHalInterruptIdLpUart1, furi_hal_serial_lpuart_irq_callback, NULL);
LL_LPUART_EnableIT_RXNE_RXFNE(LPUART1);
} else {
furi_hal_interrupt_set_isr(FuriHalInterruptIdLpUart1, NULL, NULL);
furi_hal_serial_lpuart_deinit_dma_rx();
LL_LPUART_DisableIT_RXNE_RXFNE(LPUART1);
}
}
furi_hal_serial[handle->id].rx_byte_callback = callback;
furi_hal_serial[handle->id].handle = handle;
furi_hal_serial[handle->id].rx_dma_callback = NULL;
furi_hal_serial[handle->id].context = context;
}
void furi_hal_serial_async_rx_start(
FuriHalSerialHandle* handle,
FuriHalSerialAsyncRxCallback callback,
void* context,
bool report_errors) {
furi_check(handle);
furi_check(callback);
furi_hal_serial_event_init(handle, report_errors);
furi_hal_serial_async_rx_configure(handle, callback, context);
// Assign different functions to different UARTs
furi_check(
furi_hal_serial[FuriHalSerialIdUsart].rx_byte_callback !=
furi_hal_serial[FuriHalSerialIdLpuart].rx_byte_callback);
}
void furi_hal_serial_async_rx_stop(FuriHalSerialHandle* handle) {
furi_check(handle);
furi_hal_serial_event_deinit(handle);
furi_hal_serial_async_rx_configure(handle, NULL, NULL);
}
uint8_t furi_hal_serial_async_rx(FuriHalSerialHandle* handle) {
furi_check(FURI_IS_IRQ_MODE());
furi_assert(handle->id < FuriHalSerialIdMax);
if(handle->id == FuriHalSerialIdUsart) {
return LL_USART_ReceiveData8(USART1);
}
return LL_LPUART_ReceiveData8(LPUART1);
}
static size_t furi_hal_serial_dma_bytes_available(FuriHalSerialId ch) {
size_t dma_remain = 0;
if(ch == FuriHalSerialIdUsart) {
dma_remain = LL_DMA_GetDataLength(
FURI_HAL_SERIAL_USART_DMA_INSTANCE, FURI_HAL_SERIAL_USART_DMA_CHANNEL);
} else if(ch == FuriHalSerialIdLpuart) {
dma_remain = LL_DMA_GetDataLength(
FURI_HAL_SERIAL_LPUART_DMA_INSTANCE, FURI_HAL_SERIAL_LPUART_DMA_CHANNEL);
} else {
furi_crash();
}
furi_hal_serial[ch].buffer_rx_index_write = FURI_HAL_SERIAL_DMA_BUFFER_SIZE - dma_remain;
if(furi_hal_serial[ch].buffer_rx_index_write >= furi_hal_serial[ch].buffer_rx_index_read) {
return furi_hal_serial[ch].buffer_rx_index_write -
furi_hal_serial[ch].buffer_rx_index_read;
} else {
return FURI_HAL_SERIAL_DMA_BUFFER_SIZE - furi_hal_serial[ch].buffer_rx_index_read +
furi_hal_serial[ch].buffer_rx_index_write;
}
}
static uint8_t furi_hal_serial_dma_rx_read_byte(FuriHalSerialHandle* handle) {
uint8_t data = 0;
data =
furi_hal_serial[handle->id].buffer_rx_ptr[furi_hal_serial[handle->id].buffer_rx_index_read];
furi_hal_serial[handle->id].buffer_rx_index_read++;
if(furi_hal_serial[handle->id].buffer_rx_index_read >= FURI_HAL_SERIAL_DMA_BUFFER_SIZE) {
furi_hal_serial[handle->id].buffer_rx_index_read = 0;
}
return data;
}
size_t furi_hal_serial_dma_rx(FuriHalSerialHandle* handle, uint8_t* data, size_t len) {
furi_check(FURI_IS_IRQ_MODE());
furi_assert(furi_hal_serial[handle->id].buffer_rx_ptr != NULL);
size_t i = 0;
size_t available = furi_hal_serial_dma_bytes_available(handle->id);
if(available < len) {
len = available;
}
for(i = 0; i < len; i++) {
data[i] = furi_hal_serial_dma_rx_read_byte(handle);
}
return i;
}
static void furi_hal_serial_dma_configure(
FuriHalSerialHandle* handle,
FuriHalSerialDmaRxCallback callback,
void* context) {
furi_check(handle);
if(handle->id == FuriHalSerialIdUsart) {
if(callback) {
furi_hal_serial_usart_init_dma_rx();
furi_hal_interrupt_set_isr(
FuriHalInterruptIdUart1, furi_hal_serial_usart_irq_callback, NULL);
} else {
LL_USART_DisableIT_RXNE_RXFNE(USART1);
furi_hal_interrupt_set_isr(FuriHalInterruptIdUart1, NULL, NULL);
furi_hal_serial_usart_deinit_dma_rx();
}
} else if(handle->id == FuriHalSerialIdLpuart) {
if(callback) {
furi_hal_serial_lpuart_init_dma_rx();
furi_hal_interrupt_set_isr(
FuriHalInterruptIdLpUart1, furi_hal_serial_lpuart_irq_callback, NULL);
} else {
LL_LPUART_DisableIT_RXNE_RXFNE(LPUART1);
furi_hal_interrupt_set_isr(FuriHalInterruptIdLpUart1, NULL, NULL);
furi_hal_serial_lpuart_deinit_dma_rx();
}
}
furi_hal_serial[handle->id].rx_byte_callback = NULL;
furi_hal_serial[handle->id].handle = handle;
furi_hal_serial[handle->id].rx_dma_callback = callback;
furi_hal_serial[handle->id].context = context;
}
void furi_hal_serial_dma_rx_start(
FuriHalSerialHandle* handle,
FuriHalSerialDmaRxCallback callback,
void* context,
bool report_errors) {
furi_check(handle);
furi_check(callback);
furi_hal_serial_event_init(handle, report_errors);
furi_hal_serial_dma_configure(handle, callback, context);
// Assign different functions to different UARTs
furi_check(
furi_hal_serial[FuriHalSerialIdUsart].rx_dma_callback !=
furi_hal_serial[FuriHalSerialIdLpuart].rx_dma_callback);
}
void furi_hal_serial_dma_rx_stop(FuriHalSerialHandle* handle) {
furi_check(handle);
furi_hal_serial_event_deinit(handle);
furi_hal_serial_dma_configure(handle, NULL, NULL);
}

View file

@ -0,0 +1,189 @@
/**
* @file furi_hal_serial.h
*
* Serial HAL API
*/
#pragma once
#include <stddef.h>
#include <stdint.h>
#include "furi_hal_serial_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/** Initialize Serial
*
* Configures GPIO, configures and enables transceiver.
*
* @param handle Serial handle
* @param baud baud rate
*/
void furi_hal_serial_init(FuriHalSerialHandle* handle, uint32_t baud);
/** De-initialize Serial
*
* Configures GPIO to analog, clears callback and callback context, disables
* hardware
*
* @param handle Serial handle
*/
void furi_hal_serial_deinit(FuriHalSerialHandle* handle);
/** Suspend operation
*
* Suspend hardware, settings and callbacks are preserved
*
* @param handle Serial handle
*/
void furi_hal_serial_suspend(FuriHalSerialHandle* handle);
/** Resume operation
*
* Resumes hardware from suspended state
*
* @param handle Serial handle
*/
void furi_hal_serial_resume(FuriHalSerialHandle* handle);
/** Changes baud rate
*
* @param handle Serial handle
* @param baud baud rate
*/
void furi_hal_serial_set_br(FuriHalSerialHandle* handle, uint32_t baud);
/** Transmits data in semi-blocking mode
*
* Fills transmission pipe with data, returns as soon as all bytes from buffer
* are in the pipe.
*
* Real transmission will be completed later. Use
* `furi_hal_serial_tx_wait_complete` to wait for completion if you need it.
*
* @param handle Serial handle
* @param buffer data
* @param buffer_size data size (in bytes)
*/
void furi_hal_serial_tx(FuriHalSerialHandle* handle, const uint8_t* buffer, size_t buffer_size);
/** Wait until transmission is completed
*
* Ensures that all data has been sent.
*
* @param handle Serial handle
*/
void furi_hal_serial_tx_wait_complete(FuriHalSerialHandle* handle);
/** Serial RX events */
typedef enum {
FuriHalSerialRxEventData = (1 << 0), /**< Data: new data available */
FuriHalSerialRxEventIdle = (1 << 1), /**< Idle: bus idle detected */
FuriHalSerialRxEventFrameError = (1 << 2), /**< Framing Error: incorrect frame detected */
FuriHalSerialRxEventNoiseError = (1 << 3), /**< Noise Error: noise on the line detected */
FuriHalSerialRxEventOverrunError = (1 << 4), /**< Overrun Error: no space for received data */
} FuriHalSerialRxEvent;
/** Receive callback
*
* @warning Callback will be called in interrupt context, ensure thread
* safety on your side.
* @param handle Serial handle
* @param event FuriHalSerialRxEvent
* @param context Callback context provided earlier
*/
typedef void (*FuriHalSerialAsyncRxCallback)(
FuriHalSerialHandle* handle,
FuriHalSerialRxEvent event,
void* context);
/** Start and sets Serial Receive callback
*
* @warning Callback will be called in interrupt context, ensure thread
* safety on your side
*
* @param handle Serial handle
* @param callback callback pointer
* @param context callback context
* @param[in] report_errors report RX error
*/
void furi_hal_serial_async_rx_start(
FuriHalSerialHandle* handle,
FuriHalSerialAsyncRxCallback callback,
void* context,
bool report_errors);
/** Stop Serial Receive
*
* @param handle Serial handle
*/
void furi_hal_serial_async_rx_stop(FuriHalSerialHandle* handle);
/** Get data Serial receive
*
* @warning This function must be called only from the callback
* FuriHalSerialAsyncRxCallback
*
* @param handle Serial handle
*
* @return data
*/
uint8_t furi_hal_serial_async_rx(FuriHalSerialHandle* handle);
/* DMA based Serial API */
#define FURI_HAL_SERIAL_DMA_BUFFER_SIZE (256u)
/** Receive DMA callback
*
* @warning DMA Callback will be called in interrupt context, ensure thread
* safety on your side.
*
* @param handle Serial handle
* @param event FuriHalSerialDmaRxEvent
* @param data_len Received data
* @param context Callback context provided earlier
*/
typedef void (*FuriHalSerialDmaRxCallback)(
FuriHalSerialHandle* handle,
FuriHalSerialRxEvent event,
size_t data_len,
void* context);
/** Start and sets Serial event callback receive DMA
*
* @param handle Serial handle
* @param callback callback pointer
* @param context callback context
* @param[in] report_errors report RX error
*/
void furi_hal_serial_dma_rx_start(
FuriHalSerialHandle* handle,
FuriHalSerialDmaRxCallback callback,
void* context,
bool report_errors);
/** Stop Serial receive DMA
*
* @param handle Serial handle
*/
void furi_hal_serial_dma_rx_stop(FuriHalSerialHandle* handle);
/** Get data Serial receive DMA
*
* @warning This function must be called only from the callback
* FuriHalSerialDmaRxCallback
*
* @param handle Serial handle
* @param data pointer to data buffer
* @param len get data size (in bytes)
*
* @return size actual data receive (in bytes)
*/
size_t furi_hal_serial_dma_rx(FuriHalSerialHandle* handle, uint8_t* data, size_t len);
#ifdef __cplusplus
}
#endif

View file

@ -0,0 +1,233 @@
#include "furi_hal_serial_control.h"
#include "furi_hal_serial_types_i.h"
#include "furi_hal_serial.h"
#include <furi.h>
#include <toolbox/api_lock.h>
#define TAG "FuriHalSerialControl"
typedef enum {
FuriHalSerialControlMessageTypeStop,
FuriHalSerialControlMessageTypeSuspend,
FuriHalSerialControlMessageTypeResume,
FuriHalSerialControlMessageTypeAcquire,
FuriHalSerialControlMessageTypeRelease,
FuriHalSerialControlMessageTypeLogging,
} FuriHalSerialControlMessageType;
typedef struct {
FuriHalSerialControlMessageType type;
FuriApiLock api_lock;
void* input;
void* output;
} FuriHalSerialControlMessage;
typedef struct {
const FuriHalSerialId id;
const uint32_t baud_rate;
} FuriHalSerialControlMessageInputLogging;
typedef struct {
FuriHalSerialHandle handles[FuriHalSerialIdMax];
FuriMessageQueue* queue;
FuriThread* thread;
// Logging
FuriHalSerialId log_config_serial_id;
uint32_t log_config_serial_baud_rate;
FuriLogHandler log_handler;
FuriHalSerialHandle* log_serial;
} FuriHalSerialControl;
FuriHalSerialControl* furi_hal_serial_control = NULL;
static void furi_hal_serial_control_log_callback(const uint8_t* data, size_t size, void* context) {
FuriHalSerialHandle* handle = context;
furi_hal_serial_tx(handle, data, size);
}
static void furi_hal_serial_control_log_set_handle(FuriHalSerialHandle* handle) {
if(furi_hal_serial_control->log_serial) {
furi_log_remove_handler(furi_hal_serial_control->log_handler);
furi_hal_serial_deinit(furi_hal_serial_control->log_serial);
furi_hal_serial_control->log_serial = NULL;
}
if(handle) {
furi_hal_serial_control->log_serial = handle;
furi_hal_serial_init(
furi_hal_serial_control->log_serial,
furi_hal_serial_control->log_config_serial_baud_rate);
furi_hal_serial_control->log_handler.callback = furi_hal_serial_control_log_callback;
furi_hal_serial_control->log_handler.context = furi_hal_serial_control->log_serial;
furi_log_add_handler(furi_hal_serial_control->log_handler);
}
}
static int32_t furi_hal_serial_control_thread(void* args) {
UNUSED(args);
bool should_continue = true;
while(should_continue || furi_message_queue_get_count(furi_hal_serial_control->queue) > 0) {
FuriHalSerialControlMessage message = {0};
FuriStatus status =
furi_message_queue_get(furi_hal_serial_control->queue, &message, FuriWaitForever);
furi_check(status == FuriStatusOk);
if(message.type == FuriHalSerialControlMessageTypeStop) {
should_continue = false;
} else if(message.type == FuriHalSerialControlMessageTypeSuspend) {
for(size_t i = 0; i < FuriHalSerialIdMax; i++) {
furi_hal_serial_tx_wait_complete(&furi_hal_serial_control->handles[i]);
furi_hal_serial_suspend(&furi_hal_serial_control->handles[i]);
}
api_lock_unlock(message.api_lock);
} else if(message.type == FuriHalSerialControlMessageTypeResume) {
for(size_t i = 0; i < FuriHalSerialIdMax; i++) {
furi_hal_serial_resume(&furi_hal_serial_control->handles[i]);
}
api_lock_unlock(message.api_lock);
} else if(message.type == FuriHalSerialControlMessageTypeAcquire) {
FuriHalSerialId serial_id = *(FuriHalSerialId*)message.input;
if(furi_hal_serial_control->handles[serial_id].in_use) {
*(FuriHalSerialHandle**)message.output = NULL;
} else {
// Logging
if(furi_hal_serial_control->log_config_serial_id == serial_id) {
furi_hal_serial_control_log_set_handle(NULL);
}
// Return handle
furi_hal_serial_control->handles[serial_id].in_use = true;
*(FuriHalSerialHandle**)message.output =
&furi_hal_serial_control->handles[serial_id];
}
api_lock_unlock(message.api_lock);
} else if(message.type == FuriHalSerialControlMessageTypeRelease) {
FuriHalSerialHandle* handle = *(FuriHalSerialHandle**)message.input;
furi_assert(handle->in_use);
furi_hal_serial_deinit(handle);
handle->in_use = false;
// Return back logging
if(furi_hal_serial_control->log_config_serial_id == handle->id) {
furi_hal_serial_control_log_set_handle(handle);
}
api_lock_unlock(message.api_lock);
} else if(message.type == FuriHalSerialControlMessageTypeLogging) {
// Set new configuration
FuriHalSerialControlMessageInputLogging* message_input = message.input;
furi_hal_serial_control->log_config_serial_id = message_input->id;
furi_hal_serial_control->log_config_serial_baud_rate = message_input->baud_rate;
// Apply new configuration
FuriHalSerialHandle* handle = NULL;
if(furi_hal_serial_control->log_config_serial_id < FuriHalSerialIdMax) {
handle = &furi_hal_serial_control
->handles[furi_hal_serial_control->log_config_serial_id];
}
furi_hal_serial_control_log_set_handle(handle);
api_lock_unlock(message.api_lock);
} else {
furi_crash("Invalid parameter");
}
}
return 0;
}
void furi_hal_serial_control_init(void) {
furi_check(furi_hal_serial_control == NULL);
// Allocate resources
furi_hal_serial_control = malloc(sizeof(FuriHalSerialControl));
furi_hal_serial_control->handles[FuriHalSerialIdUsart].id = FuriHalSerialIdUsart;
furi_hal_serial_control->handles[FuriHalSerialIdLpuart].id = FuriHalSerialIdLpuart;
furi_hal_serial_control->queue =
furi_message_queue_alloc(8, sizeof(FuriHalSerialControlMessage));
furi_hal_serial_control->thread =
furi_thread_alloc_ex("SerialControlDriver", 512, furi_hal_serial_control_thread, NULL);
furi_thread_mark_as_service(furi_hal_serial_control->thread);
furi_thread_set_priority(furi_hal_serial_control->thread, FuriThreadPriorityHighest);
furi_hal_serial_control->log_config_serial_id = FuriHalSerialIdMax;
// Start control plane thread
furi_thread_start(furi_hal_serial_control->thread);
}
void furi_hal_serial_control_deinit(void) {
furi_check(furi_hal_serial_control);
// Stop control plane thread
FuriHalSerialControlMessage message;
message.type = FuriHalSerialControlMessageTypeStop;
furi_message_queue_put(furi_hal_serial_control->queue, &message, FuriWaitForever);
furi_thread_join(furi_hal_serial_control->thread);
// Release resources
furi_thread_free(furi_hal_serial_control->thread);
furi_message_queue_free(furi_hal_serial_control->queue);
free(furi_hal_serial_control);
}
void furi_hal_serial_control_suspend(void) {
furi_check(furi_hal_serial_control);
FuriHalSerialControlMessage message;
message.type = FuriHalSerialControlMessageTypeSuspend;
message.api_lock = api_lock_alloc_locked();
furi_message_queue_put(furi_hal_serial_control->queue, &message, FuriWaitForever);
api_lock_wait_unlock_and_free(message.api_lock);
}
void furi_hal_serial_control_resume(void) {
furi_check(furi_hal_serial_control);
FuriHalSerialControlMessage message;
message.type = FuriHalSerialControlMessageTypeResume;
message.api_lock = api_lock_alloc_locked();
furi_message_queue_put(furi_hal_serial_control->queue, &message, FuriWaitForever);
api_lock_wait_unlock_and_free(message.api_lock);
}
FuriHalSerialHandle* furi_hal_serial_control_acquire(FuriHalSerialId serial_id) {
furi_check(furi_hal_serial_control);
FuriHalSerialHandle* output = NULL;
FuriHalSerialControlMessage message;
message.type = FuriHalSerialControlMessageTypeAcquire;
message.api_lock = api_lock_alloc_locked();
message.input = &serial_id;
message.output = &output;
furi_message_queue_put(furi_hal_serial_control->queue, &message, FuriWaitForever);
api_lock_wait_unlock_and_free(message.api_lock);
return output;
}
void furi_hal_serial_control_release(FuriHalSerialHandle* handle) {
furi_check(furi_hal_serial_control);
furi_check(handle);
FuriHalSerialControlMessage message;
message.type = FuriHalSerialControlMessageTypeRelease;
message.api_lock = api_lock_alloc_locked();
message.input = &handle;
furi_message_queue_put(furi_hal_serial_control->queue, &message, FuriWaitForever);
api_lock_wait_unlock_and_free(message.api_lock);
}
void furi_hal_serial_control_set_logging_config(FuriHalSerialId serial_id, uint32_t baud_rate) {
furi_check(serial_id <= FuriHalSerialIdMax);
furi_check(baud_rate >= 9600 && baud_rate <= 4000000);
// Very special case of updater, where RTC initialized before kernel start
if(!furi_hal_serial_control) return;
FuriHalSerialControlMessageInputLogging message_input = {
.id = serial_id,
.baud_rate = baud_rate,
};
FuriHalSerialControlMessage message;
message.type = FuriHalSerialControlMessageTypeLogging;
message.api_lock = api_lock_alloc_locked();
message.input = &message_input;
furi_message_queue_put(furi_hal_serial_control->queue, &message, FuriWaitForever);
api_lock_wait_unlock_and_free(message.api_lock);
}

View file

@ -0,0 +1,46 @@
#pragma once
#include "furi_hal_serial_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/** Initialize Serial Control */
void furi_hal_serial_control_init(void);
/** De-Initialize Serial Control */
void furi_hal_serial_control_deinit(void);
/** Suspend All Serial Interfaces */
void furi_hal_serial_control_suspend(void);
/** Resume All Serial Interfaces */
void furi_hal_serial_control_resume(void);
/** Acquire Serial Interface Handler
*
* @param[in] serial_id The serial transceiver identifier
*
* @return The Serial Interface Handle or null if interfaces is in use
*/
FuriHalSerialHandle* furi_hal_serial_control_acquire(FuriHalSerialId serial_id);
/** Release Serial Interface Handler
*
* @param handle The handle
*/
void furi_hal_serial_control_release(FuriHalSerialHandle* handle);
/** Acquire Serial Interface Handler
*
* @param[in] serial_id The serial transceiver identifier. Use FuriHalSerialIdMax to disable logging.
* @param[in] baud_rate The baud rate
*
* @return The Serial Interface Handle or null if interfaces is in use
*/
void furi_hal_serial_control_set_logging_config(FuriHalSerialId serial_id, uint32_t baud_rate);
#ifdef __cplusplus
}
#endif

View file

@ -0,0 +1,15 @@
#pragma once
#include <furi.h>
/**
* UART channels
*/
typedef enum {
FuriHalSerialIdUsart,
FuriHalSerialIdLpuart,
FuriHalSerialIdMax,
} FuriHalSerialId;
typedef struct FuriHalSerialHandle FuriHalSerialHandle;

View file

@ -0,0 +1,8 @@
#pragma once
#include <furi_hal_serial_types.h>
struct FuriHalSerialHandle {
FuriHalSerialId id;
bool in_use;
};

View file

@ -1,244 +0,0 @@
#include <furi_hal_uart.h>
#include <stdbool.h>
#include <stm32wbxx_ll_lpuart.h>
#include <stm32wbxx_ll_usart.h>
#include <stm32wbxx_ll_rcc.h>
#include <furi_hal_resources.h>
#include <furi_hal_bus.h>
#include <furi.h>
static bool furi_hal_usart_prev_enabled[2];
static void (*irq_cb[2])(uint8_t ev, uint8_t data, void* context);
static void* irq_ctx[2];
static void furi_hal_usart_init(uint32_t baud) {
furi_hal_bus_enable(FuriHalBusUSART1);
LL_RCC_SetUSARTClockSource(LL_RCC_USART1_CLKSOURCE_PCLK2);
furi_hal_gpio_init_ex(
&gpio_usart_tx,
GpioModeAltFunctionPushPull,
GpioPullUp,
GpioSpeedVeryHigh,
GpioAltFn7USART1);
furi_hal_gpio_init_ex(
&gpio_usart_rx,
GpioModeAltFunctionPushPull,
GpioPullUp,
GpioSpeedVeryHigh,
GpioAltFn7USART1);
LL_USART_InitTypeDef USART_InitStruct;
USART_InitStruct.PrescalerValue = LL_USART_PRESCALER_DIV1;
USART_InitStruct.BaudRate = baud;
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_RX;
USART_InitStruct.HardwareFlowControl = LL_USART_HWCONTROL_NONE;
USART_InitStruct.OverSampling = LL_USART_OVERSAMPLING_16;
LL_USART_Init(USART1, &USART_InitStruct);
LL_USART_EnableFIFO(USART1);
LL_USART_ConfigAsyncMode(USART1);
LL_USART_Enable(USART1);
while(!LL_USART_IsActiveFlag_TEACK(USART1) || !LL_USART_IsActiveFlag_REACK(USART1))
;
LL_USART_DisableIT_ERROR(USART1);
NVIC_SetPriority(USART1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 5, 0));
}
static void furi_hal_lpuart_init(uint32_t baud) {
furi_hal_bus_enable(FuriHalBusLPUART1);
LL_RCC_SetLPUARTClockSource(LL_RCC_LPUART1_CLKSOURCE_PCLK1);
furi_hal_gpio_init_ex(
&gpio_ext_pc0,
GpioModeAltFunctionPushPull,
GpioPullUp,
GpioSpeedVeryHigh,
GpioAltFn8LPUART1);
furi_hal_gpio_init_ex(
&gpio_ext_pc1,
GpioModeAltFunctionPushPull,
GpioPullUp,
GpioSpeedVeryHigh,
GpioAltFn8LPUART1);
LL_LPUART_InitTypeDef LPUART_InitStruct;
LPUART_InitStruct.PrescalerValue = LL_LPUART_PRESCALER_DIV1;
LPUART_InitStruct.BaudRate = 115200;
LPUART_InitStruct.DataWidth = LL_LPUART_DATAWIDTH_8B;
LPUART_InitStruct.StopBits = LL_LPUART_STOPBITS_1;
LPUART_InitStruct.Parity = LL_LPUART_PARITY_NONE;
LPUART_InitStruct.TransferDirection = LL_LPUART_DIRECTION_TX_RX;
LPUART_InitStruct.HardwareFlowControl = LL_LPUART_HWCONTROL_NONE;
LL_LPUART_Init(LPUART1, &LPUART_InitStruct);
LL_LPUART_EnableFIFO(LPUART1);
LL_LPUART_Enable(LPUART1);
while(!LL_LPUART_IsActiveFlag_TEACK(LPUART1) || !LL_LPUART_IsActiveFlag_REACK(LPUART1))
;
furi_hal_uart_set_br(FuriHalUartIdLPUART1, baud);
LL_LPUART_DisableIT_ERROR(LPUART1);
NVIC_SetPriority(LPUART1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 5, 0));
}
void furi_hal_uart_init(FuriHalUartId ch, uint32_t baud) {
if(ch == FuriHalUartIdLPUART1) {
furi_hal_lpuart_init(baud);
} else if(ch == FuriHalUartIdUSART1) {
furi_hal_usart_init(baud);
}
}
void furi_hal_uart_set_br(FuriHalUartId ch, uint32_t baud) {
if(ch == FuriHalUartIdUSART1) {
if(LL_USART_IsEnabled(USART1)) {
// Wait for transfer complete flag
while(!LL_USART_IsActiveFlag_TC(USART1))
;
LL_USART_Disable(USART1);
uint32_t uartclk = LL_RCC_GetUSARTClockFreq(LL_RCC_USART1_CLKSOURCE);
LL_USART_SetBaudRate(
USART1, uartclk, LL_USART_PRESCALER_DIV1, LL_USART_OVERSAMPLING_16, baud);
LL_USART_Enable(USART1);
}
} else if(ch == FuriHalUartIdLPUART1) {
if(LL_LPUART_IsEnabled(LPUART1)) {
// Wait for transfer complete flag
while(!LL_LPUART_IsActiveFlag_TC(LPUART1))
;
LL_LPUART_Disable(LPUART1);
uint32_t uartclk = LL_RCC_GetLPUARTClockFreq(LL_RCC_LPUART1_CLKSOURCE);
if(uartclk / baud > 4095) {
LL_LPUART_SetPrescaler(LPUART1, LL_LPUART_PRESCALER_DIV32);
LL_LPUART_SetBaudRate(LPUART1, uartclk, LL_LPUART_PRESCALER_DIV32, baud);
} else {
LL_LPUART_SetPrescaler(LPUART1, LL_LPUART_PRESCALER_DIV1);
LL_LPUART_SetBaudRate(LPUART1, uartclk, LL_LPUART_PRESCALER_DIV1, baud);
}
LL_LPUART_Enable(LPUART1);
}
}
}
void furi_hal_uart_deinit(FuriHalUartId ch) {
furi_hal_uart_set_irq_cb(ch, NULL, NULL);
if(ch == FuriHalUartIdUSART1) {
if(furi_hal_bus_is_enabled(FuriHalBusUSART1)) {
furi_hal_bus_disable(FuriHalBusUSART1);
}
furi_hal_gpio_init(&gpio_usart_tx, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
furi_hal_gpio_init(&gpio_usart_rx, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
} else if(ch == FuriHalUartIdLPUART1) {
if(furi_hal_bus_is_enabled(FuriHalBusLPUART1)) {
furi_hal_bus_disable(FuriHalBusLPUART1);
}
furi_hal_gpio_init(&gpio_ext_pc0, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
furi_hal_gpio_init(&gpio_ext_pc1, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
}
}
void furi_hal_uart_suspend(FuriHalUartId channel) {
if(channel == FuriHalUartIdLPUART1 && LL_LPUART_IsEnabled(LPUART1)) {
LL_LPUART_Disable(LPUART1);
furi_hal_usart_prev_enabled[channel] = true;
} else if(channel == FuriHalUartIdUSART1 && LL_USART_IsEnabled(USART1)) {
LL_USART_Disable(USART1);
furi_hal_usart_prev_enabled[channel] = true;
}
}
void furi_hal_uart_resume(FuriHalUartId channel) {
if(!furi_hal_usart_prev_enabled[channel]) {
return;
} else if(channel == FuriHalUartIdLPUART1) {
LL_LPUART_Enable(LPUART1);
} else if(channel == FuriHalUartIdUSART1) {
LL_USART_Enable(USART1);
}
furi_hal_usart_prev_enabled[channel] = false;
}
void furi_hal_uart_tx(FuriHalUartId ch, uint8_t* buffer, size_t buffer_size) {
if(ch == FuriHalUartIdUSART1) {
if(LL_USART_IsEnabled(USART1) == 0) return;
while(buffer_size > 0) {
while(!LL_USART_IsActiveFlag_TXE(USART1))
;
LL_USART_TransmitData8(USART1, *buffer);
buffer++;
buffer_size--;
}
} else if(ch == FuriHalUartIdLPUART1) {
if(LL_LPUART_IsEnabled(LPUART1) == 0) return;
while(buffer_size > 0) {
while(!LL_LPUART_IsActiveFlag_TXE(LPUART1))
;
LL_LPUART_TransmitData8(LPUART1, *buffer);
buffer++;
buffer_size--;
}
}
}
void furi_hal_uart_set_irq_cb(
FuriHalUartId ch,
void (*cb)(UartIrqEvent ev, uint8_t data, void* ctx),
void* ctx) {
if(cb == NULL) {
if(ch == FuriHalUartIdUSART1) {
NVIC_DisableIRQ(USART1_IRQn);
LL_USART_DisableIT_RXNE_RXFNE(USART1);
} else if(ch == FuriHalUartIdLPUART1) {
NVIC_DisableIRQ(LPUART1_IRQn);
LL_LPUART_DisableIT_RXNE_RXFNE(LPUART1);
}
irq_cb[ch] = cb;
irq_ctx[ch] = ctx;
} else {
irq_ctx[ch] = ctx;
irq_cb[ch] = cb;
if(ch == FuriHalUartIdUSART1) {
NVIC_EnableIRQ(USART1_IRQn);
LL_USART_EnableIT_RXNE_RXFNE(USART1);
} else if(ch == FuriHalUartIdLPUART1) {
NVIC_EnableIRQ(LPUART1_IRQn);
LL_LPUART_EnableIT_RXNE_RXFNE(LPUART1);
}
}
}
void LPUART1_IRQHandler(void) {
if(LL_LPUART_IsActiveFlag_RXNE_RXFNE(LPUART1)) {
uint8_t data = LL_LPUART_ReceiveData8(LPUART1);
irq_cb[FuriHalUartIdLPUART1](UartIrqEventRXNE, data, irq_ctx[FuriHalUartIdLPUART1]);
} else if(LL_LPUART_IsActiveFlag_ORE(LPUART1)) {
LL_LPUART_ClearFlag_ORE(LPUART1);
}
}
void USART1_IRQHandler(void) {
if(LL_USART_IsActiveFlag_RXNE_RXFNE(USART1)) {
uint8_t data = LL_USART_ReceiveData8(USART1);
irq_cb[FuriHalUartIdUSART1](UartIrqEventRXNE, data, irq_ctx[FuriHalUartIdUSART1]);
} else if(LL_USART_IsActiveFlag_ORE(USART1)) {
LL_USART_ClearFlag_ORE(USART1);
}
}

View file

@ -1,89 +0,0 @@
/**
* @file furi_hal_uart.h
* @version 1.0
* @date 2021-11-19
*
* UART HAL api interface
*/
#pragma once
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* UART channels
*/
typedef enum {
FuriHalUartIdUSART1,
FuriHalUartIdLPUART1,
} FuriHalUartId;
/**
* UART events
*/
typedef enum {
UartIrqEventRXNE,
} UartIrqEvent;
/**
* Init UART
* Configures GPIO to UART function, сonfigures UART hardware, enables UART hardware
* @param channel UART channel
* @param baud baudrate
*/
void furi_hal_uart_init(FuriHalUartId channel, uint32_t baud);
/**
* Deinit UART
* Configures GPIO to analog, clears callback and callback context, disables UART hardware
* @param channel UART channel
*/
void furi_hal_uart_deinit(FuriHalUartId channel);
/**
* Suspend UART operation
* Disables UART hardware, settings and callbacks are preserved
* @param channel UART channel
*/
void furi_hal_uart_suspend(FuriHalUartId channel);
/**
* Resume UART operation
* Resumes UART hardware from suspended state
* @param channel UART channel
*/
void furi_hal_uart_resume(FuriHalUartId channel);
/**
* Changes UART baudrate
* @param channel UART channel
* @param baud baudrate
*/
void furi_hal_uart_set_br(FuriHalUartId channel, uint32_t baud);
/**
* Transmits data
* @param channel UART channel
* @param buffer data
* @param buffer_size data size (in bytes)
*/
void furi_hal_uart_tx(FuriHalUartId channel, uint8_t* buffer, size_t buffer_size);
/**
* Sets UART event callback
* @param channel UART channel
* @param callback callback pointer
* @param context callback context
*/
void furi_hal_uart_set_irq_cb(
FuriHalUartId channel,
void (*callback)(UartIrqEvent event, uint8_t data, void* context),
void* context);
#ifdef __cplusplus
}
#endif

View file

@ -14,7 +14,6 @@ struct STOP_EXTERNING_ME {};
#include <furi_hal_clock.h>
#include <furi_hal_bus.h>
#include <furi_hal_crypto.h>
#include <furi_hal_console.h>
#include <furi_hal_debug.h>
#include <furi_hal_dma.h>
#include <furi_hal_os.h>
@ -36,7 +35,8 @@ struct STOP_EXTERNING_ME {};
#include <furi_hal_usb.h>
#include <furi_hal_usb_hid.h>
#include <furi_hal_usb_ccid.h>
#include <furi_hal_uart.h>
#include <furi_hal_serial_control.h>
#include <furi_hal_serial.h>
#include <furi_hal_info.h>
#include <furi_hal_random.h>
#include <furi_hal_target_hw.h>