CRSFforArduino icon indicating copy to clipboard operation
CRSFforArduino copied to clipboard

CRSF frame parsing timeout repeatedly expires thus dropping all frames

Open britannio opened this issue 10 months ago • 5 comments

Is there an existing issue for this bug?

  • [X] I have searched the issues and there is no existing issue for this bug.

What development environment are you using?

PlatformIO

What board are you using?

Raspberry Pi Pico RP2040

What part of CRSF for Arduino is this bug related to?

RC Channels

Current behaviour

When I set up the library to get rc channel data, the callback will run but the channel data never changes. I only encounter this issue when my Pi Pico is connected to the Adafruit PiCowbell CAN Bus.

Expected behaviour

The rc data should update as normal.

Steps to reproduce

I'm unsure how to reproduce this issue without the mentioned hardware.

Additional information

Removing the following lines fixes the issue. https://github.com/ZZ-Cat/CRSFforArduino/blob/26952d5351165cd8d6a42ac5d72a14b1c7eda686/src/SerialReceiver/CRSF/CRSF.cpp#L78-L87 So the frame expires before it is fully parsed, causing framePosition to be reset to 0 mid-way through parsing a frame and thus the CRC check will fail.

britannio avatar Apr 10 '24 20:04 britannio

While I'm here, is it necessary to run the rc channels callback upon parsing a frame with a different frame type such as a telemetry frame? Likewise for link statistics. https://github.com/ZZ-Cat/CRSFforArduino/blob/Main-Trunk/src/SerialReceiver/SerialReceiver.cpp#L297

britannio avatar Apr 10 '24 20:04 britannio

https://github.com/ZZ-Cat/CRSFforArduino/blob/26952d5351165cd8d6a42ac5d72a14b1c7eda686/src/SerialReceiver/CRSF/CRSF.cpp#L66

Increasing the timeout here may fix the issue but is the timeout necessary?

britannio avatar Apr 10 '24 20:04 britannio

...is the timeout necessary?

Oh gods, you have my intrusive thoughts in a nutshell, here. :laughing:

The time-out is calculated based on the number of possible size of CRSF packets (which is 64 bytes), the number of packets that are expected to be received, and the baud rate.
From what I understand of the protocol, a timeout of approximately 1500 µS is required to receive all bytes before the buffer is reset.
If an incomplete packet is received, it is assumed that the connection between your receiver and your target (EG development board) is either janky or broken... at least this is the theory behind it.

Removing the time-out altogether may fix your Issue. However, without the timeout, CRSF for Arduino will have no way of knowing the time difference between each byte received. This could create more issues than what your issue is trying to solve, here. It's more likely that my implementation of the time-out could do with a re-factor, as it was derived from Betaflight's implementation, and it's more likely that calling it in the context of the main loop() could be coming back to bite me here, because Betaflight's timeout is executed within interrupt context.


Increasing the timeout here may fix the issue but is the timeout necessary?

If you expand that function, you will see the calculation I am using:

timePerFrame = ((1000000 * packetCount) / (baudRate / (CRSF_FRAME_SIZE_MAX - 1)))

Punch that into your calculator with packetCount at 10 and baudRate of 420000, this yields 1500 µS exactly.
Full disclosure, I have no idea where the Betaflight devs even got 1500 µS from, because it makes zero sense.
You can increase the timePerFrame by passing in a packetCount higher than 10 when you use setFrameTime().

If you set the packetCount to 12, it will set the timePerFrame to 1800 µS. This may work for you.


While I'm here, is it necessary to run the rc channels callback upon parsing a frame with a different frame type such as a telemetry frame? Likewise for link statistics.

What do you mean by this? Could you elaborate on this a little more?

ZZ-Cat avatar Apr 12 '24 08:04 ZZ-Cat

What do you mean by this? Could you elaborate on this a little more?

Each invocation of CRSF::receiveFrames() parses a single frame. The frame has a frame type and the ones accepted by the library are:

  • CRSF_FRAMETYPE_RC_CHANNELS_PACKED
  • CRSF_FRAMETYPE_LINK_STATISTICS

If the received frame is RC_CHANNELS_PACKED then the callback set in CRSFforArduino::setRcChannelsCallback should be invoked. Likewise, if the frame is LINK_STATISTICS then the CRSFforArduino::setLinkStatisticsCallback callback should be invoked. But right now the callbacks are being invoked irrespective of the frame type or whether the CRC check for the current frame passes.

If this change is made, the failsafe flag may need to be moved as it only relies on link statistics data.

britannio avatar Apr 12 '24 11:04 britannio

Each invocation of CRSF::receiveFrames() parses a single frame. The frame has a frame type and the ones accepted by the library are:

* `CRSF_FRAMETYPE_RC_CHANNELS_PACKED`

* `CRSF_FRAMETYPE_LINK_STATISTICS`

If the received frame is RC_CHANNELS_PACKED then the callback set in CRSFforArduino::setRcChannelsCallback should be invoked. Likewise, if the frame is LINK_STATISTICS then the CRSFforArduino::setLinkStatisticsCallback callback should be invoked. But right now the callbacks are being invoked irrespective of the frame type or whether the CRC check for the current frame passes.

Interesting. :thinking: Yea, nah. It shouldn't be doing that, and I will look into it. At this time, my focus is primarily with #103 (which has taken priority). So, it may be some time before I sort this issue out.

ZZ-Cat avatar Apr 12 '24 22:04 ZZ-Cat