@@ -107,17 +107,27 @@ constexpr uint32_t TAG_OPERATION_TIMEOUT_MS{2000};
107107constexpr int TAG_OPERATION_ATTEMPTS {3 };
108108
109109/* !
110- @brief How long to wait for the rest of a frame that has already started
111- @details A frame is sent in one go, and the longest the module can send is 517 bytes, which
112- at 115200 baud takes about 45ms. This is the ceiling on how long a stream that stops halfway
113- can hold the caller up, and it is deliberately not the configured timeout: that one is for a
114- frame arriving at all, which is a different wait and a far longer one
110+ @brief Longest gap between two bytes of the same frame
111+ @details The module sends a frame in one go, so a pause longer than a couple of dozen byte
112+ times means it has finished sending rather than that more is coming
115113 */
116- // Longest gap between two bytes of the same frame. The module sends a frame in one go, so a
117- // pause longer than a couple of dozen byte times means it has finished sending rather than that
118- // more is coming
119114constexpr uint32_t BYTE_GAP_TIMEOUT_MS {2 };
120115
116+ /* !
117+ @brief How long the link has to stay silent before the next command is sent
118+ @details The answer to a command that timed out can still arrive afterwards, and a response
119+ frame carries nothing but the command code to say what it answers. A gap this long says the
120+ answer is not on its way, which is what makes the next command's answer its own
121+ */
122+ constexpr uint32_t RESYNC_QUIET_MS {50 };
123+
124+ /* !
125+ @brief Longest a resynchronisation may take
126+ @details Tag notifications keep arriving while a round is running, so the link does not fall
127+ silent on its own during one. This bounds the wait for that case
128+ */
129+ constexpr uint32_t RESYNC_LIMIT_MS {250 };
130+
121131// ! @brief Byte sent to wake the module. Any value does; this is what the vendor's driver sends
122132constexpr uint8_t WAKE_BYTE {0x55 };
123133// ! @brief How long waking takes. Not documented; this is what the vendor's driver waits
@@ -401,6 +411,21 @@ bool UnitJRD4035::pump(const uint32_t timeout_ms)
401411 return handled;
402412}
403413
414+ void UnitJRD4035::resynchronize ()
415+ {
416+ // Nothing is pending, so route_frame queues tag notifications as usual and drops answers.
417+ // Reading on until the link falls silent is what keeps a late answer out of the next exchange
418+ const unsigned long give_up_at = m5::utility::millis () + RESYNC_LIMIT_MS ;
419+ Frame f{};
420+ while (m5::utility::millis () < give_up_at) {
421+ if (!read_frame (f, RESYNC_QUIET_MS )) {
422+ return ;
423+ }
424+ route_frame (f);
425+ }
426+ M5_LIB_LOGW (" The link did not fall silent; the next answer may belong to an earlier command" );
427+ }
428+
404429bool UnitJRD4035::send_command (const uint8_t command, const uint8_t * param, const uint16_t param_len)
405430{
406431 std::vector<uint8_t > frame{};
@@ -415,10 +440,9 @@ bool UnitJRD4035::send_command(const uint8_t command, const uint8_t* param, cons
415440bool UnitJRD4035::send_and_wait (Frame& response, const uint8_t command, const uint8_t * param, const uint16_t param_len,
416441 const uint32_t timeout_ms)
417442{
418- // The response to a command that timed out can still arrive afterwards, and would then be
419- // taken for the answer to this one, shifting every later exchange by one frame. Whatever is
420- // already in flight is therefore consumed first: route_frame queues tag notifications as
421- // usual and drops the stale responses, because nothing is pending yet.
443+ // Anything that arrived since the last exchange is taken first: route_frame queues tag
444+ // notifications as usual and drops answers, because nothing is pending yet. That clears what
445+ // has already come in; an answer still on its way is waited out where the timeout happens
422446 pump (1 );
423447
424448 _awaiting_command = command;
@@ -445,6 +469,9 @@ bool UnitJRD4035::send_and_wait(Frame& response, const uint8_t command, const ui
445469 }
446470 _response_pending = false ;
447471 M5_LIB_LOGE (" Timeout waiting for the response to %02X" , command);
472+ // The answer may still be on its way, and nothing but the command code says what a response
473+ // answers. Leaving it there would make it the answer to whatever is sent next
474+ resynchronize ();
448475 return false ;
449476}
450477
0 commit comments