diff --git a/.vscode/arduino.json b/.vscode/arduino.json index 3d8ebd7..dbd298b 100644 --- a/.vscode/arduino.json +++ b/.vscode/arduino.json @@ -1,5 +1,5 @@ { - "board": "STMicroelectronics:stm32:GenF4", + "board": "STMicroelectronics:stm32:GenG4", "port": "COM17", "prebuild": "if exist bin rd /s /q bin" } \ No newline at end of file diff --git a/IR_DecoderRaw.h b/IR_DecoderRaw.h index e634e23..08374a4 100644 --- a/IR_DecoderRaw.h +++ b/IR_DecoderRaw.h @@ -187,8 +187,8 @@ bool isReciveRaw; //////////////////////////////////////////////////////////////////////// bool isData = true; // Флаг относится ли бит к данным, или битам синхронизации - uint16_t i_dataBuffer; // Счётчик буфера данных - uint8_t nextControlBit = bitPerByte; // Метка для смены флага isData + uint16_t i_dataBuffer; // Счётчик буфера данных + uint16_t nextControlBit = bitPerByte; // Метка для смены флага isData; uint16_t нужен для длинных кадров (>24 байт total) uint8_t i_syncBit; // Счётчик битов синхронизации uint8_t err_syncBit; // Счётчик ошибок синхронизации diff --git a/test_examples/longData/longData.ino b/test_examples/longData/longData.ino new file mode 100644 index 0000000..370e3c3 --- /dev/null +++ b/test_examples/longData/longData.ino @@ -0,0 +1,150 @@ +/* + * Тест длинной полезной нагрузки IR (0x5E + строка, как ответ версии в Car). + * Передача через DMA + TIM17 — как в машинке (Car/src/IR/IR.cpp, BoardTest/IR_DMA). + * Авто-режим: чередование total длины кадра 24/25 байт. + */ +#include "IR_Decoder.h" +#include "IR_Encoder.h" +#include "TimerStatic.h" + +/** 1 — TX через DMA (STM32G4). */ +#ifndef LONGDATA_USE_DMA +#define LONGDATA_USE_DMA 0 +#endif + +#if LONGDATA_USE_DMA +#include +#endif + +static constexpr uint16_t kIrDeviceAddr = 0; +static constexpr uint8_t kCmdVersion = 0x5E; +static constexpr uint32_t kSerialBaud = 115200; +static constexpr uint32_t kSendPeriodMs = 500; +static constexpr uint8_t kMaxPayload = bytePerPack; +static constexpr uint8_t kMaxParamBytes = kMaxPayload - 1; + +static IR_Encoder enc(PIN_IR_ENC_FORWARD, kIrDeviceAddr, nullptr); +static HardwareTimer irTimer(TIM17); + +#if LONGDATA_USE_DMA +namespace { +constexpr size_t kIrDmaStreams = 1; +constexpr uint16_t kIrDmaTxWordCount = 4096U; +constexpr size_t kIrDmaTxMaxGateRuns = 1024U; +static uint32_t s_irDmaWords[kIrDmaTxWordCount]; +static IR_Encoder::IR_TxGateRun s_irGateRuns[kIrDmaTxMaxGateRuns]; +} // namespace + +static IrDmaTxStm32 dmaBackend; +static bool txBusy(void * /*ctx*/) { return dmaBackend.busy(); } +static bool txStart(void * /*ctx*/, IR_Encoder *e, const uint8_t *packet, uint8_t len) { + return dmaBackend.start(e, packet, len); +} +#endif + +static char s_paramAscii[kMaxParamBytes + 1]; +static uint8_t s_irPayload[kMaxPayload]; +static uint8_t s_irPayloadLen = 0; +static uint32_t s_lastSendMs = 0; +static bool s_sendLongerFrame = false; + +// 24 байта total: msg(1)+addr(2)+addr(2)+data(17)+crc(2), где data=0x5E + 16 ASCII. +static const char kPayload16[] = "Car_v4.3.9_[12MH"; +// 25 байт total: как выше, но data=0x5E + 17 ASCII. +static const char kPayload17[] = "Car_v4.3.9_[12MHz]_G491"; + +static void rebuildIrPayload() { + s_irPayload[0] = kCmdVersion; + size_t n = 0; + while (n < sizeof(s_paramAscii) && s_paramAscii[n]) { + ++n; + } + const size_t copyLen = (n > kMaxParamBytes) ? kMaxParamBytes : n; + memcpy(s_irPayload + 1, s_paramAscii, copyLen); + s_irPayloadLen = static_cast(1 + copyLen); +} + +static void setAlternatingPayload() { + const char* src = s_sendLongerFrame ? kPayload17 : kPayload16; + strncpy(s_paramAscii, src, kMaxParamBytes); + s_paramAscii[kMaxParamBytes] = '\0'; + s_sendLongerFrame = !s_sendLongerFrame; +} + +static void sendVersionPacket() { + rebuildIrPayload(); + const IR_SendResult r = enc.sendData(IR_Broadcast, s_irPayload, s_irPayloadLen); + Serial.print(F("TX 0x5E + ")); + Serial.print((unsigned)(s_irPayloadLen - 1)); + Serial.print(F(" B, ok=")); + Serial.print(r.success ? F("1") : F("0")); + Serial.print(F(", t=")); + Serial.print(r.sendTimeMs); + Serial.println(F(" ms")); +} + +void setup() { + Serial.begin(kSerialBaud); + + strncpy(s_paramAscii, kPayload16, kMaxParamBytes); + s_paramAscii[kMaxParamBytes] = '\0'; + rebuildIrPayload(); + + #if LONGDATA_USE_DMA + IR_Encoder::beginClockOnly(&irTimer); + + IrDmaTxStm32::Config cfg; + cfg.timer = &irTimer; + cfg.streamCount = kIrDmaStreams; + cfg.streams[0].instance = DMA1_Channel1; + cfg.streams[0].irq = DMA1_Channel1_IRQn; + cfg.streams[0].dmamuxRequest = DMA_REQUEST_TIM17_UP; + cfg.streams[0].enc = &enc; + cfg.streams[0].dmaWords = s_irDmaWords; + cfg.streams[0].dmaWordCount = kIrDmaTxWordCount; + cfg.streams[0].gateRuns = s_irGateRuns; + cfg.streams[0].maxGateRuns = kIrDmaTxMaxGateRuns; + + if (!dmaBackend.begin(cfg)) { + Serial.println(F("[IR_DMA] init FAILED")); + return; + } + IR_Encoder::setExternalTxBackend(txStart, txBusy, nullptr); + #elif LONGDATA_LEGACY_ISR + IR_Encoder::begin(&irTimer, 1, TIM17_IRQn, 0); + #else + IR_Encoder::begin(&irTimer, 1, TIM17_IRQn, 0); + #endif + enc.enable(); + + #if LONGDATA_USE_DMA + Serial.println(F("longData: DMA TX alternating 24/25 bytes")); + #elif LONGDATA_LEGACY_ISR + Serial.println(F("longData: legacy ISR TX (pre-unified FSM) 24/25 bytes")); + #else + Serial.println(F("longData: ISR TX (unified FSM) alternating 24/25 bytes")); + #endif + Serial.print(F("Auto-period ms = ")); + Serial.println((unsigned long)kSendPeriodMs); +} + +void loop() { + #if LONGDATA_USE_DMA + IR_Encoder::tick(); + #endif + + const uint32_t now = millis(); + if (now - s_lastSendMs >= kSendPeriodMs) { + s_lastSendMs = now; + setAlternatingPayload(); + sendVersionPacket(); + } +} + +#if LONGDATA_USE_DMA && defined(STM32G4xx) +extern "C" void DMA1_Channel1_IRQHandler(void) { + if (auto *p = IrDmaTxStm32::instance()) { + p->irqForStream(0); + } +} +#endif