1
0
mirror of https://github.com/DCC-EX/CommandStation-EX.git synced 2024-12-23 12:51:24 +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;
}
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);

View File

@ -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;

View File

@ -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;

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
// 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();