Files
IR-protocol/IR_Encoder.cpp
DashyFox b4f644c258 Align main with fix-DMA-and-Analyzer (encoder API, sketch, .gitignore)
Restore IR_SendResult + sendDataFULL, fix IR-protocol.ino, match .gitignore to analyzer branch.

Made-with: Cursor
2026-04-17 15:07:54 +03:00

1018 lines
27 KiB
C++

#include "IR_Encoder.h"
#include "IR_DecoderRaw.h"
#include <string.h>
#define LoopOut 12
#define ISR_Out 10
#define TestOut 13
IR_Encoder *IR_Encoder::head = nullptr;
IR_Encoder *IR_Encoder::last = nullptr;
volatile bool IR_Encoder::carrierStopPending = false;
IR_Encoder::IR_Encoder(uint8_t pin, uint16_t addr, IR_DecoderRaw *decPair, bool autoHandle)
{
setPin(pin);
id = addr;
this->decPair = decPair;
if (decPair != nullptr)
{
singleBlindDecoder = decPair;
blindDecoders = &singleBlindDecoder;
decodersCount = 1;
decPair->encoder = this;
}
registerWithBlindDecoders();
if (autoHandle)
{
if (IR_Encoder::head == nullptr)
{
IR_Encoder::head = this;
}
if (last != nullptr)
{
last->next = this;
}
last = this;
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;}
void IR_Encoder::carrierResume() {
if (IR_Timer != nullptr)
IR_Timer->resume();
}
void IR_Encoder::carrierPauseIfIdle() {
for (IR_Encoder *p = head; p != nullptr; p = p->next)
if (p->isSending)
return;
if (IR_Timer != nullptr)
IR_Timer->pause();
}
void IR_Encoder::tick() {
if (!carrierStopPending)
return;
carrierStopPending = false;
carrierPauseIfIdle();
}
void IR_Encoder::begin(HardwareTimer* timer, uint8_t channel, IRQn_Type IRQn, uint8_t priority, void(*isrCallback)()){
IR_Timer = timer;
if(IR_Timer == nullptr) return;
IR_Timer->pause();
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();
}
void IR_Encoder::beginClockOnly(HardwareTimer *timer)
{
IR_Timer = timer;
if (IR_Timer == nullptr)
return;
IR_Timer->pause();
IR_Timer->setOverflow((uint32_t)carrierFrec * (uint32_t)s_carrierMultiply, HERTZ_FORMAT);
IR_Timer->pause();
}
void IR_Encoder::setExternalTxBackend(ExternalTxStartFn startFn, ExternalTxBusyFn busyFn, void *ctx)
{
externalTxStartFn = startFn;
externalTxBusyFn = busyFn;
externalTxCtx = ctx;
}
void IR_Encoder::externalFinishSend()
{
if (!isSending)
return;
// Force output low.
if (port != nullptr) {
port->BSRR = ((uint32_t)mask) << 16;
}
isSending = false;
refreshBlindDecoderMuteState();
}
size_t IR_Encoder::buildGateRuns(const uint8_t *packet, uint8_t len, IR_TxGateRun *outRuns, size_t maxRuns)
{
if (packet == nullptr || outRuns == nullptr || maxRuns == 0)
{
return 0;
}
if (len == 0 || len > dataByteSizeMax)
{
return 0;
}
// Copy into fixed-size buffer to match original encoder behavior (safe reads past sendLen).
uint8_t sendBufferLocal[dataByteSizeMax] = {0};
memcpy(sendBufferLocal, packet, len);
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;
bool isActive = true;
while (isActive)
{
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 + 1U);
}
else
{
if (runCount >= maxRuns)
{
return 0;
}
outRuns[runCount].gate = gate;
outRuns[runCount].lenTicks = 1U;
runCount++;
}
}
return runCount;
}
void IR_Encoder::enable()
{
bool exist = false;
IR_Encoder *current = IR_Encoder::head;
while (current != nullptr)
{
exist = (current == this);
if (exist) break;
current = current->next;
}
if (!exist)
{
if (IR_Encoder::head == nullptr)
{
IR_Encoder::head = this;
last = this;
}
else
{
last->next = this;
last = this;
}
this->next = nullptr; // Указываем, что следующий за этим элементом — nullptr
}
pinMode(pin, OUTPUT);
}
void IR_Encoder::disable()
{
IR_Encoder *current = IR_Encoder::head;
IR_Encoder *prev = nullptr;
while (current != nullptr)
{
if (current == this) break;
prev = current;
current = current->next;
}
if (current != nullptr) // Элемент найден в списке
{
if (prev != nullptr)
{
prev->next = current->next; // Убираем текущий элемент из списка
}
else
{
IR_Encoder::head = current->next; // Удаляемый элемент был первым
}
if (current == last)
{
last = prev; // Если удаляется последний элемент, обновляем last
}
}
pinMode(pin, INPUT);
}
void IR_Encoder::setBlindDecoders(IR_DecoderRaw *decoders[], uint8_t count)
{
if (count > IR_PAIR_MUTE_MAX_ENCODERS)
{
decodersCount = 0;
blindDecoders = nullptr;
return;
}
decodersCount = count;
blindDecoders = decoders;
registerWithBlindDecoders();
refreshBlindDecoderMuteState();
}
IR_Encoder::~IR_Encoder(){};
IR_SendResult IR_Encoder::sendData(uint16_t addrTo, uint8_t dataByte, bool needAccept)
{
return sendData(addrTo, &dataByte, 1, needAccept);
}
IR_SendResult IR_Encoder::sendData(uint16_t addrTo, uint8_t *data, uint8_t len, bool needAccept){
return sendDataFULL(id, addrTo, data, len, needAccept);
}
IR_SendResult IR_Encoder::sendDataFULL(uint16_t addrFrom, uint16_t addrTo, uint8_t *data, uint8_t len, bool needAccept)
{
if (len > bytePerPack)
{
Serial.println("IR Pack to big");
return IR_SendResult(false, 0);
}
constexpr uint8_t dataStart = msgBytes + addrBytes + addrBytes;
memset(sendBuffer, 0x00, dataByteSizeMax);
uint8_t packSize = msgBytes + addrBytes + addrBytes + len + crcBytes;
uint8_t msgType =
((needAccept ? IR_MSG_DATA_ACCEPT : IR_MSG_DATA_NOACCEPT) << 5) | (packSize & IR_MASK_MSG_INFO);
// формирование массива
// msg_type
sendBuffer[0] = msgType;
// addr_self
sendBuffer[1] = addrFrom >> 8 & 0xFF;
sendBuffer[2] = addrFrom & 0xFF;
// addr_to
sendBuffer[3] = addrTo >> 8 & 0xFF;
sendBuffer[4] = addrTo & 0xFF;
for (uint16_t i = dataStart; (i < dataStart + len) && (data != nullptr); i++)
{
sendBuffer[i] = ((uint8_t *)data)[i - dataStart];
}
// data crc
sendBuffer[packSize - crcBytes] = crc8(sendBuffer, 0, packSize - crcBytes, poly1) & 0xFF;
sendBuffer[packSize - crcBytes + 1] = crc8(sendBuffer, 0, packSize - crcBytes + 1, poly2) & 0xFF;
//* вывод итогового буфера
// Serial.print("IR SEND [len=");
// Serial.print(packSize);
// Serial.print("] : ");
// for (uint8_t i = 0; i < packSize; i++)
// {
// if (sendBuffer[i] < 0x10)
// Serial.print('0');
// Serial.print(sendBuffer[i], HEX);
// Serial.print(' ');
// }
// Serial.println();
// if (decPair != nullptr) {
// decPair->isWaitingAccept = ((msgType >> 5) & IR_MASK_MSG_TYPE == IR_MSG_DATA_ACCEPT);
// if (decPair->isWaitingAccept) {
// decPair->addrWaitingFrom = addrTo;
// }
// }
// отправка
rawSend(sendBuffer, packSize);
// Возвращаем результат отправки
uint32_t sendTime = calculateSendTime(packSize);
return IR_SendResult(true, sendTime);
}
IR_SendResult IR_Encoder::sendAccept(uint16_t addrTo, uint8_t customByte)
{
constexpr uint8_t packsize = msgBytes + addrBytes + 1U + crcBytes;
memset(sendBuffer, 0x00, dataByteSizeMax);
sendBuffer[0] = IR_MSG_ACCEPT << 5;
sendBuffer[0] |= packsize & IR_MASK_MSG_INFO; // размер пакета
// addr_self
sendBuffer[1] = id >> 8 & 0xFF;
sendBuffer[2] = id & 0xFF;
// Serial.print("\nRAW Accept to ");
// Serial.println(addrTo);
sendBuffer[3] = customByte;
// data crc
sendBuffer[4] = crc8(sendBuffer, 0, 4, poly1) & 0xFF;
sendBuffer[5] = crc8(sendBuffer, 0, 5, poly2) & 0xFF;
rawSend(sendBuffer, packsize);
// Возвращаем результат отправки
uint32_t sendTime = calculateSendTime(packsize);
return IR_SendResult(true, sendTime);
}
IR_SendResult IR_Encoder::sendRequest(uint16_t addrTo)
{
constexpr uint8_t packsize = msgBytes + addrBytes + addrBytes + crcBytes;
memset(sendBuffer, 0x00, dataByteSizeMax);
sendBuffer[0] = IR_MSG_REQUEST << 5;
sendBuffer[0] |= packsize & IR_MASK_MSG_INFO;
// addr_self
sendBuffer[1] = id >> 8 & 0xFF;
sendBuffer[2] = id & 0xFF;
// addr_to
sendBuffer[3] = addrTo >> 8 & 0xFF;
sendBuffer[4] = addrTo & 0xFF;
// data crc
sendBuffer[5] = crc8(sendBuffer, 0, 5, poly1) & 0xFF;
sendBuffer[6] = crc8(sendBuffer, 0, 6, poly2) & 0xFF;
rawSend(sendBuffer, packsize);
// Возвращаем результат отправки
uint32_t sendTime = calculateSendTime(packsize);
return IR_SendResult(true, sendTime);
}
IR_SendResult IR_Encoder::sendBack(uint8_t data)
{
return _sendBack(false, 0, &data, 1);
}
IR_SendResult IR_Encoder::sendBack(uint8_t *data, uint8_t len)
{
return _sendBack(false, 0, data, len);
}
IR_SendResult IR_Encoder::sendBackTo(uint16_t addrTo, uint8_t *data, uint8_t len)
{
return _sendBack(true, addrTo, data, len);
}
IR_SendResult IR_Encoder::_sendBack(bool isAdressed, uint16_t addrTo, uint8_t *data, uint8_t len)
{
if (len > bytePerPack)
{
return IR_SendResult(false, 0);
}
memset(sendBuffer, 0x00, dataByteSizeMax);
uint8_t dataStart = msgBytes + addrBytes + (isAdressed ? addrBytes : 0);
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);
// формирование массива
// msg_type
sendBuffer[0] = msgType;
// addr_from or data
sendBuffer[1] = id >> 8 & 0xFF;
sendBuffer[2] = id & 0xFF;
// addr_to
sendBuffer[3] = addrTo >> 8 & 0xFF;
sendBuffer[4] = addrTo & 0xFF;
for (uint16_t i = dataStart; i < dataStart + len; i++)
{
sendBuffer[i] = ((uint8_t *)data)[i - dataStart];
}
// data crc
sendBuffer[packSize - crcBytes] = crc8(sendBuffer, 0, packSize - crcBytes, poly1) & 0xFF;
sendBuffer[packSize - crcBytes + 1] = crc8(sendBuffer, 0, packSize - crcBytes + 1, poly2) & 0xFF;
// отправка
rawSend(sendBuffer, packSize);
// Возвращаем результат отправки
uint32_t sendTime = calculateSendTime(packSize);
return IR_SendResult(true, sendTime);
}
void IR_Encoder::registerWithBlindDecoders()
{
if (!decodersCount || blindDecoders == nullptr)
return;
for (uint8_t i = 0; i < decodersCount; i++)
{
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();
}
}
void IR_Encoder::rawSend(uint8_t *ptr, uint8_t len)
{
if (isSending)
{
// TODO: Обработка повторной отправки
return;
}
// Проверка на переполнение буфера
if (len > dataByteSizeMax)
{
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))
{
return;
}
sendLen = len;
isSending = true;
refreshBlindDecoderMuteState();
const bool ok = externalTxStartFn(externalTxCtx, this, ptr, len);
if (!ok)
{
isSending = false;
refreshBlindDecoderMuteState();
}
return;
}
if (port == nullptr || mask == 0)
{
return;
}
if (ptr != sendBuffer)
{
memcpy(sendBuffer, ptr, len);
}
sendLen = len;
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;
}
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;
isSending = true;
refreshBlindDecoderMuteState();
if (port != nullptr)
{
port->BSRR = resetW;
}
IR_Encoder::carrierResume();
}
void IR_Encoder::isr()
{
IR_Encoder *current = IR_Encoder::head;
while (current != nullptr)
{
current->_isr();
current = current->next;
}
}
void IR_Encoder::_isr()
{
if (!isSending)
return;
if (port == nullptr)
return;
if (txIsrLegacyMode_)
{
const uint32_t setW = (uint32_t)mask;
const uint32_t resetW = ((uint32_t)mask) << 16U;
if (!state)
{
port->BSRR = resetW;
legacySlotInPeriod_ = 0;
}
else
{
port->BSRR = (legacySlotInPeriod_ < txPowerSnap_) ? setW : resetW;
legacySlotInPeriod_++;
if (legacySlotInPeriod_ >= txMultiplySnap_)
{
legacySlotInPeriod_ = 0;
}
}
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_);
}
}
void IR_Encoder::sendByte(uint8_t byte, bool *prev, bool LOW_FIRST)
{
uint8_t mask = LOW_FIRST ? 0b00000001 : 0b10000000;
for (uint8_t bitShift = 8; bitShift; bitShift--)
{
// digitalWrite(9, HIGH);
// digitalWrite(9, LOW);
byte &mask ? send_HIGH(prev) : send_LOW();
*prev = byte & mask;
LOW_FIRST ? mask <<= 1 : mask >>= 1;
// digitalWrite(9, HIGH);
// digitalWrite(9, LOW);
}
}
void IR_Encoder::addSync(bool *prev, bool *next)
{
switch (syncBits)
{
case 0:
break;
case 1:
*prev ? send_LOW() : send_HIGH();
*prev = !*prev;
break;
default:
for (int16_t i = 0; i < syncBits - 1; i++)
{
*prev ? send_LOW() : send_HIGH();
*prev = !*prev;
}
*next ? send_LOW() : send_HIGH(0);
*prev = !*next;
break;
}
}
uint8_t IR_Encoder::bitHigh[2] = {
(bitPauseTakts) * 2 - 1,
(bitActiveTakts) * 2 - 1};
uint8_t IR_Encoder::bitLow[2] = {
(bitPauseTakts / 2 + bitActiveTakts) * 2 - 1,
(bitPauseTakts)-1};
uint32_t IR_Encoder::calculateSendTime(uint8_t packSize) const
{
// Расчет времени отправки пакета в миллисекундах
// Время преамбулы: preambPulse * 2 фронта * bitTakts тактов
uint32_t preambTime = preambPulse * 2 * bitTakts;
// Время данных: количество бит * bitTakts тактов
uint32_t dataTime = packSize * 8 * bitTakts;
// Время синхронизации: syncBits * 2 фронта * bitTakts тактов
uint32_t syncTime = syncBits * 2 * bitTakts;
// Общее время в тактах
uint32_t totalTakts = preambTime + dataTime + syncTime;
// Конвертируем в миллисекунды
// carrierPeriod - период несущей в микросекундах
// totalTakts * carrierPeriod / 1000 = время в миллисекундах
uint32_t sendTimeMs = (totalTakts * carrierPeriod) / 1000;
return sendTimeMs;
}
// Функции для тестирования времени отправки без фактической отправки
uint32_t IR_Encoder::testSendTime(uint16_t addrTo, uint8_t dataByte, bool needAccept) const
{
return testSendTime(addrTo, &dataByte, 1, needAccept);
}
uint32_t IR_Encoder::testSendTime(uint16_t addrTo, uint8_t *data, uint8_t len, bool needAccept) const
{
return testSendTimeFULL(id, addrTo, data, len, needAccept);
}
uint32_t IR_Encoder::testSendTimeFULL(uint16_t addrFrom, uint16_t addrTo, uint8_t *data, uint8_t len, bool needAccept) const
{
if (len > bytePerPack)
{
return 0; // Возвращаем 0 для недопустимого размера
}
uint8_t packSize = msgBytes + addrBytes + addrBytes + len + crcBytes;
return calculateSendTime(packSize);
}
uint32_t IR_Encoder::testSendAccept(uint16_t addrTo, uint8_t customByte) const
{
constexpr uint8_t packsize = msgBytes + addrBytes + 1U + crcBytes;
return calculateSendTime(packsize);
}
uint32_t IR_Encoder::testSendRequest(uint16_t addrTo) const
{
constexpr uint8_t packsize = msgBytes + addrBytes + addrBytes + crcBytes;
return calculateSendTime(packsize);
}
uint32_t IR_Encoder::testSendBack(uint8_t data) const
{
return testSendBack(false, 0, &data, 1);
}
uint32_t IR_Encoder::testSendBack(uint8_t *data, uint8_t len) const
{
return testSendBack(false, 0, data, len);
}
uint32_t IR_Encoder::testSendBackTo(uint16_t addrTo, uint8_t *data, uint8_t len) const
{
return testSendBack(true, addrTo, data, len);
}
uint32_t IR_Encoder::testSendBack(bool isAdressed, uint16_t addrTo, uint8_t *data, uint8_t len) const
{
if (len > bytePerPack)
{
return 0; // Возвращаем 0 для недопустимого размера
}
uint8_t packSize = msgBytes + addrBytes + (isAdressed ? addrBytes : 0) + min(uint8_t(1), len) + crcBytes;
return calculateSendTime(packSize);
}
// uint8_t* IR_Encoder::bitHigh = new uint8_t[2]{
// (bitPauseTakts) * 2 - 0,
// (bitActiveTakts) * 2 - 0};
// uint8_t* IR_Encoder::bitLow = new uint8_t[2]{
// (bitPauseTakts/2 + bitActiveTakts) * 2 - 0,
// (bitPauseTakts) - 0};