From bf14b3d7ad768cdff9c1c35aa6e200a7dfc68338 Mon Sep 17 00:00:00 2001 From: DashyFox Date: Wed, 1 Jul 2026 13:38:51 +0300 Subject: [PATCH] fix(rx/tx): B5 pop-by-value, B6 ISR micros mask, B7 crc parens, B10 div guard, send length validation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit B5 (MEDIUM): RingBuffer::pop(T&) копирует под одной критсекцией; tick() перешёл на неё → нет торн-рида (внутренний interrupts() в T* pop снимал внешнюю защиту до чтения *ptr). T* pop() оставлен (не используется). B6 (MEDIUM): убрана лишняя noInterrupts/interrupts вокруг micros() в EXTI-ISR (снимала PRIMASK посреди ISR). std::function-диспетчеризация attachInterrupt — структурна, не трогаю. B7 (LOW): скобки в crcCheck (== & 0xFF по приоритету). B10 (LOW): guard деления на 0 в ceil_div (актуально только при freeFrec — НЕ включаю). send: sendDataFULL — валидация полного packSize<=31 (было len>bytePerPack=31, packSize=7+len оборачивался → тихая потеря Data payload 25..31). B8 (isSubBufferOverflow) — уже volatile, потеря флага безвредна (диагностика), не трогаю. B9 (prevRise==0 при micros()==0) — уже обработан веткой в preambleProcessEdge, намеренно. Co-Authored-By: Claude Opus 4.8 (1M context) --- IR_DecoderRaw.cpp | 19 +++++-------------- IR_Encoder.cpp | 5 ++++- RingBuffer.h | 15 +++++++++++++++ 3 files changed, 24 insertions(+), 15 deletions(-) diff --git a/IR_DecoderRaw.cpp b/IR_DecoderRaw.cpp index 2be0582..66482f2 100644 --- a/IR_DecoderRaw.cpp +++ b/IR_DecoderRaw.cpp @@ -276,10 +276,8 @@ void IR_DecoderRaw::isr() // Интервалы между соседними фронтами считаются как (uint32_t)(t1 - t0) — корректно при // паузе < ~35 мин между фронтами; условие «тишина > longSilence» в preambleProcessEdge // переписано без front.time > prevRise (оно ломается при wrap). - uint32_t t; - noInterrupts(); - t = micros(); - interrupts(); + // B6: micros() в ISR не требует маскировки; прежний interrupts() посреди ISR снимал PRIMASK. + const uint32_t t = micros(); FrontStorage edge; edge.dir = port->IDR & mask; @@ -403,16 +401,8 @@ void IR_DecoderRaw::tick() // с метками ISR из очереди → ложные TIMEOUT (bits=0) каждый пакет. FrontStorage rawFront; - bool hasRawFront = false; bool processedFront = false; - noInterrupts(); - FrontStorage *rawPtr = subBuffer.pop(); - if (rawPtr != nullptr) - { - rawFront = *rawPtr; - hasRawFront = true; - } - interrupts(); + const bool hasRawFront = subBuffer.pop(rawFront); // B5: копия под одной критсекцией (без торн-рида) if (IR_INPUT_MIN_PULSE_US > 0U) { @@ -961,7 +951,7 @@ bool IR_DecoderRaw::crcCheck(uint8_t len, crc_t &crc) crc = (crc8(dataBuffer, 0, len, poly1) << 8) & ~((crc_t)0xFF); crc |= crc8(dataBuffer, 0, len + 1, poly2) & (crc_t)0xFF; - if (dataBuffer[len] == (crc >> 8) & 0xFF && + if (dataBuffer[len] == ((crc >> 8) & 0xFF) && // B7: скобки — иначе (== & 0xFF) по приоритету dataBuffer[len + 1] == (crc & 0xFF)) { crcOK = true; @@ -984,6 +974,7 @@ bool IR_DecoderRaw::availableReject() uint16_t IR_DecoderRaw::ceil_div(uint16_t val, uint16_t divider) { + if (divider == 0) return 0; // B10: защита от деления на 0 (актуально при freeFrec — сейчас выкл, не включаем) int ret = val / divider; if ((val << 4) / divider - (ret << 4) >= 8) ret++; diff --git a/IR_Encoder.cpp b/IR_Encoder.cpp index 872e47e..e92b565 100644 --- a/IR_Encoder.cpp +++ b/IR_Encoder.cpp @@ -688,7 +688,10 @@ IR_SendResult IR_Encoder::sendData(uint16_t addrTo, uint8_t *data, uint8_t len, IR_SendResult IR_Encoder::sendDataFULL(uint16_t addrFrom, uint16_t addrTo, uint8_t *data, uint8_t len, bool needAccept) { - if (len > bytePerPack) + // 5-битное поле длины => ВЕСЬ кадр ≤31 байт (для Data payload ≤24). Было `len > bytePerPack(31)` — + // неверно: packSize=7+len оборачивался в заголовке (packSize & 0x1F) при len 25..31 → кадр молча + // терялся, а send возвращал успех. Проверяем полный packSize в широком типе (uint8_t 7+len мог переполниться). + if (((uint16_t)msgBytes + addrBytes + addrBytes + len + crcBytes) > IR_MASK_MSG_INFO) { Serial.println("IR Pack to big"); return IR_SendResult(false, 0, IR_SendStatus::PayloadTooLarge); diff --git a/RingBuffer.h b/RingBuffer.h index 7bd7818..2ed56c5 100644 --- a/RingBuffer.h +++ b/RingBuffer.h @@ -36,6 +36,21 @@ public: return value; } + // B5: безопасный pop — копирует элемент под ОДНОЙ критсекцией и отдаёт по значению. + // (T* pop() отдаёт указатель во внутренний слот; его внутренний interrupts() снимает внешнюю + // защиту вызывающего ДО чтения *ptr → торн-рид, если кольцо переполнится в этом окне.) + bool pop(T &out) { + bool popped = false; + noInterrupts(); + if (!isEmpty()) { + out = data[start]; + start = (start + 1) % BufferSize; + popped = true; + } + interrupts(); + return popped; + } + private: T data[BufferSize]; unsigned int start, end;