From ad1e16cfdae272b26b45d9a7c798ae4eb3a3971b Mon Sep 17 00:00:00 2001 From: DashyFox Date: Mon, 13 Apr 2026 14:45:38 +0300 Subject: [PATCH] common fsm --- IR_Encoder.cpp | 346 +++++++++++++++++++++++-------------------------- IR_Encoder.h | 21 +++ 2 files changed, 180 insertions(+), 187 deletions(-) diff --git a/IR_Encoder.cpp b/IR_Encoder.cpp index bf5a372..1d323d2 100644 --- a/IR_Encoder.cpp +++ b/IR_Encoder.cpp @@ -50,6 +50,129 @@ IR_Encoder::ExternalTxStartFn IR_Encoder::externalTxStartFn = nullptr; IR_Encoder::ExternalTxBusyFn IR_Encoder::externalTxBusyFn = nullptr; void *IR_Encoder::externalTxCtx = nullptr; +bool IR_Encoder::txAdvanceBoundary(TxFsmState &st, const uint8_t *sendBufferLocal) +{ + while (true) + { + switch (st.signal) + { + case noSignal: + st.signal = preamb; + return false; + + case preamb: + if (st.preambFrontCounter) + { + st.preambFrontCounter--; + st.toggleCounter = preambToggle; + st.state = !st.state; + return true; + } + st.signal = data; + st.state = !LOW; + continue; + + case data: + if (st.dataSequenceCounter) + { + if (!(st.dataSequenceCounter & 1U)) + { + st.currentBitSequence = + ((sendBufferLocal[st.dataByteCounter] >> st.dataBitCounter) & 1U) ? bitHigh : bitLow; + st.dataBitCounter--; + } + st.toggleCounter = st.currentBitSequence[!st.state]; + st.dataSequenceCounter--; + st.state = !st.state; + return true; + } + st.syncLastBit = ((sendBufferLocal[st.dataByteCounter]) & 1U); + st.dataByteCounter++; + st.dataBitCounter = bitPerByte - 1; + st.dataSequenceCounter = bitPerByte * 2; + st.signal = sync; + continue; + + case sync: + if (st.syncSequenceCounter) + { + if (!(st.syncSequenceCounter & 1U)) + { + if (st.syncSequenceCounter == 2) + { + st.currentBitSequence = ((sendBufferLocal[st.dataByteCounter]) & 0b10000000) ? bitLow : bitHigh; + } + else + { + st.currentBitSequence = st.syncLastBit ? bitLow : bitHigh; + st.syncLastBit = !st.syncLastBit; + } + } + st.toggleCounter = st.currentBitSequence[!st.state]; + st.syncSequenceCounter--; + st.state = !st.state; + return true; + } + st.signal = data; + st.syncSequenceCounter = syncBits * 2; + if (st.dataByteCounter >= st.sendLen) + { + st.signal = noSignal; + } + continue; + + default: + return false; + } + } +} + +bool IR_Encoder::txAdvanceAfterOutput(TxFsmState &st, const uint8_t *sendBufferLocal) +{ + if (st.toggleCounter) + { + st.toggleCounter--; + return true; + } + return txAdvanceBoundary(st, sendBufferLocal); +} + +bool IR_Encoder::txEmitTick(TxFsmState &st, const uint8_t *sendBufferLocal, bool &gateOut) +{ + gateOut = st.state; + return txAdvanceAfterOutput(st, sendBufferLocal); +} + +void IR_Encoder::loadTxFsmFromMembers(TxFsmState &st) const +{ + st.sendLen = sendLen; + st.toggleCounter = toggleCounter; + st.dataBitCounter = dataBitCounter; + st.dataByteCounter = dataByteCounter; + st.preambFrontCounter = preambFrontCounter; + st.dataSequenceCounter = dataSequenceCounter; + st.syncSequenceCounter = syncSequenceCounter; + st.syncLastBit = syncLastBit; + st.state = state; + st.currentBitSequence = currentBitSequence; + st.signal = signal; +} + +void IR_Encoder::storeTxFsmToMembers(const TxFsmState &st) +{ + sendLen = st.sendLen; + toggleCounter = st.toggleCounter; + dataBitCounter = st.dataBitCounter; + dataByteCounter = st.dataByteCounter; + preambFrontCounter = st.preambFrontCounter; + dataSequenceCounter = st.dataSequenceCounter; + syncSequenceCounter = st.syncSequenceCounter; + syncLastBit = st.syncLastBit; + state = st.state; + currentBitSequence = st.currentBitSequence; + signal = st.signal; +} + inline HardwareTimer* IR_Encoder::get_IR_Timer(){return IR_Encoder::IR_Timer;} void IR_Encoder::carrierResume() { @@ -128,28 +251,29 @@ size_t IR_Encoder::buildGateRuns(const uint8_t *packet, uint8_t len, IR_TxGateRu uint8_t sendBufferLocal[dataByteSizeMax] = {0}; memcpy(sendBufferLocal, packet, len); - uint8_t sendLenLocal = len; - uint8_t toggleCounterLocal = preambToggle; - uint8_t dataBitCounterLocal = bitPerByte - 1; - uint8_t dataByteCounterLocal = 0; - uint8_t preambFrontCounterLocal = preambPulse * 2 - 1; - uint8_t dataSequenceCounterLocal = bitPerByte * 2; - uint8_t syncSequenceCounterLocal = syncBits * 2; - bool syncLastBitLocal = false; - SignalPart signalLocal = preamb; - bool stateLocal = HIGH; - uint8_t *currentBitSequenceLocal = bitHigh; + TxFsmState st{}; + st.sendLen = len; + st.toggleCounter = preambToggle; + st.dataBitCounter = bitPerByte - 1; + st.dataByteCounter = 0; + st.preambFrontCounter = preambPulse * 2 - 1; + st.dataSequenceCounter = bitPerByte * 2; + st.syncSequenceCounter = syncBits * 2; + st.syncLastBit = false; + st.signal = preamb; + st.state = HIGH; + st.currentBitSequence = bitHigh; size_t runCount = 0; - - while (true) + bool isActive = true; + while (isActive) { - const bool gate = stateLocal; - const uint16_t runLenTicks = (uint16_t)toggleCounterLocal + 1U; + bool gate = false; + isActive = txEmitTick(st, sendBufferLocal, gate); if (runCount > 0 && outRuns[runCount - 1].gate == gate) { - outRuns[runCount - 1].lenTicks = (uint16_t)(outRuns[runCount - 1].lenTicks + runLenTicks); + outRuns[runCount - 1].lenTicks = (uint16_t)(outRuns[runCount - 1].lenTicks + 1U); } else { @@ -158,86 +282,11 @@ size_t IR_Encoder::buildGateRuns(const uint8_t *packet, uint8_t len, IR_TxGateRu return 0; } outRuns[runCount].gate = gate; - outRuns[runCount].lenTicks = runLenTicks; + outRuns[runCount].lenTicks = 1U; runCount++; } - - // Advance state to the next run boundary (equivalent to ISR iteration when toggleCounter == 0). - while (true) - { - switch (signalLocal) - { - case noSignal: - return runCount; - - case preamb: - if (preambFrontCounterLocal) - { - preambFrontCounterLocal--; - toggleCounterLocal = preambToggle; - break; - } - // End of preamble. - signalLocal = data; - stateLocal = !LOW; - continue; - - case data: - if (dataSequenceCounterLocal) - { - if (!(dataSequenceCounterLocal & 1U)) - { - currentBitSequenceLocal = ((sendBufferLocal[dataByteCounterLocal] >> dataBitCounterLocal) & 1U) ? bitHigh : bitLow; - dataBitCounterLocal--; - } - toggleCounterLocal = currentBitSequenceLocal[!stateLocal]; - dataSequenceCounterLocal--; - break; - } - // End of data byte. - syncLastBitLocal = ((sendBufferLocal[dataByteCounterLocal]) & 1U); - dataByteCounterLocal++; - dataBitCounterLocal = bitPerByte - 1; - dataSequenceCounterLocal = bitPerByte * 2; - signalLocal = sync; - continue; - - case sync: - if (syncSequenceCounterLocal) - { - if (!(syncSequenceCounterLocal & 1U)) - { - if (syncSequenceCounterLocal == 2) - { - currentBitSequenceLocal = ((sendBufferLocal[dataByteCounterLocal]) & 0b10000000) ? bitLow : bitHigh; - } - else - { - currentBitSequenceLocal = syncLastBitLocal ? bitLow : bitHigh; - syncLastBitLocal = !syncLastBitLocal; - } - } - toggleCounterLocal = currentBitSequenceLocal[!stateLocal]; - syncSequenceCounterLocal--; - break; - } - // End of sync. - signalLocal = data; - syncSequenceCounterLocal = syncBits * 2; - if (dataByteCounterLocal >= sendLenLocal) - { - signalLocal = noSignal; - } - continue; - - default: - return 0; - } - - stateLocal = !stateLocal; - break; - } } + return runCount; } @@ -523,6 +572,14 @@ void IR_Encoder::rawSend(uint8_t *ptr, uint8_t len) return; } + Serial.print("IR tx hex: "); + for (uint8_t i = 0; i < len; i++) + { + if (ptr[i] < 0x10) Serial.print("0"); + Serial.print(ptr[i], HEX); + } + Serial.println(); + if (externalTxStartFn != nullptr) { if (externalTxBusyFn != nullptr && externalTxBusyFn(externalTxCtx)) @@ -586,101 +643,16 @@ void IR_Encoder::_isr() port->ODR &= ~(mask); port->ODR |= mask & (ir_out_virtual ? (uint16_t)0xFFFF : (uint16_t)0x0000); - if (toggleCounter) + TxFsmState st{}; + loadTxFsmFromMembers(st); + const bool active = txAdvanceAfterOutput(st, sendBuffer); + storeTxFsmToMembers(st); + + if (!active) { - toggleCounter--; - } - else - { - IsrStart: - switch (signal) - { - case noSignal: - signal = preamb; - // сброс счетчиков - // ... - isSending = false; - // Serial.println("STOP"); - setDecoder_isSending(); - carrierStopPending = true; - // Serial.println(); - return; - break; - - case preamb: - if (preambFrontCounter) - { - preambFrontCounter--; - toggleCounter = preambToggle; // Вторая и последующие генерации для этого signal - } - else - { // Конец преамбулы, переход на следующий signal - signal = data; - state = !LOW; // Инверсное состояние первой генерации следующего signal - goto IsrStart; // Применение новых параметров в этй же итерации прерывания - } - - break; - - case data: - if (dataSequenceCounter) - { - if (!(dataSequenceCounter & 1U)) - { // если чётный - смена бита - currentBitSequence = ((sendBuffer[dataByteCounter] >> dataBitCounter) & 1U) ? bitHigh : bitLow; // определение текущего бита - dataBitCounter--; - } - toggleCounter = currentBitSequence[!state]; - dataSequenceCounter--; - } - else - { // Конец data, переход на следующий signal - syncLastBit = ((sendBuffer[dataByteCounter]) & 1U); - dataByteCounter++; - dataBitCounter = bitPerByte - 1; - dataSequenceCounter = bitPerByte * 2; - signal = sync; - goto IsrStart; // Применение новых параметров в этй же итерации прерывания - } - break; - - case sync: - if (syncSequenceCounter) - { - if (!(syncSequenceCounter & 1U)) - { // если чётный - смена бита - if (syncSequenceCounter == 2) - { // Если последний бит - currentBitSequence = ((sendBuffer[dataByteCounter]) & 0b10000000) ? bitLow : bitHigh; - } - else - { - currentBitSequence = syncLastBit ? bitLow : bitHigh; // определение текущего бита - syncLastBit = !syncLastBit; - } - } - toggleCounter = currentBitSequence[!state]; - syncSequenceCounter--; - } - else - { // Конец sync, переход на следующий signal - signal = data; - syncSequenceCounter = syncBits * 2; - - if (dataByteCounter >= sendLen) - { // определение конца данных - signal = noSignal; - } - goto IsrStart; // Применение новых параметров в этй же итерации прерывания - } - break; - - default: - return; - break; - } - - state = !state; + isSending = false; + setDecoder_isSending(); + carrierStopPending = true; } } diff --git a/IR_Encoder.h b/IR_Encoder.h index f1013de..f3858a9 100644 --- a/IR_Encoder.h +++ b/IR_Encoder.h @@ -116,6 +116,27 @@ private: sync = 3 }; + struct TxFsmState + { + uint8_t sendLen = 0; + uint8_t toggleCounter = 0; + uint8_t dataBitCounter = 0; + uint8_t dataByteCounter = 0; + uint8_t preambFrontCounter = 0; + uint8_t dataSequenceCounter = 0; + uint8_t syncSequenceCounter = 0; + bool syncLastBit = false; + bool state = LOW; + uint8_t *currentBitSequence = nullptr; + SignalPart signal = noSignal; + }; + + 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); + void loadTxFsmFromMembers(TxFsmState &st) const; + void storeTxFsmToMembers(const TxFsmState &st); + IR_DecoderRaw *decPair; IR_DecoderRaw **blindDecoders; uint8_t decodersCount;