UART echo app (#831)
* HAL: add context to UART IRQ's * Apps: uart echo/log application * Sync api * Another api sync
This commit is contained in:
		
							parent
							
								
									4303945748
								
							
						
					
					
						commit
						013ed64cbb
					
				| @ -20,6 +20,7 @@ extern int32_t desktop_srv(void* p); | |||||||
| extern int32_t accessor_app(void* p); | extern int32_t accessor_app(void* p); | ||||||
| extern int32_t archive_app(void* p); | extern int32_t archive_app(void* p); | ||||||
| extern int32_t bad_usb_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 blink_test_app(void* p); | ||||||
| extern int32_t bt_debug_app(void* p); | extern int32_t bt_debug_app(void* p); | ||||||
| extern int32_t delay_test_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}, |     {.app = bad_usb_app, .name = "Bad USB test", .stack_size = 2048, .icon = NULL}, | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | #ifdef APP_UART_ECHO | ||||||
|  |     {.app = uart_echo_app, .name = "Uart Echo", .stack_size = 2048, .icon = NULL}, | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| #ifdef APP_IRDA_MONITOR | #ifdef APP_IRDA_MONITOR | ||||||
|     {.app = irda_monitor_app, .name = "Irda Monitor", .stack_size = 1024, .icon = NULL}, |     {.app = irda_monitor_app, .name = "Irda Monitor", .stack_size = 1024, .icon = NULL}, | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -48,6 +48,7 @@ APP_DISPLAY_TEST = 1 | |||||||
| 
 | 
 | ||||||
| APP_USB_MOUSE = 1 | APP_USB_MOUSE = 1 | ||||||
| APP_BAD_USB = 1 | APP_BAD_USB = 1 | ||||||
|  | APP_UART_ECHO = 1 | ||||||
| endif | endif | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @ -132,6 +133,11 @@ CFLAGS		+= -DAPP_USB_TEST | |||||||
| SRV_GUI = 1 | SRV_GUI = 1 | ||||||
| endif | endif | ||||||
| 
 | 
 | ||||||
|  | APP_UART_ECHO ?= 0 | ||||||
|  | ifeq ($(APP_UART_ECHO), 1) | ||||||
|  | CFLAGS		+= -DAPP_UART_ECHO | ||||||
|  | SRV_GUI = 1 | ||||||
|  | endif | ||||||
| 
 | 
 | ||||||
| APP_DISPLAY_TEST ?= 0 | APP_DISPLAY_TEST ?= 0 | ||||||
| ifeq ($(APP_DISPLAY_TEST), 1) | ifeq ($(APP_DISPLAY_TEST), 1) | ||||||
|  | |||||||
							
								
								
									
										268
									
								
								applications/debug_tools/uart_echo.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										268
									
								
								applications/debug_tools/uart_echo.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,268 @@ | |||||||
|  | #include <furi.h> | ||||||
|  | #include <m-string.h> | ||||||
|  | #include <gui/gui.h> | ||||||
|  | #include <notification/notification.h> | ||||||
|  | #include <notification/notification-messages.h> | ||||||
|  | #include <gui/elements.h> | ||||||
|  | #include <stream_buffer.h> | ||||||
|  | #include <furi-hal-uart.h> | ||||||
|  | #include <furi-hal-console.h> | ||||||
|  | #include <gui/view_dispatcher.h> | ||||||
|  | #include <gui/modules/dialog_ex.h> | ||||||
|  | 
 | ||||||
|  | #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; | ||||||
|  | } | ||||||
| @ -57,7 +57,7 @@ static CdcCallbacks cdc_cb = { | |||||||
| 
 | 
 | ||||||
| static int32_t usb_uart_tx_thread(void* context); | 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; |     BaseType_t xHigherPriorityTaskWoken = pdFALSE; | ||||||
| 
 | 
 | ||||||
|     if(ev == UartIrqEventRXNE) { |     if(ev == UartIrqEventRXNE) { | ||||||
| @ -94,10 +94,10 @@ static int32_t usb_uart_worker(void* context) { | |||||||
|         furi_hal_console_disable(); |         furi_hal_console_disable(); | ||||||
|     } else if(usb_uart->cfg.uart_ch == FuriHalUartIdLPUART1) { |     } else if(usb_uart->cfg.uart_ch == FuriHalUartIdLPUART1) { | ||||||
|         furi_hal_uart_init(usb_uart->cfg.uart_ch, 115200); |         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) |     if(usb_uart->cfg.baudrate != 0) | ||||||
|         furi_hal_uart_set_br(usb_uart->cfg.uart_ch, usb_uart->cfg.baudrate); |         furi_hal_uart_set_br(usb_uart->cfg.uart_ch, usb_uart->cfg.baudrate); | ||||||
|     else |     else | ||||||
|  | |||||||
| @ -24,7 +24,7 @@ void furi_hal_console_init() { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void furi_hal_console_enable() { | 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)); |     while (!LL_USART_IsActiveFlag_TC(USART1)); | ||||||
|     furi_hal_uart_set_br(FuriHalUartIdUSART1, CONSOLE_BAUDRATE); |     furi_hal_uart_set_br(FuriHalUartIdUSART1, CONSOLE_BAUDRATE); | ||||||
|     furi_hal_console_alive = true; |     furi_hal_console_alive = true; | ||||||
|  | |||||||
| @ -6,7 +6,8 @@ | |||||||
| 
 | 
 | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
| 
 | 
 | ||||||
| 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) { | static void furi_hal_usart_init(uint32_t baud) { | ||||||
|     hal_gpio_init_ex( |     hal_gpio_init_ex( | ||||||
| @ -38,7 +39,8 @@ static void furi_hal_usart_init(uint32_t baud) { | |||||||
| 
 | 
 | ||||||
|     LL_USART_Enable(USART1); |     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_RXNE_RXFNE(USART1); | ||||||
|     LL_USART_EnableIT_IDLE(USART1); |     LL_USART_EnableIT_IDLE(USART1); | ||||||
| @ -74,7 +76,8 @@ static void furi_hal_lpuart_init(uint32_t baud) { | |||||||
| 
 | 
 | ||||||
|     LL_LPUART_Enable(LPUART1); |     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); |     furi_hal_uart_set_br(FuriHalUartIdLPUART1, baud); | ||||||
| 
 | 
 | ||||||
| @ -94,16 +97,19 @@ void furi_hal_uart_set_br(FuriHalUartId ch, uint32_t baud) { | |||||||
|     if(ch == FuriHalUartIdUSART1) { |     if(ch == FuriHalUartIdUSART1) { | ||||||
|         if(LL_USART_IsEnabled(USART1)) { |         if(LL_USART_IsEnabled(USART1)) { | ||||||
|             // Wait for transfer complete flag
 |             // Wait for transfer complete flag
 | ||||||
|             while (!LL_USART_IsActiveFlag_TC(USART1)); |             while(!LL_USART_IsActiveFlag_TC(USART1)) | ||||||
|  |                 ; | ||||||
|             LL_USART_Disable(USART1); |             LL_USART_Disable(USART1); | ||||||
|             uint32_t uartclk = LL_RCC_GetUSARTClockFreq(LL_RCC_USART1_CLKSOURCE); |             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); |             LL_USART_Enable(USART1); | ||||||
|         } |         } | ||||||
|     } else if(ch == FuriHalUartIdLPUART1) { |     } else if(ch == FuriHalUartIdLPUART1) { | ||||||
|         if(LL_LPUART_IsEnabled(LPUART1)) { |         if(LL_LPUART_IsEnabled(LPUART1)) { | ||||||
|             // Wait for transfer complete flag
 |             // Wait for transfer complete flag
 | ||||||
|             while (!LL_LPUART_IsActiveFlag_TC(LPUART1)); |             while(!LL_LPUART_IsActiveFlag_TC(LPUART1)) | ||||||
|  |                 ; | ||||||
|             LL_LPUART_Disable(LPUART1); |             LL_LPUART_Disable(LPUART1); | ||||||
|             uint32_t uartclk = LL_RCC_GetLPUARTClockFreq(LL_RCC_LPUART1_CLKSOURCE); |             uint32_t uartclk = LL_RCC_GetLPUARTClockFreq(LL_RCC_LPUART1_CLKSOURCE); | ||||||
|             if(uartclk / baud > 4095) { |             if(uartclk / baud > 4095) { | ||||||
| @ -119,7 +125,7 @@ void furi_hal_uart_set_br(FuriHalUartId ch, uint32_t baud) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void furi_hal_uart_deinit(FuriHalUartId ch) { | void furi_hal_uart_deinit(FuriHalUartId ch) { | ||||||
|     furi_hal_uart_set_irq_cb(ch, NULL); |     furi_hal_uart_set_irq_cb(ch, NULL, NULL); | ||||||
|     if(ch == FuriHalUartIdUSART1) { |     if(ch == FuriHalUartIdUSART1) { | ||||||
|         LL_USART_Disable(USART1); |         LL_USART_Disable(USART1); | ||||||
|         hal_gpio_init(&gpio_usart_tx, GpioModeAnalog, GpioPullNo, GpioSpeedLow); |         hal_gpio_init(&gpio_usart_tx, GpioModeAnalog, GpioPullNo, GpioSpeedLow); | ||||||
| @ -133,11 +139,11 @@ void furi_hal_uart_deinit(FuriHalUartId ch) { | |||||||
| 
 | 
 | ||||||
| void furi_hal_uart_tx(FuriHalUartId ch, uint8_t* buffer, size_t buffer_size) { | void furi_hal_uart_tx(FuriHalUartId ch, uint8_t* buffer, size_t buffer_size) { | ||||||
|     if(ch == FuriHalUartIdUSART1) { |     if(ch == FuriHalUartIdUSART1) { | ||||||
|         if (LL_USART_IsEnabled(USART1) == 0) |         if(LL_USART_IsEnabled(USART1) == 0) return; | ||||||
|             return; |  | ||||||
| 
 | 
 | ||||||
|         while(buffer_size > 0) { |         while(buffer_size > 0) { | ||||||
|             while (!LL_USART_IsActiveFlag_TXE(USART1)); |             while(!LL_USART_IsActiveFlag_TXE(USART1)) | ||||||
|  |                 ; | ||||||
| 
 | 
 | ||||||
|             LL_USART_TransmitData8(USART1, *buffer); |             LL_USART_TransmitData8(USART1, *buffer); | ||||||
|             buffer++; |             buffer++; | ||||||
| @ -145,11 +151,11 @@ void furi_hal_uart_tx(FuriHalUartId ch, uint8_t* buffer, size_t buffer_size) { | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|     } else if(ch == FuriHalUartIdLPUART1) { |     } else if(ch == FuriHalUartIdLPUART1) { | ||||||
|         if (LL_LPUART_IsEnabled(LPUART1) == 0) |         if(LL_LPUART_IsEnabled(LPUART1) == 0) return; | ||||||
|             return; |  | ||||||
| 
 | 
 | ||||||
|         while(buffer_size > 0) { |         while(buffer_size > 0) { | ||||||
|             while (!LL_LPUART_IsActiveFlag_TXE(LPUART1)); |             while(!LL_LPUART_IsActiveFlag_TXE(LPUART1)) | ||||||
|  |                 ; | ||||||
| 
 | 
 | ||||||
|             LL_LPUART_TransmitData8(LPUART1, *buffer); |             LL_LPUART_TransmitData8(LPUART1, *buffer); | ||||||
| 
 | 
 | ||||||
| @ -159,14 +165,19 @@ void furi_hal_uart_tx(FuriHalUartId ch, uint8_t* buffer, size_t buffer_size) { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void furi_hal_uart_set_irq_cb(FuriHalUartId ch, void (*cb)(UartIrqEvent ev, uint8_t data)) { | void furi_hal_uart_set_irq_cb( | ||||||
|  |     FuriHalUartId ch, | ||||||
|  |     void (*cb)(UartIrqEvent ev, uint8_t data, void* ctx), | ||||||
|  |     void* ctx) { | ||||||
|     if(cb == NULL) { |     if(cb == NULL) { | ||||||
|         if(ch == FuriHalUartIdUSART1) |         if(ch == FuriHalUartIdUSART1) | ||||||
|             NVIC_DisableIRQ(USART1_IRQn); |             NVIC_DisableIRQ(USART1_IRQn); | ||||||
|         else if(ch == FuriHalUartIdLPUART1) |         else if(ch == FuriHalUartIdLPUART1) | ||||||
|             NVIC_DisableIRQ(LPUART1_IRQn); |             NVIC_DisableIRQ(LPUART1_IRQn); | ||||||
|         irq_cb[ch] = cb; |         irq_cb[ch] = cb; | ||||||
|  |         irq_ctx[ch] = ctx; | ||||||
|     } else { |     } else { | ||||||
|  |         irq_ctx[ch] = ctx; | ||||||
|         irq_cb[ch] = cb; |         irq_cb[ch] = cb; | ||||||
|         if(ch == FuriHalUartIdUSART1) |         if(ch == FuriHalUartIdUSART1) | ||||||
|             NVIC_EnableIRQ(USART1_IRQn); |             NVIC_EnableIRQ(USART1_IRQn); | ||||||
| @ -178,9 +189,9 @@ void furi_hal_uart_set_irq_cb(FuriHalUartId ch, void (*cb)(UartIrqEvent ev, uint | |||||||
| void LPUART1_IRQHandler(void) { | 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); |         uint8_t data = LL_LPUART_ReceiveData8(LPUART1); | ||||||
|         irq_cb[FuriHalUartIdLPUART1](UartIrqEventRXNE, data); |         irq_cb[FuriHalUartIdLPUART1](UartIrqEventRXNE, data, irq_ctx[FuriHalUartIdLPUART1]); | ||||||
|     } else if(LL_LPUART_IsActiveFlag_IDLE(LPUART1)) { |     } else if(LL_LPUART_IsActiveFlag_IDLE(LPUART1)) { | ||||||
|         irq_cb[FuriHalUartIdLPUART1](UartIrqEventIDLE, 0); |         irq_cb[FuriHalUartIdLPUART1](UartIrqEventIDLE, 0, irq_ctx[FuriHalUartIdLPUART1]); | ||||||
|         LL_LPUART_ClearFlag_IDLE(LPUART1); |         LL_LPUART_ClearFlag_IDLE(LPUART1); | ||||||
|     } else if(LL_LPUART_IsActiveFlag_ORE(LPUART1)) { |     } else if(LL_LPUART_IsActiveFlag_ORE(LPUART1)) { | ||||||
|         LL_LPUART_ClearFlag_ORE(LPUART1); |         LL_LPUART_ClearFlag_ORE(LPUART1); | ||||||
| @ -191,9 +202,9 @@ void LPUART1_IRQHandler(void) { | |||||||
| void USART1_IRQHandler(void) { | 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); |         uint8_t data = LL_USART_ReceiveData8(USART1); | ||||||
|         irq_cb[FuriHalUartIdUSART1](UartIrqEventRXNE, data); |         irq_cb[FuriHalUartIdUSART1](UartIrqEventRXNE, data, irq_ctx[FuriHalUartIdUSART1]); | ||||||
|     } else if(LL_USART_IsActiveFlag_IDLE(USART1)) { |     } else if(LL_USART_IsActiveFlag_IDLE(USART1)) { | ||||||
|         irq_cb[FuriHalUartIdUSART1](UartIrqEventIDLE, 0); |         irq_cb[FuriHalUartIdUSART1](UartIrqEventIDLE, 0, irq_ctx[FuriHalUartIdUSART1]); | ||||||
|         LL_USART_ClearFlag_IDLE(USART1); |         LL_USART_ClearFlag_IDLE(USART1); | ||||||
|     } else if(LL_USART_IsActiveFlag_ORE(USART1)) { |     } else if(LL_USART_IsActiveFlag_ORE(USART1)) { | ||||||
|         LL_USART_ClearFlag_ORE(USART1); |         LL_USART_ClearFlag_ORE(USART1); | ||||||
|  | |||||||
| @ -1,3 +1,10 @@ | |||||||
|  | /**
 | ||||||
|  |  * @file furi-hal-uart.h | ||||||
|  |  * @version 1.0 | ||||||
|  |  * @date 2021-11-19 | ||||||
|  |  *  | ||||||
|  |  * UART HAL api interface | ||||||
|  |  */ | ||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| #include <stddef.h> | #include <stddef.h> | ||||||
| @ -7,26 +14,63 @@ | |||||||
| extern "C" { | extern "C" { | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * UART channels | ||||||
|  |  */ | ||||||
| typedef enum { | typedef enum { | ||||||
|     FuriHalUartIdUSART1, |     FuriHalUartIdUSART1, | ||||||
|     FuriHalUartIdLPUART1, |     FuriHalUartIdLPUART1, | ||||||
| } FuriHalUartId; | } FuriHalUartId; | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * UART events | ||||||
|  |  */ | ||||||
| typedef enum { | typedef enum { | ||||||
|     UartIrqEventRXNE, |     UartIrqEventRXNE, | ||||||
|     UartIrqEventIDLE, |     UartIrqEventIDLE, | ||||||
|     //TODO: more events
 |     //TODO: more events
 | ||||||
| } UartIrqEvent; | } 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 | #ifdef __cplusplus | ||||||
| } | } | ||||||
|  | |||||||
| @ -24,32 +24,33 @@ void furi_hal_console_init() { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void furi_hal_console_enable() { | 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)); |     while(!LL_USART_IsActiveFlag_TC(USART1)) | ||||||
|  |         ; | ||||||
|     furi_hal_uart_set_br(FuriHalUartIdUSART1, CONSOLE_BAUDRATE); |     furi_hal_uart_set_br(FuriHalUartIdUSART1, CONSOLE_BAUDRATE); | ||||||
|     furi_hal_console_alive = true; |     furi_hal_console_alive = true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void furi_hal_console_disable() { | void furi_hal_console_disable() { | ||||||
|     while (!LL_USART_IsActiveFlag_TC(USART1)); |     while(!LL_USART_IsActiveFlag_TC(USART1)) | ||||||
|  |         ; | ||||||
|     furi_hal_console_alive = false; |     furi_hal_console_alive = false; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void furi_hal_console_tx(const uint8_t* buffer, size_t buffer_size) { | void furi_hal_console_tx(const uint8_t* buffer, size_t buffer_size) { | ||||||
|     if (!furi_hal_console_alive) |     if(!furi_hal_console_alive) return; | ||||||
|         return; |  | ||||||
| 
 | 
 | ||||||
|     UTILS_ENTER_CRITICAL_SECTION(); |     UTILS_ENTER_CRITICAL_SECTION(); | ||||||
|     // Transmit data
 |     // Transmit data
 | ||||||
|     furi_hal_uart_tx(FuriHalUartIdUSART1, (uint8_t*)buffer, buffer_size); |     furi_hal_uart_tx(FuriHalUartIdUSART1, (uint8_t*)buffer, buffer_size); | ||||||
|     // Wait for TC flag to be raised for last char
 |     // 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(); |     UTILS_EXIT_CRITICAL_SECTION(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void furi_hal_console_tx_with_new_line(const uint8_t* buffer, size_t buffer_size) { | void furi_hal_console_tx_with_new_line(const uint8_t* buffer, size_t buffer_size) { | ||||||
|     if (!furi_hal_console_alive) |     if(!furi_hal_console_alive) return; | ||||||
|         return; |  | ||||||
| 
 | 
 | ||||||
|     UTILS_ENTER_CRITICAL_SECTION(); |     UTILS_ENTER_CRITICAL_SECTION(); | ||||||
|     // Transmit data
 |     // 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
 |     // Transmit new line symbols
 | ||||||
|     furi_hal_uart_tx(FuriHalUartIdUSART1, (uint8_t*)"\r\n", 2); |     furi_hal_uart_tx(FuriHalUartIdUSART1, (uint8_t*)"\r\n", 2); | ||||||
|     // Wait for TC flag to be raised for last char
 |     // 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(); |     UTILS_EXIT_CRITICAL_SECTION(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -6,7 +6,8 @@ | |||||||
| 
 | 
 | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
| 
 | 
 | ||||||
| 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) { | static void furi_hal_usart_init(uint32_t baud) { | ||||||
|     hal_gpio_init_ex( |     hal_gpio_init_ex( | ||||||
| @ -38,7 +39,8 @@ static void furi_hal_usart_init(uint32_t baud) { | |||||||
| 
 | 
 | ||||||
|     LL_USART_Enable(USART1); |     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_RXNE_RXFNE(USART1); | ||||||
|     LL_USART_EnableIT_IDLE(USART1); |     LL_USART_EnableIT_IDLE(USART1); | ||||||
| @ -74,7 +76,8 @@ static void furi_hal_lpuart_init(uint32_t baud) { | |||||||
| 
 | 
 | ||||||
|     LL_LPUART_Enable(LPUART1); |     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); |     furi_hal_uart_set_br(FuriHalUartIdLPUART1, baud); | ||||||
| 
 | 
 | ||||||
| @ -94,16 +97,19 @@ void furi_hal_uart_set_br(FuriHalUartId ch, uint32_t baud) { | |||||||
|     if(ch == FuriHalUartIdUSART1) { |     if(ch == FuriHalUartIdUSART1) { | ||||||
|         if(LL_USART_IsEnabled(USART1)) { |         if(LL_USART_IsEnabled(USART1)) { | ||||||
|             // Wait for transfer complete flag
 |             // Wait for transfer complete flag
 | ||||||
|             while (!LL_USART_IsActiveFlag_TC(USART1)); |             while(!LL_USART_IsActiveFlag_TC(USART1)) | ||||||
|  |                 ; | ||||||
|             LL_USART_Disable(USART1); |             LL_USART_Disable(USART1); | ||||||
|             uint32_t uartclk = LL_RCC_GetUSARTClockFreq(LL_RCC_USART1_CLKSOURCE); |             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); |             LL_USART_Enable(USART1); | ||||||
|         } |         } | ||||||
|     } else if(ch == FuriHalUartIdLPUART1) { |     } else if(ch == FuriHalUartIdLPUART1) { | ||||||
|         if(LL_LPUART_IsEnabled(LPUART1)) { |         if(LL_LPUART_IsEnabled(LPUART1)) { | ||||||
|             // Wait for transfer complete flag
 |             // Wait for transfer complete flag
 | ||||||
|             while (!LL_LPUART_IsActiveFlag_TC(LPUART1)); |             while(!LL_LPUART_IsActiveFlag_TC(LPUART1)) | ||||||
|  |                 ; | ||||||
|             LL_LPUART_Disable(LPUART1); |             LL_LPUART_Disable(LPUART1); | ||||||
|             uint32_t uartclk = LL_RCC_GetLPUARTClockFreq(LL_RCC_LPUART1_CLKSOURCE); |             uint32_t uartclk = LL_RCC_GetLPUARTClockFreq(LL_RCC_LPUART1_CLKSOURCE); | ||||||
|             if(uartclk / baud > 4095) { |             if(uartclk / baud > 4095) { | ||||||
| @ -119,7 +125,7 @@ void furi_hal_uart_set_br(FuriHalUartId ch, uint32_t baud) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void furi_hal_uart_deinit(FuriHalUartId ch) { | void furi_hal_uart_deinit(FuriHalUartId ch) { | ||||||
|     furi_hal_uart_set_irq_cb(ch, NULL); |     furi_hal_uart_set_irq_cb(ch, NULL, NULL); | ||||||
|     if(ch == FuriHalUartIdUSART1) { |     if(ch == FuriHalUartIdUSART1) { | ||||||
|         LL_USART_Disable(USART1); |         LL_USART_Disable(USART1); | ||||||
|         hal_gpio_init(&gpio_usart_tx, GpioModeAnalog, GpioPullNo, GpioSpeedLow); |         hal_gpio_init(&gpio_usart_tx, GpioModeAnalog, GpioPullNo, GpioSpeedLow); | ||||||
| @ -133,11 +139,11 @@ void furi_hal_uart_deinit(FuriHalUartId ch) { | |||||||
| 
 | 
 | ||||||
| void furi_hal_uart_tx(FuriHalUartId ch, uint8_t* buffer, size_t buffer_size) { | void furi_hal_uart_tx(FuriHalUartId ch, uint8_t* buffer, size_t buffer_size) { | ||||||
|     if(ch == FuriHalUartIdUSART1) { |     if(ch == FuriHalUartIdUSART1) { | ||||||
|         if (LL_USART_IsEnabled(USART1) == 0) |         if(LL_USART_IsEnabled(USART1) == 0) return; | ||||||
|             return; |  | ||||||
| 
 | 
 | ||||||
|         while(buffer_size > 0) { |         while(buffer_size > 0) { | ||||||
|             while (!LL_USART_IsActiveFlag_TXE(USART1)); |             while(!LL_USART_IsActiveFlag_TXE(USART1)) | ||||||
|  |                 ; | ||||||
| 
 | 
 | ||||||
|             LL_USART_TransmitData8(USART1, *buffer); |             LL_USART_TransmitData8(USART1, *buffer); | ||||||
|             buffer++; |             buffer++; | ||||||
| @ -145,11 +151,11 @@ void furi_hal_uart_tx(FuriHalUartId ch, uint8_t* buffer, size_t buffer_size) { | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|     } else if(ch == FuriHalUartIdLPUART1) { |     } else if(ch == FuriHalUartIdLPUART1) { | ||||||
|         if (LL_LPUART_IsEnabled(LPUART1) == 0) |         if(LL_LPUART_IsEnabled(LPUART1) == 0) return; | ||||||
|             return; |  | ||||||
| 
 | 
 | ||||||
|         while(buffer_size > 0) { |         while(buffer_size > 0) { | ||||||
|             while (!LL_LPUART_IsActiveFlag_TXE(LPUART1)); |             while(!LL_LPUART_IsActiveFlag_TXE(LPUART1)) | ||||||
|  |                 ; | ||||||
| 
 | 
 | ||||||
|             LL_LPUART_TransmitData8(LPUART1, *buffer); |             LL_LPUART_TransmitData8(LPUART1, *buffer); | ||||||
| 
 | 
 | ||||||
| @ -159,14 +165,19 @@ void furi_hal_uart_tx(FuriHalUartId ch, uint8_t* buffer, size_t buffer_size) { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void furi_hal_uart_set_irq_cb(FuriHalUartId ch, void (*cb)(UartIrqEvent ev, uint8_t data)) { | void furi_hal_uart_set_irq_cb( | ||||||
|  |     FuriHalUartId ch, | ||||||
|  |     void (*cb)(UartIrqEvent ev, uint8_t data, void* ctx), | ||||||
|  |     void* ctx) { | ||||||
|     if(cb == NULL) { |     if(cb == NULL) { | ||||||
|         if(ch == FuriHalUartIdUSART1) |         if(ch == FuriHalUartIdUSART1) | ||||||
|             NVIC_DisableIRQ(USART1_IRQn); |             NVIC_DisableIRQ(USART1_IRQn); | ||||||
|         else if(ch == FuriHalUartIdLPUART1) |         else if(ch == FuriHalUartIdLPUART1) | ||||||
|             NVIC_DisableIRQ(LPUART1_IRQn); |             NVIC_DisableIRQ(LPUART1_IRQn); | ||||||
|         irq_cb[ch] = cb; |         irq_cb[ch] = cb; | ||||||
|  |         irq_ctx[ch] = ctx; | ||||||
|     } else { |     } else { | ||||||
|  |         irq_ctx[ch] = ctx; | ||||||
|         irq_cb[ch] = cb; |         irq_cb[ch] = cb; | ||||||
|         if(ch == FuriHalUartIdUSART1) |         if(ch == FuriHalUartIdUSART1) | ||||||
|             NVIC_EnableIRQ(USART1_IRQn); |             NVIC_EnableIRQ(USART1_IRQn); | ||||||
| @ -178,9 +189,9 @@ void furi_hal_uart_set_irq_cb(FuriHalUartId ch, void (*cb)(UartIrqEvent ev, uint | |||||||
| void LPUART1_IRQHandler(void) { | 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); |         uint8_t data = LL_LPUART_ReceiveData8(LPUART1); | ||||||
|         irq_cb[FuriHalUartIdLPUART1](UartIrqEventRXNE, data); |         irq_cb[FuriHalUartIdLPUART1](UartIrqEventRXNE, data, irq_ctx[FuriHalUartIdLPUART1]); | ||||||
|     } else if(LL_LPUART_IsActiveFlag_IDLE(LPUART1)) { |     } else if(LL_LPUART_IsActiveFlag_IDLE(LPUART1)) { | ||||||
|         irq_cb[FuriHalUartIdLPUART1](UartIrqEventIDLE, 0); |         irq_cb[FuriHalUartIdLPUART1](UartIrqEventIDLE, 0, irq_ctx[FuriHalUartIdLPUART1]); | ||||||
|         LL_LPUART_ClearFlag_IDLE(LPUART1); |         LL_LPUART_ClearFlag_IDLE(LPUART1); | ||||||
|     } else if(LL_LPUART_IsActiveFlag_ORE(LPUART1)) { |     } else if(LL_LPUART_IsActiveFlag_ORE(LPUART1)) { | ||||||
|         LL_LPUART_ClearFlag_ORE(LPUART1); |         LL_LPUART_ClearFlag_ORE(LPUART1); | ||||||
| @ -191,9 +202,9 @@ void LPUART1_IRQHandler(void) { | |||||||
| void USART1_IRQHandler(void) { | 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); |         uint8_t data = LL_USART_ReceiveData8(USART1); | ||||||
|         irq_cb[FuriHalUartIdUSART1](UartIrqEventRXNE, data); |         irq_cb[FuriHalUartIdUSART1](UartIrqEventRXNE, data, irq_ctx[FuriHalUartIdUSART1]); | ||||||
|     } else if(LL_USART_IsActiveFlag_IDLE(USART1)) { |     } else if(LL_USART_IsActiveFlag_IDLE(USART1)) { | ||||||
|         irq_cb[FuriHalUartIdUSART1](UartIrqEventIDLE, 0); |         irq_cb[FuriHalUartIdUSART1](UartIrqEventIDLE, 0, irq_ctx[FuriHalUartIdUSART1]); | ||||||
|         LL_USART_ClearFlag_IDLE(USART1); |         LL_USART_ClearFlag_IDLE(USART1); | ||||||
|     } else if(LL_USART_IsActiveFlag_ORE(USART1)) { |     } else if(LL_USART_IsActiveFlag_ORE(USART1)) { | ||||||
|         LL_USART_ClearFlag_ORE(USART1); |         LL_USART_ClearFlag_ORE(USART1); | ||||||
|  | |||||||
| @ -1,3 +1,10 @@ | |||||||
|  | /**
 | ||||||
|  |  * @file furi-hal-uart.h | ||||||
|  |  * @version 1.0 | ||||||
|  |  * @date 2021-11-19 | ||||||
|  |  *  | ||||||
|  |  * UART HAL api interface | ||||||
|  |  */ | ||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| #include <stddef.h> | #include <stddef.h> | ||||||
| @ -7,26 +14,63 @@ | |||||||
| extern "C" { | extern "C" { | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * UART channels | ||||||
|  |  */ | ||||||
| typedef enum { | typedef enum { | ||||||
|     FuriHalUartIdUSART1, |     FuriHalUartIdUSART1, | ||||||
|     FuriHalUartIdLPUART1, |     FuriHalUartIdLPUART1, | ||||||
| } FuriHalUartId; | } FuriHalUartId; | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * UART events | ||||||
|  |  */ | ||||||
| typedef enum { | typedef enum { | ||||||
|     UartIrqEventRXNE, |     UartIrqEventRXNE, | ||||||
|     UartIrqEventIDLE, |     UartIrqEventIDLE, | ||||||
|     //TODO: more events
 |     //TODO: more events
 | ||||||
| } UartIrqEvent; | } 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 | #ifdef __cplusplus | ||||||
| } | } | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 SG
						SG