mirror of
https://github.com/Show-maket/IR-protocol.git
synced 2026-04-28 03:08:08 +00:00
fix timer overflow?
This commit is contained in:
@ -77,9 +77,9 @@ void IrFoxDecoder::first_rx()
|
|||||||
|
|
||||||
void IrFoxDecoder::listen_start(double t_us)
|
void IrFoxDecoder::listen_start(double t_us)
|
||||||
{
|
{
|
||||||
(void)t_us;
|
|
||||||
const uint32_t irmax = irfox::irTimeoutUs(rise_sync_time_us);
|
const uint32_t irmax = irfox::irTimeoutUs(rise_sync_time_us);
|
||||||
if (is_recive_raw && (t_us - prev_rise_us) > irmax * 2.0)
|
// Как IR_DecoderRaw::listenStart: пауза по lastEdgeTime, не по prevRise.
|
||||||
|
if (is_recive_raw && last_edge_time_us > 0.0 && (t_us - last_edge_time_us) > irmax * 2.0)
|
||||||
{
|
{
|
||||||
is_recive_raw = false;
|
is_recive_raw = false;
|
||||||
first_rx();
|
first_rx();
|
||||||
@ -93,9 +93,12 @@ void IrFoxDecoder::check_timeout(double t_us)
|
|||||||
const uint32_t irmax = irfox::irTimeoutUs(rise_sync_time_us);
|
const uint32_t irmax = irfox::irTimeoutUs(rise_sync_time_us);
|
||||||
if (t_us - last_edge_time_us > irmax * 2.0)
|
if (t_us - last_edge_time_us > irmax * 2.0)
|
||||||
{
|
{
|
||||||
|
// Как IR_DecoderRaw::checkTimeout после фикса: полный сброс, иначе залипание FSM.
|
||||||
is_recive = false;
|
is_recive = false;
|
||||||
msg_type_receive = 0;
|
msg_type_receive = 0;
|
||||||
last_edge_time_us = t_us;
|
is_recive_raw = false;
|
||||||
|
first_rx();
|
||||||
|
// Не last_edge_time_us = t_us: как IR_DecoderRaw — не расходить с «хвостом» фронтов.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,9 +124,8 @@ void IrFoxDecoder::write_to_buffer(bool bit, bool pack_trace_invert_fix, uint64_
|
|||||||
|
|
||||||
if (is_buffer_overflow || is_preamb || is_wrong_pack)
|
if (is_buffer_overflow || is_preamb || is_wrong_pack)
|
||||||
{
|
{
|
||||||
is_recive = false;
|
// Как IR_DecoderRaw::writeToBuffer: полный first_rx() вместо только сброса флагов приёма.
|
||||||
is_recive_raw = false;
|
first_rx();
|
||||||
msg_type_receive = 0;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -254,7 +256,8 @@ void IrFoxDecoder::processEdge(uint64_t sample, bool rising, uint32_t fs, const
|
|||||||
|
|
||||||
listen_start(t_us);
|
listen_start(t_us);
|
||||||
|
|
||||||
if (have_last_processed && (t_us - last_processed_edge_us) > irmax * 2.0 && is_recive)
|
// Как IR_DecoderRaw: пауза между фронтами по lastEdgeTime при активном приёме кадра.
|
||||||
|
if (last_edge_time_us > 0.0 && (t_us - last_edge_time_us) > irmax * 2.0 && is_recive)
|
||||||
check_timeout(t_us);
|
check_timeout(t_us);
|
||||||
|
|
||||||
last_edge_time_us = t_us;
|
last_edge_time_us = t_us;
|
||||||
@ -354,7 +357,7 @@ void IrFoxDecoder::processEdge(uint64_t sample, bool rising, uint32_t fs, const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// IR_DecoderRaw::tick (STM32DMA): без firstRX(); старт сырого приёма только этим блоком.
|
// Как IR_DecoderRaw::tick: после длинной паузы старт сырого приёма (без отдельного firstRX — флаги ниже).
|
||||||
if (t_us > prev_rise_us && (t_us - prev_rise_us) > irmax * 2.0 && !is_recive_raw)
|
if (t_us > prev_rise_us && (t_us - prev_rise_us) > irmax * 2.0 && !is_recive_raw)
|
||||||
{
|
{
|
||||||
preamb_front_counter = static_cast<int8_t>(irfox::kPreambFronts - 1);
|
preamb_front_counter = static_cast<int8_t>(irfox::kPreambFronts - 1);
|
||||||
@ -583,6 +586,7 @@ void IrFoxDecoder::processEdge(uint64_t sample, bool rising, uint32_t fs, const
|
|||||||
void IrFoxDecoder::flushEnd(uint64_t last_sample, uint32_t fs, const IrFoxOnBit& on_bit, const IrFoxOnPacket& on_pkt)
|
void IrFoxDecoder::flushEnd(uint64_t last_sample, uint32_t fs, const IrFoxOnBit& on_bit, const IrFoxOnPacket& on_pkt)
|
||||||
{
|
{
|
||||||
const double t_us = sample_to_us(last_sample, fs);
|
const double t_us = sample_to_us(last_sample, fs);
|
||||||
|
listen_start(t_us);
|
||||||
check_timeout(t_us);
|
check_timeout(t_us);
|
||||||
(void)on_bit;
|
(void)on_bit;
|
||||||
(void)on_pkt;
|
(void)on_pkt;
|
||||||
|
|||||||
BIN
Analyzer/raw/Session Sync anchor.sal
Normal file
BIN
Analyzer/raw/Session Sync anchor.sal
Normal file
Binary file not shown.
@ -272,22 +272,19 @@ void IR_DecoderRaw::rxBriefFlushDeferredIsrLogs()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
//////////////////////////////////// isr ///////////////////////////////////////////
|
//////////////////////////////////// isr ///////////////////////////////////////////
|
||||||
volatile uint32_t time_;
|
|
||||||
|
|
||||||
void IR_DecoderRaw::isr()
|
void IR_DecoderRaw::isr()
|
||||||
{
|
{
|
||||||
|
// Интервалы между соседними фронтами считаются как (uint32_t)(t1 - t0) — корректно при
|
||||||
|
// паузе < ~35 мин между фронтами; условие «тишина > longSilence» в preambleProcessEdge
|
||||||
|
// переписано без front.time > prevRise (оно ломается при wrap).
|
||||||
|
uint32_t t;
|
||||||
noInterrupts();
|
noInterrupts();
|
||||||
time_ = micros();
|
t = micros();
|
||||||
interrupts();
|
interrupts();
|
||||||
if (time_ < oldTime)
|
|
||||||
{
|
|
||||||
time_ += 1000;
|
|
||||||
}
|
|
||||||
oldTime = time_;
|
|
||||||
|
|
||||||
FrontStorage edge;
|
FrontStorage edge;
|
||||||
edge.dir = port->IDR & mask;
|
edge.dir = port->IDR & mask;
|
||||||
edge.time = time_;
|
edge.time = t;
|
||||||
|
|
||||||
#if defined(IR_EDGE_TRACE)
|
#if defined(IR_EDGE_TRACE)
|
||||||
edgeTracePush(edge.time, edge.dir ? 1u : 0u,
|
edgeTracePush(edge.time, edge.dir ? 1u : 0u,
|
||||||
@ -342,8 +339,20 @@ void IR_DecoderRaw::firstRX()
|
|||||||
preambleResetToIdle();
|
preambleResetToIdle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IR_DecoderRaw::rxTimeoutPipelineBusy() const
|
||||||
|
{
|
||||||
|
if (pulseFilterHoldCount != 0U)
|
||||||
|
return true;
|
||||||
|
noInterrupts();
|
||||||
|
const bool busy = !subBuffer.isEmpty() || !filteredSubBuffer.isEmpty();
|
||||||
|
interrupts();
|
||||||
|
return busy;
|
||||||
|
}
|
||||||
|
|
||||||
void IR_DecoderRaw::listenStart()
|
void IR_DecoderRaw::listenStart()
|
||||||
{
|
{
|
||||||
|
if (rxTimeoutPipelineBusy())
|
||||||
|
return;
|
||||||
if (isReciveRaw && ((micros() - lastEdgeTime) > IR_timeout * 2U))
|
if (isReciveRaw && ((micros() - lastEdgeTime) > IR_timeout * 2U))
|
||||||
{
|
{
|
||||||
#if defined(IRDEBUG_SERIAL_PACK)
|
#if defined(IRDEBUG_SERIAL_PACK)
|
||||||
@ -359,6 +368,8 @@ void IR_DecoderRaw::listenStart()
|
|||||||
inline void IR_DecoderRaw::checkTimeout()
|
inline void IR_DecoderRaw::checkTimeout()
|
||||||
{
|
{
|
||||||
if (!isRecive) return; // уже не принимаем – нечего проверять
|
if (!isRecive) return; // уже не принимаем – нечего проверять
|
||||||
|
if (rxTimeoutPipelineBusy())
|
||||||
|
return;
|
||||||
|
|
||||||
if (micros() - lastEdgeTime > IR_timeout * 2U)
|
if (micros() - lastEdgeTime > IR_timeout * 2U)
|
||||||
{
|
{
|
||||||
@ -371,8 +382,14 @@ inline void IR_DecoderRaw::checkTimeout()
|
|||||||
#endif
|
#endif
|
||||||
isRecive = false; // приём завершён
|
isRecive = false; // приём завершён
|
||||||
msgTypeReceive = 0;
|
msgTypeReceive = 0;
|
||||||
// firstRX(); // подготовка к новому пакету
|
// Как после listenStart(): без сброса isReciveRaw + firstRX() декодер остаётся
|
||||||
lastEdgeTime = micros(); // защита от повторного срабатывания
|
// с «сырым» флагом приёма / Locked и не может заново поймать преамбулу до очень
|
||||||
|
// длинной тишины (см. preambleProcessEdge Idle и listenStart).
|
||||||
|
isReciveRaw = false;
|
||||||
|
firstRX();
|
||||||
|
// Не подставлять lastEdgeTime = micros(): при хвосте в subBuffer следующий фронт
|
||||||
|
// имеет edge.time < micros() — откат lastEdgeTime даёт ложный TIMEOUT на следующем tick().
|
||||||
|
// Повторного checkTimeout при тишине нет: isRecive уже false.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ====================================================================
|
// ====================================================================
|
||||||
@ -382,6 +399,10 @@ void IR_DecoderRaw::tick()
|
|||||||
#if IR_RX_BRIEF_LOG
|
#if IR_RX_BRIEF_LOG
|
||||||
rxBriefFlushDeferredIsrLogs();
|
rxBriefFlushDeferredIsrLogs();
|
||||||
#endif
|
#endif
|
||||||
|
// listenStart/checkTimeout: в конце tick (END) и при отсутствии фронта (ниже).
|
||||||
|
// Не в начале до pop: иначе после checkTimeout lastEdgeTime vs micros() расходятся
|
||||||
|
// с метками ISR из очереди → ложные TIMEOUT (bits=0) каждый пакет.
|
||||||
|
|
||||||
FrontStorage currentFront;
|
FrontStorage currentFront;
|
||||||
bool hasCurrentFront = false;
|
bool hasCurrentFront = false;
|
||||||
FrontStorage rawFront;
|
FrontStorage rawFront;
|
||||||
@ -420,21 +441,8 @@ void IR_DecoderRaw::tick()
|
|||||||
if (!hasCurrentFront)
|
if (!hasCurrentFront)
|
||||||
{
|
{
|
||||||
isSubBufferOverflow = false;
|
isSubBufferOverflow = false;
|
||||||
bool rawQueueHasPending = false;
|
|
||||||
bool filteredQueueHasPending = false;
|
|
||||||
noInterrupts();
|
|
||||||
rawQueueHasPending = !subBuffer.isEmpty();
|
|
||||||
if (IR_INPUT_MIN_PULSE_US > 0U)
|
|
||||||
filteredQueueHasPending = !filteredSubBuffer.isEmpty();
|
|
||||||
interrupts();
|
|
||||||
const bool filterHoldHasPending = (IR_INPUT_MIN_PULSE_US > 0U) && (pulseFilterHoldCount > 0U);
|
|
||||||
const bool hasPendingEdges = hasRawFront || rawQueueHasPending || filteredQueueHasPending || filterHoldHasPending;
|
|
||||||
|
|
||||||
if (!hasPendingEdges)
|
|
||||||
{
|
|
||||||
listenStart();
|
listenStart();
|
||||||
checkTimeout();
|
checkTimeout();
|
||||||
}
|
|
||||||
#if defined(IR_EDGE_TRACE)
|
#if defined(IR_EDGE_TRACE)
|
||||||
while (edgeTraceFlushChunk(Serial, 48) > 0) {}
|
while (edgeTraceFlushChunk(Serial, 48) > 0) {}
|
||||||
#endif
|
#endif
|
||||||
@ -722,6 +730,8 @@ void IR_DecoderRaw::tick()
|
|||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
END:;
|
END:;
|
||||||
|
listenStart();
|
||||||
|
checkTimeout();
|
||||||
#if IR_RX_BRIEF_LOG
|
#if IR_RX_BRIEF_LOG
|
||||||
rxBriefFlushDeferredIsrLogs();
|
rxBriefFlushDeferredIsrLogs();
|
||||||
#endif
|
#endif
|
||||||
@ -748,10 +758,12 @@ void IR_DecoderRaw::writeToBuffer(bool bit, bool packTraceInvertFix)
|
|||||||
}
|
}
|
||||||
if (isBufferOverflow || isPreamb || isWrongPack)
|
if (isBufferOverflow || isPreamb || isWrongPack)
|
||||||
{
|
{
|
||||||
|
// Как checkTimeout/listenStart: firstRX() сбрасывает буфер битов, преамбулу и
|
||||||
|
// pulseFilterReset() — при IR_INPUT_MIN_PULSE_US > 0 иначе остаётся «хвост» в hold/filtered.
|
||||||
isRecive = false;
|
isRecive = false;
|
||||||
isReciveRaw = false;
|
isReciveRaw = false;
|
||||||
preambleResetToIdle();
|
|
||||||
msgTypeReceive = 0;
|
msgTypeReceive = 0;
|
||||||
|
firstRX();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1593,7 +1605,12 @@ bool IR_DecoderRaw::preambleProcessEdge(const FrontStorage &front)
|
|||||||
{
|
{
|
||||||
if (isReciveRaw)
|
if (isReciveRaw)
|
||||||
return false;
|
return false;
|
||||||
if (!isReciveRaw && front.dir && front.time > prevRise && (front.time - prevRise) > longSilence)
|
// Не использовать front.time > prevRise: после переполнения micros (~2^32 µs) новое t
|
||||||
|
// меньше prevRise в unsigned-смысле — преамбула никогда не стартует («залипание» RX).
|
||||||
|
// prevRise == 0: как раньше — «длинная тишина» только по абсолютному front.time > longSilence.
|
||||||
|
if (!isReciveRaw && front.dir &&
|
||||||
|
((prevRise == 0U && front.time > longSilence) ||
|
||||||
|
(prevRise != 0U && (uint32_t)(front.time - prevRise) > longSilence)))
|
||||||
preambleStartCandidate(front);
|
preambleStartCandidate(front);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -181,7 +181,6 @@ private:
|
|||||||
volatile uint32_t highTime;
|
volatile uint32_t highTime;
|
||||||
volatile uint32_t lowTime;
|
volatile uint32_t lowTime;
|
||||||
|
|
||||||
uint32_t oldTime;
|
|
||||||
uint16_t wrongCounter;
|
uint16_t wrongCounter;
|
||||||
|
|
||||||
int8_t highCount;
|
int8_t highCount;
|
||||||
@ -196,6 +195,8 @@ private:
|
|||||||
bool isReciveRaw = false;
|
bool isReciveRaw = false;
|
||||||
void listenStart();
|
void listenStart();
|
||||||
void checkTimeout(); //
|
void checkTimeout(); //
|
||||||
|
/** В очередях/hold фильтра ещё есть фронты — не оценивать таймаут по micros()-lastEdgeTime (ложный TIMEOUT). */
|
||||||
|
bool rxTimeoutPipelineBusy() const;
|
||||||
/** Один сырой фронт из subBuffer -> потоковый holdback-антиглитч. */
|
/** Один сырой фронт из subBuffer -> потоковый holdback-антиглитч. */
|
||||||
void pulseFilterFeedOneRaw(const FrontStorage &e);
|
void pulseFilterFeedOneRaw(const FrontStorage &e);
|
||||||
void pulseFilterFlushTimeout(uint32_t nowUs);
|
void pulseFilterFlushTimeout(uint32_t nowUs);
|
||||||
|
|||||||
@ -35,7 +35,7 @@ IRRX t=1234988 rsn=MUTE_END cnt=42
|
|||||||
| `PREAMB` | Кандидат преамбулы не залочился или был перезапущен | `good`, `per` |
|
| `PREAMB` | Кандидат преамбулы не залочился или был перезапущен | `good`, `per` |
|
||||||
| `SYNC` | Ошибка sync-бита привела к reject кадра | `err` |
|
| `SYNC` | Ошибка sync-бита привела к reject кадра | `err` |
|
||||||
| `BUF` | Переполнен битовый буфер кадра | `bits` |
|
| `BUF` | Переполнен битовый буфер кадра | `bits` |
|
||||||
| `TIMEOUT` | Кадр оборвался по таймауту до завершения | `bits`, `exp` |
|
| `TIMEOUT` | Кадр оборвался по таймауту до завершения; после записи в лог вызываются `isReciveRaw=false` и `firstRX()` (полный сброс декодера) | `bits`, `exp` |
|
||||||
| `CRC` | Кадр дошёл до конца по длине, но CRC не сошёлся | `len`, `err` |
|
| `CRC` | Кадр дошёл до конца по длине, но CRC не сошёлся | `len`, `err` |
|
||||||
| `OK` | Кадр успешно распознан | `len`, `err` |
|
| `OK` | Кадр успешно распознан | `len`, `err` |
|
||||||
|
|
||||||
@ -54,6 +54,8 @@ IRRX t=1234988 rsn=MUTE_END cnt=42
|
|||||||
|
|
||||||
## Когда смотреть подробный debug
|
## Когда смотреть подробный debug
|
||||||
|
|
||||||
|
- `listenStart` / `checkTimeout` — в конце обработки фронта (`END:`) и во ветке «нет фронта» в `tick()`; не в начале до `pop`, иначе после таймаута `lastEdgeTime` расходится с метками ISR из очереди → ложные `TIMEOUT` (`bits=0`).
|
||||||
|
- Пока в `subBuffer` / `filteredSubBuffer` или в hold фильтра есть необработанные фронты, таймаут по `micros() - lastEdgeTime` **не оценивается** (`rxTimeoutPipelineBusy`): иначе при хвосте очереди «тихая пауза» считается слишком длинной и снова ложный `TIMEOUT`.
|
||||||
- Если нужен полный поток битов и sync: включать `IRDEBUG_SERIAL_PACK`
|
- Если нужен полный поток битов и sync: включать `IRDEBUG_SERIAL_PACK`
|
||||||
- Если нужно понять, какие именно фронты пришли в ISR: включать `IR_EDGE_TRACE`
|
- Если нужно понять, какие именно фронты пришли в ISR: включать `IR_EDGE_TRACE`
|
||||||
- `IR_RX_BRIEF_LOG` нужен как короткий always-on-ish индикатор сути проблемы, без длинного дампа
|
- `IR_RX_BRIEF_LOG` нужен как короткий always-on-ish индикатор сути проблемы, без длинного дампа
|
||||||
|
|||||||
@ -161,7 +161,9 @@ class SimState:
|
|||||||
|
|
||||||
|
|
||||||
def first_rx(st: SimState) -> None:
|
def first_rx(st: SimState) -> None:
|
||||||
"""IR_DecoderRaw::firstRX — сброс буфера; isRecive/isReciveRaw в прошивке здесь не меняются."""
|
"""Аналог IR_DecoderRaw::firstRX: сброс буфера битов, преамбулы, счётчиков ошибок по битам.
|
||||||
|
В прошивке isRecive / isReciveRaw сбрасывают вызывающие пути (listenStart, checkTimeout, конец кадра);
|
||||||
|
затем firstRX() обнуляет буфер и preambleResetToIdle()."""
|
||||||
st.is_preamb = True
|
st.is_preamb = True
|
||||||
st.is_wrong_pack = False
|
st.is_wrong_pack = False
|
||||||
st.is_buffer_overflow = False
|
st.is_buffer_overflow = False
|
||||||
@ -188,11 +190,18 @@ def tick(
|
|||||||
rise_max = rise_sync_time + TOLERANCE_US
|
rise_max = rise_sync_time + TOLERANCE_US
|
||||||
irmax = IR_TIMEOUT # упрощ.: без подстройки riseSyncTime в timeout
|
irmax = IR_TIMEOUT # упрощ.: без подстройки riseSyncTime в timeout
|
||||||
|
|
||||||
# listenStart: обрыв незавершённого приёма
|
# listenStart: как IR_DecoderRaw — пауза по lastEdgeTime (между обработанными фронтами), не по prevRise.
|
||||||
if st.is_recive_raw and (t_us - st.prev_rise) > irmax * 2:
|
if st.last_edge > 0 and st.is_recive_raw and (t_us - st.last_edge) > irmax * 2:
|
||||||
st.is_recive_raw = False
|
st.is_recive_raw = False
|
||||||
first_rx(st)
|
first_rx(st)
|
||||||
|
|
||||||
|
# checkTimeout: как IR_DecoderRaw после фикса — isReciveRaw=0 и firstRX(), иначе залипание FSM.
|
||||||
|
if st.last_edge > 0 and st.is_recive and (t_us - st.last_edge) > irmax * 2:
|
||||||
|
st.is_recive = False
|
||||||
|
st.is_recive_raw = False
|
||||||
|
first_rx(st)
|
||||||
|
# Не подставлять last_edge = t_us здесь: как IR_DecoderRaw после фикса.
|
||||||
|
|
||||||
st.last_edge = t_us
|
st.last_edge = t_us
|
||||||
skip_rest = False
|
skip_rest = False
|
||||||
|
|
||||||
@ -307,6 +316,7 @@ def tick(
|
|||||||
if st.is_buffer_overflow or st.is_preamb or st.is_wrong_pack:
|
if st.is_buffer_overflow or st.is_preamb or st.is_wrong_pack:
|
||||||
st.is_recive = False
|
st.is_recive = False
|
||||||
st.is_recive_raw = False
|
st.is_recive_raw = False
|
||||||
|
first_rx(st)
|
||||||
return
|
return
|
||||||
if st.buf_bit_pos == st.next_control_bit:
|
if st.buf_bit_pos == st.next_control_bit:
|
||||||
st.next_control_bit += SYNC_BITS if st.is_data else BIT_PER_BYTE
|
st.next_control_bit += SYNC_BITS if st.is_data else BIT_PER_BYTE
|
||||||
@ -345,7 +355,7 @@ def tick(
|
|||||||
st.packets.append((ok, st.pack_size, bytes(st.data_buffer[: st.pack_size])))
|
st.packets.append((ok, st.pack_size, bytes(st.data_buffer[: st.pack_size])))
|
||||||
st.is_recive = False
|
st.is_recive = False
|
||||||
st.is_recive_raw = False
|
st.is_recive_raw = False
|
||||||
# буфер не чистят здесь — как в IR_DecoderRaw; firstRX по listenStart
|
# Как в IR_DecoderRaw: буфер не чистят на успешном CRC; сброс по listenStart/checkTimeout/firstRX
|
||||||
|
|
||||||
if around_rise_period(st.rise_period, rise_sync_time):
|
if around_rise_period(st.rise_period, rise_sync_time):
|
||||||
if st.high_time > st.low_time:
|
if st.high_time > st.low_time:
|
||||||
|
|||||||
@ -16,7 +16,8 @@ WRONG_PACK_SYNC — отдельное событие с причиной и т
|
|||||||
отброшенных фронтов; без флага эти события только в счётчиках сводки.
|
отброшенных фронтов; без флага эти события только в счётчиках сводки.
|
||||||
|
|
||||||
Не моделирует IRDEBUG_SERIAL_SOFT_REJECT (жёсткий Wrong sync).
|
Не моделирует IRDEBUG_SERIAL_SOFT_REJECT (жёсткий Wrong sync).
|
||||||
Таймауты: между фронтами, если gap > IR_timeout*2 и isRecive — checkTimeout.
|
Таймауты: как IR_DecoderRaw::tick — listenStart и checkTimeout в начале каждого тика (не только при пустых
|
||||||
|
очередях), пауза > IR_timeout*2 по lastEdgeTime; при checkTimeout: isReciveRaw=0, firstRX(), lastEdgeTime=now.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
@ -360,8 +361,8 @@ class DecoderSim:
|
|||||||
|
|
||||||
def listen_start(self, now: int) -> None:
|
def listen_start(self, now: int) -> None:
|
||||||
to = ir_timeout_us(self.rise_sync_time)
|
to = ir_timeout_us(self.rise_sync_time)
|
||||||
if self.is_recive_raw and (now - self.prev_rise) > to * 2:
|
if self.is_recive_raw and self.last_edge_time > 0 and (now - self.last_edge_time) > to * 2:
|
||||||
self.events.append(f"t={now} listenStart abort raw (gap from prev_rise)")
|
self.events.append(f"t={now} listenStart abort raw (gap since last edge, как IR_DecoderRaw)")
|
||||||
self.is_recive_raw = False
|
self.is_recive_raw = False
|
||||||
self._clear_packet_state()
|
self._clear_packet_state()
|
||||||
self.first_rx()
|
self.first_rx()
|
||||||
@ -371,9 +372,12 @@ class DecoderSim:
|
|||||||
return
|
return
|
||||||
to = ir_timeout_us(self.rise_sync_time)
|
to = ir_timeout_us(self.rise_sync_time)
|
||||||
if now - self.last_edge_time > to * 2:
|
if now - self.last_edge_time > to * 2:
|
||||||
self.events.append(f"t={now} checkTimeout (gap since last edge)")
|
self.events.append(f"t={now} checkTimeout -> isReciveRaw=0, firstRX() (как IR_DecoderRaw)")
|
||||||
self.is_recive = False
|
self.is_recive = False
|
||||||
self.last_edge_time = now
|
self.is_recive_raw = False
|
||||||
|
self._clear_packet_state()
|
||||||
|
self.first_rx()
|
||||||
|
# Не last_edge_time = now: в прошивке убрано — расхождение с метками фронтов из очереди.
|
||||||
|
|
||||||
def write_to_buffer(self, bit_val: int) -> None:
|
def write_to_buffer(self, bit_val: int) -> None:
|
||||||
if self.i_data_buffer > DATA_BYTE_SIZE_MAX * 8:
|
if self.i_data_buffer > DATA_BYTE_SIZE_MAX * 8:
|
||||||
@ -382,6 +386,7 @@ class DecoderSim:
|
|||||||
if self.is_buffer_overflow or self.is_preamb or self.is_wrong_pack:
|
if self.is_buffer_overflow or self.is_preamb or self.is_wrong_pack:
|
||||||
self.is_recive = False
|
self.is_recive = False
|
||||||
self.is_recive_raw = False
|
self.is_recive_raw = False
|
||||||
|
self.first_rx()
|
||||||
return
|
return
|
||||||
|
|
||||||
if self.buf_bit_pos == self.next_control_bit:
|
if self.buf_bit_pos == self.next_control_bit:
|
||||||
@ -478,6 +483,9 @@ class DecoderSim:
|
|||||||
def tick_edge(self, t: int, level: int) -> None:
|
def tick_edge(self, t: int, level: int) -> None:
|
||||||
"""Один фронт: level = состояние линии ПОСЛЕ фронта (как dir в C++)."""
|
"""Один фронт: level = состояние линии ПОСЛЕ фронта (как dir в C++)."""
|
||||||
self.listen_start(t)
|
self.listen_start(t)
|
||||||
|
to = ir_timeout_us(self.rise_sync_time)
|
||||||
|
if self.is_recive and self.last_edge_time > 0 and (t - self.last_edge_time) > to * 2:
|
||||||
|
self.check_timeout(t)
|
||||||
self.last_edge_time = t
|
self.last_edge_time = t
|
||||||
rising = level == 1
|
rising = level == 1
|
||||||
|
|
||||||
@ -689,9 +697,6 @@ def main() -> int:
|
|||||||
|
|
||||||
dec = DecoderSim(verbose=args.verbose)
|
dec = DecoderSim(verbose=args.verbose)
|
||||||
for e in edges:
|
for e in edges:
|
||||||
to_us = ir_timeout_us(dec.rise_sync_time)
|
|
||||||
if dec.is_recive and dec.last_edge_time > 0 and (e.t_us - dec.last_edge_time) > to_us * 2:
|
|
||||||
dec.check_timeout(e.t_us)
|
|
||||||
dec.tick_edge(e.t_us, e.level)
|
dec.tick_edge(e.t_us, e.level)
|
||||||
|
|
||||||
print("--- События декодера (первые N), пакеты разделены пустой строкой ---")
|
print("--- События декодера (первые N), пакеты разделены пустой строкой ---")
|
||||||
|
|||||||
Reference in New Issue
Block a user