Skip to content

Commit db40e4e

Browse files
committed
Wait out a late answer before sending the next command
1 parent 581a49e commit db40e4e

2 files changed

Lines changed: 41 additions & 12 deletions

File tree

src/unit/unit_JRD4035.cpp

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -107,17 +107,27 @@ constexpr uint32_t TAG_OPERATION_TIMEOUT_MS{2000};
107107
constexpr 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
119114
constexpr 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
122132
constexpr 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+
404429
bool 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
415440
bool 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

src/unit/unit_JRD4035.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,8 @@ class UnitJRD4035 : public UHFRFIDComponent {
106106
void flush_rx();
107107
//! @brief Route a received frame
108108
void route_frame(const m100::Frame& f);
109+
//! @brief Wait out an answer that may still be on its way, so that it cannot answer the next command
110+
void resynchronize();
109111
//! @brief Read the module information for one kind (0x00 hardware / 0x01 software / 0x02 manufacturer)
110112
bool read_module_information_kind(std::string& out, const uint8_t kind);
111113
//! @brief Run one of the channel scans and decode its contiguous range of levels

0 commit comments

Comments
 (0)