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

Compare commits

..

No commits in common. "c780b968564eae454d2001d51b0988f2245b0e02" and "8293749ac76199d9b0db6988872c49039f1a4ca8" have entirely different histories.

15 changed files with 18 additions and 185 deletions

View File

@ -1035,30 +1035,7 @@ bool DCCEXParser::parseC(Print *stream, int16_t params, int16_t p[]) {
DCC::setGlobalSpeedsteps(128); DCC::setGlobalSpeedsteps(128);
DIAG(F("128 Speedsteps")); DIAG(F("128 Speedsteps"));
return true; return true;
case "RAILCOM"_hk:
{ // <C RAILCOM ON|OFF|DEBUG >
if (params<2) return false;
bool on=false;
bool debug=false;
switch (p[1]) {
case "ON"_hk:
case 1:
on=true;
break;
case "DEBUG"_hk:
on=true;
debug=true;
break;
case "OFF"_hk:
case 0:
break;
default:
return false;
}
DIAG(F("Railcom %S")
,DCCWaveform::setRailcom(on,debug)?F("ON"):F("OFF"));
return true;
}
#ifndef DISABLE_PROG #ifndef DISABLE_PROG
case "ACK"_hk: // <D ACK ON/OFF> <D ACK [LIMIT|MIN|MAX|RETRY] Value> case "ACK"_hk: // <D ACK ON/OFF> <D ACK [LIMIT|MIN|MAX|RETRY] Value>
if (params >= 3) { if (params >= 3) {

View File

@ -62,8 +62,6 @@ class DCCTimer {
static bool isPWMPin(byte pin); static bool isPWMPin(byte pin);
static void setPWM(byte pin, bool high); static void setPWM(byte pin, bool high);
static void clearPWM(); static void clearPWM();
static void startRailcomTimer(byte brakePin);
static void ackRailcomTimer();
static void DCCEXanalogWriteFrequency(uint8_t pin, uint32_t frequency); static void DCCEXanalogWriteFrequency(uint8_t pin, uint32_t frequency);
static void DCCEXanalogWrite(uint8_t pin, int value); static void DCCEXanalogWrite(uint8_t pin, int value);

View File

@ -39,9 +39,6 @@ INTERRUPT_CALLBACK interruptHandler=0;
#define TIMER1_A_PIN 11 #define TIMER1_A_PIN 11
#define TIMER1_B_PIN 12 #define TIMER1_B_PIN 12
#define TIMER1_C_PIN 13 #define TIMER1_C_PIN 13
#define TIMER2_A_PIN 10
#define TIMER2_B_PIN 9
#else #else
#define TIMER1_A_PIN 9 #define TIMER1_A_PIN 9
#define TIMER1_B_PIN 10 #define TIMER1_B_PIN 10
@ -58,67 +55,6 @@ void DCCTimer::begin(INTERRUPT_CALLBACK callback) {
interrupts(); interrupts();
} }
void DCCTimer::startRailcomTimer(byte brakePin) {
/* The Railcom timer is started in such a way that it
- First triggers 28uS after the last TIMER1 tick.
This provides an accurate offset (in High Accuracy mode)
for the start of the Railcom cutout.
- Sets the Railcom pin high at first tick,
because its been setup with 100% PWM duty cycle.
- Cycles at 436uS so the second tick is the
correct distance from the cutout.
- Waveform code is responsible for altering the PWM
duty cycle to 0% any time between the first and last tick.
(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
// Set up Timer2 for CTC mode (Clear Timer on Compare Match)
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)
// Enable Timer2 output on pin 9 (OC2B)
DDRB |= (1 << DDB1);
// TODO Fudge TCNT2 to sync with last tcnt1 tick + 28uS
// Previous TIMER1 Tick was at rising end-of-packet bit
// Cutout starts half way through first preamble
// 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() {
OCR2B= 0x00; // brake pin pwm duty cycle 0 at next tick
}
// ISR called by timer interrupt every 58uS // ISR called by timer interrupt every 58uS
ISR(TIMER1_OVF_vect){ interruptHandler(); } ISR(TIMER1_OVF_vect){ interruptHandler(); }

View File

@ -80,15 +80,6 @@ extern char *__malloc_heap_start;
interruptHandler(); interruptHandler();
} }
void DCCTimer::startRailcomTimer(byte brakePin) {
// TODO: for intended operation see DCCTimerAVR.cpp
(void) brakePin;
}
void DCCTimer::ackRailcomTimer() {
// TODO: for intended operation see DCCTimerAVR.cpp
}
bool DCCTimer::isPWMPin(byte pin) { bool DCCTimer::isPWMPin(byte pin) {
(void) pin; (void) pin;
return false; // TODO what are the relevant pins? return false; // TODO what are the relevant pins?

View File

@ -76,15 +76,6 @@ void DCCTimer::begin(INTERRUPT_CALLBACK callback) {
interrupts(); interrupts();
} }
void DCCTimer::startRailcomTimer(byte brakePin) {
// TODO: for intended operation see DCCTimerAVR.cpp
(void) brakePin;
}
void DCCTimer::ackRailcomTimer() {
// TODO: for intended operation see DCCTimerAVR.cpp
}
// Timer IRQ handlers replace the dummy handlers (in cortex_handlers) // Timer IRQ handlers replace the dummy handlers (in cortex_handlers)
// copied from rf24 branch // copied from rf24 branch
void TCC0_Handler() { void TCC0_Handler() {

View File

@ -201,15 +201,6 @@ void DCCTimer::begin(INTERRUPT_CALLBACK callback) {
interrupts(); interrupts();
} }
void DCCTimer::startRailcomTimer(byte brakePin) {
// TODO: for intended operation see DCCTimerAVR.cpp
(void) brakePin;
}
void DCCTimer::ackRailcomTimer() {
// TODO: for intended operation see DCCTimerAVR.cpp
}
bool DCCTimer::isPWMPin(byte pin) { bool DCCTimer::isPWMPin(byte pin) {
//TODO: STM32 whilst this call to digitalPinHasPWM will reveal which pins can do PWM, //TODO: STM32 whilst this call to digitalPinHasPWM will reveal which pins can do PWM,
// there's no support yet for High Accuracy, so for now return false // there's no support yet for High Accuracy, so for now return false

View File

@ -39,15 +39,6 @@ void DCCTimer::begin(INTERRUPT_CALLBACK callback) {
myDCCTimer.begin(interruptHandler, DCC_SIGNAL_TIME); myDCCTimer.begin(interruptHandler, DCC_SIGNAL_TIME);
} }
void DCCTimer::startRailcomTimer(byte brakePin) {
// TODO: for intended operation see DCCTimerAVR.cpp
(void) brakePin;
}
void DCCTimer::ackRailcomTimer() {
// TODO: for intended operation see DCCTimerAVR.cpp
}
bool DCCTimer::isPWMPin(byte pin) { bool DCCTimer::isPWMPin(byte pin) {
//Teensy: digitalPinHasPWM, todo //Teensy: digitalPinHasPWM, todo
(void) pin; (void) pin;

View File

@ -115,22 +115,8 @@ DCCWaveform::DCCWaveform( byte preambleBits, bool isMain) {
bytes_sent = 0; bytes_sent = 0;
bits_sent = 0; bits_sent = 0;
} }
volatile bool DCCWaveform::railcomActive=false; // switched on by user
volatile bool DCCWaveform::railcomDebug=false; // switched on by user
bool DCCWaveform::setRailcom(bool on, bool debug) {
if (on) {
// TODO check possible
railcomActive=true;
railcomDebug=debug;
}
else {
railcomActive=false;
railcomDebug=false;
}
return railcomActive;
}
#pragma GCC push_options #pragma GCC push_options
#pragma GCC optimize ("-O3") #pragma GCC optimize ("-O3")
@ -138,16 +124,16 @@ void DCCWaveform::interrupt2() {
// calculate the next bit to be sent: // calculate the next bit to be sent:
// set state WAVE_MID_1 for a 1=bit // set state WAVE_MID_1 for a 1=bit
// 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<4 && remainingPreambles>1;
if (remainingPreambles==1) promotePendingPacket(); if (remainingPreambles==1) promotePendingPacket();
else if (remainingPreambles==10 && isMainTrack && railcomActive) DCCTimer::ackRailcomTimer();
// 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);
@ -171,12 +157,6 @@ 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);
} }
} }
} }
@ -228,11 +208,7 @@ void DCCWaveform::promotePendingPacket() {
// nothing to do, just send idles or resets // nothing to do, just send idles or resets
// 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 memcpy( transmitPacket, isMainTrack ? idlePacket : resetPacket, sizeof(idlePacket));
// track instead of idles. This means that all data will be zeros
// and only the porersets will be ones, making it much
// easier to read on a logic analyser.
memcpy( transmitPacket, (isMainTrack && (!railcomDebug)) ? idlePacket : resetPacket, sizeof(idlePacket));
transmitLength = sizeof(idlePacket); transmitLength = sizeof(idlePacket);
transmitRepeats = 0; transmitRepeats = 0;
if (getResets() < 250) sentResetsSincePacket++; // only place to increment (private!) if (getResets() < 250) sentResetsSincePacket++; // only place to increment (private!)
@ -321,10 +297,4 @@ bool DCCWaveform::isReminderWindowOpen() {
void IRAM_ATTR DCCWaveform::loop() { void IRAM_ATTR DCCWaveform::loop() {
DCCACK::checkAck(progTrack.getResets()); DCCACK::checkAck(progTrack.getResets());
} }
bool DCCWaveform::setRailcom(bool on, bool debug) {
// TODO... ESP32 railcom waveform
return false;
}
#endif #endif

View File

@ -40,14 +40,7 @@ const byte MAX_PACKET_SIZE = 5; // NMRA standard extended packets, payload s
// The WAVE_STATE enum is deliberately numbered because a change of order would be catastrophic // The WAVE_STATE enum is deliberately numbered because a change of order would be catastrophic
// to the transform array. // to the transform array.
enum WAVE_STATE : byte { enum WAVE_STATE : byte {WAVE_START=0,WAVE_MID_1=1,WAVE_HIGH_0=2,WAVE_MID_0=3,WAVE_LOW_0=4,WAVE_PENDING=5};
WAVE_START=0, // wave going high at start of bit
WAVE_MID_1=1, // middle of 1 bit
WAVE_HIGH_0=2, // first part of 0 bit high
WAVE_MID_0=3, // middle of 0 bit
WAVE_LOW_0=4, // first part of 0 bit low
WAVE_PENDING=5 // next bit not yet known
};
// NOTE: static functions are used for the overall controller, then // NOTE: static functions are used for the overall controller, then
// one instance is created for each track. // one instance is created for each track.
@ -85,8 +78,6 @@ 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 bool setRailcom(bool on, bool debug);
static bool isRailcom() {return railcomActive;}
private: private:
#ifndef ARDUINO_ARCH_ESP32 #ifndef ARDUINO_ARCH_ESP32
@ -112,9 +103,6 @@ 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 volatile bool railcomDebug; // switched on by user
#ifdef ARDUINO_ARCH_ESP32 #ifdef ARDUINO_ARCH_ESP32
static RMTChannel *rmtMainChannel; static RMTChannel *rmtMainChannel;
static RMTChannel *rmtProgChannel; static RMTChannel *rmtProgChannel;

View File

@ -42,7 +42,6 @@
#undef CLEAR_STASH #undef CLEAR_STASH
#undef CLEAR_ALL_STASH #undef CLEAR_ALL_STASH
#undef CLOSE #undef CLOSE
#undef CONFIGURE_SERVO
#undef DCC_SIGNAL #undef DCC_SIGNAL
#undef DCC_TURNTABLE #undef DCC_TURNTABLE
#undef DEACTIVATE #undef DEACTIVATE
@ -195,8 +194,7 @@
#define CALL(route) #define CALL(route)
#define CLEAR_STASH(id) #define CLEAR_STASH(id)
#define CLEAR_ALL_STASH(id) #define CLEAR_ALL_STASH(id)
#define CLOSE(id) #define CLOSE(id)
#define CONFIGURE_SERVO(vpin,pos1,pos2,profile)
#define DCC_SIGNAL(id,add,subaddr) #define DCC_SIGNAL(id,add,subaddr)
#define DCC_TURNTABLE(id,home,description) #define DCC_TURNTABLE(id,home,description)
#define DEACTIVATE(addr,subaddr) #define DEACTIVATE(addr,subaddr)

View File

@ -151,8 +151,6 @@ static_assert(!hasdup(compileTimeSequenceList[0],1),"Duplicate SEQUENCE/ROUTE/AU
#define HAL_IGNORE_DEFAULTS ignore_defaults=true; #define HAL_IGNORE_DEFAULTS ignore_defaults=true;
#undef JMRI_SENSOR #undef JMRI_SENSOR
#define JMRI_SENSOR(vpin,count...) Sensor::createMultiple(vpin,##count); #define JMRI_SENSOR(vpin,count...) Sensor::createMultiple(vpin,##count);
#undef CONFIGURE_SERVO
#define CONFIGURE_SERVO(vpin,pos1,pos2,profile) IODevice::configureServo(vpin,pos1,pos2,PCA9685::profile);
bool exrailHalSetup() { bool exrailHalSetup() {
bool ignore_defaults=false; bool ignore_defaults=false;
#include "myAutomation.h" #include "myAutomation.h"
@ -443,7 +441,6 @@ int RMFT2::onLCCLookup[RMFT2::countLCCLookup];
#define CLEAR_STASH(id) OPCODE_CLEAR_STASH,V(id), #define CLEAR_STASH(id) OPCODE_CLEAR_STASH,V(id),
#define CLEAR_ALL_STASH OPCODE_CLEAR_ALL_STASH,V(0), #define CLEAR_ALL_STASH OPCODE_CLEAR_ALL_STASH,V(0),
#define CLOSE(id) OPCODE_CLOSE,V(id), #define CLOSE(id) OPCODE_CLOSE,V(id),
#define CONFIGURE_SERVO(vpin,pos1,pos2,profile)
#ifndef IO_NO_HAL #ifndef IO_NO_HAL
#define DCC_TURNTABLE(id,home,description...) OPCODE_DCCTURNTABLE,V(id),OPCODE_PAD,V(home), #define DCC_TURNTABLE(id,home,description...) OPCODE_DCCTURNTABLE,V(id),OPCODE_PAD,V(home),
#endif #endif

View File

@ -204,7 +204,7 @@ MotorDriver::MotorDriver(int16_t power_pin, byte signal_pin, byte signal_pin2, i
} }
bool MotorDriver::isPWMCapable() { bool MotorDriver::isPWMCapable() {
return (!dualSignal) && DCCTimer::isPWMPin(signalPin); return (!dualSignal) && DCCTimer::isPWMPin(signalPin);
} }

View File

@ -157,6 +157,12 @@ void TrackManager::setDCCSignal( bool on) {
HAVE_PORTF(PORTF=shadowPORTF); HAVE_PORTF(PORTF=shadowPORTF);
} }
void TrackManager::setCutout( bool on) {
(void) on;
// TODO Cutout needs fake ports as well
// TODO APPLY_BY_MODE(TRACK_MODE_MAIN,setCutout(on));
}
// setPROGSignal(), called from interrupt context // setPROGSignal(), called from interrupt context
// does assume ports are shadowed if they can be // does assume ports are shadowed if they can be
void TrackManager::setPROGSignal( bool on) { void TrackManager::setPROGSignal( bool on) {

View File

@ -57,6 +57,7 @@ class TrackManager {
); );
static void setDCCSignal( bool on); static void setDCCSignal( bool on);
static void setCutout( bool on);
static void setPROGSignal( bool on); static void setPROGSignal( bool on);
static void setDCSignal(int16_t cab, byte speedbyte); static void setDCSignal(int16_t cab, byte speedbyte);
static MotorDriver * getProgDriver(); static MotorDriver * getProgDriver();

View File

@ -3,11 +3,9 @@
#include "StringFormatter.h" #include "StringFormatter.h"
#define VERSION "5.2.33" #define VERSION "5.2.31"
// 5.2.33 - Exrail CONFIGURE_SERVO(vpin,pos1,pos2,profile) // 5.2.31 - Exrail JMRI_SENSORS(vpin [,count]) creates <S> types.
// 5.2.32 - Railcom Cutout (Initial trial Mega2560 only) // 5.2.40 - Bugfix: WiThrottle sendIntro after initial N message as well
// 5.2.31 - Exrail JMRI_SENSOR(vpin [,count]) creates <S> types.
// 5.2.30 - Bugfix: WiThrottle sendIntro after initial N message as well
// 5.2.29 - Added IO_I2CDFPlayer.h to support DFPLayer over I2C connected to NXP SC16IS750/SC16IS752 (currently only single UART for SC16IS752) // 5.2.29 - Added IO_I2CDFPlayer.h to support DFPLayer over I2C connected to NXP SC16IS750/SC16IS752 (currently only single UART for SC16IS752)
// - Added enhanced IO_I2CDFPLayer enum commands to EXRAIL2.h // - Added enhanced IO_I2CDFPLayer enum commands to EXRAIL2.h
// - Added PLAYSOUND alias of ANOUT to EXRAILMacros.h // - Added PLAYSOUND alias of ANOUT to EXRAILMacros.h