From e5c66a27553c5e2a13f6dbdc70f4d9c6acb6c32d Mon Sep 17 00:00:00 2001 From: Asbelos Date: Wed, 15 Dec 2021 22:04:09 +0000 Subject: [PATCH 1/2] Fixup functionMap and remove duplicates --- DCC.cpp | 7 ++++--- DCC.h | 2 +- WiThrottle.cpp | 57 +++++++++++++++++++++++++------------------------- WiThrottle.h | 2 +- 4 files changed, 34 insertions(+), 34 deletions(-) diff --git a/DCC.cpp b/DCC.cpp index fbb5eed..67bf676 100644 --- a/DCC.cpp +++ b/DCC.cpp @@ -200,6 +200,7 @@ int DCC::changeFn( int cab, int16_t functionNumber, bool pressed) { if (cab<=0 || functionNumber>28) return funcstate; int reg = lookupSpeedTable(cab); if (reg<0) return funcstate; + uint32_t oldFunctionMap=speedTable[reg].functions; // Take care of functions: // Imitate how many command stations do it: Button press is @@ -222,7 +223,7 @@ int DCC::changeFn( int cab, int16_t functionNumber, bool pressed) { funcstate = (speedTable[reg].functions & funcmask)? 1 : 0; } updateGroupflags(speedTable[reg].groupFlags, functionNumber); - CommandDistributor::broadcastLoco(reg); + if (oldFunctionMap!=speedTable[reg].functions) CommandDistributor::broadcastLoco(reg); return funcstate; } @@ -247,7 +248,7 @@ void DCC::updateGroupflags(byte & flags, int16_t functionNumber) { flags |= groupMask; } -uint16_t DCC::getFunctionMap(int cab) { +uint32_t DCC::getFunctionMap(int cab) { if (cab<=0) return 0; // unknown pretend all functions off int reg = lookupSpeedTable(cab); return (reg<0)?0:speedTable[reg].functions; @@ -696,7 +697,7 @@ void DCC::updateLocoReminder(int loco, byte speedCode) { // determine speed reg for this loco int reg=lookupSpeedTable(loco); - if (reg>=0) { + if (reg>=0 && speedTable[reg].speedCode!=speedCode) { speedTable[reg].speedCode = speedCode; CommandDistributor::broadcastLoco(reg); } diff --git a/DCC.h b/DCC.h index bb65095..0b02b5b 100644 --- a/DCC.h +++ b/DCC.h @@ -101,7 +101,7 @@ public: static void setFn(int cab, int16_t functionNumber, bool on); static int changeFn(int cab, int16_t functionNumber, bool pressed); static int getFn(int cab, int16_t functionNumber); - static uint16_t getFunctionMap(int cab); + static uint32_t getFunctionMap(int cab); static void updateGroupflags(byte &flags, int16_t functionNumber); static void setAccessory(int aAdd, byte aNum, bool activate); static bool writeTextPacket(byte *b, int nBytes); diff --git a/WiThrottle.cpp b/WiThrottle.cpp index c17ce3d..8e63b12 100644 --- a/WiThrottle.cpp +++ b/WiThrottle.cpp @@ -272,16 +272,17 @@ void WiThrottle::multithrottle(RingStream * stream, byte * cmd){ for (int loco=0;loco\n"), throttleChar, cmd[3] ,locoid); //tell client to add loco - //Get known Fn states from DCC + for(int fKey=0; fKey<=28; fKey++) { int fstate=DCC::getFn(locoid,fKey); if (fstate>=0) StringFormatter::send(stream,F("M%cA%c%d<;>F%d%d\n"),throttleChar,cmd[3],locoid,fstate,fKey); } - StringFormatter::send(stream, F("M%cA%c%d<;>V%d\n"), throttleChar, cmd[3], locoid, DCCToWiTSpeed(DCC::getThrottleSpeed(locoid))); - StringFormatter::send(stream, F("M%cA%c%d<;>R%d\n"), throttleChar, cmd[3], locoid, DCC::getThrottleDirection(locoid)); + //speed and direction will be published at next broadcast cycle StringFormatter::send(stream, F("M%cA%c%d<;>s1\n"), throttleChar, cmd[3], locoid); //default speed step 128 return; } @@ -303,6 +304,7 @@ void WiThrottle::multithrottle(RingStream * stream, byte * cmd){ void WiThrottle::locoAction(RingStream * stream, byte* aval, char throttleChar, int cab){ // Note cab=-1 for all cabs in the consist called throttleChar. // DIAG(F("Loco Action aval=%c%c throttleChar=%c, cab=%d"), aval[0],aval[1],throttleChar, cab); + (void) stream; switch (aval[0]) { case 'V': // Vspeed { @@ -310,33 +312,25 @@ void WiThrottle::locoAction(RingStream * stream, byte* aval, char throttleChar, LOOPLOCOS(throttleChar, cab) { mostRecentCab=myLocos[loco].cab; DCC::setThrottle(myLocos[loco].cab, WiTToDCCSpeed(witSpeed), DCC::getThrottleDirection(myLocos[loco].cab)); - StringFormatter::send(stream,F("M%cA%c%d<;>V%d\n"), throttleChar, LorS(myLocos[loco].cab), myLocos[loco].cab, witSpeed); + // SetThrottle will cause speed change broadcast } } break; case 'F': //F onOff function { - bool funcstate; - bool pressed=aval[1]=='1'; + bool pressed=aval[1]=='1'; int fKey = getInt(aval+2); LOOPLOCOS(throttleChar, cab) { - funcstate = DCC::changeFn(myLocos[loco].cab, fKey, pressed); - if(funcstate==0 || funcstate==1) - StringFormatter::send(stream,F("M%cA%c%d<;>F%d%d\n"), throttleChar, LorS(myLocos[loco].cab), - myLocos[loco].cab, funcstate, fKey); - } + DCC::changeFn(myLocos[loco].cab, fKey, pressed); } break; + } case 'q': - if (aval[1]=='V') { //qV + if (aval[1]=='V' || aval[1]=='R' ) { //qV or qR + // just flag the loco for broadcast and it will happen. LOOPLOCOS(throttleChar, cab) { - StringFormatter::send(stream,F("M%cA%c%d<;>V%d\n"), throttleChar, LorS(myLocos[loco].cab), myLocos[loco].cab, DCCToWiTSpeed(DCC::getThrottleSpeed(myLocos[loco].cab))); - } - } - else if (aval[1]=='R') { // qR - LOOPLOCOS(throttleChar, cab) { - StringFormatter::send(stream,F("M%cA%c%d<;>R%d\n"), throttleChar, LorS(myLocos[loco].cab), myLocos[loco].cab, DCC::getThrottleDirection(myLocos[loco].cab)); - } + myLocos[loco].broadcastPending=true; + } } break; case 'R': @@ -345,15 +339,15 @@ void WiThrottle::locoAction(RingStream * stream, byte* aval, char throttleChar, LOOPLOCOS(throttleChar, cab) { mostRecentCab=myLocos[loco].cab; DCC::setThrottle(myLocos[loco].cab, DCC::getThrottleSpeed(myLocos[loco].cab), forward); - StringFormatter::send(stream,F("M%cA%c%d<;>R%d\n"), throttleChar, LorS(myLocos[loco].cab), myLocos[loco].cab, forward); - } + // setThrottle will cause a broadcast so notification will be sent + } } break; case 'X': //Emergency Stop (speed code 1) LOOPLOCOS(throttleChar, cab) { DCC::setThrottle(myLocos[loco].cab, 1, DCC::getThrottleDirection(myLocos[loco].cab)); - StringFormatter::send(stream,F("M%cA%c%d<;>V%d\n"), throttleChar, LorS(myLocos[loco].cab), myLocos[loco].cab, -1); + // setThrottle will cause a broadcast so notification will be sent } break; case 'I': // Idle, set speed to 0 @@ -361,7 +355,7 @@ void WiThrottle::locoAction(RingStream * stream, byte* aval, char throttleChar, LOOPLOCOS(throttleChar, cab) { mostRecentCab=myLocos[loco].cab; DCC::setThrottle(myLocos[loco].cab, 0, DCC::getThrottleDirection(myLocos[loco].cab)); - StringFormatter::send(stream,F("M%cA%c%d<;>V%d\n"), throttleChar, LorS(myLocos[loco].cab), myLocos[loco].cab, 0); + // setThrottle will cause a broadcast so notification will be sent } break; } @@ -403,10 +397,15 @@ void WiThrottle::checkHeartbeat(RingStream * stream) { return; } - // send any speed/direction/function changes for this loco + // send any outstanding speed/direction/function changes for this clients locos + // Changes may have been caused by this client, or another non-Withrottle or Exrail + bool streamHasBeenMarked=false; LOOPLOCOS('*', -1) { if (myLocos[loco].throttle!='\0' && myLocos[loco].broadcastPending) { - stream->mark(clientid); + if (!streamHasBeenMarked) { + stream->mark(clientid); + streamHasBeenMarked=true; + } myLocos[loco].broadcastPending=false; int cab=myLocos[loco].cab; char lors=LorS(cab); @@ -417,8 +416,8 @@ void WiThrottle::checkHeartbeat(RingStream * stream) { throttle, lors , cab, DCC::getThrottleDirection(cab)); // compare the DCC functionmap with the local copy and send changes - uint16_t dccFunctionMap=DCC::getFunctionMap(cab); - uint16_t myFunctionMap=myLocos[loco].functionMap; + uint32_t dccFunctionMap=DCC::getFunctionMap(cab); + uint32_t myFunctionMap=myLocos[loco].functionMap; myLocos[loco].functionMap=dccFunctionMap; // loop the maps sending any bit changed @@ -432,9 +431,9 @@ void WiThrottle::checkHeartbeat(RingStream * stream) { dccFunctionMap>>=1; myFunctionMap>>=1; } - stream->commit(); } } + if (streamHasBeenMarked) stream->commit(); } void WiThrottle::markForBroadcast(int cab) { diff --git a/WiThrottle.h b/WiThrottle.h index 7cbdb88..0e1f525 100644 --- a/WiThrottle.h +++ b/WiThrottle.h @@ -25,7 +25,7 @@ struct MYLOCO { char throttle; //indicates which throttle letter on client, often '0','1' or '2' int cab; //address of this loco bool broadcastPending; - uint16_t functionMap; + uint32_t functionMap; }; class WiThrottle { From 1b07d0a5c60766f828f4663478c039da06ff6e6e Mon Sep 17 00:00:00 2001 From: Asbelos Date: Thu, 16 Dec 2021 10:28:41 +0000 Subject: [PATCH 2/2] Simplify Withrottle function changes --- DCC.cpp | 38 +++++++------------------------------- DCC.h | 2 +- WiThrottle.cpp | 10 ++++++---- WiThrottle.h | 4 ++-- 4 files changed, 16 insertions(+), 38 deletions(-) diff --git a/DCC.cpp b/DCC.cpp index 67bf676..4469aa1 100644 --- a/DCC.cpp +++ b/DCC.cpp @@ -192,39 +192,15 @@ void DCC::setFn( int cab, int16_t functionNumber, bool on) { } } -// Change function according to how button was pressed, -// typically in WiThrottle. -// Returns new state or -1 if nothing was changed. -int DCC::changeFn( int cab, int16_t functionNumber, bool pressed) { - int funcstate = -1; - if (cab<=0 || functionNumber>28) return funcstate; +// Flip function state +void DCC::changeFn( int cab, int16_t functionNumber) { + if (cab<=0 || functionNumber>28) return; int reg = lookupSpeedTable(cab); - if (reg<0) return funcstate; - uint32_t oldFunctionMap=speedTable[reg].functions; - - // Take care of functions: - // Imitate how many command stations do it: Button press is - // toggle but for F2 where it is momentary + if (reg<0) return; unsigned long funcmask = (1UL<