From 56c207b058b908b942f798600356d6a5d050447f Mon Sep 17 00:00:00 2001 From: DashyFox Date: Wed, 24 Jan 2024 12:23:18 +0300 Subject: [PATCH] isr optimizations --- IR_Decoder.cpp | 177 ++++++++++++++++++++++++++++++++++++++++++++++--- IR_Decoder.h | 26 +++++++- 2 files changed, 192 insertions(+), 11 deletions(-) diff --git a/IR_Decoder.cpp b/IR_Decoder.cpp index fb33897..9293ef9 100644 --- a/IR_Decoder.cpp +++ b/IR_Decoder.cpp @@ -23,7 +23,7 @@ void IR_Decoder::writeToBuffer(bool bit) { }/* else { rawBuffer[(bufBitPos >> 3)] |= bit << (bufBitPos & ~(~0 << 3)); } */ - + Serial.print(bit); #ifdef IRDEBUG bit ? infoPulse(writeOp, 2) : infoPulse(writeOp, 1); #endif @@ -31,7 +31,7 @@ void IR_Decoder::writeToBuffer(bool bit) { if (isBufferOverflow) { //TODO: Буффер переполнен! } - +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //const auto testval = bufferBitSizeMax; if ((bufBitPos >= (8 * msgBytes) - syncBits) && !isMsgAvaliable) { switch ((rawBuffer[0] >> 5) & IR_MASK_MSG_TYPE) { @@ -80,7 +80,7 @@ void IR_Decoder::writeToBuffer(bool bit) { break; } } - +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// if (bufBitPos >= bufferRawSize * 8 - 1) { isBufferOverflow = true; } bufBitPos++; } @@ -168,19 +168,27 @@ uint16_t IR_Decoder::ceil_div(uint16_t val, uint16_t divider) { return ret; } -void IR_Decoder::listen(){ - if(isRecive && micros()-prevRise > IR_timeout*2) {isRecive = false;} +void IR_Decoder::listen() { + if (isRecive && micros() - prevRise > IR_timeout * 2) { + isRecive = false; + } } //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////// isr /////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// +void IR_Decoder::tick() { + if (firstUnHandledFront == nullptr) return; //Если данных нет - ничего не делаем -void IR_Decoder::isr() { // в прерывании вызываем isr() - if (isPairSending) return; + FrontStorage currentFront; + //найти следующий необработанный фронт/спад + noInterrupts(); + currentFront = *((FrontStorage*)firstUnHandledFront); + interrupts(); + //////////////////////////////////////////////////////////////////////////////////////////////////////////// - if (micros() - prevRise > IR_timeout) { // первый + if (currentFront.time - prevRise > IR_timeout && currentFront.dir) { // первый ↑ isRecive = true; isPreamb = true; frontCounter = preambFronts - 1U; @@ -188,6 +196,156 @@ void IR_Decoder::isr() { // в прерывании вызываем isr() riseSyncTime = bitTime /* 1100 */; start_RX(); + // Serial.println(); + // Serial.print("currentFront.time: "); Serial.println(currentFront.time); + // Serial.print("currentFront.dir: "); Serial.println(currentFront.dir ? "UP" : "Down"); + // Serial.print("prevRise: "); Serial.println(prevRise); + // Serial.print("frontCounter: "); Serial.println(frontCounter); + + // prevRise = currentFront.time; + } + + if (frontCounter > 0) { // в преамбуле + uint32_t risePeriod = currentFront.time - prevRise; + if (currentFront.dir && risePeriod < IR_timeout) { // __/``` ↑ и мы в внутри пакета + + if (risePeriod < riseTimeMin << 1) { // fix рваной единицы + frontCounter += 2; + errorCounter++; + } else { + if (freeFrec) { riseSyncTime = (riseSyncTime + risePeriod / 2) / 2; } // tuner + } + } else { /* riseSyncTime = bitTime; */ } // сброс тюнера + frontCounter--; + // Serial.print("frontCounter: "); Serial.println(frontCounter); + } else { + if (isPreamb) {// первый фронт после + gotTune._set(riseSyncTime); + } + isPreamb = false; + } + + // определить направление фронта + if (currentFront.dir) { // Если __/``` ↑ + + uint16_t risePeriod = currentFront.time - prevRise; + uint16_t highTime = currentFront.time - prevFall; + uint16_t lowTime = prevFall - prevRise; + + int8_t highCount = 0; + int8_t lowCount = 0; + int8_t allCount = 0; + + if (risePeriod < IR_timeout && !isBufferOverflow && risePeriod > riseTimeMin) { + // Мы в пределах таймаута и буффер не переполнен и fix дроблёных единиц + + if (aroundRise(risePeriod)) { // тактирование есть, сигнал хороший - без ошибок(?) + + if (highTime > riseTimeMin >> 1) { // 1 + writeToBuffer(HIGH); + } else { // 0 + writeToBuffer(LOW); + } + + } else { // пропущены такты! сигнал средний // ошибка пропуска + highCount = ceil_div(highTime, riseTime); // предполагаемое колличество HIGH битов + lowCount = ceil_div(lowTime, riseTime); // предполагаемое колличество LOW битов + allCount = ceil_div(risePeriod, riseTime); // предполагаемое колличество всего битов + + if (highCount == 0 && highTime > riseTime / 3) { // fix короткой единицы (?)после пропуска нулей(?) + highCount++; + errorCounter++; + } + + if (lowCount + highCount > allCount) { // fix ошибочных сдвигов + if (lowCount > highCount) { // Лишние нули + lowCount = allCount - highCount; + } else if (lowCount < highCount) { // Лишние единицы + highCount = allCount - lowCount; + } else if (lowCount == highCount) {} // неизвестный случай + errorCounter += allCount; + } + + errorCounter += allCount; + + for (int8_t i = 0; i < lowCount && 8 - i; i++) { // отправка LOW битов, если есть + writeToBuffer(LOW); + } + + for (int8_t i = 0; i < highCount && 8 - i; i++) { // отправка HIGH битов, если есть + writeToBuffer(HIGH); + } + } + } + + if (risePeriod > riseTimeMax / 2 || highCount || lowCount) { // комплексный фикс рваной единицы + prevPrevRise = prevRise; + prevRise = currentFront.time; + } else { + errorCounter++; + + } + + } else { // Если ```\__ ↓ + + if (currentFront.time - prevFall > riseTimeMin) { + prevPrevFall = prevFall; + prevFall = currentFront.time; + } else { + + } + } + + if (isPreamb && frontCounter <= 0) { + prevRise = currentFront.time + riseTime; + } + + + //////////////////////////////////////////////////////////////////////////////////////////////////////////// + firstUnHandledFront = firstUnHandledFront->next; //переместить флаг на следующий элемент (next or nullptr) +} + +void IR_Decoder::isr() { // в прерывании вызываем isr() + if (isPairSending) return; + + frontBuffer[currentFrontBufferWriteIndex].next = nullptr; + frontBuffer[currentFrontBufferWriteIndex].dir = (PIND >> isrPin) & 1; + frontBuffer[currentFrontBufferWriteIndex].time = micros(); + + if (firstUnHandledFront == nullptr) { + firstUnHandledFront = &frontBuffer[currentFrontBufferWriteIndex]; // Если нет необработанных данных - добавляем их + } else { + if (firstUnHandledFront == &frontBuffer[currentFrontBufferWriteIndex]) { // Если контроллер не успел обработать новый сигнал, принудительно пропускаем его + firstUnHandledFront = firstUnHandledFront->next; + Serial.println(); + Serial.println("ERROR"); + Serial.println(); + } + } + + if (lastFront == nullptr) { + lastFront = &frontBuffer[currentFrontBufferWriteIndex]; + } else { + lastFront->next = &frontBuffer[currentFrontBufferWriteIndex]; + lastFront = &frontBuffer[currentFrontBufferWriteIndex]; + } + + + currentFrontBufferWriteIndex == (subBuffer - 1) ? currentFrontBufferWriteIndex = 0 : currentFrontBufferWriteIndex++; +} + + +void IR_Decoder::noFunc() { + //////////////////////////////////////////////////////////////////////////////////////////////////////////// + if (micros() - prevRise > IR_timeout && (PIND >> isrPin) & 1) { // первый + isRecive = true; + isPreamb = true; + frontCounter = preambFronts - 1U; + errorCounter = 0; + riseSyncTime = bitTime /* 1100 */; + start_RX(); + Serial.println("First!"); + } if (frontCounter > 0) { // в преамбуле uint32_t risePeriod = micros() - prevRise; @@ -206,7 +364,7 @@ void IR_Decoder::isr() { // в прерывании вызываем isr() if (isPreamb) {// первый фронт после gotTune._set(riseSyncTime); } - isPreamb = false; + isPreamb = false; } // определить направление фронта @@ -325,6 +483,7 @@ void IR_Decoder::isr() { // в прерывании вызываем isr() #ifdef IRDEBUG digitalWrite(writeOp, isPreamb); #endif + //////////////////////////////////////////////////////////////////////////////////////////////////////////// } diff --git a/IR_Decoder.h b/IR_Decoder.h index 8397273..6eec030 100644 --- a/IR_Decoder.h +++ b/IR_Decoder.h @@ -21,6 +21,8 @@ #define aroundRise(t) (riseTimeMin < t && t < riseTimeMax) #define IR_timeout ((riseTimeMax * 8) + syncBits +1) // us // таймаут в 8 data + 3 sync + 1 +#define subBuffer 5 //Буфер для складирования фронтов, пока их не обработают + class IR_Encoder; class IR_Decoder : private IR_FOX { friend IR_Encoder; @@ -33,6 +35,8 @@ public: // @brief Для прерывания void isr(); + void tick(); + // @return Буффер переполнился bool isOverflow() { return isBufferOverflow; }; @@ -111,7 +115,6 @@ public: }; // class RawData : public Data { - // }; class Accept : public InputData { @@ -175,7 +178,6 @@ private: bool isWaitingAccept = false; uint16_t addrWaitingFrom = 0; - uint16_t addrFrom = 0; uint16_t riseSyncTime = bitTime; @@ -196,6 +198,26 @@ private: (bufferBitSizeMax / 8) + 1 : (bufferBitSizeMax / 8)); const uint8_t bufferDataSize = dataByteSizeMax; // + crc + //////////////////////////////////////////////////////////////////////// + void noFunc(); + volatile uint8_t currentFrontBufferWriteIndex; + struct FrontStorage { + volatile uint32_t time; + volatile bool dir; + volatile FrontStorage* next; + + FrontStorage& operator= (FrontStorage& val) { + this->next = val.next; + this->time = val.time; + this->dir = val.dir; + + return *this; + } + }; + volatile FrontStorage* lastFront = nullptr; + volatile FrontStorage* firstUnHandledFront = nullptr; + volatile FrontStorage frontBuffer[subBuffer]; + //////////////////////////////////////////////////////////////////////// uint8_t* rawBuffer = nullptr; uint8_t* dataBuffer = nullptr;