From 013ed64cbbb6ba0a97958a7e7e96bfc667bda176 Mon Sep 17 00:00:00 2001 From: SG Date: Sat, 20 Nov 2021 08:19:31 +1000 Subject: [PATCH] UART echo app (#831) * HAL: add context to UART IRQ's * Apps: uart echo/log application * Sync api * Another api sync --- applications/applications.c | 5 + applications/applications.mk | 6 + applications/debug_tools/uart_echo.c | 268 ++++++++++++++++++ applications/gpio/usb_uart_bridge.c | 6 +- .../targets/f6/furi-hal/furi-hal-console.c | 2 +- firmware/targets/f6/furi-hal/furi-hal-uart.c | 93 +++--- firmware/targets/f6/furi-hal/furi-hal-uart.h | 54 +++- .../targets/f7/furi-hal/furi-hal-console.c | 22 +- firmware/targets/f7/furi-hal/furi-hal-uart.c | 93 +++--- firmware/targets/f7/furi-hal/furi-hal-uart.h | 56 +++- 10 files changed, 498 insertions(+), 107 deletions(-) create mode 100644 applications/debug_tools/uart_echo.c diff --git a/applications/applications.c b/applications/applications.c index 7cc105bb..fe58e56a 100644 --- a/applications/applications.c +++ b/applications/applications.c @@ -20,6 +20,7 @@ extern int32_t desktop_srv(void* p); extern int32_t accessor_app(void* p); extern int32_t archive_app(void* p); extern int32_t bad_usb_app(void* p); +extern int32_t uart_echo_app(void* p); extern int32_t blink_test_app(void* p); extern int32_t bt_debug_app(void* p); extern int32_t delay_test_app(void* p); @@ -236,6 +237,10 @@ const FlipperApplication FLIPPER_DEBUG_APPS[] = { {.app = bad_usb_app, .name = "Bad USB test", .stack_size = 2048, .icon = NULL}, #endif +#ifdef APP_UART_ECHO + {.app = uart_echo_app, .name = "Uart Echo", .stack_size = 2048, .icon = NULL}, +#endif + #ifdef APP_IRDA_MONITOR {.app = irda_monitor_app, .name = "Irda Monitor", .stack_size = 1024, .icon = NULL}, #endif diff --git a/applications/applications.mk b/applications/applications.mk index 4f0a5a67..9f87c6c3 100644 --- a/applications/applications.mk +++ b/applications/applications.mk @@ -48,6 +48,7 @@ APP_DISPLAY_TEST = 1 APP_USB_MOUSE = 1 APP_BAD_USB = 1 +APP_UART_ECHO = 1 endif @@ -132,6 +133,11 @@ CFLAGS += -DAPP_USB_TEST SRV_GUI = 1 endif +APP_UART_ECHO ?= 0 +ifeq ($(APP_UART_ECHO), 1) +CFLAGS += -DAPP_UART_ECHO +SRV_GUI = 1 +endif APP_DISPLAY_TEST ?= 0 ifeq ($(APP_DISPLAY_TEST), 1) diff --git a/applications/debug_tools/uart_echo.c b/applications/debug_tools/uart_echo.c new file mode 100644 index 00000000..feff06e7 --- /dev/null +++ b/applications/debug_tools/uart_echo.c @@ -0,0 +1,268 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LINES_ON_SCREEN 6 +#define COLUMNS_ON_SCREEN 21 + +typedef struct UartDumpModel UartDumpModel; + +typedef struct { + Gui* gui; + NotificationApp* notification; + ViewDispatcher* view_dispatcher; + View* view; + FuriThread* worker_thread; + StreamBufferHandle_t rx_stream; +} UartEchoApp; + +typedef struct { + string_t text; +} ListElement; + +struct UartDumpModel { + ListElement* list[LINES_ON_SCREEN]; + uint8_t line; + + char last_char; + bool escape; +}; + +typedef enum { + WorkerEventReserved = (1 << 0), // Reserved for StreamBuffer internal event + WorkerEventStop = (1 << 1), + WorkerEventRx = (1 << 2), +} WorkerEventFlags; + +#define WORKER_EVENTS_MASK (WorkerEventStop | WorkerEventRx) + +const NotificationSequence sequence_notification = { + &message_display_on, + &message_green_255, + &message_delay_10, + NULL, +}; + +static void uart_echo_view_draw_callback(Canvas* canvas, void* _model) { + UartDumpModel* model = _model; + + // Prepare canvas + canvas_clear(canvas); + canvas_set_color(canvas, ColorBlack); + canvas_set_font(canvas, FontKeyboard); + + for(size_t i = 0; i < LINES_ON_SCREEN; i++) { + canvas_draw_str( + canvas, + 0, + (i + 1) * (canvas_current_font_height(canvas) - 1), + string_get_cstr(model->list[i]->text)); + + if(i == model->line) { + uint8_t width = canvas_string_width(canvas, string_get_cstr(model->list[i]->text)); + + canvas_draw_box( + canvas, + width, + (i) * (canvas_current_font_height(canvas) - 1) + 2, + 2, + canvas_current_font_height(canvas) - 2); + } + } +} + +static bool uart_echo_view_input_callback(InputEvent* event, void* context) { + bool consumed = false; + return consumed; +} + +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) { + furi_assert(context); + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + UartEchoApp* app = context; + + if(ev == UartIrqEventRXNE) { + xStreamBufferSendFromISR(app->rx_stream, &data, 1, &xHigherPriorityTaskWoken); + osThreadFlagsSet(furi_thread_get_thread_id(app->worker_thread), WorkerEventRx); + portYIELD_FROM_ISR(xHigherPriorityTaskWoken); + } +} + +static void uart_echo_push_to_list(UartDumpModel* model, const char data) { + if(model->escape) { + // escape code end with letter + if((data >= 'a' && data <= 'z') || (data >= 'A' && data <= 'Z')) { + model->escape = false; + } + } else if(data == '[' && model->last_char == '\e') { + // "Esc[" is a escape code + model->escape = true; + } else if((data >= ' ' && data <= '~') || (data == '\n' || data == '\r')) { + bool new_string_needed = false; + if(string_size(model->list[model->line]->text) >= COLUMNS_ON_SCREEN) { + new_string_needed = true; + } else if((data == '\n' || data == '\r')) { + // pack line breaks + if(model->last_char != '\n' && model->last_char != '\r') { + new_string_needed = true; + } + } + + if(new_string_needed) { + if((model->line + 1) < LINES_ON_SCREEN) { + model->line += 1; + } else { + ListElement* first = model->list[0]; + + for(size_t i = 1; i < LINES_ON_SCREEN; i++) { + model->list[i - 1] = model->list[i]; + } + + string_reset(first->text); + model->list[model->line] = first; + } + } + + if(data != '\n' && data != '\r') { + string_push_back(model->list[model->line]->text, data); + } + } + model->last_char = data; +} + +static int32_t uart_echo_worker(void* context) { + furi_assert(context); + UartEchoApp* app = context; + + while(1) { + uint32_t events = osThreadFlagsWait(WORKER_EVENTS_MASK, osFlagsWaitAny, osWaitForever); + furi_check((events & osFlagsError) == 0); + + if(events & WorkerEventStop) break; + if(events & WorkerEventRx) { + size_t length = 0; + do { + uint8_t data[64]; + length = xStreamBufferReceive(app->rx_stream, data, 64, 0); + if(length > 0) { + furi_hal_uart_tx(FuriHalUartIdUSART1, data, length); + with_view_model( + app->view, (UartDumpModel * model) { + for(size_t i = 0; i < length; i++) { + uart_echo_push_to_list(model, data[i]); + } + return false; + }); + } + } while(length > 0); + + notification_message(app->notification, &sequence_notification); + with_view_model( + app->view, (UartDumpModel * model) { return true; }); + } + } + + return 0; +} + +static UartEchoApp* uart_echo_app_alloc() { + UartEchoApp* app = furi_alloc(sizeof(UartEchoApp)); + + app->rx_stream = xStreamBufferCreate(2048, 1); + + // Gui + app->gui = furi_record_open("gui"); + app->notification = furi_record_open("notification"); + + // View dispatcher + app->view_dispatcher = view_dispatcher_alloc(); + view_dispatcher_enable_queue(app->view_dispatcher); + view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); + + // Views + app->view = view_alloc(); + view_set_draw_callback(app->view, uart_echo_view_draw_callback); + view_set_input_callback(app->view, uart_echo_view_input_callback); + view_allocate_model(app->view, ViewModelTypeLocking, sizeof(UartDumpModel)); + with_view_model( + app->view, (UartDumpModel * model) { + for(size_t i = 0; i < LINES_ON_SCREEN; i++) { + model->line = 0; + model->escape = false; + model->list[i] = furi_alloc(sizeof(ListElement)); + string_init(model->list[i]->text); + } + return true; + }); + + view_set_previous_callback(app->view, uart_echo_exit); + view_dispatcher_add_view(app->view_dispatcher, 0, app->view); + view_dispatcher_switch_to_view(app->view_dispatcher, 0); + + // Enable uart listener + furi_hal_console_disable(); + furi_hal_uart_set_br(FuriHalUartIdUSART1, 115200); + furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, uart_echo_on_irq_cb, app); + + app->worker_thread = furi_thread_alloc(); + furi_thread_set_name(app->worker_thread, "UsbUartWorker"); + furi_thread_set_stack_size(app->worker_thread, 1024); + furi_thread_set_context(app->worker_thread, app); + furi_thread_set_callback(app->worker_thread, uart_echo_worker); + furi_thread_start(app->worker_thread); + + return app; +} + +static void uart_echo_app_free(UartEchoApp* app) { + furi_assert(app); + + osThreadFlagsSet(furi_thread_get_thread_id(app->worker_thread), WorkerEventStop); + furi_thread_join(app->worker_thread); + furi_thread_free(app->worker_thread); + + furi_hal_console_enable(); + + // Free views + view_dispatcher_remove_view(app->view_dispatcher, 0); + + with_view_model( + app->view, (UartDumpModel * model) { + for(size_t i = 0; i < LINES_ON_SCREEN; i++) { + string_clear(model->list[i]->text); + free(model->list[i]); + } + return true; + }); + view_free(app->view); + view_dispatcher_free(app->view_dispatcher); + + // Close gui record + furi_record_close("gui"); + furi_record_close("notification"); + app->gui = NULL; + + vStreamBufferDelete(app->rx_stream); + + // Free rest + free(app); +} + +int32_t uart_echo_app(void* p) { + UartEchoApp* app = uart_echo_app_alloc(); + view_dispatcher_run(app->view_dispatcher); + uart_echo_app_free(app); + return 0; +} \ No newline at end of file diff --git a/applications/gpio/usb_uart_bridge.c b/applications/gpio/usb_uart_bridge.c index 9b43f643..99fe62eb 100644 --- a/applications/gpio/usb_uart_bridge.c +++ b/applications/gpio/usb_uart_bridge.c @@ -57,7 +57,7 @@ static CdcCallbacks cdc_cb = { static int32_t usb_uart_tx_thread(void* context); -static void usb_uart_on_irq_cb(UartIrqEvent ev, uint8_t data) { +static void usb_uart_on_irq_cb(UartIrqEvent ev, uint8_t data, void* context) { BaseType_t xHigherPriorityTaskWoken = pdFALSE; if(ev == UartIrqEventRXNE) { @@ -94,10 +94,10 @@ static int32_t usb_uart_worker(void* context) { furi_hal_console_disable(); } else if(usb_uart->cfg.uart_ch == FuriHalUartIdLPUART1) { furi_hal_uart_init(usb_uart->cfg.uart_ch, 115200); - furi_hal_uart_set_irq_cb(usb_uart->cfg.uart_ch, usb_uart_on_irq_cb); + furi_hal_uart_set_irq_cb(usb_uart->cfg.uart_ch, usb_uart_on_irq_cb, NULL); } - furi_hal_uart_set_irq_cb(usb_uart->cfg.uart_ch, usb_uart_on_irq_cb); + furi_hal_uart_set_irq_cb(usb_uart->cfg.uart_ch, usb_uart_on_irq_cb, NULL); if(usb_uart->cfg.baudrate != 0) furi_hal_uart_set_br(usb_uart->cfg.uart_ch, usb_uart->cfg.baudrate); else diff --git a/firmware/targets/f6/furi-hal/furi-hal-console.c b/firmware/targets/f6/furi-hal/furi-hal-console.c index 993b498e..a0b0083b 100644 --- a/firmware/targets/f6/furi-hal/furi-hal-console.c +++ b/firmware/targets/f6/furi-hal/furi-hal-console.c @@ -24,7 +24,7 @@ void furi_hal_console_init() { } void furi_hal_console_enable() { - furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, NULL); + 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; diff --git a/firmware/targets/f6/furi-hal/furi-hal-uart.c b/firmware/targets/f6/furi-hal/furi-hal-uart.c index ff5a056b..92942a91 100644 --- a/firmware/targets/f6/furi-hal/furi-hal-uart.c +++ b/firmware/targets/f6/furi-hal/furi-hal-uart.c @@ -6,7 +6,8 @@ #include -static void (*irq_cb[2])(uint8_t ev, uint8_t data); +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) { hal_gpio_init_ex( @@ -38,7 +39,8 @@ static void furi_hal_usart_init(uint32_t baud) { LL_USART_Enable(USART1); - while(!LL_USART_IsActiveFlag_TEACK(USART1)); + while(!LL_USART_IsActiveFlag_TEACK(USART1)) + ; LL_USART_EnableIT_RXNE_RXFNE(USART1); LL_USART_EnableIT_IDLE(USART1); @@ -74,7 +76,8 @@ static void furi_hal_lpuart_init(uint32_t baud) { LL_LPUART_Enable(LPUART1); - while((!(LL_LPUART_IsActiveFlag_TEACK(LPUART1))) || (!(LL_LPUART_IsActiveFlag_REACK(LPUART1)))); + while((!(LL_LPUART_IsActiveFlag_TEACK(LPUART1))) || (!(LL_LPUART_IsActiveFlag_REACK(LPUART1)))) + ; furi_hal_uart_set_br(FuriHalUartIdLPUART1, baud); @@ -84,29 +87,32 @@ static void furi_hal_lpuart_init(uint32_t baud) { } void furi_hal_uart_init(FuriHalUartId ch, uint32_t baud) { - if (ch == FuriHalUartIdLPUART1) + if(ch == FuriHalUartIdLPUART1) furi_hal_lpuart_init(baud); - else if (ch == FuriHalUartIdUSART1) + 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)) { + if(ch == FuriHalUartIdUSART1) { + if(LL_USART_IsEnabled(USART1)) { // Wait for transfer complete flag - while (!LL_USART_IsActiveFlag_TC(USART1)); + 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_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)) { + } else if(ch == FuriHalUartIdLPUART1) { + if(LL_LPUART_IsEnabled(LPUART1)) { // Wait for transfer complete flag - while (!LL_LPUART_IsActiveFlag_TC(LPUART1)); + while(!LL_LPUART_IsActiveFlag_TC(LPUART1)) + ; LL_LPUART_Disable(LPUART1); uint32_t uartclk = LL_RCC_GetLPUARTClockFreq(LL_RCC_LPUART1_CLKSOURCE); - if (uartclk/baud > 4095) { + if(uartclk / baud > 4095) { LL_LPUART_SetPrescaler(LPUART1, LL_LPUART_PRESCALER_DIV32); LL_LPUART_SetBaudRate(LPUART1, uartclk, LL_LPUART_PRESCALER_DIV32, baud); } else { @@ -119,12 +125,12 @@ void furi_hal_uart_set_br(FuriHalUartId ch, uint32_t baud) { } void furi_hal_uart_deinit(FuriHalUartId ch) { - furi_hal_uart_set_irq_cb(ch, NULL); - if (ch == FuriHalUartIdUSART1) { + furi_hal_uart_set_irq_cb(ch, NULL, NULL); + if(ch == FuriHalUartIdUSART1) { LL_USART_Disable(USART1); hal_gpio_init(&gpio_usart_tx, GpioModeAnalog, GpioPullNo, GpioSpeedLow); hal_gpio_init(&gpio_usart_rx, GpioModeAnalog, GpioPullNo, GpioSpeedLow); - } else if (ch == FuriHalUartIdLPUART1) { + } else if(ch == FuriHalUartIdLPUART1) { LL_LPUART_Disable(LPUART1); hal_gpio_init(&gpio_ext_pc0, GpioModeAnalog, GpioPullNo, GpioSpeedLow); hal_gpio_init(&gpio_ext_pc1, GpioModeAnalog, GpioPullNo, GpioSpeedLow); @@ -132,70 +138,75 @@ void furi_hal_uart_deinit(FuriHalUartId ch) { } void furi_hal_uart_tx(FuriHalUartId ch, uint8_t* buffer, size_t buffer_size) { - if (ch == FuriHalUartIdUSART1) { - if (LL_USART_IsEnabled(USART1) == 0) - return; + if(ch == FuriHalUartIdUSART1) { + if(LL_USART_IsEnabled(USART1) == 0) return; while(buffer_size > 0) { - while (!LL_USART_IsActiveFlag_TXE(USART1)); + 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; + } else if(ch == FuriHalUartIdLPUART1) { + if(LL_LPUART_IsEnabled(LPUART1) == 0) return; while(buffer_size > 0) { - while (!LL_LPUART_IsActiveFlag_TXE(LPUART1)); + 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)) { - if (cb == NULL) { - if (ch == FuriHalUartIdUSART1) +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); - else if (ch == FuriHalUartIdLPUART1) + else if(ch == FuriHalUartIdLPUART1) NVIC_DisableIRQ(LPUART1_IRQn); irq_cb[ch] = cb; + irq_ctx[ch] = ctx; } else { + irq_ctx[ch] = ctx; irq_cb[ch] = cb; - if (ch == FuriHalUartIdUSART1) + if(ch == FuriHalUartIdUSART1) NVIC_EnableIRQ(USART1_IRQn); - else if (ch == FuriHalUartIdLPUART1) + else if(ch == FuriHalUartIdLPUART1) NVIC_EnableIRQ(LPUART1_IRQn); } } void LPUART1_IRQHandler(void) { - if (LL_LPUART_IsActiveFlag_RXNE_RXFNE(LPUART1)) { + if(LL_LPUART_IsActiveFlag_RXNE_RXFNE(LPUART1)) { uint8_t data = LL_LPUART_ReceiveData8(LPUART1); - irq_cb[FuriHalUartIdLPUART1](UartIrqEventRXNE, data); - } else if (LL_LPUART_IsActiveFlag_IDLE(LPUART1)) { - irq_cb[FuriHalUartIdLPUART1](UartIrqEventIDLE, 0); + irq_cb[FuriHalUartIdLPUART1](UartIrqEventRXNE, data, irq_ctx[FuriHalUartIdLPUART1]); + } else if(LL_LPUART_IsActiveFlag_IDLE(LPUART1)) { + irq_cb[FuriHalUartIdLPUART1](UartIrqEventIDLE, 0, irq_ctx[FuriHalUartIdLPUART1]); LL_LPUART_ClearFlag_IDLE(LPUART1); - } else if (LL_LPUART_IsActiveFlag_ORE(LPUART1)) { + } else if(LL_LPUART_IsActiveFlag_ORE(LPUART1)) { LL_LPUART_ClearFlag_ORE(LPUART1); } //TODO: more events } void USART1_IRQHandler(void) { - if (LL_USART_IsActiveFlag_RXNE_RXFNE(USART1)) { + if(LL_USART_IsActiveFlag_RXNE_RXFNE(USART1)) { uint8_t data = LL_USART_ReceiveData8(USART1); - irq_cb[FuriHalUartIdUSART1](UartIrqEventRXNE, data); - } else if (LL_USART_IsActiveFlag_IDLE(USART1)) { - irq_cb[FuriHalUartIdUSART1](UartIrqEventIDLE, 0); + irq_cb[FuriHalUartIdUSART1](UartIrqEventRXNE, data, irq_ctx[FuriHalUartIdUSART1]); + } else if(LL_USART_IsActiveFlag_IDLE(USART1)) { + irq_cb[FuriHalUartIdUSART1](UartIrqEventIDLE, 0, irq_ctx[FuriHalUartIdUSART1]); LL_USART_ClearFlag_IDLE(USART1); - } else if (LL_USART_IsActiveFlag_ORE(USART1)) { + } else if(LL_USART_IsActiveFlag_ORE(USART1)) { LL_USART_ClearFlag_ORE(USART1); } } diff --git a/firmware/targets/f6/furi-hal/furi-hal-uart.h b/firmware/targets/f6/furi-hal/furi-hal-uart.h index 731a12a2..f245c484 100644 --- a/firmware/targets/f6/furi-hal/furi-hal-uart.h +++ b/firmware/targets/f6/furi-hal/furi-hal-uart.h @@ -1,3 +1,10 @@ +/** + * @file furi-hal-uart.h + * @version 1.0 + * @date 2021-11-19 + * + * UART HAL api interface + */ #pragma once #include @@ -7,26 +14,63 @@ extern "C" { #endif +/** + * UART channels + */ typedef enum { FuriHalUartIdUSART1, FuriHalUartIdLPUART1, } FuriHalUartId; +/** + * UART events + */ typedef enum { UartIrqEventRXNE, UartIrqEventIDLE, //TODO: more events } UartIrqEvent; -void furi_hal_uart_init(FuriHalUartId ch, uint32_t baud); +/** + * 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); -void furi_hal_uart_deinit(FuriHalUartId ch); +/** + * 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); -void furi_hal_uart_set_br(FuriHalUartId ch, uint32_t baud); +/** + * Changes UART baudrate + * @param channel UART channel + * @param baud baudrate + */ +void furi_hal_uart_set_br(FuriHalUartId channel, uint32_t baud); -void furi_hal_uart_tx(FuriHalUartId ch, uint8_t* buffer, size_t buffer_size); +/** + * 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); -void furi_hal_uart_set_irq_cb(FuriHalUartId ch, void (*cb)(UartIrqEvent ev, uint8_t data)); +/** + * 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 } diff --git a/firmware/targets/f7/furi-hal/furi-hal-console.c b/firmware/targets/f7/furi-hal/furi-hal-console.c index 993b498e..66ff40ee 100644 --- a/firmware/targets/f7/furi-hal/furi-hal-console.c +++ b/firmware/targets/f7/furi-hal/furi-hal-console.c @@ -24,32 +24,33 @@ void furi_hal_console_init() { } void furi_hal_console_enable() { - furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, NULL); - while (!LL_USART_IsActiveFlag_TC(USART1)); + 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)); + while(!LL_USART_IsActiveFlag_TC(USART1)) + ; furi_hal_console_alive = false; } void furi_hal_console_tx(const uint8_t* buffer, size_t buffer_size) { - if (!furi_hal_console_alive) - return; + if(!furi_hal_console_alive) return; UTILS_ENTER_CRITICAL_SECTION(); // Transmit data 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)); + while(!LL_USART_IsActiveFlag_TC(USART1)) + ; UTILS_EXIT_CRITICAL_SECTION(); } void furi_hal_console_tx_with_new_line(const uint8_t* buffer, size_t buffer_size) { - if (!furi_hal_console_alive) - return; + if(!furi_hal_console_alive) return; UTILS_ENTER_CRITICAL_SECTION(); // Transmit data @@ -57,7 +58,8 @@ void furi_hal_console_tx_with_new_line(const uint8_t* buffer, size_t 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)); + while(!LL_USART_IsActiveFlag_TC(USART1)) + ; UTILS_EXIT_CRITICAL_SECTION(); } @@ -71,6 +73,6 @@ void furi_hal_console_printf(const char format[], ...) { string_clear(string); } -void furi_hal_console_puts(const char *data) { +void furi_hal_console_puts(const char* data) { furi_hal_console_tx((const uint8_t*)data, strlen(data)); } diff --git a/firmware/targets/f7/furi-hal/furi-hal-uart.c b/firmware/targets/f7/furi-hal/furi-hal-uart.c index ff5a056b..92942a91 100644 --- a/firmware/targets/f7/furi-hal/furi-hal-uart.c +++ b/firmware/targets/f7/furi-hal/furi-hal-uart.c @@ -6,7 +6,8 @@ #include -static void (*irq_cb[2])(uint8_t ev, uint8_t data); +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) { hal_gpio_init_ex( @@ -38,7 +39,8 @@ static void furi_hal_usart_init(uint32_t baud) { LL_USART_Enable(USART1); - while(!LL_USART_IsActiveFlag_TEACK(USART1)); + while(!LL_USART_IsActiveFlag_TEACK(USART1)) + ; LL_USART_EnableIT_RXNE_RXFNE(USART1); LL_USART_EnableIT_IDLE(USART1); @@ -74,7 +76,8 @@ static void furi_hal_lpuart_init(uint32_t baud) { LL_LPUART_Enable(LPUART1); - while((!(LL_LPUART_IsActiveFlag_TEACK(LPUART1))) || (!(LL_LPUART_IsActiveFlag_REACK(LPUART1)))); + while((!(LL_LPUART_IsActiveFlag_TEACK(LPUART1))) || (!(LL_LPUART_IsActiveFlag_REACK(LPUART1)))) + ; furi_hal_uart_set_br(FuriHalUartIdLPUART1, baud); @@ -84,29 +87,32 @@ static void furi_hal_lpuart_init(uint32_t baud) { } void furi_hal_uart_init(FuriHalUartId ch, uint32_t baud) { - if (ch == FuriHalUartIdLPUART1) + if(ch == FuriHalUartIdLPUART1) furi_hal_lpuart_init(baud); - else if (ch == FuriHalUartIdUSART1) + 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)) { + if(ch == FuriHalUartIdUSART1) { + if(LL_USART_IsEnabled(USART1)) { // Wait for transfer complete flag - while (!LL_USART_IsActiveFlag_TC(USART1)); + 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_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)) { + } else if(ch == FuriHalUartIdLPUART1) { + if(LL_LPUART_IsEnabled(LPUART1)) { // Wait for transfer complete flag - while (!LL_LPUART_IsActiveFlag_TC(LPUART1)); + while(!LL_LPUART_IsActiveFlag_TC(LPUART1)) + ; LL_LPUART_Disable(LPUART1); uint32_t uartclk = LL_RCC_GetLPUARTClockFreq(LL_RCC_LPUART1_CLKSOURCE); - if (uartclk/baud > 4095) { + if(uartclk / baud > 4095) { LL_LPUART_SetPrescaler(LPUART1, LL_LPUART_PRESCALER_DIV32); LL_LPUART_SetBaudRate(LPUART1, uartclk, LL_LPUART_PRESCALER_DIV32, baud); } else { @@ -119,12 +125,12 @@ void furi_hal_uart_set_br(FuriHalUartId ch, uint32_t baud) { } void furi_hal_uart_deinit(FuriHalUartId ch) { - furi_hal_uart_set_irq_cb(ch, NULL); - if (ch == FuriHalUartIdUSART1) { + furi_hal_uart_set_irq_cb(ch, NULL, NULL); + if(ch == FuriHalUartIdUSART1) { LL_USART_Disable(USART1); hal_gpio_init(&gpio_usart_tx, GpioModeAnalog, GpioPullNo, GpioSpeedLow); hal_gpio_init(&gpio_usart_rx, GpioModeAnalog, GpioPullNo, GpioSpeedLow); - } else if (ch == FuriHalUartIdLPUART1) { + } else if(ch == FuriHalUartIdLPUART1) { LL_LPUART_Disable(LPUART1); hal_gpio_init(&gpio_ext_pc0, GpioModeAnalog, GpioPullNo, GpioSpeedLow); hal_gpio_init(&gpio_ext_pc1, GpioModeAnalog, GpioPullNo, GpioSpeedLow); @@ -132,70 +138,75 @@ void furi_hal_uart_deinit(FuriHalUartId ch) { } void furi_hal_uart_tx(FuriHalUartId ch, uint8_t* buffer, size_t buffer_size) { - if (ch == FuriHalUartIdUSART1) { - if (LL_USART_IsEnabled(USART1) == 0) - return; + if(ch == FuriHalUartIdUSART1) { + if(LL_USART_IsEnabled(USART1) == 0) return; while(buffer_size > 0) { - while (!LL_USART_IsActiveFlag_TXE(USART1)); + 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; + } else if(ch == FuriHalUartIdLPUART1) { + if(LL_LPUART_IsEnabled(LPUART1) == 0) return; while(buffer_size > 0) { - while (!LL_LPUART_IsActiveFlag_TXE(LPUART1)); + 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)) { - if (cb == NULL) { - if (ch == FuriHalUartIdUSART1) +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); - else if (ch == FuriHalUartIdLPUART1) + else if(ch == FuriHalUartIdLPUART1) NVIC_DisableIRQ(LPUART1_IRQn); irq_cb[ch] = cb; + irq_ctx[ch] = ctx; } else { + irq_ctx[ch] = ctx; irq_cb[ch] = cb; - if (ch == FuriHalUartIdUSART1) + if(ch == FuriHalUartIdUSART1) NVIC_EnableIRQ(USART1_IRQn); - else if (ch == FuriHalUartIdLPUART1) + else if(ch == FuriHalUartIdLPUART1) NVIC_EnableIRQ(LPUART1_IRQn); } } void LPUART1_IRQHandler(void) { - if (LL_LPUART_IsActiveFlag_RXNE_RXFNE(LPUART1)) { + if(LL_LPUART_IsActiveFlag_RXNE_RXFNE(LPUART1)) { uint8_t data = LL_LPUART_ReceiveData8(LPUART1); - irq_cb[FuriHalUartIdLPUART1](UartIrqEventRXNE, data); - } else if (LL_LPUART_IsActiveFlag_IDLE(LPUART1)) { - irq_cb[FuriHalUartIdLPUART1](UartIrqEventIDLE, 0); + irq_cb[FuriHalUartIdLPUART1](UartIrqEventRXNE, data, irq_ctx[FuriHalUartIdLPUART1]); + } else if(LL_LPUART_IsActiveFlag_IDLE(LPUART1)) { + irq_cb[FuriHalUartIdLPUART1](UartIrqEventIDLE, 0, irq_ctx[FuriHalUartIdLPUART1]); LL_LPUART_ClearFlag_IDLE(LPUART1); - } else if (LL_LPUART_IsActiveFlag_ORE(LPUART1)) { + } else if(LL_LPUART_IsActiveFlag_ORE(LPUART1)) { LL_LPUART_ClearFlag_ORE(LPUART1); } //TODO: more events } void USART1_IRQHandler(void) { - if (LL_USART_IsActiveFlag_RXNE_RXFNE(USART1)) { + if(LL_USART_IsActiveFlag_RXNE_RXFNE(USART1)) { uint8_t data = LL_USART_ReceiveData8(USART1); - irq_cb[FuriHalUartIdUSART1](UartIrqEventRXNE, data); - } else if (LL_USART_IsActiveFlag_IDLE(USART1)) { - irq_cb[FuriHalUartIdUSART1](UartIrqEventIDLE, 0); + irq_cb[FuriHalUartIdUSART1](UartIrqEventRXNE, data, irq_ctx[FuriHalUartIdUSART1]); + } else if(LL_USART_IsActiveFlag_IDLE(USART1)) { + irq_cb[FuriHalUartIdUSART1](UartIrqEventIDLE, 0, irq_ctx[FuriHalUartIdUSART1]); LL_USART_ClearFlag_IDLE(USART1); - } else if (LL_USART_IsActiveFlag_ORE(USART1)) { + } else if(LL_USART_IsActiveFlag_ORE(USART1)) { LL_USART_ClearFlag_ORE(USART1); } } diff --git a/firmware/targets/f7/furi-hal/furi-hal-uart.h b/firmware/targets/f7/furi-hal/furi-hal-uart.h index 731a12a2..53a45f1e 100644 --- a/firmware/targets/f7/furi-hal/furi-hal-uart.h +++ b/firmware/targets/f7/furi-hal/furi-hal-uart.h @@ -1,3 +1,10 @@ +/** + * @file furi-hal-uart.h + * @version 1.0 + * @date 2021-11-19 + * + * UART HAL api interface + */ #pragma once #include @@ -7,27 +14,64 @@ extern "C" { #endif +/** + * UART channels + */ typedef enum { FuriHalUartIdUSART1, FuriHalUartIdLPUART1, } FuriHalUartId; +/** + * UART events + */ typedef enum { UartIrqEventRXNE, UartIrqEventIDLE, //TODO: more events } UartIrqEvent; -void furi_hal_uart_init(FuriHalUartId ch, uint32_t baud); +/** + * 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); -void furi_hal_uart_deinit(FuriHalUartId ch); +/** + * 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); -void furi_hal_uart_set_br(FuriHalUartId ch, uint32_t baud); +/** + * Changes UART baudrate + * @param channel UART channel + * @param baud baudrate + */ +void furi_hal_uart_set_br(FuriHalUartId channel, uint32_t baud); -void furi_hal_uart_tx(FuriHalUartId ch, uint8_t* buffer, size_t buffer_size); +/** + * 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); -void furi_hal_uart_set_irq_cb(FuriHalUartId ch, void (*cb)(UartIrqEvent ev, uint8_t data)); +/** + * 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 +#endif \ No newline at end of file