 fc043da9c6
			
		
	
	
		fc043da9c6
		
			
		
	
	
	
	
		
			
			* 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>
		
			
				
	
	
		
			234 lines
		
	
	
		
			9.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			234 lines
		
	
	
		
			9.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #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);
 | |
| }
 |