1
0
mirror of https://github.com/DCC-EX/CommandStation-EX.git synced 2025-02-22 08:46:04 +01:00

Compare commits

..

No commits in common. "a08195332f2387d5a9e4ad32bb4128fe0d4ad406" and "854ddb0c6c696c808586eb8febaabb52261266bb" have entirely different histories.

8 changed files with 145 additions and 141 deletions

View File

@ -207,13 +207,9 @@ int16_t CommandDistributor::retClockTime() {
return lastclocktime; return lastclocktime;
} }
void CommandDistributor::broadcastLoco(DCC::LOCO* sp) { void CommandDistributor::broadcastLoco(byte slot) {
if (!sp) { DCC::LOCO * sp=&DCC::speedTable[slot];
broadcastReply(COMMAND_TYPE,F("<l 0 -1 128 0>\n")); broadcastReply(COMMAND_TYPE, F("<l %d %d %d %l>\n"), sp->loco,slot,sp->targetSpeed,sp->functions);
return;
}
broadcastReply(COMMAND_TYPE, F("<l %d 0 %d %l>\n"),
sp->loco,sp->targetSpeed,sp->functions);
#ifdef SABERTOOTH #ifdef SABERTOOTH
if (Serial2 && sp->loco == SABERTOOTH) { if (Serial2 && sp->loco == SABERTOOTH) {
static uint8_t rampingmode = 0; static uint8_t rampingmode = 0;

View File

@ -28,7 +28,6 @@
#include "StringBuffer.h" #include "StringBuffer.h"
#include "defines.h" #include "defines.h"
#include "EXRAIL2.h" #include "EXRAIL2.h"
#include "DCC.h"
#if WIFI_ON | ETHERNET_ON #if WIFI_ON | ETHERNET_ON
// Command Distributor must handle a RingStream of clients // Command Distributor must handle a RingStream of clients
@ -47,7 +46,7 @@ private:
#endif #endif
public : public :
static void parse(byte clientId,byte* buffer, RingStream * ring); static void parse(byte clientId,byte* buffer, RingStream * ring);
static void broadcastLoco(DCC::LOCO * slot); static void broadcastLoco(byte slot);
static void broadcastForgetLoco(int16_t loco); static void broadcastForgetLoco(int16_t loco);
static void broadcastSensor(int16_t id, bool value); static void broadcastSensor(int16_t id, bool value);
static void broadcastTurnout(int16_t id, bool isClosed); static void broadcastTurnout(int16_t id, bool isClosed);

240
DCC.cpp
View File

@ -60,8 +60,6 @@ const byte FN_GROUP_5=0x10;
FSH* DCC::shieldName=NULL; FSH* DCC::shieldName=NULL;
byte DCC::globalSpeedsteps=128; byte DCC::globalSpeedsteps=128;
#define SLOTLOOP for (auto slot=&speedTable[0];slot!=&speedTable[MAX_LOCOS];slot++)
void DCC::begin() { void DCC::begin() {
StringFormatter::send(&USB_SERIAL,F("<iDCC-EX V-%S / %S / %S G-%S>\n"), F(VERSION), F(ARDUINO_TYPE), shieldName, F(GITHUB_SHA)); StringFormatter::send(&USB_SERIAL,F("<iDCC-EX V-%S / %S / %S G-%S>\n"), F(VERSION), F(ARDUINO_TYPE), shieldName, F(GITHUB_SHA));
#ifndef DISABLE_EEPROM #ifndef DISABLE_EEPROM
@ -77,26 +75,23 @@ void DCC::begin() {
int16_t DCC::defaultMomentum=0; int16_t DCC::defaultMomentum=0;
void DCC::setThrottle( uint16_t cab, uint8_t tSpeed, bool tDirection) { void DCC::setThrottle( uint16_t cab, uint8_t tSpeed, bool tDirection) {
if (cab==0) {
if (tSpeed==1) estopAll(); // ESTOP broadcast fix
return;
}
byte speedCode = (tSpeed & 0x7F) + tDirection * 128; byte speedCode = (tSpeed & 0x7F) + tDirection * 128;
LOCO * slot=lookupSpeedTable(cab); int reg=lookupSpeedTable(cab);
if (slot->targetSpeed==speedCode) return; if (reg<0 || speedTable[reg].targetSpeed==speedCode) return;
slot->targetSpeed=speedCode; speedTable[reg].targetSpeed=speedCode;
auto momentum=slot->millis_per_notch; auto momentum=speedTable[reg].millis_per_notch;
if (momentum<0) momentum=defaultMomentum; if (momentum<0) momentum=defaultMomentum;
if (momentum>0 && tSpeed!=1) { // not ESTOP if (momentum>0 && tSpeed!=1) { // not ESTOP
// we dont throttle speed, we just let the reminders take it to target // we dont throttle speed, we just let the reminders take it to target
slot->momentum_base=millis(); speedTable[reg].momentum_base=millis();
} }
else { // Momentum not involved, throttle now. else { // Momentum not involved, throttle now.
slot->speedCode = speedCode; speedTable[reg].speedCode = speedCode;
setThrottle2(cab, speedCode); setThrottle2(cab, speedCode);
TrackManager::setDCSignal(cab,speedCode); // in case this is a dcc track on this addr TrackManager::setDCSignal(cab,speedCode); // in case this is a dcc track on this addr
if ((speedCode & 0x7f)==1) updateLocoReminder(cab,speedCode); // ESTOP broadcast fix
} }
CommandDistributor::broadcastLoco(slot); CommandDistributor::broadcastLoco(reg);
} }
void DCC::setThrottle2( uint16_t cab, byte speedCode) { void DCC::setThrottle2( uint16_t cab, byte speedCode) {
@ -157,22 +152,18 @@ void DCC::setFunctionInternal(int cab, byte byte1, byte byte2, byte count) {
// returns speed steps 0 to 127 (1 == emergency stop) // returns speed steps 0 to 127 (1 == emergency stop)
// or -1 on "loco not found" // or -1 on "loco not found"
int8_t DCC::getThrottleSpeed(int cab) { int8_t DCC::getThrottleSpeed(int cab) {
return getThrottleSpeedByte(cab) & 0x7F; int reg=lookupSpeedTable(cab);
if (reg<0) return -1;
return speedTable[reg].speedCode & 0x7F;
} }
// returns speed code byte // returns speed code byte
// or 128 (speed 0, dir forward) on "loco not found". // or 128 (speed 0, dir forward) on "loco not found".
// This is the throttle set speed
uint8_t DCC::getThrottleSpeedByte(int cab) { uint8_t DCC::getThrottleSpeedByte(int cab) {
LOCO * slot=lookupSpeedTable(cab,false); int reg=lookupSpeedTable(cab);
return slot?slot->targetSpeed:128; if (reg<0)
} return 128;
// returns speed code byte for loco. return speedTable[reg].speedCode;
// This is the most recently send DCC speed packet byte
// or 128 (speed 0, dir forward) on "loco not found".
uint8_t DCC::getLocoSpeedByte(int cab) {
LOCO* slot=lookupSpeedTable(cab,false);
return slot?slot->speedCode:128;
} }
// returns 0 to 7 for frequency // returns 0 to 7 for frequency
@ -181,11 +172,12 @@ uint8_t DCC::getThrottleFrequency(int cab) {
(void)cab; (void)cab;
return 0; return 0;
#else #else
LOCO* slot=lookupSpeedTable(cab); int reg=lookupSpeedTable(cab);
if (!slot) return 0; // use default frequency if (reg<0)
return 0; // use default frequency
// shift out first 29 bits so we have the 3 "frequency bits" left // shift out first 29 bits so we have the 3 "frequency bits" left
uint8_t res = (uint8_t)(slot->functions >>29); uint8_t res = (uint8_t)(speedTable[reg].functions >>29);
//DIAG(F("Speed table %d functions %l shifted %d"), reg, slot->functions, res); //DIAG(F("Speed table %d functions %l shifted %d"), reg, speedTable[reg].functions, res);
return res; return res;
#endif #endif
} }
@ -193,7 +185,9 @@ uint8_t DCC::getThrottleFrequency(int cab) {
// returns direction on loco // returns direction on loco
// or true/forward on "loco not found" // or true/forward on "loco not found"
bool DCC::getThrottleDirection(int cab) { bool DCC::getThrottleDirection(int cab) {
return getThrottleSpeedByte(cab) % 0x80; int reg=lookupSpeedTable(cab);
if (reg<0) return true;
return (speedTable[reg].speedCode & 0x80) !=0;
} }
// Set function to value on or off // Set function to value on or off
@ -226,21 +220,22 @@ bool DCC::setFn( int cab, int16_t functionNumber, bool on) {
if (functionNumber > 31) if (functionNumber > 31)
return true; return true;
LOCO * slot = lookupSpeedTable(cab); int reg = lookupSpeedTable(cab);
if (reg<0) return false;
// Take care of functions: // Take care of functions:
// Set state of function // Set state of function
uint32_t previous=slot->functions; uint32_t previous=speedTable[reg].functions;
uint32_t funcmask = (1UL<<functionNumber); uint32_t funcmask = (1UL<<functionNumber);
if (on) { if (on) {
slot->functions |= funcmask; speedTable[reg].functions |= funcmask;
} else { } else {
slot->functions &= ~funcmask; speedTable[reg].functions &= ~funcmask;
} }
if (slot->functions != previous) { if (speedTable[reg].functions != previous) {
if (functionNumber <= 28) if (functionNumber <= 28)
updateGroupflags(slot->groupFlags, functionNumber); updateGroupflags(speedTable[reg].groupFlags, functionNumber);
CommandDistributor::broadcastLoco(slot); CommandDistributor::broadcastLoco(reg);
} }
return true; return true;
} }
@ -248,13 +243,14 @@ bool DCC::setFn( int cab, int16_t functionNumber, bool on) {
// Flip function state (used from withrottle protocol) // Flip function state (used from withrottle protocol)
void DCC::changeFn( int cab, int16_t functionNumber) { void DCC::changeFn( int cab, int16_t functionNumber) {
if (cab<=0 || functionNumber>31) return; if (cab<=0 || functionNumber>31) return;
auto slot=lookupSpeedTable(cab); int reg = lookupSpeedTable(cab);
if (reg<0) return;
unsigned long funcmask = (1UL<<functionNumber); unsigned long funcmask = (1UL<<functionNumber);
slot->functions ^= funcmask; speedTable[reg].functions ^= funcmask;
if (functionNumber <= 28) { if (functionNumber <= 28) {
updateGroupflags(slot->groupFlags, functionNumber); updateGroupflags(speedTable[reg].groupFlags, functionNumber);
} }
CommandDistributor::broadcastLoco(slot); CommandDistributor::broadcastLoco(reg);
} }
// Report function state (used from withrottle protocol) // Report function state (used from withrottle protocol)
@ -262,10 +258,12 @@ void DCC::changeFn( int cab, int16_t functionNumber) {
int8_t DCC::getFn( int cab, int16_t functionNumber) { int8_t DCC::getFn( int cab, int16_t functionNumber) {
if (cab<=0 || functionNumber>31) if (cab<=0 || functionNumber>31)
return -1; // unknown return -1; // unknown
auto slot = lookupSpeedTable(cab); int reg = lookupSpeedTable(cab);
if (reg<0)
return -1;
unsigned long funcmask = (1UL<<functionNumber); unsigned long funcmask = (1UL<<functionNumber);
return (slot->functions & funcmask)? 1 : 0; return (speedTable[reg].functions & funcmask)? 1 : 0;
} }
// Set the group flag to say we have touched the particular group. // Set the group flag to say we have touched the particular group.
@ -282,22 +280,22 @@ void DCC::updateGroupflags(byte & flags, int16_t functionNumber) {
uint32_t DCC::getFunctionMap(int cab) { uint32_t DCC::getFunctionMap(int cab) {
if (cab<=0) return 0; // unknown pretend all functions off if (cab<=0) return 0; // unknown pretend all functions off
auto slot = lookupSpeedTable(cab,false); int reg = lookupSpeedTable(cab);
return slot?slot->functions:0; return (reg<0)?0:speedTable[reg].functions;
} }
// saves DC frequency (0..3) in spare functions 29,30,31 // saves DC frequency (0..3) in spare functions 29,30,31
void DCC::setDCFreq(int cab,byte freq) { void DCC::setDCFreq(int cab,byte freq) {
if (cab==0 || freq>3) return; if (cab==0 || freq>3) return;
auto slot=lookupSpeedTable(cab,true); auto reg=lookupSpeedTable(cab,true);
// drop and replace F29,30,31 (top 3 bits) // drop and replace F29,30,31 (top 3 bits)
auto newFunctions=slot->functions & 0x1FFFFFFFUL; auto newFunctions=speedTable[reg].functions & 0x1FFFFFFFUL;
if (freq==1) newFunctions |= (1UL<<29); // F29 if (freq==1) newFunctions |= (1UL<<29); // F29
else if (freq==2) newFunctions |= (1UL<<30); // F30 else if (freq==2) newFunctions |= (1UL<<30); // F30
else if (freq==3) newFunctions |= (1UL<<31); // F31 else if (freq==3) newFunctions |= (1UL<<31); // F31
if (newFunctions==slot->functions) return; // no change if (newFunctions==speedTable[reg].functions) return; // no change
slot->functions=newFunctions; speedTable[reg].functions=newFunctions;
CommandDistributor::broadcastLoco(slot); CommandDistributor::broadcastLoco(reg);
} }
void DCC::setAccessory(int address, byte port, bool gate, byte onoff /*= 2*/) { void DCC::setAccessory(int address, byte port, bool gate, byte onoff /*= 2*/) {
@ -753,9 +751,10 @@ void DCC::setConsistId(int id,bool reverse,ACK_CALLBACK callback) {
void DCC::forgetLoco(int cab) { // removes any speed reminders for this loco void DCC::forgetLoco(int cab) { // removes any speed reminders for this loco
setThrottle2(cab,1); // ESTOP this loco if still on track setThrottle2(cab,1); // ESTOP this loco if still on track
auto slot=lookupSpeedTable(cab, false); int reg=lookupSpeedTable(cab, false);
if (slot) { if (reg>=0) {
slot->loco=-1; // no longer used but not end of world speedTable[reg].loco=0;
setThrottle2(cab,1); // ESTOP if this loco still on track
CommandDistributor::broadcastForgetLoco(cab); CommandDistributor::broadcastForgetLoco(cab);
} }
} }
@ -763,7 +762,7 @@ void DCC::forgetAllLocos() { // removes all speed reminders
setThrottle2(0,1); // ESTOP all locos still on track setThrottle2(0,1); // ESTOP all locos still on track
for (int i=0;i<MAX_LOCOS;i++) { for (int i=0;i<MAX_LOCOS;i++) {
if (speedTable[i].loco) CommandDistributor::broadcastForgetLoco(speedTable[i].loco); if (speedTable[i].loco) CommandDistributor::broadcastForgetLoco(speedTable[i].loco);
speedTable[i].loco=0; // no longer used and looks like end speedTable[i].loco=0;
} }
} }
@ -778,14 +777,14 @@ void DCC::issueReminders() {
// if the main track transmitter still has a pending packet, skip this time around. // if the main track transmitter still has a pending packet, skip this time around.
if (!DCCWaveform::mainTrack.isReminderWindowOpen()) return; if (!DCCWaveform::mainTrack.isReminderWindowOpen()) return;
// Move to next loco slot. If occupied, send a reminder. // Move to next loco slot. If occupied, send a reminder.
auto slot = nextLocoReminder; int reg = lastLocoReminder+1;
if (slot >= &speedTable[MAX_LOCOS]) slot=&speedTable[0]; // Go to start of table if (reg > highestUsedReg) reg = 0; // Go to start of table
if (slot->loco > 0) if (speedTable[reg].loco > 0) {
if (!issueReminder(slot)) // have found loco to remind
return; if (issueReminder(reg))
// a loco=0 is at the end of the list, a loco <0 is deleted lastLocoReminder = reg;
if (slot->loco==0) nextLocoReminder = &speedTable[0]; } else
else nextLocoReminder=slot+1; lastLocoReminder = reg;
} }
int16_t normalize(byte speed) { int16_t normalize(byte speed) {
@ -800,27 +799,27 @@ byte dccalize(int16_t speed) {
return (int16_t)-1 - speed; return (int16_t)-1 - speed;
} }
bool DCC::issueReminder(LOCO * slot) { bool DCC::issueReminder(int reg) {
unsigned long functions=slot->functions; unsigned long functions=speedTable[reg].functions;
int loco=slot->loco; int loco=speedTable[reg].loco;
byte flags=slot->groupFlags; byte flags=speedTable[reg].groupFlags;
switch (loopStatus) { switch (loopStatus) {
case 0: { case 0: {
// calculate any momentum change going on // calculate any momentum change going on
auto sc=slot->speedCode; auto sc=speedTable[reg].speedCode;
if (slot->targetSpeed!=sc) { if (speedTable[reg].targetSpeed!=speedTable[reg].speedCode) {
// calculate new speed code // calculate new speed code
auto now=millis(); auto now=millis();
int16_t delay=now-slot->momentum_base; int16_t delay=now-speedTable[reg].momentum_base;
auto millisPerNotch=slot->millis_per_notch; auto millisPerNotch=speedTable[reg].millis_per_notch;
if (millisPerNotch<0) millisPerNotch=defaultMomentum; if (millisPerNotch<0) millisPerNotch=defaultMomentum;
// allow for momentum change to 0 while accelerating/slowing // allow for momentum change to 0 while accelerating/slowing
auto ticks=(millisPerNotch>0)?(delay/millisPerNotch):500; auto ticks=(millisPerNotch>0)?(delay/millisPerNotch):500;
if (ticks>0) { if (ticks>0) {
auto current=normalize(sc); // -128..+127 auto current=normalize(sc); // -128..+127
auto target=normalize(slot->targetSpeed); auto target=normalize(speedTable[reg].targetSpeed);
// DIAG(F("Momentum l=%d ti=%d sc=%d c=%d t=%d"),loco,ticks,sc,current,target); // DIAG(F("Momentum l=%d t=%d sc=%d c=%d t=%d"),loco,ticks,sc,current,target);
if (current<target) { // accelerate if (current<target) { // accelerate
current+=ticks; current+=ticks;
if (current>target) current=target; if (current>target) current=target;
@ -830,13 +829,13 @@ bool DCC::issueReminder(LOCO * slot) {
if (current<target) current=target; if (current<target) current=target;
} }
sc=dccalize(current); sc=dccalize(current);
//DIAG(F("c=%d newsc=%d"),current,sc); // DIAG(F("c=%d t=%d newsc=%d"),current,target,sc);
slot->speedCode=sc; speedTable[reg].speedCode=sc;
TrackManager::setDCSignal(loco,sc); // in case this is a dcc track on this addr TrackManager::setDCSignal(loco,sc); // in case this is a dcc track on this addr
slot->momentum_base=now; speedTable[reg].momentum_base=now;
} }
} }
// DIAG(F("Reminder %d speed %d"),loco,slot->speedCode); // DIAG(F("Reminder %d speed %d"),loco,speedTable[reg].speedCode);
setThrottle2(loco, sc); setThrottle2(loco, sc);
} }
break; break;
@ -900,28 +899,32 @@ byte DCC::cv2(int cv) {
return lowByte(cv); return lowByte(cv);
} }
DCC::LOCO * DCC::lookupSpeedTable(int locoId, bool autoCreate) { int DCC::lookupSpeedTable(int locoId, bool autoCreate) {
// determine speed reg for this loco // determine speed reg for this loco
LOCO * firstEmpty=nullptr; int firstEmpty = MAX_LOCOS;
SLOTLOOP { int reg;
if (firstEmpty==nullptr && slot->loco<=0) firstEmpty=slot; for (reg = 0; reg < MAX_LOCOS; reg++) {
if (slot->loco == locoId) return slot; if (speedTable[reg].loco == locoId) break;
if (slot->loco==0) break; if (speedTable[reg].loco == 0 && firstEmpty == MAX_LOCOS) firstEmpty = reg;
} }
if (!autoCreate) return nullptr;
if (firstEmpty==nullptr) { // return -1 if not found and not auto creating
// return last slot if full if (reg== MAX_LOCOS && !autoCreate) return -1;
DIAG(F("Too many locos, reusing last slot")); if (reg == MAX_LOCOS) reg = firstEmpty;
firstEmpty=&speedTable[MAX_LOCOS-1]; if (reg >= MAX_LOCOS) {
DIAG(F("Too many locos"));
return -1;
} }
// fill first empty slot with new entry if (reg==firstEmpty){
firstEmpty->loco = locoId; speedTable[reg].loco = locoId;
firstEmpty->speedCode=128; // default direction forward speedTable[reg].speedCode=128; // default direction forward
firstEmpty->targetSpeed=128; // default direction forward speedTable[reg].targetSpeed=128; // default direction forward
firstEmpty->groupFlags=0; speedTable[reg].groupFlags=0;
firstEmpty->functions=0; speedTable[reg].functions=0;
firstEmpty->millis_per_notch=-1; // use default speedTable[reg].millis_per_notch=-1; // use default
return firstEmpty; }
if (reg > highestUsedReg) highestUsedReg = reg;
return reg;
} }
bool DCC::setMomentum(int locoId,int16_t millis_per_notch) { bool DCC::setMomentum(int locoId,int16_t millis_per_notch) {
@ -933,42 +936,45 @@ bool DCC::setMomentum(int locoId,int16_t millis_per_notch) {
// We dont copy the default here because it can be changed // We dont copy the default here because it can be changed
// while running and have immediate effect on all locos using -1. // while running and have immediate effect on all locos using -1.
if (locoId<=0 || millis_per_notch<-1) return false; if (locoId<=0 || millis_per_notch<-1) return false;
lookupSpeedTable(locoId,true)->millis_per_notch=millis_per_notch; auto reg=lookupSpeedTable(locoId);
if (reg<0) return false; // table full
speedTable[reg].millis_per_notch=millis_per_notch;
return true; return true;
} }
void DCC::updateLocoReminder(int loco, byte speedCode) {
void DCC::estopAll() { if (loco==0) {
setThrottle2(0,1); // estop all locos // broadcast stop/estop but dont change direction
TrackManager::setDCSignal(0,1); for (int reg = 0; reg <= highestUsedReg; reg++) {
if (speedTable[reg].loco==0) continue;
// remind stop/estop but dont change direction byte newspeed=(speedTable[reg].speedCode & 0x80) | (speedCode & 0x7f);
SLOTLOOP { if (speedTable[reg].speedCode != newspeed) {
if (slot->loco<=0) continue; speedTable[reg].speedCode = newspeed;
byte newspeed=(slot->targetSpeed & 0x80) | 0x01; speedTable[reg].targetSpeed = newspeed;
slot->speedCode = newspeed; CommandDistributor::broadcastLoco(reg);
slot->targetSpeed = newspeed; }
CommandDistributor::broadcastLoco(slot); }
} }
} }
DCC::LOCO DCC::speedTable[MAX_LOCOS]; DCC::LOCO DCC::speedTable[MAX_LOCOS];
DCC::LOCO * DCC::nextLocoReminder = &DCC::speedTable[0]; int DCC::lastLocoReminder = 0;
int DCC::highestUsedReg = 0;
void DCC::displayCabList(Print * stream) { void DCC::displayCabList(Print * stream) {
StringFormatter::send(stream,F("<*\n"));
int used=0; int used=0;
SLOTLOOP { for (int reg = 0; reg <= highestUsedReg; reg++) {
if (slot->loco==0) break; // no more locos if (speedTable[reg].loco>0) {
if (slot->loco>0) {
used ++; used ++;
StringFormatter::send(stream,F("cab=%d, speed=%d, target=%d momentum=%d\n"), StringFormatter::send(stream,F("cab=%d, speed=%d, dir=%c momentum=%d\n"),
slot->loco, slot->speedCode, slot->targetSpeed, speedTable[reg].loco, speedTable[reg].speedCode & 0x7f,
slot->millis_per_notch); (speedTable[reg].speedCode & 0x80) ? 'F':'R',
speedTable[reg].millis_per_notch);
} }
} }
StringFormatter::send(stream,F("Used=%d, max=%d, momentum=%d *>\n"), StringFormatter::send(stream,F("Used=%d, max=%d\n"),used,MAX_LOCOS);
used,MAX_LOCOS, DCC::defaultMomentum);
} }

10
DCC.h
View File

@ -59,10 +59,8 @@ public:
// Public DCC API functions // Public DCC API functions
static void setThrottle(uint16_t cab, uint8_t tSpeed, bool tDirection); static void setThrottle(uint16_t cab, uint8_t tSpeed, bool tDirection);
static void estopAll();
static int8_t getThrottleSpeed(int cab); static int8_t getThrottleSpeed(int cab);
static uint8_t getThrottleSpeedByte(int cab); static uint8_t getThrottleSpeedByte(int cab);
static uint8_t getLocoSpeedByte(int cab); // may lag throttle
static uint8_t getThrottleFrequency(int cab); static uint8_t getThrottleFrequency(int cab);
static bool getThrottleDirection(int cab); static bool getThrottleDirection(int cab);
static void writeCVByteMain(int cab, int cv, byte bValue); static void writeCVByteMain(int cab, int cv, byte bValue);
@ -110,7 +108,7 @@ public:
byte targetSpeed; // speed set by throttle byte targetSpeed; // speed set by throttle
}; };
static LOCO speedTable[MAX_LOCOS]; static LOCO speedTable[MAX_LOCOS];
static LOCO * lookupSpeedTable(int locoId, bool autoCreate=true); static int lookupSpeedTable(int locoId, bool autoCreate=true);
static byte cv1(byte opcode, int cv); static byte cv1(byte opcode, int cv);
static byte cv2(int cv); static byte cv2(int cv);
static bool setMomentum(int locoId,int16_t millis_per_notch); static bool setMomentum(int locoId,int16_t millis_per_notch);
@ -119,9 +117,11 @@ private:
static byte loopStatus; static byte loopStatus;
static int16_t defaultMomentum; // Millis per speed step static int16_t defaultMomentum; // Millis per speed step
static void setThrottle2(uint16_t cab, uint8_t speedCode); static void setThrottle2(uint16_t cab, uint8_t speedCode);
static void updateLocoReminder(int loco, byte speedCode);
static void setFunctionInternal(int cab, byte fByte, byte eByte, byte count); static void setFunctionInternal(int cab, byte fByte, byte eByte, byte count);
static bool issueReminder(LOCO * slot); static bool issueReminder(int reg);
static LOCO* nextLocoReminder; static int lastLocoReminder;
static int highestUsedReg;
static FSH *shieldName; static FSH *shieldName;
static byte globalSpeedsteps; static byte globalSpeedsteps;

View File

@ -289,9 +289,12 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream)
int16_t direction; int16_t direction;
if (params==1) { // <t cab> display state if (params==1) { // <t cab> display state
if (p[0]<=0) break; int16_t slot=DCC::lookupSpeedTable(p[0],false);
CommandDistributor::broadcastLoco(DCC::lookupSpeedTable(p[0],false)); if (slot>=0)
return; CommandDistributor::broadcastLoco(slot);
else // send dummy state speed 0 fwd no functions.
StringFormatter::send(stream,F("<l %d -1 128 0>\n"),p[0]);
return;
} }
if (params == 4) if (params == 4)
@ -583,7 +586,7 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream)
} }
case '!': // ESTOP ALL <!> case '!': // ESTOP ALL <!>
DCC::estopAll(); // this broadcasts speed 1(estop) and sets all reminders to speed 1. DCC::setThrottle(0,1,1); // this broadcasts speed 1(estop) and sets all reminders to speed 1.
return; return;
#ifdef HAS_ENOUGH_MEMORY #ifdef HAS_ENOUGH_MEMORY

View File

@ -683,7 +683,7 @@ void RMFT2::loop2() {
break; break;
case OPCODE_PAUSE: case OPCODE_PAUSE:
DCC::estopAll(); // pause all locos on the track DCC::setThrottle(0,1,true); // pause all locos on the track
pausingTask=this; pausingTask=this;
break; break;

View File

@ -276,7 +276,7 @@ bool RMFT2::parseSlash(Print * stream, byte & paramCount, int16_t p[]) {
switch (p[0]) { switch (p[0]) {
case "PAUSE"_hk: // </ PAUSE> case "PAUSE"_hk: // </ PAUSE>
if (paramCount!=1) return false; if (paramCount!=1) return false;
DCC::estopAll(); // pause all locos on the track DCC::setThrottle(0,1,true); // pause all locos on the track
pausingTask=(RMFT2 *)1; // Impossible task address pausingTask=(RMFT2 *)1; // Impossible task address
return true; return true;

View File

@ -358,7 +358,7 @@ bool TrackManager::setTrackMode(byte trackToSet, TRACK_MODE mode, int16_t dcAddr
} }
void TrackManager::applyDCSpeed(byte t) { void TrackManager::applyDCSpeed(byte t) {
track[t]->setDCSignal(DCC::getLocoSpeedByte(trackDCAddr[t]), track[t]->setDCSignal(DCC::getThrottleSpeedByte(trackDCAddr[t]),
DCC::getThrottleFrequency(trackDCAddr[t])); DCC::getThrottleFrequency(trackDCAddr[t]));
} }