mirror of
https://github.com/Show-maket/IR-protocol.git
synced 2026-04-28 03:08:08 +00:00
fix overflow and mute
This commit is contained in:
@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user