# Режимы IR TX в библиотеке

Этот документ описывает, как в библиотеке выбирается путь передачи IR и как его правильно использовать в проектах Arduino STM32.

## Кратко

У библиотеки есть три варианта TX:

- `legacy ISR` — внутренний ISR-путь без внешнего backend. Это путь по умолчанию для обратной совместимости.
- `buffered ISR` — внутренний ISR-путь с предварительной подготовкой BSRR-слов и кольцевым буфером.
- `external backend` — передача делегируется проекту через `IR_Encoder::setExternalTxBackend(...)`, например в DMA backend.

Порядок выбора такой:

1. Если зарегистрирован `external backend`, используется он.
2. Иначе используется внутренний ISR библиотеки.
3. Для внутреннего ISR:
   - по умолчанию включён `legacy ISR`
   - `buffered ISR` включается явно: нужно привязать storage к encoder и переключить режим

## 1. Legacy ISR

Это режим по умолчанию. Старые проекты могут ничего не менять:

```cpp
static HardwareTimer timer(TIM11);
static IR_Encoder enc(PA9, 42, &dec);

void setup() {
    IR_Encoder::begin(&timer, 1, TIM11_IRQn, 0);
    enc.enable();
}
```

Если проект не регистрирует внешний backend и не переключает режим явно, библиотека работает в `legacy ISR`.

Для явного выбора можно написать:

```cpp
IR_Encoder::setTxIsrLegacyMode(true);
IR_Encoder::begin(&timer, 1, TIM11_IRQn, 0);
```

## 2. Buffered ISR

Этот режим использует внутренний буферный ISR-путь библиотеки. Он включается только явно:

```cpp
#include <IrTxIsrBufferedStorage.h>

static IrTxIsrBufferedStorage<> txStorage;

enc.enableBufferedIsr(txStorage);
IR_Encoder::begin(&timer, 1, TIM11_IRQn, 0);
```

Нижнеуровневый вариант API — отдельно привязать storage через `attachBufferedIsrStorage(...)`, но в обычном проекте удобнее использовать `enableBufferedIsr(...)`.

Смысл режима:

- пакет сначала превращается в `gate runs`
- затем в поток слов `GPIO->BSRR`
- ISR выдаёт готовые слова из кольцевого буфера

### Важно про RAM

В текущей реализации память под буферный ISR вынесена из `IR_Encoder` в отдельный storage-объект.

То есть:

- `legacy ISR` не тянет buffered-буферы в RAM самого `IR_Encoder`
- память под `gate runs` и `BSRR words` появляется только там, где проект сам создал `IrTxIsrBufferedStorage<>`

Это важно для STM32 с небольшим объёмом RAM, например для `STM32F401`.

## 3. External backend

Если проект хочет полностью взять TX на себя, библиотека позволяет зарегистрировать внешний backend:

```cpp
static bool txBusy(void* ctx);
static bool txStart(void* ctx, IR_Encoder* enc, const uint8_t* packet, uint8_t len);

void setup() {
    IR_Encoder::beginClockOnly(&timer);
    IR_Encoder::setExternalTxBackend(txStart, txBusy, nullptr);
    enc.enable();
}
```

После вызова `setExternalTxBackend(...)` библиотека больше не использует свои внутренние ISR-пути для фактической передачи.

В этом режиме:

- `setTxIsrLegacyMode(true/false)` игнорируется
- завершение передачи должен сигнализировать сам backend через `enc->externalFinishSend()`

Подробности по встроенному DMA backend для `STM32G4xx`: см. [IR_DMA_TX_backend.md](IR_DMA_TX_backend.md).

## Когда какой режим использовать

### Старый проект, который ничего не настраивает

Использовать как есть:

```cpp
IR_Encoder::begin(...);
```

Итог: `legacy ISR`

### Нужен новый внутренний буферный ISR

Включить явно:

```cpp
#include <IrTxIsrBufferedStorage.h>

static IrTxIsrBufferedStorage<> txStorage;

enc.enableBufferedIsr(txStorage);
IR_Encoder::begin(...);
```

Итог: `buffered ISR`

### Нужен проектный DMA или другой свой транспорт

Подключить внешний backend:

```cpp
IR_Encoder::beginClockOnly(...);
IR_Encoder::setExternalTxBackend(...);
```

Итог: `external backend`

## Рекомендация для совместимости

Для старых проектов безопаснее не вызывать `setTxIsrLegacyMode(false)`, если нет явной причины переходить на buffered ISR.

Если задача — сохранить старое поведение без неожиданного роста нагрузки на TX-логику, оставляйте default `legacy ISR` или задавайте его явно:

```cpp
IR_Encoder::setTxIsrLegacyMode(true);
```
