From 45f4bf20417f2e69dc28763a8113bd6a244f3c7e Mon Sep 17 00:00:00 2001 From: Asbelos Date: Sat, 31 Aug 2024 11:27:27 +0100 Subject: [PATCH] Railcom sample window --- DCCWaveform.cpp | 29 ++++++++++++++++++++++------- DCCWaveform.h | 12 +++++++++--- IO_I2CRailcom.h | 9 +++++---- TrackManager.cpp | 6 +++++- 4 files changed, 41 insertions(+), 15 deletions(-) diff --git a/DCCWaveform.cpp b/DCCWaveform.cpp index 3d77e9e..3122610 100644 --- a/DCCWaveform.cpp +++ b/DCCWaveform.cpp @@ -116,18 +116,20 @@ DCCWaveform::DCCWaveform( byte preambleBits, bool isMain) { bits_sent = 0; } +bool DCCWaveform::railcomPossible=false; // High accuracy only volatile bool DCCWaveform::railcomActive=false; // switched on by user +volatile bool DCCWaveform::railcomSampleWindow=false; // true during packet transmit volatile bool DCCWaveform::railcomDebug=false; // switched on by user bool DCCWaveform::setRailcom(bool on, bool debug) { - if (on) { - // TODO check possible + if (on && railcomPossible) { railcomActive=true; railcomDebug=debug; } else { railcomActive=false; railcomDebug=false; + railcomSampleWindow=false; } return railcomActive; } @@ -147,7 +149,17 @@ void DCCWaveform::interrupt2() { // that the reminder doesn't block a more urgent packet. reminderWindowOpen=transmitRepeats==0 && remainingPreambles<4 && remainingPreambles>1; if (remainingPreambles==1) promotePendingPacket(); - else if (remainingPreambles==10 && isMainTrack && railcomActive) DCCTimer::ackRailcomTimer(); + else if (isMainTrack && railcomActive) { + if (remainingPreambles==10) { + // cutout has started so the railcom timer needs to end the cutout at next + // cutout timer tick. + DCCTimer::ackRailcomTimer(); + } + else if (remainingPreambles==5) { + // cutout has ended so its now possible to poll the railcom detectors + railcomSampleWindow=true; + } + } // Update free memory diagnostic as we don't have anything else to do this time. // Allow for checkAck and its called functions using 22 bytes more. else DCCTimer::updateMinimumFreeMemoryISR(22); @@ -172,11 +184,14 @@ void DCCWaveform::interrupt2() { // preamble for next packet will start... remainingPreambles = requiredPreambles; - // set the railcom coundown to trigger half way + // Set the railcom coundown to trigger half way // through the first preamble bit. // Note.. we are still sending the last packet bit - // and we then have to allow for the packet end bit - if (isMainTrack && railcomActive) DCCTimer::startRailcomTimer(9); + // but the timer code allows for this + if (isMainTrack && railcomActive) { + railcomSampleWindow=false; // about to cutout, stop reading railcom data. + DCCTimer::startRailcomTimer(9); + } } } } @@ -230,7 +245,7 @@ void DCCWaveform::promotePendingPacket() { // Fortunately reset and idle packets are the same length // Note: If railcomDebug is on, then we send resets to the main // track instead of idles. This means that all data will be zeros - // and only the porersets will be ones, making it much + // and only the presets will be ones, making it much // easier to read on a logic analyser. memcpy( transmitPacket, (isMainTrack && (!railcomDebug)) ? idlePacket : resetPacket, sizeof(idlePacket)); transmitLength = sizeof(idlePacket); diff --git a/DCCWaveform.h b/DCCWaveform.h index a3e20da..40f55f2 100644 --- a/DCCWaveform.h +++ b/DCCWaveform.h @@ -85,8 +85,13 @@ class DCCWaveform { void schedulePacket(const byte buffer[], byte byteCount, byte repeats); bool isReminderWindowOpen(); void promotePendingPacket(); + static void setRailcomPossible(bool yes) { + railcomPossible=yes; + if (!yes) setRailcom(false,false); + } static bool setRailcom(bool on, bool debug); static bool isRailcom() {return railcomActive;} + static bool isRailcomSampleWindow() {return railcomSampleWindow;} private: #ifndef ARDUINO_ARCH_ESP32 @@ -112,9 +117,10 @@ class DCCWaveform { byte pendingPacket[MAX_PACKET_SIZE+1]; // +1 for checksum byte pendingLength; byte pendingRepeats; - static volatile bool railcomActive; // switched on by user - static volatile bool railcomDebug; // switched on by user - + static bool railcomPossible; // High accuracy mode only + static volatile bool railcomActive; // switched on by user + static volatile bool railcomDebug; // switched on by user + static volatile bool railcomSampleWindow; // when safe to sample #ifdef ARDUINO_ARCH_ESP32 static RMTChannel *rmtMainChannel; static RMTChannel *rmtProgChannel; diff --git a/IO_I2CRailcom.h b/IO_I2CRailcom.h index 2f59ed0..00ad625 100644 --- a/IO_I2CRailcom.h +++ b/IO_I2CRailcom.h @@ -47,11 +47,11 @@ #include "IODevice.h" #include "I2CManager.h" #include "DIAG.h" +#include "DCCWaveform.h" // Debug and diagnostic defines, enable too many will result in slowing the driver #define DIAG_I2CRailcom #define DIAG_I2CRailcom_data -#define DIAG_I2CRailcom_reg class I2CRailcom : public IODevice { private: @@ -62,7 +62,7 @@ private: const uint8_t STOP_BIT = 0x00; // Value LCR bit 2 const uint8_t PARITY_ENA = 0x00; // Value LCR bit 3 const uint8_t PARITY_TYPE = 0x00; // Value LCR bit 4 - const uint32_t BAUD_RATE = 9600; + const uint32_t BAUD_RATE = 250000; const uint8_t PRESCALER = 0x01; // Value MCR bit 7 const unsigned long SC16IS752_XTAL_FREQ_RAILCOM = 16000000; // Baud rate for Railcom signal byte _inbuf[65]; @@ -106,8 +106,9 @@ public: // Read responses from device if (_deviceState!=DEVSTATE_NORMAL) return; - // TODO - return if in cutout or cutout very soon. - + // return if in cutout or cutout very soon. + if (!DCCWaveform::isRailcomSampleWindow()) return; + // flip channels each loop if (_nPins>1) _UART_CH=_UART_CH?0:1; diff --git a/TrackManager.cpp b/TrackManager.cpp index af3be71..6d5fa6f 100644 --- a/TrackManager.cpp +++ b/TrackManager.cpp @@ -338,13 +338,17 @@ bool TrackManager::setTrackMode(byte trackToSet, TRACK_MODE mode, int16_t dcAddr // if we discover that HA mode was globally impossible // we must adjust the trackPWM capabilities DIAG(F("High Accuracy & Railcom disabled")); + DCCWaveform::setRailcomPossible(false); FOR_EACH_TRACK(t) { track[t]->trackPWM=false; //DIAG(F("Track %c trackPWM 0 (global override)"), t+'A'); } DCCTimer::clearPWM(); // has to be AFTER trackPWM changes because if trackPWM==true this is undone for that track } - else DIAG(F("High Accuracy Enabled")); + else { + DIAG(F("High Accuracy Enabled")); + DCCWaveform::setRailcomPossible(true); + } #else // For ESP32 we just reinitialize the DCC Waveform DCCWaveform::begin();