From 337af77a030ca57f9bfa5e1343965fe4069aa7aa Mon Sep 17 00:00:00 2001 From: Harald Barth Date: Fri, 10 Nov 2023 20:33:14 +0100 Subject: [PATCH 01/10] booster test --- MotorDriver.cpp | 4 ++++ MotorDriver.h | 38 ++++++++++++++++++++++++++++++++++++-- TrackManager.cpp | 19 +++++++++++++------ 3 files changed, 53 insertions(+), 8 deletions(-) diff --git a/MotorDriver.cpp b/MotorDriver.cpp index 61e229f..15b5607 100644 --- a/MotorDriver.cpp +++ b/MotorDriver.cpp @@ -605,6 +605,10 @@ void MotorDriver::checkPowerOverload(bool useProgLimit, byte trackno) { DIAG(F("TRACK %c ALERT FAULT"), trackno + 'A'); } setPower(POWERMODE::ALERT); + if (trackMode & (TRACK_MODE_MAIN|TRACK_MODE_EXT)){ // add (&& isAutoreverse) later + DIAG(F("TRACK %c INVERT"), trackno + 'A'); + invertOutput(); + } break; } // all well diff --git a/MotorDriver.h b/MotorDriver.h index 20a91d3..c6e06b8 100644 --- a/MotorDriver.h +++ b/MotorDriver.h @@ -148,7 +148,9 @@ class MotorDriver { // otherwise the call from interrupt context can undo whatever we do // from outside interrupt void setBrake( bool on, bool interruptContext=false); - __attribute__((always_inline)) inline void setSignal( bool high) { + __attribute__((always_inline)) inline void setSignal( bool high) { + if (invertPhase) + high = !high; if (trackPWM) { DCCTimer::setPWM(signalPin,high); } @@ -168,6 +170,12 @@ class MotorDriver { pinMode(signalPin, OUTPUT); else pinMode(signalPin, INPUT); + if (signalPin2 != UNUSED_PIN) { + if (on) + pinMode(signalPin2, OUTPUT); + else + pinMode(signalPin2, INPUT); + } }; inline pinpair getSignalPin() { return pinpair(signalPin,signalPin2); }; void setDCSignal(byte speedByte); @@ -232,6 +240,32 @@ class MotorDriver { #endif inline void setMode(TRACK_MODE m) { trackMode = m; + invertOutput(trackMode & TRACK_MODE_DCX);// change later to TRACK_MODE_INVERTED? + }; + inline void invertOutput() { // toggles output inversion + invertPhase = !invertPhase; + invertOutput(invertPhase); + }; + inline void invertOutput(bool b) { // sets output inverted or not + if (b) + invertPhase = 1; + else + invertPhase = 0; +#if defined(ARDUINO_ARCH_ESP32) + pinpair p = getSignalPin(); + uint32_t *outreg = (uint32_t *)(GPIO_FUNC0_OUT_SEL_CFG_REG + 4*p.pin); + if (invertPhase) // set or clear the invert bit in the gpio out register + *outreg |= ((uint32_t)0x1 << GPIO_FUNC0_OUT_INV_SEL_S); + else + *outreg &= ~((uint32_t)0x1 << GPIO_FUNC0_OUT_INV_SEL_S); + if (p.invpin != UNUSED_PIN) { + outreg = (uint32_t *)(GPIO_FUNC0_OUT_SEL_CFG_REG + 4*p.invpin); + if (invertPhase) // clear or set the invert bit in the gpio out register + *outreg &= ~((uint32_t)0x1 << GPIO_FUNC0_OUT_INV_SEL_S); + else + *outreg |= ((uint32_t)0x1 << GPIO_FUNC0_OUT_INV_SEL_S); + } +#endif }; inline TRACK_MODE getMode() { return trackMode; @@ -263,7 +297,7 @@ class MotorDriver { bool invertBrake; // brake pin passed as negative means pin is inverted bool invertPower; // power pin passed as negative means pin is inverted bool invertFault; // fault pin passed as negative means pin is inverted - + bool invertPhase = 0; // phase of out pin is inverted // Raw to milliamp conversion factors avoiding float data types. // Milliamps=rawADCreading * sensefactorInternal / senseScale // diff --git a/TrackManager.cpp b/TrackManager.cpp index dedf45e..772f64e 100644 --- a/TrackManager.cpp +++ b/TrackManager.cpp @@ -197,8 +197,8 @@ void TrackManager::setPROGSignal( bool on) { void TrackManager::setDCSignal(int16_t cab, byte speedbyte) { FOR_EACH_TRACK(t) { if (trackDCAddr[t]!=cab && cab != 0) continue; - if (track[t]->getMode()==TRACK_MODE_DC) track[t]->setDCSignal(speedbyte); - else if (track[t]->getMode()==TRACK_MODE_DCX) track[t]->setDCSignal(speedbyte ^ 128); + if (track[t]->getMode() & (TRACK_MODE_DC|TRACK_MODE_DCX)) + track[t]->setDCSignal(speedbyte); } } @@ -223,11 +223,18 @@ bool TrackManager::setTrackMode(byte trackToSet, TRACK_MODE mode, int16_t dcAddr pinpair p = track[trackToSet]->getSignalPin(); //DIAG(F("Track=%c remove pin %d"),trackToSet+'A', p.pin); gpio_reset_pin((gpio_num_t)p.pin); - pinMode(p.pin, OUTPUT); // gpio_reset_pin may reset to input if (p.invpin != UNUSED_PIN) { //DIAG(F("Track=%c remove ^pin %d"),trackToSet+'A', p.invpin); gpio_reset_pin((gpio_num_t)p.invpin); - pinMode(p.invpin, OUTPUT); // gpio_reset_pin may reset to input + } + + if (mode == TRACK_MODE_EXT) { + pinMode(26, INPUT); + gpio_matrix_in(26, SIG_IN_FUNC228_IDX, false); //pads 224 to 228 available as loopback + gpio_matrix_out(p.pin, SIG_IN_FUNC228_IDX, false, false); + if (p.invpin != UNUSED_PIN) { + gpio_matrix_out(p.invpin, SIG_IN_FUNC228_IDX, true /*inverted*/, false); + } } #endif #ifndef DISABLE_PROG @@ -261,10 +268,12 @@ bool TrackManager::setTrackMode(byte trackToSet, TRACK_MODE mode, int16_t dcAddr track[trackToSet]->setBrake(false); } +#ifndef ARDUINO_ARCH_ESP32 // EXT is a special case where the signal pin is // turned off. So unless that is set, the signal // pin should be turned on track[trackToSet]->enableSignal(mode != TRACK_MODE_EXT); +#endif #ifndef ARDUINO_ARCH_ESP32 // re-evaluate HighAccuracy mode @@ -320,8 +329,6 @@ bool TrackManager::setTrackMode(byte trackToSet, TRACK_MODE mode, int16_t dcAddr void TrackManager::applyDCSpeed(byte t) { uint8_t speedByte=DCC::getThrottleSpeedByte(trackDCAddr[t]); - if (track[t]->getMode()==TRACK_MODE_DCX) - speedByte = speedByte ^ 128; // reverse direction bit track[t]->setDCSignal(speedByte); } From 2f3d489f1836d5ed1f6650b65bafc7d7a104ac54 Mon Sep 17 00:00:00 2001 From: Harald Barth Date: Fri, 10 Nov 2023 23:58:30 +0100 Subject: [PATCH 02/10] ESP32: autoreverse and booster prototype --- EXRAIL2.cpp | 2 +- MotorDriver.cpp | 2 +- MotorDriver.h | 12 +++- TrackManager.cpp | 162 ++++++++++++++++++++++++++--------------------- TrackManager.h | 2 +- 5 files changed, 102 insertions(+), 78 deletions(-) diff --git a/EXRAIL2.cpp b/EXRAIL2.cpp index c902708..2e9761a 100644 --- a/EXRAIL2.cpp +++ b/EXRAIL2.cpp @@ -857,7 +857,7 @@ void RMFT2::loop2() { // If DC/DCX use my loco for DC address { TRACK_MODE mode = (TRACK_MODE)(operand>>8); - int16_t cab=(mode==TRACK_MODE_DC || mode==TRACK_MODE_DCX) ? loco : 0; + int16_t cab=(mode & TRACK_MODE_DC) ? loco : 0; TrackManager::setTrackMode(operand & 0x0F, mode, cab); } break; diff --git a/MotorDriver.cpp b/MotorDriver.cpp index 15b5607..c9b820e 100644 --- a/MotorDriver.cpp +++ b/MotorDriver.cpp @@ -605,7 +605,7 @@ void MotorDriver::checkPowerOverload(bool useProgLimit, byte trackno) { DIAG(F("TRACK %c ALERT FAULT"), trackno + 'A'); } setPower(POWERMODE::ALERT); - if (trackMode & (TRACK_MODE_MAIN|TRACK_MODE_EXT)){ // add (&& isAutoreverse) later + if ((trackMode & TRACK_MODE_AUTOINV) && (trackMode & (TRACK_MODE_MAIN|TRACK_MODE_EXT|TRACK_MODE_BOOST))){ DIAG(F("TRACK %c INVERT"), trackno + 'A'); invertOutput(); } diff --git a/MotorDriver.h b/MotorDriver.h index c6e06b8..db2ccc5 100644 --- a/MotorDriver.h +++ b/MotorDriver.h @@ -3,7 +3,7 @@ * © 2021 Mike S * © 2021 Fred Decker * © 2020 Chris Harlow - * © 2022 Harald Barth + * © 2022,2023 Harald Barth * All rights reserved. * * This file is part of CommandStation-EX @@ -28,8 +28,14 @@ #include "DCCTimer.h" // use powers of two so we can do logical and/or on the track modes in if clauses. +// RACK_MODE_DCX is (TRACK_MODE_DC|TRACK_MODE_INV) +template inline T operator~ (T a) { return (T)~(int)a; } +template inline T operator| (T a, T b) { return (T)((int)a | (int)b); } +template inline T operator& (T a, T b) { return (T)((int)a & (int)b); } +template inline T operator^ (T a, T b) { return (T)((int)a ^ (int)b); } enum TRACK_MODE : byte {TRACK_MODE_NONE = 1, TRACK_MODE_MAIN = 2, TRACK_MODE_PROG = 4, - TRACK_MODE_DC = 8, TRACK_MODE_DCX = 16, TRACK_MODE_EXT = 32}; + TRACK_MODE_DC = 8, TRACK_MODE_EXT = 16, TRACK_MODE_BOOST = 32, + TRACK_MODE_INV = 64, TRACK_MODE_DCX = 72, TRACK_MODE_AUTOINV = 128}; #define setHIGH(fastpin) *fastpin.inout |= fastpin.maskHIGH #define setLOW(fastpin) *fastpin.inout &= fastpin.maskLOW @@ -240,7 +246,7 @@ class MotorDriver { #endif inline void setMode(TRACK_MODE m) { trackMode = m; - invertOutput(trackMode & TRACK_MODE_DCX);// change later to TRACK_MODE_INVERTED? + invertOutput(trackMode & TRACK_MODE_INV); }; inline void invertOutput() { // toggles output inversion invertPhase = !invertPhase; diff --git a/TrackManager.cpp b/TrackManager.cpp index 772f64e..1fffb0b 100644 --- a/TrackManager.cpp +++ b/TrackManager.cpp @@ -1,6 +1,6 @@ /* * © 2022 Chris Harlow - * © 2022 Harald Barth + * © 2022,2023 Harald Barth * © 2023 Colin Murdoch * All rights reserved. * @@ -45,6 +45,9 @@ const int16_t HASH_KEYWORD_DC = 2183; const int16_t HASH_KEYWORD_DCX = 6463; // DC reversed polarity const int16_t HASH_KEYWORD_EXT = 8201; // External DCC signal const int16_t HASH_KEYWORD_A = 65; // parser makes single chars the ascii. +const int16_t HASH_KEYWORD_AUTO = -5457; +const int16_t HASH_KEYWORD_BOOST = 11269; +const int16_t HASH_KEYWORD_INV = 11857; MotorDriver * TrackManager::track[MAX_TRACKS]; int16_t TrackManager::trackDCAddr[MAX_TRACKS]; @@ -87,7 +90,7 @@ void TrackManager::sampleCurrent() { if (!waiting) { // look for a valid track to sample or until we are around while (true) { - if (track[tr]->getMode() & ( TRACK_MODE_MAIN|TRACK_MODE_PROG|TRACK_MODE_DC|TRACK_MODE_DCX|TRACK_MODE_EXT )) { + if (track[tr]->getMode() & ( TRACK_MODE_MAIN|TRACK_MODE_PROG|TRACK_MODE_DC|TRACK_MODE_BOOST|TRACK_MODE_EXT )) { track[tr]->startCurrentFromHW(); // for scope debug track[1]->setBrake(1); waiting = true; @@ -197,7 +200,7 @@ void TrackManager::setPROGSignal( bool on) { void TrackManager::setDCSignal(int16_t cab, byte speedbyte) { FOR_EACH_TRACK(t) { if (trackDCAddr[t]!=cab && cab != 0) continue; - if (track[t]->getMode() & (TRACK_MODE_DC|TRACK_MODE_DCX)) + if (track[t]->getMode() & TRACK_MODE_DC) track[t]->setDCSignal(speedbyte); } } @@ -207,7 +210,7 @@ bool TrackManager::setTrackMode(byte trackToSet, TRACK_MODE mode, int16_t dcAddr //DIAG(F("Track=%c Mode=%d"),trackToSet+'A', mode); // DC tracks require a motorDriver that can set brake! - if (mode==TRACK_MODE_DC || mode==TRACK_MODE_DCX) { + if (mode & TRACK_MODE_DC) { #if defined(ARDUINO_AVR_UNO) DIAG(F("Uno has no PWM timers available for DC")); return false; @@ -227,24 +230,30 @@ bool TrackManager::setTrackMode(byte trackToSet, TRACK_MODE mode, int16_t dcAddr //DIAG(F("Track=%c remove ^pin %d"),trackToSet+'A', p.invpin); gpio_reset_pin((gpio_num_t)p.invpin); } - - if (mode == TRACK_MODE_EXT) { - pinMode(26, INPUT); + if (mode & TRACK_MODE_BOOST) { + DIAG(F("Track=%c mode boost pin %d"),trackToSet+'A', p.pin); + pinMode(26, INPUT); // hardcoded XXX gpio_matrix_in(26, SIG_IN_FUNC228_IDX, false); //pads 224 to 228 available as loopback gpio_matrix_out(p.pin, SIG_IN_FUNC228_IDX, false, false); if (p.invpin != UNUSED_PIN) { gpio_matrix_out(p.invpin, SIG_IN_FUNC228_IDX, true /*inverted*/, false); } + } else if (mode & (TRACK_MODE_MAIN | TRACK_MODE_PROG | TRACK_MODE_DC)) { + // gpio_reset_pin may reset to input + pinMode(p.pin, OUTPUT); + if (p.invpin != UNUSED_PIN) + pinMode(p.invpin, OUTPUT); } + #endif #ifndef DISABLE_PROG - if (mode==TRACK_MODE_PROG) { + if (mode & TRACK_MODE_PROG) { #else if (false) { #endif // only allow 1 track to be prog FOR_EACH_TRACK(t) - if (track[t]->getMode()==TRACK_MODE_PROG && t != trackToSet) { + if ( (track[t]->getMode() & TRACK_MODE_PROG) && t != trackToSet) { track[t]->setPower(POWERMODE::OFF); track[t]->setMode(TRACK_MODE_NONE); track[t]->makeProgTrack(false); // revoke prog track special handling @@ -262,18 +271,20 @@ bool TrackManager::setTrackMode(byte trackToSet, TRACK_MODE mode, int16_t dcAddr // state, otherwise trains run away or just dont move. // This can be done BEFORE the PWM-Timer evaluation (methinks) - if (!(mode==TRACK_MODE_DC || mode==TRACK_MODE_DCX)) { + if (!(mode & TRACK_MODE_DC)) { // DCC tracks need to have set the PWM to zero or they will not work. track[trackToSet]->detachDCSignal(); track[trackToSet]->setBrake(false); } -#ifndef ARDUINO_ARCH_ESP32 - // EXT is a special case where the signal pin is - // turned off. So unless that is set, the signal - // pin should be turned on - track[trackToSet]->enableSignal(mode != TRACK_MODE_EXT); -#endif + // BOOST: + // Leave it as is + // otherwise: + // EXT is a special case where the signal pin is + // turned off. So unless that is set, the signal + // pin should be turned on + if (!(mode & TRACK_MODE_BOOST)) + track[trackToSet]->enableSignal(!(mode & TRACK_MODE_EXT)); #ifndef ARDUINO_ARCH_ESP32 // re-evaluate HighAccuracy mode @@ -283,7 +294,7 @@ bool TrackManager::setTrackMode(byte trackToSet, TRACK_MODE mode, int16_t dcAddr // DC tracks must not have the DCC PWM switched on // so we globally turn it off if one of the PWM // capable tracks is now DC or DCX. - if (track[t]->getMode()==TRACK_MODE_DC || track[t]->getMode()==TRACK_MODE_DCX) { + if (track[t]->getMode() & TRACK_MODE_DC) { if (track[t]->isPWMCapable()) { canDo=false; // this track is capable but can not run PWM break; // in this mode, so abort and prevent globally below @@ -291,7 +302,7 @@ bool TrackManager::setTrackMode(byte trackToSet, TRACK_MODE mode, int16_t dcAddr track[t]->trackPWM=false; // this track sure can not run with PWM //DIAG(F("Track %c trackPWM 0 (not capable)"), t+'A'); } - } else if (track[t]->getMode()==TRACK_MODE_MAIN || track[t]->getMode()==TRACK_MODE_PROG) { + } else if (track[t]->getMode() & (TRACK_MODE_MAIN |TRACK_MODE_PROG)) { track[t]->trackPWM = track[t]->isPWMCapable(); // trackPWM is still a guess here //DIAG(F("Track %c trackPWM %d"), t+'A', track[t]->trackPWM); canDo &= track[t]->trackPWM; @@ -309,10 +320,12 @@ bool TrackManager::setTrackMode(byte trackToSet, TRACK_MODE mode, int16_t dcAddr #else // For ESP32 we just reinitialize the DCC Waveform DCCWaveform::begin(); + // setMode() again AFTER Waveform::begin() of ESP32 fixes INVERTED signal + track[trackToSet]->setMode(mode); #endif // This block must be AFTER the PWM-Timer modifications - if (mode==TRACK_MODE_DC || mode==TRACK_MODE_DCX) { + if (mode & TRACK_MODE_DC) { // DC tracks need to be given speed of the throttle for that cab address // otherwise will not match other tracks on same cab. // This also needs to allow for inverted DCX @@ -321,7 +334,7 @@ bool TrackManager::setTrackMode(byte trackToSet, TRACK_MODE mode, int16_t dcAddr // Normal running tracks are set to the global power state track[trackToSet]->setPower( - (mode==TRACK_MODE_MAIN || mode==TRACK_MODE_DC || mode==TRACK_MODE_DCX || mode==TRACK_MODE_EXT) ? + (mode & (TRACK_MODE_MAIN | TRACK_MODE_DC | TRACK_MODE_EXT | TRACK_MODE_BOOST)) ? mainPowerGuess : POWERMODE::OFF); //DIAG(F("TrackMode=%d"),mode); return true; @@ -361,11 +374,20 @@ bool TrackManager::parseJ(Print *stream, int16_t params, int16_t p[]) if (params==2 && p[1]==HASH_KEYWORD_EXT) // <= id EXT> return setTrackMode(p[0],TRACK_MODE_EXT); + if (params==2 && p[1]==HASH_KEYWORD_BOOST) // <= id BOOST> + return setTrackMode(p[0],TRACK_MODE_BOOST); + + if (params==2 && p[1]==HASH_KEYWORD_AUTO) // <= id AUTO> + return setTrackMode(p[0], track[p[0]]->getMode() | TRACK_MODE_AUTOINV); + + if (params==2 && p[1]==HASH_KEYWORD_INV) // <= id AUTO> + return setTrackMode(p[0], track[p[0]]->getMode() | TRACK_MODE_INV); + if (params==3 && p[1]==HASH_KEYWORD_DC && p[2]>0) // <= id DC cab> return setTrackMode(p[0],TRACK_MODE_DC,p[2]); if (params==3 && p[1]==HASH_KEYWORD_DCX && p[2]>0) // <= id DCX cab> - return setTrackMode(p[0],TRACK_MODE_DCX,p[2]); + return setTrackMode(p[0],TRACK_MODE_DC|TRACK_MODE_INV,p[2]); return false; } @@ -374,35 +396,38 @@ void TrackManager::streamTrackState(Print* stream, byte t) { // null stream means send to commandDistributor for broadcast if (track[t]==NULL) return; auto format=F(""); - bool pstate = TrackManager::isPowerOn(t); - - switch(track[t]->getMode()) { - case TRACK_MODE_MAIN: - if (pstate) {format=F("<= %c MAIN ON>\n");} else {format = F("<= %c MAIN OFF>\n");} - break; +// bool pstate = TrackManager::isPowerOn(t); +// char *statestr; +// if (pstate) +// statestr = (char *)"ON"; +// else +// statestr = (char *)"OFF"; + TRACK_MODE tm = track[t]->getMode(); + if (tm & TRACK_MODE_MAIN) + format=F("<= %c MAIN>\n"); #ifndef DISABLE_PROG - case TRACK_MODE_PROG: - if (pstate) {format=F("<= %c PROG ON>\n");} else {format=F("<= %c PROG OFF>\n");} - break; + else if (tm & TRACK_MODE_PROG) + format=F("<= %c PROG>\n"); #endif - case TRACK_MODE_NONE: - if (pstate) {format=F("<= %c NONE ON>\n");} else {format=F("<= %c NONE OFF>\n");} - break; - case TRACK_MODE_EXT: - if (pstate) {format=F("<= %c EXT ON>\n");} else {format=F("<= %c EXT OFF>\n");} - break; - case TRACK_MODE_DC: - if (pstate) {format=F("<= %c DC %d ON>\n");} else {format=F("<= %c DC %d OFF>\n");} - break; - case TRACK_MODE_DCX: - if (pstate) {format=F("<= %c DCX %d ON>\n");} else {format=F("<= %c DCX %d OFF>\n");} - break; - default: - break; // unknown, dont care + else if (tm & TRACK_MODE_NONE) + format=F("<= %c NONE>\n"); + else if(tm & TRACK_MODE_EXT) + format=F("<= %c EXT>\n"); + else if(tm & TRACK_MODE_BOOST) + format=F("<= %c BOOST>\n"); + else if (tm & TRACK_MODE_DC) { + if (tm & TRACK_MODE_INV) + format=F("<= %c DCX>\n"); + else + format=F("<= %c DC>\n"); } + else + format=F("<= %c XXX>\n"); - if (stream) StringFormatter::send(stream,format,'A'+t, trackDCAddr[t]); - else CommandDistributor::broadcastTrackState(format,'A'+t, trackDCAddr[t]); + if (stream) + StringFormatter::send(stream,format,'A'+t, trackDCAddr[t]); + else + CommandDistributor::broadcastTrackState(format,'A'+t, trackDCAddr[t]); } @@ -418,13 +443,13 @@ void TrackManager::loop() { if (nextCycleTrack>lastTrack) nextCycleTrack=0; if (track[nextCycleTrack]==NULL) return; MotorDriver * motorDriver=track[nextCycleTrack]; - bool useProgLimit=dontLimitProg? false: track[nextCycleTrack]->getMode()==TRACK_MODE_PROG; + bool useProgLimit=dontLimitProg ? false : (bool)(track[nextCycleTrack]->getMode() & TRACK_MODE_PROG); motorDriver->checkPowerOverload(useProgLimit, nextCycleTrack); } MotorDriver * TrackManager::getProgDriver() { FOR_EACH_TRACK(t) - if (track[t]->getMode()==TRACK_MODE_PROG) return track[t]; + if (track[t]->getMode() & TRACK_MODE_PROG) return track[t]; return NULL; } @@ -432,7 +457,7 @@ MotorDriver * TrackManager::getProgDriver() { std::vectorTrackManager::getMainDrivers() { std::vector v; FOR_EACH_TRACK(t) - if (track[t]->getMode()==TRACK_MODE_MAIN) v.push_back(track[t]); + if (track[t]->getMode() & TRACK_MODE_MAIN) v.push_back(track[t]); return v; } #endif @@ -453,40 +478,33 @@ void TrackManager::setTrackPower(bool setProg, bool setJoin, POWERMODE mode, byt MotorDriver * driver=track[thistrack]; if (!driver) return; - switch (track[thistrack]->getMode()) { - case TRACK_MODE_MAIN: - if (setProg) break; + TRACK_MODE tm = track[thistrack]->getMode(); + if ( (tm & TRACK_MODE_MAIN) + && !setProg ){ // toggle brake before turning power on - resets overcurrent error // on the Pololu board if brake is wired to ^D2. // XXX see if we can make this conditional driver->setBrake(true); driver->setBrake(false); // DCC runs with brake off - driver->setPower(mode); - break; - case TRACK_MODE_DC: - case TRACK_MODE_DCX: - //DIAG(F("Processing track - %d setProg %d"), thistrack, setProg); - if (setProg || setJoin) break; + driver->setPower(mode); + } else if ( (tm & TRACK_MODE_DC) + && !(setProg || setJoin)){ + //DIAG(F("Processing track - %d setProg %d"), thistrack, setProg); driver->setBrake(true); // DC starts with brake on applyDCSpeed(thistrack); // speed match DCC throttles driver->setPower(mode); - break; - case TRACK_MODE_PROG: - if (!setProg && !setJoin) break; + } else if ( (tm & TRACK_MODE_PROG) + && (setProg || setJoin) ){ driver->setBrake(true); driver->setBrake(false); driver->setPower(mode); - break; - case TRACK_MODE_EXT: + } else if ( (tm & TRACK_MODE_EXT) + || (tm & TRACK_MODE_BOOST)){ driver->setBrake(true); driver->setBrake(false); driver->setPower(mode); - break; - case TRACK_MODE_NONE: - break; - } - - } + } +} void TrackManager::reportPowerChange(Print* stream, byte thistrack) { // This function is for backward JMRI compatibility only @@ -499,7 +517,7 @@ void TrackManager::setTrackPower(bool setProg, bool setJoin, POWERMODE mode, byt POWERMODE TrackManager::getProgPower() { FOR_EACH_TRACK(t) - if (track[t]->getMode()==TRACK_MODE_PROG) + if (track[t]->getMode() & TRACK_MODE_PROG) return track[t]->getPower(); return POWERMODE::OFF; } @@ -544,7 +562,7 @@ void TrackManager::setJoin(bool joined) { #ifdef ARDUINO_ARCH_ESP32 if (joined) { FOR_EACH_TRACK(t) { - if (track[t]->getMode()==TRACK_MODE_PROG) { + if (track[t]->getMode() & TRACK_MODE_PROG) { tempProgTrack = t; setTrackMode(t, TRACK_MODE_MAIN); break; @@ -573,7 +591,7 @@ bool TrackManager::isPowerOn(byte t) { } bool TrackManager::isProg(byte t) { - if (track[t]->getMode()==TRACK_MODE_PROG) + if (track[t]->getMode() & TRACK_MODE_PROG) return true; return false; } diff --git a/TrackManager.h b/TrackManager.h index d197751..d1edca2 100644 --- a/TrackManager.h +++ b/TrackManager.h @@ -112,7 +112,7 @@ class TrackManager { static POWERMODE mainPowerGuess; static void applyDCSpeed(byte t); - static int16_t trackDCAddr[MAX_TRACKS]; // dc address if TRACK_MODE_DC or TRACK_MODE_DCX + static int16_t trackDCAddr[MAX_TRACKS]; // dc address if TRACK_MODE_DC #ifdef ARDUINO_ARCH_ESP32 static byte tempProgTrack; // holds the prog track number during join #endif From 9ce95c07aaeda5ae710455368245fb1199783e1e Mon Sep 17 00:00:00 2001 From: Harald Barth Date: Sat, 11 Nov 2023 08:03:59 +0100 Subject: [PATCH 03/10] Booster mode configured by defined booster pin. New mode name output --- TrackManager.cpp | 39 ++++++++++++++++++++++++++++----------- config.example.h | 6 ++++++ 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/TrackManager.cpp b/TrackManager.cpp index 1fffb0b..3b380f1 100644 --- a/TrackManager.cpp +++ b/TrackManager.cpp @@ -46,7 +46,9 @@ const int16_t HASH_KEYWORD_DCX = 6463; // DC reversed polarity const int16_t HASH_KEYWORD_EXT = 8201; // External DCC signal const int16_t HASH_KEYWORD_A = 65; // parser makes single chars the ascii. const int16_t HASH_KEYWORD_AUTO = -5457; +#ifdef BOOSTER_INPUT const int16_t HASH_KEYWORD_BOOST = 11269; +#endif const int16_t HASH_KEYWORD_INV = 11857; MotorDriver * TrackManager::track[MAX_TRACKS]; @@ -230,15 +232,18 @@ bool TrackManager::setTrackMode(byte trackToSet, TRACK_MODE mode, int16_t dcAddr //DIAG(F("Track=%c remove ^pin %d"),trackToSet+'A', p.invpin); gpio_reset_pin((gpio_num_t)p.invpin); } +#ifdef BOOSTER_INPUT if (mode & TRACK_MODE_BOOST) { - DIAG(F("Track=%c mode boost pin %d"),trackToSet+'A', p.pin); - pinMode(26, INPUT); // hardcoded XXX + //DIAG(F("Track=%c mode boost pin %d"),trackToSet+'A', p.pin); + pinMode(BOOSTER_INPUT, INPUT); gpio_matrix_in(26, SIG_IN_FUNC228_IDX, false); //pads 224 to 228 available as loopback gpio_matrix_out(p.pin, SIG_IN_FUNC228_IDX, false, false); if (p.invpin != UNUSED_PIN) { gpio_matrix_out(p.invpin, SIG_IN_FUNC228_IDX, true /*inverted*/, false); } - } else if (mode & (TRACK_MODE_MAIN | TRACK_MODE_PROG | TRACK_MODE_DC)) { + } else // elseif clause continues +#endif + if (mode & (TRACK_MODE_MAIN | TRACK_MODE_PROG | TRACK_MODE_DC)) { // gpio_reset_pin may reset to input pinMode(p.pin, OUTPUT); if (p.invpin != UNUSED_PIN) @@ -373,10 +378,10 @@ bool TrackManager::parseJ(Print *stream, int16_t params, int16_t p[]) if (params==2 && p[1]==HASH_KEYWORD_EXT) // <= id EXT> return setTrackMode(p[0],TRACK_MODE_EXT); - +#ifdef BOOSTER_INPUT if (params==2 && p[1]==HASH_KEYWORD_BOOST) // <= id BOOST> return setTrackMode(p[0],TRACK_MODE_BOOST); - +#endif if (params==2 && p[1]==HASH_KEYWORD_AUTO) // <= id AUTO> return setTrackMode(p[0], track[p[0]]->getMode() | TRACK_MODE_AUTOINV); @@ -403,8 +408,14 @@ void TrackManager::streamTrackState(Print* stream, byte t) { // else // statestr = (char *)"OFF"; TRACK_MODE tm = track[t]->getMode(); - if (tm & TRACK_MODE_MAIN) - format=F("<= %c MAIN>\n"); + if (tm & TRACK_MODE_MAIN) { + if(tm & TRACK_MODE_AUTOINV) + format=F("<= %c MAIN AUTOINV>\n"); + else if (tm & TRACK_MODE_INV) + format=F("<= %c MAIN INV>\n"); + else + format=F("<= %c MAIN>\n"); + } #ifndef DISABLE_PROG else if (tm & TRACK_MODE_PROG) format=F("<= %c PROG>\n"); @@ -413,13 +424,19 @@ void TrackManager::streamTrackState(Print* stream, byte t) { format=F("<= %c NONE>\n"); else if(tm & TRACK_MODE_EXT) format=F("<= %c EXT>\n"); - else if(tm & TRACK_MODE_BOOST) - format=F("<= %c BOOST>\n"); + else if(tm & TRACK_MODE_BOOST) { + if(tm & TRACK_MODE_AUTOINV) + format=F("<= %c BOOST AUTOINV>\n"); + else if (tm & TRACK_MODE_INV) + format=F("<= %c BOOST INV>\n"); + else + format=F("<= %c BOOST>\n"); + } else if (tm & TRACK_MODE_DC) { if (tm & TRACK_MODE_INV) - format=F("<= %c DCX>\n"); + format=F("<= %c DCX %d>\n"); else - format=F("<= %c DC>\n"); + format=F("<= %c DC %d>\n"); } else format=F("<= %c XXX>\n"); diff --git a/config.example.h b/config.example.h index 0f136f9..de31743 100644 --- a/config.example.h +++ b/config.example.h @@ -266,6 +266,12 @@ The configuration file for DCC-EX Command Station // //#define SERIAL_BT_COMMANDS +// BOOSTER PIN INPUT ON ESP32 +// On ESP32 you have the possibility to define a pin as booster input +// Arduio pin D2 is GPIO 26 on ESPDuino32 +// +//#define BOOSTER_INPUT 26 + // SABERTOOTH // // This is a very special option and only useful if you happen to have a From befcfebec7d2d6021389e37b714ae3f6baffe97d Mon Sep 17 00:00:00 2001 From: Harald Barth Date: Sat, 11 Nov 2023 08:15:15 +0100 Subject: [PATCH 04/10] version 5.2.0 --- GITHUB_SHA.h | 2 +- version.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/GITHUB_SHA.h b/GITHUB_SHA.h index d2a7fd1..867619e 100644 --- a/GITHUB_SHA.h +++ b/GITHUB_SHA.h @@ -1 +1 @@ -#define GITHUB_SHA "devel-202310230944Z" +#define GITHUB_SHA "devel-202311110712Z" diff --git a/version.h b/version.h index 242d730..4258cf4 100644 --- a/version.h +++ b/version.h @@ -3,7 +3,8 @@ #include "StringFormatter.h" -#define VERSION "5.1.21" +#define VERSION "5.2.0" +// 5.2.0 - ESP32: Autoreverse and booster mode support // 5.1.21 - EXRAIL invoke multiple ON handlers for same event // 5.1.20 - EXRAIL Tidy and ROUTE_STATE, ROUTE_CAPTION // 5.1.19 - Only flag 2.2.0.0-dev as broken, not 2.2.0.0 From e8b9f80c8cd232cf1736c8740c7a534b776abf03 Mon Sep 17 00:00:00 2001 From: Harald Barth Date: Sat, 11 Nov 2023 09:45:28 +0100 Subject: [PATCH 05/10] Reformat reply to <=> --- CommandDistributor.cpp | 4 ++-- CommandDistributor.h | 2 +- TrackManager.cpp | 35 +++++++++++++++-------------------- 3 files changed, 18 insertions(+), 23 deletions(-) diff --git a/CommandDistributor.cpp b/CommandDistributor.cpp index 351a18d..653bbef 100644 --- a/CommandDistributor.cpp +++ b/CommandDistributor.cpp @@ -269,8 +269,8 @@ void CommandDistributor::broadcastRaw(clientType type, char * msg) { broadcastReply(type, F("%s"),msg); } -void CommandDistributor::broadcastTrackState(const FSH* format,byte trackLetter, int16_t dcAddr) { - broadcastReply(COMMAND_TYPE, format,trackLetter, dcAddr); +void CommandDistributor::broadcastTrackState(const FSH* format,byte trackLetter, byte pstate, int16_t dcAddr) { + broadcastReply(COMMAND_TYPE, format,trackLetter, pstate, dcAddr); } void CommandDistributor::broadcastRouteState(uint16_t routeId, byte state ) { diff --git a/CommandDistributor.h b/CommandDistributor.h index 83bfbbd..7dfcdf6 100644 --- a/CommandDistributor.h +++ b/CommandDistributor.h @@ -55,7 +55,7 @@ public : static int16_t retClockTime(); static void broadcastPower(); static void broadcastRaw(clientType type,char * msg); - static void broadcastTrackState(const FSH* format,byte trackLetter, int16_t dcAddr); + static void broadcastTrackState(const FSH* format,byte trackLetter, byte pstate, int16_t dcAddr); template static void broadcastReply(clientType type, Targs... msg); static void forget(byte clientId); static void broadcastRouteState(uint16_t routeId,byte state); diff --git a/TrackManager.cpp b/TrackManager.cpp index 3b380f1..647f07c 100644 --- a/TrackManager.cpp +++ b/TrackManager.cpp @@ -401,50 +401,45 @@ void TrackManager::streamTrackState(Print* stream, byte t) { // null stream means send to commandDistributor for broadcast if (track[t]==NULL) return; auto format=F(""); -// bool pstate = TrackManager::isPowerOn(t); -// char *statestr; -// if (pstate) -// statestr = (char *)"ON"; -// else -// statestr = (char *)"OFF"; + byte pstate = TrackManager::isPowerOn(t) ? 1 : 0; TRACK_MODE tm = track[t]->getMode(); if (tm & TRACK_MODE_MAIN) { if(tm & TRACK_MODE_AUTOINV) - format=F("<= %c MAIN AUTOINV>\n"); + format=F("<= %c %d MAIN AUTOINV>\n"); else if (tm & TRACK_MODE_INV) - format=F("<= %c MAIN INV>\n"); + format=F("<= %c %d MAIN INV>\n"); else - format=F("<= %c MAIN>\n"); + format=F("<= %c %d MAIN>\n"); } #ifndef DISABLE_PROG else if (tm & TRACK_MODE_PROG) - format=F("<= %c PROG>\n"); + format=F("<= %c %d PROG>\n"); #endif else if (tm & TRACK_MODE_NONE) - format=F("<= %c NONE>\n"); + format=F("<= %c %d NONE>\n"); else if(tm & TRACK_MODE_EXT) - format=F("<= %c EXT>\n"); + format=F("<= %c %d EXT>\n"); else if(tm & TRACK_MODE_BOOST) { if(tm & TRACK_MODE_AUTOINV) - format=F("<= %c BOOST AUTOINV>\n"); + format=F("<= %c %d BOOST AUTOINV>\n"); else if (tm & TRACK_MODE_INV) - format=F("<= %c BOOST INV>\n"); + format=F("<= %c %d BOOST INV>\n"); else - format=F("<= %c BOOST>\n"); + format=F("<= %c %d BOOST>\n"); } else if (tm & TRACK_MODE_DC) { if (tm & TRACK_MODE_INV) - format=F("<= %c DCX %d>\n"); + format=F("<= %c %d DCX %d>\n"); else - format=F("<= %c DC %d>\n"); + format=F("<= %c %d DC %d>\n"); } else - format=F("<= %c XXX>\n"); + format=F("<= %c %d XXX>\n"); if (stream) - StringFormatter::send(stream,format,'A'+t, trackDCAddr[t]); + StringFormatter::send(stream,format,'A'+t, pstate, trackDCAddr[t]); else - CommandDistributor::broadcastTrackState(format,'A'+t, trackDCAddr[t]); + CommandDistributor::broadcastTrackState(format,'A'+t, pstate, trackDCAddr[t]); } From 86ed8ff8a6aeb45abaf0a25def6d0d3e10815c82 Mon Sep 17 00:00:00 2001 From: Harald Barth Date: Mon, 13 Nov 2023 17:16:58 +0100 Subject: [PATCH 06/10] remove power state from <=> answer --- CommandDistributor.cpp | 4 ++-- CommandDistributor.h | 2 +- TrackManager.cpp | 31 ++++++++++++++----------------- 3 files changed, 17 insertions(+), 20 deletions(-) diff --git a/CommandDistributor.cpp b/CommandDistributor.cpp index 653bbef..cd9e89e 100644 --- a/CommandDistributor.cpp +++ b/CommandDistributor.cpp @@ -269,8 +269,8 @@ void CommandDistributor::broadcastRaw(clientType type, char * msg) { broadcastReply(type, F("%s"),msg); } -void CommandDistributor::broadcastTrackState(const FSH* format,byte trackLetter, byte pstate, int16_t dcAddr) { - broadcastReply(COMMAND_TYPE, format,trackLetter, pstate, dcAddr); +void CommandDistributor::broadcastTrackState(const FSH* format,byte trackLetter, int16_t dcAddr) { + broadcastReply(COMMAND_TYPE, format, trackLetter, dcAddr); } void CommandDistributor::broadcastRouteState(uint16_t routeId, byte state ) { diff --git a/CommandDistributor.h b/CommandDistributor.h index 7dfcdf6..83bfbbd 100644 --- a/CommandDistributor.h +++ b/CommandDistributor.h @@ -55,7 +55,7 @@ public : static int16_t retClockTime(); static void broadcastPower(); static void broadcastRaw(clientType type,char * msg); - static void broadcastTrackState(const FSH* format,byte trackLetter, byte pstate, int16_t dcAddr); + static void broadcastTrackState(const FSH* format,byte trackLetter, int16_t dcAddr); template static void broadcastReply(clientType type, Targs... msg); static void forget(byte clientId); static void broadcastRouteState(uint16_t routeId,byte state); diff --git a/TrackManager.cpp b/TrackManager.cpp index 647f07c..8cdadb2 100644 --- a/TrackManager.cpp +++ b/TrackManager.cpp @@ -400,46 +400,43 @@ bool TrackManager::parseJ(Print *stream, int16_t params, int16_t p[]) void TrackManager::streamTrackState(Print* stream, byte t) { // null stream means send to commandDistributor for broadcast if (track[t]==NULL) return; - auto format=F(""); - byte pstate = TrackManager::isPowerOn(t) ? 1 : 0; + auto format=F("<= %d XXX>\n"); TRACK_MODE tm = track[t]->getMode(); if (tm & TRACK_MODE_MAIN) { if(tm & TRACK_MODE_AUTOINV) - format=F("<= %c %d MAIN AUTOINV>\n"); + format=F("<= %c MAIN A>\n"); else if (tm & TRACK_MODE_INV) - format=F("<= %c %d MAIN INV>\n"); + format=F("<= %c MAIN I>\n"); else - format=F("<= %c %d MAIN>\n"); + format=F("<= %c MAIN>\n"); } #ifndef DISABLE_PROG else if (tm & TRACK_MODE_PROG) - format=F("<= %c %d PROG>\n"); + format=F("<= %c PROG>\n"); #endif else if (tm & TRACK_MODE_NONE) - format=F("<= %c %d NONE>\n"); + format=F("<= %c NONE>\n"); else if(tm & TRACK_MODE_EXT) - format=F("<= %c %d EXT>\n"); + format=F("<= %c EXT>\n"); else if(tm & TRACK_MODE_BOOST) { if(tm & TRACK_MODE_AUTOINV) - format=F("<= %c %d BOOST AUTOINV>\n"); + format=F("<= %c B A>\n"); else if (tm & TRACK_MODE_INV) - format=F("<= %c %d BOOST INV>\n"); + format=F("<= %c B I>\n"); else - format=F("<= %c %d BOOST>\n"); + format=F("<= %c B>\n"); } else if (tm & TRACK_MODE_DC) { if (tm & TRACK_MODE_INV) - format=F("<= %c %d DCX %d>\n"); + format=F("<= %c DCX %d>\n"); else - format=F("<= %c %d DC %d>\n"); + format=F("<= %c DC %d>\n"); } - else - format=F("<= %c %d XXX>\n"); if (stream) - StringFormatter::send(stream,format,'A'+t, pstate, trackDCAddr[t]); + StringFormatter::send(stream,format,'A'+t, trackDCAddr[t]); else - CommandDistributor::broadcastTrackState(format,'A'+t, pstate, trackDCAddr[t]); + CommandDistributor::broadcastTrackState(format,'A'+t, trackDCAddr[t]); } From 582ff890f4e41dafc00c54cebadbfc9a6d37db8f Mon Sep 17 00:00:00 2001 From: Harald Barth Date: Tue, 14 Nov 2023 00:05:18 +0100 Subject: [PATCH 07/10] Trackmanager rework for simpler structure --- CommandDistributor.cpp | 5 ++ DCCEXParser.cpp | 147 ++++++++++++----------------------------- EXRAIL2.cpp | 4 +- MotorDriver.h | 3 +- TrackManager.cpp | 115 +++++++++++++++++++------------- TrackManager.h | 15 ++--- 6 files changed, 126 insertions(+), 163 deletions(-) diff --git a/CommandDistributor.cpp b/CommandDistributor.cpp index cd9e89e..89c8714 100644 --- a/CommandDistributor.cpp +++ b/CommandDistributor.cpp @@ -248,6 +248,11 @@ void CommandDistributor::broadcastLoco(byte slot) { } void CommandDistributor::broadcastPower() { + char pstr[] = "? x"; + for(byte t=0; t<8; t++) + if (TrackManager::getPower(t, pstr)) + broadcastReply(COMMAND_TYPE, F("\n"),pstr); + bool main=TrackManager::getMainPower()==POWERMODE::ON; bool prog=TrackManager::getProgPower()==POWERMODE::ON; bool join=TrackManager::isJoined(); diff --git a/DCCEXParser.cpp b/DCCEXParser.cpp index 96596c6..3b91d86 100644 --- a/DCCEXParser.cpp +++ b/DCCEXParser.cpp @@ -553,131 +553,66 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream) case '1': // POWERON <1 [MAIN|PROG|JOIN]> { - bool main=false; - bool prog=false; - bool join=false; - bool singletrack=false; - //byte t=0; - if (params > 1) break; - if (params==0) { // All - main=true; - prog=true; - } - if (params==1) { - if (p[0]==HASH_KEYWORD_MAIN) { // <1 MAIN> - main=true; + if (params > 1) break; + if (params==0) { // All + TrackManager::setTrackPower(TRACK_MODE_ALL, POWERMODE::ON); + } + if (params==1) { + if (p[0]==HASH_KEYWORD_MAIN) { // <1 MAIN> + TrackManager::setTrackPower(TRACK_MODE_MAIN, POWERMODE::ON); } #ifndef DISABLE_PROG else if (p[0] == HASH_KEYWORD_JOIN) { // <1 JOIN> - main=true; - prog=true; - join=true; + TrackManager::setJoin(true); + TrackManager::setTrackPower(TRACK_MODE_MAIN|TRACK_MODE_PROG, POWERMODE::ON); } else if (p[0]==HASH_KEYWORD_PROG) { // <1 PROG> - prog=true; + TrackManager::setJoin(false); + TrackManager::setTrackPower(TRACK_MODE_PROG, POWERMODE::ON); } #endif - //else if (p[0] >= 'A' && p[0] <= 'H') { // <1 A-H> else if (p[0] >= HASH_KEYWORD_A && p[0] <= HASH_KEYWORD_H) { // <1 A-H> - byte t = (p[0] - 'A'); - //DIAG(F("Processing track - %d "), t); - if (TrackManager::isProg(t)) { - main = false; - prog = true; - } - else - { - main=true; - prog=false; - } - singletrack=true; - if (main) TrackManager::setTrackPower(false, false, POWERMODE::ON, t); - if (prog) TrackManager::setTrackPower(true, false, POWERMODE::ON, t); - - StringFormatter::send(stream, F("<1 %c>\n"), t+'A'); - //CommandDistributor::broadcastPower(); - //TrackManager::streamTrackState(NULL,t); - return; + byte t = (p[0] - 'A'); + TrackManager::setTrackPower(POWERMODE::ON, t); + //StringFormatter::send(stream, F("\n"), t+'A'); } - else break; // will reply - } - - if (!singletrack) { - TrackManager::setJoin(join); - if (join) TrackManager::setJoinPower(POWERMODE::ON); - else { - if (main) TrackManager::setMainPower(POWERMODE::ON); - if (prog) TrackManager::setProgPower(POWERMODE::ON); - } - CommandDistributor::broadcastPower(); + } + CommandDistributor::broadcastPower(); + //TrackManager::streamTrackState(NULL,t); - return; - } + return; + } - } - case '0': // POWEROFF <0 [MAIN | PROG] > { - bool main=false; - bool prog=false; - bool singletrack=false; - //byte t=0; - if (params > 1) break; - if (params==0) { // All - main=true; - prog=true; - } - if (params==1) { - if (p[0]==HASH_KEYWORD_MAIN) { // <0 MAIN> - main=true; - } + if (params > 1) break; + if (params==0) { // All + TrackManager::setJoin(false); + TrackManager::setTrackPower(TRACK_MODE_ALL, POWERMODE::OFF); + } + if (params==1) { + if (p[0]==HASH_KEYWORD_MAIN) { // <0 MAIN> + TrackManager::setJoin(false); + TrackManager::setTrackPower(TRACK_MODE_MAIN, POWERMODE::OFF); + } #ifndef DISABLE_PROG else if (p[0]==HASH_KEYWORD_PROG) { // <0 PROG> - prog=true; + TrackManager::progTrackBoosted=false; // Prog track boost mode will not outlive prog track off + TrackManager::setTrackPower(TRACK_MODE_PROG, POWERMODE::OFF); } #endif - //else if (p[0] >= 'A' && p[0] <= 'H') { // <1 A-H> - else if (p[0] >= HASH_KEYWORD_A && p[0] <= HASH_KEYWORD_H) { // <1 A-H> - byte t = (p[0] - 'A'); - //DIAG(F("Processing track - %d "), t); - if (TrackManager::isProg(t)) { - main = false; - prog = true; - } - else - { - main=true; - prog=false; - } - singletrack=true; - TrackManager::setJoin(false); - if (main) TrackManager::setTrackPower(false, false, POWERMODE::OFF, t); - if (prog) { - TrackManager::progTrackBoosted=false; // Prog track boost mode will not outlive prog track off - TrackManager::setTrackPower(true, false, POWERMODE::OFF, t); - } - StringFormatter::send(stream, F("<0 %c>\n"), t+'A'); - //CommandDistributor::broadcastPower(); - //TrackManager::streamTrackState(NULL, t); - return; - } - - else break; // will reply + else if (p[0] >= HASH_KEYWORD_A && p[0] <= HASH_KEYWORD_H) { // <1 A-H> + byte t = (p[0] - 'A'); + TrackManager::setJoin(false); + TrackManager::setTrackPower(POWERMODE::OFF, t); + //StringFormatter::send(stream, F("\n"), t+'A'); } - - if (!singletrack) { - TrackManager::setJoin(false); - - if (main) TrackManager::setMainPower(POWERMODE::OFF); - if (prog) { - TrackManager::progTrackBoosted=false; // Prog track boost mode will not outlive prog track off - TrackManager::setProgPower(POWERMODE::OFF); - } - CommandDistributor::broadcastPower(); - return; - } - } + else break; // will reply + } + CommandDistributor::broadcastPower(); + return; + } case '!': // ESTOP ALL DCC::setThrottle(0,1,1); // this broadcasts speed 1(estop) and sets all reminders to speed 1. diff --git a/EXRAIL2.cpp b/EXRAIL2.cpp index 8e6a6b5..933650c 100644 --- a/EXRAIL2.cpp +++ b/EXRAIL2.cpp @@ -636,10 +636,10 @@ void RMFT2::loop2() { //byte thistrack=getOperand(1); switch (operand) { case TRACK_POWER_0: - TrackManager::setTrackPower(TrackManager::isProg(getOperand(1)), false, POWERMODE::OFF, getOperand(1)); + TrackManager::setTrackPower(POWERMODE::OFF, getOperand(1)); break; case TRACK_POWER_1: - TrackManager::setTrackPower(TrackManager::isProg(getOperand(1)), false, POWERMODE::ON, getOperand(1)); + TrackManager::setTrackPower(POWERMODE::ON, getOperand(1)); break; } diff --git a/MotorDriver.h b/MotorDriver.h index db2ccc5..19bfd13 100644 --- a/MotorDriver.h +++ b/MotorDriver.h @@ -35,7 +35,8 @@ template inline T operator& (T a, T b) { return (T)((int)a & (int)b); } template inline T operator^ (T a, T b) { return (T)((int)a ^ (int)b); } enum TRACK_MODE : byte {TRACK_MODE_NONE = 1, TRACK_MODE_MAIN = 2, TRACK_MODE_PROG = 4, TRACK_MODE_DC = 8, TRACK_MODE_EXT = 16, TRACK_MODE_BOOST = 32, - TRACK_MODE_INV = 64, TRACK_MODE_DCX = 72, TRACK_MODE_AUTOINV = 128}; + TRACK_MODE_ALL = 62, // only to operate all tracks + TRACK_MODE_INV = 64, TRACK_MODE_DCX = 72 /*DC + INV*/, TRACK_MODE_AUTOINV = 128}; #define setHIGH(fastpin) *fastpin.inout |= fastpin.maskHIGH #define setLOW(fastpin) *fastpin.inout &= fastpin.maskLOW diff --git a/TrackManager.cpp b/TrackManager.cpp index 8cdadb2..ff56001 100644 --- a/TrackManager.cpp +++ b/TrackManager.cpp @@ -471,51 +471,48 @@ std::vectorTrackManager::getMainDrivers() { } #endif -void TrackManager::setPower2(bool setProg,bool setJoin, POWERMODE mode) { - if (!setProg) mainPowerGuess=mode; - FOR_EACH_TRACK(t) { - - TrackManager::setTrackPower(setProg, setJoin, mode, t); - - } - return; -} - -void TrackManager::setTrackPower(bool setProg, bool setJoin, POWERMODE mode, byte thistrack) { - - //DIAG(F("SetTrackPower Processing Track %d"), thistrack); - MotorDriver * driver=track[thistrack]; - if (!driver) return; - - TRACK_MODE tm = track[thistrack]->getMode(); - if ( (tm & TRACK_MODE_MAIN) - && !setProg ){ - // toggle brake before turning power on - resets overcurrent error - // on the Pololu board if brake is wired to ^D2. - // XXX see if we can make this conditional - driver->setBrake(true); - driver->setBrake(false); // DCC runs with brake off - driver->setPower(mode); - } else if ( (tm & TRACK_MODE_DC) - && !(setProg || setJoin)){ - //DIAG(F("Processing track - %d setProg %d"), thistrack, setProg); - driver->setBrake(true); // DC starts with brake on - applyDCSpeed(thistrack); // speed match DCC throttles - driver->setPower(mode); - } else if ( (tm & TRACK_MODE_PROG) - && (setProg || setJoin) ){ - driver->setBrake(true); - driver->setBrake(false); - driver->setPower(mode); - } else if ( (tm & TRACK_MODE_EXT) - || (tm & TRACK_MODE_BOOST)){ - driver->setBrake(true); - driver->setBrake(false); - driver->setPower(mode); +// Set track power for all tracks with this mode +void TrackManager::setTrackPower(TRACK_MODE trackmode, POWERMODE powermode) { + FOR_EACH_TRACK(t) { + MotorDriver *driver=track[t]; + if (trackmode & driver->getMode()) { + if (powermode == POWERMODE::ON) { + if (trackmode & TRACK_MODE_DC) { + driver->setBrake(true); // DC starts with brake on + applyDCSpeed(t); // speed match DCC throttles + } else { + // toggle brake before turning power on - resets overcurrent error + // on the Pololu board if brake is wired to ^D2. + driver->setBrake(true); + driver->setBrake(false); // DCC runs with brake off + } } + driver->setPower(powermode); + } + } } - void TrackManager::reportPowerChange(Print* stream, byte thistrack) { +// Set track power for this track, inependent of mode +void TrackManager::setTrackPower(POWERMODE powermode, byte t) { + MotorDriver *driver=track[t]; + TRACK_MODE trackmode = driver->getMode(); + if (trackmode & TRACK_MODE_DC) { + if (powermode == POWERMODE::ON) { + driver->setBrake(true); // DC starts with brake on + applyDCSpeed(t); // speed match DCC throttles + } + } else { + if (powermode == POWERMODE::ON) { + // toggle brake before turning power on - resets overcurrent error + // on the Pololu board if brake is wired to ^D2. + driver->setBrake(true); + driver->setBrake(false); // DCC runs with brake off + } + } + driver->setPower(powermode); +} + +void TrackManager::reportPowerChange(Print* stream, byte thistrack) { // This function is for backward JMRI compatibility only // It reports the first track only, as main, regardless of track settings. // @@ -524,12 +521,38 @@ void TrackManager::setTrackPower(bool setProg, bool setJoin, POWERMODE mode, byt track[0]->raw2mA(track[0]->getCurrentRaw(false)), maxCurrent, maxCurrent); } +// returns state of the one and only prog track POWERMODE TrackManager::getProgPower() { - FOR_EACH_TRACK(t) - if (track[t]->getMode() & TRACK_MODE_PROG) - return track[t]->getPower(); - return POWERMODE::OFF; + FOR_EACH_TRACK(t) + if (track[t]->getMode() & TRACK_MODE_PROG) + return track[t]->getPower(); // optimize: there is max one prog track + return POWERMODE::OFF; +} + +// returns on if all are on. returns off otherwise +POWERMODE TrackManager::getMainPower() { + POWERMODE result = POWERMODE::OFF; + FOR_EACH_TRACK(t) { + if (track[t]->getMode() & TRACK_MODE_MAIN) { + POWERMODE p = track[t]->getPower(); + if (p == POWERMODE::OFF) + return POWERMODE::OFF; // done and out + if (p == POWERMODE::ON) + result = POWERMODE::ON; + } } + return result; +} + +bool TrackManager::getPower(byte t, char s[]) { + if (track[t]) { + s[0] = track[t]->getPower() == POWERMODE::ON ? '1' : '0'; + s[2] = t + 'A'; + return true; + } + return false; +} + void TrackManager::reportObsoleteCurrent(Print* stream) { // This function is for backward JMRI compatibility only diff --git a/TrackManager.h b/TrackManager.h index d1edca2..644c45a 100644 --- a/TrackManager.h +++ b/TrackManager.h @@ -62,23 +62,22 @@ class TrackManager { static void setDCSignal(int16_t cab, byte speedbyte); static MotorDriver * getProgDriver(); #ifdef ARDUINO_ARCH_ESP32 - static std::vectorgetMainDrivers(); + static std::vectorgetMainDrivers(); #endif - static void setPower2(bool progTrack,bool joinTrack,POWERMODE mode); static void setPower(POWERMODE mode) {setMainPower(mode); setProgPower(mode);} - static void setMainPower(POWERMODE mode) {setPower2(false,false,mode);} - static void setProgPower(POWERMODE mode) {setPower2(true,false,mode);} - static void setJoinPower(POWERMODE mode) {setPower2(false,true,mode);} - static void setTrackPower(bool setProg, bool setJoin, POWERMODE mode, byte thistrack); - + static void setTrackPower(POWERMODE mode, byte t); + static void setTrackPower(TRACK_MODE trackmode, POWERMODE powermode); + static void setMainPower(POWERMODE mode) {setTrackPower(TRACK_MODE_MAIN, mode);} + static void setProgPower(POWERMODE mode) {setTrackPower(TRACK_MODE_PROG, mode);} static const int16_t MAX_TRACKS=8; static bool setTrackMode(byte track, TRACK_MODE mode, int16_t DCaddr=0); static bool parseJ(Print * stream, int16_t params, int16_t p[]); static void loop(); - static POWERMODE getMainPower() {return mainPowerGuess;} + static POWERMODE getMainPower(); static POWERMODE getProgPower(); + static bool getPower(byte t, char s[]); static void setJoin(bool join); static bool isJoined() { return progTrackSyncMain;} static void setJoinRelayPin(byte joinRelayPin); From 503378f1bbee6d8bb55d60ae3728a2b60f6a908b Mon Sep 17 00:00:00 2001 From: Harald Barth Date: Tue, 14 Nov 2023 00:06:53 +0100 Subject: [PATCH 08/10] version 5.2.1 --- GITHUB_SHA.h | 2 +- version.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/GITHUB_SHA.h b/GITHUB_SHA.h index 867619e..71069ca 100644 --- a/GITHUB_SHA.h +++ b/GITHUB_SHA.h @@ -1 +1 @@ -#define GITHUB_SHA "devel-202311110712Z" +#define GITHUB_SHA "devel-202311132306Z" diff --git a/version.h b/version.h index 4258cf4..5640feb 100644 --- a/version.h +++ b/version.h @@ -3,7 +3,8 @@ #include "StringFormatter.h" -#define VERSION "5.2.0" +#define VERSION "5.2.1" +// 5.2.1 - Trackmanager rework for simpler structure // 5.2.0 - ESP32: Autoreverse and booster mode support // 5.1.21 - EXRAIL invoke multiple ON handlers for same event // 5.1.20 - EXRAIL Tidy and ROUTE_STATE, ROUTE_CAPTION From 763ef8be34743835308ad7eaad31a1d59db8b471 Mon Sep 17 00:00:00 2001 From: Harald Barth Date: Tue, 14 Nov 2023 11:12:14 +0100 Subject: [PATCH 09/10] prettier MAX_TRACKS --- CommandDistributor.cpp | 2 +- TrackManager.cpp | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CommandDistributor.cpp b/CommandDistributor.cpp index 89c8714..4269492 100644 --- a/CommandDistributor.cpp +++ b/CommandDistributor.cpp @@ -249,7 +249,7 @@ void CommandDistributor::broadcastLoco(byte slot) { void CommandDistributor::broadcastPower() { char pstr[] = "? x"; - for(byte t=0; t<8; t++) + for(byte t=0; t\n"),pstr); diff --git a/TrackManager.cpp b/TrackManager.cpp index ff56001..7c1e651 100644 --- a/TrackManager.cpp +++ b/TrackManager.cpp @@ -526,7 +526,7 @@ POWERMODE TrackManager::getProgPower() { FOR_EACH_TRACK(t) if (track[t]->getMode() & TRACK_MODE_PROG) return track[t]->getPower(); // optimize: there is max one prog track - return POWERMODE::OFF; + return POWERMODE::OFF; } // returns on if all are on. returns off otherwise @@ -545,6 +545,8 @@ POWERMODE TrackManager::getMainPower() { } bool TrackManager::getPower(byte t, char s[]) { + if (t > lastTrack) + return false; if (track[t]) { s[0] = track[t]->getPower() == POWERMODE::ON ? '1' : '0'; s[2] = t + 'A'; From 1af5132e6aca4dea56636ba5df9f2533d538f17a Mon Sep 17 00:00:00 2001 From: Harald Barth Date: Tue, 14 Nov 2023 11:16:54 +0100 Subject: [PATCH 10/10] version 5.2.1 timestamp --- GITHUB_SHA.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GITHUB_SHA.h b/GITHUB_SHA.h index 71069ca..3f9b1e1 100644 --- a/GITHUB_SHA.h +++ b/GITHUB_SHA.h @@ -1 +1 @@ -#define GITHUB_SHA "devel-202311132306Z" +#define GITHUB_SHA "devel-202311141013Z"