isr optimizations

This commit is contained in:
DashyFox 2024-01-24 12:23:18 +03:00
parent d8283620b7
commit 56c207b058
2 changed files with 192 additions and 11 deletions

View File

@ -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;
@ -325,6 +483,7 @@ void IR_Decoder::isr() { // в прерывании вызываем isr()
#ifdef IRDEBUG
digitalWrite(writeOp, isPreamb);
#endif
////////////////////////////////////////////////////////////////////////////////////////////////////////////
}

View File

@ -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;