-
Notifications
You must be signed in to change notification settings - Fork 17.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Decode high duty-cycle CRSF frames using frame marker rather than timeouts #26183
Conversation
d1ba6f0
to
4d20ff1
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this looks like it should work, but it seems a bit awkward.
might be easier if you had a union on Frame with a uint8_t array?
4d20ff1
to
7fdaff0
Compare
Maybe, but that then makes it a very large change as all the references to _frame have to be updated. I think it would be better to do that as a separate NFC PR. |
Flew this on the copter that was having multiple RC failsafes - clean as a whistle, no issues at all and flew great. I think this is a good solution and should definitely go in 4.5. Should be possibly considered for 4.4 after further user testing. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i would prefer the union/memmove approach, it is just much clear
@andyp1per I think you might only be using Crossfire, should this be tested with Express LRS (which also uses CRSF)? |
Tested on ELRS at 250Hz 1:2 and 500Hz 1:2 without issue |
Upon reflection I don't agree with this. If I was going to do a union I was only going to do that to make the maths a bit easier, I wasn't planning on doing a memmove. The problem is if we do a memmove we still have to process the bytes to see if the new start makes any sense or not. The new code would then have to have a separate parser to look at frames rather than bytes and we still need to do byte-based processing in the happy path. We still don't know when we have got a frame until we have finally read the CRC and validated it. We don't even know that we have enough bytes to process - in fact quite likely that we don't since that is the general problem that cause the failsafes in the first place. memmove also adds in the overhead of the copy as well as processing the data. So although I agree its a little hard to get your head around at first I think the approach I have implemented is actually the most efficient and the best for the kind of data stream we are dealing with. |
@andyp1per valgrind is not happy with the decoder: |
no, you don't. The basis of a union based decoder is this:
|
@andyp1per note that to use valgrind, you typically build for the linux target with:
|
I am unable to get valgrind to complain, would be good to understand what else I might need to do. |
@andyp1per can you have a look at this branch? I've added a commit that reworks the parser using the more conventional memchr/memmove approach for re-sync. I think it makes the code clearer |
@andyp1per I've updated that branch some more to fix the test code under SITL and moved the crc calculation to be done once we have the full frame, which makes the skip to next frame work properly |
@andyp1per note that the CRSF4 test fails with your PR as-is |
7f9f01b
to
30a7138
Compare
@tridge I have incorporated your changes into my PR, fixed up, reviewed and tested. Seems to be working well - thanks. |
@peterbarker would you mind checking the parser for any logic errors that could cause a crash? |
@andyp1per can we remove AP_SerialProtocol_CRSF? It's been broken for 18 months and nobody noticed. We could save bytes and code complexity by removing it. 9b8ea84 was the commit which killed it AFAICS. |
@andyp1per to expand on the comment from peter, the AP_RCProtocol_CRSF::update() function calls process_byte() with invalid arguments (passes in micros as the byte). The if (_uart) section of update() is only used when SERIALn_PROTOCOL is set to CRSF as opposed to RC. I don't see the point of setting it to CRSF, what is that meant to do? |
I'll fix. Most of the TBS kit supports direct CRSF control without RC frames - I have many. This was the original implementation and I don't want to lose it. |
Fixed and tested |
ea73cd5
to
c5a2a10
Compare
@@ -299,7 +349,7 @@ void AP_RCProtocol_CRSF::update(void) | |||
for (uint8_t i = 0; i < n; i++) { | |||
int16_t b = _uart->read(); | |||
if (b >= 0) { | |||
_process_byte(AP_HAL::micros(), uint8_t(b)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could you explain what the "standalone" mode is for? It seems to be setup by setting SERIALn_PROTOCOL to CRSF instead of RCIN, but I don't see how it fits in. It has clearly been broken for a long time so I wonder if it is really needed at all?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pretty much all TBS kit supports CRSF control without RC packets. e.g. like SmartAudio for VTX or I have a TBS VTX that supports OSD natively via CRSF - the standalone mode allows you to support these devices. The format is pretty much the same, its just how you integrate that is not - you can't do it via the RC protocol because that essentially assumes that you have data always coming in that you need to reply to. These devices are genuine full-duplex so the FC is often initiating the comms. This was the original CRSF support, I have several copters using it I just haven't flown them for a while - I'm not planning on losing it.
a63276d
to
a85fbc8
Compare
@andyp1per I've force pushed a fix for the trailing bytes error |
fixed RCProtocolTest on SITL and make it pass/fail with an exit code Co-authored-by: Andrew Tridgell <[email protected]>
a85fbc8
to
7e57c78
Compare
… rather than timeouts Co-authored-by: Andrew Tridgell <[email protected]>
7e57c78
to
b464712
Compare
|
Squashed, cherry-picked @peterbarker's commit in as a separate commit and re-tested. All looks good. Happy for this to go in now @tridge |
This fixes an issue with CRSF and ELRS where fast update rates and/or high CPU load can lead to radio failsafes due to scheduling delays preventing full parsing of frames and then the re-synchronization taking too long. The approach is to look for the CRSF frame marker (0xC8) and parse from that point. If parsing fails then the next frame marker is searched for and intermediate bytes are dropped. This means that re-synchronization should take place in a single frame.