mirror of
https://github.com/Show-maket/IR-protocol.git
synced 2026-04-28 03:08:08 +00:00
Merge branch 'main' of https://github.com/Show-maket/IR-protocol
This commit is contained in:
122
IR_Encoder.h
122
IR_Encoder.h
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include "IR_config.h"
|
||||
#include "IrTxBsrrWave.h"
|
||||
|
||||
// TODO: Отложенная передача после завершения приема
|
||||
|
||||
@ -23,10 +24,7 @@ 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 IR_TxGateRun = IrTxGateRun;
|
||||
|
||||
using ExternalTxBusyFn = bool (*)(void *ctx);
|
||||
using ExternalTxStartFn = bool (*)(void *ctx, IR_Encoder *enc, const uint8_t *packet, uint8_t len);
|
||||
@ -36,16 +34,47 @@ public:
|
||||
/// @brief Класс передатчика
|
||||
/// @param addr Адрес передатчика
|
||||
/// @param pin Вывод передатчика
|
||||
/// @param decPair Приёмник, для которого отключается приём в момент передачи передатчиком
|
||||
/// @param decPair Если задан, конструктор регистрирует этот один приёмник как blind-decoder
|
||||
/// (аналог setBlindDecoders() для одного RX).
|
||||
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. */
|
||||
/**
|
||||
* Глобальный знаменатель: частота таймера TX = carrierFrec × multiply (слотов на период несущей).
|
||||
* По умолчанию multiply=2 (как бывшие carrierFrec×2). Задавать до begin/beginClockOnly либо после
|
||||
* изменения вызвать retuneCarrierClock() (не менять multiply во время активной передачи).
|
||||
*/
|
||||
static void setCarrierMultiply(uint16_t multiply);
|
||||
static uint16_t carrierMultiply();
|
||||
/** Повторно применить carrierFrec×multiply к IR_Timer (pause + setOverflow), ISR не перенавешивает. */
|
||||
static void retuneCarrierClock();
|
||||
|
||||
/** Максимальный числитель мощности: ⌊multiply/2⌋ (100% в setPowerPercent). */
|
||||
static uint16_t maxPowerNumerator();
|
||||
|
||||
/** Числитель N: при открытой огибающей N из multiply тиков HIGH за период несущей. Clamped к maxPowerNumerator(). */
|
||||
void setPowerNumerator(uint16_t n);
|
||||
uint16_t powerNumerator() const;
|
||||
/** p∈[0,100] → ближайший допустимый числитель; 100% даёт N = maxPowerNumerator(). */
|
||||
void setPowerPercent(uint8_t p);
|
||||
|
||||
/** После buildGateRuns: lenTicks в тактах 2×Fc → физические тики (carrierFrec×multiply). Может разбить сегменты. */
|
||||
static bool scaleGateRunsToPhysical(IR_TxGateRun* runs, size_t* ioCount, size_t maxRuns, uint16_t multiply);
|
||||
|
||||
/** Configure timer frequency for TX clock (carrierFrec × multiply) 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();
|
||||
|
||||
/**
|
||||
* Режим внутреннего TX без DMA: false — BSRR + кольцо (buildGateRuns + scaleGateRunsToPhysical);
|
||||
* true — FSM «налету» + скважность несущей как у буферного пути (подшаги multiply/2 на шаг FSM).
|
||||
* Выставить до begin/rawSend (глобально на все IR_Encoder). Игнорируется при externalTxStartFn.
|
||||
*/
|
||||
static void setTxIsrLegacyMode(bool legacy);
|
||||
static bool txIsrLegacyMode();
|
||||
|
||||
/** Optional: register external TX backend (e.g. DMA driver). */
|
||||
static void setExternalTxBackend(ExternalTxStartFn startFn, ExternalTxBusyFn busyFn, void *ctx);
|
||||
|
||||
@ -59,6 +88,13 @@ public:
|
||||
void disable();
|
||||
|
||||
void setBlindDecoders(IR_DecoderRaw *decoders[], uint8_t count);
|
||||
template <size_t N>
|
||||
void setBlindDecoders(IR_DecoderRaw *(&decoders)[N])
|
||||
{
|
||||
static_assert(N <= IR_PAIR_MUTE_MAX_ENCODERS,
|
||||
"IR_Encoder::setBlindDecoders: array size exceeds IR_PAIR_MUTE_MAX_ENCODERS");
|
||||
setBlindDecoders(decoders, static_cast<uint8_t>(N));
|
||||
}
|
||||
void rawSend(uint8_t *ptr, uint8_t len);
|
||||
|
||||
void sendData(uint16_t addrTo, uint8_t dataByte, bool needAccept = false);
|
||||
@ -91,6 +127,8 @@ public:
|
||||
void _isr();
|
||||
private:
|
||||
static volatile bool carrierStopPending;
|
||||
static bool txIsrLegacyMode_;
|
||||
static uint16_t s_carrierMultiply;
|
||||
static void carrierResume();
|
||||
static void carrierPauseIfIdle();
|
||||
|
||||
@ -99,7 +137,8 @@ private:
|
||||
static void *externalTxCtx;
|
||||
IR_SendResult _sendBack(bool isAdressed, uint16_t addrTo, uint8_t *data, uint8_t len);
|
||||
|
||||
void setDecoder_isSending();
|
||||
void refreshBlindDecoderMuteState();
|
||||
void registerWithBlindDecoders();
|
||||
void sendByte(uint8_t byte, bool *prev, bool LOW_FIRST);
|
||||
void addSync(bool *prev, bool *next);
|
||||
uint32_t calculateSendTime(uint8_t packSize) const;
|
||||
@ -116,25 +155,66 @@ private:
|
||||
sync = 3
|
||||
};
|
||||
|
||||
IR_DecoderRaw *decPair;
|
||||
IR_DecoderRaw **blindDecoders;
|
||||
uint8_t decodersCount;
|
||||
struct TxFsmState
|
||||
{
|
||||
uint8_t sendLen = 0;
|
||||
uint8_t toggleCounter = 0;
|
||||
uint8_t dataBitCounter = 0;
|
||||
uint8_t dataByteCounter = 0;
|
||||
uint8_t preambFrontCounter = 0;
|
||||
uint8_t dataSequenceCounter = 0;
|
||||
uint8_t syncSequenceCounter = 0;
|
||||
bool syncLastBit = false;
|
||||
bool state = LOW;
|
||||
uint8_t *currentBitSequence = nullptr;
|
||||
SignalPart signal = noSignal;
|
||||
};
|
||||
|
||||
uint8_t sendLen;
|
||||
static bool txAdvanceBoundary(TxFsmState &st, const uint8_t *sendBufferLocal);
|
||||
static bool txAdvanceAfterOutput(TxFsmState &st, const uint8_t *sendBufferLocal);
|
||||
static bool txEmitTick(TxFsmState &st, const uint8_t *sendBufferLocal, bool &gateOut);
|
||||
void loadTxFsmFromMembers(TxFsmState &st) const;
|
||||
void storeTxFsmToMembers(const TxFsmState &st);
|
||||
|
||||
IrTxBsrrWave txBsrrWave_{};
|
||||
IR_TxGateRun txGateRuns_[irproto::kIsrTxMaxGateRuns]{};
|
||||
uint32_t txBsrrWords_[irproto::kIsrTxBsrrWordCount]{};
|
||||
uint16_t txBsrrReadIdx_ = 0;
|
||||
uint16_t txBsrrHalfLen_ = 0;
|
||||
uint32_t txBsrrTotalTicks_ = 0;
|
||||
uint32_t txBsrrTicksSent_ = 0;
|
||||
|
||||
/** Снимок на старт TX (буферный и legacy путь). */
|
||||
uint16_t txPowerSnap_ = 1;
|
||||
uint16_t txMultiplySnap_ = 2;
|
||||
|
||||
/** Legacy: физических тиков на один логический шаг FSM = multiply/2. */
|
||||
uint16_t legacyPhysPerLogical_ = 1;
|
||||
uint16_t legacyPhysCounter_ = 0;
|
||||
uint16_t legacySlotInPeriod_ = 0;
|
||||
|
||||
volatile uint16_t powerNumerator_ = 1;
|
||||
|
||||
IR_DecoderRaw *decPair = nullptr;
|
||||
IR_DecoderRaw *singleBlindDecoder = nullptr;
|
||||
IR_DecoderRaw **blindDecoders = nullptr;
|
||||
uint8_t decodersCount = 0;
|
||||
|
||||
uint8_t sendLen = 0;
|
||||
uint8_t sendBuffer[dataByteSizeMax]{0}; /// @brief Буффер данных для отправки
|
||||
|
||||
volatile bool isSending;
|
||||
volatile bool state; /// @brief Текущий уровень генерации
|
||||
volatile bool isSending = false;
|
||||
volatile bool state = LOW; /// @brief Текущий уровень генерации
|
||||
|
||||
volatile uint8_t dataByteCounter;
|
||||
volatile uint8_t dataByteCounter = 0;
|
||||
|
||||
volatile uint8_t toggleCounter; /// @brief Счётчик переключений
|
||||
volatile uint8_t dataBitCounter;
|
||||
volatile uint8_t toggleCounter = 0; /// @brief Счётчик переключений
|
||||
volatile uint8_t dataBitCounter = 0;
|
||||
|
||||
volatile uint8_t preambFrontCounter;
|
||||
volatile uint8_t dataSequenceCounter;
|
||||
volatile uint8_t syncSequenceCounter;
|
||||
volatile bool syncLastBit;
|
||||
volatile uint8_t preambFrontCounter = 0;
|
||||
volatile uint8_t dataSequenceCounter = 0;
|
||||
volatile uint8_t syncSequenceCounter = 0;
|
||||
volatile bool syncLastBit = false;
|
||||
|
||||
struct BitSequence
|
||||
{
|
||||
@ -144,5 +224,5 @@ private:
|
||||
static uint8_t bitHigh[2];
|
||||
static uint8_t bitLow[2];
|
||||
uint8_t *currentBitSequence = bitLow;
|
||||
volatile SignalPart signal;
|
||||
volatile SignalPart signal = noSignal;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user