mirror of
https://github.com/Show-maket/IR-protocol.git
synced 2026-04-28 03:08:08 +00:00
tx error tracking and inline glitch filter
This commit is contained in:
213
IR_Encoder.cpp
213
IR_Encoder.cpp
@ -66,6 +66,41 @@ void *IR_Encoder::externalTxCtx = nullptr;
|
||||
bool IR_Encoder::txIsrLegacyMode_ = true;
|
||||
uint16_t IR_Encoder::s_carrierMultiply = 2;
|
||||
|
||||
const char* irSendStatusToString(IR_SendStatus status)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case IR_SendStatus::Success:
|
||||
return "Success";
|
||||
case IR_SendStatus::PayloadTooLarge:
|
||||
return "PayloadTooLarge";
|
||||
case IR_SendStatus::EncoderBusy:
|
||||
return "EncoderBusy";
|
||||
case IR_SendStatus::BufferTooLarge:
|
||||
return "BufferTooLarge";
|
||||
case IR_SendStatus::ExternalBackendBusy:
|
||||
return "ExternalBackendBusy";
|
||||
case IR_SendStatus::ExternalStartFailed:
|
||||
return "ExternalStartFailed";
|
||||
case IR_SendStatus::ExternalNoStream:
|
||||
return "ExternalNoStream";
|
||||
case IR_SendStatus::ExternalInvalidConfig:
|
||||
return "ExternalInvalidConfig";
|
||||
case IR_SendStatus::BuildGateRunsFailed:
|
||||
return "BuildGateRunsFailed";
|
||||
case IR_SendStatus::ScaleGateRunsFailed:
|
||||
return "ScaleGateRunsFailed";
|
||||
case IR_SendStatus::DmaStartFailed:
|
||||
return "DmaStartFailed";
|
||||
case IR_SendStatus::EncoderPinUnavailable:
|
||||
return "EncoderPinUnavailable";
|
||||
case IR_SendStatus::BufferedStorageInvalid:
|
||||
return "BufferedStorageInvalid";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
void IR_Encoder::setCarrierMultiply(uint16_t multiply)
|
||||
{
|
||||
if (multiply < 2)
|
||||
@ -465,6 +500,107 @@ size_t IR_Encoder::buildGateRuns(const uint8_t *packet, uint8_t len, IR_TxGateRu
|
||||
return runCount;
|
||||
}
|
||||
|
||||
size_t IR_Encoder::buildPhysicalGateRuns(const uint8_t *packet, uint8_t len, IR_TxGateRun *outRuns, size_t maxRuns, uint16_t multiply)
|
||||
{
|
||||
if (packet == nullptr || outRuns == nullptr || maxRuns == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (len == 0 || len > dataByteSizeMax)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (multiply < 2)
|
||||
{
|
||||
multiply = 2;
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
auto appendPhysicalRun = [&](bool gate, uint32_t logicalLen, size_t& runCount) -> bool {
|
||||
if (logicalLen == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t phys = (logicalLen * (uint32_t)multiply) / 2U;
|
||||
if (logicalLen > 0 && phys == 0)
|
||||
{
|
||||
phys = 1;
|
||||
}
|
||||
|
||||
while (phys > 0)
|
||||
{
|
||||
if (runCount >= maxRuns)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint32_t chunk = phys > 65535U ? 65535U : phys;
|
||||
outRuns[runCount].gate = gate;
|
||||
outRuns[runCount].lenTicks = static_cast<uint16_t>(chunk);
|
||||
runCount++;
|
||||
phys -= chunk;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
size_t runCount = 0;
|
||||
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)
|
||||
{
|
||||
currentGate = gate;
|
||||
currentLogicalLen = 1U;
|
||||
havePendingRun = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (currentGate == gate)
|
||||
{
|
||||
currentLogicalLen++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!appendPhysicalRun(currentGate, currentLogicalLen, runCount))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
currentGate = gate;
|
||||
currentLogicalLen = 1U;
|
||||
}
|
||||
|
||||
if (havePendingRun && !appendPhysicalRun(currentGate, currentLogicalLen, runCount))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return runCount;
|
||||
}
|
||||
|
||||
|
||||
void IR_Encoder::enable()
|
||||
{
|
||||
@ -555,7 +691,7 @@ IR_SendResult IR_Encoder::sendDataFULL(uint16_t addrFrom, uint16_t addrTo, uint8
|
||||
if (len > bytePerPack)
|
||||
{
|
||||
Serial.println("IR Pack to big");
|
||||
return IR_SendResult(false, 0);
|
||||
return IR_SendResult(false, 0, IR_SendStatus::PayloadTooLarge);
|
||||
}
|
||||
constexpr uint8_t dataStart = msgBytes + addrBytes + addrBytes;
|
||||
memset(sendBuffer, 0x00, dataByteSizeMax);
|
||||
@ -605,11 +741,15 @@ IR_SendResult IR_Encoder::sendDataFULL(uint16_t addrFrom, uint16_t addrTo, uint8
|
||||
// }
|
||||
|
||||
// отправка
|
||||
rawSend(sendBuffer, packSize);
|
||||
|
||||
const IR_SendStatus status = rawSend(sendBuffer, packSize);
|
||||
if (status != IR_SendStatus::Success)
|
||||
{
|
||||
return IR_SendResult(false, 0, status);
|
||||
}
|
||||
|
||||
// Возвращаем результат отправки
|
||||
uint32_t sendTime = calculateSendTime(packSize);
|
||||
return IR_SendResult(true, sendTime);
|
||||
return IR_SendResult(true, sendTime, status);
|
||||
}
|
||||
|
||||
|
||||
@ -633,11 +773,15 @@ IR_SendResult IR_Encoder::sendAccept(uint16_t addrTo, uint8_t customByte)
|
||||
sendBuffer[4] = crc8(sendBuffer, 0, 4, poly1) & 0xFF;
|
||||
sendBuffer[5] = crc8(sendBuffer, 0, 5, poly2) & 0xFF;
|
||||
|
||||
rawSend(sendBuffer, packsize);
|
||||
|
||||
const IR_SendStatus status = rawSend(sendBuffer, packsize);
|
||||
if (status != IR_SendStatus::Success)
|
||||
{
|
||||
return IR_SendResult(false, 0, status);
|
||||
}
|
||||
|
||||
// Возвращаем результат отправки
|
||||
uint32_t sendTime = calculateSendTime(packsize);
|
||||
return IR_SendResult(true, sendTime);
|
||||
return IR_SendResult(true, sendTime, status);
|
||||
}
|
||||
|
||||
IR_SendResult IR_Encoder::sendRequest(uint16_t addrTo)
|
||||
@ -659,11 +803,15 @@ IR_SendResult IR_Encoder::sendRequest(uint16_t addrTo)
|
||||
sendBuffer[5] = crc8(sendBuffer, 0, 5, poly1) & 0xFF;
|
||||
sendBuffer[6] = crc8(sendBuffer, 0, 6, poly2) & 0xFF;
|
||||
|
||||
rawSend(sendBuffer, packsize);
|
||||
|
||||
const IR_SendStatus status = rawSend(sendBuffer, packsize);
|
||||
if (status != IR_SendStatus::Success)
|
||||
{
|
||||
return IR_SendResult(false, 0, status);
|
||||
}
|
||||
|
||||
// Возвращаем результат отправки
|
||||
uint32_t sendTime = calculateSendTime(packsize);
|
||||
return IR_SendResult(true, sendTime);
|
||||
return IR_SendResult(true, sendTime, status);
|
||||
}
|
||||
|
||||
IR_SendResult IR_Encoder::sendBack(uint8_t data)
|
||||
@ -685,7 +833,7 @@ IR_SendResult IR_Encoder::_sendBack(bool isAdressed, uint16_t addrTo, uint8_t *d
|
||||
{
|
||||
if (len > bytePerPack)
|
||||
{
|
||||
return IR_SendResult(false, 0);
|
||||
return IR_SendResult(false, 0, IR_SendStatus::PayloadTooLarge);
|
||||
}
|
||||
memset(sendBuffer, 0x00, dataByteSizeMax);
|
||||
uint8_t dataStart = msgBytes + addrBytes + (isAdressed ? addrBytes : 0);
|
||||
@ -716,11 +864,15 @@ IR_SendResult IR_Encoder::_sendBack(bool isAdressed, uint16_t addrTo, uint8_t *d
|
||||
sendBuffer[packSize - crcBytes + 1] = crc8(sendBuffer, 0, packSize - crcBytes + 1, poly2) & 0xFF;
|
||||
|
||||
// отправка
|
||||
rawSend(sendBuffer, packSize);
|
||||
|
||||
const IR_SendStatus status = rawSend(sendBuffer, packSize);
|
||||
if (status != IR_SendStatus::Success)
|
||||
{
|
||||
return IR_SendResult(false, 0, status);
|
||||
}
|
||||
|
||||
// Возвращаем результат отправки
|
||||
uint32_t sendTime = calculateSendTime(packSize);
|
||||
return IR_SendResult(true, sendTime);
|
||||
return IR_SendResult(true, sendTime, status);
|
||||
}
|
||||
|
||||
void IR_Encoder::registerWithBlindDecoders()
|
||||
@ -747,18 +899,18 @@ void IR_Encoder::refreshBlindDecoderMuteState()
|
||||
}
|
||||
}
|
||||
|
||||
void IR_Encoder::rawSend(uint8_t *ptr, uint8_t len)
|
||||
IR_SendStatus IR_Encoder::rawSend(uint8_t *ptr, uint8_t len)
|
||||
{
|
||||
if (isSending)
|
||||
{
|
||||
// TODO: Обработка повторной отправки
|
||||
return;
|
||||
return IR_SendStatus::EncoderBusy;
|
||||
}
|
||||
|
||||
// Проверка на переполнение буфера
|
||||
if (len > dataByteSizeMax)
|
||||
{
|
||||
return;
|
||||
return IR_SendStatus::BufferTooLarge;
|
||||
}
|
||||
|
||||
// Serial.print("IR tx hex: ");
|
||||
@ -773,7 +925,7 @@ void IR_Encoder::rawSend(uint8_t *ptr, uint8_t len)
|
||||
{
|
||||
if (externalTxBusyFn != nullptr && externalTxBusyFn(externalTxCtx))
|
||||
{
|
||||
return;
|
||||
return IR_SendStatus::ExternalBackendBusy;
|
||||
}
|
||||
|
||||
sendLen = len;
|
||||
@ -782,18 +934,18 @@ void IR_Encoder::rawSend(uint8_t *ptr, uint8_t len)
|
||||
isSending = true;
|
||||
refreshBlindDecoderMuteState();
|
||||
|
||||
const bool ok = externalTxStartFn(externalTxCtx, this, ptr, len);
|
||||
if (!ok)
|
||||
const IR_SendStatus status = externalTxStartFn(externalTxCtx, this, ptr, len);
|
||||
if (status != IR_SendStatus::Success)
|
||||
{
|
||||
isSending = false;
|
||||
refreshBlindDecoderMuteState();
|
||||
}
|
||||
return;
|
||||
return status;
|
||||
}
|
||||
|
||||
if (port == nullptr || mask == 0)
|
||||
{
|
||||
return;
|
||||
return IR_SendStatus::EncoderPinUnavailable;
|
||||
}
|
||||
|
||||
if (ptr != sendBuffer)
|
||||
@ -832,7 +984,7 @@ void IR_Encoder::rawSend(uint8_t *ptr, uint8_t len)
|
||||
isSending = true;
|
||||
refreshBlindDecoderMuteState();
|
||||
IR_Encoder::carrierResume();
|
||||
return;
|
||||
return IR_SendStatus::Success;
|
||||
}
|
||||
|
||||
IrTxIsrBufferedStorageBase* buf = txActiveBufferedCtx_;
|
||||
@ -840,23 +992,18 @@ void IR_Encoder::rawSend(uint8_t *ptr, uint8_t len)
|
||||
{
|
||||
txUseBufferedIsr_ = false;
|
||||
txActiveBufferedCtx_ = nullptr;
|
||||
return;
|
||||
return IR_SendStatus::BufferedStorageInvalid;
|
||||
}
|
||||
|
||||
buf->resetRuntimeState();
|
||||
|
||||
size_t nRuns = buildGateRuns(sendBuffer, len, buf->gateRuns, buf->maxGateRuns);
|
||||
txMultiplySnap_ = carrierMultiply();
|
||||
size_t nRuns = buildPhysicalGateRuns(sendBuffer, len, buf->gateRuns, buf->maxGateRuns, txMultiplySnap_);
|
||||
if (nRuns == 0U)
|
||||
{
|
||||
txUseBufferedIsr_ = false;
|
||||
txActiveBufferedCtx_ = nullptr;
|
||||
return;
|
||||
}
|
||||
if (!scaleGateRunsToPhysical(buf->gateRuns, &nRuns, buf->maxGateRuns, carrierMultiply()))
|
||||
{
|
||||
txUseBufferedIsr_ = false;
|
||||
txActiveBufferedCtx_ = nullptr;
|
||||
return;
|
||||
return IR_SendStatus::BuildGateRunsFailed;
|
||||
}
|
||||
|
||||
uint32_t total = 0;
|
||||
@ -868,7 +1015,6 @@ void IR_Encoder::rawSend(uint8_t *ptr, uint8_t len)
|
||||
|
||||
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_;
|
||||
@ -883,6 +1029,7 @@ void IR_Encoder::rawSend(uint8_t *ptr, uint8_t len)
|
||||
port->BSRR = resetW;
|
||||
}
|
||||
IR_Encoder::carrierResume();
|
||||
return IR_SendStatus::Success;
|
||||
}
|
||||
|
||||
void IR_Encoder::isr()
|
||||
|
||||
Reference in New Issue
Block a user