[rio] link-health telemetry: req/rep/btn counters, reply age, the existing (never-printed) line-error/abandon/board counters, and STALL/RECOVER event lines -- default-on for hardware RIO, BT_RIO_LOG=0 opts out (encoder-dropout hunt on ALPHA-MR)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
a7722d9ca9
commit
a28878beaf
@@ -1240,6 +1240,23 @@ RIO::~RIO()
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
//
|
||||
// [rio] telemetry state (see the block in GetNextEvent). File-scope statics
|
||||
// on purpose: one hardware RIO per process, and no header/layout churn.
|
||||
//
|
||||
static int sRioLog = -1;
|
||||
static unsigned gRioReqCount = 0;
|
||||
static unsigned gRioRepCount = 0;
|
||||
static unsigned gRioBtnCount = 0;
|
||||
static int gRioReqPending = 0;
|
||||
static DWORD gRioLastReqTick = 0;
|
||||
static DWORD gRioLastReplyTick = 0;
|
||||
static DWORD gRioLastReportTick = 0;
|
||||
static int gRioStallActive = 0;
|
||||
static DWORD gRioStallStart = 0;
|
||||
static unsigned gRioStallBtnBase = 0;
|
||||
static unsigned gRioStallErrBase = 0;
|
||||
|
||||
Logical
|
||||
RIO::TestInstance() const
|
||||
{
|
||||
@@ -1264,6 +1281,57 @@ Logical
|
||||
Logical reply, looping;
|
||||
Word errors;
|
||||
|
||||
//
|
||||
// [rio] link-health telemetry (encoder-dropout hunt, 2026-08-10). The
|
||||
// protocol is polled (host requests analog, board replies) over an
|
||||
// ACK-gated packet layer, so ONE lost byte can freeze every axis until
|
||||
// unrelated board traffic resyncs the exchange -- which is exactly what
|
||||
// a dropout-revived-by-a-button feels like from the seat. These lines
|
||||
// discriminate wire noise (lineErr/overrun climbing) from protocol jams
|
||||
// (abandon/rRetry/rFull climbing) from quiet stalls (age grows, counters
|
||||
// still). STALL = a specific analog request unanswered for >500 ms;
|
||||
// RECOVER records whether a BUTTON arrived during the stall (the field
|
||||
// theory). Default ON on real-RIO rigs only; BT_RIO_LOG=0 opts out.
|
||||
//
|
||||
{
|
||||
if (sRioLog < 0)
|
||||
{
|
||||
const char *e = getenv("BT_RIO_LOG");
|
||||
sRioLog = (e != 0 && *e == '0') ? 0 : 1;
|
||||
}
|
||||
if (sRioLog && operational)
|
||||
{
|
||||
DWORD now = GetTickCount();
|
||||
if (!gRioStallActive && gRioReqPending
|
||||
&& now - gRioLastReqTick > 500)
|
||||
{
|
||||
gRioStallActive = 1;
|
||||
gRioStallStart = now;
|
||||
gRioStallBtnBase = gRioBtnCount;
|
||||
gRioStallErrBase = (unsigned)(lineErrorCount + abandonCount);
|
||||
DEBUG_STREAM << "[rio] STALL analog request unanswered "
|
||||
<< (now - gRioLastReqTick) << "ms req=" << gRioReqCount
|
||||
<< " rep=" << gRioRepCount << "\n" << std::flush;
|
||||
}
|
||||
if (now - gRioLastReportTick >= 5000)
|
||||
{
|
||||
gRioLastReportTick = now;
|
||||
DEBUG_STREAM << "[rio] req=" << gRioReqCount
|
||||
<< " rep=" << gRioRepCount
|
||||
<< " btn=" << gRioBtnCount
|
||||
<< " age=" << (gRioLastReplyTick != 0
|
||||
? (now - gRioLastReplyTick) : 0)
|
||||
<< "ms lineErr=" << lineErrorCount
|
||||
<< " overrun=" << overrunCount
|
||||
<< " abandon=" << abandonCount
|
||||
<< " rRetry=" << remoteRetryCount
|
||||
<< " rAbandon=" << remoteAbandonCount
|
||||
<< " rFull=" << remoteFullBufferCount
|
||||
<< "\n" << std::flush;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//PCSPAKState(this);
|
||||
//
|
||||
//cout << flush;
|
||||
@@ -1377,6 +1445,24 @@ Logical
|
||||
break;
|
||||
|
||||
case AnalogReply:
|
||||
++gRioRepCount;
|
||||
gRioReqPending = 0;
|
||||
gRioLastReplyTick = GetTickCount();
|
||||
if (gRioStallActive)
|
||||
{
|
||||
// The reply that ended the drought. btnDuring is the
|
||||
// field theory's verdict: >0 on every RECOVER = button
|
||||
// traffic is what resyncs the link; 0 = it self-heals.
|
||||
DEBUG_STREAM << "[rio] RECOVER after "
|
||||
<< (gRioLastReplyTick - gRioStallStart)
|
||||
<< "ms btnDuring="
|
||||
<< (gRioBtnCount - gRioStallBtnBase)
|
||||
<< " errsDuring="
|
||||
<< ((unsigned)(lineErrorCount + abandonCount)
|
||||
- gRioStallErrBase)
|
||||
<< "\n" << std::flush;
|
||||
gRioStallActive = 0;
|
||||
}
|
||||
destination->Type = RIO::AnalogEvent;
|
||||
//
|
||||
// NOTE: no data is sent in this packet.
|
||||
@@ -1423,11 +1509,13 @@ Logical
|
||||
break;
|
||||
|
||||
case ButtonPressed:
|
||||
++gRioBtnCount;
|
||||
destination->Type = RIO::ButtonPressedEvent;
|
||||
destination->Data.Unit = receive_buffer[1];
|
||||
break;
|
||||
|
||||
case ButtonReleased:
|
||||
++gRioBtnCount;
|
||||
destination->Type = RIO::ButtonReleasedEvent;
|
||||
destination->Data.Unit = receive_buffer[1];
|
||||
break;
|
||||
@@ -1568,6 +1656,9 @@ void
|
||||
if (operational && !TestModeActive)
|
||||
{
|
||||
SendPacket((Byte *) request_analog_string);
|
||||
++gRioReqCount;
|
||||
gRioReqPending = 1;
|
||||
gRioLastReqTick = GetTickCount();
|
||||
}
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user