#include "IR_Decoder.h" #include "IR_Encoder.h" #define IRDEBUG_INFO #define checkAddr(h, l) (\ ((uint16_t)((dataBuffer[h] << 8) | dataBuffer[l]) == id) || \ ((uint16_t)((dataBuffer[h] << 8) | dataBuffer[l]) >= IR_Broadcast)\ ) IR_Decoder::IR_Decoder(const uint8_t isrPin, uint16_t addr, IR_Encoder* encPair = nullptr) : isrPin(isrPin), id(addr), encoder(encPair) { // rawBuffer = new uint8_t[bufferRawSize] { 0 }; dataBuffer = new uint8_t[dataByteSizeMax] { 0 }; prevRise = prevFall = prevPrevFall = prevPrevRise = 0; // start_RX(); } IR_Decoder::~IR_Decoder() { delete dataBuffer; } //////////////////////////////////// isr /////////////////////////////////////////// void IR_Decoder::isr() { if (isPairSending) return; subBuffer[currentSubBufferIndex].next = nullptr; subBuffer[currentSubBufferIndex].dir = (PIND >> isrPin) & 1; subBuffer[currentSubBufferIndex].time = micros(); if (firstUnHandledFront == nullptr) { firstUnHandledFront = &subBuffer[currentSubBufferIndex]; // Если нет необработанных данных - добавляем их } else { if (firstUnHandledFront == &subBuffer[currentSubBufferIndex]) { // Если контроллер не успел обработать новый сигнал, принудительно пропускаем его firstUnHandledFront = firstUnHandledFront->next; #ifdef IRDEBUG_INFO // Serial.println(); // Serial.println("ERROR"); // 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_Decoder::start_RX() { #ifdef IRDEBUG_INFO Serial.print("\n>"); #endif errors.reset(); isBufferOverflow = false; isCrcCorrect = 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_Decoder::listen() { if (isRecive && ((micros() - prevRise) > IR_timeout * 2)) { isRecive = false; start_RX(); } } void IR_Decoder::tick() { FrontStorage currentFront; noInterrupts(); listen(); if (firstUnHandledFront == nullptr) { interrupts(); return; } //Если данных нет - ничего не делаем currentFront = *((FrontStorage*)firstUnHandledFront); //найти следующий необработанный фронт/спад interrupts(); //////////////////////////////////////////////////////////////////////////////////////////////////////////// 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; } } if (preambFrontCounter > 0) { // в преамбуле uint32_t 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(dataBuffer, 1, 0, errors, 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 //////////////////////////////////////////////////////////////////////////////////////////////////////////// firstUnHandledFront = firstUnHandledFront->next; //переместить флаг на следующий элемент для обработки (next or nullptr) } void IR_Decoder::writeToBuffer(bool bit) { if (i_dataBuffer > dataByteSizeMax * 8) {// проверка переполнения //TODO: Буффер переполнен! #ifdef IRDEBUG_INFO Serial.println("OverBuf"); #endif isBufferOverflow = true; } if (isBufferOverflow || isPreamb || isWrongPack) 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)) { // start_RX(); // firstUnHandledFront = firstUnHandledFront->next; // firstUnHandledFront = nullptr; #ifdef IRDEBUG_INFO Serial.print("****************"); #endif }; }//**************************************************************************************************// // Serial.print(bit); #ifdef IRDEBUG bit ? infoPulse(writeOp, 2) : infoPulse(writeOp, 1); #endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //const auto testval = bufferBitSizeMax; #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) * bitPerByte)) { Serial.print(" <-"); } } #endif if ((i_dataBuffer >= (8 * msgBytes)) && !isCrcCorrect) { uint16_t crcValue; switch ((dataBuffer[0] >> 5) & IR_MASK_MSG_TYPE) { case IR_MSG_ACCEPT: packToOutClass( ((msgBytes + addrBytes + crcBytes) * bitPerByte), // endBitOffset (msgBytes + addrBytes), // bytesToCheck 1, // addressForCheck_Offset &gotAccept // objFine ); break; case IR_MSG_REQUEST: packToOutClass( ((msgBytes + addrBytes + addrBytes + crcBytes) * bitPerByte), // endBitOffset (msgBytes + addrBytes + addrBytes), // bytesToCheck 3, // addressForCheck_Offset &gotRequest // objFine ); break; case IR_MSG_DATA_ACCEPT: case IR_MSG_DATA_NOACCEPT: packToOutClass( (((dataBuffer[0] & IR_MASK_MSG_INFO) + crcBytes) * bitPerByte), // endBitOffset (dataBuffer[0] & IR_MASK_MSG_INFO), // bytesToCheck 3, // addressForCheck_Offset &gotData, // objFine &gotRawData // objWrong ); break; default: break; } }/**/ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// } void IR_Decoder::packToOutClass(uint8_t endBitOffset, uint8_t bytesToCheck, uint8_t addressForCheckOffset, IDataPack* objFine, IDataPack* objWrong = nullptr) { uint16_t crcValue; IDataPack* objResult = nullptr; if (i_dataBuffer == endBitOffset) { #ifdef IRDEBUG_INFO Serial.print(" IN "); #endif isCrcCorrect = crcCheck(bytesToCheck, crcValue); if (isCrcCorrect && checkAddr(addressForCheckOffset, addressForCheckOffset + 1)) { #ifdef IRDEBUG_INFO Serial.println(" OK "); #endif objResult = objFine; } else { objResult = objWrong; #ifdef IRDEBUG_INFO Serial.println(" NOT OK "); #endif } if (objWrong != nullptr) { objResult->isAvaliable = true; objResult->set(dataBuffer, bytesToCheck + crcBytes, crcValue, errors, riseSyncTime); } isRecive = false; } } bool IR_Decoder::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_Decoder::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_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