/* * Тест длинной полезной нагрузки 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::setCarrierMultiply(N); // до beginClockOnly; после смены — retuneCarrierClock() 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