diff --git a/.gitignore b/.gitignore index d833061..75ec3f0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1 @@ -.vscode/* -!.vscode/arduino.json \ No newline at end of file +.vscode/* \ No newline at end of file diff --git a/.vscode/arduino.json b/.vscode/arduino.json deleted file mode 100644 index 35ff5f8..0000000 --- a/.vscode/arduino.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "port": "COM3", - "board": "arduino:avr:uno", - "sketch": "IR.ino" -} \ No newline at end of file diff --git a/IR-Protocol.ino b/IR-Protocol.ino new file mode 100644 index 0000000..2333e7e --- /dev/null +++ b/IR-Protocol.ino @@ -0,0 +1,404 @@ +#include "IR_Decoder.h" +#include "IR_Encoder.h" +#include "TimerStatic.h" +#include "MemoryCheck.h" +/////////////// Pinout /////////////// + +#define encForward_PIN 5 +#define encBackward_PIN 6 + +#define LoopOut 12 +#define ISR_Out 10 + +#define TestOut 13 + +//////////////// Ini ///////////////// + +#define INFO "IR_FOX TEST" +#define SERIAL_SPEED 115200 + +//////////////// Var ///////////////// + +IR_Decoder decForward(2, 555); +IR_Decoder decBackward(3, 777); + +IR_Encoder encForward(42, encForward_PIN, &decBackward); +// IR_Encoder encBackward(321, encBackward_PIN); +// IR_Encoder encTree(325, A2); + +//////////////////////// Функции прерываний //////////////////////// + +void decForwardISR() { + decForward.isr(); +} + +void decBackwardISR() { + decBackward.isr(); +} + +static uint8_t* portOut; +ISR(TIMER2_COMPA_vect) { + encForward.isr(); + // encBackward.isr(); + // encTree.isr(); + //TODO: Сделать выбор порта + *portOut = (*portOut & 0b11001111) | + ( + encForward.ir_out_virtual << 5U + // | encBackward.ir_out_virtual << 6U + // | encTree.ir_out_virtual << 2U + ); +} +///////////////////////////////////////////////////////////////////// +uint8_t data0 [] = { }; +uint8_t data1 [] = { 42 }; +uint8_t data2 [] = { 42 , 127 }; +uint8_t data3 [] = { 42 , 127, 137 }; +uint8_t data4 [] = { 42 , 127, 137, 255 }; + +uint32_t loopTimer; +uint8_t sig = 255; + +uint16_t targetAddr = IR_Broadcast; +Timer t1(500, millis, []() { + + // Serial.println(sig); + + switch (sig) { + case 0: + encForward.sendData(targetAddr, data0, sizeof(data0)); + break; + case 1: + encForward.sendData(targetAddr, data1, sizeof(data1)); + break; + case 2: + encForward.sendData(targetAddr, data2, sizeof(data2)); + break; + case 3: + encForward.sendData(targetAddr, data3, sizeof(data3)); + break; + case 4: + encForward.sendData(targetAddr, data4, sizeof(data4)); + break; + + case 10: + encForward.sendData(targetAddr, data0, sizeof(data0), true); + break; + case 11: + encForward.sendData(targetAddr, data1, sizeof(data1), true); + break; + case 12: + encForward.sendData(targetAddr, data2, sizeof(data2), true); + break; + case 13: + encForward.sendData(targetAddr, data3, sizeof(data3), true); + break; + case 14: + encForward.sendData(targetAddr, data4, sizeof(data4), true); + break; + + + + case 20: + encForward.sendBack(); + break; + case 21: + encForward.sendBack(data1, sizeof(data1)); + break; + case 22: + encForward.sendBack(data2, sizeof(data2)); + break; + case 23: + encForward.sendBack(data3, sizeof(data3)); + break; + case 24: + encForward.sendBack(data4, sizeof(data4)); + break; + + case 30: + encForward.sendBackTo(targetAddr); + break; + case 31: + encForward.sendBackTo(targetAddr, data1, sizeof(data1)); + break; + case 32: + encForward.sendBackTo(targetAddr, data2, sizeof(data2)); + break; + case 33: + encForward.sendBackTo(targetAddr, data3, sizeof(data3)); + break; + case 34: + encForward.sendBackTo(targetAddr, data4, sizeof(data4)); + break; + + case 41: + encForward.sendRequest(targetAddr); + break; + case 42: + encForward.sendAccept(targetAddr); + break; + + + default: + break; + } + // encBackward.sendData(IR_Broadcast, data2); + // encTree.sendData(IR_Broadcast, rawData3); +}); +Timer t2(500, millis, []() { + digitalToggle(13); +}); +///////////////////////////////////////////////////////////////////// +void setup() { + IR_Encoder::timerSetup(); + portOut = &PORTD; + + Serial.begin(SERIAL_SPEED); + Serial.println(F(INFO)); + + pinMode(A0, INPUT_PULLUP); + pinMode(A1, INPUT_PULLUP); + pinMode(A2, INPUT_PULLUP); + pinMode(A3, INPUT_PULLUP); + + pinMode(LoopOut, OUTPUT); + pinMode(ISR_Out, OUTPUT); + + pinMode(2, INPUT_PULLUP); + pinMode(3, INPUT_PULLUP); + + pinMode(8, OUTPUT); + pinMode(9, OUTPUT); + pinMode(11, OUTPUT); + pinMode(13, OUTPUT); + pinMode(encForward_PIN, OUTPUT); + pinMode(encBackward_PIN, OUTPUT); + pinMode(13, OUTPUT); + + + + IR_DecoderRaw* blindFromForward [] { &decForward, &decBackward }; + encForward.setBlindDecoders(blindFromForward, sizeof(blindFromForward) / sizeof(IR_DecoderRaw*)); + + + attachInterrupt(0, decForwardISR, CHANGE); // D2 + attachInterrupt(1, decBackwardISR, CHANGE); // D3 +} + +void loop() { + digitalToggle(LoopOut); + Timer::tick(); + + decForward.tick(); + decBackward.tick(); + + status(decForward); + status(decBackward); + + + // Serial.println(micros() - loopTimer); + // loopTimer = micros(); + // delayMicroseconds(120*5); + + if (Serial.available()) { + uint8_t in = Serial.parseInt(); + switch (in) { + case 100: + targetAddr = IR_Broadcast; + break; + case 101: + targetAddr = 555; + break; + case 102: + targetAddr = 777; + break; + + default: + sig = in; + break; + } + } +} + + + + + + +//test +void status(IR_Decoder& dec) { + if (dec.gotData.available()) { + String str; + if (/* dec.gotData.getDataPrt()[1] */1) { + str += ("Data on pin "); str += (dec.isrPin); str += "\n"; + + uint8_t msg = dec.gotData.getMsgRAW(); + str += (" MSG: "); + for (size_t i = 0; i < 8; i++) { + if (i == 3) str += " "; + str += (msg >> (7 - i)) & 1U; + } + + str += "\n"; + + str += (" DATA SIZE: "); str += (dec.gotData.getDataSize()); str += "\n"; + str += (" ADDRESS FROM: "); str += (dec.gotData.getAddrFrom()); str += "\n"; + str += (" ADDRESS TO: "); str += (dec.gotData.getAddrTo()); str += "\n"; + // str += (" CRC PACK: "); str += (dec.gotData.getCrcIN()); str += "\n"; + // str += (" CRC CALC: "); str += (dec.gotData.getCrcCALC()); str += "\n"; + str += "\n"; + + for (size_t i = 0; i < min(10, dec.gotData.getDataSize()); i++) { + switch (i) { + // case 0: + // str += (" ADDR: "); + // break; + // case 1: + // str += (" CMD: "); + // break; + + default: + str += (" Data["); str += (i); str += ("]: "); + break; + } + str += (dec.gotData.getDataPrt()[i]); str += "\n"; + } + + + str += ("\n*******ErrAll: "); str += (dec.gotData.getErrorCount()); str += "\n"; + str += ("**ErrDistance: "); str += ((int)(dec.gotData.getErrorHighSignal() - dec.gotData.getErrorLowSignal())); str += "\n"; + + str += "\n"; + } else { + str += ("SELF"); str += "\n"; + str += "\n"; + } + // obj->resetAvailable(); + Serial.write(str.c_str()); + } + + if (dec.gotBackData.available()) { + String str; + if (/* dec.gotData.getDataPrt()[1] */1) { + str += ("BackData on pin "); str += (dec.isrPin); str += "\n"; + + uint8_t msg = dec.gotBackData.getMsgRAW(); + str += (" MSG: "); + for (size_t i = 0; i < 8; i++) { + if (i == 3) str += " "; + str += (msg >> (7 - i)) & 1U; + } + + str += "\n"; + + str += (" DATA SIZE: "); str += (dec.gotBackData.getDataSize()); str += "\n"; + str += (" ADDRESS FROM: "); str += (dec.gotBackData.getAddrFrom()); str += "\n"; + // str += (" ADDRESS TO: "); str += (dec.gotBackData.getAddrTo()); str += "\n"; + // str += (" CRC PACK: "); str += (dec.gotBackData.getCrcIN()); str += "\n"; + // str += (" CRC CALC: "); str += (dec.gotBackData.getCrcCALC()); str += "\n"; + str += "\n"; + + for (size_t i = 0; i < min(10, dec.gotBackData.getDataSize()); i++) { + switch (i) { + // case 0: + // str += (" ADDR: "); + // break; + // case 1: + // str += (" CMD: "); + // break; + + default: + str += (" Data["); str += (i); str += ("]: "); + break; + } + str += (dec.gotBackData.getDataPrt()[i]); str += "\n"; + } + + + str += ("\n*******ErrAll: "); str += (dec.gotBackData.getErrorCount()); str += "\n"; + str += ("**ErrDistance: "); str += ((int)(dec.gotBackData.getErrorHighSignal() - dec.gotBackData.getErrorLowSignal())); str += "\n"; + + str += "\n"; + } else { + str += ("SELF"); str += "\n"; + str += "\n"; + } + // obj->resetAvailable(); + Serial.write(str.c_str()); + } + + if (dec.gotAccept.available()) { + String str; + if (/* dec.gotData.getDataPrt()[1] */1) { + str += ("Accept on pin "); str += (dec.isrPin); str += "\n"; + + uint8_t msg = dec.gotAccept.getMsgRAW(); + str += (" MSG: "); + for (size_t i = 0; i < 8; i++) { + if (i == 3) str += " "; + str += (msg >> (7 - i)) & 1U; + } + + str += "\n"; + + // str += (" DATA SIZE: "); str += (dec.gotAccept.getDataSize()); str += "\n"; + str += (" ADDRESS FROM: "); str += (dec.gotAccept.getAddrFrom()); str += "\n"; + // str += (" ADDRESS TO: "); str += (dec.gotAccept.getAddrTo()); str += "\n"; + // str += (" CRC PACK: "); str += (dec.gotAccept.getCrcIN()); str += "\n"; + // str += (" CRC CALC: "); str += (dec.gotAccept.getCrcCALC()); str += "\n"; + str += "\n"; + + str += (" Data: "); str += (dec.gotAccept.getCustomByte()); + + + + str += ("\n\n*******ErrAll: "); str += (dec.gotAccept.getErrorCount()); str += "\n"; + str += ("**ErrDistance: "); str += ((int)(dec.gotAccept.getErrorHighSignal() - dec.gotAccept.getErrorLowSignal())); str += "\n"; + + str += "\n"; + } else { + str += ("SELF"); str += "\n"; + str += "\n"; + } + // obj->resetAvailable(); + Serial.write(str.c_str()); + } + + if (dec.gotRequest.available()) { + String str; + if (/* dec.gotData.getDataPrt()[1] */1) { + str += ("Request on pin "); str += (dec.isrPin); str += "\n"; + + uint8_t msg = dec.gotRequest.getMsgRAW(); + str += (" MSG: "); + for (size_t i = 0; i < 8; i++) { + if (i == 3) str += " "; + str += (msg >> (7 - i)) & 1U; + } + + str += "\n"; + + // str += (" DATA SIZE: "); str += (dec.gotRequest.getDataSize()); str += "\n"; + str += (" ADDRESS FROM: "); str += (dec.gotRequest.getAddrFrom()); str += "\n"; + str += (" ADDRESS TO: "); str += (dec.gotRequest.getAddrTo()); str += "\n"; + // str += (" CRC PACK: "); str += (dec.gotRequest.getCrcIN()); str += "\n"; + // str += (" CRC CALC: "); str += (dec.gotRequest.getCrcCALC()); str += "\n"; + str += "\n"; + + + str += ("\n*******ErrAll: "); str += (dec.gotRequest.getErrorCount()); str += "\n"; + str += ("**ErrDistance: "); str += ((int)(dec.gotRequest.getErrorHighSignal() - dec.gotRequest.getErrorLowSignal())); str += "\n"; + + str += "\n"; + } else { + str += ("SELF"); str += "\n"; + str += "\n"; + } + // obj->resetAvailable(); + Serial.write(str.c_str()); + } + + +} + + diff --git a/IR.ino b/IR.ino deleted file mode 100644 index 1250a8d..0000000 --- a/IR.ino +++ /dev/null @@ -1,9 +0,0 @@ -#define SerialSpeed 115200 - -void setup() { - Serial.begin(SerialSpeed); -} - -void loop() { - -} \ No newline at end of file diff --git a/IR_Decoder.cpp b/IR_Decoder.cpp deleted file mode 100644 index fb33897..0000000 --- a/IR_Decoder.cpp +++ /dev/null @@ -1,349 +0,0 @@ -#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 }; - 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 >> 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 - - diff --git a/IR_Decoder.h b/IR_Decoder.h index 8397273..32ecb79 100644 --- a/IR_Decoder.h +++ b/IR_Decoder.h @@ -1,254 +1,68 @@ #pragma once -#include "IR_config.h" +#include "IR_DecoderRaw.h" +#include "PacketTypes.h" +#include "IR_Encoder.h" -//#define IRDEBUG +class IR_Decoder : public IR_DecoderRaw { + uint32_t acceptSendTimer; + bool isWaitingAcceptSend; + uint16_t addrAcceptSendTo; -#ifdef IRDEBUG -#define wrHigh A3 // Запись HIGH инициирована // green -#define wrLow A3 // Запись LOW инициирована // blue -#define writeOp 13 // Операция записи, 1 пульс для 0 и 2 для 1 // orange -// Исправленные ошибки // purle -// 1 пульс: fix -#define errOut A3 -#endif + uint16_t acceptDelay = 75; + uint8_t acceptCustomByte; -///////////////////////////////////////////////////////////////////////////////////////////////// - -#define riseTime riseSyncTime //* bitTime */ 893U // TODO: Должно высчитываться медианой -#define riseTolerance tolerance /* 250U */ // погрешность -#define riseTimeMax (riseTime + riseTolerance) -#define riseTimeMin (riseTime - riseTolerance) -#define aroundRise(t) (riseTimeMin < t && t < riseTimeMax) -#define IR_timeout ((riseTimeMax * 8) + syncBits +1) // us // таймаут в 8 data + 3 sync + 1 - -class IR_Encoder; -class IR_Decoder : private IR_FOX { - friend IR_Encoder; public: - uint16_t addrSelf; - IR_Decoder(const uint8_t isrPin, uint16_t addr, IR_Encoder* encPair = nullptr); - ~IR_Decoder(); + PacketTypes::Data gotData; + PacketTypes::DataBack gotBackData; + PacketTypes::Accept gotAccept; + PacketTypes::Request gotRequest; - // @brief Для прерывания - void isr(); + IR_Decoder(const uint8_t isrPin, uint16_t addr, IR_Encoder* encPair = nullptr) : IR_DecoderRaw(isrPin, addr, encPair) {} + void tick() { + IR_DecoderRaw::tick(); + if (available()) { + #ifdef IRDEBUG_INFO + Serial.println("PARSING RAW DATA"); + #endif + isWaitingAcceptSend = false; + switch (packInfo.buffer[0] >> 5 & IR_MASK_MSG_TYPE) { + case IR_MSG_DATA_ACCEPT: + case IR_MSG_DATA_NOACCEPT: + gotData.set(&packInfo, id); + break; + case IR_MSG_BACK: + case IR_MSG_BACK_TO: + gotBackData.set(&packInfo, id); + break; + case IR_MSG_REQUEST: + gotRequest.set(&packInfo, id); + break; + case IR_MSG_ACCEPT: + gotAccept.set(&packInfo, id); + break; - // @return Буффер переполнился - bool isOverflow() { return isBufferOverflow; }; - bool isReciving() { return isRecive; }; - // @brief Слушатель для работы isReciving() - void listen(); - - ////////////////////////////////////////////////////////////////////////// - - class InputData : protected IR_FOX { - friend IR_Decoder; - protected: - bool _isAvaliable = false; - uint8_t _msgType = 0; - uint16_t _addrFrom = 0; - uint16_t _addrTo = 0; - uint8_t* _data = nullptr; - uint8_t _dataRawSize = 0; - uint16_t _crcPackVal = 0; - uint16_t _crcCalcVal = 0; - uint16_t _errCount = 0; - uint16_t _bitPeriod = 0; - - void _set(uint8_t* ptr, uint8_t len, uint16_t crc, uint16_t err, uint16_t rTime) { - _crcCalcVal = crc; - _dataRawSize = len; - _errCount = err; - _bitPeriod = rTime; - if (_data != nullptr) { delete _data; _data = nullptr; } - _data = new uint8_t[len]; - for (uint8_t i = 0; i < len; i++) { _data[i] = ptr[i]; } - _msgType = _data[0]; - ini(); - _isAvaliable = true; + default: + break; + } + if (gotData.isAvailable && (gotData.getMsgType() == IR_MSG_DATA_ACCEPT)) { + acceptSendTimer = millis(); + addrAcceptSendTo = gotData.getAddrFrom(); + acceptCustomByte = crc8(gotData.getDataPrt(), 0, gotData.getDataSize(), poly1); + if (addrAcceptSendTo && addrAcceptSendTo < IR_Broadcast) isWaitingAcceptSend = true; + } } - - private: - virtual void ini(); - - public: - bool avaliable() { return _isAvaliable; }; - uint8_t msgInfo() { return _msgType & IR_MASK_MSG_INFO; }; - uint8_t msgType() { return (_msgType >> 5) & IR_MASK_MSG_TYPE; }; - uint8_t msgRAW() { return _msgType; }; - uint16_t errorCount() { return _errCount; }; - uint16_t crcIN() { return _crcPackVal; }; - uint16_t crcCALC() { return _crcCalcVal; }; - uint16_t tunerTime() { return _bitPeriod; }; - void resetAvaliable() { _isAvaliable = false; }; - }; - - ////////////////////////////////////////////////////////////////////////// - - class Data : public InputData { - public: - uint16_t addrFrom() { return _addrFrom; }; - uint16_t addrTo() { return _addrTo; }; - uint8_t dataSize() { return _dataRawSize - (msgBytes + addrBytes + addrBytes + crcBytes); }; - uint8_t* data() { return &_data[msgBytes + addrBytes + addrBytes]; }; - uint8_t dataRawSize() { return _dataRawSize; }; - uint8_t* dataRaw() { return _data; }; - bool isNeedAccept() { return ((_msgType >> 5) & IR_MASK_MSG_TYPE) == IR_MSG_DATA_ACCEPT; }; - String printRawData(uint8_t mode = 10) { - return printBytes(dataRaw(), dataRawSize(), mode); + if (isWaitingAcceptSend && millis() - acceptSendTimer > 75) { + encoder->sendAccept(addrAcceptSendTo, acceptCustomByte); + isWaitingAcceptSend = false; } - String printData(uint8_t mode = 10) { - return printBytes(data(), dataSize(), mode); - } - ~Data() {}; - private: - void ini() override { - _addrFrom = (_data[1] << 8) | _data[2]; - _addrTo = (_data[3] << 8) | _data[4]; - _crcPackVal = (_data[_dataRawSize - 2] << 8) | _data[_dataRawSize - 1]; - } - }; + } - // class RawData : public Data { - - // }; - - class Accept : public InputData { - public: - uint16_t addrFrom() { return _addrFrom; }; - - private: - void ini() override { - _addrFrom = (_data[1] << 8) | _data[2]; - _crcPackVal = (_data[3] << 8) | _data[4]; - } - }; - - class Request : public Accept { - public: - uint16_t addrTo() { return _addrTo; }; - private: - void ini() override { - _addrFrom = (_data[1] << 8) | _data[2]; - _addrTo = (_data[3] << 8) | _data[4]; - _crcPackVal = (_data[5] << 8) | _data[6]; - } - }; - - class RawTune { - friend IR_Decoder; - private: - bool _isAvaliable = false; - uint16_t _errCount = 0; - uint16_t _tune = 0; - public: - bool avaliable() { return _isAvaliable; }; - uint16_t getTune() { return _tune; }; - uint16_t errorCount() { return _errCount; }; - void resetAvaliable() { _isAvaliable = false; }; - private: - void _set(uint16_t val) { - _tune = val; - _isAvaliable = true; - } - }; - - Data gotData; - Data gotRawData; - // RawData gotRawData; - Accept gotAccept; - Request gotRequest; - RawTune gotTune; - - -private: - const uint8_t isrPin; - - IR_Encoder* encoder; - bool isPairSending = false; - bool IsPairSendLOW = false; - - - volatile bool isRecive = false; - - bool isWaitingAccept = false; - uint16_t addrWaitingFrom = 0; - - - uint16_t addrFrom = 0; - - uint16_t riseSyncTime = bitTime; - - volatile bool isRawAvaliable = false; - - volatile bool isMsgAvaliable = false; - volatile bool isFilterBufferAvaliable = false; - - volatile bool isBufferOverflow = false; - - volatile bool isPreamb = false; // флаг начальной последовости - bool HIGH_FIRST = true; // порядок приходящих битов - - //Буффер - const uint8_t bufferRawSize = - ((bufferBitSizeMax % 8 > 0) ? - (bufferBitSizeMax / 8) + 1 : - (bufferBitSizeMax / 8)); - const uint8_t bufferDataSize = dataByteSizeMax; // + crc - uint8_t* rawBuffer = nullptr; - uint8_t* dataBuffer = nullptr; - - volatile uint32_t prevRise, prevFall, prevPrevFall, prevPrevRise; - volatile uint16_t errorCounter = 0; - volatile int8_t frontCounter = 0; - volatile int16_t bufBitPos = 0; - crc_t crcValue = 0; -private: - uint8_t* getDataBuffer(bool reset = false); - bool crcCheck(uint8_t len); - - inline void writeToBuffer(bool); - inline void start_RX(); - void resetAvaliable(); - - uint16_t ceil_div(uint16_t, uint16_t); - //uint16_t sma = 0; - void SMA(uint16_t); - - //TODO: Сделать функцию медианы - void medi(uint16_t); - - // class Medi { - // public: - // uint16_t* arr; - // uint8_t size; - // uint8_t center; - - // Medi(uint8_t _size) : size(_size - 1) { - // arr = new uint16_t[size] { 0 }; - // center = size / 2; - // }; - - // void add(uint16_t newVal) { - // _add(newVal, center); - // } - - // void _add(uint16_t newVal, int8_t pos, bool f) { - // if (pos < 0 || pos > size) return; - - // if (newVal < arr[pos]) _add(newVal, pos-1, f); - // if (newVal > arr[pos]) _add(newVal, pos+1, f); - // } - - // ~Medi() { delete arr; } - // }; - - -#ifdef IRDEBUG - inline void errPulse(uint8_t pin, uint8_t count); - inline void infoPulse(uint8_t pin, uint8_t count); -#endif - - -}; \ No newline at end of file + void setAcceptDelay(uint16_t acceptDelay) { + this->acceptDelay = acceptDelay; + } + uint16_t getAcceptDelay() { + return this->acceptDelay; + } +}; diff --git a/IR_DecoderRaw.cpp b/IR_DecoderRaw.cpp new file mode 100644 index 0000000..401da09 --- /dev/null +++ b/IR_DecoderRaw.cpp @@ -0,0 +1,432 @@ +#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), id(addr), encoder(encPair) { + 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]; // Если нет необработанных данных - добавляем их + } else { + if (firstUnHandledFront == &subBuffer[currentSubBufferIndex]) { // Если контроллер не успел обработать новый сигнал, принудительно пропускаем его + firstUnHandledFront = firstUnHandledFront->next; + #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; + noInterrupts(); + listenStart(); + if (firstUnHandledFront == nullptr) { interrupts(); return; } //Если данных нет - ничего не делаем + currentFront = *((FrontStorage*)firstUnHandledFront); //найти следующий необработанный фронт/спад + interrupts(); + 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 > 0) { // в преамбуле + 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 + //////////////////////////////////////////////////////////////////////////////////////////////////////////// + firstUnHandledFront = firstUnHandledFront->next; //переместить флаг на следующий элемент для обработки (next or nullptr) +} + +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 + + diff --git a/IR_DecoderRaw.h b/IR_DecoderRaw.h new file mode 100644 index 0000000..e0a24e3 --- /dev/null +++ b/IR_DecoderRaw.h @@ -0,0 +1,117 @@ +#pragma once +#include "IR_config.h" + +//#define IRDEBUG + +#ifdef IRDEBUG +#define wrHigh A3 // Запись HIGH инициирована // green +#define wrLow A3 // Запись LOW инициирована // blue +#define writeOp 13 // Операция записи, 1 пульс для 0 и 2 для 1 // orange +// Исправленные ошибки // purle +// 1 пульс: fix +#define errOut A3 +#endif + +///////////////////////////////////////////////////////////////////////////////////////////////// + +#define riseTime riseSyncTime //* bitTime */ 893U // TODO: Должно высчитываться медианой +#define riseTolerance tolerance /* 250U */ // погрешность +#define riseTimeMax (riseTime + riseTolerance) +#define riseTimeMin (riseTime - riseTolerance) +#define aroundRise(t) (riseTimeMin < t && t < riseTimeMax) +#define IR_timeout (riseTimeMax * (8 + syncBits +1)) // us // таймаут в 8 data + 3 sync + 1 + + +class IR_Encoder; +class IR_DecoderRaw : virtual public IR_FOX { + friend IR_Encoder; +public: + const uint8_t isrPin; // Пин прерывания + + ////////////////////////////////////////////////////////////////////////// + /// @brief Конструктор + /// @param isrPin Номер вывода прерывания/данных от приёмника (2 или 3 для atmega 328p) + /// @param addr Адрес приёмника + /// @param encPair Указатель на передатчик, работающий в паре + IR_DecoderRaw(const uint8_t isrPin, uint16_t addr, IR_Encoder* encPair = nullptr); + + void isr(); // Функция прерывания + void tick(); // Обработка приёмника, необходима для работы + bool available() { if (isAvailable) { isAvailable = false; return true; } else { return false; } }; + bool isOverflow() { return isBufferOverflow; }; // Буффер переполнился + bool isReciving() { return isBufferOverflow; }; // Возвращает true, если происходит приём пакета + + ////////////////////////////////////////////////////////////////////////// +protected: + PackInfo packInfo; + uint16_t id; + IR_Encoder* encoder; // Указатель на парный передатчик +private: + ErrorsStruct errors; + bool isAvailable = false; + uint16_t packSize; + uint16_t crcValue; + volatile uint16_t isPairSending = 0; // Флаг передачи парного передатчика + volatile bool isRecive = false; // Флаг приёма + volatile bool isPreamb = false; // флаг начальной последовости + bool isBufferOverflow = false; // Флаг переполнения буффера данных + bool isWrongPack = false; // Флаг битого пакета + + uint16_t riseSyncTime = bitTime; // Подстраиваемое время бита в мкс + + //////////////////////////////////////////////////////////////////////// + volatile uint8_t currentSubBufferIndex; // Счетчик текущей позиции во вспомогательном буфере фронтов/спадов + + struct FrontStorage { // Структура для хранения времени и направления фронта/спада + volatile uint32_t time = 0; // Время + volatile bool dir = false; // Направление (true = ↑; false = ↓) + volatile FrontStorage* next = nullptr; // Указатель на следующий связанный фронт/спад, или nullptr если конец + }; + volatile FrontStorage* lastFront = nullptr; // Указатель последнего фронта/спада + volatile FrontStorage* firstUnHandledFront = nullptr; // Указатель первого необработанного фронта/спада + volatile FrontStorage subBuffer[subBufferSize]; // вспомогательный буфер для хранения необработанных фронтов/спадов + //////////////////////////////////////////////////////////////////////// + uint8_t dataBuffer[dataByteSizeMax] { 0 }; // Буффер данных + uint32_t prevRise, prevPrevRise, prevFall, prevPrevFall; // Время предыдущих фронтов/спадов + uint32_t risePeriod; + uint16_t errorCounter = 0; // Счётчик ошибок + int8_t preambFrontCounter = 0; // Счётчик __/``` ↑ преамбулы + int16_t bufBitPos = 0; // Позиция для записи бита в буффер + +private: + void listenStart(); // @brief Слушатель для работы isReciving() + + /// @brief Проверка CRC. Проверяет len байт со значением crc, пришедшим в пакете + /// @param len Длина в байтах проверяемых данных + /// @param crc Результат рассчёта crc (Выходной параметр) + /// @return true если crc верно + bool crcCheck(uint8_t len, uint16_t& crc); + + //////////////////////////////////////////////////////////////////////// + bool isData = true; // Флаг относится ли бит к данным, или битам синхронизации + uint16_t i_dataBuffer; // Счётчик буфера данных + uint8_t nextControlBit = bitPerByte; // Метка для смены флага isData + uint8_t i_syncBit; // Счётчик битов синхронизации + uint8_t err_syncBit; // Счётчик ошибок синхронизации + + /// @brief Запиь бита в буффер, а так же проверка битов синхранизации и их фильтрация + /// @param Бит данных + void writeToBuffer(bool); + //////////////////////////////////////////////////////////////////////// + + + void firstRX(); /// @brief Установка и сброс начальных значений и флагов в готовность к приёму данных + + /// @brief Целочисленное деление с округлением вверх + /// @param val Значение + /// @param divider Делитель + /// @return Результат + uint16_t ceil_div(uint16_t val, uint16_t divider); + + #ifdef IRDEBUG + inline void errPulse(uint8_t pin, uint8_t count); + inline void infoPulse(uint8_t pin, uint8_t count); + #endif + + +}; \ No newline at end of file diff --git a/IR_Encoder.cpp b/IR_Encoder.cpp index cad54f2..12b40e9 100644 --- a/IR_Encoder.cpp +++ b/IR_Encoder.cpp @@ -1,135 +1,320 @@ #include "IR_Encoder.h" -#include "IR_Decoder.h" +#include "IR_DecoderRaw.h" -IR_Encoder::IR_Encoder(uint16_t addr, uint8_t pin, uint8_t tune = 0, IR_Decoder* decPair) { - ir_out = pin; - addrSelf = addr; - decoder = decPair; - carrierTune = tune; - halfPeriod = (carrierPeriod / 2) - carrierTune; +#define LoopOut 12 +#define ISR_Out 10 +#define TestOut 13 -}; -IR_Encoder::~IR_Encoder() {}; - -void IR_Encoder::sendACK(uint16_t addrTo, uint8_t addInfo, bool forAll = false) { - uint8_t* ptr = new uint8_t[msgBytes + addrBytes + crcBytes] { 0 }; - - ptr[0] = IR_MSG_ACCEPT << 5; - ptr[0] |= addInfo & IR_MASK_MSG_INFO; - - // addr_self - if (!forAll) { - ptr[1] = addrSelf >> 8 & 0xFF; - ptr[2] = addrSelf & 0xFF; +IR_Encoder::IR_Encoder(uint16_t addr, uint8_t pin, IR_DecoderRaw* decPair = nullptr) { + id = addr; + this->decPair = decPair; + signal = noSignal; + isSending = false; + #if disablePairDec + if (decPair != nullptr) { + blindDecoders = new IR_DecoderRaw * [1] {decPair}; + decodersCount = 1; } - - // data crc - ptr[3] = crc8(ptr, 0, 3, poly1) & 0xFF; - ptr[4] = crc8(ptr, 0, 4, poly2) & 0xFF; - - rawSend(ptr, msgBytes + addrBytes + crcBytes); - - // освобождение ресурсов - delete ptr; - ptr = nullptr; + #endif + if (decPair != nullptr) { + decPair->encoder = this; + } +}; +void IR_Encoder::setBlindDecoders(IR_DecoderRaw* decoders [], uint8_t count) { + #if disablePairDec + if (blindDecoders != nullptr) delete [] blindDecoders; + #endif + decodersCount = count; + blindDecoders = decoders; } -void IR_Encoder::sendRequest(uint16_t addrTo, uint8_t addInfo) { - uint8_t* ptr = new uint8_t[msgBytes + addrBytes + crcBytes] { 0 }; - - ptr[0] = IR_MSG_REQUEST << 5; - ptr[0] |= addInfo & IR_MASK_MSG_INFO; - - // addr_self - ptr[1] = addrSelf >> 8 & 0xFF; - ptr[2] = addrSelf & 0xFF; - - //addr_to - ptr[3] = addrTo >> 8 & 0xFF; - ptr[4] = addrTo & 0xFF; - - // data crc - ptr[5] = crc8(ptr, 0, 5, poly1) & 0xFF; - ptr[6] = crc8(ptr, 0, 6, poly2) & 0xFF; - - rawSend(ptr, msgBytes + addrBytes + addrBytes + crcBytes); - - // освобождение ресурсов - delete ptr; - ptr = nullptr; -} - -void IR_Encoder::_sendData(uint16_t addrTo, uint8_t* data, uint8_t len, uint8_t msgType) { +IR_Encoder::~IR_Encoder() { + delete [] bitLow; + delete [] bitHigh; +}; +void IR_Encoder::sendData(uint16_t addrTo, uint8_t* data, uint8_t len, bool needAccept = false) { + if (len > bytePerPack) { return; } + constexpr uint8_t dataStart = msgBytes + addrBytes + addrBytes; + memset(sendBuffer, 0x00, dataByteSizeMax); uint8_t packSize = msgBytes + addrBytes + addrBytes + len + crcBytes; - uint8_t dataStart = msgBytes + addrBytes + addrBytes; - - // создание массива для отправки - uint8_t* ptr = new uint8_t[packSize] { 0 }; - //memset(ptr, 0, sizeof(ptr)); + uint8_t msgType = + ((needAccept ? IR_MSG_DATA_ACCEPT : IR_MSG_DATA_NOACCEPT) << 5) | (packSize & IR_MASK_MSG_INFO); // формирование массива // msg_type - ptr[0] = msgType; + sendBuffer[0] = msgType; // addr_self - ptr[1] = addrSelf >> 8 & 0xFF; - ptr[2] = addrSelf & 0xFF; + sendBuffer[1] = id >> 8 & 0xFF; + sendBuffer[2] = id & 0xFF; // addr_to - ptr[3] = addrTo >> 8 & 0xFF; - ptr[4] = addrTo & 0xFF; + sendBuffer[3] = addrTo >> 8 & 0xFF; + sendBuffer[4] = addrTo & 0xFF; for (uint16_t i = dataStart; i < dataStart + len; i++) { - ptr[i] = ((uint8_t*)data)[i - dataStart]; + sendBuffer[i] = ((uint8_t*)data)[i - dataStart]; } // data crc - ptr[packSize - crcBytes] = crc8(ptr, 0, packSize - crcBytes, poly1) & 0xFF; - ptr[packSize - crcBytes + 1] = crc8(ptr, 0, packSize - crcBytes + 1, poly2) & 0xFF; + sendBuffer[packSize - crcBytes] = crc8(sendBuffer, 0, packSize - crcBytes, poly1) & 0xFF; + sendBuffer[packSize - crcBytes + 1] = crc8(sendBuffer, 0, packSize - crcBytes + 1, poly2) & 0xFF; + + // if (decPair != nullptr) { + // decPair->isWaitingAccept = ((msgType >> 5) & IR_MASK_MSG_TYPE == IR_MSG_DATA_ACCEPT); + // if (decPair->isWaitingAccept) { + // decPair->addrWaitingFrom = addrTo; + // } + // } - if (decoder != nullptr) { - decoder->isWaitingAccept = ((msgType >> 5) & IR_MASK_MSG_TYPE == IR_MSG_DATA_ACCEPT); - decoder->addrWaitingFrom = addrTo; - } // отправка - rawSend(ptr, packSize); + rawSend(sendBuffer, packSize); +} - // освобождение ресурсов - delete ptr; - ptr = nullptr; +void IR_Encoder::sendAccept(uint16_t addrTo, uint8_t customByte = 0) { + constexpr uint8_t packsize = msgBytes + addrBytes + 1U + crcBytes; + memset(sendBuffer, 0x00, dataByteSizeMax); + sendBuffer[0] = IR_MSG_ACCEPT << 5; + sendBuffer[0] |= packsize & IR_MASK_MSG_INFO; // размер пакета + // addr_self + sendBuffer[1] = id >> 8 & 0xFF; + sendBuffer[2] = id & 0xFF; + + // Serial.print("\nRAW Accept to "); + // Serial.println(addrTo); + + sendBuffer[3] = customByte; + + // data crc + sendBuffer[4] = crc8(sendBuffer, 0, 4, poly1) & 0xFF; + sendBuffer[5] = crc8(sendBuffer, 0, 5, poly2) & 0xFF; + + rawSend(sendBuffer, packsize); +} + +void IR_Encoder::sendRequest(uint16_t addrTo) { + constexpr uint8_t packsize = msgBytes + addrBytes + addrBytes + crcBytes; + memset(sendBuffer, 0x00, dataByteSizeMax); + sendBuffer[0] = IR_MSG_REQUEST << 5; + sendBuffer[0] |= packsize & IR_MASK_MSG_INFO; + + // addr_self + sendBuffer[1] = id >> 8 & 0xFF; + sendBuffer[2] = id & 0xFF; + + //addr_to + sendBuffer[3] = addrTo >> 8 & 0xFF; + sendBuffer[4] = addrTo & 0xFF; + + // data crc + sendBuffer[5] = crc8(sendBuffer, 0, 5, poly1) & 0xFF; + sendBuffer[6] = crc8(sendBuffer, 0, 6, poly2) & 0xFF; + + rawSend(sendBuffer, packsize); +} + +void IR_Encoder::sendBack(uint8_t* data = nullptr, uint8_t len = 0) { + _sendBack(false, 0, data, len); +} + +void IR_Encoder::sendBackTo(uint16_t addrTo, uint8_t* data = nullptr, uint8_t len = 0) { + _sendBack(true, addrTo, data, len); +} + +void IR_Encoder::_sendBack(bool isAdressed, uint16_t addrTo, uint8_t* data, uint8_t len) { + if (len > bytePerPack) { return; } + memset(sendBuffer, 0x00, dataByteSizeMax); + uint8_t dataStart = msgBytes + addrBytes + (isAdressed ? addrBytes : 0); + + uint8_t packSize = msgBytes + addrBytes + (isAdressed ? addrBytes : 0) + min(1, len) + crcBytes; + uint8_t msgType = + ((isAdressed ? IR_MSG_BACK_TO : IR_MSG_BACK) << 5) | ((packSize) & (IR_MASK_MSG_INFO >> 1)); + + // формирование массива + // msg_type + sendBuffer[0] = msgType; + + // addr_from or data + sendBuffer[1] = id >> 8 & 0xFF; + sendBuffer[2] = id & 0xFF; + + // addr_to + sendBuffer[3] = addrTo >> 8 & 0xFF; + sendBuffer[4] = addrTo & 0xFF; + + for (uint16_t i = dataStart; i < dataStart + len; i++) { + sendBuffer[i] = ((uint8_t*)data)[i - dataStart]; + } + + // data crc + sendBuffer[packSize - crcBytes] = crc8(sendBuffer, 0, packSize - crcBytes, poly1) & 0xFF; + sendBuffer[packSize - crcBytes + 1] = crc8(sendBuffer, 0, packSize - crcBytes + 1, poly2) & 0xFF; + + // отправка + rawSend(sendBuffer, packSize); +} + +void IR_Encoder::setDecoder_isSending() { + if (decodersCount) { + for (uint8_t i = 0; i < decodersCount; i++) { + blindDecoders[i]->isPairSending ^= id; + } + + } } void IR_Encoder::rawSend(uint8_t* ptr, uint8_t len) { - /*tmp*/bool LOW_FIRST = false;/*tmp*/ - - if (decoder != nullptr) { decoder->isPairSending = true; } - - bool prev = 1; - bool next; - - send_EMPTY(preambPulse); // преамбула - for (uint16_t byteNum = 0; byteNum < len; byteNum++) { - sendByte(ptr[byteNum], &prev, LOW_FIRST); - if (byteNum < len - 1) { - next = ptr[byteNum + 1] & (LOW_FIRST ? 0b00000001 : 0b10000000); - } else { - next = 0; - } - addSync(&prev, &next); + if (isSending) { + //TODO: Обработка повторной отправки + return; } - if (decoder != nullptr) { decoder->isPairSending = false; } + setDecoder_isSending(); + cli(); + sendLen = len; + toggleCounter = preambToggle; // Первая генерация для первого signal + + dataBitCounter = bitPerByte - 1; + dataByteCounter = 0; + + preambFrontCounter = preambPulse * 2 - 1; // -1 за счёт генерации уже на этапе сразу после инициализации + dataSequenceCounter = bitPerByte * 2; + syncSequenceCounter = syncBits * 2; + + signal = preamb; + isSending = true; + state = HIGH; + + currentBitSequence = bitHigh; + isSending = true; + sei(); +} + + + +void IR_Encoder::isr() { + if (!isSending) return; + + ir_out_virtual = !ir_out_virtual && state; + + if (toggleCounter) { + toggleCounter--; + } else { + IsrStart: + switch (signal) { + case noSignal: + signal = preamb; + // сброс счетчиков + // ... + isSending = false; + setDecoder_isSending(); + return; + break; + + case preamb: + if (preambFrontCounter) { + preambFrontCounter--; + toggleCounter = preambToggle; // Вторая и последующие генерации для этого signal + } else {// Конец преамбулы, переход на следующий signal + signal = data; + state = !LOW; // Инверсное состояние первой генерации следующего signal + goto IsrStart; // Применение новых параметров в этй же итерации прерывания + } + + break; + + case data: + if (dataSequenceCounter) { + if (!(dataSequenceCounter & 1U)) { // если чётный - смена бита + currentBitSequence = ((sendBuffer[dataByteCounter] >> dataBitCounter) & 1U) ? bitHigh : bitLow; // определение текущего бита + dataBitCounter--; + } + toggleCounter = currentBitSequence[!state]; + dataSequenceCounter--; + } else { // Конец data, переход на следующий signal + syncLastBit = ((sendBuffer[dataByteCounter]) & 1U); + dataByteCounter++; + dataBitCounter = bitPerByte - 1; + dataSequenceCounter = bitPerByte * 2; + signal = sync; + goto IsrStart; // Применение новых параметров в этй же итерации прерывания + } + break; + + case sync: + if (syncSequenceCounter) { + if (!(syncSequenceCounter & 1U)) { // если чётный - смена бита + if (syncSequenceCounter == 2) { // Если последний бит + currentBitSequence = ((sendBuffer[dataByteCounter]) & 0b10000000) ? bitLow : bitHigh; + } else { + currentBitSequence = syncLastBit ? bitLow : bitHigh; // определение текущего бита + syncLastBit = !syncLastBit; + } + } + toggleCounter = currentBitSequence[!state]; + syncSequenceCounter--; + } else { // Конец sync, переход на следующий signal + signal = data; + syncSequenceCounter = syncBits * 2; + + if (dataByteCounter >= sendLen) { // определение конца данных + signal = noSignal; + } + goto IsrStart; // Применение новых параметров в этй же итерации прерывания + } + break; + + default: + return; + break; + } + + state = !state; + } +} + + + + + +void old() {/////////////////////////////////////////////////////// + // void IR_Encoder::rawSend(uint8_t* ptr, uint8_t len) { + // /*tmp*/bool LOW_FIRST = false;/*tmp*/ + + // if (decoders != nullptr) { decoders->isPairSending = true; } + + // bool prev = 1; + // bool next; + + // send_EMPTY(preambPulse); // преамбула + // for (uint16_t byteNum = 0; byteNum < len; byteNum++) { + // sendByte(ptr[byteNum], &prev, LOW_FIRST); + // if (byteNum < len - 1) { + // next = ptr[byteNum + 1] & (LOW_FIRST ? 0b00000001 : 0b10000000); + // } else { + // next = 0; + // } + // addSync(&prev, &next); + // } + + // if (decoders != nullptr) { decoders->isPairSending = false; } + + // } } void IR_Encoder::sendByte(uint8_t byte, bool* prev, bool LOW_FIRST) { uint8_t mask = LOW_FIRST ? 0b00000001 : 0b10000000; for (uint8_t bitShift = 8; bitShift; bitShift--) { + digitalWrite(9, HIGH); + digitalWrite(9, LOW); byte& mask ? send_HIGH(prev) : send_LOW(); *prev = byte & mask; LOW_FIRST ? mask <<= 1 : mask >>= 1; + digitalWrite(9, HIGH); + digitalWrite(9, LOW); } } @@ -152,39 +337,29 @@ void IR_Encoder::addSync(bool* prev, bool* next) { } void IR_Encoder::send_HIGH(bool prevBite = 1) { - if (prevBite) { - meanderBlock(bitPauseTakts * 2, halfPeriod, LOW); - meanderBlock(bitActiveTakts, halfPeriod, HIGH); - } else { // более короткий HIGH после нуля - meanderBlock(bitTakts - (bitActiveTakts - bitPauseTakts), halfPeriod, LOW); - meanderBlock(bitActiveTakts - bitPauseTakts, halfPeriod, HIGH); - } + + // if (/* prevBite */1) { + // meanderBlock(bitPauseTakts * 2, halfPeriod, LOW); + // meanderBlock(bitActiveTakts, halfPeriod, HIGH); + // } else { // более короткий HIGH после нуля + // meanderBlock(bitTakts - (bitActiveTakts - bitPauseTakts), halfPeriod, LOW); + // meanderBlock(bitActiveTakts - bitPauseTakts, halfPeriod, HIGH); + // } + } void IR_Encoder::send_LOW() { - meanderBlock(bitPauseTakts, halfPeriod, LOW); - meanderBlock(bitActiveTakts, halfPeriod, LOW); - meanderBlock(bitPauseTakts, halfPeriod, HIGH); + // meanderBlock(bitPauseTakts, halfPeriod, LOW); + // meanderBlock(bitActiveTakts, halfPeriod, LOW); + // meanderBlock(bitPauseTakts, halfPeriod, HIGH); } void IR_Encoder::send_EMPTY(uint8_t count) { - for (size_t i = 0; i < count * 2; i++) { - meanderBlock(bitPauseTakts * 2 + bitActiveTakts, halfPeriod, prevPreambBit); - prevPreambBit = !prevPreambBit; - } + // for (size_t i = 0; i < count * 2; i++) { + // meanderBlock((bitPauseTakts * 2 + bitActiveTakts), halfPeriod, prevPreambBit); + // prevPreambBit = !prevPreambBit; + // } + // meanderBlock(bitPauseTakts * 2 + bitActiveTakts, halfPeriod, 0); //TODO: Отодвинуть преамбулу } -void IR_Encoder::meanderBlock(uint16_t count, uint16_t _period, bool high = true) { - for (uint16_t i = 0; i < count << 1; i++) { - if ((i & 1)) { // Если чётное - //PORTC &= ~(1 << 3); // LOW - digitalWrite(ir_out, high ? LOW : LOW); - } else { // Если не четное - //PORTC |= 1 << 3; // HIGH - digitalWrite(ir_out, high ? HIGH : LOW); - } - - delayMicroseconds(_period); - } -} \ No newline at end of file diff --git a/IR_Encoder.h b/IR_Encoder.h index 42ec69b..be2c400 100644 --- a/IR_Encoder.h +++ b/IR_Encoder.h @@ -3,25 +3,14 @@ //TODO: Отложенная передача после завершения приема -class IR_Decoder; +class IR_DecoderRaw; class IR_Encoder : IR_FOX { - friend IR_Decoder; + friend IR_DecoderRaw; public: - /// @brief Вывод передатчика - uint8_t ir_out; - - /// @brief Адрес передатчика - uint16_t addrSelf; + uint16_t id; /// @brief Адрес передатчика private: - /// @brief предыдущий бит преамбулы - bool prevPreambBit = true; - /// @brief Подстройка несущей частоты - uint8_t carrierTune; - - /// @brief полупериод несущей частоты - uint8_t halfPeriod; public: /// @brief Класс передатчика @@ -29,38 +18,95 @@ public: /// @param pin Вывод передатчика /// @param tune Подстройка несущей частоты /// @param decPair Приёмник, для которого отключается приём в момент передачи передатчиком - IR_Encoder(uint16_t addr, uint8_t pin, uint8_t tune, IR_Decoder* decPair = nullptr); + IR_Encoder(uint16_t addr, uint8_t pin, IR_DecoderRaw* decPair = nullptr); - template - void sendData(uint16_t addrTo, T& data, bool needAccept = false); - void sendACK(uint16_t addrTo, uint8_t addInfo = 0, bool forAll = false); - void sendRequest(uint16_t addrTo, uint8_t addInfo = 0); + static void timerSetup() { + // TIMER2 Ini + uint8_t oldSREG = SREG; // Save global interupts settings + cli(); + // DDRB |= (1 << PORTB3); //OC2A (17) + TCCR2A = 0; + TCCR2B = 0; + // TCCR2A |= (1 << COM2A0); //Переключение состояния + + TCCR2A |= (1 << WGM21); // Clear Timer On Compare (Сброс по совпадению) + TCCR2B |= (1 << CS20); // Предделитель 1 + TIMSK2 |= (1 << OCIE2A); // Прерывание по совпадению + #if F_CPU == 16000000 + OCR2A = /* 465 */((F_CPU / (38000 * 2)) - 2); //38кГц + #elif F_CPU == 8000000 + OCR2A = ((F_CPU / (38000 * 2)) - 2); //38кГц Частота_мк / (Предделитель * Частота * 2) + #endif + + SREG = oldSREG; // Return interrupt settings + } + + void IR_Encoder::setBlindDecoders(IR_DecoderRaw* decoders [], uint8_t count); + void rawSend(uint8_t* ptr, uint8_t len); + void sendData(uint16_t addrTo, uint8_t* data, uint8_t len, bool needAccept = false); + void sendAccept(uint16_t addrTo, uint8_t customByte = 0); + void sendRequest(uint16_t addrTo); + void sendBack(uint8_t* data = nullptr, uint8_t len = 0); + void sendBackTo(uint16_t addrTo, uint8_t* data = nullptr, uint8_t len = 0); + void isr(); ~IR_Encoder(); + volatile bool ir_out_virtual; private: - IR_Decoder* decoder; - void meanderBlock(uint16_t count, uint16_t _period, bool isNoPause = true); + void IR_Encoder::_sendBack(bool isAdressed, uint16_t addrTo, uint8_t* data, uint8_t len); + + void IR_Encoder::setDecoder_isSending(); void sendByte(uint8_t byte, bool* prev, bool LOW_FIRST); void addSync(bool* prev, bool* next); void send_HIGH(bool = 1); void send_LOW(); void send_EMPTY(uint8_t count); - void rawSend(uint8_t* ptr, uint8_t len); - void _sendData(uint16_t addrTo, uint8_t* data, uint8_t len, uint8_t msgType); + + enum SignalPart : uint8_t { + noSignal = 0, + preamb = 1, + data = 2, + sync = 3 + }; + + IR_DecoderRaw* decPair; + IR_DecoderRaw** blindDecoders; + uint8_t decodersCount; + + uint8_t sendLen; + uint8_t sendBuffer[dataByteSizeMax] { 0 }; /// @brief Буффер данных для отправки + + volatile bool isSending; + volatile bool state; /// @brief Текущий уровень генерации + + volatile uint8_t dataByteCounter; + + volatile uint8_t toggleCounter; /// @brief Счётчик переключений + volatile uint8_t dataBitCounter; + + volatile uint8_t preambFrontCounter; + volatile uint8_t dataSequenceCounter; + volatile uint8_t syncSequenceCounter; + volatile bool syncLastBit; + + struct BitSequence { + uint8_t low; + uint8_t high; + }; + static inline uint8_t* bitHigh = new uint8_t[2] { + (bitPauseTakts * 2) * 2 - 1, + (bitActiveTakts) * 2 - 1 + }; + static inline uint8_t* bitLow = new uint8_t[2] { + (bitPauseTakts + bitActiveTakts) * 2 - 1, + (bitPauseTakts) * 2 - 1 + }; + uint8_t* currentBitSequence = bitLow; + volatile SignalPart signal; + }; -//////////////////////////////////////////////////////////////////////////////////////////////// -template -void IR_Encoder::sendData(uint16_t addrTo, T& data, bool needAccept = false) { // TODO: переделать логику LOW_FIRST - uint8_t len = sizeof(T); - uint8_t packSize = msgBytes + addrBytes + addrBytes + len + crcBytes; - - uint8_t msgType = - ((needAccept ? IR_MSG_DATA_ACCEPT : IR_MSG_DATA_NOACCEPT) << 5) | ((packSize - crcBytes) & IR_MASK_MSG_INFO); - - _sendData(addrTo, data, len, msgType); -} diff --git a/IR_config.h b/IR_config.h index abb8b5b..0a20143 100644 --- a/IR_config.h +++ b/IR_config.h @@ -1,5 +1,7 @@ #pragma once #include + +// #define IRDEBUG_INFO /*////////////////////////////////////////////////////////////////////////////////////// Для работы в паре положить декодер в энкодер @@ -11,7 +13,7 @@ IR_MSG_ACCEPT с адреса 0 воспринимается всеми устройствами -Адресное пространство: +Адресное пространство: Излучатели контрольных точек: 1000 ~ 1999 Излучатели без обратной связиЖ 2000 ~ 2999 @@ -19,14 +21,13 @@ IR_MSG_ACCEPT с адреса 0 воспринимается всеми устр - /```````````````````````````````````````````````` data pack `````````````````````````````````````````````\                                                                                                                                             {``````````} [````````````````````````] [````````````````````] [````````````````````````] [``````````````] -{ msg type } [ addr_self uint16_t ] [ addr_to uint16_t ] [ data bytes ] [ CRC Bytes ] +{ msg type } [ addr_from uint16_t ] [ addr_to uint16_t ] [====== data bytes ======] [ CRC Bytes ] {..........} [........................] [....................] [........................] [..............]                                                                                                            -{ aka size } [addr_self_H][addr_self_L] [addr_to_H][addr_to_L] [data_H][data_n..][data_L] [ crc1 ][ crc2 ] +{ aka size } [addr_from_H][addr_from_L] [addr_to_H][addr_to_L] [data_H][data_n..][data_L] [ crc1 ][ crc2 ] |     0           1            2              3         4          5                         |       |     \____________________________________________________________________________________________/       |     |                                                                                                    |     @@ -37,31 +38,59 @@ msg type:                                         // | 01234567 |                                         //  ----------                                         // | xxx..... | = тип сообщения -                                        // | ...xxxxx | = длина (максимум 32 бита) +                                        // | ...xxxxx | = длина (максимум 31 бита)                                         //  ---------- */ -#define IR_MSG_ 0U // | 000..... | = = ?? -#define IR_MSG_ACCEPT 1U // | 001..... | = */ /* = подтверждение -#define IR_MSG_REQUEST 2U // | 010..... | = */ /* = запрос -#define IR_MSG_ 3U // | 011..... | = */ /* = ?? -#define IR_MSG_ 4U // | 100..... | = */ /* = ?? -#define IR_MSG_ 5U // | 101..... | = */ /* = ?? -#define IR_MSG_DATA_NOACCEPT 6U // | 110..... | = */ /* = данные, не требующие подтверждения - //                                      // | \\\xxxxx | = = L длина данных -#define IR_MSG_DATA_ACCEPT 7U // | 111..... | = */ /* = данные требующие подтверждения -//                                      // | \\\xxxxx | = = L длина данных -/*   // ---------- +#define IR_MSG_BACK 0U // | 000...... | = Задний сигнал машинки +#define IR_MSG_ACCEPT 1U // | 001..... | = подтверждение +#define IR_MSG_REQUEST 2U // | 010..... | = запрос +#define IR_MSG_ 3U // | 011..... | = ?? +#define IR_MSG_BACK_TO 4U // | 100..... | = Задний сигнал машинки c адресацией +#define IR_MSG_ 5U // | 101..... | = ?? +#define IR_MSG_DATA_NOACCEPT 6U // | 110..... | = данные, не требующие подтверждения +#define IR_MSG_DATA_ACCEPT 7U // | 111..... | = данные требующие подтверждения +;/*   // ---------- -/```````````````````` подтверждение ```````````````````\      /``````````````````````````````````````` запрос ``````````````````````````````````\ +/``````````````````````````````` подтверждение `````````````````````````````\      /``````````````````````````````````````` запрос ``````````````````````````````````\                                                                                                                        -{``````````} [````````````````````````] [``````````````]      {``````````} [````````````````````````] [````````````````````````] [``````````````] -{ msg type } [ addr_self uint16_t ] [ CRC Bytes ]      { msg type } [ addr_self uint16_t ] [ addr_to uint16_t ] [ CRC Bytes ] -{..........} [........................] [..............]      {..........} [........................] [........................] [..............] -                                                                                                                                                  -{ 001..... } [addr_self_H][addr_self_L] [ crc1 ][ crc2 ]      { 010..... } [addr_self_H][addr_self_L] [addr_self_H][addr_self_L] [ crc1 ][ crc2 ] -|     0            1           2           3       4          |     0            1           2              3           4           5       6     -\__________________________________________/       |          \_____________________________________________________________________/       |     -|                                                  |          |                                                                             |     -\__________________________________________________/          \_____________________________________________________________________________/     +{``````````} [````````````````````````] [``````````````````] [``````````````]      {``````````} [````````````````````````] [````````````````````````] [``````````````] +{ msg type } [ addr_from uint16_t ] [=== customByte ===] [ CRC Bytes ]      { msg type } [ addr_from uint16_t ] [ addr_to uint16_t ] [ CRC Bytes ] +{..........} [........................] [..................] [..............]      {..........} [........................] [........................] [..............] +                                                                                                                                                             +{ 001..... } [addr_from_H][addr_from_L] [=== customByte ===] [ crc1 ][ crc2 ]      { 010..... } [addr_from_H][addr_from_L] [addr_from_H][addr_from_L] [ crc1 ][ crc2 ] +|     0            1           2                  3              4       5          |     0            1           2              3           4           5       6     +\________________________________________________________________/       |          \_____________________________________________________________________/       |     +|                                                                        |          |                                                                             |     +\________________________________________________________________________/          \_____________________________________________________________________________/     + +customByte - контрольная сумма принятых данных по poly1 + + + +/`````````````````````` Задний сигнал машинки без адресации ``````````````````````\        В (IR_MASK_MSG_INFO & 15U) содержится количество байт +                                                                                           сквозных команд, максимум 15 +{``````````} [````````````````````````] [````````````````````````] [``````````````]        Если полезных байт информации нет, отправляется один +{ msg type } [ addr_from uint16_t ] [====== data bytes ======] [ CRC Bytes ]        байт нулей +{..........} [........................] [........................] [..............]         +                                                                                            +{ 0000xxxx } [addr_from_H][addr_from_L] [data_H][data_n..][data_L] [ crc1 ][ crc2 ]         +|     0           1            2            3                         |       |             +\_____________________________________________________________________/       |             +|                                                                             |             +\_____________________________________________________________________________/             + + + +/```````````````````````````````````` Задний сигнал машинки с адресацией ````````````````````````````````````\  +                                                                                     +{``````````} [````````````````````````] [````````````````````````] [````````````````````````] [``````````````]  +{ msg type } [ addr_from uint16_t ] [ addr_to uint16_t ] [====== data bytes ======] [ CRC Bytes ]  +{..........} [........................] [........................] [........................] [..............]  +                                                                                                                +{ 0001xxxx } [addr_from_H][addr_from_L] [addr_from_H][addr_from_L] [data_H][data_n..][data_L] [ crc1 ][ crc2 ]  +|     0           1            2              3           4            5                         |       |      +\________________________________________________________________________________________________/       |      +|                                                                                                        |      +\________________________________________________________________________________________________________/      */ @@ -70,18 +99,17 @@ msg type: /* /////////////////////////////////////////////////////////////////////////////////////*/ +typedef uint16_t crc_t; -#define bytePerPack 3 // колличество байтов в пакете +#define bytePerPack 16 // колличество байтов в пакете #ifndef freeFrec #define freeFrec true #endif +#define subBufferSize 15 //Буфер для складирования фронтов, пока их не обработают (передатчик) -//#define carrierTune 4 #define preambPulse 3 -// 8 для gyverCore -// 4~5 для arduino nano - +#define disablePairDec false // Отключать парный приёмник, возможны баги, используйте setBlindDecoders() ///////////////////////////////////////////////////////////////////////////////////// @@ -89,35 +117,67 @@ msg type: #define addrBytes 2 #define msgBytes 1 #define crcBytes 2 -typedef uint16_t crc_t; #define poly1 0x31 #define poly2 0x8C #define syncBits 3U // количество битов синхронизации #define dataByteSizeMax (msgBytes + addrBytes + addrBytes + bytePerPack + crcBytes) -// размер msg в битах // размер короткой посылки в битах -#define dataBitSize ((8 + syncBits) * dataByteSizeMax) // размер посылки с данными в битах -#define bufferBitSizeMax (dataBitSize) // Размер буффера в битах -//const auto x = bufferBitSizeMax; -#define preambFronts (preambPulse*2) // количество фронтов преамбулы +#define preambFronts (preambPulse*2) // количество фронтов преамбулы (Приём) +#define preambToggle ((bitPauseTakts * 2 + bitActiveTakts) * 2 - 1) // колличество переключений преамбулы (Передача) -#define carrierFrec 38000U // частота несущей -#define carrierPeriod (1000000U/carrierFrec) // период несущей в us +#define carrierFrec 38000U // частота несущей (Приём/Передача) +#define carrierPeriod (1000000U/carrierFrec) // период несущей в us (Приём) // В процессе работы значения будут отклонятся в соответствии с предыдущим битом -#define bitActiveTakts 25U // длительность единицы в тактах -#define bitPauseTakts 6U // длительность нуля в тактах +#define bitActiveTakts 25U // длительность высокого уровня в тактах +#define bitPauseTakts 6U // длительность низкого уровня в тактах -#define bitTakts (bitActiveTakts+bitPauseTakts*2U) // Общая длительность бита в тактах +#define bitTakts (bitActiveTakts+(bitPauseTakts*2U)) // Общая длительность бита в тактах #define bitTime (bitTakts*carrierPeriod) // Общая длительность бита -const auto viewValue = bitTime; #define tolerance 300U class IR_FOX { -private: - bool isSending = false; +public: + struct PackOffsets { + uint8_t msgOffset; + uint8_t addrFromOffset; + uint8_t addrToOffset; + uint8_t dataOffset; + uint8_t crcOffset; + }; + + struct ErrorsStruct { + uint8_t lowSignal = 0; + uint8_t highSignal = 0; + uint8_t other = 0; + + void reset() { + lowSignal = 0; + highSignal = 0; + other = 0; + } + uint16_t all() { return lowSignal + highSignal + other; } + + }; + + struct PackInfo { + uint8_t* buffer = nullptr; + uint8_t packSize = 0; + uint16_t crc = 0; + ErrorsStruct err; + uint16_t rTime = 0; + }; + + static void checkaddressRuleApply(uint16_t address, uint16_t id, bool& flag) { + flag = false; + flag |= id == 0; + flag |= address == id; + flag |= address >= IR_Broadcast; + } + protected: + ErrorsStruct errors; uint8_t crc8(uint8_t* data, uint8_t start, uint8_t end, uint8_t poly) { //TODO: сделать возможность межбайтовой проверки uint8_t crc = 0xff; size_t i, j; @@ -132,41 +192,5 @@ protected: } return crc; } -public: - /// @brief Вывод массива байт в строковом формате - /// @param d Указатель на массив - /// @param s Размер массива - /// @param mode Формат вывода DEC, BIN - /// @return Готовая для вывода строка - String printBytes(uint8_t* d, uint8_t s, uint8_t mode = 10) { - String str = ""; - uint8_t control = bitPerByte; - uint8_t* _data = d; - switch (mode) { - case 2: - for (size_t i = 0; i < s * 8; i++) { - if (i == control) { - str += " "; - control += bitPerByte; - } - - str += _data[(i / 8)] >> (7 - (i % 8)) & 1; - } - break; - case 10: - for (size_t i = 0; i < s; i++) { - str += _data[i]; - str += " "; - } - - break; - - default: - break; - } - - str += " "; - return str; - } }; diff --git a/PacketTypes.h b/PacketTypes.h new file mode 100644 index 0000000..4bb8e58 --- /dev/null +++ b/PacketTypes.h @@ -0,0 +1,312 @@ +#pragma once +#include "IR_config.h" + +class IR_Decoder; +namespace PacketTypes { + class BasePack { + friend IR_Decoder; + protected: + bool isAvailable; + bool isRawAvailable; + bool isNeedAccept; + + uint8_t msgOffset; + uint8_t addressFromOffset; + uint8_t addressToOffset; + uint8_t DataOffset; + + IR_FOX::PackInfo* packInfo; + uint16_t id; + + virtual bool checkAddress(); + void set(IR_FOX::PackInfo* packInfo, uint16_t id) { + this->packInfo = packInfo; + this->id = id; + + if (isAvailable = checkAddress()) { + isAvailable = true; + isRawAvailable = true; + #ifdef IRDEBUG_INFO + Serial.print(" OK "); + #endif + } else { + isRawAvailable = true; + #ifdef IRDEBUG_INFO + Serial.print(" NOT-OK "); + #endif + } + } + + + static uint16_t _getAddrFrom(BasePack* obj) { + return (obj->packInfo->buffer[obj->addressFromOffset] << 8) | obj->packInfo->buffer[obj->addressFromOffset + 1]; + }; + static uint16_t _getAddrTo(BasePack* obj) { + return (obj->packInfo->buffer[obj->addressToOffset] << 8) | obj->packInfo->buffer[obj->addressToOffset + 1]; + }; + + static uint8_t _getDataSize(BasePack* obj) { + return obj->packInfo->packSize - crcBytes - obj->DataOffset; + }; + static uint8_t* _getDataPrt(BasePack* obj) { + return obj->packInfo->buffer + obj->DataOffset; + }; + static uint8_t _getDataRawSize(BasePack* obj) { + return obj->packInfo->packSize; + }; + + public: + bool available() { if (isAvailable) { isAvailable = false; isRawAvailable = false; return true; } else { return false; } }; + bool availableRaw() { if (isRawAvailable) { isRawAvailable = false; return true; } else { return false; } }; + uint8_t getMsgInfo() { return packInfo->buffer[0] & IR_MASK_MSG_INFO; }; + uint8_t getMsgType() { return (packInfo->buffer[0] >> 5) & IR_MASK_MSG_TYPE; }; + uint8_t getMsgRAW() { return packInfo->buffer[0]; }; + uint16_t getErrorCount() { return packInfo->err.all(); }; + uint8_t getErrorLowSignal() { return packInfo->err.lowSignal; }; + uint8_t getErrorHighSignal() { return packInfo->err.highSignal; }; + uint8_t getErrorOther() { return packInfo->err.other; }; + uint16_t getTunerTime() { return packInfo->rTime; }; + uint8_t* getDataRawPtr() { return packInfo->buffer; }; + }; + + + class Data : public BasePack { + public: + Data() { + msgOffset = 0; + addressFromOffset = 1; + addressToOffset = 3; + DataOffset = 5; + } + + uint16_t getAddrFrom() { return _getAddrFrom(this); }; + uint16_t getAddrTo() { return _getAddrTo(this); }; + + uint8_t getDataSize() { return _getDataSize(this); }; + uint8_t* getDataPrt() { return _getDataPrt(this); }; + uint8_t getDataRawSize() { return _getDataRawSize(this); }; + + private: + bool checkAddress() override { + bool ret; + IR_FOX::checkaddressRuleApply(getAddrTo(), this->id, ret); + return ret; + } + }; + + class DataBack : public BasePack { + public: + DataBack() { + msgOffset = 0; + addressFromOffset = 1; + addressToOffset = 3; + DataOffset = 3; + } + + uint16_t getAddrFrom() { return _getAddrFrom(this); }; + uint16_t getAddrTo() { return _getAddrTo(this); }; + + uint8_t getDataSize() { return _getDataSize(this); }; + uint8_t* getDataPrt() { return _getDataPrt(this); }; + uint8_t getDataRawSize() { return _getDataRawSize(this); }; + private: + bool checkAddress() override { + bool ret; + if (getMsgType() == IR_MSG_BACK_TO) { + DataOffset = 5; + IR_FOX::checkaddressRuleApply((packInfo->buffer[addressToOffset] << 8) | packInfo->buffer[addressToOffset + 1], this->id, ret); + } else { + DataOffset = 3; + ret = true; + } + return ret; + } + }; + + class Accept : public BasePack { + public: + Accept() { + msgOffset = 0; + addressFromOffset = 1; + DataOffset = 3; + } + + uint16_t getAddrFrom() { return _getAddrFrom(this); }; + uint8_t getCustomByte() { return packInfo->buffer[DataOffset]; }; + private: + bool checkAddress() override { return true; } + }; + + class Request : public BasePack { + public: + Request() { + msgOffset = 0; + addressFromOffset = 1; + addressToOffset = 3; + DataOffset = 3; + } + + uint16_t getAddrFrom() { return _getAddrFrom(this); }; + uint16_t getAddrTo() { return _getAddrTo(this); }; + + private: + bool checkAddress() override { + bool ret; + IR_FOX::checkaddressRuleApply(getAddrTo(), this->id, ret); + return ret; + } + }; + +} + +// class IOffsets { +// protected: +// uint8_t msgOffset; +// uint8_t addressFromOffset; +// uint8_t addressToOffset; +// uint8_t DataOffset; +// }; + +// class IPackInfo { +// public: +// IR_FOX::PackInfo* packInfo; +// }; + +// class IBaseEmptyPack : virtual public IOffsets, virtual public IPackInfo { +// }; + +// class IR_Decoder; +// class IEmptyPack : virtual protected IBaseEmptyPack, virtual public IR_FOX { +// friend IR_Decoder; +// bool isAvailable; +// bool isRawAvailable; +// bool isNeedAccept; + +// protected: +// uint16_t id; + +// virtual bool checkAddress() {}; + +// virtual void set(IR_FOX::PackInfo* packInfo, uint16_t id, bool isNeedAccept = false) { +// IBaseEmptyPack::IPackInfo::packInfo = packInfo; +// this->id = id; +// this->isNeedAccept = isNeedAccept; + +// if (isAvailable = checkAddress()) { +// isAvailable = true; +// isRawAvailable = true; +// Serial.print(" OK "); +// } else { +// isRawAvailable = true; +// Serial.print(" NOT-OK "); +// } +// } + +// public: +// virtual bool available() { if (isAvailable) { isAvailable = false; isRawAvailable = false; return true; } else { return false; } }; +// virtual bool availableRaw() { if (isRawAvailable) { isRawAvailable = false; return true; } else { return false; } }; +// virtual uint8_t getMsgInfo() { return packInfo->buffer[0] & IR_MASK_MSG_INFO; }; +// virtual uint8_t getMsgType() { return (packInfo->buffer[0] >> 5) & IR_MASK_MSG_TYPE; }; +// virtual uint8_t getMsgRAW() { return packInfo->buffer[0]; }; +// virtual uint16_t getErrorCount() { return packInfo->err.all(); }; +// virtual uint8_t getErrorLowSignal() { return packInfo->err.lowSignal; }; +// virtual uint8_t getErrorHighSignal() { return packInfo->err.highSignal; }; +// virtual uint8_t getErrorOther() { return packInfo->err.other; }; +// virtual uint16_t getTunerTime() { return packInfo->rTime; }; +// }; + +// class IHasAddresFrom : virtual protected IBaseEmptyPack { +// public: +// virtual uint16_t getAddrFrom() { return (packInfo->buffer[addressFromOffset] << 8) | packInfo->buffer[addressFromOffset + 1]; }; +// }; + +// class IHasAddresTo : virtual protected IBaseEmptyPack { +// public: +// virtual uint16_t getAddrTo() { return (packInfo->buffer[addressToOffset] << 8) | packInfo->buffer[addressToOffset + 1]; }; +// }; + +// class IHasAddresData : virtual protected IBaseEmptyPack { +// public: +// virtual uint8_t getDataSize() { return packInfo->packSize - crcBytes - DataOffset; }; +// virtual uint8_t* getDataPrt() { return packInfo->buffer + DataOffset; }; +// virtual uint8_t getDataRawSize() { return packInfo->packSize; }; +// virtual uint8_t* getDataRawPtr() { return packInfo->buffer; }; +// }; + +// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// class Data : +// virtual public IEmptyPack, +// virtual public IHasAddresFrom, +// virtual public IHasAddresTo, +// virtual public IHasAddresData { +// public: +// Data() { +// msgOffset = 0; +// addressFromOffset = 1; +// addressToOffset = 3; +// DataOffset = 5; +// } +// protected: +// bool checkAddress() override { +// bool ret; +// checkaddressRuleApply(getAddrTo(), this->id, ret); +// return ret; +// } +// }; + +// class DataBack : +// virtual public IEmptyPack, +// virtual public IHasAddresFrom, +// virtual public IHasAddresData { +// public: +// DataBack() { +// msgOffset = 0; +// addressFromOffset = 1; +// addressToOffset = 3; +// DataOffset = 3; +// } +// protected: +// bool checkAddress() override { +// bool ret; +// if (getMsgType() == IR_MSG_BACK_TO) { +// DataOffset = 5; +// checkaddressRuleApply((packInfo->buffer[addressToOffset] << 8) | packInfo->buffer[addressToOffset + 1], this->id, ret); +// } else { +// DataOffset = 3; +// ret = true; +// } +// return ret; +// } +// }; + +// class Request : +// virtual public IEmptyPack, +// virtual public IHasAddresFrom, +// virtual public IHasAddresTo { +// public: +// Request() { +// msgOffset = 0; +// addressFromOffset = 1; +// addressToOffset = 3; +// DataOffset = 3; +// } +// protected: +// bool checkAddress() override { +// bool ret; +// checkaddressRuleApply(getAddrTo(), this->id, ret); +// return ret; +// } +// }; + +// class Accept : +// virtual public IEmptyPack, +// virtual public IHasAddresFrom { +// public: +// Accept() { +// msgOffset = 0; +// addressFromOffset = 1; +// DataOffset = 1; +// } +// protected: +// };