mirror of
https://github.com/Show-maket/IR-protocol.git
synced 2026-04-28 03:08:08 +00:00
Merge branch 'main' of https://github.com/Show-maket/IR-protocol
This commit is contained in:
656
IR_Encoder.cpp
656
IR_Encoder.cpp
@ -15,19 +15,14 @@ IR_Encoder::IR_Encoder(uint8_t pin, uint16_t addr, IR_DecoderRaw *decPair, bool
|
||||
setPin(pin);
|
||||
id = addr;
|
||||
this->decPair = decPair;
|
||||
signal = noSignal;
|
||||
isSending = false;
|
||||
#if disablePairDec
|
||||
if (decPair != nullptr)
|
||||
{
|
||||
blindDecoders = new IR_DecoderRaw *[1]{decPair};
|
||||
singleBlindDecoder = decPair;
|
||||
blindDecoders = &singleBlindDecoder;
|
||||
decodersCount = 1;
|
||||
}
|
||||
#endif
|
||||
if (decPair != nullptr)
|
||||
{
|
||||
decPair->encoder = this;
|
||||
}
|
||||
registerWithBlindDecoders();
|
||||
|
||||
if (autoHandle)
|
||||
{
|
||||
@ -43,12 +38,243 @@ IR_Encoder::IR_Encoder(uint8_t pin, uint16_t addr, IR_DecoderRaw *decPair, bool
|
||||
|
||||
pinMode(pin, OUTPUT);
|
||||
}
|
||||
powerNumerator_ = 1;
|
||||
};
|
||||
|
||||
HardwareTimer* IR_Encoder::IR_Timer = nullptr;
|
||||
IR_Encoder::ExternalTxStartFn IR_Encoder::externalTxStartFn = nullptr;
|
||||
IR_Encoder::ExternalTxBusyFn IR_Encoder::externalTxBusyFn = nullptr;
|
||||
void *IR_Encoder::externalTxCtx = nullptr;
|
||||
bool IR_Encoder::txIsrLegacyMode_ = false;
|
||||
uint16_t IR_Encoder::s_carrierMultiply = 2;
|
||||
|
||||
void IR_Encoder::setCarrierMultiply(uint16_t multiply)
|
||||
{
|
||||
if (multiply < 2)
|
||||
{
|
||||
multiply = 2;
|
||||
}
|
||||
s_carrierMultiply = multiply;
|
||||
}
|
||||
|
||||
uint16_t IR_Encoder::carrierMultiply()
|
||||
{
|
||||
return s_carrierMultiply;
|
||||
}
|
||||
|
||||
void IR_Encoder::retuneCarrierClock()
|
||||
{
|
||||
if (IR_Timer == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
IR_Timer->pause();
|
||||
IR_Timer->setOverflow((uint32_t)carrierFrec * (uint32_t)s_carrierMultiply, HERTZ_FORMAT);
|
||||
IR_Timer->pause();
|
||||
}
|
||||
|
||||
uint16_t IR_Encoder::maxPowerNumerator()
|
||||
{
|
||||
return static_cast<uint16_t>(s_carrierMultiply / 2U);
|
||||
}
|
||||
|
||||
void IR_Encoder::setPowerNumerator(uint16_t n)
|
||||
{
|
||||
const uint16_t cap = maxPowerNumerator();
|
||||
powerNumerator_ = (n > cap) ? cap : n;
|
||||
}
|
||||
|
||||
void IR_Encoder::setPowerPercent(uint8_t p)
|
||||
{
|
||||
if (p > 100U)
|
||||
{
|
||||
p = 100U;
|
||||
}
|
||||
const uint16_t cap = maxPowerNumerator();
|
||||
const uint32_t n = ((uint32_t)p * (uint32_t)cap + 50U) / 100U;
|
||||
powerNumerator_ = static_cast<uint16_t>(n);
|
||||
}
|
||||
|
||||
uint16_t IR_Encoder::powerNumerator() const
|
||||
{
|
||||
return powerNumerator_;
|
||||
}
|
||||
|
||||
bool IR_Encoder::scaleGateRunsToPhysical(IR_TxGateRun* runs, size_t* ioCount, size_t maxRuns, uint16_t multiply)
|
||||
{
|
||||
if (runs == nullptr || ioCount == nullptr || maxRuns == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (multiply < 2)
|
||||
{
|
||||
multiply = 2;
|
||||
}
|
||||
const size_t nIn = *ioCount;
|
||||
if (nIn > irproto::kIsrTxMaxGateRuns)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
IrTxGateRun copy[irproto::kIsrTxMaxGateRuns];
|
||||
memcpy(copy, runs, nIn * sizeof(IrTxGateRun));
|
||||
size_t w = 0;
|
||||
for (size_t r = 0; r < nIn; r++)
|
||||
{
|
||||
uint32_t phys = (uint32_t)copy[r].lenTicks * (uint32_t)multiply / 2U;
|
||||
if (copy[r].lenTicks > 0 && phys == 0)
|
||||
{
|
||||
phys = 1;
|
||||
}
|
||||
const bool g = copy[r].gate;
|
||||
while (phys > 0)
|
||||
{
|
||||
if (w >= maxRuns)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
const uint32_t chunk = phys > 65535U ? 65535U : phys;
|
||||
runs[w].lenTicks = static_cast<uint16_t>(chunk);
|
||||
runs[w].gate = g;
|
||||
w++;
|
||||
phys -= chunk;
|
||||
}
|
||||
}
|
||||
*ioCount = w;
|
||||
return true;
|
||||
}
|
||||
|
||||
void IR_Encoder::setTxIsrLegacyMode(bool legacy)
|
||||
{
|
||||
txIsrLegacyMode_ = legacy;
|
||||
}
|
||||
|
||||
bool IR_Encoder::txIsrLegacyMode()
|
||||
{
|
||||
return txIsrLegacyMode_;
|
||||
}
|
||||
|
||||
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;}
|
||||
|
||||
@ -76,7 +302,7 @@ void IR_Encoder::begin(HardwareTimer* timer, uint8_t channel, IRQn_Type IRQn, ui
|
||||
IR_Timer = timer;
|
||||
if(IR_Timer == nullptr) return;
|
||||
IR_Timer->pause();
|
||||
IR_Timer->setOverflow(carrierFrec * 2, HERTZ_FORMAT);
|
||||
IR_Timer->setOverflow((uint32_t)carrierFrec * (uint32_t)s_carrierMultiply, HERTZ_FORMAT);
|
||||
IR_Timer->attachInterrupt(channel, (isrCallback == nullptr ? IR_Encoder::isr : isrCallback));
|
||||
NVIC_SetPriority(IRQn, priority);
|
||||
IR_Timer->pause();
|
||||
@ -88,7 +314,7 @@ void IR_Encoder::beginClockOnly(HardwareTimer *timer)
|
||||
if (IR_Timer == nullptr)
|
||||
return;
|
||||
IR_Timer->pause();
|
||||
IR_Timer->setOverflow(carrierFrec * 2, HERTZ_FORMAT);
|
||||
IR_Timer->setOverflow((uint32_t)carrierFrec * (uint32_t)s_carrierMultiply, HERTZ_FORMAT);
|
||||
IR_Timer->pause();
|
||||
}
|
||||
|
||||
@ -110,7 +336,7 @@ void IR_Encoder::externalFinishSend()
|
||||
}
|
||||
|
||||
isSending = false;
|
||||
setDecoder_isSending();
|
||||
refreshBlindDecoderMuteState();
|
||||
}
|
||||
|
||||
size_t IR_Encoder::buildGateRuns(const uint8_t *packet, uint8_t len, IR_TxGateRun *outRuns, size_t maxRuns)
|
||||
@ -128,28 +354,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 +385,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;
|
||||
}
|
||||
|
||||
|
||||
@ -302,12 +454,16 @@ void IR_Encoder::disable()
|
||||
|
||||
void IR_Encoder::setBlindDecoders(IR_DecoderRaw *decoders[], uint8_t count)
|
||||
{
|
||||
#if disablePairDec
|
||||
if (blindDecoders != nullptr)
|
||||
delete[] blindDecoders;
|
||||
#endif
|
||||
if (count > IR_PAIR_MUTE_MAX_ENCODERS)
|
||||
{
|
||||
decodersCount = 0;
|
||||
blindDecoders = nullptr;
|
||||
return;
|
||||
}
|
||||
decodersCount = count;
|
||||
blindDecoders = decoders;
|
||||
registerWithBlindDecoders();
|
||||
refreshBlindDecoderMuteState();
|
||||
}
|
||||
|
||||
IR_Encoder::~IR_Encoder(){};
|
||||
@ -466,7 +622,7 @@ IR_SendResult IR_Encoder::_sendBack(bool isAdressed, uint16_t addrTo, uint8_t *d
|
||||
|
||||
uint8_t packSize = msgBytes + addrBytes + (isAdressed ? addrBytes : 0) + min(uint8_t(1), len) + crcBytes;
|
||||
uint8_t msgType =
|
||||
((isAdressed ? IR_MSG_BACK_TO : IR_MSG_BACK) << 5) | ((packSize) & (IR_MASK_MSG_INFO >> 1));
|
||||
((isAdressed ? IR_MSG_BACK_TO : IR_MSG_BACK) << 5) | ((packSize) & IR_MASK_MSG_INFO);
|
||||
|
||||
// формирование массива
|
||||
// msg_type
|
||||
@ -497,18 +653,27 @@ IR_SendResult IR_Encoder::_sendBack(bool isAdressed, uint16_t addrTo, uint8_t *d
|
||||
return IR_SendResult(true, sendTime);
|
||||
}
|
||||
|
||||
void IR_Encoder::setDecoder_isSending()
|
||||
void IR_Encoder::registerWithBlindDecoders()
|
||||
{
|
||||
if (decodersCount)
|
||||
if (!decodersCount || blindDecoders == nullptr)
|
||||
return;
|
||||
|
||||
for (uint8_t i = 0; i < decodersCount; i++)
|
||||
{
|
||||
for (uint8_t i = 0; i < decodersCount; i++)
|
||||
{
|
||||
blindDecoders[i]->isPairSending ^= id;
|
||||
// Serial.print("setDecoder_isSending() id = ");
|
||||
// Serial.print(id);
|
||||
// Serial.print(" isPairSending = ");
|
||||
// Serial.println(blindDecoders[i]->isPairSending);
|
||||
}
|
||||
if (blindDecoders[i] != nullptr)
|
||||
blindDecoders[i]->registerPairMuteEncoder(this);
|
||||
}
|
||||
}
|
||||
|
||||
void IR_Encoder::refreshBlindDecoderMuteState()
|
||||
{
|
||||
if (!decodersCount || blindDecoders == nullptr)
|
||||
return;
|
||||
|
||||
for (uint8_t i = 0; i < decodersCount; i++)
|
||||
{
|
||||
if (blindDecoders[i] != nullptr)
|
||||
blindDecoders[i]->refreshPairMuteState();
|
||||
}
|
||||
}
|
||||
|
||||
@ -526,6 +691,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))
|
||||
@ -533,40 +706,98 @@ void IR_Encoder::rawSend(uint8_t *ptr, uint8_t len)
|
||||
return;
|
||||
}
|
||||
|
||||
// Mark as sending and delegate actual signal output to external backend.
|
||||
setDecoder_isSending();
|
||||
sendLen = len;
|
||||
isSending = true;
|
||||
refreshBlindDecoderMuteState();
|
||||
|
||||
const bool ok = externalTxStartFn(externalTxCtx, this, ptr, len);
|
||||
if (!ok)
|
||||
{
|
||||
isSending = false;
|
||||
setDecoder_isSending();
|
||||
refreshBlindDecoderMuteState();
|
||||
}
|
||||
return;
|
||||
}
|
||||
IR_Encoder::carrierResume();
|
||||
// Serial.println("START");
|
||||
setDecoder_isSending();
|
||||
|
||||
// noInterrupts();
|
||||
if (port == nullptr || mask == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (ptr != sendBuffer)
|
||||
{
|
||||
memcpy(sendBuffer, ptr, len);
|
||||
}
|
||||
sendLen = len;
|
||||
toggleCounter = preambToggle; // Первая генерация для первого signal
|
||||
|
||||
dataBitCounter = bitPerByte - 1;
|
||||
dataByteCounter = 0;
|
||||
if (txIsrLegacyMode_)
|
||||
{
|
||||
toggleCounter = preambToggle;
|
||||
dataBitCounter = bitPerByte - 1;
|
||||
dataByteCounter = 0;
|
||||
preambFrontCounter = preambPulse * 2 - 1;
|
||||
dataSequenceCounter = bitPerByte * 2;
|
||||
syncSequenceCounter = syncBits * 2;
|
||||
signal = preamb;
|
||||
state = HIGH;
|
||||
currentBitSequence = bitHigh;
|
||||
txMultiplySnap_ = carrierMultiply();
|
||||
{
|
||||
const uint16_t cap = maxPowerNumerator();
|
||||
txPowerSnap_ = (powerNumerator_ > cap) ? cap : powerNumerator_;
|
||||
}
|
||||
legacyPhysPerLogical_ = static_cast<uint16_t>(txMultiplySnap_ / 2U);
|
||||
if (legacyPhysPerLogical_ == 0)
|
||||
{
|
||||
legacyPhysPerLogical_ = 1;
|
||||
}
|
||||
legacyPhysCounter_ = 0;
|
||||
legacySlotInPeriod_ = 0;
|
||||
isSending = true;
|
||||
refreshBlindDecoderMuteState();
|
||||
IR_Encoder::carrierResume();
|
||||
return;
|
||||
}
|
||||
|
||||
preambFrontCounter = preambPulse * 2 - 1; // -1 за счёт генерации уже на этапе сразу после инициализации
|
||||
dataSequenceCounter = bitPerByte * 2;
|
||||
syncSequenceCounter = syncBits * 2;
|
||||
size_t nRuns = buildGateRuns(sendBuffer, len, txGateRuns_, irproto::kIsrTxMaxGateRuns);
|
||||
if (nRuns == 0U)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!scaleGateRunsToPhysical(txGateRuns_, &nRuns, irproto::kIsrTxMaxGateRuns, carrierMultiply()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t total = 0;
|
||||
for (size_t i = 0; i < nRuns; i++)
|
||||
{
|
||||
total += txGateRuns_[i].lenTicks;
|
||||
}
|
||||
txBsrrTotalTicks_ = total;
|
||||
|
||||
const uint32_t setW = (uint32_t)mask;
|
||||
const uint32_t resetW = ((uint32_t)mask) << 16U;
|
||||
txMultiplySnap_ = carrierMultiply();
|
||||
{
|
||||
const uint16_t cap = maxPowerNumerator();
|
||||
txPowerSnap_ = (powerNumerator_ > cap) ? cap : powerNumerator_;
|
||||
}
|
||||
txBsrrWave_.configure(setW, resetW, txGateRuns_, nRuns, txMultiplySnap_, txPowerSnap_);
|
||||
|
||||
txBsrrHalfLen_ = (uint16_t)(irproto::kIsrTxBsrrWordCount / 2U);
|
||||
txBsrrWave_.fill(txBsrrWords_, irproto::kIsrTxBsrrWordCount);
|
||||
|
||||
txBsrrReadIdx_ = 0;
|
||||
txBsrrTicksSent_ = 0;
|
||||
|
||||
signal = preamb;
|
||||
isSending = true;
|
||||
state = HIGH;
|
||||
|
||||
currentBitSequence = bitHigh;
|
||||
// interrupts();
|
||||
refreshBlindDecoderMuteState();
|
||||
if (port != nullptr)
|
||||
{
|
||||
port->BSRR = resetW;
|
||||
}
|
||||
IR_Encoder::carrierResume();
|
||||
}
|
||||
|
||||
void IR_Encoder::isr()
|
||||
@ -584,106 +815,71 @@ void IR_Encoder::_isr()
|
||||
if (!isSending)
|
||||
return;
|
||||
|
||||
ir_out_virtual = !ir_out_virtual && state;
|
||||
if (port == nullptr)
|
||||
return;
|
||||
|
||||
port->ODR &= ~(mask);
|
||||
port->ODR |= mask & (ir_out_virtual ? (uint16_t)0xFFFF : (uint16_t)0x0000);
|
||||
|
||||
if (toggleCounter)
|
||||
if (txIsrLegacyMode_)
|
||||
{
|
||||
toggleCounter--;
|
||||
}
|
||||
else
|
||||
{
|
||||
IsrStart:
|
||||
switch (signal)
|
||||
const uint32_t setW = (uint32_t)mask;
|
||||
const uint32_t resetW = ((uint32_t)mask) << 16U;
|
||||
if (!state)
|
||||
{
|
||||
case noSignal:
|
||||
signal = preamb;
|
||||
// сброс счетчиков
|
||||
// ...
|
||||
isSending = false;
|
||||
// Serial.println("STOP");
|
||||
setDecoder_isSending();
|
||||
carrierStopPending = true;
|
||||
// Serial.println();
|
||||
return;
|
||||
break;
|
||||
|
||||
case preamb:
|
||||
if (preambFrontCounter)
|
||||
port->BSRR = resetW;
|
||||
legacySlotInPeriod_ = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
port->BSRR = (legacySlotInPeriod_ < txPowerSnap_) ? setW : resetW;
|
||||
legacySlotInPeriod_++;
|
||||
if (legacySlotInPeriod_ >= txMultiplySnap_)
|
||||
{
|
||||
preambFrontCounter--;
|
||||
toggleCounter = preambToggle; // Вторая и последующие генерации для этого signal
|
||||
legacySlotInPeriod_ = 0;
|
||||
}
|
||||
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;
|
||||
legacyPhysCounter_++;
|
||||
if (legacyPhysCounter_ < legacyPhysPerLogical_)
|
||||
{
|
||||
return;
|
||||
}
|
||||
legacyPhysCounter_ = 0;
|
||||
|
||||
TxFsmState st{};
|
||||
loadTxFsmFromMembers(st);
|
||||
const bool active = txAdvanceAfterOutput(st, sendBuffer);
|
||||
storeTxFsmToMembers(st);
|
||||
|
||||
if (!active)
|
||||
{
|
||||
port->BSRR = resetW;
|
||||
isSending = false;
|
||||
refreshBlindDecoderMuteState();
|
||||
carrierStopPending = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
port->BSRR = txBsrrWords_[txBsrrReadIdx_];
|
||||
txBsrrReadIdx_++;
|
||||
txBsrrTicksSent_++;
|
||||
|
||||
if (txBsrrTicksSent_ >= txBsrrTotalTicks_)
|
||||
{
|
||||
port->BSRR = ((uint32_t)mask) << 16U;
|
||||
isSending = false;
|
||||
refreshBlindDecoderMuteState();
|
||||
carrierStopPending = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (txBsrrReadIdx_ == txBsrrHalfLen_)
|
||||
{
|
||||
txBsrrWave_.fill(&txBsrrWords_[0], txBsrrHalfLen_);
|
||||
}
|
||||
else if (txBsrrReadIdx_ >= irproto::kIsrTxBsrrWordCount)
|
||||
{
|
||||
txBsrrReadIdx_ = 0;
|
||||
txBsrrWave_.fill(&txBsrrWords_[txBsrrHalfLen_], txBsrrHalfLen_);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user