furi_hal_serial: shared RX callback for both UARTs triggers furi_check
Describe the bug.
furi_hal_serial_async_rx_start() aborts when both UARTs are given the same callback function pointer:
// targets/f7/furi_hal/furi_hal_serial.c:868
// Assign different functions to different UARTs
furi_check(
furi_hal_serial[FuriHalSerialIdUsart].rx_byte_callback !=
furi_hal_serial[FuriHalSerialIdLpuart].rx_byte_callback);As far as I can tell from this file, the callback pointer is never used to tell the two ports apart:
- furi_hal_serial_async_rx_configure() stores callback, handle and context indexed by handle->id
- the same function installs a separate ISR per port, selected by handle->id: furi_hal_serial_usart_irq_callback or furi_hal_serial_lpuart_irq_callback
- each ISR indexes the array with a hardcoded constant (lines 128 and 329), not with the callback pointer
The port is already identified three times over before the callback is reached, and the only comparison of rx_byte_callback in the whole file is the check above.
The effect is that one shared handler dispatching on its handle argument - the ordinary C callback pattern, and the reason handle is passed to the callback at all - is rejected with a hard abort.
The same check is duplicated for the DMA path at line 998 (rx_dma_callback), so furi_hal_serial_dma_rx_start() carries the same restriction.
Reproduction
- From an application, acquire both FuriHalSerialIdUsart and FuriHalSerialIdLpuart
- Call furi_hal_serial_init() on both handles
- Call furi_hal_serial_async_rx_start() on both, passing the same function pointer and different context values
- The second call aborts with furi_check failed
Target
f7
Logs
The crash screen shows only “furi_check failed”, with no file or line, so from an
application this is difficult to trace back to its cause.Anything else?
Found while writing an application that listens on both buses at once - K-line on USART1 and K-bus on LPUART1.
It also bites code that does not share a callback on purpose. A generic Rust trampoline instantiated twice compiles to identical machine code, the linker folds the two copies into one symbol, and both ports end up registered with the same address:
00000000 t async_serial_receiver_worker
000001d8 t async_serial_receiver_worker
000003b0 t async_serial_receiver_rx_callback <- one address, two portsEither dropping the check or documenting the requirement in furi_hal_serial.h would help. The header does not mention it.
Source: flipperdevices/flipperzero-firmware