Files
IR-protocol/IR_config.h
2026-04-20 17:47:33 +03:00

310 lines
20 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#pragma once
#include <Arduino.h>
#include <list>
// #define IRDEBUG_INFO
/** Число потоков DMA-TX задаётся шаблоном: IrDmaTxStm32<2>, см. IrDmaTxStm32.h и irproto::kDefaultDmaTxMaxStreams. */
namespace irproto {
constexpr size_t kDefaultDmaTxMaxStreams = 4U;
/** Кольцевой буфер BSRR-слов для ISR-TX (как у DMA: два полублока). Чётное число. */
constexpr uint16_t kIsrTxBsrrWordCount = 256U;
/** Максимум RLE-сегментов для buildGateRuns при ISR-TX. */
constexpr size_t kIsrTxMaxGateRuns = 512U;
static_assert((kIsrTxBsrrWordCount & 1U) == 0U, "kIsrTxBsrrWordCount must be even");
}
// Пошаговый разбор кадра на Serial (по умолчанию выключено). Пульсы IRDEBUG на пинах не меняют.
// #define IRDEBUG_SERIAL_PACK
// Не обрывать приём сразу при накопленной sync-ошибке — «дописывать» до таймаута (только вместе с IRDEBUG_SERIAL_PACK).
// #define IRDEBUG_SERIAL_SOFT_REJECT
// Краткий лог причин, почему физический сигнал не дошёл до распознанного пакета.
// Формат и коды: ref/IR_RX_BRIEF_LOG.md
#ifndef IR_RX_BRIEF_LOG
#define IR_RX_BRIEF_LOG 0
#endif
// 1: печатать только отклонённые/ошибочные события; успехи и шумовые PREAMB скрыть.
#ifndef IR_RX_BRIEF_LOG_REJECT_ONLY
#define IR_RX_BRIEF_LOG_REJECT_ONLY 1
#endif
// Журнал фронтов ИК в ISR; сброс строк @IRF1v1: в IR_DecoderRaw::tick(). См. ref/IR_EDGE_TRACE_FORMAT.md
// Расход RAM ≈ IR_EDGE_TRACE_CAPACITY * 6 байт на декодер. Выключить — закомментировать:
// #define IR_EDGE_TRACE
#if defined(IR_EDGE_TRACE)
#ifndef IR_EDGE_TRACE_CAPACITY
#define IR_EDGE_TRACE_CAPACITY 512u
#endif
/** Запись в edgeTrace: фронт не передан в decode (isPairSending). */
#define IR_EDGE_TRACE_F_SKIP_DECODE 0x01u
#endif
// Пример в скетче: void irPackTracePrintOkCommand(const uint8_t* b, uint8_t n) { Serial.print(F("CarCmd::...")); }
#if defined(IRDEBUG_SERIAL_PACK)
/** Слабая реализация в IR_DecoderRaw.cpp; в скетче определите свою для вывода вроде CarCmd::... */
void irPackTracePrintOkCommand(const uint8_t *buf, uint8_t packSize);
#endif
/*//////////////////////////////////////////////////////////////////////////////////////
Для работы в паре положить декодер в энкодер
*/
// Адресация с 1 до 65 499
#define IR_Broadcast 65000 // 65 500 ~ 65 535 - широковещательные пакеты (всем)
/*
*Адресное пространство:
Адрес 0 запрещен и зарезервирован под NULL, либо тесты
IR_MSG_ACCEPT с адреса 0 воспринимается всеми устройствами
*/
//**** Контрольные точки ******
#define IR_MAX_ADDR_CPU 63999
#define IR_MIN_ADDR_CPU 32000
// //***** Группы машинок ********
// #define IR_MAX_CAR_GROUP 31999
// #define IR_MIN_CAR_GROUP 30000
// //********** FREE *************
// #define IR_MAX_FREE 31999
// #define IR_MIN_FREE 2000
//********* Машинки ***********
#define IR_MAX_CAR 31999
#define IR_MIN_CAR 1
//***** Пульты управления *****
#define IR_MAX_CONTROLLER 64999
#define IR_MIN_CONTROLLER 64000
/*
/```````````````````````````````````````````````` data pack `````````````````````````````````````````````\                                  
                                                                                                         
{``````````} [````````````````````````] [````````````````````] [````````````````````````] [``````````````]
{ msg type } [ addr_from uint16_t ] [ addr_to uint16_t ] [====== data bytes ======] [ CRC Bytes ]
{..........} [........................] [....................] [........................] [..............]
                                                                                                          
{ aka size } [addr_from_H][addr_from_L] [addr_to_H][addr_to_L] [data_H][data_n..][data_L] [ crc1 ][ crc2 ]
|     0           1            2              3         4          5                         |       |    
\____________________________________________________________________________________________/       |    
|                                                                                                    |    
\____________________________________________________________________________________________________/    
msg type:
                                //  __________
                                // | 01234567 |
                                //  ----------
                                // | xxx..... | = тип сообщения (биты 7..5)
                                // | ...xxxxx | = полная длина кадра в байтах (5 бит, 0..31, IR_MASK_MSG_INFO), не «31 бит» и не отдельный лимит «24 байта»
                                // Полезная нагрузка в data pack: до bytePerPack байт (см. #define bytePerPack).
                                //  ---------- */
#define IR_MSG_BACK 0U // | 000...... | = Задний сигнал машинки
#define IR_MSG_ACCEPT 1U // | 001..... | = подтверждение
#define IR_MSG_REQUEST 2U // | 010..... | = запрос
// #define IR_MSG_ 3U // | 011..... | = ??
#define IR_MSG_BACK_TO 4U // | 100..... | = Задний сигнал машинки c адресацией
// #define IR_MSG_ 5U // | 101..... | = ??
#define IR_MSG_DATA_NOACCEPT 6U // | 110..... | = данные, не требующие подтверждения
#define IR_MSG_DATA_ACCEPT 7U // | 111..... | = данные требующие подтверждения
; /*   // ----------
/``````````````````````````````` подтверждение `````````````````````````````\      /``````````````````````````````````````` запрос ``````````````````````````````````\
                                                                                                                      
{``````````} [````````````````````````] [``````````````````] [``````````````]      {``````````} [````````````````````````] [````````````````````````] [``````````````]
{ msg type } [ addr_from uint16_t ] [=== customByte ===] [ CRC Bytes ]      { msg type } [ addr_from uint16_t ] [ addr_to uint16_t ] [ CRC Bytes ]
{..........} [........................] [..................] [..............]      {..........} [........................] [........................] [..............]
                                                                                                                                                            
{ 001..... } [addr_from_H][addr_from_L] [=== customByte ===] [ crc1 ][ crc2 ]      { 010..... } [addr_from_H][addr_from_L] [addr_from_H][addr_from_L] [ crc1 ][ crc2 ]
|     0            1           2                  3              4       5          |     0            1           2              3           4           5       6    
\________________________________________________________________/       |          \_____________________________________________________________________/       |    
|                                                                        |          |                                                                             |    
\________________________________________________________________________/          \_____________________________________________________________________________/    
customByte - контрольная сумма принятых данных по poly1
/`````````````````````` Задний сигнал машинки без адресации ``````````````````````\        
// Первый байт: (IR_MSG_BACK<<5) | (packSize & IR_MASK_MSG_INFO) — как у data pack (тип + длина 0..31).
                                                                                           
{``````````} [````````````````````````] [````````````````````````] [``````````````]        
{ msg type } [ addr_from uint16_t ] [====== data bytes ======] [ CRC Bytes ]        
{..........} [........................] [........................] [..............]        
                                                                                           
{ xxx..|..xxxxx } [addr_from_H][addr_from_L] [data_H][data_n..][data_L] [ crc1 ][ crc2 ]        
|     0           1            2            3                         |       |            
\_____________________________________________________________________/       |            
|                                                                             |            
\_____________________________________________________________________________/            
/```````````````````````````````````` Задний сигнал машинки с адресацией ````````````````````````````````````\ 
// Первый байт: (IR_MSG_BACK_TO<<5) | (packSize & IR_MASK_MSG_INFO) — IR_MSG_BACK_TO в битах 7..5, длина 0..31.
                                                                                          
{``````````} [````````````````````````] [````````````````````````] [````````````````````````] [``````````````] 
{ msg type } [ addr_from uint16_t ] [ addr_to uint16_t ] [====== data bytes ======] [ CRC Bytes ] 
{..........} [........................] [........................] [........................] [..............] 
                                                                                                                
{ xxx..|..xxxxx } [addr_from_H][addr_from_L] [addr_to_H][addr_to_L] [data_H][data_n..][data_L] [ crc1 ][ crc2 ] 
|     0           1            2              3           4            5                         |       |     
\________________________________________________________________________________________________/       |     
|                                                                                                        |     
\________________________________________________________________________________________________________/     
*/
#define IR_MASK_MSG_TYPE 0b00000111
#define IR_MASK_MSG_INFO 0b00011111
/*
/////////////////////////////////////////////////////////////////////////////////////*/
typedef uint16_t crc_t;
// #define BRUTEFORCE_CHECK // Перепроверяет пакет на 1 битные ошибки //TODO: зависает
#define bytePerPack (31) // колличество байтов в пакете
#ifndef freeFrec
#define freeFrec false
#endif
#ifndef subBufferSize
#define subBufferSize 250 // Буфер для складирования фронтов, пока их не обработают (передатчик)
#endif
/** Максимальное число передатчиков, способных временно заглушить один декодер. */
#ifndef IR_PAIR_MUTE_MAX_ENCODERS
#define IR_PAIR_MUTE_MAX_ENCODERS 8U
#endif
/** Минимальная длительность удержания уровня (мкс): короче — импульс/пара фронтов выкидывается до tick()
* (иголки на плато, дребезг). 0 — фильтр выключен, фронты идут в декодер как с ISR. */
#ifndef IR_INPUT_MIN_PULSE_US
#define IR_INPUT_MIN_PULSE_US 0
#endif
/** Сколько подтверждённых фронтов держать перед выпуском в декодер (потоковая задержка). */
#ifndef IR_INPUT_FILTER_HOLDBACK_EDGES
#define IR_INPUT_FILTER_HOLDBACK_EDGES 3U
#endif
/** Если новых фронтов нет, через minPulse*mult держатель принудительно сбрасывается в декодер. */
#ifndef IR_INPUT_FILTER_TIMEOUT_MULT
#define IR_INPUT_FILTER_TIMEOUT_MULT 5U
#endif
/** Синхронно с IrFoxProtocolConstants.h / IrFoxDecoder (плагин Saleae). */
#ifndef IR_SHORT_LOW_GLITCH_REJECT
#define IR_SHORT_LOW_GLITCH_REJECT 1
#endif
#ifndef IR_GLITCH_REJECT_PHASE_NUDGE
#define IR_GLITCH_REJECT_PHASE_NUDGE 1
#endif
#ifndef IR_MICRO_GAP_RISE_REJECT
#define IR_MICRO_GAP_RISE_REJECT 1
#endif
/** Лок преамбулы: сколько одинаковых подряд периодов подъёма нужно для старта кадра. */
#ifndef IR_PREAMBLE_LOCK_RISE_PERIODS
#define IR_PREAMBLE_LOCK_RISE_PERIODS 2U
#endif
/** Допуск одинаковости периода преамбулы (проценты) + минимальная абсолютная полка в мкс. */
#ifndef IR_PREAMBLE_JITTER_PCT
#define IR_PREAMBLE_JITTER_PCT 18U
#endif
#ifndef IR_PREAMBLE_JITTER_US_MIN
#define IR_PREAMBLE_JITTER_US_MIN 80U
#endif
/** Грубое окно валидности периода преамбулы RISE->RISE (в процентах от bitTime).
* Для текущего протокола преамбула заметно длиннее обычного битового периода. */
#ifndef IR_PREAMBLE_PERIOD_MIN_FACTOR_PCT
#define IR_PREAMBLE_PERIOD_MIN_FACTOR_PCT 220U
#endif
#ifndef IR_PREAMBLE_PERIOD_MAX_FACTOR_PCT
#define IR_PREAMBLE_PERIOD_MAX_FACTOR_PCT 340U
#endif
/** Таймаут окна кандидата преамбулы: IR_timeout * mult. */
#ifndef IR_PREAMBLE_CANDIDATE_TIMEOUT_MULT
#define IR_PREAMBLE_CANDIDATE_TIMEOUT_MULT 3U
#endif
#define preambPulse 3
/////////////////////////////////////////////////////////////////////////////////////
#define bitPerByte 8U // Колличество бит в байте
#define addrBytes 2
#define msgBytes 1
#define crcBytes 2
#define poly1 0x31
#define poly2 0x8C
#define syncBits 3U // количество битов синхронизации
#define dataByteSizeMax (msgBytes + addrBytes + addrBytes + bytePerPack + crcBytes)
#define preambFronts (preambPulse * 2) // количество фронтов преамбулы (Приём)
#define preambToggle ((bitPauseTakts * 2 + bitActiveTakts) * 2 - 1) // колличество переключений преамбулы (Передача)
#define carrierFrec 38000U // частота несущей (Приём/Передача)
#define carrierPeriod (1000000U / carrierFrec) // период несущей в us (Приём)
// В процессе работы значения будут отклонятся в соответствии с предыдущим битом
#define bitActiveTakts 25U // длительность высокого уровня в тактах
#define bitPauseTakts 12U // длительность низкого уровня в тактах
#define bitTakts (bitActiveTakts + bitPauseTakts) // Общая длительность бита в тактах
#define bitTime (bitTakts * carrierPeriod) // Общая длительность бита
#define tolerance 300U
constexpr uint16_t test_all_Time = bitTime;
constexpr uint16_t test_all_Takts = bitTakts * 2;
constexpr uint16_t test_hi = ((bitPauseTakts) * 2 - 0) + ((bitActiveTakts) * 2 - 0);
constexpr uint16_t test_low = ((bitPauseTakts / 2 + bitActiveTakts) * 2 - 0) + ((bitPauseTakts)-0);
class IR_FOX
{
public:
struct PackOffsets
{
uint8_t msgOffset;
uint8_t addrFromOffset;
uint8_t addrToOffset;
uint8_t dataOffset;
uint8_t crcOffset;
};
struct ErrorsStruct
{
uint8_t lowSignal = 0;
uint8_t highSignal = 0;
uint8_t other = 0;
void reset()
{
lowSignal = 0;
highSignal = 0;
other = 0;
}
uint16_t all() { return lowSignal + highSignal + other; }
};
struct PackInfo
{
uint8_t *buffer = nullptr;
uint8_t packSize = 0;
uint16_t crc = 0;
ErrorsStruct err;
uint16_t rTime = 0;
};
inline uint16_t getId() const { return id; }
inline void setId(uint16_t id) { this->id = id; }
static void checkAddressRuleApply(uint16_t address, uint16_t id, bool &flag);
void setPin(uint8_t pin);
inline uint8_t getPin() { return pin; };
inline GPIO_TypeDef *getPort() const { return port; }
inline uint16_t getPinMask() const { return mask; }
protected:
uint16_t id;
uint8_t pin;
GPIO_TypeDef *port;
uint16_t mask;
ErrorsStruct errors;
uint8_t crc8(uint8_t *data, uint8_t start, uint8_t end, uint8_t poly);
};