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

dual momentum

This commit is contained in:
Asbelos 2024-07-25 10:08:03 +01:00
parent 3ac2fff70d
commit 2d58d06b19
7 changed files with 55 additions and 32 deletions

60
DCC.cpp
View File

@ -74,20 +74,28 @@ void DCC::begin() {
#endif #endif
} }
int16_t DCC::defaultMomentum=0; byte DCC::defaultMomentumA=0;
byte DCC::defaultMomentumD=0;
byte DCC::getMomentum(LOCO * slot) {
if ((slot->targetSpeed & 0x7f) > (slot->speedCode & 0x7f)) // accelerate
return slot->momentumA==MOMENTUM_USE_DEFAULT ? defaultMomentumA : slot->momentumA;
return slot->momentumD==MOMENTUM_USE_DEFAULT ? defaultMomentumD : slot->momentumD;
}
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) {
if (tSpeed==1) estopAll(); // ESTOP broadcast fix if (cab==0) {
return; estopAll(); // ESTOP broadcast fix
return;
}
} }
byte speedCode = (tSpeed & 0x7F) + tDirection * 128; byte speedCode = (tSpeed & 0x7F) + tDirection * 128;
LOCO * slot=lookupSpeedTable(cab); LOCO * slot=lookupSpeedTable(cab);
if (slot->targetSpeed==speedCode) return; if (slot->targetSpeed==speedCode) return;
slot->targetSpeed=speedCode; slot->targetSpeed=speedCode;
auto momentum=slot->millis_per_notch; byte momentum=getMomentum(slot);;
if (momentum<0) momentum=defaultMomentum; if (momentum && 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(); slot->momentum_base=millis();
} }
@ -813,8 +821,7 @@ bool DCC::issueReminder(LOCO * slot) {
// 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-slot->momentum_base;
auto millisPerNotch=slot->millis_per_notch; auto millisPerNotch=MOMENTUM_FACTOR * (int16_t)getMomentum(slot);
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) {
@ -920,20 +927,29 @@ DCC::LOCO * DCC::lookupSpeedTable(int locoId, bool autoCreate) {
firstEmpty->targetSpeed=128; // default direction forward firstEmpty->targetSpeed=128; // default direction forward
firstEmpty->groupFlags=0; firstEmpty->groupFlags=0;
firstEmpty->functions=0; firstEmpty->functions=0;
firstEmpty->millis_per_notch=-1; // use default firstEmpty->momentumA=MOMENTUM_USE_DEFAULT;
firstEmpty->momentumD=MOMENTUM_USE_DEFAULT;
return firstEmpty; return firstEmpty;
} }
bool DCC::setMomentum(int locoId,int16_t millis_per_notch) { bool DCC::setMomentum(int locoId,int16_t accelerating, int16_t decelerating) {
if (locoId==0 && millis_per_notch>=0) { if (locoId<=0 ) return false;
defaultMomentum=millis_per_notch; if (locoId==0) {
if (accelerating<0 || decelerating<0) return false;
defaultMomentumA=accelerating/MOMENTUM_FACTOR;
defaultMomentumD=decelerating/MOMENTUM_FACTOR;
return true; return true;
} }
// millis=-1 is ok and means this loco should use the default. // -1 is ok and means this loco should use the default.
// We dont copy the default here because it can be changed if (accelerating<-1 || decelerating<-1) return false;
// while running and have immediate effect on all locos using -1. if (accelerating>2000 || decelerating>2000) return false;
if (locoId<=0 || millis_per_notch<-1) return false;
lookupSpeedTable(locoId,true)->millis_per_notch=millis_per_notch; // Values stored are 255=MOMENTUM_USE_DEFAULT, or millis/MOMENTUM_FACTOR.
// This is to keep the values in a byte rather than int16
// thus saving 2 bytes RAM per loco slot.
LOCO* slot=lookupSpeedTable(locoId,true);
slot->momentumA=(accelerating<0)? MOMENTUM_USE_DEFAULT: (accelerating/MOMENTUM_FACTOR);
slot->momentumD=(decelerating<0)? MOMENTUM_USE_DEFAULT: (decelerating/MOMENTUM_FACTOR);
return true; return true;
} }
@ -964,11 +980,11 @@ void DCC::displayCabList(Print * stream) {
if (slot->loco==0) break; // no more locos if (slot->loco==0) break; // no more locos
if (slot->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, target=%d momentum=%d/%d\n"),
slot->loco, slot->speedCode, slot->targetSpeed, slot->loco, slot->speedCode, slot->targetSpeed,
slot->millis_per_notch); slot->momentumA, slot->momentumD);
} }
} }
StringFormatter::send(stream,F("Used=%d, max=%d, momentum=%d *>\n"), StringFormatter::send(stream,F("Used=%d, max=%d, momentum=%d/%d *>\n"),
used,MAX_LOCOS, DCC::defaultMomentum); used,MAX_LOCOS, DCC::defaultMomentumA,DCC::defaultMomentumD);
} }

11
DCC.h
View File

@ -106,18 +106,23 @@ public:
uint32_t functions; uint32_t functions;
// Momentum management variables // Momentum management variables
uint32_t momentum_base; // millis() when speed modified under momentum uint32_t momentum_base; // millis() when speed modified under momentum
int16_t millis_per_notch; // 0=no momentum, -1=defaultMomentum byte momentumA, momentumD;
byte targetSpeed; // speed set by throttle byte targetSpeed; // speed set by throttle
}; };
static const int16_t MOMENTUM_FACTOR=8;
static const byte MOMENTUM_USE_DEFAULT=255;
static byte getMomentum(LOCO * slot);
static LOCO speedTable[MAX_LOCOS]; static LOCO speedTable[MAX_LOCOS];
static LOCO * lookupSpeedTable(int locoId, bool autoCreate=true); static LOCO * 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 accelerating, int16_t decelerating);
private: private:
static byte loopStatus; static byte loopStatus;
static int16_t defaultMomentum; // Millis per speed step static byte defaultMomentumA; // Accelerating
static byte defaultMomentumD; // Accelerating
static void setThrottle2(uint16_t cab, uint8_t speedCode); static void setThrottle2(uint16_t cab, uint8_t 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(LOCO * slot);

View File

@ -430,9 +430,10 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream)
return; return;
#endif #endif
case 'm': // <m cabid momentum> case 'm': // <m cabid momentum [braking]>
if (params!=2) break; if (params<2 || params>3) break;
if (DCC::setMomentum(p[0],p[1])) return; if (params==2) p[2]=p[1];
if (DCC::setMomentum(p[0],p[1],p[2])) return;
break; break;
case 'M': // WRITE TRANSPARENT DCC PACKET MAIN <M REG X1 ... X9> case 'M': // WRITE TRANSPARENT DCC PACKET MAIN <M REG X1 ... X9>

View File

@ -568,7 +568,7 @@ void RMFT2::loop2() {
break; break;
case OPCODE_MOMENTUM: case OPCODE_MOMENTUM:
DCC::setMomentum(loco,operand); DCC::setMomentum(loco,operand,getOperand(1));
break; break;
case OPCODE_FORGET: case OPCODE_FORGET:

View File

@ -266,7 +266,7 @@
#define LCC(eventid) #define LCC(eventid)
#define LCCX(senderid,eventid) #define LCCX(senderid,eventid)
#define LCD(row,msg) #define LCD(row,msg)
#define MOMENTUM(mspertick) #define MOMENTUM(accel,decel...)
#define SCREEN(display,row,msg) #define SCREEN(display,row,msg)
#define LCN(msg) #define LCN(msg)
#define MESSAGE(msg) #define MESSAGE(msg)

View File

@ -551,7 +551,7 @@ int RMFT2::onLCCLookup[RMFT2::countLCCLookup];
#define STEALTH_GLOBAL(code...) #define STEALTH_GLOBAL(code...)
#define LCN(msg) PRINT(msg) #define LCN(msg) PRINT(msg)
#define MESSAGE(msg) PRINT(msg) #define MESSAGE(msg) PRINT(msg)
#define MOMENTUM(mspertick) OPCODE_MOMENTUM,V(mspertick), #define MOMENTUM(accel,decel...) OPCODE_MOMENTUM,V(accel),OPCODE_PAD,V(#decel[0]?decel+0:accel),
#define MOVETT(id,steps,activity) OPCODE_SERVO,V(id),OPCODE_PAD,V(steps),OPCODE_PAD,V(EXTurntable::activity),OPCODE_PAD,V(0), #define MOVETT(id,steps,activity) OPCODE_SERVO,V(id),OPCODE_PAD,V(steps),OPCODE_PAD,V(EXTurntable::activity),OPCODE_PAD,V(0),
#define ONACTIVATE(addr,subaddr) OPCODE_ONACTIVATE,V(addr<<2|subaddr), #define ONACTIVATE(addr,subaddr) OPCODE_ONACTIVATE,V(addr<<2|subaddr),
#define ONACTIVATEL(linear) OPCODE_ONACTIVATE,V(linear+3), #define ONACTIVATEL(linear) OPCODE_ONACTIVATE,V(linear+3),

View File

@ -3,7 +3,8 @@
#include "StringFormatter.h" #include "StringFormatter.h"
#define VERSION "5.2.71" #define VERSION "5.2.72"
// 5.2.72 - Momentum.
// 5.2.71 - Broadcasts of loco forgets. // 5.2.71 - Broadcasts of loco forgets.
// 5.2.70 - IO_RocoDriver renamed to IO_EncoderThrottle. // 5.2.70 - IO_RocoDriver renamed to IO_EncoderThrottle.
// - and included in IODEvice.h (circular dependency removed) // - and included in IODEvice.h (circular dependency removed)