IR-protocol/IR_Decoder.cpp
2023-10-06 16:46:42 +03:00

338 lines
11 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "IR_Decoder.h"
#include "IR_Encoder.h"
#define checkAddr(h, l) (\
((uint16_t)((dataBuffer[h] << 8) | dataBuffer[l]) == addrSelf) || \
((uint16_t)((dataBuffer[h] << 8) | dataBuffer[l]) >= IR_Broadcast)\
)
IR_Decoder::IR_Decoder(uint16_t addr, IR_Encoder* encPair = nullptr) : addrSelf(addr), encoder(encPair) {
rawBuffer = new uint8_t[bufferRawSize] { 0 };
prevRise = prevFall = prevPrevFall = prevPrevRise = 0;
start_RX();
}
IR_Decoder::~IR_Decoder() {
delete rawBuffer;
}
void IR_Decoder::writeToBuffer(bool bit) {
if (!isBufferOverflow && !isPreamb) {
if (HIGH_FIRST) {
rawBuffer[(bufBitPos >> 3)] |= bit << (7 - (bufBitPos & ~(~0 << 3)));
}/* else {
rawBuffer[(bufBitPos >> 3)] |= bit << (bufBitPos & ~(~0 << 3));
} */
#ifdef IRDEBUG
bit ? infoPulse(writeOp, 2) : infoPulse(writeOp, 1);
#endif
if (isBufferOverflow) { //TODO: Буффер переполнен!
}
//const auto testval = bufferBitSizeMax;
if ((bufBitPos >= (8 * msgBytes) - syncBits) && !isMsgAvaliable) {
switch ((rawBuffer[0] >> 5) & IR_MASK_MSG_TYPE) {
case IR_MSG_ACCEPT:
if (bufBitPos >= ((msgBytes + addrBytes + crcBytes) * (8 + 3)) - syncBits) {
const uint8_t dataSize = msgBytes + addrBytes;
isRawAvaliable = true;
isMsgAvaliable = crcCheck(dataSize);
if (isMsgAvaliable && checkAddr(1, 2)) {
gotAccept._set(dataBuffer, msgBytes + addrBytes + crcBytes, crcValue, errorCounter);
gotAccept._isAvaliable = true;
}
}
break;
case IR_MSG_REQUEST:
if (bufBitPos >= ((msgBytes + addrBytes + addrBytes + crcBytes) * (8 + 3)) - syncBits) {
const uint8_t dataSize = msgBytes + addrBytes + addrBytes;
isRawAvaliable = true;
isMsgAvaliable = (crcCheck(dataSize));
if (isMsgAvaliable && checkAddr(3, 4)) {
gotRequest._isAvaliable = true;
gotRequest._set(dataBuffer, msgBytes + addrBytes + addrBytes + crcBytes, crcValue, errorCounter);
}
}
break;
case IR_MSG_DATA_ACCEPT:
case IR_MSG_DATA_NOACCEPT:
if (bufBitPos >= ((bitPerByte + syncBits) * ((rawBuffer[0] & IR_MASK_MSG_INFO) + crcBytes)) - syncBits) {
const uint8_t dataSize = (rawBuffer[0] & IR_MASK_MSG_INFO);
isRawAvaliable = true;
isMsgAvaliable = crcCheck(dataSize);
if (isMsgAvaliable && checkAddr(3, 4)
) {
gotData._isAvaliable = true;
gotData._set(dataBuffer, (dataSize)+crcBytes, crcValue, errorCounter);
}
}
break;
default:
break;
}
}
if (bufBitPos >= bufferRawSize * 8 - 1) { isBufferOverflow = true; }
bufBitPos++;
}
}
uint8_t* IR_Decoder::getDataBuffer(bool reset = false) {
if (!isRawAvaliable) { return nullptr; }
if (dataBuffer != nullptr) { delete dataBuffer; dataBuffer = nullptr; } // устранение утечки памяти
dataBuffer = new uint8_t[dataByteSizeMax] { 0 }; // Буффер по максимуму
bool isData = true;
bool controlCheckFirst = true;
bool controlCheck;
uint8_t nextControlBit = bitPerByte;
uint16_t i_dataBuffer = 0;
for (uint16_t i = 0; i < dataBitSize; i++) {
if (i == nextControlBit) {
controlCheckFirst = true;
nextControlBit += (isData ? syncBits : bitPerByte);
isData = !isData;
}
if (isData) {
dataBuffer[i_dataBuffer / 8] |= (rawBuffer[(i / 8)] >> (7 - (i % 8)) & 1) << 7 - (i_dataBuffer % 8);
i_dataBuffer++;
} else { // Проверка контрольных sync битов
if (controlCheckFirst) {
controlCheck = (rawBuffer[(i / 8)] >> (7 - (i % 8)) & 1);
controlCheckFirst = false;
} else {
controlCheck |= (rawBuffer[(i / 8)] >> (7 - (i % 8)) & 1);
}
}
}
isFilterBufferAvaliable = controlCheck;
if (reset) { resetAvaliable(); }
return dataBuffer;
}
bool IR_Decoder::crcCheck(uint8_t len) {
bool crcOK = false;
// получить буффер, если нет
if (!isFilterBufferAvaliable) getDataBuffer();
if (dataBuffer == nullptr) {
return false;
}
crcValue = 0;
crcValue = (crc8(dataBuffer, 0, len, poly1) << 8) & ~((crc_t)0xFF);
crcValue |= crc8(dataBuffer, 0, len + 1, poly2) & (crc_t)0xFF;
if (
crcValue &&
dataBuffer[len] == (crcValue >> 8) & 0xFF &&
dataBuffer[len + 1] == (crcValue & 0xFF)
) {
crcOK = true;
} else { crcOK = false; }
return crcOK;
}
void IR_Decoder::start_RX() {
resetAvaliable();
isBufferOverflow = false;
memset(rawBuffer, 0x00, bufferRawSize);
bufBitPos = 0;
}
void IR_Decoder::resetAvaliable() {
isRawAvaliable = false;
isMsgAvaliable = false;
isFilterBufferAvaliable = false;
}
uint16_t IR_Decoder::ceil_div(uint16_t val, uint16_t divider) {
int ret = val / divider;
if ((val << 4) / divider - (ret << 4) >= 8)
ret++;
return ret;
}
void IR_Decoder::isr() { // в прерывании вызываем isr()
if (isPairSending) return;
if (micros() - prevRise > IR_timeout) { // первый
isPreamb = true;
frontCounter = preambFronts - 1U;
errorCounter = 0;
riseSyncTime = bitTime;
start_RX();
}
if (frontCounter > 0) { // в преамбуле
uint32_t risePeriod = micros() - prevRise;
if ((PIND >> 2) & 1 && risePeriod < IR_timeout) { // __/``` ↑ и мы в внутри пакета
if (freeFrec) { riseSyncTime = (riseSyncTime + risePeriod / 2) / 2; } // tuner
if (risePeriod < riseTimeMin << 1) { // fix рваной единицы
frontCounter += 2;
errorCounter++;
}
} else { riseSyncTime = bitTime; } // сброс тюнера
frontCounter--;
} else {
if (isPreamb) {// первый фронт после
}
isPreamb = false;
}
// определить направление фронта
if ((PIND >> 2) & 1) { // Если __/``` ↑
uint16_t risePeriod = micros() - prevRise;
uint16_t highTime = micros() - prevFall;
uint16_t lowTime = prevFall - prevRise;
int8_t highCount = 0;
int8_t lowCount = 0;
int8_t allCount = 0;
if (risePeriod < IR_timeout && !isBufferOverflow && risePeriod > riseTimeMin) {
// Мы в пределах таймаута и буффер не переполнен и fix дроблёных единиц
if (aroundRise(risePeriod)) { // тактирование есть, сигнал хороший - без ошибок(?)
if (highTime > riseTimeMin >> 1) { // 1
#ifdef IRDEBUG
digitalWrite(wrHigh, 1);
#endif
writeToBuffer(HIGH);
} else { // 0
#ifdef IRDEBUG
digitalWrite(wrLow, 1);
#endif
writeToBuffer(LOW);
}
} else { // пропущены такты! сигнал средний // ошибка пропуска
highCount = ceil_div(highTime, riseTime); // предполагаемое колличество HIGH битов
lowCount = ceil_div(lowTime, riseTime); // предполагаемое колличество LOW битов
allCount = ceil_div(risePeriod, riseTime); // предполагаемое колличество всего битов
if (highCount == 0 && highTime > riseTime / 3) { // fix короткой единицы (?)после пропуска нулей(?)
highCount++;
errorCounter++;
#ifdef IRDEBUG
errPulse(errOut, 2);
#endif
}
if (lowCount + highCount > allCount) { // fix ошибочных сдвигов
if (lowCount > highCount) { // Лишние нули
lowCount = allCount - highCount;
#ifdef IRDEBUG
errPulse(errOut, 3);
#endif
} else if (lowCount < highCount) { // Лишние единицы
highCount = allCount - lowCount;
#ifdef IRDEBUG
errPulse(errOut, 4);
#endif
} else if (lowCount == highCount) {} // неизвестный случай
errorCounter += allCount;
}
errorCounter += allCount;
#ifdef IRDEBUG
errPulse(errOut, 1);
#endif
for (int8_t i = 0; i < lowCount && 8 - i; i++) { // отправка LOW битов, если есть
#ifdef IRDEBUG
digitalWrite(wrLow, 1);
#endif
writeToBuffer(LOW);
}
for (int8_t i = 0; i < highCount && 8 - i; i++) { // отправка HIGH битов, если есть
#ifdef IRDEBUG
digitalWrite(wrHigh, 1);
#endif
writeToBuffer(HIGH);
}
}
#ifdef IRDEBUG
digitalWrite(wrHigh, 0);
digitalWrite(wrLow, 0);
#endif
}
if (risePeriod > riseTimeMax >> 1 || highCount || lowCount) { // комплексный фикс рваной единицы
prevPrevRise = prevRise;
prevRise = micros();
} else {
errorCounter++;
#ifdef IRDEBUG
errPulse(errOut, 5);
#endif
}
} else { // Если ```\__ ↓
if (micros() - prevFall > riseTimeMin) {
prevPrevFall = prevFall;
prevFall = micros();
} else {
#ifdef IRDEBUG
//errPulse(errOut, 5);
#endif
}
}
if (isPreamb && frontCounter <= 0) {
prevRise = micros() + riseTime;
}
#ifdef IRDEBUG
digitalWrite(writeOp, isPreamb);
#endif
}
// IRDEBUG FUNC
#ifdef IRDEBUG
inline void IR_Decoder::errPulse(uint8_t pin, uint8_t count) {
for (size_t i = 0; i < count; i++) {
digitalWrite(pin, 1);
digitalWrite(pin, 0);
}
digitalWrite(pin, 0);
}
inline void IR_Decoder::infoPulse(uint8_t pin, uint8_t count) {
for (size_t i = 0; i < count; i++) {
digitalWrite(pin, 1);
digitalWrite(pin, 0);
}
}
#endif