diff --git a/IR_Encoder.cpp b/IR_Encoder.cpp index 8663ccb..62ec179 100644 --- a/IR_Encoder.cpp +++ b/IR_Encoder.cpp @@ -352,6 +352,29 @@ bool IR_Encoder::txEmitTick(TxFsmState &st, const uint8_t *sendBufferLocal, bool return txAdvanceAfterOutput(st, sendBufferLocal); } +// Обход кадра по границам ранов: между границами автомат выдаёт st.toggleCounter+1 тактов +// уровня st.state (txAdvanceAfterOutput считает toggleCounter до нуля, затем txAdvanceBoundary +// открывает следующий ран). Даёт ту же последовательность тактов, что потиковый обход, но за +// число шагов = число ранов (пинг: ~230 вместо ~8700 тактов — на 12 МГц это ~30 мс перед стартом DMA). +template +bool IR_Encoder::txWalkRuns(TxFsmState &st, const uint8_t *sendBufferLocal, Emit emit) +{ + for (;;) + { + const bool gate = st.state; + const uint32_t lenTicks = (uint32_t)st.toggleCounter + 1U; + if (!emit(gate, lenTicks)) + { + return false; + } + st.toggleCounter = 0; + if (!txAdvanceBoundary(st, sendBufferLocal)) + { + return true; + } + } +} + void IR_Encoder::loadTxFsmFromMembers(TxFsmState &st) const { st.sendLen = sendLen; @@ -476,28 +499,27 @@ size_t IR_Encoder::buildGateRuns(const uint8_t *packet, uint8_t len, IR_TxGateRu st.currentBitSequence = bitHigh; size_t runCount = 0; - bool isActive = true; - while (isActive) - { - bool gate = false; - isActive = txEmitTick(st, sendBufferLocal, gate); - + const bool ok = txWalkRuns(st, sendBufferLocal, [&](bool gate, uint32_t lenTicks) -> bool { if (runCount > 0 && outRuns[runCount - 1].gate == gate) { - outRuns[runCount - 1].lenTicks = (uint16_t)(outRuns[runCount - 1].lenTicks + 1U); - } - else - { - if (runCount >= maxRuns) + const uint32_t merged = (uint32_t)outRuns[runCount - 1].lenTicks + lenTicks; + if (merged > 65535U) { - return 0; + return false; } - outRuns[runCount].gate = gate; - outRuns[runCount].lenTicks = 1U; - runCount++; + outRuns[runCount - 1].lenTicks = (uint16_t)merged; + return true; } - } - return runCount; + if (runCount >= maxRuns || lenTicks > 65535U) + { + return false; + } + outRuns[runCount].gate = gate; + outRuns[runCount].lenTicks = (uint16_t)lenTicks; + runCount++; + return true; + }); + return ok ? runCount : 0; } size_t IR_Encoder::buildPhysicalGateRuns(const uint8_t *packet, uint8_t len, IR_TxGateRun *outRuns, size_t maxRuns, uint16_t multiply) @@ -564,40 +586,29 @@ size_t IR_Encoder::buildPhysicalGateRuns(const uint8_t *packet, uint8_t len, IR_ bool currentGate = false; uint32_t currentLogicalLen = 0; bool havePendingRun = false; - bool isActive = true; - while (isActive) - { - bool gate = false; - isActive = txEmitTick(st, sendBufferLocal, gate); - - if (!havePendingRun) + const bool ok = txWalkRuns(st, sendBufferLocal, [&](bool gate, uint32_t lenTicks) -> bool { + if (havePendingRun && currentGate == gate) { - currentGate = gate; - currentLogicalLen = 1U; - havePendingRun = true; - continue; + currentLogicalLen += lenTicks; + return true; } - - if (currentGate == gate) + if (havePendingRun && !appendPhysicalRun(currentGate, currentLogicalLen, runCount)) { - currentLogicalLen++; - continue; + return false; } - - if (!appendPhysicalRun(currentGate, currentLogicalLen, runCount)) - { - return 0; - } - currentGate = gate; - currentLogicalLen = 1U; + currentLogicalLen = lenTicks; + havePendingRun = true; + return true; + }); + if (!ok) + { + return 0; } - if (havePendingRun && !appendPhysicalRun(currentGate, currentLogicalLen, runCount)) { return 0; } - return runCount; } diff --git a/IR_Encoder.h b/IR_Encoder.h index af097cf..df55d86 100644 --- a/IR_Encoder.h +++ b/IR_Encoder.h @@ -214,6 +214,8 @@ private: static bool txAdvanceBoundary(TxFsmState &st, const uint8_t *sendBufferLocal); static bool txAdvanceAfterOutput(TxFsmState &st, const uint8_t *sendBufferLocal); static bool txEmitTick(TxFsmState &st, const uint8_t *sendBufferLocal, bool &gateOut); + template + static bool txWalkRuns(TxFsmState &st, const uint8_t *sendBufferLocal, Emit emit); void loadTxFsmFromMembers(TxFsmState &st) const; void storeTxFsmToMembers(const TxFsmState &st); bool shouldUseBufferedIsr() const;