#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(uint16_t addr, IR_Encoder* encPair = nullptr) : addrSelf(addr), encoder(encPair) { rawBuffer = new uint8_t[bufferRawSize] { 0 }; prevRise = prevFall = prevPrevFall = prevPrevRise = 0; start_RX(); } IR_Decoder::~IR_Decoder() { delete rawBuffer; } void IR_Decoder::writeToBuffer(bool bit) { if (!isBufferOverflow && !isPreamb) { if (HIGH_FIRST) { rawBuffer[(bufBitPos >> 3)] |= bit << (7 - (bufBitPos & ~(~0 << 3))); }/* else { rawBuffer[(bufBitPos >> 3)] |= bit << (bufBitPos & ~(~0 << 3)); } */ #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; } } if (bufBitPos >= bufferRawSize * 8 - 1) { isBufferOverflow = true; } bufBitPos++; } } 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() { resetAvaliable(); isBufferOverflow = false; memset(rawBuffer, 0x00, bufferRawSize); bufBitPos = 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::isr() { // в прерывании вызываем isr() if (isPairSending) return; if (micros() - prevRise > IR_timeout) { // первый isRecive = true; isPreamb = true; frontCounter = preambFronts - 1U; errorCounter = 0; riseSyncTime = bitTime /* 1100 */; start_RX(); } if (frontCounter > 0) { // в преамбуле uint32_t risePeriod = micros() - prevRise; if ((PIND >> 2) & 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 >> 2) & 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