fix overflow and mute

This commit is contained in:
2026-04-14 09:36:27 +03:00
parent ad1e16cfda
commit 8631f23b53
9 changed files with 466 additions and 69 deletions

View File

@ -26,6 +26,11 @@ static inline uint8_t irPulseFilterHoldbackEdges()
return hb;
}
static inline uint16_t irClampU16(uint32_t v)
{
return (v > 0xFFFFU) ? 0xFFFFU : (uint16_t)v;
}
IR_DecoderRaw::IR_DecoderRaw(const uint8_t pin, uint16_t addr, IR_Encoder *encPair) : encoder(encPair)
{
setPin(pin);
@ -74,6 +79,198 @@ void IR_DecoderRaw::pulseFilterResetStats()
pulseFilterDropGlitchPairs = 0;
}
bool IR_DecoderRaw::registerPairMuteEncoder(IR_Encoder *enc)
{
if (enc == nullptr)
return false;
for (uint8_t i = 0; i < pairMuteEncoderCount; ++i)
{
if (pairMuteEncoders[i] == enc)
return true;
}
if (pairMuteEncoderCount >= IR_PAIR_MUTE_MAX_ENCODERS)
return false;
pairMuteEncoders[pairMuteEncoderCount++] = enc;
return true;
}
void IR_DecoderRaw::refreshPairMuteState()
{
uint16_t active = 0;
for (uint8_t i = 0; i < pairMuteEncoderCount; ++i)
{
IR_Encoder *enc = pairMuteEncoders[i];
if (enc != nullptr && enc->isBusy())
++active;
}
const uint32_t nowUs = micros();
noInterrupts();
const bool wasActive = (isPairSending != 0);
isPairSending = active;
#if IR_RX_BRIEF_LOG
if (!wasActive && active != 0)
{
rxBriefMuteBlockedEdges = 0;
rxBriefMuteBeginPending = true;
rxBriefMuteBeginUs = nowUs;
}
else if (wasActive && active == 0)
{
rxBriefMuteEndPending = true;
rxBriefMuteEndUs = nowUs;
rxBriefMuteEndCount = rxBriefMuteBlockedEdges;
rxBriefMuteBlockedEdges = 0;
}
#endif
interrupts();
}
#if IR_RX_BRIEF_LOG
const __FlashStringHelper *IR_DecoderRaw::rxBriefReasonTag(RxBriefReason reason)
{
switch (reason)
{
case RxBriefReason::MuteBegin: return F("MUTE_BEGIN");
case RxBriefReason::MuteEnd: return F("MUTE_END");
case RxBriefReason::RawOverflow: return F("QRAW");
case RxBriefReason::FilterOverflow: return F("QFLT");
case RxBriefReason::HoldOverflow: return F("HOLD");
case RxBriefReason::Glitch: return F("GLITCH");
case RxBriefReason::Timing: return F("TIME");
case RxBriefReason::Preamble: return F("PREAMB");
case RxBriefReason::Sync: return F("SYNC");
case RxBriefReason::BufferOverflow: return F("BUF");
case RxBriefReason::Timeout: return F("TIMEOUT");
case RxBriefReason::Crc: return F("CRC");
case RxBriefReason::Ok: return F("OK");
default: return F("UNK");
}
}
void IR_DecoderRaw::rxBriefLog(RxBriefReason reason, uint16_t a, uint16_t b, uint32_t tUs)
{
#if IR_RX_BRIEF_LOG_REJECT_ONLY
if (reason == RxBriefReason::Ok || reason == RxBriefReason::Preamble)
return;
#endif
if (tUs == 0U)
tUs = micros();
Serial.print(F("IRRX t="));
Serial.print((unsigned long)tUs);
Serial.print(F(" rsn="));
Serial.print(rxBriefReasonTag(reason));
switch (reason)
{
case RxBriefReason::MuteBegin:
break;
case RxBriefReason::MuteEnd:
case RxBriefReason::RawOverflow:
Serial.print(F(" cnt="));
Serial.print(a);
break;
case RxBriefReason::FilterOverflow:
case RxBriefReason::HoldOverflow:
case RxBriefReason::Glitch:
Serial.print(F(" total="));
Serial.print(a);
break;
case RxBriefReason::Timing:
Serial.print(F(" rp="));
Serial.print(a);
if (b)
{
Serial.print(F(" hp="));
Serial.print(b);
}
break;
case RxBriefReason::Preamble:
Serial.print(F(" good="));
Serial.print(a);
if (b)
{
Serial.print(F(" per="));
Serial.print(b);
}
break;
case RxBriefReason::Sync:
Serial.print(F(" err="));
Serial.print(a);
break;
case RxBriefReason::BufferOverflow:
Serial.print(F(" bits="));
Serial.print(a);
break;
case RxBriefReason::Timeout:
Serial.print(F(" bits="));
Serial.print(a);
if (b)
{
Serial.print(F(" exp="));
Serial.print(b);
}
break;
case RxBriefReason::Crc:
case RxBriefReason::Ok:
Serial.print(F(" len="));
Serial.print(a);
if (b)
{
Serial.print(F(" err="));
Serial.print(b);
}
break;
}
Serial.println();
}
void IR_DecoderRaw::rxBriefNoteMuteBlockedIsr(uint32_t tUs)
{
(void)tUs;
if (rxBriefMuteBlockedEdges != UINT16_MAX)
++rxBriefMuteBlockedEdges;
}
void IR_DecoderRaw::rxBriefNoteRawOverflowIsr(uint32_t tUs)
{
if (rxBriefRawOverflowDrops != UINT16_MAX)
++rxBriefRawOverflowDrops;
rxBriefRawOverflowLastUs = tUs;
}
void IR_DecoderRaw::rxBriefFlushDeferredIsrLogs()
{
bool muteBeginPending = false;
uint32_t muteBeginUs = 0;
bool muteEndPending = false;
uint32_t muteEndUs = 0;
uint16_t muteEndCnt = 0;
uint16_t rawCnt = 0;
uint32_t rawLastUs = 0;
noInterrupts();
muteBeginPending = rxBriefMuteBeginPending;
muteBeginUs = rxBriefMuteBeginUs;
rxBriefMuteBeginPending = false;
rxBriefMuteBeginUs = 0;
muteEndPending = rxBriefMuteEndPending;
muteEndUs = rxBriefMuteEndUs;
muteEndCnt = rxBriefMuteEndCount;
rxBriefMuteEndPending = false;
rxBriefMuteEndUs = 0;
rxBriefMuteEndCount = 0;
rawCnt = rxBriefRawOverflowDrops;
rawLastUs = rxBriefRawOverflowLastUs;
rxBriefRawOverflowDrops = 0;
rxBriefRawOverflowLastUs = 0;
interrupts();
if (muteBeginPending)
rxBriefLog(RxBriefReason::MuteBegin, 0, 0, muteBeginUs);
if (muteEndPending)
rxBriefLog(RxBriefReason::MuteEnd, muteEndCnt, 0, muteEndUs);
if (rawCnt)
rxBriefLog(RxBriefReason::RawOverflow, rawCnt, 0, rawLastUs);
}
#endif
//////////////////////////////////// isr ///////////////////////////////////////////
volatile uint32_t time_;
@ -99,10 +296,19 @@ void IR_DecoderRaw::isr()
if (isPairSending)
{
#if IR_RX_BRIEF_LOG
rxBriefNoteMuteBlockedIsr(edge.time);
#endif
return;
}
subBuffer.push(edge);
if (!subBuffer.push(edge))
{
isSubBufferOverflow = true;
#if IR_RX_BRIEF_LOG
rxBriefNoteRawOverflowIsr(edge.time);
#endif
}
}
////////////////////////////////////////////////////////////////////////////////////
@ -123,6 +329,7 @@ void IR_DecoderRaw::firstRX()
i_dataBuffer = 0;
nextControlBit = bitPerByte;
i_syncBit = 0;
err_syncBit = 0;
isWrongPack = false;
isPreamb = true;
@ -157,6 +364,10 @@ inline void IR_DecoderRaw::checkTimeout()
{
#if defined(IRDEBUG_SERIAL_PACK)
packTraceOnTimeoutOrAbort(false);
#endif
#if IR_RX_BRIEF_LOG
const uint16_t expected = (i_dataBuffer >= 8U) ? uint16_t(dataBuffer[0] & IR_MASK_MSG_INFO) : 0U;
rxBriefLog(RxBriefReason::Timeout, i_dataBuffer, expected, micros());
#endif
isRecive = false; // приём завершён
msgTypeReceive = 0;
@ -168,6 +379,9 @@ inline void IR_DecoderRaw::checkTimeout()
void IR_DecoderRaw::tick()
{
#if IR_RX_BRIEF_LOG
rxBriefFlushDeferredIsrLogs();
#endif
FrontStorage currentFront;
bool hasCurrentFront = false;
FrontStorage rawFront;
@ -250,6 +464,9 @@ void IR_DecoderRaw::tick()
if (short_low_glitch)
{
errors.other++;
#if IR_RX_BRIEF_LOG
rxBriefLog(RxBriefReason::Glitch, 1, 0, currentFront.time);
#endif
#if IR_GLITCH_REJECT_PHASE_NUDGE
irGlitchPhaseNudge(currentFront.time, riseSyncTime, prevRise);
#endif
@ -264,6 +481,9 @@ void IR_DecoderRaw::tick()
if (micro_gap_rise)
{
errors.other++;
#if IR_RX_BRIEF_LOG
rxBriefLog(RxBriefReason::Glitch, 1, 0, currentFront.time);
#endif
#if IR_GLITCH_REJECT_PHASE_NUDGE
irGlitchPhaseNudge(currentFront.time, riseSyncTime, prevRise);
#endif
@ -273,6 +493,9 @@ void IR_DecoderRaw::tick()
if (candRp <= riseTimeMax / 4U && !highCount && !lowCount)
{
errors.other++;
#if IR_RX_BRIEF_LOG
rxBriefLog(RxBriefReason::Timing, irClampU16(candRp), 0, currentFront.time);
#endif
goto END;
}
@ -336,6 +559,11 @@ void IR_DecoderRaw::tick()
if (risePeriod > IR_timeout || isBufferOverflow || risePeriod < riseTimeMin || isWrongPack)
// ~Мы в пределах таймаута и буффер не переполнен и fix дроблёных единиц
{
#if IR_RX_BRIEF_LOG
if (!isBufferOverflow && !isWrongPack)
rxBriefLog(RxBriefReason::Timing, irClampU16((uint32_t)risePeriod),
irClampU16((uint32_t)highTime), currentFront.time);
#endif
goto END;
}
@ -494,6 +722,9 @@ void IR_DecoderRaw::tick()
////////////////////////////////////////////////////////////////////////////////////////////////////////////
END:;
#if IR_RX_BRIEF_LOG
rxBriefFlushDeferredIsrLogs();
#endif
#if defined(IR_EDGE_TRACE)
while (edgeTraceFlushChunk(Serial, 48) > 0) {}
#endif
@ -507,6 +738,9 @@ void IR_DecoderRaw::writeToBuffer(bool bit, bool packTraceInvertFix)
if (i_dataBuffer > dataByteSizeMax * 8)
{ // проверка переполнения
isBufferOverflow = true;
#if IR_RX_BRIEF_LOG
rxBriefLog(RxBriefReason::BufferOverflow, i_dataBuffer, 0, micros());
#endif
#if defined(IRDEBUG_SERIAL_PACK)
if (packTraceOpen)
packTraceEmitErrorFlash(F("ERROR: buffer overflow"));
@ -581,6 +815,9 @@ void IR_DecoderRaw::writeToBuffer(bool bit, bool packTraceInvertFix)
#endif
{
isWrongPack = true;
#if IR_RX_BRIEF_LOG
rxBriefLog(RxBriefReason::Sync, err_syncBit, 0, micros());
#endif
#if defined(IRDEBUG_SERIAL_PACK)
packTraceEmitErrorFlash(F("ERROR: Wrong sync bit"));
#endif
@ -674,6 +911,14 @@ void IR_DecoderRaw::writeToBuffer(bool bit, bool packTraceInvertFix)
packTraceEmitEndOk(static_cast<uint8_t>(packSize));
else
packTraceEmitEndBadCrc(static_cast<uint8_t>(packSize));
#endif
const uint16_t errSum =
uint16_t(errors.lowSignal) + uint16_t(errors.highSignal) + uint16_t(errors.other);
#if IR_RX_BRIEF_LOG
if (isAvailable)
rxBriefLog(RxBriefReason::Ok, packSize, errSum, micros());
else
rxBriefLog(RxBriefReason::Crc, packSize, errSum, micros());
#endif
if (!isAvailable && packSize > 0 && packSize <= dataByteSizeMax) {
memcpy(rejectBuffer, dataBuffer, packSize);
@ -1203,6 +1448,9 @@ bool IR_DecoderRaw::pulseFilterEmit(const FrontStorage &e)
if (filteredSubBuffer.isFull())
{
pulseFilterDropFilteredOverflow++;
#if IR_RX_BRIEF_LOG
rxBriefLog(RxBriefReason::FilterOverflow, irClampU16(pulseFilterDropFilteredOverflow), 0, e.time);
#endif
return false;
}
filteredSubBuffer.push(e);
@ -1232,6 +1480,9 @@ void IR_DecoderRaw::pulseFilterFeedOneRaw(const FrontStorage &e)
if (pulseFilterHoldCount >= kPulseFilterHoldCap)
{
pulseFilterDropHoldOverflow++;
#if IR_RX_BRIEF_LOG
rxBriefLog(RxBriefReason::HoldOverflow, irClampU16(pulseFilterDropHoldOverflow), 0, e.time);
#endif
pulseFilterEmit(pulseFilterHoldEdges[0]);
pulseFilterShiftLeft(1);
}
@ -1248,6 +1499,9 @@ void IR_DecoderRaw::pulseFilterFeedOneRaw(const FrontStorage &e)
if (dt < minUs)
{
pulseFilterDropGlitchPairs++;
#if IR_RX_BRIEF_LOG
rxBriefLog(RxBriefReason::Glitch, irClampU16(pulseFilterDropGlitchPairs), 0, e.time);
#endif
pulseFilterShiftLeft(2);
continue;
}
@ -1276,6 +1530,9 @@ void IR_DecoderRaw::pulseFilterFlushTimeout(uint32_t nowUs)
if (dt < IR_INPUT_MIN_PULSE_US)
{
pulseFilterDropGlitchPairs++;
#if IR_RX_BRIEF_LOG
rxBriefLog(RxBriefReason::Glitch, irClampU16(pulseFilterDropGlitchPairs), 0, nowUs);
#endif
pulseFilterShiftLeft(2);
continue;
}
@ -1343,7 +1600,12 @@ bool IR_DecoderRaw::preambleProcessEdge(const FrontStorage &front)
if (preambleState == PreambleState::Candidate)
{
if ((uint32_t)(front.time - preambleCandidateLastEdgeTime) > candTimeout)
{
#if IR_RX_BRIEF_LOG
rxBriefLog(RxBriefReason::Preamble, preambleGoodPeriods, 0, front.time);
#endif
preambleStartCandidate(front);
}
preambleCandidateLastEdgeTime = front.time;
if (!front.dir)
@ -1362,6 +1624,9 @@ bool IR_DecoderRaw::preambleProcessEdge(const FrontStorage &front)
{
preambleGoodPeriods = 0;
preambleMeanPeriod = 0;
#if IR_RX_BRIEF_LOG
rxBriefLog(RxBriefReason::Preamble, 0, irClampU16(period), front.time);
#endif
return true;
}
@ -1382,6 +1647,9 @@ bool IR_DecoderRaw::preambleProcessEdge(const FrontStorage &front)
}
else
{
#if IR_RX_BRIEF_LOG
rxBriefLog(RxBriefReason::Preamble, preambleGoodPeriods, irClampU16(period), front.time);
#endif
preambleGoodPeriods = 1;
preambleMeanPeriod = (uint16_t)period;
}