diff --git a/.gitignore b/.gitignore index 005e2da..be23829 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ .vscode/* bin/* -log/* \ No newline at end of file +log/* diff --git a/.vscode/arduino.json b/.vscode/arduino.json new file mode 100644 index 0000000..3d8ebd7 --- /dev/null +++ b/.vscode/arduino.json @@ -0,0 +1,5 @@ +{ + "board": "STMicroelectronics:stm32:GenF4", + "port": "COM17", + "prebuild": "if exist bin rd /s /q bin" +} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..d4b3099 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,20 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + + { + "cwd": "${workspaceFolder}", + "executable": "${workspaceFolder}/bin/${workspaceFolderBasename}.ino.elf", + "name": "Debug with ST-Link", + "request": "launch", + "type": "cortex-debug", + "runToEntryPoint": "main", + "showDevDebugOutput": "raw", + "servertype": "stlink", + "armToolchainPath": "C://Program Files (x86)//Arm GNU Toolchain arm-none-eabi//13.2 Rel1//bin" + } + ] + } \ No newline at end of file diff --git a/IR-protocol.ino b/IR-protocol.ino index 41afb54..42e7815 100644 --- a/IR-protocol.ino +++ b/IR-protocol.ino @@ -19,18 +19,24 @@ #define SERIAL_SPEED 115200 //////////////// Var ///////////////// +// IR_Encoder encForward(PA5, 42 /* , &decBackward */); -IR_Decoder decForward(2, 555); -IR_Decoder decBackward(3, 777); +IR_Encoder enc0(PIN_KT8_OUT, 42 /* , &decBackward */); +// IR_Encoder enc1(PA1, 127 /* , &decBackward */); +// IR_Encoder enc2(PA2, 137 /* , &decBackward */); +// IR_Encoder enc3(PA3, 777 /* , &decBackward */); +// IR_Encoder enc10(PA4, 555 /* , &decBackward */); +// IR_Encoder enc11(PC14, 127 /* , &decBackward */); +// IR_Encoder enc12(PC13, 137 /* , &decBackward */); +// IR_Encoder enc13(PA12, 777 /* , &decBackward */); -IR_Encoder encForward(42/* , &decBackward */); -// IR_Encoder encBackward(321, encBackward_PIN); // IR_Encoder encTree(325, A2); //////////////////////// Функции прерываний //////////////////////// -void decForwardISR() { - decForward.isr(); +void EncoderISR() +{ + IR_Encoder::isr(); } void decBackwardISR() { @@ -63,82 +69,29 @@ uint8_t sig = 255; uint16_t targetAddr = IR_Broadcast; Timer t1(750, millis, []() { - // Serial.println(sig); +IR_Decoder dec2(dec2_PIN, 2); +void dec_2_ISR() { dec2.isr(); } - switch (sig) { - case 0: - encForward.sendData(targetAddr); - 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; +IR_Decoder dec3(dec3_PIN, 3); +void dec_3_ISR() { dec3.isr(); } - 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; +IR_Decoder dec4(dec4_PIN, 4); +void dec_4_ISR() { dec4.isr(); } +IR_Decoder dec5(dec5_PIN, 5); +void dec_5_ISR() { dec5.isr(); } +IR_Decoder dec6(dec6_PIN, 6); +void dec_6_ISR() { dec6.isr(); } - 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; +IR_Decoder dec7(dec7_PIN, 7); +void dec_7_ISR() { dec7.isr(); } - 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; +// IR_Decoder dec8(dec8_PIN, 8); +// void dec_8_ISR() { dec8.isr(); } +// IR_Decoder dec9(dec9_PIN, 9); +// void dec_9_ISR() { dec9.isr(); } default: break; @@ -154,19 +107,21 @@ void setup() { IR_Encoder::timerSetup(); portOut = &PORTB; - Serial.begin(SERIAL_SPEED); - Serial.println(F(INFO)); +// IR_Decoder dec11(dec11_PIN, 11); +// void dec_11_ISR() { dec11.isr(); } - pinMode(A0, INPUT_PULLUP); - pinMode(A1, INPUT_PULLUP); - pinMode(A2, INPUT_PULLUP); - pinMode(A3, INPUT_PULLUP); +// IR_Decoder dec12(dec12_PIN, 12); +// void dec_12_ISR() { dec12.isr(); } - pinMode(LoopOut, OUTPUT); - pinMode(ISR_Out, OUTPUT); +// IR_Decoder dec13(dec13_PIN, 13); +// void dec_13_ISR() { dec13.isr(); } - pinMode(2, INPUT_PULLUP); - pinMode(3, INPUT_PULLUP); +///////////////////////////////////////////////////////////////////// +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}; pinMode(8, OUTPUT); pinMode(9, OUTPUT); @@ -177,11 +132,118 @@ void setup() { pinMode(13, OUTPUT); pinMode(12, OUTPUT); +Timer t1(500, millis, []() + { + // Serial.println( digitalPinToBitMask(enc0.getPin()), BIN); + // enc0.sendData(IR_Broadcast, data4, sizeof(data4)); + // enc1.sendData(IR_Broadcast, data3, sizeof(data3)); + // enc2.sendData(IR_Broadcast, data2, sizeof(data2)); + // enc3.sendData(IR_Broadcast, data1, sizeof(data1)); + // enc10.sendData(IR_Broadcast, data4, sizeof(data4)); + // enc11.sendData(IR_Broadcast, data3, sizeof(data3)); + // enc12.sendData(IR_Broadcast, data2, sizeof(data2)); + // enc13.sendData(IR_Broadcast, data1, sizeof(data1)); + // Serial.println(sig); - // IR_DecoderRaw* blindFromForward [] { &decForward, &decBackward }; - // encForward.setBlindDecoders(blindFromForward, sizeof(blindFromForward) / sizeof(IR_DecoderRaw*)); + // switch (sig) + // { + // case 0: + // encForward.sendData(targetAddr); + // 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(50, millis, []() +// { digitalToggle(LED_BUILTIN); }); + +Timer signalDetectTimer; +///////////////////////////////////////////////////////////////////// +HardwareTimer IR_Timer(TIM3); + +void setup() +{ + IR_Timer.setOverflow(carrierFrec * 2, HERTZ_FORMAT); + IR_Timer.attachInterrupt(1, EncoderISR); + NVIC_SetPriority(IRQn_Type::TIM3_IRQn, 0); + IR_Timer.resume(); + + Serial.begin(SERIAL_SPEED); + Serial.println(F(INFO)); + + pinMode(LoopOut, OUTPUT); attachInterrupt(0, decForwardISR, CHANGE); // D2 attachInterrupt(1, decBackwardISR, CHANGE); // D3 @@ -208,20 +270,20 @@ void loop() { 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; + switch (in) + { + case 100: + targetAddr = IR_Broadcast; + break; + case 101: + targetAddr = 555; + break; + case 102: + targetAddr = 777; + break; + default: + sig = in; + break; } } @@ -234,7 +296,29 @@ void loop() { } +Timer statusSimpleDelay; +bool statusSimple(IR_Decoder &dec) +{ + bool ret; + if (ret = dec.gotData.available()) + { + Serial.print("DEC: "); + Serial.print(dec.getId()); + Serial.print(" err: "); + Serial.print(dec.gotData.getErrorCount()); + Serial.print("\n"); + statusSimpleDelay.delay(100, millis, []() + { Serial.print("\n\n\n\n"); }); + } + return ret; +} +void detectSignal() +{ + // digitalWrite(SignalDetectLed, HIGH); + // signalDetectTimer.delay(50, millis, []() + // { digitalWrite(SignalDetectLed, LOW); }); +} @@ -250,27 +334,40 @@ void status(IR_Decoder& dec) { String str; - if (/* dec.gotData.getDataPrt()[1] */1) { - str += ("Data on pin "); str += (dec.isrPin); str += "\n"; + if (/* dec.gotData.getDataPrt()[1] */ 1) + { + str += ("Data on pin "); + str += (dec.getPin()); + str += "\n"; uint8_t msg = dec.gotData.getMsgRAW(); str += (" MSG: "); - for (size_t i = 0; i < 8; i++) { - if (i == 3) str += " "; + 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 += (" 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) { + for (size_t i = 0; i < min(uint8_t(10), dec.gotData.getDataSize()); i++) + { + switch (i) + { // case 0: // str += (" ADDR: "); // break; @@ -278,49 +375,71 @@ void status(IR_Decoder& dec) { // str += (" CMD: "); // break; - default: - str += (" Data["); str += (i); str += ("]: "); - break; + default: + str += (" Data["); + str += (i); + str += ("]: "); + break; } - str += (dec.gotData.getDataPrt()[i]); str += "\n"; + 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*******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"; + } + else + { + str += ("SELF"); + str += "\n"; str += "\n"; } // obj->resetAvailable(); Serial.write(str.c_str()); } - if (dec.gotBackData.available()) { + if (dec.gotBackData.available()) + { + detectSignal(); String str; - if (/* dec.gotData.getDataPrt()[1] */1) { - str += ("BackData on pin "); str += (dec.isrPin); str += "\n"; + if (/* dec.gotData.getDataPrt()[1] */ 1) + { + str += ("BackData on pin "); + str += (dec.getPin()); + str += "\n"; uint8_t msg = dec.gotBackData.getMsgRAW(); str += (" MSG: "); - for (size_t i = 0; i < 8; i++) { - if (i == 3) str += " "; + 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 += (" 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) { + for (size_t i = 0; i < min(uint8_t(10), dec.gotBackData.getDataSize()); i++) + { + switch (i) + { // case 0: // str += (" ADDR: "); // break; @@ -328,98 +447,136 @@ void status(IR_Decoder& dec) { // str += (" CMD: "); // break; - default: - str += (" Data["); str += (i); str += ("]: "); - break; + default: + str += (" Data["); + str += (i); + str += ("]: "); + break; } - str += (dec.gotBackData.getDataPrt()[i]); str += "\n"; + 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*******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"; + } + else + { + str += ("SELF"); + str += "\n"; str += "\n"; } // obj->resetAvailable(); Serial.write(str.c_str()); } - if (dec.gotAccept.available()) { + if (dec.gotAccept.available()) + { + detectSignal(); String str; - if (/* dec.gotData.getDataPrt()[1] */1) { - str += ("Accept on pin "); str += (dec.isrPin); str += "\n"; + if (/* dec.gotData.getDataPrt()[1] */ 1) + { + str += ("Accept on pin "); + str += (dec.getPin()); + str += "\n"; uint8_t msg = dec.gotAccept.getMsgRAW(); str += (" MSG: "); - for (size_t i = 0; i < 8; i++) { - if (i == 3) str += " "; + 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 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 += (" 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\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"; + } + else + { + str += ("SELF"); + str += "\n"; str += "\n"; } // obj->resetAvailable(); Serial.write(str.c_str()); } - if (dec.gotRequest.available()) { + if (dec.gotRequest.available()) + { + detectSignal(); String str; - if (/* dec.gotData.getDataPrt()[1] */1) { - str += ("Request on pin "); str += (dec.isrPin); str += "\n"; + if (/* dec.gotData.getDataPrt()[1] */ 1) + { + str += ("Request on pin "); + str += (dec.getPin()); + str += "\n"; uint8_t msg = dec.gotRequest.getMsgRAW(); str += (" MSG: "); - for (size_t i = 0; i < 8; i++) { - if (i == 3) str += " "; + 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 += (" 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*******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"; + } + else + { + str += ("SELF"); + str += "\n"; str += "\n"; } // obj->resetAvailable(); Serial.write(str.c_str()); } - - + return false; } - - diff --git a/IR_Decoder.cpp b/IR_Decoder.cpp new file mode 100644 index 0000000..211dfda --- /dev/null +++ b/IR_Decoder.cpp @@ -0,0 +1,110 @@ +#include "IR_Decoder.h" + +std::list &IR_Decoder::get_dec_list() // определение функции +{ + static std::list dec_list; // статическая локальная переменная + return dec_list; // возвращается ссылка на переменную +} + +// IR_Decoder::IR_Decoder() {}; +IR_Decoder::IR_Decoder(const uint8_t pin, uint16_t addr, IR_Encoder *encPair, bool autoHandle) + : IR_DecoderRaw(pin, addr, encPair) +{ + get_dec_list().push_back(this); + if(autoHandle){ + enable(); + } +}; + +void IR_Decoder::enable() +{ + auto &dec_list = get_dec_list(); + if (std::find(dec_list.begin(), dec_list.end(), this) == dec_list.end()) + { + dec_list.push_back(this); + } + pinMode(pin, INPUT_PULLUP); + attachInterrupt(pin, (*this)(), CHANGE); +} + +void IR_Decoder::disable() +{ + detachInterrupt(pin); + pinMode(pin, INPUT); + auto &dec_list = get_dec_list(); + auto it = std::find(dec_list.begin(), dec_list.end(), this); + if (it != dec_list.end()) + { + dec_list.erase(it); + } +} + + +std::function IR_Decoder::operator()() +{ + return std::bind(&IR_Decoder::isr, this); +} + +IR_Decoder::~IR_Decoder() +{ + IR_Decoder::get_dec_list().remove(this); +} + +void IR_Decoder::tick() +{ + for (const auto &element : IR_Decoder::get_dec_list()) + { + element->_tick(); + } +} + +void IR_Decoder::_tick() +{ + IR_DecoderRaw::tick(); + + if (availableRaw()) + { +#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; + + 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; + } + gotRaw.set(&packInfo, id); + } + if (isWaitingAcceptSend && millis() - acceptSendTimer > acceptDelay) + { + encoder->sendAccept(addrAcceptSendTo, acceptCustomByte); + isWaitingAcceptSend = false; + } +} + +bool IR_Decoder::isReceive(uint8_t type) { + return (msgTypeReceive & 0b11111000) && ((msgTypeReceive & IR_MASK_MSG_TYPE) == type); +} diff --git a/IR_Decoder.h b/IR_Decoder.h index d7555ea..3344562 100644 --- a/IR_Decoder.h +++ b/IR_Decoder.h @@ -5,11 +5,16 @@ class IR_Decoder : public IR_DecoderRaw { +private: + // static std::list dec_list; + static std::list& get_dec_list(); + void _tick(); + uint32_t acceptSendTimer; bool isWaitingAcceptSend; uint16_t addrAcceptSendTo; - uint16_t acceptDelay = 75; + uint16_t acceptDelay = IR_ResponseDelay; uint8_t acceptCustomByte; public: @@ -19,59 +24,25 @@ public: PacketTypes::Request gotRequest; PacketTypes::BasePack gotRaw; - IR_Decoder(const uint8_t isrPin, uint16_t addr, IR_Encoder *encPair = nullptr) : IR_DecoderRaw(isrPin, addr, encPair) {} + // IR_Decoder(); + IR_Decoder(const uint8_t pin, uint16_t addr = 0, IR_Encoder *encPair = nullptr, bool autoHandle = true); - void tick() - { - IR_DecoderRaw::tick(); - if (availableRaw()) - { -#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; + std::function operator()(); - 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; - } - gotRaw.set(&packInfo, id); - } - if (isWaitingAcceptSend && millis() - acceptSendTimer > 75) - { - encoder->sendAccept(addrAcceptSendTo, acceptCustomByte); - isWaitingAcceptSend = false; - } - } + void enable(); + void disable(); + + bool isReceive(uint8_t type); - void setAcceptDelay(uint16_t acceptDelay) + ~IR_Decoder(); + + static void tick(); + + inline void setAcceptDelay(uint16_t acceptDelay) { this->acceptDelay = acceptDelay; } - uint16_t getAcceptDelay() + inline uint16_t getAcceptDelay() { return this->acceptDelay; } diff --git a/IR_DecoderRaw.cpp b/IR_DecoderRaw.cpp index 8b2ffce..5cfd3ce 100644 --- a/IR_DecoderRaw.cpp +++ b/IR_DecoderRaw.cpp @@ -1,58 +1,84 @@ #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), encoder(encPair) +IR_DecoderRaw::IR_DecoderRaw(const uint8_t pin, uint16_t addr, IR_Encoder *encPair) : encoder(encPair) { + setPin(pin); id = addr; prevRise = prevFall = prevPrevFall = prevPrevRise = 0; if (encPair != nullptr) { encPair->decPair = this; } + +#ifdef IRDEBUG + pinMode(wrHigh, OUTPUT); + pinMode(wrLow, OUTPUT); + pinMode(writeOp, OUTPUT); + pinMode(errOut, OUTPUT); + pinMode(up, OUTPUT); + pinMode(down, OUTPUT); +#endif } +bool IR_DecoderRaw::isSubOverflow() +{ + noInterrupts(); + volatile bool ret = isSubBufferOverflow; + interrupts(); + return ret; +} + +bool IR_DecoderRaw::availableRaw() + { + if (isAvailable) + { + isAvailable = false; + return true; + } + else + { + return false; + } + }; + //////////////////////////////////// isr /////////////////////////////////////////// +volatile uint32_t time_; void IR_DecoderRaw::isr() { - if (isPairSending) + // Serial.print("ISR\n"); + if(isPairSending){ return; - - subBuffer[currentSubBufferIndex].next = nullptr; - subBuffer[currentSubBufferIndex].dir = (PIND >> isrPin) & 1; - subBuffer[currentSubBufferIndex].time = micros(); - - if (firstUnHandledFront == nullptr) - { - firstUnHandledFront = &subBuffer[currentSubBufferIndex]; // Если нет необработанных данных - добавляем их - isSubBufferOverflow = false; } - else - { - if (firstUnHandledFront == &subBuffer[currentSubBufferIndex]) - { // Если контроллер не успел обработать новый сигнал, принудительно пропускаем его - firstUnHandledFront = firstUnHandledFront->next; - isSubBufferOverflow = true; -#ifdef IRDEBUG_INFO - // Serial.println(); - Serial.println(" ISR BUFFER OVERFLOW "); -// Serial.println(); + noInterrupts(); + // time_ = HAL_GetTick() * 1000 + ((SysTick->LOAD + 1 - SysTick->VAL) * 1000) / SysTick->LOAD + 1; + time_ = micros(); + interrupts(); + if (time_ < oldTime) + { + +#ifdef IRDEBUG + Serial.print("\n"); + Serial.print("count: "); + Serial.println(wrongCounter++); + Serial.print("time: "); + Serial.println(time_); + Serial.print("oldTime: "); + Serial.println(oldTime); + Serial.print("sub: "); + Serial.println(max((uint32_t)time_, oldTime) - min((uint32_t)time_, oldTime)); #endif - } + time_ += 1000; } + oldTime = time_; - if (lastFront == nullptr) - { - lastFront = &subBuffer[currentSubBufferIndex]; - } - else - { - lastFront->next = &subBuffer[currentSubBufferIndex]; - lastFront = &subBuffer[currentSubBufferIndex]; - } + FrontStorage edge; + edge.dir = port->IDR & mask; + edge.time = time_; - currentSubBufferIndex == (subBufferSize - 1) ? currentSubBufferIndex = 0 : currentSubBufferIndex++; // Закольцовка буффера + subBuffer.push(edge); } //////////////////////////////////////////////////////////////////////////////////// @@ -78,70 +104,166 @@ void IR_DecoderRaw::firstRX() isPreamb = true; riseSyncTime = bitTime /* 1100 */; - +#ifdef IRDEBUG + wrCounter = 0; +#endif memset(dataBuffer, 0x00, dataByteSizeMax); } void IR_DecoderRaw::listenStart() { - if (isRecive && ((micros() - prevRise) > IR_timeout * 2)) + if (isReciveRaw && ((micros() - prevRise) > IR_timeout * 2)) { // Serial.print("\nlis>"); - isRecive = false; + isReciveRaw = false; firstRX(); } } + +// ---- быстрая проверка конца пакета --------------------------------- +inline void IR_DecoderRaw::checkTimeout() +{ + if (!isRecive) return; // уже не принимаем – нечего проверять + + if (micros() - lastEdgeTime > IR_timeout * 2U) + { + isRecive = false; // приём завершён + msgTypeReceive = 0; + // firstRX(); // подготовка к новому пакету + lastEdgeTime = micros(); // защита от повторного срабатывания + } +} +// ==================================================================== + void IR_DecoderRaw::tick() { + // FrontStorage *currentFrontPtr; + // noInterrupts(); + // currentFrontPtr = subBuffer.pop(); + // interrupts(); + FrontStorage currentFront; - uint8_t oldSREG = SREG; - cli(); + noInterrupts(); listenStart(); - if (firstUnHandledFront == nullptr) + FrontStorage *currentFrontPtr; + currentFrontPtr = subBuffer.pop(); + if (currentFrontPtr == nullptr) { isSubBufferOverflow = false; - SREG = oldSREG; + checkTimeout(); // <--- новое место проверки + interrupts(); return; - } // Если данных нет - ничего не делаем - currentFront = *((FrontStorage *)firstUnHandledFront); // найти следующий необработанный фронт/спад - SREG = oldSREG; - if (currentFront.next == nullptr) - { - isRecive = false; - return; - } + } // Если данных нет - ничего не делаем + currentFront = *currentFrontPtr; + interrupts(); + + // ---------- буфер пуст: фронтов нет, проверяем тайм-аут ---------- + // if (currentFrontPtr == nullptr) + // { + // isSubBufferOverflow = false; + // return; + // } + + // // ---------- есть фронт: продолжаем обработку ---------- + // FrontStorage currentFront = *currentFrontPtr; + lastEdgeTime = currentFront.time; // запоминаем любой фронт + //////////////////////////////////////////////////////////////////////////////////////////////////////////// - if (currentFront.time > prevRise && currentFront.time - prevRise > IR_timeout * 2 && !isRecive) - { // первый - preambFrontCounter = preambFronts - 1U; + if (currentFront.dir) + { // Если __/``` ↑ + if (currentFront.time - prevRise > riseTimeMax / 4 || highCount || lowCount) + { // комплексный фикс рваной единицы + risePeriod = currentFront.time - prevRise; + highTime = currentFront.time - prevFall; + lowTime = prevFall - prevRise; + prevRise = currentFront.time; - if (!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); + if ( + risePeriod > UINT32_MAX - IR_timeout * 10 || + highTime > UINT32_MAX - IR_timeout * 10 || + lowTime > UINT32_MAX - IR_timeout * 10 || + prevRise > UINT32_MAX - IR_timeout * 10) + { +#ifdef IRDEBUG + errPulse(down, 50); + + // Serial.print("\n"); + + // Serial.print("risePeriod: "); + // Serial.println(risePeriod); + + // Serial.print("highTime: "); + // Serial.println(highTime); + + // Serial.print("lowTime: "); + // Serial.println(lowTime); + + // Serial.print("prevRise: "); + // Serial.println(prevRise); #endif - isRecive = true; - isWrongPack = false; + } + } + else + { + errors.other++; } } + else + { // Если ```\__ ↓ + + if (currentFront.time - prevFall > riseTimeMin / 4) + { + prevFall = currentFront.time; + } + else + { + errors.other++; + } + } +#ifdef IRDEBUG + // goto END; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +#endif + //---------------------------------------------------------------------------------- +#ifdef IRDEBUG + digitalWrite(errOut, currentFront.dir); +#endif + + if (currentFront.time > prevRise && currentFront.time - prevRise > IR_timeout * 2 && !isReciveRaw) + { // первый +#ifdef IRDEBUG + errPulse(up, 50); + errPulse(down, 50); + errPulse(up, 150); + errPulse(down, 150); +#endif + preambFrontCounter = preambFronts - 1U; + isPreamb = true; + + isRecive = true; + isReciveRaw = true; + isWrongPack = false; + } + + //------------------------------------------------------------------------------------------------------- if (preambFrontCounter) { // в преамбуле - uint32_t risePeriod; - risePeriod = currentFront.time - prevRise; +#ifdef IRDEBUG + Serial.print("risePeriod: "); + Serial.println(risePeriod); +#endif if (currentFront.dir && risePeriod < IR_timeout) { // __/``` ↑ и мы в внутри пакета - if (risePeriod < riseTimeMin << 1) + if (risePeriod < riseTimeMin / 2) { // fix рваной единицы preambFrontCounter += 2; errors.other++; +#ifdef IRDEBUG + errPulse(down, 350); +#endif } else { @@ -161,196 +283,183 @@ void IR_DecoderRaw::tick() { if (isPreamb) { // первый фронт после - // gotTune.set(riseSyncTime); + // gotTune.set(riseSyncTime); + isPreamb = false; +#ifdef IRDEBUG + errPulse(up, 50); + errPulse(down, 50); +#endif + prevRise += risePeriod / 2; + // prevRise = currentFront.time + riseTime; + goto END; } - isPreamb = false; } + + if (isPreamb) + { + goto END; + } + if (risePeriod > IR_timeout || isBufferOverflow || risePeriod < riseTimeMin || isWrongPack) + // ~Мы в пределах таймаута и буффер не переполнен и fix дроблёных единиц + { + goto END; + } + // определить направление фронта 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; + highCount = 0; + lowCount = 0; + 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); // предполагаемое колличество всего битов + Serial.print("\n"); - if (highCount == 0 && highTime > riseTime / 3) - { // fix короткой единицы (?)после пропуска нулей(?) - highCount++; - errors.other++; -#ifdef IRDEBUG - errPulse(errOut, 2); -#endif - } + Serial.print("wrCounter: "); + Serial.println(wrCounter++); - 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; - } + Serial.print("risePeriod: "); + Serial.println(risePeriod); - // errorCounter += allCount; - // errors.other+=allCount; - if (lowCount < highCount) - { - errors.highSignal += highCount; - } - else - { - errors.lowSignal += lowCount; - } + Serial.print("highTime: "); + Serial.println(highTime); -#ifdef IRDEBUG - errPulse(errOut, 1); + Serial.print("lowTime: "); + Serial.println(lowTime); #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 - } - } + if (aroundRise(risePeriod)) + { // тактирование есть, сигнал хороший - без ошибок(?) - for (int8_t i = 0; i < highCount && 8 - i; i++) - { // отправка HIGH битов, если есть - if (i == highCount - 1 && invertErr) - { - invertErr = false; - writeToBuffer(!HIGH); + if (highTime > lowTime) + { // 1 #ifdef IRDEBUG - digitalWrite(wrLow, 1); + errPulse(wrHigh, 1); #endif - } - else - { - writeToBuffer(HIGH); + writeToBuffer(HIGH); + } + else + { // 0 #ifdef IRDEBUG - digitalWrite(wrHigh, 1); -#endif - } - } - } -#ifdef IRDEBUG - digitalWrite(wrHigh, 0); - digitalWrite(wrLow, 0); + errPulse(wrLow, 1); #endif + writeToBuffer(LOW); } } - if (risePeriod > riseTimeMax / 2 || highCount || lowCount) - { // комплексный фикс рваной единицы - prevPrevRise = prevRise; - prevRise = currentFront.time; - } else - { - errors.other++; + { // пропущены такты! сигнал средний // ошибка пропуска + 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, 5); + errPulse(up, 50); #endif + } + + if (lowCount + highCount > allCount) + { // fix ошибочных сдвигов + if (lowCount > highCount) + { // Лишние нули + lowCount = allCount - highCount; + errors.lowSignal += lowCount; +#ifdef IRDEBUG + // errPulse(errOut, 3); + errPulse(down, 40); + errPulse(up, 10); + errPulse(down, 40); +#endif + } + else if (lowCount < highCount) + { // Лишние единицы + highCount = allCount - lowCount; + errors.highSignal += highCount; +#ifdef IRDEBUG + errPulse(down, 10); + errPulse(up, 40); + errPulse(down, 10); +// errPulse(errOut, 4); +#endif + // неизвестный случай Инверсит след бит или соседние + // Очень редко + // TODO: Отловить проверить + } + else if (lowCount == highCount) + { +#ifdef IRDEBUG + errPulse(down, 40); + errPulse(up, 40); + errPulse(down, 40); +#endif + invertErr = true; + // Serial.print("..."); + errors.other += allCount; + } + // errorCounter += allCount; + } + + // errorCounter += allCount; + // errors.other+=allCount; + if (lowCount < highCount) + { + errors.highSignal += highCount; + } + else + { + errors.lowSignal += lowCount; + } + + // errPulse(errOut, 1); + + for (int8_t i = 0; i < lowCount && 8 - i; i++) + { // отправка LOW битов, если есть + if (i == lowCount - 1 && invertErr) + { + invertErr = false; + writeToBuffer(HIGH); +#ifdef IRDEBUG + errPulse(wrHigh, 1); +#endif + } + else + { + writeToBuffer(LOW); +#ifdef IRDEBUG + errPulse(wrLow, 1); +#endif + } + } + + for (int8_t i = 0; i < highCount && 8 - i; i++) + { // отправка HIGH битов, если есть + if (i == highCount - 1 && invertErr) + { + invertErr = false; + writeToBuffer(LOW); +#ifdef IRDEBUG + errPulse(wrLow, 1); +#endif + } + else + { + writeToBuffer(HIGH); +#ifdef IRDEBUG + errPulse(wrHigh, 1); +#endif + } + } } } else { // Если ```\__ ↓ - - 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 - //////////////////////////////////////////////////////////////////////////////////////////////////////////// - oldSREG = SREG; - cli(); - if (firstUnHandledFront != nullptr) - { - firstUnHandledFront = firstUnHandledFront->next; // переместить флаг на следующий элемент для обработки (next or nullptr) - } - SREG = oldSREG; +//////////////////////////////////////////////////////////////////////////////////////////////////////////// +END:; } void IR_DecoderRaw::writeToBuffer(bool bit) @@ -366,6 +475,8 @@ void IR_DecoderRaw::writeToBuffer(bool bit) if (isBufferOverflow || isPreamb || isWrongPack) { isRecive = false; + isReciveRaw = false; + msgTypeReceive = 0; return; } @@ -479,7 +590,7 @@ void IR_DecoderRaw::writeToBuffer(bool bit) if (packSize && (i_dataBuffer == packSize * bitPerByte)) { // Конец #ifdef IRDEBUG_INFO - Serial.print(" END DATA "); + Serial.print(" END DATA " + crcCheck(packSize - crcBytes, crcValue) ? "OK " : "ERR "); #endif packInfo.buffer = dataBuffer; @@ -489,7 +600,43 @@ void IR_DecoderRaw::writeToBuffer(bool bit) packInfo.rTime = riseSyncTime; isRecive = false; + isReciveRaw = false; + msgTypeReceive = 0; isAvailable = crcCheck(packSize - crcBytes, crcValue); + +#ifdef BRUTEFORCE_CHECK + if (!isAvailable) // Исправление первого бита // Очень большая затычка... + for (size_t i = 0; i < min(uint16_t(packSize - crcBytes * 2U), uint16_t(dataByteSizeMax)); ++i) + { + for (int j = 0; j < 8; ++j) + { + // инвертируем бит + dataBuffer[i] ^= 1 << j; + + isAvailable = crcCheck(min(uint16_t(packSize - crcBytes), uint16_t(dataByteSizeMax - 1U)), crcValue); + // обратно инвертируем бит в исходное состояние + + if (isAvailable) + { +#ifdef IRDEBUG_INFO + Serial.println("!!!INV!!!"); +#endif + goto OUT_BRUTEFORCE; + } + else + { + dataBuffer[i] ^= 1 << j; + } + } + } + OUT_BRUTEFORCE:; +#endif + } + + if (packSize && (i_dataBuffer == 8)) { + msgTypeReceive = (dataBuffer[0]>>5) | 0b11111000; + // SerialUSB.println(msgTypeReceive & IR_MASK_MSG_TYPE); + } } diff --git a/IR_DecoderRaw.h b/IR_DecoderRaw.h index 82912e6..7361982 100644 --- a/IR_DecoderRaw.h +++ b/IR_DecoderRaw.h @@ -1,15 +1,18 @@ #pragma once #include "IR_config.h" +#include "RingBuffer.h" // #define IRDEBUG #ifdef IRDEBUG -#define wrHigh A3 // Запись HIGH инициирована // green -#define wrLow A3 // Запись LOW инициирована // blue -#define writeOp 13 // Операция записи, 1 пульс для 0 и 2 для 1 // orange +#define wrHigh PA1 // Запись HIGH инициирована // green +#define wrLow PA0 // Запись LOW инициирована // blue +#define writeOp PA5 // Операция записи, 1 пульс для 0 и 2 для 1 // orange // Исправленные ошибки // purle // 1 пульс: fix -#define errOut A3 +#define errOut PA4 +#define up PA3 +#define down PA2 #endif ///////////////////////////////////////////////////////////////////////////////////////////////// @@ -20,6 +23,7 @@ #define riseTimeMin (riseTime - riseTolerance) #define aroundRise(t) (riseTimeMin < t && t < riseTimeMax) #define IR_timeout (riseTimeMax * (8 + syncBits + 1)) // us // таймаут в 8 data + 3 sync + 1 +constexpr uint16_t IR_ResponseDelay = ((uint16_t)(((bitTime+riseTolerance) * (8 + syncBits + 1))*2.7735))/1000; class IR_Encoder; class IR_DecoderRaw : virtual public IR_FOX @@ -27,44 +31,25 @@ class IR_DecoderRaw : virtual public IR_FOX friend IR_Encoder; protected: - PackInfo packInfo; - IR_Encoder *encoder; // Указатель на парный передатчик - bool availableRaw() - { - if (isAvailable) - { - isAvailable = false; - return true; - } - else - { - return false; - } - }; +PackInfo packInfo; +uint8_t msgTypeReceive = 0; +IR_Encoder *encoder; // Указатель на парный передатчик +bool availableRaw(); public: - const uint8_t isrPin; // Пин прерывания - ////////////////////////////////////////////////////////////////////////// /// @brief Конструктор - /// @param isrPin Номер вывода прерывания/данных от приёмника (2 или 3 для atmega 328p) + /// @param pin Номер вывода прерывания/данных от приёмника (2 или 3 для atmega 328p) /// @param addr Адрес приёмника /// @param encPair Указатель на передатчик, работающий в паре - IR_DecoderRaw(const uint8_t isrPin, uint16_t addr, IR_Encoder *encPair = nullptr); + IR_DecoderRaw(const uint8_t pin, uint16_t addr, IR_Encoder *encPair = nullptr); void isr(); // Функция прерывания void tick(); // Обработка приёмника, необходима для работы - bool isOverflow() { return isBufferOverflow; }; // Буффер переполнился - bool isSubOverflow() - { - uint8_t oldSREG = SREG; - cli(); - volatile bool ret = isSubBufferOverflow; - SREG = oldSREG; - return ret; - }; - bool isReciving() { return isBufferOverflow; }; // Возвращает true, если происходит приём пакета + inline bool isOverflow() { return isBufferOverflow; }; // Буффер переполнился + bool isSubOverflow(); + volatile inline bool isReciving() { return isRecive; }; // Возвращает true, если происходит приём пакета ////////////////////////////////////////////////////////////////////////// private: @@ -81,27 +66,46 @@ private: uint16_t riseSyncTime = bitTime; // Подстраиваемое время бита в мкс + volatile uint32_t lastEdgeTime = 0; // время последнего фронта + //////////////////////////////////////////////////////////////////////// - volatile uint8_t currentSubBufferIndex; // Счетчик текущей позиции во вспомогательном буфере фронтов/спадов + volatile uint32_t currentSubBufferIndex; // Счетчик текущей позиции во вспомогательном буфере фронтов/спадов struct FrontStorage - { // Структура для хранения времени и направления фронта/спада - volatile uint32_t time = 0; // Время - volatile bool dir = false; // Направление (true = ↑; false = ↓) - volatile FrontStorage *next = nullptr; // Указатель на следующий связанный фронт/спад, или nullptr если конец + { // Структура для хранения времени и направления фронта/спада + 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]; // вспомогательный буфер для хранения необработанных фронтов/спадов + // volatile FrontStorage subBuffer[subBufferSize]; // вспомогательный буфер для хранения необработанных фронтов/спадов + + RingBuffer subBuffer; + //////////////////////////////////////////////////////////////////////// - uint8_t dataBuffer[dataByteSizeMax]{0}; // Буффер данных - uint32_t prevRise, prevPrevRise, prevFall, prevPrevFall; // Время предыдущих фронтов/спадов - uint16_t errorCounter = 0; // Счётчик ошибок - int8_t preambFrontCounter = 0; // Счётчик __/``` ↑ преамбулы - int16_t bufBitPos = 0; // Позиция для записи бита в буффер + uint8_t dataBuffer[dataByteSizeMax]{0}; // Буффер данных + volatile uint32_t prevRise, prevPrevRise, prevFall, prevPrevFall; // Время предыдущих фронтов/спадов + + volatile uint32_t risePeriod; + volatile uint32_t highTime; + volatile uint32_t lowTime; + + uint32_t oldTime; + uint16_t wrongCounter; + + int8_t highCount; + int8_t lowCount; + int8_t allCount; + + uint16_t errorCounter = 0; // Счётчик ошибок + int8_t preambFrontCounter = 0; // Счётчик __/``` ↑ преамбулы + int16_t bufBitPos = 0; // Позиция для записи бита в буффер private: - void listenStart(); // @brief Слушатель для работы isReciving() +bool isReciveRaw; + void listenStart(); + void checkTimeout(); // /// @brief Проверка CRC. Проверяет len байт со значением crc, пришедшим в пакете /// @param len Длина в байтах проверяемых данных @@ -130,7 +134,8 @@ private: uint16_t ceil_div(uint16_t val, uint16_t divider); #ifdef IRDEBUG + uint32_t wrCounter; 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 f817ba1..f47937d 100644 --- a/IR_Encoder.cpp +++ b/IR_Encoder.cpp @@ -1,12 +1,18 @@ #include "IR_Encoder.h" #include "IR_DecoderRaw.h" +#include #define LoopOut 12 #define ISR_Out 10 #define TestOut 13 -IR_Encoder::IR_Encoder(uint16_t addr, IR_DecoderRaw *decPair = nullptr) +IR_Encoder *IR_Encoder::head = nullptr; +IR_Encoder *IR_Encoder::last = nullptr; +volatile bool IR_Encoder::carrierStopPending = false; + +IR_Encoder::IR_Encoder(uint8_t pin, uint16_t addr, IR_DecoderRaw *decPair, bool autoHandle) { + setPin(pin); id = addr; this->decPair = decPair; signal = noSignal; @@ -14,8 +20,7 @@ IR_Encoder::IR_Encoder(uint16_t addr, IR_DecoderRaw *decPair = nullptr) #if disablePairDec if (decPair != nullptr) { - blindDecoders = new IR_DecoderRaw *[1] - { decPair }; + blindDecoders = new IR_DecoderRaw *[1]{decPair}; decodersCount = 1; } #endif @@ -23,7 +28,278 @@ IR_Encoder::IR_Encoder(uint16_t addr, IR_DecoderRaw *decPair = nullptr) { decPair->encoder = this; } + + if (autoHandle) + { + if (IR_Encoder::head == nullptr) + { + IR_Encoder::head = this; + } + if (last != nullptr) + { + last->next = this; + } + last = this; + + pinMode(pin, OUTPUT); + } }; + +HardwareTimer* IR_Encoder::IR_Timer = nullptr; +IR_Encoder::ExternalTxStartFn IR_Encoder::externalTxStartFn = nullptr; +IR_Encoder::ExternalTxBusyFn IR_Encoder::externalTxBusyFn = nullptr; +void *IR_Encoder::externalTxCtx = nullptr; + +inline HardwareTimer* IR_Encoder::get_IR_Timer(){return IR_Encoder::IR_Timer;} + +void IR_Encoder::carrierResume() { + if (IR_Timer != nullptr) + IR_Timer->resume(); +} + +void IR_Encoder::carrierPauseIfIdle() { + for (IR_Encoder *p = head; p != nullptr; p = p->next) + if (p->isSending) + return; + if (IR_Timer != nullptr) + IR_Timer->pause(); +} + +void IR_Encoder::tick() { + if (!carrierStopPending) + return; + carrierStopPending = false; + carrierPauseIfIdle(); +} + +void IR_Encoder::begin(HardwareTimer* timer, uint8_t channel, IRQn_Type IRQn, uint8_t priority, void(*isrCallback)()){ + IR_Timer = timer; + if(IR_Timer == nullptr) return; + IR_Timer->pause(); + IR_Timer->setOverflow(carrierFrec * 2, HERTZ_FORMAT); + IR_Timer->attachInterrupt(channel, (isrCallback == nullptr ? IR_Encoder::isr : isrCallback)); + NVIC_SetPriority(IRQn, priority); + IR_Timer->pause(); +} + +void IR_Encoder::beginClockOnly(HardwareTimer *timer) +{ + IR_Timer = timer; + if (IR_Timer == nullptr) + return; + IR_Timer->pause(); + IR_Timer->setOverflow(carrierFrec * 2, HERTZ_FORMAT); + IR_Timer->pause(); +} + +void IR_Encoder::setExternalTxBackend(ExternalTxStartFn startFn, ExternalTxBusyFn busyFn, void *ctx) +{ + externalTxStartFn = startFn; + externalTxBusyFn = busyFn; + externalTxCtx = ctx; +} + +void IR_Encoder::externalFinishSend() +{ + if (!isSending) + return; + + // Force output low. + if (port != nullptr) { + port->BSRR = ((uint32_t)mask) << 16; + } + + isSending = false; + setDecoder_isSending(); +} + +size_t IR_Encoder::buildGateRuns(const uint8_t *packet, uint8_t len, IR_TxGateRun *outRuns, size_t maxRuns) +{ + if (packet == nullptr || outRuns == nullptr || maxRuns == 0) + { + return 0; + } + if (len == 0 || len > dataByteSizeMax) + { + return 0; + } + + // Copy into fixed-size buffer to match original encoder behavior (safe reads past sendLen). + uint8_t sendBufferLocal[dataByteSizeMax] = {0}; + memcpy(sendBufferLocal, packet, len); + + uint8_t sendLenLocal = len; + uint8_t toggleCounterLocal = preambToggle; + uint8_t dataBitCounterLocal = bitPerByte - 1; + uint8_t dataByteCounterLocal = 0; + uint8_t preambFrontCounterLocal = preambPulse * 2 - 1; + uint8_t dataSequenceCounterLocal = bitPerByte * 2; + uint8_t syncSequenceCounterLocal = syncBits * 2; + bool syncLastBitLocal = false; + SignalPart signalLocal = preamb; + bool stateLocal = HIGH; + uint8_t *currentBitSequenceLocal = bitHigh; + + size_t runCount = 0; + + while (true) + { + const bool gate = stateLocal; + const uint16_t runLenTicks = (uint16_t)toggleCounterLocal + 1U; + + if (runCount > 0 && outRuns[runCount - 1].gate == gate) + { + outRuns[runCount - 1].lenTicks = (uint16_t)(outRuns[runCount - 1].lenTicks + runLenTicks); + } + else + { + if (runCount >= maxRuns) + { + return 0; + } + outRuns[runCount].gate = gate; + outRuns[runCount].lenTicks = runLenTicks; + runCount++; + } + + // Advance state to the next run boundary (equivalent to ISR iteration when toggleCounter == 0). + while (true) + { + switch (signalLocal) + { + case noSignal: + return runCount; + + case preamb: + if (preambFrontCounterLocal) + { + preambFrontCounterLocal--; + toggleCounterLocal = preambToggle; + break; + } + // End of preamble. + signalLocal = data; + stateLocal = !LOW; + continue; + + case data: + if (dataSequenceCounterLocal) + { + if (!(dataSequenceCounterLocal & 1U)) + { + currentBitSequenceLocal = ((sendBufferLocal[dataByteCounterLocal] >> dataBitCounterLocal) & 1U) ? bitHigh : bitLow; + dataBitCounterLocal--; + } + toggleCounterLocal = currentBitSequenceLocal[!stateLocal]; + dataSequenceCounterLocal--; + break; + } + // End of data byte. + syncLastBitLocal = ((sendBufferLocal[dataByteCounterLocal]) & 1U); + dataByteCounterLocal++; + dataBitCounterLocal = bitPerByte - 1; + dataSequenceCounterLocal = bitPerByte * 2; + signalLocal = sync; + continue; + + case sync: + if (syncSequenceCounterLocal) + { + if (!(syncSequenceCounterLocal & 1U)) + { + if (syncSequenceCounterLocal == 2) + { + currentBitSequenceLocal = ((sendBufferLocal[dataByteCounterLocal]) & 0b10000000) ? bitLow : bitHigh; + } + else + { + currentBitSequenceLocal = syncLastBitLocal ? bitLow : bitHigh; + syncLastBitLocal = !syncLastBitLocal; + } + } + toggleCounterLocal = currentBitSequenceLocal[!stateLocal]; + syncSequenceCounterLocal--; + break; + } + // End of sync. + signalLocal = data; + syncSequenceCounterLocal = syncBits * 2; + if (dataByteCounterLocal >= sendLenLocal) + { + signalLocal = noSignal; + } + continue; + + default: + return 0; + } + + stateLocal = !stateLocal; + break; + } + } +} + + +void IR_Encoder::enable() +{ + bool exist = false; + IR_Encoder *current = IR_Encoder::head; + while (current != nullptr) + { + exist = (current == this); + if (exist) break; + current = current->next; + } + if (!exist) + { + if (IR_Encoder::head == nullptr) + { + IR_Encoder::head = this; + last = this; + } + else + { + last->next = this; + last = this; + } + this->next = nullptr; // Указываем, что следующий за этим элементом — nullptr + } + pinMode(pin, OUTPUT); +} + +void IR_Encoder::disable() +{ + IR_Encoder *current = IR_Encoder::head; + IR_Encoder *prev = nullptr; + + while (current != nullptr) + { + if (current == this) break; + prev = current; + current = current->next; + } + + if (current != nullptr) // Элемент найден в списке + { + if (prev != nullptr) + { + prev->next = current->next; // Убираем текущий элемент из списка + } + else + { + IR_Encoder::head = current->next; // Удаляемый элемент был первым + } + + if (current == last) + { + last = prev; // Если удаляется последний элемент, обновляем last + } + } + + pinMode(pin, INPUT); +} + void IR_Encoder::setBlindDecoders(IR_DecoderRaw *decoders[], uint8_t count) { #if disablePairDec @@ -34,18 +310,15 @@ void IR_Encoder::setBlindDecoders(IR_DecoderRaw *decoders[], uint8_t count) blindDecoders = decoders; } -IR_Encoder::~IR_Encoder() -{ - delete[] bitLow; - delete[] bitHigh; -}; +IR_Encoder::~IR_Encoder(){}; -void IR_Encoder::sendData(uint16_t addrTo, uint8_t dataByte, bool needAccept = false) +IR_SendResult IR_Encoder::sendData(uint16_t addrTo, uint8_t dataByte, bool needAccept) { - uint8_t *dataPtr = new uint8_t[1]; - dataPtr[0] = dataByte; - sendData(addrTo, dataPtr, 1, needAccept); - delete[] dataPtr; + return sendData(addrTo, &dataByte, 1, needAccept); +} + +IR_SendResult IR_Encoder::sendData(uint16_t addrTo, uint8_t *data, uint8_t len, bool needAccept){ + return sendDataFULL(id, addrTo, data, len, needAccept); } void IR_Encoder::sendData(uint16_t addrTo, uint8_t *data = nullptr, uint8_t len = 0, bool needAccept = false){ @@ -55,7 +328,8 @@ void IR_Encoder::sendData(uint16_t addrFrom, uint16_t addrTo, uint8_t *data = nu { if (len > bytePerPack) { - return; + Serial.println("IR Pack to big"); + return IR_SendResult(false, 0); } constexpr uint8_t dataStart = msgBytes + addrBytes + addrBytes; memset(sendBuffer, 0x00, dataByteSizeMax); @@ -84,6 +358,19 @@ void IR_Encoder::sendData(uint16_t addrFrom, uint16_t addrTo, uint8_t *data = nu sendBuffer[packSize - crcBytes] = crc8(sendBuffer, 0, packSize - crcBytes, poly1) & 0xFF; sendBuffer[packSize - crcBytes + 1] = crc8(sendBuffer, 0, packSize - crcBytes + 1, poly2) & 0xFF; + //* вывод итогового буфера + // Serial.print("IR SEND [len="); + // Serial.print(packSize); + // Serial.print("] : "); + // for (uint8_t i = 0; i < packSize; i++) + // { + // if (sendBuffer[i] < 0x10) + // Serial.print('0'); + // Serial.print(sendBuffer[i], HEX); + // Serial.print(' '); + // } + // Serial.println(); + // if (decPair != nullptr) { // decPair->isWaitingAccept = ((msgType >> 5) & IR_MASK_MSG_TYPE == IR_MSG_DATA_ACCEPT); // if (decPair->isWaitingAccept) { @@ -93,9 +380,14 @@ void IR_Encoder::sendData(uint16_t addrFrom, uint16_t addrTo, uint8_t *data = nu // отправка rawSend(sendBuffer, packSize); + + // Возвращаем результат отправки + uint32_t sendTime = calculateSendTime(packSize); + return IR_SendResult(true, sendTime); } -void IR_Encoder::sendAccept(uint16_t addrTo, uint8_t customByte = 0) + +IR_SendResult IR_Encoder::sendAccept(uint16_t addrTo, uint8_t customByte) { constexpr uint8_t packsize = msgBytes + addrBytes + 1U + crcBytes; memset(sendBuffer, 0x00, dataByteSizeMax); @@ -116,9 +408,13 @@ void IR_Encoder::sendAccept(uint16_t addrTo, uint8_t customByte = 0) sendBuffer[5] = crc8(sendBuffer, 0, 5, poly2) & 0xFF; rawSend(sendBuffer, packsize); + + // Возвращаем результат отправки + uint32_t sendTime = calculateSendTime(packsize); + return IR_SendResult(true, sendTime); } -void IR_Encoder::sendRequest(uint16_t addrTo) +IR_SendResult IR_Encoder::sendRequest(uint16_t addrTo) { constexpr uint8_t packsize = msgBytes + addrBytes + addrBytes + crcBytes; memset(sendBuffer, 0x00, dataByteSizeMax); @@ -138,32 +434,37 @@ void IR_Encoder::sendRequest(uint16_t addrTo) sendBuffer[6] = crc8(sendBuffer, 0, 6, poly2) & 0xFF; rawSend(sendBuffer, packsize); + + // Возвращаем результат отправки + uint32_t sendTime = calculateSendTime(packsize); + return IR_SendResult(true, sendTime); } -void IR_Encoder::sendBack(uint8_t data) +IR_SendResult IR_Encoder::sendBack(uint8_t data) { - _sendBack(false, 0, &data, 1); -} -void IR_Encoder::sendBack(uint8_t *data = nullptr, uint8_t len = 0) -{ - _sendBack(false, 0, data, len); + return _sendBack(false, 0, &data, 1); } -void IR_Encoder::sendBackTo(uint16_t addrTo, uint8_t *data = nullptr, uint8_t len = 0) +IR_SendResult IR_Encoder::sendBack(uint8_t *data, uint8_t len) { - _sendBack(true, addrTo, data, len); + return _sendBack(false, 0, data, len); } -void IR_Encoder::_sendBack(bool isAdressed, uint16_t addrTo, uint8_t *data, uint8_t len) +IR_SendResult IR_Encoder::sendBackTo(uint16_t addrTo, uint8_t *data, uint8_t len) +{ + return _sendBack(true, addrTo, data, len); +} + +IR_SendResult IR_Encoder::_sendBack(bool isAdressed, uint16_t addrTo, uint8_t *data, uint8_t len) { if (len > bytePerPack) { - return; + return IR_SendResult(false, 0); } 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 packSize = msgBytes + addrBytes + (isAdressed ? addrBytes : 0) + min(uint8_t(1), len) + crcBytes; uint8_t msgType = ((isAdressed ? IR_MSG_BACK_TO : IR_MSG_BACK) << 5) | ((packSize) & (IR_MASK_MSG_INFO >> 1)); @@ -190,6 +491,10 @@ void IR_Encoder::_sendBack(bool isAdressed, uint16_t addrTo, uint8_t *data, uint // отправка rawSend(sendBuffer, packSize); + + // Возвращаем результат отправки + uint32_t sendTime = calculateSendTime(packSize); + return IR_SendResult(true, sendTime); } void IR_Encoder::setDecoder_isSending() @@ -199,6 +504,10 @@ void IR_Encoder::setDecoder_isSending() for (uint8_t i = 0; i < decodersCount; i++) { blindDecoders[i]->isPairSending ^= id; + // Serial.print("setDecoder_isSending() id = "); + // Serial.print(id); + // Serial.print(" isPairSending = "); + // Serial.println(blindDecoders[i]->isPairSending); } } } @@ -210,10 +519,38 @@ void IR_Encoder::rawSend(uint8_t *ptr, uint8_t len) // TODO: Обработка повторной отправки return; } + + // Проверка на переполнение буфера + if (len > dataByteSizeMax) + { + return; + } + if (externalTxStartFn != nullptr) + { + if (externalTxBusyFn != nullptr && externalTxBusyFn(externalTxCtx)) + { + return; + } + + // Mark as sending and delegate actual signal output to external backend. + setDecoder_isSending(); + sendLen = len; + isSending = true; + + const bool ok = externalTxStartFn(externalTxCtx, this, ptr, len); + if (!ok) + { + isSending = false; + setDecoder_isSending(); + } + return; + } + IR_Encoder::carrierResume(); + // Serial.println("START"); setDecoder_isSending(); - cli(); + // noInterrupts(); sendLen = len; toggleCounter = preambToggle; // Первая генерация для первого signal @@ -229,17 +566,29 @@ void IR_Encoder::rawSend(uint8_t *ptr, uint8_t len) state = HIGH; currentBitSequence = bitHigh; - isSending = true; - sei(); + // interrupts(); } void IR_Encoder::isr() +{ + IR_Encoder *current = IR_Encoder::head; + while (current != nullptr) + { + current->_isr(); + current = current->next; + } +} + +void IR_Encoder::_isr() { if (!isSending) return; ir_out_virtual = !ir_out_virtual && state; + port->ODR &= ~(mask); + port->ODR |= mask & (ir_out_virtual ? (uint16_t)0xFFFF : (uint16_t)0x0000); + if (toggleCounter) { toggleCounter--; @@ -254,7 +603,10 @@ void IR_Encoder::isr() // сброс счетчиков // ... isSending = false; + // Serial.println("STOP"); setDecoder_isSending(); + carrierStopPending = true; + // Serial.println(); return; break; @@ -335,32 +687,6 @@ void IR_Encoder::isr() } } -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; @@ -398,30 +724,101 @@ void IR_Encoder::addSync(bool *prev, bool *next) } } -void IR_Encoder::send_HIGH(bool prevBite = 1) -{ +uint8_t IR_Encoder::bitHigh[2] = { + (bitPauseTakts) * 2 - 1, + (bitActiveTakts) * 2 - 1}; +uint8_t IR_Encoder::bitLow[2] = { + (bitPauseTakts / 2 + bitActiveTakts) * 2 - 1, + (bitPauseTakts)-1}; - // 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); - // } +uint32_t IR_Encoder::calculateSendTime(uint8_t packSize) const +{ + // Расчет времени отправки пакета в миллисекундах + + // Время преамбулы: preambPulse * 2 фронта * bitTakts тактов + uint32_t preambTime = preambPulse * 2 * bitTakts; + + // Время данных: количество бит * bitTakts тактов + uint32_t dataTime = packSize * 8 * bitTakts; + + // Время синхронизации: syncBits * 2 фронта * bitTakts тактов + uint32_t syncTime = syncBits * 2 * bitTakts; + + // Общее время в тактах + uint32_t totalTakts = preambTime + dataTime + syncTime; + + // Конвертируем в миллисекунды + // carrierPeriod - период несущей в микросекундах + // totalTakts * carrierPeriod / 1000 = время в миллисекундах + uint32_t sendTimeMs = (totalTakts * carrierPeriod) / 1000; + + return sendTimeMs; } -void IR_Encoder::send_LOW() +// Функции для тестирования времени отправки без фактической отправки + +uint32_t IR_Encoder::testSendTime(uint16_t addrTo, uint8_t dataByte, bool needAccept) const { - // meanderBlock(bitPauseTakts, halfPeriod, LOW); - // meanderBlock(bitActiveTakts, halfPeriod, LOW); - // meanderBlock(bitPauseTakts, halfPeriod, HIGH); + return testSendTime(addrTo, &dataByte, 1, needAccept); } -void IR_Encoder::send_EMPTY(uint8_t count) +uint32_t IR_Encoder::testSendTime(uint16_t addrTo, uint8_t *data, uint8_t len, bool needAccept) const { - // for (size_t i = 0; i < count * 2; i++) { - // meanderBlock((bitPauseTakts * 2 + bitActiveTakts), halfPeriod, prevPreambBit); - // prevPreambBit = !prevPreambBit; - // } - // meanderBlock(bitPauseTakts * 2 + bitActiveTakts, halfPeriod, 0); //TODO: Отодвинуть преамбулу + return testSendTimeFULL(id, addrTo, data, len, needAccept); } + +uint32_t IR_Encoder::testSendTimeFULL(uint16_t addrFrom, uint16_t addrTo, uint8_t *data, uint8_t len, bool needAccept) const +{ + if (len > bytePerPack) + { + return 0; // Возвращаем 0 для недопустимого размера + } + + uint8_t packSize = msgBytes + addrBytes + addrBytes + len + crcBytes; + return calculateSendTime(packSize); +} + +uint32_t IR_Encoder::testSendAccept(uint16_t addrTo, uint8_t customByte) const +{ + constexpr uint8_t packsize = msgBytes + addrBytes + 1U + crcBytes; + return calculateSendTime(packsize); +} + +uint32_t IR_Encoder::testSendRequest(uint16_t addrTo) const +{ + constexpr uint8_t packsize = msgBytes + addrBytes + addrBytes + crcBytes; + return calculateSendTime(packsize); +} + +uint32_t IR_Encoder::testSendBack(uint8_t data) const +{ + return testSendBack(false, 0, &data, 1); +} + +uint32_t IR_Encoder::testSendBack(uint8_t *data, uint8_t len) const +{ + return testSendBack(false, 0, data, len); +} + +uint32_t IR_Encoder::testSendBackTo(uint16_t addrTo, uint8_t *data, uint8_t len) const +{ + return testSendBack(true, addrTo, data, len); +} + +uint32_t IR_Encoder::testSendBack(bool isAdressed, uint16_t addrTo, uint8_t *data, uint8_t len) const +{ + if (len > bytePerPack) + { + return 0; // Возвращаем 0 для недопустимого размера + } + + uint8_t packSize = msgBytes + addrBytes + (isAdressed ? addrBytes : 0) + min(uint8_t(1), len) + crcBytes; + return calculateSendTime(packSize); +} + +// uint8_t* IR_Encoder::bitHigh = new uint8_t[2]{ +// (bitPauseTakts) * 2 - 0, +// (bitActiveTakts) * 2 - 0}; +// uint8_t* IR_Encoder::bitLow = new uint8_t[2]{ +// (bitPauseTakts/2 + bitActiveTakts) * 2 - 0, +// (bitPauseTakts) - 0}; diff --git a/IR_Encoder.h b/IR_Encoder.h index 0344ed0..ddfaab0 100644 --- a/IR_Encoder.h +++ b/IR_Encoder.h @@ -3,72 +3,107 @@ // TODO: Отложенная передача после завершения приема +// Структура для возврата результата отправки +struct IR_SendResult { + bool success; // Флаг успешности отправки + uint32_t sendTimeMs; // Время отправки пакета в миллисекундах + + IR_SendResult(bool success = false, uint32_t sendTimeMs = 0) + : success(success), sendTimeMs(sendTimeMs) {} +}; + class IR_DecoderRaw; class IR_Encoder : public IR_FOX { friend IR_DecoderRaw; - + static IR_Encoder *head; + static IR_Encoder *last; + IR_Encoder *next; public: private: // uint16_t id; /// @brief Адрес передатчика + struct IR_TxGateRun { + uint16_t lenTicks; // number of timer ticks at carrierFrec*2 + bool gate; // true: carrier enabled (output toggles), false: silent (output forced low) + }; + + using ExternalTxBusyFn = bool (*)(void *ctx); + using ExternalTxStartFn = bool (*)(void *ctx, IR_Encoder *enc, const uint8_t *packet, uint8_t len); +private: + // uint16_t id; /// @brief Адрес передатчика public: /// @brief Класс передатчика /// @param addr Адрес передатчика /// @param pin Вывод передатчика - /// @param tune Подстройка несущей частоты /// @param decPair Приёмник, для которого отключается приём в момент передачи передатчиком - IR_Encoder(uint16_t addr, IR_DecoderRaw *decPair = nullptr); + IR_Encoder(uint8_t pin, uint16_t addr = 0, IR_DecoderRaw *decPair = nullptr, bool autoHandle = true); + static void isr(); + static void begin(HardwareTimer* timer, uint8_t channel, IRQn_Type IRQn, uint8_t priority, void(*isrCallback)() = nullptr); + /** Configure timer frequency for TX clock (carrierFrec*2) without attaching ISR. */ + static void beginClockOnly(HardwareTimer *timer); + static HardwareTimer* get_IR_Timer(); + /** Call from main loop/tick: if ISR requested carrier stop, pause timer here (not in ISR). */ + static void tick(); - static void timerSetup() - { - // TIMER2 Ini - uint8_t oldSREG = SREG; // Save global interupts settings - cli(); - // DDRB |= (1 << PORTB3); //OC2A (17) - TCCR2A = 0; - TCCR2B = 0; + /** Optional: register external TX backend (e.g. DMA driver). */ + static void setExternalTxBackend(ExternalTxStartFn startFn, ExternalTxBusyFn busyFn, void *ctx); - // TCCR2A |= (1 << COM2A0); //Переключение состояния + /** Called by external TX backend on actual end of transmission. */ + void externalFinishSend(); - TCCR2A |= (1 << WGM21); // Clear Timer On Compare (Сброс по совпадению) - TCCR2B |= (1 << CS20); // Предделитель 1 - TIMSK2 |= (1 << OCIE2A); // Прерывание по совпадению + /** Build RLE runs of carrier gate for a packet (no HW access). */ + static size_t buildGateRuns(const uint8_t *packet, uint8_t len, IR_TxGateRun *outRuns, size_t maxRuns); - OCR2A = /* 465 */ ((F_CPU / (38000 * 2)) - 2); // 38кГц + void enable(); + void disable(); - SREG = oldSREG; // Return interrupt settings - } - static void timerOFFSetup() - { - TIMSK2 &= ~(1 << OCIE2A); // Прерывание по совпадению выкл - } - - void IR_Encoder::setBlindDecoders(IR_DecoderRaw *decoders[], uint8_t count); + void setBlindDecoders(IR_DecoderRaw *decoders[], uint8_t count); void rawSend(uint8_t *ptr, uint8_t len); void sendData(uint16_t addrTo, uint8_t dataByte, bool needAccept = false); void sendData(uint16_t addrTo, uint8_t *data = nullptr, uint8_t len = 0, bool needAccept = false); void sendData(uint16_t addrFrom, uint16_t addrTo, uint8_t *data = nullptr, uint8_t len = 0, bool needAccept = false); - void sendAccept(uint16_t addrTo, uint8_t customByte = 0); - void sendRequest(uint16_t addrTo); + IR_SendResult sendAccept(uint16_t addrTo, uint8_t customByte = 0); + IR_SendResult sendRequest(uint16_t addrTo); - void sendBack(uint8_t data); - void sendBack(uint8_t *data = nullptr, uint8_t len = 0); - void sendBackTo(uint16_t addrTo, uint8_t *data = nullptr, uint8_t len = 0); + IR_SendResult sendBack(uint8_t data); + IR_SendResult sendBack(uint8_t *data = nullptr, uint8_t len = 0); + IR_SendResult sendBackTo(uint16_t addrTo, uint8_t *data = nullptr, uint8_t len = 0); + + // Функция для тестирования времени отправки без фактической отправки + uint32_t testSendTime(uint16_t addrTo, uint8_t dataByte, bool needAccept = false) const; + uint32_t testSendTime(uint16_t addrTo, uint8_t *data = nullptr, uint8_t len = 0, bool needAccept = false) const; + uint32_t testSendTimeFULL(uint16_t addrFrom, uint16_t addrTo, uint8_t *data = nullptr, uint8_t len = 0, bool needAccept = false) const; + uint32_t testSendAccept(uint16_t addrTo, uint8_t customByte = 0) const; + uint32_t testSendRequest(uint16_t addrTo) const; + uint32_t testSendBack(uint8_t data) const; + uint32_t testSendBack(uint8_t *data = nullptr, uint8_t len = 0) const; + uint32_t testSendBackTo(uint16_t addrTo, uint8_t *data = nullptr, uint8_t len = 0) const; + + inline bool isBusy() const { return isSending;} - void isr(); ~IR_Encoder(); volatile bool ir_out_virtual; + void _isr(); private: - void IR_Encoder::_sendBack(bool isAdressed, uint16_t addrTo, uint8_t *data, uint8_t len); + static volatile bool carrierStopPending; + static void carrierResume(); + static void carrierPauseIfIdle(); - void IR_Encoder::setDecoder_isSending(); + static ExternalTxStartFn externalTxStartFn; + static ExternalTxBusyFn externalTxBusyFn; + static void *externalTxCtx; + IR_SendResult _sendBack(bool isAdressed, uint16_t addrTo, uint8_t *data, uint8_t len); + + void setDecoder_isSending(); void sendByte(uint8_t byte, bool *prev, bool LOW_FIRST); void addSync(bool *prev, bool *next); + uint32_t calculateSendTime(uint8_t packSize) const; + uint32_t testSendBack(bool isAdressed, uint16_t addrTo, uint8_t *data, uint8_t len) const; void send_HIGH(bool = 1); void send_LOW(); void send_EMPTY(uint8_t count); @@ -106,12 +141,8 @@ private: 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}; + static uint8_t bitHigh[2]; + static uint8_t bitLow[2]; uint8_t *currentBitSequence = bitLow; volatile SignalPart signal; }; diff --git a/IR_config.cpp b/IR_config.cpp new file mode 100644 index 0000000..9ddae25 --- /dev/null +++ b/IR_config.cpp @@ -0,0 +1,33 @@ +#include "IR_config.h" + +void IR_FOX::setPin(uint8_t pin){ + this->pin = pin; + port = digitalPinToPort(pin); + mask = digitalPinToBitMask(pin); +} + +void IR_FOX::checkAddressRuleApply(uint16_t address, uint16_t id, bool &flag) +{ + flag = false; + flag |= id == 0; + flag |= address == id; + flag |= address >= IR_Broadcast; +} + +uint8_t IR_FOX::crc8(uint8_t *data, uint8_t start, uint8_t end, uint8_t poly) +{ // TODO: сделать возможность межбайтовой проверки + uint8_t crc = 0xff; + size_t i, j; + for (i = start; i < end; i++) + { + crc ^= data[i]; + for (j = 0; j < 8; j++) + { + if ((crc & 0x80) != 0) + crc = (uint8_t)((crc << 1) ^ poly); + else + crc <<= 1; + } + } + return crc; +}; diff --git a/IR_config.h b/IR_config.h index 9271d32..48ca2aa 100644 --- a/IR_config.h +++ b/IR_config.h @@ -1,25 +1,39 @@ #pragma once #include - +#include // #define IRDEBUG_INFO /*////////////////////////////////////////////////////////////////////////////////////// Для работы в паре положить декодер в энкодер -*/// Адресация с 1 до 65 499 -#define IR_Broadcast 65000 // 65 500 ~ 65 535 - широковещательные пакеты (всем), возможно разделить на 35 типов +*/ +// Адресация с 1 до 65 499 +#define IR_Broadcast 65000 // 65 500 ~ 65 535 - широковещательные пакеты (всем) /* -Адрес 0 запрещен и зарезервирован под NULL, либо тесты -IR_MSG_ACCEPT с адреса 0 воспринимается всеми устройствами +*Адресное пространство: + Адрес 0 запрещен и зарезервирован под NULL, либо тесты + IR_MSG_ACCEPT с адреса 0 воспринимается всеми устройствами +*/ +//**** Контрольные точки ****** +#define IR_MAX_ADDR_CPU 63999 +#define IR_MIN_ADDR_CPU 32000 +// //***** Группы машинок ******** +// #define IR_MAX_CAR_GROUP 31999 +// #define IR_MIN_CAR_GROUP 30000 -Адресное пространство: - -Излучатели контрольных точек: 1000 ~ 1999 -Излучатели без обратной связиЖ 2000 ~ 2999 -Излучатели светофоров: 3000 ~ 3999 +// //********** FREE ************* +// #define IR_MAX_FREE 31999 +// #define IR_MIN_FREE 2000 +//********* Машинки *********** +#define IR_MAX_CAR 31999 +#define IR_MIN_CAR 1 +//***** Пульты управления ***** +#define IR_MAX_CONTROLLER 64999 +#define IR_MIN_CONTROLLER 64000 +/* /```````````````````````````````````````````````` data pack `````````````````````````````````````````````\                                                                                                                                             @@ -38,61 +52,61 @@ msg type:                                         // | 01234567 |                                         //  ----------                                         // | xxx..... | = тип сообщения -                                        // | ...xxxxx | = длина (максимум 31 бита) +                                        // | ...xxxxx | = длина (максимум 31 бита) - не больше 24 байт на тело пакета                                         //  ---------- */ -#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_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 - - - -/`````````````````````` Задний сигнал машинки без адресации ``````````````````````\         -                                                                                            -{``````````} [````````````````````````] [````````````````````````] [``````````````]         -{ 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                         |       |      -\________________________________________________________________________________________________/       |      -|                                                                                                        |      -\________________________________________________________________________________________________________/      - -*/ +#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_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 + + + + /`````````````````````` Задний сигнал машинки без адресации ``````````````````````\         +                                                                                             + {``````````} [````````````````````````] [````````````````````````] [``````````````]         + { 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                         |       |      + \________________________________________________________________________________________________/       |      + |                                                                                                        |      + \________________________________________________________________________________________________________/      + + */ #define IR_MASK_MSG_TYPE 0b00000111 #define IR_MASK_MSG_INFO 0b00011111 @@ -101,13 +115,14 @@ customByte - контрольная сумма принятых данных п /////////////////////////////////////////////////////////////////////////////////////*/ typedef uint16_t crc_t; -#define bytePerPack 16 // колличество байтов в пакете +// #define BRUTEFORCE_CHECK // Перепроверяет пакет на 1 битные ошибки //TODO: зависает +#define bytePerPack (31) // колличество байтов в пакете #ifndef freeFrec -#define freeFrec true +#define freeFrec false #endif #ifndef subBufferSize -#define subBufferSize 35 //Буфер для складирования фронтов, пока их не обработают (передатчик) +#define subBufferSize 250 // Буфер для складирования фронтов, пока их не обработают (передатчик) #endif #define preambPulse 3 @@ -116,33 +131,40 @@ typedef uint16_t crc_t; ///////////////////////////////////////////////////////////////////////////////////// -#define bitPerByte 8U // Колличество бит в байте +#define bitPerByte 8U // Колличество бит в байте #define addrBytes 2 #define msgBytes 1 #define crcBytes 2 #define poly1 0x31 #define poly2 0x8C -#define syncBits 3U // количество битов синхронизации +#define syncBits 3U // количество битов синхронизации #define dataByteSizeMax (msgBytes + addrBytes + addrBytes + bytePerPack + crcBytes) -#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 12U // длительность низкого уровня в тактах -#define bitTakts (bitActiveTakts+(bitPauseTakts*2U)) // Общая длительность бита в тактах -#define bitTime (bitTakts*carrierPeriod) // Общая длительность бита +#define bitTakts (bitActiveTakts + bitPauseTakts) // Общая длительность бита в тактах +#define bitTime (bitTakts * carrierPeriod) // Общая длительность бита #define tolerance 300U -class IR_FOX { +constexpr uint16_t test_all_Time = bitTime; +constexpr uint16_t test_all_Takts = bitTakts * 2; +constexpr uint16_t test_hi = ((bitPauseTakts) * 2 - 0) + ((bitActiveTakts) * 2 - 0); +constexpr uint16_t test_low = ((bitPauseTakts / 2 + bitActiveTakts) * 2 - 0) + ((bitPauseTakts)-0); + +class IR_FOX +{ public: - struct PackOffsets { + struct PackOffsets + { uint8_t msgOffset; uint8_t addrFromOffset; uint8_t addrToOffset; @@ -150,54 +172,43 @@ public: uint8_t crcOffset; }; - struct ErrorsStruct { + struct ErrorsStruct + { uint8_t lowSignal = 0; uint8_t highSignal = 0; uint8_t other = 0; - void reset() { + void reset() + { lowSignal = 0; highSignal = 0; other = 0; } uint16_t all() { return lowSignal + highSignal + other; } - }; - struct PackInfo { - uint8_t* buffer = nullptr; + 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; - } - - uint16_t getId() { return id; } - void setId(uint16_t id) { this->id = id; } + inline uint16_t getId() const { return id; } + inline void setId(uint16_t id) { this->id = id; } + static void checkAddressRuleApply(uint16_t address, uint16_t id, bool &flag); + void setPin(uint8_t pin); + inline uint8_t getPin() { return pin; }; + inline GPIO_TypeDef *getPort() const { return port; } + inline uint16_t getPinMask() const { return mask; } protected: - ErrorsStruct errors; uint16_t id; - uint8_t crc8(uint8_t* data, uint8_t start, uint8_t end, uint8_t poly) { //TODO: сделать возможность межбайтовой проверки - uint8_t crc = 0xff; - size_t i, j; - for (i = start; i < end; i++) { - crc ^= data[i]; - for (j = 0; j < 8; j++) { - if ((crc & 0x80) != 0) - crc = (uint8_t)((crc << 1) ^ poly); - else - crc <<= 1; - } - } - return crc; - } - + uint8_t pin; + GPIO_TypeDef *port; + uint16_t mask; + ErrorsStruct errors; + uint8_t crc8(uint8_t *data, uint8_t start, uint8_t end, uint8_t poly); }; diff --git a/PacketTypes.cpp b/PacketTypes.cpp new file mode 100644 index 0000000..d1c9dc4 --- /dev/null +++ b/PacketTypes.cpp @@ -0,0 +1,107 @@ +#include "PacketTypes.h" + +namespace PacketTypes +{ + bool BasePack::checkAddress() { return true; }; + void BasePack::set(IR_FOX::PackInfo *packInfo, uint16_t id) + { + this->packInfo = packInfo; + this->id = id; + + if (checkAddress()) + { + isAvailable = true; + isRawAvailable = true; +#ifdef IRDEBUG_INFO + Serial.print(" OK "); +#endif + } + else + { + isRawAvailable = true; +#ifdef IRDEBUG_INFO + Serial.print(" NOT-OK "); +#endif + } + } + + uint16_t BasePack::_getAddrFrom(BasePack *obj) + { + return (obj->packInfo->buffer[obj->addressFromOffset] << 8) | obj->packInfo->buffer[obj->addressFromOffset + 1]; + }; + uint16_t BasePack::_getAddrTo(BasePack *obj) + { + return (obj->packInfo->buffer[obj->addressToOffset] << 8) | obj->packInfo->buffer[obj->addressToOffset + 1]; + }; + + uint8_t BasePack::_getDataSize(BasePack *obj) + { + return obj->packInfo->packSize - crcBytes - obj->DataOffset; + }; + uint8_t *BasePack::_getDataPrt(BasePack *obj) + { + return obj->packInfo->buffer + obj->DataOffset; + }; + uint8_t BasePack::_getDataRawSize(BasePack *obj) + { + return obj->packInfo->packSize; + }; + + bool BasePack::available() + { + if (isAvailable) + { + isAvailable = false; + isRawAvailable = false; + return true; + } + else + { + return false; + } + }; + bool BasePack::availableRaw() + { + if (isRawAvailable) + { + isRawAvailable = false; + return true; + } + else + { + return false; + } + }; + + bool Data::checkAddress() + { + bool ret; + IR_FOX::checkAddressRuleApply(getAddrTo(), this->id, ret); + return ret; + } + + bool DataBack::checkAddress() + { + 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; + } + + bool Accept::checkAddress() { return true; } + + bool Request::checkAddress() + { + bool ret; + IR_FOX::checkAddressRuleApply(getAddrTo(), this->id, ret); + return ret; + } +} \ No newline at end of file diff --git a/PacketTypes.h b/PacketTypes.h index 07d24fd..ea37677 100644 --- a/PacketTypes.h +++ b/PacketTypes.h @@ -21,86 +21,28 @@ namespace PacketTypes IR_FOX::PackInfo *packInfo; uint16_t id; - virtual bool checkAddress() { return true; }; - void set(IR_FOX::PackInfo *packInfo, uint16_t id) - { - this->packInfo = packInfo; - this->id = id; + virtual bool checkAddress(); + void set(IR_FOX::PackInfo *packInfo, uint16_t id); - if (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; - }; + static uint16_t _getAddrFrom(BasePack *obj); + static uint16_t _getAddrTo(BasePack *obj); + static uint8_t _getDataSize(BasePack *obj); + static uint8_t *_getDataPrt(BasePack *obj); + static uint8_t _getDataRawSize(BasePack *obj); 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; }; + bool available(); + bool availableRaw(); + + inline uint8_t getMsgInfo() { return packInfo->buffer[0] & IR_MASK_MSG_INFO; }; + inline uint8_t getMsgType() { return (packInfo->buffer[0] >> 5) & IR_MASK_MSG_TYPE; }; + inline uint8_t getMsgRAW() { return packInfo->buffer[0]; }; + inline uint16_t getErrorCount() { return packInfo->err.all(); }; + inline uint8_t getErrorLowSignal() { return packInfo->err.lowSignal; }; + inline uint8_t getErrorHighSignal() { return packInfo->err.highSignal; }; + inline uint8_t getErrorOther() { return packInfo->err.other; }; + inline uint16_t getTunerTime() { return packInfo->rTime; }; + inline uint8_t *getDataRawPtr() { return packInfo->buffer; }; }; class Data : public BasePack @@ -114,20 +56,15 @@ namespace PacketTypes DataOffset = 5; } - uint16_t getAddrFrom() { return _getAddrFrom(this); }; - uint16_t getAddrTo() { return _getAddrTo(this); }; + inline uint16_t getAddrFrom() { return _getAddrFrom(this); }; + inline uint16_t getAddrTo() { return _getAddrTo(this); }; - uint8_t getDataSize() { return _getDataSize(this); }; - uint8_t *getDataPrt() { return _getDataPrt(this); }; - uint8_t getDataRawSize() { return _getDataRawSize(this); }; + inline uint8_t getDataSize() { return _getDataSize(this); }; + inline uint8_t *getDataPrt() { return _getDataPrt(this); }; + inline uint8_t getDataRawSize() { return _getDataRawSize(this); }; private: - bool checkAddress() override - { - bool ret; - IR_FOX::checkAddressRuleApply(getAddrTo(), this->id, ret); - return ret; - } + bool checkAddress() override; }; class DataBack : public BasePack @@ -141,29 +78,15 @@ namespace PacketTypes DataOffset = 3; } - uint16_t getAddrFrom() { return _getAddrFrom(this); }; - uint16_t getAddrTo() { return _getAddrTo(this); }; + inline uint16_t getAddrFrom() { return _getAddrFrom(this); }; + inline uint16_t getAddrTo() { return _getAddrTo(this); }; - uint8_t getDataSize() { return _getDataSize(this); }; - uint8_t *getDataPrt() { return _getDataPrt(this); }; - uint8_t getDataRawSize() { return _getDataRawSize(this); }; + inline uint8_t getDataSize() { return _getDataSize(this); }; + inline uint8_t *getDataPrt() { return _getDataPrt(this); }; + inline 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; - } + bool checkAddress() override; }; class Accept : public BasePack @@ -176,11 +99,11 @@ namespace PacketTypes DataOffset = 3; } - uint16_t getAddrFrom() { return _getAddrFrom(this); }; - uint8_t getCustomByte() { return packInfo->buffer[DataOffset]; }; + inline uint16_t getAddrFrom() { return _getAddrFrom(this); }; + inline uint8_t getCustomByte() { return packInfo->buffer[DataOffset]; }; private: - bool checkAddress() override { return true; } + bool checkAddress() override; }; class Request : public BasePack @@ -194,168 +117,11 @@ namespace PacketTypes DataOffset = 3; } - uint16_t getAddrFrom() { return _getAddrFrom(this); }; - uint16_t getAddrTo() { return _getAddrTo(this); }; + inline uint16_t getAddrFrom() { return _getAddrFrom(this); }; + inline uint16_t getAddrTo() { return _getAddrTo(this); }; private: - bool checkAddress() override - { - bool ret; - IR_FOX::checkAddressRuleApply(getAddrTo(), this->id, ret); - return ret; - } + bool checkAddress() override; }; } - -// 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: -// }; diff --git a/RingBuffer.h b/RingBuffer.h new file mode 100644 index 0000000..4e23bfe --- /dev/null +++ b/RingBuffer.h @@ -0,0 +1,39 @@ +#pragma once +#include "Arduino.h" +template +class RingBuffer { +public: + RingBuffer() : start(0), end(0) {} + + bool isFull() const { + return ((end + 1) % BufferSize) == start; + } + + bool isEmpty() const { + return start == end; + } + + void push(T element) { + noInterrupts(); + if (!isFull()) { + data[end] = element; + end = (end + 1) % BufferSize; + } + interrupts(); + } + + T* pop() { + noInterrupts(); + T* value = nullptr; + if (!isEmpty()) { + value = &data[start]; + start = (start + 1) % BufferSize; + } + interrupts(); + return value; + } + +private: + T data[BufferSize]; + unsigned int start, end; +}; \ No newline at end of file