IR-protocol/IR_DecoderRaw.cpp
2024-03-15 16:08:06 +03:00

551 lines
17 KiB
C++
Raw Permalink 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 = nullptr) : isrPin(isrPin), encoder(encPair)
{
id = addr;
prevRise = prevFall = prevPrevFall = prevPrevRise = 0;
if (encPair != nullptr)
{
encPair->decPair = this;
}
}
//////////////////////////////////// isr ///////////////////////////////////////////
void IR_DecoderRaw::isr()
{
if (isPairSending)
return;
subBuffer[currentSubBufferIndex].next = nullptr;
subBuffer[currentSubBufferIndex].dir = (PIND >> isrPin) & 1;
subBuffer[currentSubBufferIndex].time = micros();
if (firstUnHandledFront == nullptr)
{
firstUnHandledFront = &subBuffer[currentSubBufferIndex]; // Если нет необработанных данных - добавляем их
isSubBufferOverflow = false;
}
else
{
if (firstUnHandledFront == &subBuffer[currentSubBufferIndex])
{ // Если контроллер не успел обработать новый сигнал, принудительно пропускаем его
firstUnHandledFront = firstUnHandledFront->next;
isSubBufferOverflow = true;
#ifdef IRDEBUG_INFO
// Serial.println();
Serial.println(" ISR BUFFER OVERFLOW ");
// Serial.println();
#endif
}
}
if (lastFront == nullptr)
{
lastFront = &subBuffer[currentSubBufferIndex];
}
else
{
lastFront->next = &subBuffer[currentSubBufferIndex];
lastFront = &subBuffer[currentSubBufferIndex];
}
currentSubBufferIndex == (subBufferSize - 1) ? currentSubBufferIndex = 0 : currentSubBufferIndex++; // Закольцовка буффера
}
////////////////////////////////////////////////////////////////////////////////////
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 */;
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;
uint8_t oldSREG = SREG;
cli();
listenStart();
if (firstUnHandledFront == nullptr)
{
isSubBufferOverflow = false;
SREG = oldSREG;
return;
} // Если данных нет - ничего не делаем
currentFront = *((FrontStorage *)firstUnHandledFront); // найти следующий необработанный фронт/спад
SREG = oldSREG;
if (currentFront.next == nullptr)
{
isRecive = false;
return;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////
if (currentFront.time > prevRise && currentFront.time - prevRise > IR_timeout * 2 && !isRecive)
{ // первый
preambFrontCounter = preambFronts - 1U;
if (!currentFront.dir)
{
#ifdef IRDEBUG_INFO
// Serial.print(" currentFront.time: "); Serial.print(currentFront.time);
// Serial.print(" currentFront.dir: "); Serial.print(currentFront.dir ? "UP" : "DOWN");
// Serial.print(" next: "); Serial.print(currentFront.next == nullptr);
// Serial.print(" prevRise: "); Serial.print(prevRise);
// Serial.print(" SUB: "); Serial.println(currentFront.time - prevRise);
#endif
isRecive = true;
isWrongPack = false;
}
}
if (preambFrontCounter)
{ // в преамбуле
uint32_t risePeriod;
risePeriod = currentFront.time - prevRise;
if (currentFront.dir && risePeriod < IR_timeout)
{ // __/``` ↑ и мы в внутри пакета
if (risePeriod < riseTimeMin << 1)
{ // fix рваной единицы
preambFrontCounter += 2;
errors.other++;
}
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;
}
// определить направление фронта
if (currentFront.dir)
{ // Если __/``` ↑
uint16_t risePeriod = currentFront.time - prevRise;
uint16_t highTime = currentFront.time - prevFall;
uint16_t lowTime = prevFall - prevRise;
int8_t highCount = 0;
int8_t lowCount = 0;
int8_t allCount = 0;
bool invertErr = false;
if (!isPreamb)
{
if (risePeriod < IR_timeout && !isBufferOverflow && risePeriod > riseTimeMin && !isWrongPack)
{
// Мы в пределах таймаута и буффер не переполнен и 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++;
errors.other++;
#ifdef IRDEBUG
errPulse(errOut, 2);
#endif
}
if (lowCount + highCount > allCount)
{ // fix ошибочных сдвигов
if (lowCount > highCount)
{ // Лишние нули
lowCount = allCount - highCount;
errors.lowSignal += lowCount;
#ifdef IRDEBUG
errPulse(errOut, 3);
#endif
}
else if (lowCount < highCount)
{ // Лишние единицы
highCount = allCount - lowCount;
errors.highSignal += highCount;
#ifdef IRDEBUG
errPulse(errOut, 4);
#endif
// неизвестный случай Инверсит след бит или соседние
// Очень редко
// TODO: Отловить проверить
}
else if (lowCount == highCount)
{
invertErr = true;
// Serial.print("...");
errors.other += allCount;
}
// errorCounter += allCount;
}
// errorCounter += allCount;
// errors.other+=allCount;
if (lowCount < highCount)
{
errors.highSignal += highCount;
}
else
{
errors.lowSignal += lowCount;
}
#ifdef IRDEBUG
errPulse(errOut, 1);
#endif
for (int8_t i = 0; i < lowCount && 8 - i; i++)
{ // отправка LOW битов, если есть
if (i == lowCount - 1 && invertErr)
{
invertErr = false;
writeToBuffer(!LOW);
#ifdef IRDEBUG
digitalWrite(wrLow, 1);
#endif
}
else
{
writeToBuffer(LOW);
#ifdef IRDEBUG
digitalWrite(wrLow, 1);
#endif
}
}
for (int8_t i = 0; i < highCount && 8 - i; i++)
{ // отправка HIGH битов, если есть
if (i == highCount - 1 && invertErr)
{
invertErr = false;
writeToBuffer(!HIGH);
#ifdef IRDEBUG
digitalWrite(wrLow, 1);
#endif
}
else
{
writeToBuffer(HIGH);
#ifdef IRDEBUG
digitalWrite(wrHigh, 1);
#endif
}
}
}
#ifdef IRDEBUG
digitalWrite(wrHigh, 0);
digitalWrite(wrLow, 0);
#endif
}
}
if (risePeriod > riseTimeMax / 2 || highCount || lowCount)
{ // комплексный фикс рваной единицы
prevPrevRise = prevRise;
prevRise = currentFront.time;
}
else
{
errors.other++;
#ifdef IRDEBUG
errPulse(errOut, 5);
#endif
}
}
else
{ // Если ```\__ ↓
if (currentFront.time - prevFall > riseTimeMin)
{
prevPrevFall = prevFall;
prevFall = currentFront.time;
}
else
{
#ifdef IRDEBUG
// errPulse(errOut, 5);
#endif
}
}
if (isPreamb && preambFrontCounter <= 0)
{
prevRise = currentFront.time + riseTime;
}
#ifdef IRDEBUG
digitalWrite(writeOp, isPreamb);
#endif
////////////////////////////////////////////////////////////////////////////////////////////////////////////
oldSREG = SREG;
cli();
if (firstUnHandledFront != nullptr)
{
firstUnHandledFront = firstUnHandledFront->next; // переместить флаг на следующий элемент для обработки (next or nullptr)
}
SREG = oldSREG;
}
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 ");
#endif
packInfo.buffer = dataBuffer;
packInfo.crc = crcValue;
packInfo.err = errors;
packInfo.packSize = packSize;
packInfo.rTime = riseSyncTime;
isRecive = false;
isAvailable = crcCheck(packSize - crcBytes, crcValue);
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
}
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