mirror of
https://github.com/Show-maket/IR-protocol.git
synced 2026-09-21 20:39:35 +00:00
Make IR timing and RX terminal state explicit
This commit is contained in:
@ -25,7 +25,30 @@ class Print;
|
||||
#define riseTimeMin (riseTime - riseTolerance)
|
||||
#define aroundRise(t) (riseTimeMin < t && t < riseTimeMax)
|
||||
#define IR_timeout (riseTimeMax * (8 + syncBits + 1)) // us // таймаут в 8 data + 3 sync + 1
|
||||
constexpr uint16_t IR_ResponseDelay = ((uint16_t)(((bitTime+riseTolerance) * (8 + syncBits + 1))*2.7735))/1000;
|
||||
constexpr uint16_t IR_ResponseDelay = irproto::kMandatoryInterPacketQuietMs;
|
||||
|
||||
/** Why the most recent observable receive attempt reached a terminal state. */
|
||||
enum class IR_RxTerminalReason : uint8_t
|
||||
{
|
||||
None = 0,
|
||||
FrameOk,
|
||||
FrameCrcError,
|
||||
LockedTimeout,
|
||||
DecodeAbort,
|
||||
CandidateTimeout
|
||||
};
|
||||
|
||||
/**
|
||||
* Monotonic receive-completion snapshot for schedulers polling after decoder.tick().
|
||||
* seq is allowed to wrap; consumers only compare it with their previous snapshot.
|
||||
*/
|
||||
struct IR_RxTerminalInfo
|
||||
{
|
||||
uint32_t seq = 0;
|
||||
IR_RxTerminalReason reason = IR_RxTerminalReason::None;
|
||||
uint8_t msgType = 0xFFU;
|
||||
bool hadLock = false;
|
||||
};
|
||||
|
||||
class IR_Encoder;
|
||||
class IR_DecoderRaw : virtual public IR_FOX
|
||||
@ -52,14 +75,28 @@ public:
|
||||
inline bool isOverflow() { return isBufferOverflow; }; // Буффер переполнился
|
||||
bool isSubOverflow();
|
||||
volatile inline bool isReciving() { return isRecive; }; // Возвращает true, если происходит приём пакета
|
||||
// Активность линии по СОСТОЯНИЮ (не по хардкод-длительности): кадр залочен ИЛИ формируется
|
||||
// ВАЛИДНАЯ преамбула (>=1 совпавший по периоду фронт — отличает реальный кадр от одиночного
|
||||
// шумового фронта, который лишь заводит Candidate, но не набирает goodPeriods). Для гейта заднего:
|
||||
// «не стрелять, пока на линии идёт/формируется кадр (напр. ответ точки)». Аддитивно, const.
|
||||
// Активность линии по СОСТОЯНИЮ (не по хардкод-длительности): кадр залочен ИЛИ открыт
|
||||
// Candidate после первого post-silence rise. Даже сильно искажённый ответ может не дать ни
|
||||
// одного coarse-valid периода, поэтому Candidate остаётся активным до lock/terminal либо
|
||||
// доказанной тишины по candidate timeout. Для гейта заднего: «не стрелять, пока на линии
|
||||
// идёт/формируется потенциальный кадр (напр. ответ точки)». Аддитивно, const.
|
||||
inline bool rxLineActive() const {
|
||||
return isRecive ||
|
||||
(preambleState == PreambleState::Candidate && preambleGoodPeriods >= 1U);
|
||||
(preambleState == PreambleState::Candidate && preambleWasObservable);
|
||||
}
|
||||
/**
|
||||
* True while a real frame is active or ISR/filter work is still queued.
|
||||
* This closes the one-loop ordering gap when Timer::tick() runs before
|
||||
* decoder.tick(): a transmitter must not start while an unprocessed edge
|
||||
* is already waiting in the receive pipeline.
|
||||
*/
|
||||
bool rxPipelineActive() const;
|
||||
/**
|
||||
* Last terminal RX transition. Updated from tick()/decode context, never from ISR.
|
||||
* A frame that starts and finishes within one tick is observable through seq.
|
||||
*/
|
||||
IR_RxTerminalInfo rxLastTerminal() const { return rxTerminalInfo; }
|
||||
uint32_t rxTerminalSeq() const { return rxTerminalInfo.seq; }
|
||||
// Объявленная длина ПРИНИМАЕМОГО кадра (байт) из ПЕРВОГО байта, если он уже принят и валиден;
|
||||
// иначе 0 (ещё не знаем / битый). До CRC это НЕДОВЕРЕННОЕ значение — потребитель, получив 0
|
||||
// или чрезмерное, обязан брать rxMaxPackSize() (безопасно держать задний до конца макс.кадра).
|
||||
@ -67,7 +104,9 @@ public:
|
||||
return (isRecive && packSize && !isWrongPack) ? packSize : 0;
|
||||
}
|
||||
// Протокольный МАКСИМУМ длины кадра (байт) — верхняя граница бюджета удержания заднего.
|
||||
static constexpr uint16_t rxMaxPackSize() { return (uint16_t)dataByteSizeMax; }
|
||||
static constexpr uint16_t rxMaxPackSize() {
|
||||
return static_cast<uint16_t>(irproto::kMaxWireFrameBytes);
|
||||
}
|
||||
uint32_t pulseFilterDroppedByFilteredOverflow() const { return 0; }
|
||||
uint32_t pulseFilterDroppedByHoldOverflow() const { return pulseFilterDropHoldOverflow; }
|
||||
uint32_t pulseFilterDroppedGlitchPairs() const { return pulseFilterDropGlitchPairs; }
|
||||
@ -127,6 +166,7 @@ private:
|
||||
volatile bool isSubBufferOverflow = false;
|
||||
bool isBufferOverflow = false; // Флаг переполнения буффера данных
|
||||
bool isWrongPack = false; // Флаг битого пакета
|
||||
IR_RxTerminalInfo rxTerminalInfo;
|
||||
|
||||
uint16_t riseSyncTime = bitTime; // Подстраиваемое время бита в мкс
|
||||
|
||||
@ -164,6 +204,10 @@ private:
|
||||
};
|
||||
PreambleState preambleState = PreambleState::Idle;
|
||||
uint8_t preambleGoodPeriods = 0;
|
||||
// Sticky potential-frame latch for one Candidate epoch. After one plausible
|
||||
// rise period, coarse-invalid activity remains busy until proven silence;
|
||||
// the scheduler's hard deadline may skip an optional tail under noise.
|
||||
bool preambleWasObservable = false;
|
||||
uint16_t preambleMeanPeriod = 0;
|
||||
uint32_t preambleCandidateLastEdgeTime = 0;
|
||||
uint32_t preambleCandidateFirstRiseTime = 0;
|
||||
@ -232,6 +276,9 @@ bool isReciveRaw = false;
|
||||
void preambleResetToIdle();
|
||||
void preambleStartCandidate(const FrontStorage &front);
|
||||
bool preambleProcessEdge(const FrontStorage &front);
|
||||
void expirePreambleCandidateIfIdle(uint32_t nowUs);
|
||||
uint8_t currentRxMsgType() const;
|
||||
void noteRxTerminal(IR_RxTerminalReason reason, uint8_t msgType, bool hadLock);
|
||||
|
||||
/// @brief Проверка CRC. Проверяет len байт со значением crc, пришедшим в пакете
|
||||
/// @param len Длина в байтах проверяемых данных
|
||||
|
||||
Reference in New Issue
Block a user