From 2d58d06b193065f45506497cd6564b0eea1e1c2f Mon Sep 17 00:00:00 2001 From: Asbelos Date: Thu, 25 Jul 2024 10:08:03 +0100 Subject: [PATCH] dual momentum --- DCC.cpp | 60 ++++++++++++++++++++++++++++----------------- DCC.h | 11 ++++++--- DCCEXParser.cpp | 7 +++--- EXRAIL2.cpp | 2 +- EXRAIL2MacroReset.h | 2 +- EXRAILMacros.h | 2 +- version.h | 3 ++- 7 files changed, 55 insertions(+), 32 deletions(-) diff --git a/DCC.cpp b/DCC.cpp index 9bbd626..fabfe84 100644 --- a/DCC.cpp +++ b/DCC.cpp @@ -74,20 +74,28 @@ void DCC::begin() { #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) { - if (cab==0) { - if (tSpeed==1) estopAll(); // ESTOP broadcast fix - return; + if (tSpeed==1) { + if (cab==0) { + estopAll(); // ESTOP broadcast fix + return; + } } byte speedCode = (tSpeed & 0x7F) + tDirection * 128; LOCO * slot=lookupSpeedTable(cab); if (slot->targetSpeed==speedCode) return; slot->targetSpeed=speedCode; - auto momentum=slot->millis_per_notch; - if (momentum<0) momentum=defaultMomentum; - if (momentum>0 && tSpeed!=1) { // not ESTOP + byte momentum=getMomentum(slot);; + if (momentum && tSpeed!=1) { // not ESTOP // we dont throttle speed, we just let the reminders take it to target slot->momentum_base=millis(); } @@ -813,8 +821,7 @@ bool DCC::issueReminder(LOCO * slot) { // calculate new speed code auto now=millis(); int16_t delay=now-slot->momentum_base; - auto millisPerNotch=slot->millis_per_notch; - if (millisPerNotch<0) millisPerNotch=defaultMomentum; + auto millisPerNotch=MOMENTUM_FACTOR * (int16_t)getMomentum(slot); // allow for momentum change to 0 while accelerating/slowing auto ticks=(millisPerNotch>0)?(delay/millisPerNotch):500; if (ticks>0) { @@ -920,20 +927,29 @@ DCC::LOCO * DCC::lookupSpeedTable(int locoId, bool autoCreate) { firstEmpty->targetSpeed=128; // default direction forward firstEmpty->groupFlags=0; firstEmpty->functions=0; - firstEmpty->millis_per_notch=-1; // use default + firstEmpty->momentumA=MOMENTUM_USE_DEFAULT; + firstEmpty->momentumD=MOMENTUM_USE_DEFAULT; return firstEmpty; } -bool DCC::setMomentum(int locoId,int16_t millis_per_notch) { - if (locoId==0 && millis_per_notch>=0) { - defaultMomentum=millis_per_notch; +bool DCC::setMomentum(int locoId,int16_t accelerating, int16_t decelerating) { + if (locoId<=0 ) return false; + if (locoId==0) { + if (accelerating<0 || decelerating<0) return false; + defaultMomentumA=accelerating/MOMENTUM_FACTOR; + defaultMomentumD=decelerating/MOMENTUM_FACTOR; return true; } - // millis=-1 is ok and means this loco should use the default. - // We dont copy the default here because it can be changed - // while running and have immediate effect on all locos using -1. - if (locoId<=0 || millis_per_notch<-1) return false; - lookupSpeedTable(locoId,true)->millis_per_notch=millis_per_notch; + // -1 is ok and means this loco should use the default. + if (accelerating<-1 || decelerating<-1) return false; + if (accelerating>2000 || decelerating>2000) return false; + + // 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; } @@ -964,11 +980,11 @@ void DCC::displayCabList(Print * stream) { if (slot->loco==0) break; // no more locos if (slot->loco>0) { 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->millis_per_notch); + slot->momentumA, slot->momentumD); } } - StringFormatter::send(stream,F("Used=%d, max=%d, momentum=%d *>\n"), - used,MAX_LOCOS, DCC::defaultMomentum); + StringFormatter::send(stream,F("Used=%d, max=%d, momentum=%d/%d *>\n"), + used,MAX_LOCOS, DCC::defaultMomentumA,DCC::defaultMomentumD); } diff --git a/DCC.h b/DCC.h index faa43f7..e5a2f6c 100644 --- a/DCC.h +++ b/DCC.h @@ -106,18 +106,23 @@ public: uint32_t functions; // Momentum management variables 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 }; + 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 * lookupSpeedTable(int locoId, bool autoCreate=true); static byte cv1(byte opcode, 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: 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 setFunctionInternal(int cab, byte fByte, byte eByte, byte count); static bool issueReminder(LOCO * slot); diff --git a/DCCEXParser.cpp b/DCCEXParser.cpp index 27462fe..1acf197 100644 --- a/DCCEXParser.cpp +++ b/DCCEXParser.cpp @@ -430,9 +430,10 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream) return; #endif - case 'm': // - if (params!=2) break; - if (DCC::setMomentum(p[0],p[1])) return; + case 'm': // + if (params<2 || params>3) break; + if (params==2) p[2]=p[1]; + if (DCC::setMomentum(p[0],p[1],p[2])) return; break; case 'M': // WRITE TRANSPARENT DCC PACKET MAIN diff --git a/EXRAIL2.cpp b/EXRAIL2.cpp index 965d0c4..85cbbec 100644 --- a/EXRAIL2.cpp +++ b/EXRAIL2.cpp @@ -568,7 +568,7 @@ void RMFT2::loop2() { break; case OPCODE_MOMENTUM: - DCC::setMomentum(loco,operand); + DCC::setMomentum(loco,operand,getOperand(1)); break; case OPCODE_FORGET: diff --git a/EXRAIL2MacroReset.h b/EXRAIL2MacroReset.h index 8773787..8ed7111 100644 --- a/EXRAIL2MacroReset.h +++ b/EXRAIL2MacroReset.h @@ -266,7 +266,7 @@ #define LCC(eventid) #define LCCX(senderid,eventid) #define LCD(row,msg) -#define MOMENTUM(mspertick) +#define MOMENTUM(accel,decel...) #define SCREEN(display,row,msg) #define LCN(msg) #define MESSAGE(msg) diff --git a/EXRAILMacros.h b/EXRAILMacros.h index 4f7d41a..f7041aa 100644 --- a/EXRAILMacros.h +++ b/EXRAILMacros.h @@ -551,7 +551,7 @@ int RMFT2::onLCCLookup[RMFT2::countLCCLookup]; #define STEALTH_GLOBAL(code...) #define LCN(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 ONACTIVATE(addr,subaddr) OPCODE_ONACTIVATE,V(addr<<2|subaddr), #define ONACTIVATEL(linear) OPCODE_ONACTIVATE,V(linear+3), diff --git a/version.h b/version.h index 52fbbb9..72a017a 100644 --- a/version.h +++ b/version.h @@ -3,7 +3,8 @@ #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.70 - IO_RocoDriver renamed to IO_EncoderThrottle. // - and included in IODEvice.h (circular dependency removed)