mirror of
https://github.com/DCC-EX/CommandStation-EX.git
synced 2025-04-23 13:31:19 +02:00
RAILCOM cutout (mega)
This commit is contained in:
parent
7e8841611d
commit
680f765775
@ -1223,6 +1223,10 @@ bool DCCEXParser::parseD(Print *stream, int16_t params, int16_t p[])
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
#ifdef HAS_ENOUGH_MEMORY
|
#ifdef HAS_ENOUGH_MEMORY
|
||||||
|
case "RAILCOM"_hk: // <D RAILCOM ON/OFF>
|
||||||
|
Diag::RAILCOM = onOff;
|
||||||
|
return true;
|
||||||
|
|
||||||
case "WIFI"_hk: // <D WIFI ON/OFF>
|
case "WIFI"_hk: // <D WIFI ON/OFF>
|
||||||
Diag::WIFI = onOff;
|
Diag::WIFI = onOff;
|
||||||
return true;
|
return true;
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
* © 2021 Mike S
|
* © 2021 Mike S
|
||||||
* © 2021-2023 Harald Barth
|
* © 2021-2023 Harald Barth
|
||||||
* © 2021 Fred Decker
|
* © 2021 Fred Decker
|
||||||
* © 2021 Chris Harlow
|
* © 2021-2025 Chris Harlow
|
||||||
* © 2021 David Cutting
|
* © 2021 David Cutting
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
@ -57,66 +57,59 @@ void DCCTimer::begin(INTERRUPT_CALLBACK callback) {
|
|||||||
TCCR1B = _BV(WGM13) | _BV(CS10); // Mode 8, clock select 1
|
TCCR1B = _BV(WGM13) | _BV(CS10); // Mode 8, clock select 1
|
||||||
TIMSK1 = _BV(TOIE1); // Enable Software interrupt
|
TIMSK1 = _BV(TOIE1); // Enable Software interrupt
|
||||||
interrupts();
|
interrupts();
|
||||||
|
//diagnostic pinMode(4,OUTPUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DCCTimer::startRailcomTimer(byte brakePin) {
|
void DCCTimer::startRailcomTimer(byte brakePin) {
|
||||||
|
(void) brakePin; // Ignored... works on pin 9 only
|
||||||
|
// diagnostic digitalWrite(4,HIGH);
|
||||||
|
|
||||||
/* The Railcom timer is started in such a way that it
|
/* The Railcom timer is started in such a way that it
|
||||||
- First triggers 28uS after the last TIMER1 tick.
|
- First triggers 58+29 uS after the previous TIMER1 tick.
|
||||||
This provides an accurate offset (in High Accuracy mode)
|
This provides an accurate offset (in High Accuracy mode)
|
||||||
for the start of the Railcom cutout.
|
for the start of the Railcom cutout.
|
||||||
- Sets the Railcom pin high at first tick,
|
- Sets the Railcom pin high at first tick and subsequent ticks
|
||||||
because its been setup with 100% PWM duty cycle.
|
until its reset to setting pin 9 low at next tick.
|
||||||
|
|
||||||
- Cycles at 436uS so the second tick is the
|
- Cycles at 436uS so the second tick is the
|
||||||
correct distance from the cutout.
|
correct distance from the cutout.
|
||||||
|
|
||||||
- Waveform code is responsible for altering the PWM
|
- Waveform code is responsible for resetting
|
||||||
duty cycle to 0% any time between the first and last tick.
|
any time between the first and second tick.
|
||||||
(there will be 7 DCC timer1 ticks in which to do this.)
|
(there will be 7 DCC timer1 ticks in which to do this.)
|
||||||
|
|
||||||
*/
|
*/
|
||||||
(void) brakePin; // Ignored... works on pin 9 only
|
|
||||||
const int cutoutDuration = 430; // Desired interval in microseconds
|
const int cutoutDuration = 430; // Desired interval in microseconds
|
||||||
|
const int cycle=cutoutDuration/2;
|
||||||
|
|
||||||
// Set up Timer2 for CTC mode (Clear Timer on Compare Match)
|
const byte RailcomFudge0=58+58+29;
|
||||||
TCCR2A = 0; // Clear Timer2 control register A
|
|
||||||
TCCR2B = 0; // Clear Timer2 control register B
|
|
||||||
TCNT2 = 0; // Initialize Timer2 counter value to 0
|
|
||||||
// Configure Phase and Frequency Correct PWM mode
|
|
||||||
TCCR2A = (1 << COM2B1); // enable pwm on pin 9
|
|
||||||
TCCR2A |= (1 << WGM20);
|
|
||||||
|
|
||||||
|
|
||||||
// Set Timer 2 prescaler to 32
|
|
||||||
TCCR2B = (1 << CS21) | (1 << CS20); // 32 prescaler
|
|
||||||
|
|
||||||
// Set the compare match value for desired interval
|
|
||||||
OCR2A = (F_CPU / 1000000) * cutoutDuration / 64 - 1;
|
|
||||||
|
|
||||||
// Calculate the compare match value for desired duty cycle
|
|
||||||
OCR2B = OCR2A+1; // set duty cycle to 100%= OCR2A)
|
|
||||||
|
|
||||||
|
// Set Timer2 to CTC mode with set on compare match
|
||||||
|
TCCR2A = (1 << WGM21) | (1 << COM2B0) | (1 << COM2B1);
|
||||||
|
// Prescaler of 32
|
||||||
|
TCCR2B = (1 << CS21) | (1 << CS20);
|
||||||
|
OCR2A = cycle-1; // Compare match value for 430 uS
|
||||||
// Enable Timer2 output on pin 9 (OC2B)
|
// Enable Timer2 output on pin 9 (OC2B)
|
||||||
DDRB |= (1 << DDB1);
|
DDRB |= (1 << DDB1);
|
||||||
// TODO Fudge TCNT2 to sync with last tcnt1 tick + 28uS
|
|
||||||
|
// RailcomFudge2 is the expected time from idealised
|
||||||
|
// setup call (at previous DCC timer interrupt) to the cutout.
|
||||||
|
// This value should be reduced to reflect the Timer1 value
|
||||||
|
// measuring the time since the previous hardware interrupt
|
||||||
|
byte tcfudge=TCNT1/16;
|
||||||
|
TCNT2=cycle-RailcomFudge0/2+tcfudge/2;
|
||||||
|
|
||||||
|
|
||||||
// Previous TIMER1 Tick was at rising end-of-packet bit
|
// Previous TIMER1 Tick was at rising end-of-packet bit
|
||||||
// Cutout starts half way through first preamble
|
// Cutout starts half way through first preamble
|
||||||
// that is 2.5 * 58uS later.
|
// that is 2.5 * 58uS later.
|
||||||
// TCNT1 ticks 8 times / microsecond
|
}
|
||||||
// auto microsendsToFirstRailcomTick=(58+58+29)-(TCNT1/8);
|
|
||||||
// set the railcom timer counter allowing for phase-correct
|
|
||||||
|
|
||||||
// CHris's NOTE:
|
|
||||||
// I dont kniow quite how this calculation works out but
|
|
||||||
// it does seems to get a good answer.
|
|
||||||
|
|
||||||
TCNT2=193 + (ICR1 - TCNT1)/8;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DCCTimer::ackRailcomTimer() {
|
void DCCTimer::ackRailcomTimer() {
|
||||||
OCR2B= 0x00; // brake pin pwm duty cycle 0 at next tick
|
// Change Timer2 to CTC mode with RESET pin 9 on next compare match
|
||||||
|
TCCR2A = (1 << WGM21) | (1 << COM2B1);
|
||||||
|
// diagnostic digitalWrite(4,LOW);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -21,18 +21,16 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with CommandStation. If not, see <https://www.gnu.org/licenses/>.
|
* along with CommandStation. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef ARDUINO_ARCH_ESP32
|
#ifndef ARDUINO_ARCH_ESP32
|
||||||
// This code is replaced entirely on an ESP32 see DCCWaveformRMT.cpp
|
// This code is replaced entirely on an ESP32
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
|
||||||
#include "DCCWaveform.h"
|
#include "DCCWaveform.h"
|
||||||
#include "TrackManager.h"
|
#include "TrackManager.h"
|
||||||
#include "DCCTimer.h"
|
#include "DCCTimer.h"
|
||||||
#include "DCCACK.h"
|
#include "DCCACK.h"
|
||||||
#include "DIAG.h"
|
#include "DIAG.h"
|
||||||
|
|
||||||
|
bool DCCWaveform::cutoutNextTime=false;
|
||||||
DCCWaveform DCCWaveform::mainTrack(PREAMBLE_BITS_MAIN, true);
|
DCCWaveform DCCWaveform::mainTrack(PREAMBLE_BITS_MAIN, true);
|
||||||
DCCWaveform DCCWaveform::progTrack(PREAMBLE_BITS_PROG, false);
|
DCCWaveform DCCWaveform::progTrack(PREAMBLE_BITS_PROG, false);
|
||||||
|
|
||||||
@ -72,9 +70,18 @@ void DCCWaveform::loop() {
|
|||||||
|
|
||||||
#pragma GCC push_options
|
#pragma GCC push_options
|
||||||
#pragma GCC optimize ("-O3")
|
#pragma GCC optimize ("-O3")
|
||||||
|
|
||||||
void DCCWaveform::interruptHandler() {
|
void DCCWaveform::interruptHandler() {
|
||||||
// call the timer edge sensitive actions for progtrack and maintrack
|
// call the timer edge sensitive actions for progtrack and maintrack
|
||||||
// member functions would be cleaner but have more overhead
|
// member functions would be cleaner but have more overhead
|
||||||
|
#if defined(HAS_ENOUGH_MEMORY)
|
||||||
|
if (cutoutNextTime) {
|
||||||
|
cutoutNextTime=false;
|
||||||
|
railcomSampleWindow=false; // about to cutout, stop reading railcom data.
|
||||||
|
railcomCutoutCounter++;
|
||||||
|
DCCTimer::startRailcomTimer(9);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
byte sigMain=signalTransform[mainTrack.state];
|
byte sigMain=signalTransform[mainTrack.state];
|
||||||
byte sigProg=TrackManager::progTrackSyncMain? sigMain : signalTransform[progTrack.state];
|
byte sigProg=TrackManager::progTrackSyncMain? sigMain : signalTransform[progTrack.state];
|
||||||
|
|
||||||
@ -117,18 +124,23 @@ 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::railcomDebug=false; // switched on by user
|
volatile bool DCCWaveform::railcomDebug=false; // switched on by user
|
||||||
|
volatile bool DCCWaveform::railcomSampleWindow=false; // true during packet transmit
|
||||||
|
volatile byte DCCWaveform::railcomCutoutCounter=0; // cyclic cutout
|
||||||
|
volatile byte DCCWaveform::railcomLastAddressHigh=0;
|
||||||
|
volatile byte DCCWaveform::railcomLastAddressLow=0;
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
@ -141,14 +153,37 @@ void DCCWaveform::interrupt2() {
|
|||||||
// or WAVE_HIGH_0 for a 0 bit.
|
// or WAVE_HIGH_0 for a 0 bit.
|
||||||
if (remainingPreambles > 0 ) {
|
if (remainingPreambles > 0 ) {
|
||||||
state=WAVE_MID_1; // switch state to trigger LOW on next interrupt
|
state=WAVE_MID_1; // switch state to trigger LOW on next interrupt
|
||||||
|
|
||||||
remainingPreambles--;
|
remainingPreambles--;
|
||||||
|
|
||||||
// As we get to the end of the preambles, open the reminder window.
|
// As we get to the end of the preambles, open the reminder window.
|
||||||
// This delays any reminder insertion until the last moment so
|
// This delays any reminder insertion until the last moment so
|
||||||
// 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<10 && remainingPreambles>1;
|
||||||
if (remainingPreambles==1) promotePendingPacket();
|
if (remainingPreambles==1)
|
||||||
else if (remainingPreambles==10 && isMainTrack && railcomActive) DCCTimer::ackRailcomTimer();
|
promotePendingPacket();
|
||||||
|
|
||||||
|
#if defined(HAS_ENOUGH_MEMORY)
|
||||||
|
else if (isMainTrack && railcomActive) {
|
||||||
|
if (remainingPreambles==(requiredPreambles-1)) {
|
||||||
|
// First look if we need to start a railcom cutout on next interrupt
|
||||||
|
cutoutNextTime= true;
|
||||||
|
} else if (remainingPreambles==(requiredPreambles-12)) {
|
||||||
|
// cutout has ended so its now possible to poll the railcom detectors
|
||||||
|
// requiredPreambles is one higher that preamble length so
|
||||||
|
// if preamble length is 16 then this evaluates to 5
|
||||||
|
// Remember address bytes of last sent packet so that Railcom can
|
||||||
|
// work out where the channel2 data came from.
|
||||||
|
railcomLastAddressHigh=transmitPacket[0];
|
||||||
|
railcomLastAddressLow =transmitPacket[1];
|
||||||
|
railcomSampleWindow=true;
|
||||||
|
} else if (remainingPreambles==(requiredPreambles-3)) {
|
||||||
|
// cutout can be ended when read
|
||||||
|
// see above for requiredPreambles
|
||||||
|
DCCTimer::ackRailcomTimer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
// 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,13 +207,7 @@ void DCCWaveform::interrupt2() {
|
|||||||
bytes_sent = 0;
|
bytes_sent = 0;
|
||||||
// preamble for next packet will start...
|
// preamble for next packet will start...
|
||||||
remainingPreambles = requiredPreambles;
|
remainingPreambles = requiredPreambles;
|
||||||
|
}
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#pragma GCC pop_options
|
#pragma GCC pop_options
|
||||||
@ -231,7 +260,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);
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
* © 2021 Mike S
|
* © 2021 Mike S
|
||||||
* © 2021 Fred Decker
|
* © 2021 Fred Decker
|
||||||
* © 2020-2024 Harald Barth
|
* © 2020-2024 Harald Barth
|
||||||
* © 2020-2021 Chris Harlow
|
* © 2020-2025 Chris Harlow
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is part of CommandStation-EX
|
* This file is part of CommandStation-EX
|
||||||
@ -23,11 +23,8 @@
|
|||||||
*/
|
*/
|
||||||
#ifndef DCCWaveform_h
|
#ifndef DCCWaveform_h
|
||||||
#define DCCWaveform_h
|
#define DCCWaveform_h
|
||||||
|
|
||||||
#include "MotorDriver.h"
|
|
||||||
#ifdef ARDUINO_ARCH_ESP32
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
#include "DCCRMT.h"
|
#include "DCCRMT.h"
|
||||||
#include "TrackManager.h"
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@ -86,7 +83,29 @@ class DCCWaveform {
|
|||||||
bool isReminderWindowOpen();
|
bool isReminderWindowOpen();
|
||||||
void promotePendingPacket();
|
void promotePendingPacket();
|
||||||
static bool setRailcom(bool on, bool debug);
|
static bool setRailcom(bool on, bool debug);
|
||||||
static bool isRailcom() {return railcomActive;}
|
inline static bool isRailcom() {
|
||||||
|
return railcomActive;
|
||||||
|
};
|
||||||
|
inline static byte getRailcomCutoutCounter() {
|
||||||
|
return railcomCutoutCounter;
|
||||||
|
};
|
||||||
|
inline static bool isRailcomSampleWindow() {
|
||||||
|
return railcomSampleWindow;
|
||||||
|
};
|
||||||
|
inline static bool isRailcomPossible() {
|
||||||
|
return railcomPossible;
|
||||||
|
};
|
||||||
|
inline static void setRailcomPossible(bool yes) {
|
||||||
|
railcomPossible=yes;
|
||||||
|
if (!yes) setRailcom(false,false);
|
||||||
|
};
|
||||||
|
inline static uint16_t getRailcomLastLocoAddress() {
|
||||||
|
// first 2 bits 00=short loco, 11=long loco , 01/10 = accessory
|
||||||
|
byte addressType=railcomLastAddressHigh & 0xC0;
|
||||||
|
if (addressType==0xC0) return ((railcomLastAddressHigh & 0x3f)<<8) | railcomLastAddressLow;
|
||||||
|
if (addressType==0x00) return railcomLastAddressHigh & 0x3F;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
#ifndef ARDUINO_ARCH_ESP32
|
#ifndef ARDUINO_ARCH_ESP32
|
||||||
@ -112,9 +131,13 @@ 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 bool railcomPossible; // High accuracy mode only
|
||||||
static volatile bool railcomActive; // switched on by user
|
static volatile bool railcomActive; // switched on by user
|
||||||
static volatile bool railcomDebug; // switched on by user
|
static volatile bool railcomDebug; // switched on by user
|
||||||
|
static volatile bool railcomSampleWindow; // when safe to sample
|
||||||
|
static volatile byte railcomCutoutCounter; // incremented for each cutout
|
||||||
|
static volatile byte railcomLastAddressHigh,railcomLastAddressLow;
|
||||||
|
static bool cutoutNextTime; // railcom
|
||||||
#ifdef ARDUINO_ARCH_ESP32
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
static RMTChannel *rmtMainChannel;
|
static RMTChannel *rmtMainChannel;
|
||||||
static RMTChannel *rmtProgChannel;
|
static RMTChannel *rmtProgChannel;
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#ifdef ARDUINO_ARCH_ESP32
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
#include "DCCWaveform.h"
|
#include "DCCWaveform.h"
|
||||||
#include "DCCACK.h"
|
#include "DCCACK.h"
|
||||||
|
#include "TrackManager.h"
|
||||||
|
|
||||||
DCCWaveform DCCWaveform::mainTrack(PREAMBLE_BITS_MAIN, true);
|
DCCWaveform DCCWaveform::mainTrack(PREAMBLE_BITS_MAIN, true);
|
||||||
DCCWaveform DCCWaveform::progTrack(PREAMBLE_BITS_PROG, false);
|
DCCWaveform DCCWaveform::progTrack(PREAMBLE_BITS_PROG, false);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* © 2020, Chris Harlow. All rights reserved.
|
* © 2020=2025, Chris Harlow. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is part of Asbelos DCC API
|
* This file is part of Asbelos DCC API
|
||||||
*
|
*
|
||||||
@ -27,6 +27,8 @@ bool Diag::WIFI=false;
|
|||||||
bool Diag::WITHROTTLE=false;
|
bool Diag::WITHROTTLE=false;
|
||||||
bool Diag::ETHERNET=false;
|
bool Diag::ETHERNET=false;
|
||||||
bool Diag::LCN=false;
|
bool Diag::LCN=false;
|
||||||
|
bool Diag::RAILCOM=false;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void StringFormatter::diag( const FSH* input...) {
|
void StringFormatter::diag( const FSH* input...) {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* © 2020, Chris Harlow. All rights reserved.
|
* © 2020-2025, Chris Harlow. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is part of Asbelos DCC API
|
* This file is part of Asbelos DCC API
|
||||||
*
|
*
|
||||||
@ -30,6 +30,7 @@ class Diag {
|
|||||||
static bool WITHROTTLE;
|
static bool WITHROTTLE;
|
||||||
static bool ETHERNET;
|
static bool ETHERNET;
|
||||||
static bool LCN;
|
static bool LCN;
|
||||||
|
static bool RAILCOM;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -332,7 +332,8 @@ bool TrackManager::setTrackMode(byte trackToSet, TRACK_MODE mode, int16_t dcAddr
|
|||||||
canDo &= track[t]->trackPWM;
|
canDo &= track[t]->trackPWM;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!canDo) {
|
if (canDo) DIAG(F("HA mode"));
|
||||||
|
else {
|
||||||
// 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
|
||||||
FOR_EACH_TRACK(t) {
|
FOR_EACH_TRACK(t) {
|
||||||
@ -341,6 +342,7 @@ bool TrackManager::setTrackMode(byte trackToSet, TRACK_MODE mode, int16_t dcAddr
|
|||||||
}
|
}
|
||||||
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
|
||||||
}
|
}
|
||||||
|
DCCWaveform::setRailcomPossible(canDo);
|
||||||
#else
|
#else
|
||||||
// For ESP32 we just reinitialize the DCC Waveform
|
// For ESP32 we just reinitialize the DCC Waveform
|
||||||
DCCWaveform::begin();
|
DCCWaveform::begin();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user