Fix MSP-over-telemetry multi-frame request assembly#11478
Fix MSP-over-telemetry multi-frame request assembly#11478b14ckyy merged 4 commits intoiNavFlight:maintenance-9.xfrom
Conversation
Maintenance 9.x to master
Updated instructions to reflect the use of the maintenance branch instead of master for cloning and merging.
…ch-7 Update branch references from master to maintenance
Branch Targeting SuggestionYou've targeted the
If This is an automated suggestion to help route contributions to the appropriate branch. |
Review Summary by QodoFix MSP-over-telemetry multi-frame request assembly deadlock
WalkthroughsDescription• Remove response-pending check causing multi-frame MSP deadlock • Fixes MSP requests over SmartPort, CRSF, FPort telemetry • Prevents silent failures for payloads exceeding single frame • Eliminates redundant buffer reinitialization logic Diagramflowchart LR
A["Multi-frame MSP Request"] --> B["START Frame Arrives"]
B --> C["mspStarted = 1"]
C --> D["CONT Frame Arrives"]
D --> E["Response-pending Check Removed"]
E --> F["Frame Processed Successfully"]
F --> G["Request Reassembled"]
File Changes1. src/main/telemetry/msp_shared.c
|
Code Review by Qodo🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0)
Great, no issues found!Qodo reviewed your code and found no material issues that require reviewⓘ The new review experience is currently in Beta. Learn more |
Fix initSharedMsp() to initialize the response buffer as empty instead of setting it to the full buffer size. This was causing the response- pending check in handleMspFrame() to incorrectly detect a pending response after every buffer reinitialization. Root cause: initSharedMsp() set responsePacket->buf.end to responseBuffer + sizeof(mspTxBuffer), putting the buffer in writer mode with sbufBytesRemaining() returning the full buffer size (e.g. 512). The response-pending check in handleMspFrame() interpreted this as unsent response data and reset mspStarted to 0. This triggered another call to initSharedMsp(), which reset the buffer to full size again, creating a permanent cycle that dropped every continuation frame. The response-pending check itself is correct and necessary: SmartPort is half-duplex, so new request assembly must be blocked while a response is still being sent. The bug was that initSharedMsp() corrupted the buffer state that the check relies on. The fix changes initSharedMsp() to set buf.end = buf.ptr (empty reader), so sbufBytesRemaining() returns 0 when no response is actually pending. processMspPacket() already sets up the response buffer in writer mode before processing, so this change is safe. Impact: all MSPv1/MSPv2 requests with payload requiring more than one telemetry frame were silently dropped over SmartPort, CRSF, and FPort MSP passthrough. Only zero-payload single-frame requests succeeded. Tested on MATEKF765 with SmartPort MSP passthrough.
b29f60c to
20745ec
Compare
|
Test firmware build ready — commit Download firmware for PR #11478 228 targets built. Find your board's
|
|
caused by #11369 |
|
Hi @b14ckyy, thanks for catching this and for the fix. I tested this change against the original TCP -> CRSF/MSP scenario that led to #11369, and it behaves correctly there as well. The crash / stability issue fixed in #11369 remains resolved without the The mistake on my side came from conflating two different buffer states around
I mistakenly applied the "writer" initialization to That said, the same full-capacity initialization should still stay in So reverting only the |
Summary
One-line fix in
initSharedMsp()to initialize the response buffer as empty, preventing the response-pending check inhandleMspFrame()from permanently blocking multi-frame MSP request assembly.Root Cause
initSharedMsp()initialized the response buffer withbuf.endpointing to the end of the full buffer:The response-pending check in
handleMspFrame()usessbufBytesRemaining()(end - ptr) to detect unsent response data:After
initSharedMsp()runs,sbufBytesRemaining()returns the full buffer size (512) rather than 0, becauseptrandendspan the entire buffer. The check misinterprets this as a pending response, resetsmspStartedto 0, which triggersinitSharedMsp()again on the next frame — creating a permanent cycle that drops every continuation frame.Fix
Initialize the response buffer as empty (
ptr == end) sosbufBytesRemaining()returns 0 when no response is actually pending. This is safe becauseprocessMspPacket()already sets up the response buffer with full capacity before writing any response.Impact
All MSPv1/MSPv2 requests requiring more than one telemetry frame are silently dropped over SmartPort, CRSF, and FPort MSP passthrough. Only zero-payload single-frame requests (e.g.
MSP2_INAV_STATUS) work because they complete in a single frame without needing continuation.Testing
Verified on MATEKF765 with SmartPort MSP passthrough using diagnostic logging in
handleMspFrame():sbufBytesRemaining()returned 512 after eachinitSharedMsp()call, causingmspStartedto be reset before the continuation could be processedmspFcProcessCommand()