[FL-3764] Expansion module service improvements (#3429)

* Separate expansion control and worker threads
* Add edge case checks
* Reduce expansion control thread stack size, add comments
* Fix crash when disabling expansion modules
* Show a different RPC icon for expansion modules
* Restore expansion interrupt on changing logging settings
* Improve responsiveness in heavy games at the expense of dropped frames
* Improve furi_hal_serial API
* Fix a typo
* Remove too optimistic furi_check, replace with condition
* Fix premature RX interrupt during serial configuration
* Disable expansion interrupt if the handle was acquired
* Do not use a timer callback

Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
This commit is contained in:
Georgii Surkov
2024-02-12 05:16:34 +03:00
committed by GitHub
parent 14dabf523a
commit 6836a7b7c5
12 changed files with 793 additions and 416 deletions

View File

@@ -730,6 +730,13 @@ static void furi_hal_serial_async_rx_configure(
FuriHalSerialHandle* handle,
FuriHalSerialAsyncRxCallback callback,
void* context) {
// Handle must be configured before enabling RX interrupt
// as it might be triggered right away on a misconfigured handle
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;
if(handle->id == FuriHalSerialIdUsart) {
if(callback) {
furi_hal_serial_usart_deinit_dma_rx();
@@ -753,10 +760,6 @@ static void furi_hal_serial_async_rx_configure(
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(
@@ -782,6 +785,17 @@ void furi_hal_serial_async_rx_stop(FuriHalSerialHandle* handle) {
furi_hal_serial_async_rx_configure(handle, NULL, NULL);
}
bool furi_hal_serial_async_rx_available(FuriHalSerialHandle* handle) {
furi_check(FURI_IS_IRQ_MODE());
furi_assert(handle->id < FuriHalSerialIdMax);
if(handle->id == FuriHalSerialIdUsart) {
return LL_USART_IsActiveFlag_RXNE_RXFNE(USART1);
} else {
return LL_LPUART_IsActiveFlag_RXNE_RXFNE(LPUART1);
}
}
uint8_t furi_hal_serial_async_rx(FuriHalSerialHandle* handle) {
furi_check(FURI_IS_IRQ_MODE());
furi_assert(handle->id < FuriHalSerialIdMax);

View File

@@ -130,6 +130,16 @@ void furi_hal_serial_async_rx_start(
*/
void furi_hal_serial_async_rx_stop(FuriHalSerialHandle* handle);
/** Check if there is data available for reading
*
* @warning This function must be called only from the callback
* FuriHalSerialAsyncRxCallback
*
* @param handle Serial handle
* @return true if data is available for reading, false otherwise
*/
bool furi_hal_serial_async_rx_available(FuriHalSerialHandle* handle);
/** Get data Serial receive
*
* @warning This function must be called only from the callback

View File

@@ -47,6 +47,7 @@ typedef struct {
FuriHalSerialHandle* log_serial;
// Expansion detection
FuriHalSerialHandle* expansion_serial;
FuriHalSerialControlExpansionCallback expansion_cb;
void* expansion_ctx;
} FuriHalSerialControl;
@@ -58,7 +59,36 @@ static void furi_hal_serial_control_log_callback(const uint8_t* data, size_t siz
furi_hal_serial_tx(handle, data, size);
}
static void furi_hal_serial_control_expansion_irq_callback(void* context) {
UNUSED(context);
FuriHalSerialControlMessage message;
message.type = FuriHalSerialControlMessageTypeExpansionIrq;
message.api_lock = NULL;
furi_message_queue_put(furi_hal_serial_control->queue, &message, 0);
}
static void
furi_hal_serial_control_enable_expansion_irq(FuriHalSerialHandle* handle, bool enable) {
const GpioPin* gpio = furi_hal_serial_get_gpio_pin(handle, FuriHalSerialDirectionRx);
if(enable) {
furi_hal_serial_disable_direction(handle, FuriHalSerialDirectionRx);
furi_hal_gpio_add_int_callback(gpio, furi_hal_serial_control_expansion_irq_callback, NULL);
furi_hal_gpio_init(gpio, GpioModeInterruptFall, GpioPullUp, GpioSpeedLow);
} else {
furi_hal_gpio_remove_int_callback(gpio);
furi_hal_serial_enable_direction(handle, FuriHalSerialDirectionRx);
}
}
static void furi_hal_serial_control_log_set_handle(FuriHalSerialHandle* handle) {
// Disable expansion module detection before reconfiguring UARTs
if(furi_hal_serial_control->expansion_serial) {
furi_hal_serial_control_enable_expansion_irq(
furi_hal_serial_control->expansion_serial, false);
}
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);
@@ -74,15 +104,12 @@ static void furi_hal_serial_control_log_set_handle(FuriHalSerialHandle* handle)
furi_hal_serial_control->log_handler.context = furi_hal_serial_control->log_serial;
furi_log_add_handler(furi_hal_serial_control->log_handler);
}
}
static void furi_hal_serial_control_expansion_irq_callback(void* context) {
UNUSED(context);
FuriHalSerialControlMessage message;
message.type = FuriHalSerialControlMessageTypeExpansionIrq;
message.api_lock = NULL;
furi_message_queue_put(furi_hal_serial_control->queue, &message, 0);
// Re-enable expansion module detection (if applicable)
if(furi_hal_serial_control->expansion_serial) {
furi_hal_serial_control_enable_expansion_irq(
furi_hal_serial_control->expansion_serial, true);
}
}
static bool furi_hal_serial_control_handler_stop(void* input, void* output) {
@@ -93,16 +120,21 @@ static bool furi_hal_serial_control_handler_stop(void* input, void* output) {
static bool furi_hal_serial_control_handler_acquire(void* input, void* output) {
FuriHalSerialId serial_id = *(FuriHalSerialId*)input;
if(furi_hal_serial_control->handles[serial_id].in_use) {
FuriHalSerialHandle* handle = &furi_hal_serial_control->handles[serial_id];
if(handle->in_use) {
*(FuriHalSerialHandle**)output = NULL;
} else {
// Logging
if(furi_hal_serial_control->log_config_serial_id == serial_id) {
furi_hal_serial_control_log_set_handle(NULL);
// Expansion
} else if(furi_hal_serial_control->expansion_serial == handle) {
furi_hal_serial_control_enable_expansion_irq(handle, false);
}
// Return handle
furi_hal_serial_control->handles[serial_id].in_use = true;
*(FuriHalSerialHandle**)output = &furi_hal_serial_control->handles[serial_id];
handle->in_use = true;
*(FuriHalSerialHandle**)output = handle;
}
return true;
@@ -116,9 +148,12 @@ static bool furi_hal_serial_control_handler_release(void* input, void* output) {
furi_hal_serial_deinit(handle);
handle->in_use = false;
// Return back logging
if(furi_hal_serial_control->log_config_serial_id == handle->id) {
// Return back logging
furi_hal_serial_control_log_set_handle(handle);
} else if(furi_hal_serial_control->expansion_serial == handle) {
// Re-enable expansion
furi_hal_serial_control_enable_expansion_irq(handle, true);
}
return true;
@@ -157,24 +192,24 @@ static bool furi_hal_serial_control_handler_expansion_set_callback(void* input,
FuriHalSerialControlMessageExpCallback* message_input = input;
FuriHalSerialHandle* handle = &furi_hal_serial_control->handles[message_input->id];
const GpioPin* gpio = furi_hal_serial_get_gpio_pin(handle, FuriHalSerialDirectionRx);
if(message_input->callback) {
const bool enable_irq = message_input->callback != NULL;
if(enable_irq) {
furi_check(furi_hal_serial_control->expansion_serial == NULL);
furi_check(furi_hal_serial_control->expansion_cb == NULL);
furi_hal_serial_disable_direction(handle, FuriHalSerialDirectionRx);
furi_hal_gpio_add_int_callback(gpio, furi_hal_serial_control_expansion_irq_callback, NULL);
furi_hal_gpio_init(gpio, GpioModeInterruptFall, GpioPullUp, GpioSpeedLow);
furi_hal_serial_control->expansion_serial = handle;
} else {
furi_check(furi_hal_serial_control->expansion_serial == handle);
furi_check(furi_hal_serial_control->expansion_cb != NULL);
furi_hal_gpio_remove_int_callback(gpio);
furi_hal_serial_enable_direction(handle, FuriHalSerialDirectionRx);
furi_hal_serial_control->expansion_serial = NULL;
}
furi_hal_serial_control->expansion_cb = message_input->callback;
furi_hal_serial_control->expansion_ctx = message_input->context;
furi_hal_serial_control_enable_expansion_irq(handle, enable_irq);
return true;
}