IR-protocol/IR_DecoderRaw.cpp
2024-04-22 11:20:53 +03:00

626 lines
18 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_DecoderRaw.h"
#include "IR_Encoder.h"
IR_DecoderRaw::IR_DecoderRaw(const uint8_t isrPin, uint16_t addr, IR_Encoder *encPair) : isrPin(isrPin), encoder(encPair)
{
id = addr;
prevRise = prevFall = prevPrevFall = prevPrevRise = 0;
if (encPair != nullptr)
{
encPair->decPair = this;
}
#ifdef IRDEBUG
pinMode(wrHigh, OUTPUT);
pinMode(wrLow, OUTPUT);
pinMode(writeOp, OUTPUT);
pinMode(errOut, OUTPUT);
pinMode(up, OUTPUT);
pinMode(down, OUTPUT);
#endif
}
//////////////////////////////////// isr ///////////////////////////////////////////
volatile uint32_t time_;
void IR_DecoderRaw::isr()
{
noInterrupts();
// time_ = HAL_GetTick() * 1000 + ((SysTick->LOAD + 1 - SysTick->VAL) * 1000) / SysTick->LOAD + 1;
time_ = micros();
interrupts();
if (time_ < oldTime)
{
#ifdef IRDEBUG
Serial.print("\n");
Serial.print("count: ");
Serial.println(wrongCounter++);
Serial.print("time: ");
Serial.println(time_);
Serial.print("oldTime: ");
Serial.println(oldTime);
Serial.print("sub: ");
Serial.println(max((uint32_t)time_, oldTime) - min((uint32_t)time_, oldTime));
#endif
time_ += 1000;
}
oldTime = time_;
FrontStorage edge;
edge.dir = digitalRead(isrPin);
edge.time = time_;
subBuffer.push(edge);
}
////////////////////////////////////////////////////////////////////////////////////
uint32_t wrCounter;
void IR_DecoderRaw::firstRX()
{
#ifdef IRDEBUG_INFO
Serial.print("\nRX>");
#endif
errors.reset();
packSize = 0;
isBufferOverflow = false;
isAvailable = false;
bufBitPos = 0;
isData = true;
i_dataBuffer = 0;
nextControlBit = bitPerByte;
i_syncBit = 0;
isWrongPack = false;
isPreamb = true;
riseSyncTime = bitTime /* 1100 */;
wrCounter = 0;
memset(dataBuffer, 0x00, dataByteSizeMax);
}
void IR_DecoderRaw::listenStart()
{
if (isRecive && ((micros() - prevRise) > IR_timeout * 2))
{
// Serial.print("\nlis>");
isRecive = false;
firstRX();
}
}
void IR_DecoderRaw::tick()
{
FrontStorage currentFront;
noInterrupts();
listenStart();
FrontStorage *currentFrontPtr;
currentFrontPtr = subBuffer.pop();
if (currentFrontPtr == nullptr)
{
isSubBufferOverflow = false;
interrupts();
return;
} // Если данных нет - ничего не делаем
currentFront = *currentFrontPtr;
interrupts();
////////////////////////////////////////////////////////////////////////////////////////////////////////////
if (currentFront.dir)
{ // Если __/``` ↑
if (currentFront.time - prevRise > riseTimeMax / 2 || highCount || lowCount)
{ // комплексный фикс рваной единицы
risePeriod = currentFront.time - prevRise;
highTime = currentFront.time - prevFall;
lowTime = prevFall - prevRise;
prevRise = currentFront.time;
if (
risePeriod > UINT32_MAX - IR_timeout * 10 ||
highTime > UINT32_MAX - IR_timeout * 10 ||
lowTime > UINT32_MAX - IR_timeout * 10 ||
prevRise > UINT32_MAX - IR_timeout * 10)
{
#ifdef IRDEBUG
errPulse(down, 50);
// Serial.print("\n");
// Serial.print("risePeriod: ");
// Serial.println(risePeriod);
// Serial.print("highTime: ");
// Serial.println(highTime);
// Serial.print("lowTime: ");
// Serial.println(lowTime);
// Serial.print("prevRise: ");
// Serial.println(prevRise);
#endif
}
}
else
{
errors.other++;
}
}
else
{ // Если ```\__ ↓
if (currentFront.time - prevFall > riseTimeMin / 4)
{
prevFall = currentFront.time;
}
else
{
errors.other++;
}
}
#ifdef IRDEBUG
// goto END; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#endif
//----------------------------------------------------------------------------------
#ifdef IRDEBUG
digitalWrite(errOut, currentFront.dir);
#endif
if (currentFront.time > prevRise && currentFront.time - prevRise > IR_timeout * 2 && !isRecive)
{ // первый
#ifdef IRDEBUG
errPulse(up, 50);
errPulse(down, 50);
errPulse(up, 150);
errPulse(down, 150);
#endif
preambFrontCounter = preambFronts - 1U;
isPreamb = true;
isRecive = true;
isWrongPack = false;
}
//-------------------------------------------------------------------------------------------------------
if (preambFrontCounter)
{ // в преамбуле
#ifdef IRDEBUG
Serial.print("risePeriod: ");
Serial.println(risePeriod);
#endif
if (currentFront.dir && risePeriod < IR_timeout)
{ // __/``` ↑ и мы в внутри пакета
if (risePeriod < riseTimeMin / 2)
{ // fix рваной единицы
preambFrontCounter += 2;
errors.other++;
#ifdef IRDEBUG
errPulse(down, 350);
#endif
}
else
{
if (freeFrec)
{
riseSyncTime = (riseSyncTime + risePeriod / 2) / 2;
} // tuner
}
}
else
{ /* riseSyncTime = bitTime; */
} // сброс тюнера
preambFrontCounter--;
// Serial.print("preambFrontCounter: "); Serial.println(preambFrontCounter);
}
else
{
if (isPreamb)
{ // первый фронт после
// gotTune.set(riseSyncTime);
isPreamb = false;
#ifdef IRDEBUG
errPulse(up, 50);
errPulse(down, 50);
#endif
prevRise += risePeriod / 2;
// prevRise = currentFront.time + riseTime;
goto END;
}
}
if (isPreamb)
{
goto END;
}
if (risePeriod > IR_timeout || isBufferOverflow || risePeriod < riseTimeMin || isWrongPack)
// ~Мы в пределах таймаута и буффер не переполнен и fix дроблёных единиц
{
goto END;
}
// определить направление фронта
if (currentFront.dir)
{ // Если __/``` ↑
highCount = 0;
lowCount = 0;
allCount = 0;
bool invertErr = false;
#ifdef IRDEBUG
Serial.print("\n");
Serial.print("wrCounter: ");
Serial.println(wrCounter++);
Serial.print("risePeriod: ");
Serial.println(risePeriod);
Serial.print("highTime: ");
Serial.println(highTime);
Serial.print("lowTime: ");
Serial.println(lowTime);
#endif
if (aroundRise(risePeriod))
{ // тактирование есть, сигнал хороший - без ошибок(?)
if (highTime > lowTime)
{ // 1
#ifdef IRDEBUG
errPulse(wrHigh, 1);
#endif
writeToBuffer(HIGH);
}
else
{ // 0
#ifdef IRDEBUG
errPulse(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++;
errors.other++;
#ifdef IRDEBUG
errPulse(up, 50);
#endif
}
if (lowCount + highCount > allCount)
{ // fix ошибочных сдвигов
if (lowCount > highCount)
{ // Лишние нули
lowCount = allCount - highCount;
errors.lowSignal += lowCount;
#ifdef IRDEBUG
// errPulse(errOut, 3);
errPulse(down, 40);
errPulse(up, 10);
errPulse(down, 40);
#endif
}
else if (lowCount < highCount)
{ // Лишние единицы
highCount = allCount - lowCount;
errors.highSignal += highCount;
#ifdef IRDEBUG
errPulse(down, 10);
errPulse(up, 40);
errPulse(down, 10);
// errPulse(errOut, 4);
#endif
// неизвестный случай Инверсит след бит или соседние
// Очень редко
// TODO: Отловить проверить
}
else if (lowCount == highCount)
{
#ifdef IRDEBUG
errPulse(down, 40);
errPulse(up, 40);
errPulse(down, 40);
#endif
invertErr = true;
// Serial.print("...");
errors.other += allCount;
}
// errorCounter += allCount;
}
// errorCounter += allCount;
// errors.other+=allCount;
if (lowCount < highCount)
{
errors.highSignal += highCount;
}
else
{
errors.lowSignal += lowCount;
}
// errPulse(errOut, 1);
for (int8_t i = 0; i < lowCount && 8 - i; i++)
{ // отправка LOW битов, если есть
if (i == lowCount - 1 && invertErr)
{
invertErr = false;
writeToBuffer(HIGH);
#ifdef IRDEBUG
errPulse(wrHigh, 1);
#endif
}
else
{
writeToBuffer(LOW);
#ifdef IRDEBUG
errPulse(wrLow, 1);
#endif
}
}
for (int8_t i = 0; i < highCount && 8 - i; i++)
{ // отправка HIGH битов, если есть
if (i == highCount - 1 && invertErr)
{
invertErr = false;
writeToBuffer(LOW);
#ifdef IRDEBUG
errPulse(wrLow, 1);
#endif
}
else
{
writeToBuffer(HIGH);
#ifdef IRDEBUG
errPulse(wrHigh, 1);
#endif
}
}
}
}
else
{ // Если ```\__ ↓
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////
END:;
}
void IR_DecoderRaw::writeToBuffer(bool bit)
{
if (i_dataBuffer > dataByteSizeMax * 8)
{ // проверка переполнения
// TODO: Буффер переполнен!
#ifdef IRDEBUG_INFO
Serial.println("OverBuf");
#endif
isBufferOverflow = true;
}
if (isBufferOverflow || isPreamb || isWrongPack)
{
isRecive = false;
return;
}
// Переключение флага, data или syncBit
if (bufBitPos == nextControlBit)
{
nextControlBit += (isData ? syncBits : bitPerByte); // маркер следующего переключения
isData = !isData;
i_syncBit = 0; // сброс счетчика битов синхронизации
err_syncBit = 0; // сброс счетчика ошибок синхронизации
#ifdef IRDEBUG_INFO
Serial.print(" ");
#endif
}
if (isData)
{ // Запись битов в dataBuffer
#ifdef IRDEBUG_INFO
Serial.print(bit);
#endif
// if (i_dataBuffer % 8 == 7) {
// // Serial.print("+");
// }
dataBuffer[(i_dataBuffer / 8)] |= bit << (7 - i_dataBuffer % 8); // Запись в буффер
i_dataBuffer++;
bufBitPos++;
}
else
{
//********************************* Проверка контрольных sync битов*******************************//
////////////////////// Исправление лишнего нуля ///////////////////////
if (i_syncBit == 0)
{ // Первый бит синхронизации
// Serial.print("~");
if (bit != (dataBuffer[((i_dataBuffer - 1) / 8)] >> (7 - (i_dataBuffer - 1) % 8) & 1))
{
bufBitPos++;
i_syncBit++;
}
else
{
i_syncBit = 0;
errors.other++;
// Serial.print("E");
err_syncBit++;
// Serial.print("bit: "); Serial.println(bit);
// Serial.print("dataBuffer: "); Serial.println(dataBuffer[((i_dataBuffer - 1) / 8)] & 1 << (7 - ((i_dataBuffer - 1) & ~(~0 << 3))));
}
}
else
{ // Последующие биты синхронизации
// Serial.print("`");
bufBitPos++;
i_syncBit++;
}
////////////////////// Проверка наличия битов синхранизации //////////////////////
if (isWrongPack = (err_syncBit >= syncBits))
{
#ifdef IRDEBUG_INFO
Serial.print("****************");
#endif
};
} //**************************************************************************************************//
// Serial.print(bit);
#ifdef IRDEBUG
bit ? infoPulse(writeOp, 2) : infoPulse(writeOp, 1);
#endif
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#ifdef IRDEBUG_INFO
if (isData)
{
if (i_dataBuffer == ((msgBytes)*bitPerByte))
{
Serial.print(" -> ");
Serial.print(dataBuffer[0] & IR_MASK_MSG_INFO);
Serial.print(" ->");
}
if (i_dataBuffer == ((msgBytes + addrBytes) * bitPerByte))
{
Serial.print(" |");
}
if (i_dataBuffer == ((msgBytes + addrBytes + addrBytes) * bitPerByte))
{
Serial.print(" ->");
}
if (i_dataBuffer == (((dataBuffer[0] & IR_MASK_MSG_INFO) - 2) * bitPerByte))
{
Serial.print(" <-");
}
}
#endif
if (!isAvailable && isData && !isWrongPack)
{
if (i_dataBuffer == 8 * msgBytes)
{ // Ппервый байт
packSize = dataBuffer[0] & IR_MASK_MSG_INFO;
#ifdef IRDEBUG_INFO
Serial.print(" [");
Serial.print(packSize);
Serial.print("] ");
#endif
}
if (packSize && (i_dataBuffer == packSize * bitPerByte))
{ // Конец
#ifdef IRDEBUG_INFO
Serial.print(" END DATA " + crcCheck(packSize - crcBytes, crcValue) ? "OK " : "ERR ");
#endif
packInfo.buffer = dataBuffer;
packInfo.crc = crcValue;
packInfo.err = errors;
packInfo.packSize = packSize;
packInfo.rTime = riseSyncTime;
isRecive = false;
isAvailable = crcCheck(packSize - crcBytes, crcValue);
#ifdef BRUTEFORCE_CHECK
if (!isAvailable) // Исправление первого бита // Очень большая затычка...
for (size_t i = 0; i < min(packSize - crcBytes*2, dataByteSizeMax); ++i)
{
for (int j = 0; j < 8; ++j)
{
// инвертируем бит
dataBuffer[i] ^= 1 << j;
isAvailable = crcCheck(packSize - crcBytes, crcValue);
// обратно инвертируем бит в исходное состояние
if (isAvailable)
{
#ifdef IRDEBUG_INFO
Serial.println("!!!INV!!!");
#endif
goto OUT_BRUTEFORCE;
}
else
{
dataBuffer[i] ^= 1 << j;
}
}
}
OUT_BRUTEFORCE:;
#endif
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
}
bool IR_DecoderRaw::crcCheck(uint8_t len, crc_t &crc)
{
bool crcOK = false;
crc = 0;
crc = (crc8(dataBuffer, 0, len, poly1) << 8) & ~((crc_t)0xFF);
crc |= crc8(dataBuffer, 0, len + 1, poly2) & (crc_t)0xFF;
if (
crc &&
dataBuffer[len] == (crc >> 8) & 0xFF &&
dataBuffer[len + 1] == (crc & 0xFF))
{
crcOK = true;
}
else
{
crcOK = false;
}
return crcOK;
}
uint16_t IR_DecoderRaw::ceil_div(uint16_t val, uint16_t divider)
{
int ret = val / divider;
if ((val << 4) / divider - (ret << 4) >= 8)
ret++;
return ret;
}
// IRDEBUG FUNC
#ifdef IRDEBUG
inline void IR_DecoderRaw::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_DecoderRaw::infoPulse(uint8_t pin, uint8_t count)
{
for (size_t i = 0; i < count; i++)
{
digitalWrite(pin, 1);
digitalWrite(pin, 0);
}
}
#endif