mirror of
https://github.com/Show-maket/IR-protocol.git
synced 2026-04-28 03:08:08 +00:00
common fsm
This commit is contained in:
346
IR_Encoder.cpp
346
IR_Encoder.cpp
@ -50,6 +50,129 @@ IR_Encoder::ExternalTxStartFn IR_Encoder::externalTxStartFn = nullptr;
|
|||||||
IR_Encoder::ExternalTxBusyFn IR_Encoder::externalTxBusyFn = nullptr;
|
IR_Encoder::ExternalTxBusyFn IR_Encoder::externalTxBusyFn = nullptr;
|
||||||
void *IR_Encoder::externalTxCtx = 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;}
|
inline HardwareTimer* IR_Encoder::get_IR_Timer(){return IR_Encoder::IR_Timer;}
|
||||||
|
|
||||||
void IR_Encoder::carrierResume() {
|
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};
|
uint8_t sendBufferLocal[dataByteSizeMax] = {0};
|
||||||
memcpy(sendBufferLocal, packet, len);
|
memcpy(sendBufferLocal, packet, len);
|
||||||
|
|
||||||
uint8_t sendLenLocal = len;
|
TxFsmState st{};
|
||||||
uint8_t toggleCounterLocal = preambToggle;
|
st.sendLen = len;
|
||||||
uint8_t dataBitCounterLocal = bitPerByte - 1;
|
st.toggleCounter = preambToggle;
|
||||||
uint8_t dataByteCounterLocal = 0;
|
st.dataBitCounter = bitPerByte - 1;
|
||||||
uint8_t preambFrontCounterLocal = preambPulse * 2 - 1;
|
st.dataByteCounter = 0;
|
||||||
uint8_t dataSequenceCounterLocal = bitPerByte * 2;
|
st.preambFrontCounter = preambPulse * 2 - 1;
|
||||||
uint8_t syncSequenceCounterLocal = syncBits * 2;
|
st.dataSequenceCounter = bitPerByte * 2;
|
||||||
bool syncLastBitLocal = false;
|
st.syncSequenceCounter = syncBits * 2;
|
||||||
SignalPart signalLocal = preamb;
|
st.syncLastBit = false;
|
||||||
bool stateLocal = HIGH;
|
st.signal = preamb;
|
||||||
uint8_t *currentBitSequenceLocal = bitHigh;
|
st.state = HIGH;
|
||||||
|
st.currentBitSequence = bitHigh;
|
||||||
|
|
||||||
size_t runCount = 0;
|
size_t runCount = 0;
|
||||||
|
bool isActive = true;
|
||||||
while (true)
|
while (isActive)
|
||||||
{
|
{
|
||||||
const bool gate = stateLocal;
|
bool gate = false;
|
||||||
const uint16_t runLenTicks = (uint16_t)toggleCounterLocal + 1U;
|
isActive = txEmitTick(st, sendBufferLocal, gate);
|
||||||
|
|
||||||
if (runCount > 0 && outRuns[runCount - 1].gate == 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
|
else
|
||||||
{
|
{
|
||||||
@ -158,86 +282,11 @@ size_t IR_Encoder::buildGateRuns(const uint8_t *packet, uint8_t len, IR_TxGateRu
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
outRuns[runCount].gate = gate;
|
outRuns[runCount].gate = gate;
|
||||||
outRuns[runCount].lenTicks = runLenTicks;
|
outRuns[runCount].lenTicks = 1U;
|
||||||
runCount++;
|
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;
|
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 (externalTxStartFn != nullptr)
|
||||||
{
|
{
|
||||||
if (externalTxBusyFn != nullptr && externalTxBusyFn(externalTxCtx))
|
if (externalTxBusyFn != nullptr && externalTxBusyFn(externalTxCtx))
|
||||||
@ -586,101 +643,16 @@ void IR_Encoder::_isr()
|
|||||||
port->ODR &= ~(mask);
|
port->ODR &= ~(mask);
|
||||||
port->ODR |= mask & (ir_out_virtual ? (uint16_t)0xFFFF : (uint16_t)0x0000);
|
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--;
|
isSending = false;
|
||||||
}
|
setDecoder_isSending();
|
||||||
else
|
carrierStopPending = true;
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
21
IR_Encoder.h
21
IR_Encoder.h
@ -116,6 +116,27 @@ private:
|
|||||||
sync = 3
|
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 *decPair;
|
||||||
IR_DecoderRaw **blindDecoders;
|
IR_DecoderRaw **blindDecoders;
|
||||||
uint8_t decodersCount;
|
uint8_t decodersCount;
|
||||||
|
|||||||
Reference in New Issue
Block a user