#include "IR_DecoderRaw.h" #include "IR_Encoder.h" IR_DecoderRaw::IR_DecoderRaw(const uint8_t pin, uint16_t addr, IR_Encoder *encPair) : encoder(encPair) { setPin(pin); 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 } bool IR_DecoderRaw::isSubOverflow() { noInterrupts(); volatile bool ret = isSubBufferOverflow; interrupts(); return ret; } bool IR_DecoderRaw::availableRaw() { if (isAvailable) { isAvailable = false; return true; } else { return false; } }; //////////////////////////////////// isr /////////////////////////////////////////// volatile uint32_t time_; void IR_DecoderRaw::isr() { // Serial.print("ISR\n"); if(isPairSending){ return; } 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 = port->IDR & mask; edge.time = time_; subBuffer.push(edge); } //////////////////////////////////////////////////////////////////////////////////// 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 */; #ifdef IRDEBUG wrCounter = 0; #endif 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 / 4 || 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(uint16_t(packSize - crcBytes * 2U), uint16_t(dataByteSizeMax)); ++i) { for (int j = 0; j < 8; ++j) { // инвертируем бит dataBuffer[i] ^= 1 << j; isAvailable = crcCheck(min(uint16_t(packSize - crcBytes), uint16_t(dataByteSizeMax - 1U)), 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