fix(crossfire): handle partial frame from half-duplex IDLE split (#7242)

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Raphael Coeffic
2026-04-28 13:31:23 +10:00
committed by GitHub
co-authored by Claude Opus 4.6
parent c51728154b
commit 29170d20c5
2 changed files with 24 additions and 9 deletions
+20 -5
View File
@@ -286,16 +286,23 @@ static uint8_t* _processFrames(void* ctx, uint8_t* buf, uint8_t& len)
static void crossfireProcessFrame(void* ctx, uint8_t* frame, uint8_t frame_len,
uint8_t* buf, uint8_t* p_len)
{
if (frame_len < MIN_FRAME_LEN) return;
uint8_t& len = *p_len;
if (len == 0) {
// buffer is empty: no re-assembly
if (frame_len == 0) return;
if (!_validHdr(frame)) {
TRACE("[XF] invalid frame start");
return;
}
if (frame_len < MIN_FRAME_LEN) {
// Too short to process, but valid header: save for reassembly
memcpy(buf, frame, frame_len);
len = frame_len;
return;
}
// process frames directly out of RX buffer
uint8_t* p_buf = _processFrames(ctx, frame, frame_len);
if (frame_len > 0) {
@@ -344,8 +351,16 @@ static void _crsf_extmodule_frame_received()
// proxy trigger to avoid calling
// FreeRTOS methods from ISR with prio 0
static void _soft_irq_trigger(void*)
static void _soft_irq_trigger(void* param)
{
// detect spurious IDLE IRQ with empty buffer
auto mod_rx = (etx_module_driver_t*)param;
auto drv = modulePortGetSerialDrv(*mod_rx);
auto ctx = modulePortGetCtx(*mod_rx);
if (!drv || !ctx || !drv->getBufferedBytes) return;
if (drv->getBufferedBytes(ctx) == 0) return;
#if defined(TELEMETRY_USE_CUSTOM_EXTI)
stm32_exti_custom_trigger_swi(TELEMETRY_RX_FRAME_EXTI_LINE);
#else
@@ -396,7 +411,7 @@ static void* crossfireInit(uint8_t module)
#if !defined(SIMU)
if (drv && ctx && drv->setIdleCb) {
drv->setIdleCb(ctx, _soft_irq_trigger, nullptr);
drv->setIdleCb(ctx, _soft_irq_trigger, &mod_st->rx);
#if defined(TELEMETRY_USE_CUSTOM_EXTI)
stm32_exti_custom_enable(TELEMETRY_RX_FRAME_EXTI_LINE, 3,
_crsf_extmodule_frame_received);
+4 -4
View File
@@ -262,9 +262,9 @@ static void pxx1SportSensorPolling(void* param)
if (outputTelemetryBuffer.destination != TELEMETRY_ENDPOINT_SPORT)
return;
auto mod_st = (etx_module_state_t*)param;
auto drv = modulePortGetSerialDrv(mod_st->rx);
auto ctx = modulePortGetCtx(mod_st->rx);
auto mod_rx = (etx_module_driver_t*)param;
auto drv = modulePortGetSerialDrv(*mod_rx);
auto ctx = modulePortGetCtx(*mod_rx);
// Match sensor polling from the module
// -> detect <0x7E [Physical ID]> as the last sequence
@@ -341,7 +341,7 @@ static void* pxx1Init(uint8_t module)
auto drv = modulePortGetSerialDrv(mod_st->rx);
auto ctx = modulePortGetCtx(mod_st->rx);
if (drv && ctx && drv->setIdleCb) {
drv->setIdleCb(ctx, pxx1SportSensorPolling, mod_st);
drv->setIdleCb(ctx, pxx1SportSensorPolling, &mod_st->rx);
}
}