#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(const uint8_t isrPin, uint16_t addr, IR_Encoder* encPair = nullptr) : isrPin(isrPin), addrSelf(addr), encoder(encPair) { rawBuffer = new uint8_t[bufferRawSize] { 0 }; dataBuffer = rawBuffer; prevRise = prevFall = prevPrevFall = prevPrevRise = 0; start_RX(); } IR_Decoder::~IR_Decoder() { delete rawBuffer; } void IR_Decoder::writeToBuffer(bool bit) { if (isBufferOverflow || isPreamb) return; // Переключение флага, data или syncBit if (bufBitPos == nextControlBit) { nextControlBit += (isData ? syncBits : bitPerByte); isData = !isData; i_syncBit = 0; Serial.print(" "); } if (isData) { // Запись битов в dataBuffer 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)] & 1 << (7 - (i_dataBuffer - 1) % 8) & 1)) { bufBitPos++; i_syncBit++; } else { i_syncBit = 0; errorCounter++; Serial.print("E"); // 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++; } } Serial.print(bit); // if (bufBitPos >= bufferRawSize * 8 - 1) { isBufferOverflow = true; } /* #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, riseSyncTime); 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, riseSyncTime); } } 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, riseSyncTime); } else { gotRawData._isAvaliable = true; gotRawData._set(dataBuffer, (dataSize)+crcBytes, crcValue, errorCounter, riseSyncTime); } } break; default: break; } }/**/ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// } 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() { // Serial.println(); // Serial.println(printBytes(dataBuffer, dataByteSizeMax-1, BIN)); // Serial.println(); resetAvaliable(); isBufferOverflow = false; memset(rawBuffer, 0x00, bufferRawSize); bufBitPos = 0; isData = true; i_dataBuffer = 0; nextControlBit = bitPerByte; i_syncBit = 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::listen() { if (isRecive && micros() - prevRise > IR_timeout * 2) { isRecive = false; } } //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////// isr /////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// void IR_Decoder::tick() { if (firstUnHandledFront == nullptr) return; //Если данных нет - ничего не делаем FrontStorage currentFront; //найти следующий необработанный фронт/спад noInterrupts(); currentFront = *((FrontStorage*)firstUnHandledFront); interrupts(); //////////////////////////////////////////////////////////////////////////////////////////////////////////// if (currentFront.time - prevRise > IR_timeout && currentFront.dir) { // первый ↑ isRecive = true; isPreamb = true; frontCounter = preambFronts - 1U; errorCounter = 0; riseSyncTime = bitTime /* 1100 */; start_RX(); // Serial.println(); // Serial.print("currentFront.time: "); Serial.println(currentFront.time); // Serial.print("currentFront.dir: "); Serial.println(currentFront.dir ? "UP" : "Down"); // Serial.print("prevRise: "); Serial.println(prevRise); // Serial.print("frontCounter: "); Serial.println(frontCounter); // prevRise = currentFront.time; } if (frontCounter > 0) { // в преамбуле uint32_t risePeriod = currentFront.time - prevRise; if (currentFront.dir && risePeriod < IR_timeout) { // __/``` ↑ и мы в внутри пакета if (risePeriod < riseTimeMin << 1) { // fix рваной единицы frontCounter += 2; errorCounter++; } else { if (freeFrec) { riseSyncTime = (riseSyncTime + risePeriod / 2) / 2; } // tuner } } else { /* riseSyncTime = bitTime; */ } // сброс тюнера frontCounter--; // Serial.print("frontCounter: "); Serial.println(frontCounter); } 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; 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 битов, если есть writeToBuffer(LOW); #ifdef IRDEBUG digitalWrite(wrLow, 1); #endif } for (int8_t i = 0; i < highCount && 8 - i; i++) { // отправка HIGH битов, если есть 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 { errorCounter++; #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 && frontCounter <= 0) { prevRise = currentFront.time + riseTime; } #ifdef IRDEBUG digitalWrite(writeOp, isPreamb); #endif //////////////////////////////////////////////////////////////////////////////////////////////////////////// firstUnHandledFront = firstUnHandledFront->next; //переместить флаг на следующий элемент для обработки (next or nullptr) } void IR_Decoder::isr() { // в прерывании вызываем 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; Serial.println(); Serial.println("ERROR"); Serial.println(); } } if (lastFront == nullptr) { lastFront = &subBuffer[currentSubBufferIndex]; } else { lastFront->next = &subBuffer[currentSubBufferIndex]; lastFront = &subBuffer[currentSubBufferIndex]; } currentSubBufferIndex == (subBufferSize - 1) ? currentSubBufferIndex = 0 : currentSubBufferIndex++; } void IR_Decoder::noFunc() { //////////////////////////////////////////////////////////////////////////////////////////////////////////// if (micros() - prevRise > IR_timeout && (PIND >> isrPin) & 1) { // первый isRecive = true; isPreamb = true; frontCounter = preambFronts - 1U; errorCounter = 0; riseSyncTime = bitTime /* 1100 */; start_RX(); Serial.println("First!"); } if (frontCounter > 0) { // в преамбуле uint32_t risePeriod = micros() - prevRise; if ((PIND >> isrPin) & 1 && risePeriod < IR_timeout) { // __/``` ↑ и мы в внутри пакета if (risePeriod < riseTimeMin << 1) { // fix рваной единицы frontCounter += 2; errorCounter++; } else { if (freeFrec) { riseSyncTime = (riseSyncTime + risePeriod / 2) / 2; } // tuner } } else { /* riseSyncTime = bitTime; */ } // сброс тюнера frontCounter--; //Serial.println(frontCounter); } else { if (isPreamb) {// первый фронт после gotTune._set(riseSyncTime); } isPreamb = false; } // определить направление фронта if ((PIND >> isrPin) & 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