1
0
mirror of https://github.com/DCC-EX/CommandStation-EX.git synced 2024-11-23 08:06:13 +01:00

Railcom sample window

This commit is contained in:
Asbelos 2024-08-31 11:27:27 +01:00
parent 9f1cdfcda6
commit 45f4bf2041
4 changed files with 41 additions and 15 deletions

View File

@ -116,18 +116,20 @@ DCCWaveform::DCCWaveform( byte preambleBits, bool isMain) {
bits_sent = 0; bits_sent = 0;
} }
bool DCCWaveform::railcomPossible=false; // High accuracy only
volatile bool DCCWaveform::railcomActive=false; // switched on by user 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 volatile bool DCCWaveform::railcomDebug=false; // switched on by user
bool DCCWaveform::setRailcom(bool on, bool debug) { bool DCCWaveform::setRailcom(bool on, bool debug) {
if (on) { if (on && railcomPossible) {
// TODO check possible
railcomActive=true; railcomActive=true;
railcomDebug=debug; railcomDebug=debug;
} }
else { else {
railcomActive=false; railcomActive=false;
railcomDebug=false; railcomDebug=false;
railcomSampleWindow=false;
} }
return railcomActive; return railcomActive;
} }
@ -147,7 +149,17 @@ void DCCWaveform::interrupt2() {
// that the reminder doesn't block a more urgent packet. // that the reminder doesn't block a more urgent packet.
reminderWindowOpen=transmitRepeats==0 && remainingPreambles<4 && remainingPreambles>1; reminderWindowOpen=transmitRepeats==0 && remainingPreambles<4 && remainingPreambles>1;
if (remainingPreambles==1) promotePendingPacket(); 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. // 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. // Allow for checkAck and its called functions using 22 bytes more.
else DCCTimer::updateMinimumFreeMemoryISR(22); else DCCTimer::updateMinimumFreeMemoryISR(22);
@ -172,11 +184,14 @@ void DCCWaveform::interrupt2() {
// preamble for next packet will start... // preamble for next packet will start...
remainingPreambles = requiredPreambles; remainingPreambles = requiredPreambles;
// set the railcom coundown to trigger half way // Set the railcom coundown to trigger half way
// through the first preamble bit. // through the first preamble bit.
// Note.. we are still sending the last packet bit // Note.. we are still sending the last packet bit
// and we then have to allow for the packet end bit // but the timer code allows for this
if (isMainTrack && railcomActive) DCCTimer::startRailcomTimer(9); 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 // Fortunately reset and idle packets are the same length
// Note: If railcomDebug is on, then we send resets to the main // Note: If railcomDebug is on, then we send resets to the main
// track instead of idles. This means that all data will be zeros // 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. // easier to read on a logic analyser.
memcpy( transmitPacket, (isMainTrack && (!railcomDebug)) ? idlePacket : resetPacket, sizeof(idlePacket)); memcpy( transmitPacket, (isMainTrack && (!railcomDebug)) ? idlePacket : resetPacket, sizeof(idlePacket));
transmitLength = sizeof(idlePacket); transmitLength = sizeof(idlePacket);

View File

@ -85,8 +85,13 @@ class DCCWaveform {
void schedulePacket(const byte buffer[], byte byteCount, byte repeats); void schedulePacket(const byte buffer[], byte byteCount, byte repeats);
bool isReminderWindowOpen(); bool isReminderWindowOpen();
void promotePendingPacket(); void promotePendingPacket();
static void setRailcomPossible(bool yes) {
railcomPossible=yes;
if (!yes) setRailcom(false,false);
}
static bool setRailcom(bool on, bool debug); static bool setRailcom(bool on, bool debug);
static bool isRailcom() {return railcomActive;} static bool isRailcom() {return railcomActive;}
static bool isRailcomSampleWindow() {return railcomSampleWindow;}
private: private:
#ifndef ARDUINO_ARCH_ESP32 #ifndef ARDUINO_ARCH_ESP32
@ -112,9 +117,10 @@ class DCCWaveform {
byte pendingPacket[MAX_PACKET_SIZE+1]; // +1 for checksum byte pendingPacket[MAX_PACKET_SIZE+1]; // +1 for checksum
byte pendingLength; byte pendingLength;
byte pendingRepeats; byte pendingRepeats;
static volatile bool railcomActive; // switched on by user static bool railcomPossible; // High accuracy mode only
static volatile bool railcomDebug; // switched on by user 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 #ifdef ARDUINO_ARCH_ESP32
static RMTChannel *rmtMainChannel; static RMTChannel *rmtMainChannel;
static RMTChannel *rmtProgChannel; static RMTChannel *rmtProgChannel;

View File

@ -47,11 +47,11 @@
#include "IODevice.h" #include "IODevice.h"
#include "I2CManager.h" #include "I2CManager.h"
#include "DIAG.h" #include "DIAG.h"
#include "DCCWaveform.h"
// Debug and diagnostic defines, enable too many will result in slowing the driver // Debug and diagnostic defines, enable too many will result in slowing the driver
#define DIAG_I2CRailcom #define DIAG_I2CRailcom
#define DIAG_I2CRailcom_data #define DIAG_I2CRailcom_data
#define DIAG_I2CRailcom_reg
class I2CRailcom : public IODevice { class I2CRailcom : public IODevice {
private: private:
@ -62,7 +62,7 @@ private:
const uint8_t STOP_BIT = 0x00; // Value LCR bit 2 const uint8_t STOP_BIT = 0x00; // Value LCR bit 2
const uint8_t PARITY_ENA = 0x00; // Value LCR bit 3 const uint8_t PARITY_ENA = 0x00; // Value LCR bit 3
const uint8_t PARITY_TYPE = 0x00; // Value LCR bit 4 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 uint8_t PRESCALER = 0x01; // Value MCR bit 7
const unsigned long SC16IS752_XTAL_FREQ_RAILCOM = 16000000; // Baud rate for Railcom signal const unsigned long SC16IS752_XTAL_FREQ_RAILCOM = 16000000; // Baud rate for Railcom signal
byte _inbuf[65]; byte _inbuf[65];
@ -106,7 +106,8 @@ public:
// Read responses from device // Read responses from device
if (_deviceState!=DEVSTATE_NORMAL) return; 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 // flip channels each loop
if (_nPins>1) _UART_CH=_UART_CH?0:1; if (_nPins>1) _UART_CH=_UART_CH?0:1;

View File

@ -338,13 +338,17 @@ bool TrackManager::setTrackMode(byte trackToSet, TRACK_MODE mode, int16_t dcAddr
// if we discover that HA mode was globally impossible // if we discover that HA mode was globally impossible
// we must adjust the trackPWM capabilities // we must adjust the trackPWM capabilities
DIAG(F("High Accuracy & Railcom disabled")); DIAG(F("High Accuracy & Railcom disabled"));
DCCWaveform::setRailcomPossible(false);
FOR_EACH_TRACK(t) { FOR_EACH_TRACK(t) {
track[t]->trackPWM=false; track[t]->trackPWM=false;
//DIAG(F("Track %c trackPWM 0 (global override)"), t+'A'); //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 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 #else
// For ESP32 we just reinitialize the DCC Waveform // For ESP32 we just reinitialize the DCC Waveform
DCCWaveform::begin(); DCCWaveform::begin();