From 39d9defec67bfa7e1e0610a6988cf05ed33ddff4 Mon Sep 17 00:00:00 2001 From: Asbelos Date: Thu, 10 Sep 2020 13:09:32 +0100 Subject: [PATCH] Improved commands --- DCC.cpp | 44 +++++++++++++++---------- DCC.h | 4 +-- DCCEXParser.cpp | 80 +++++++++++++++++++++++++++++++++++++-------- DCCEXParser.h | 1 + DCCWaveform.cpp | 14 ++++---- DCCWaveform.h | 6 ++-- StringFormatter.cpp | 5 +++ StringFormatter.h | 8 +++++ WiThrottle.cpp | 10 +++--- WifiInterface.cpp | 20 ++++++------ 10 files changed, 132 insertions(+), 60 deletions(-) diff --git a/DCC.cpp b/DCC.cpp index 679f771..bc663fb 100644 --- a/DCC.cpp +++ b/DCC.cpp @@ -43,7 +43,6 @@ const byte FN_GROUP_5=0x10; void DCC::begin(MotorDriver * mainDriver, MotorDriver* progDriver, byte timerNumber) { - debugMode=false; DCCWaveform::begin(mainDriver,progDriver, timerNumber); } @@ -352,10 +351,6 @@ void DCC::forgetAllLocos() { // removes all speed reminders for (int i=0;i0) { + used ++; + StringFormatter::send(stream,F("\ncab=%d, speed=%d, dir=%c "), + speedTable[reg].loco, speedTable[reg].speedCode & 0x7f,(speedTable[reg].speedCode & 0x80) ? 'F':'R'); + } + } + StringFormatter::send(stream,F("\nUsed=%d, max=%d\n"),used,MAX_LOCOS); + +} diff --git a/DCC.h b/DCC.h index ea14cbf..f62feb2 100644 --- a/DCC.h +++ b/DCC.h @@ -74,7 +74,6 @@ class DCC { static void updateGroupflags(byte & flags, int functionNumber); static void setAccessory(int aAdd, byte aNum, bool activate) ; static bool writeTextPacket( byte *b, int nBytes); - static void setDebug(bool on); static void setProgTrackSyncMain(bool on); // when true, prog track becomes driveable // ACKable progtrack calls bitresults callback 0,0 or -1, cv returns value or -1 @@ -88,7 +87,7 @@ class DCC { // Enhanced API functions static void forgetLoco(int cab); // removes any speed reminders for this loco static void forgetAllLocos(); // removes all speed reminders - + static void displayCabList(Print * stream); private: struct LOCO { int loco; @@ -108,7 +107,6 @@ private: static int lookupSpeedTable(int locoId); static void issueReminders(); static void callback(int value); - static bool debugMode; // ACK MANAGER static ackOp const * ackManagerProg; diff --git a/DCCEXParser.cpp b/DCCEXParser.cpp index b03805b..60b2233 100644 --- a/DCCEXParser.cpp +++ b/DCCEXParser.cpp @@ -24,6 +24,7 @@ #include "Turnouts.h" #include "Outputs.h" #include "Sensors.h" +#include "freeMemory.h" #include "EEStore.h" #include "DIAG.h" @@ -35,6 +36,14 @@ const char VERSION[] PROGMEM ="0.1.9"; const int HASH_KEYWORD_PROG=-29718; const int HASH_KEYWORD_MAIN=11339; const int HASH_KEYWORD_JOIN=-30750; +const int HASH_KEYWORD_CABS=-11981; +const int HASH_KEYWORD_RAM=25982; +const int HASH_KEYWORD_CMD=9962; +const int HASH_KEYWORD_WIT=31594; +const int HASH_KEYWORD_WIFI=-5583; +const int HASH_KEYWORD_ACK=3113; +const int HASH_KEYWORD_ON=2657; +const int HASH_KEYWORD_OFF=22479; int DCCEXParser::stashP[MAX_PARAMS]; @@ -50,7 +59,7 @@ bool DCCEXParser::stashBusy; DCCEXParser::DCCEXParser() {} void DCCEXParser::flush() { -DIAG(F("\nBuffer flush")); + if (Diag::CMD) DIAG(F("\nBuffer flush")); bufferLength=0; inCommandPayload=false; } @@ -133,7 +142,7 @@ void DCCEXParser::setFilter(FILTER_CALLBACK filter) { // See documentation on DCC class for info on this section void DCCEXParser::parse(Print * stream, byte *com, bool blocking) { - DIAG(F("\nPARSING:%s\n"),com); + if (Diag::CMD) DIAG(F("\nPARSING:%s\n"),com); (void) EEPROM; // tell compiler not to warn thi is unused int p[MAX_PARAMS]; while (com[0]=='<' || com[0]==' ') com++; // strip off any number of < or spaces @@ -145,22 +154,35 @@ void DCCEXParser::parse(Print * stream, byte *com, bool blocking) { // Functions return from this switch if complete, break from switch implies error to send switch(opcode) { case '\0': return; // filterCallback asked us to ignore - case 't': // THROTTLE + case 't': // THROTTLE { - if (params!=4) break; + int cab; + int tspeed; + int direction; + + if (params==4) { // + cab=p[1]; + tspeed=p[2]; + direction=p[3]; + } + else if (params==3) { // + cab=p[0]; + tspeed=p[1]; + direction=p[2]; + } + else break; // Convert JMRI bizarre -1=emergency stop, 0-126 as speeds // to DCC 0=stop, 1= emergency stop, 2-127 speeds - int tspeed=p[2]; if (tspeed>126 || tspeed<-1) break; // invalid JMRI speed code if (tspeed<0) tspeed=1; // emergency stop DCC speed else if (tspeed>0) tspeed++; // map 1-126 -> 2-127 - if (p[1] == 0 && tspeed>1) break; // ignore broadcasts of speed>1 + if (cab == 0 && tspeed>1) break; // ignore broadcasts of speed>1 - if (p[3]<0 || p[3]>1) break; // invalid direction code + if (direction<0 || direction>1) break; // invalid direction code - DCC::setThrottle(p[1],tspeed,p[3]); - StringFormatter::send(stream,F(""), p[0], p[2],p[3]); + DCC::setThrottle(cab,tspeed,direction); + if (params==4) StringFormatter::send(stream,F(""), p[0], p[2],p[3]); return; } case 'f': // FUNCTION @@ -240,7 +262,6 @@ void DCCEXParser::parse(Print * stream, byte *com, bool blocking) { return; } - DIAG(F("\nUnexpected keyword hash=%d\n"),p[0]); break; } return; @@ -278,8 +299,7 @@ void DCCEXParser::parse(Print * stream, byte *com, bool blocking) { return; case 'D': // < > - DCC::setDebug(p[0]==1); - DIAG(F("\nDCC DEBUG MODE %d"),p[0]==1); + if (parseD(stream,params,p)) return; return; case '#': // NUMBER OF LOCOSLOTS <#> @@ -287,7 +307,7 @@ void DCCEXParser::parse(Print * stream, byte *com, bool blocking) { return; case 'F': // New command to call the new Loco Function API - DIAG(F("Setting loco %d F%d %S"),p[0],p[1],p[2]?F("ON"):F("OFF")); + if (Diag::CMD) DIAG(F("Setting loco %d F%d %S"),p[0],p[1],p[2]?F("ON"):F("OFF")); DCC::setFn(p[0],p[1],p[2]==1); return; @@ -433,6 +453,40 @@ bool DCCEXParser::parseS( Print * stream,int params, int p[]) { return false; } +bool DCCEXParser::parseD( Print * stream,int params, int p[]) { + if (params==0) return false; + bool onOff=p[1]==1 || p[1]==HASH_KEYWORD_ON; // dont care if other stuff or missing... just means off + switch(p[0]){ + case HASH_KEYWORD_CABS: // + DCC::displayCabList(stream); + return true; + + case HASH_KEYWORD_RAM: // + StringFormatter::send(stream,F("\nFree memory=%d\n"),freeMemory()); + break; + + case HASH_KEYWORD_ACK: // + Diag::ACK=onOff; + return true; + + case HASH_KEYWORD_CMD: // + Diag::CMD=onOff; + return true; + + case HASH_KEYWORD_WIFI: // + Diag::WIFI=onOff; + return true; + + case HASH_KEYWORD_WIT: // + Diag::WITHROTTLE=onOff; + return true; + + default: // invalid/unknown + break; + } + return false; +} + // CALLBACKS must be static bool DCCEXParser::stashCallback(Print * stream,int p[MAX_PARAMS]) { diff --git a/DCCEXParser.h b/DCCEXParser.h index 4711e9c..9067340 100644 --- a/DCCEXParser.h +++ b/DCCEXParser.h @@ -44,6 +44,7 @@ struct DCCEXParser bool parseZ(Print * stream, int params, int p[]); bool parseS(Print * stream, int params, int p[]); bool parsef(Print * stream, int params, int p[]); + bool parseD(Print * stream, int params, int p[]); static bool stashBusy; diff --git a/DCCWaveform.cpp b/DCCWaveform.cpp index 024af68..2a59852 100644 --- a/DCCWaveform.cpp +++ b/DCCWaveform.cpp @@ -41,10 +41,9 @@ void DCCWaveform::begin(MotorDriver * mainDriver, MotorDriver * progDriver, byte case 2: interruptTimer= &TimerB; break; #ifndef ARDUINO_AVR_UNO case 3: interruptTimer= &TimerC; break; - case 4: interruptTimer= &TimerD; break; #endif default: - DIAG(F("\n\n *** Invalid Timer number %d requested. Only 1..4 valid. DCC will not work.*** \n\n"), timerNumber); + DIAG(F("\n\n *** Invalid Timer number %d requested. Only 1..3 valid. DCC will not work.*** \n\n"), timerNumber); return; } interruptTimer->initialize(); @@ -278,15 +277,14 @@ int DCCWaveform::getLastCurrent() { // Operations applicable to PROG track ONLY. // (yes I know I could have subclassed the main track but...) -void DCCWaveform::setAckBaseline(bool debug) { +void DCCWaveform::setAckBaseline() { if (isMainTrack) return; ackThreshold=motorDriver->getCurrentRaw() + (int)(65 / motorDriver->senseFactor); - if (debug) DIAG(F("\nACK-BASELINE %d/%dmA"),ackThreshold,motorDriver->convertToMilliamps(ackThreshold)); + if (Diag::ACK) DIAG(F("\nACK-BASELINE %d/%dmA"),ackThreshold,motorDriver->convertToMilliamps(ackThreshold)); } -void DCCWaveform::setAckPending(bool debug) { +void DCCWaveform::setAckPending() { if (isMainTrack) return; - (void)debug; ackMaxCurrent=0; ackPulseStart=0; ackPulseDuration=0; @@ -295,9 +293,9 @@ void DCCWaveform::setAckPending(bool debug) { ackPending=true; // interrupt routines will now take note } -byte DCCWaveform::getAck(bool debug) { +byte DCCWaveform::getAck() { if (ackPending) return (2); // still waiting - if (debug) DIAG(F("\nACK-%S after %dmS max=%d/%dmA pulse=%duS"),ackDetected?F("OK"):F("FAIL"), ackCheckDuration, + if (Diag::ACK) DIAG(F("\nACK-%S after %dmS max=%d/%dmA pulse=%duS"),ackDetected?F("OK"):F("FAIL"), ackCheckDuration, ackMaxCurrent,motorDriver->convertToMilliamps(ackMaxCurrent), ackPulseDuration); if (ackDetected) return (1); // Yes we had an ack return(0); // pending set off but not detected means no ACK. diff --git a/DCCWaveform.h b/DCCWaveform.h index 489dc89..fa2d444 100644 --- a/DCCWaveform.h +++ b/DCCWaveform.h @@ -62,9 +62,9 @@ class DCCWaveform { volatile bool packetPending; volatile byte sentResetsSincePacket; volatile bool autoPowerOff=false; - void setAckBaseline(bool debug); //prog track only - void setAckPending(bool debug); //prog track only - byte getAck(bool debug); //prog track only 0=NACK, 1=ACK 2=keep waiting + void setAckBaseline(); //prog track only + void setAckPending(); //prog track only + byte getAck(); //prog track only 0=NACK, 1=ACK 2=keep waiting static bool progTrackSyncMain; // true when prog track is a siding switched to main inline void doAutoPowerOff() { if (autoPowerOff) { diff --git a/StringFormatter.cpp b/StringFormatter.cpp index 89fd8cc..e99cfc3 100644 --- a/StringFormatter.cpp +++ b/StringFormatter.cpp @@ -31,6 +31,11 @@ #define __FlashStringHelper char #endif +bool Diag::ACK=false; +bool Diag::CMD=false; +bool Diag::WIFI=false; +bool Diag::WITHROTTLE=false; + void StringFormatter::diag( const __FlashStringHelper* input...) { if (!diagSerial) return; diff --git a/StringFormatter.h b/StringFormatter.h index 3d43ebf..62d2492 100644 --- a/StringFormatter.h +++ b/StringFormatter.h @@ -27,6 +27,14 @@ #define __FlashStringHelper char #endif +class Diag { + public: + static bool ACK; + static bool CMD; + static bool WIFI; + static bool WITHROTTLE; +}; + class StringFormatter { public: diff --git a/WiThrottle.cpp b/WiThrottle.cpp index 46c192a..f9c5a41 100644 --- a/WiThrottle.cpp +++ b/WiThrottle.cpp @@ -74,7 +74,7 @@ bool WiThrottle::areYouUsingThrottle(int cab) { // One instance of WiThrottle per connected client, so we know what the locos are WiThrottle::WiThrottle( int wificlientid) { - DIAG(F("\nCreating new WiThrottle for client %d\n"),wificlientid); + if (Diag::WITHROTTLE) DIAG(F("\nCreating new WiThrottle for client %d\n"),wificlientid); nextThrottle=firstThrottle; firstThrottle= this; clientid=wificlientid; @@ -110,7 +110,7 @@ void WiThrottle::parse(Print & stream, byte * cmdx) { byte * cmd=local; heartBeat=millis(); - // DIAG(F("\nWiThrottle(%d)<-[%e]\n"),clientid, cmd); + if (Diag::WITHROTTLE) DIAG(F("\nWiThrottle(%d)<-[%e]\n"),clientid, cmd); if (initSent) { // Send power state if different than last sent @@ -187,7 +187,7 @@ void WiThrottle::parse(Print & stream, byte * cmdx) { StringFormatter::send(stream, F("M%c-%c%d<;>\n"), myLocos[loco].throttle, LorS(myLocos[loco].cab), myLocos[loco].cab); } } - DIAG(F("WiThrottle(%d) Quit\n"), clientid); + if (Diag::WITHROTTLE) DIAG(F("WiThrottle(%d) Quit\n"), clientid); delete this; break; } @@ -345,10 +345,10 @@ void WiThrottle::loop() { void WiThrottle::checkHeartbeat() { // if 2 heartbeats missed... drop connection and eStop any locos still assigned to this client if(heartBeatEnable && (millis()-heartBeat > HEARTBEAT_TIMEOUT*2000)) { - DIAG(F("\n\nWiThrottle(%d) hearbeat missed, dropping connection\n\n"),clientid); + if (Diag::WITHROTTLE) DIAG(F("\n\nWiThrottle(%d) hearbeat missed, dropping connection\n\n"),clientid); LOOPLOCOS('*', -1) { if (myLocos[loco].throttle!='\0') { - DIAG(F(" eStopping cab %d\n"), myLocos[loco].cab); + if (Diag::WITHROTTLE) DIAG(F(" eStopping cab %d\n"), myLocos[loco].cab); DCC::setThrottle(myLocos[loco].cab, 1, DCC::getThrottleDirection(myLocos[loco].cab)); // speed 1 is eStop } } diff --git a/WifiInterface.cpp b/WifiInterface.cpp index c778510..c08a33e 100644 --- a/WifiInterface.cpp +++ b/WifiInterface.cpp @@ -231,7 +231,7 @@ void WifiInterface::loop() { int ch = wifiStream->read(); // echo the char to the diagnostic stream in escaped format - StringFormatter::printEscape(ch); // DIAG in disguise + if (Diag::WIFI) StringFormatter::printEscape(ch); // DIAG in disguise switch (loopstate) { case 0: // looking for +IPD @@ -272,7 +272,7 @@ void WifiInterface::loop() { case 10: // Waiting for > so we can send reply if (millis() - loopTimeoutStart > LOOP_TIMEOUT) { - DIAG(F("\nWifi TIMEOUT on wait for > prompt or ERROR\n")); + if (Diag::WIFI) DIAG(F("\nWifi TIMEOUT on wait for > prompt or ERROR\n")); loopstate = 0; // go back to +IPD break; } @@ -290,12 +290,12 @@ void WifiInterface::loop() { break; case 11: // Waiting for SEND OK or ERROR to complete so we can closeAfter if (millis() - loopTimeoutStart > LOOP_TIMEOUT) { - DIAG(F("\nWifi TIMEOUT on wait for SEND OK or ERROR\n")); + if (Diag::WIFI) DIAG(F("\nWifi TIMEOUT on wait for SEND OK or ERROR\n")); loopstate = 0; // go back to +IPD break; } if (ch == 'K') { // assume its in SEND OK - DIAG(F("\n Wifi AT+CIPCLOSE=%d\r\n"), connectionId); + if (Diag::WIFI) DIAG(F("\n Wifi AT+CIPCLOSE=%d\r\n"), connectionId); StringFormatter::send(wifiStream, F("AT+CIPCLOSE=%d\r\n"), connectionId); loopstate = 0; // wait for +IPD } @@ -303,12 +303,12 @@ void WifiInterface::loop() { case 12: // Waiting for OK after send busy if (ch == '+') { // Uh-oh IPD problem - DIAG(F("\n\n Wifi ASYNC CLASH - LOST REPLY\n")); + if (Diag::WIFI) DIAG(F("\n\n Wifi ASYNC CLASH - LOST REPLY\n")); connectionId = 0; loopstate = 1; } if (ch == 'K') { // assume its in SEND OK - DIAG(F("\n\n Wifi BUSY RETRYING.. AT+CIPSEND=%d,%d\r\n"), connectionId, streamer.available()); + if (Diag::WIFI) DIAG(F("\n\n Wifi BUSY RETRYING.. AT+CIPSEND=%d,%d\r\n"), connectionId, streamer.available()); StringFormatter::send(wifiStream, F("AT+CIPSEND=%d,%d\r\n"), connectionId, streamer.available()); loopTimeoutStart = millis(); loopstate = 10; // non-blocking loop waits for > before sending @@ -321,7 +321,7 @@ void WifiInterface::loop() { // AT this point we have read an incoming message into the buffer - DIAG(F("\n%l Wifi(%d)<-[%e]\n"), millis(),connectionId, buffer); + if (Diag::WIFI) DIAG(F("\n%l Wifi(%d)<-[%e]\n"), millis(),connectionId, buffer); streamer.setBufferContentPosition(0, 0); // reset write position to start of buffer // SIDE EFFECT WARNING::: // We know that parser will read the entire buffer before starting to write to it. @@ -345,7 +345,7 @@ void WifiInterface::loop() { if (streamer.available() == 0) { // No reply if (closeAfter) { - DIAG(F("AT+CIPCLOSE=%d\r\n"), connectionId); + if (Diag::WIFI) DIAG(F("AT+CIPCLOSE=%d\r\n"), connectionId); StringFormatter::send(wifiStream, F("AT+CIPCLOSE=%d\r\n"), connectionId); } loopstate = 0; // go back to waiting for +IPD @@ -353,8 +353,8 @@ void WifiInterface::loop() { } // prepare to send reply buffer[streamer.available()]='\0'; // mark end of buffer, so it can be used as a string later - DIAG(F("%l WiFi(%d)->[%e] l(%d)\n"), millis(), connectionId, buffer, streamer.available()); - DIAG(F("AT+CIPSEND=%d,%d\r\n"), connectionId, streamer.available()); + if (Diag::WIFI) DIAG(F("%l WiFi(%d)->[%e] l(%d)\n"), millis(), connectionId, buffer, streamer.available()); + if (Diag::WIFI) DIAG(F("AT+CIPSEND=%d,%d\r\n"), connectionId, streamer.available()); StringFormatter::send(wifiStream, F("AT+CIPSEND=%d,%d\r\n"), connectionId, streamer.available()); loopTimeoutStart = millis(); loopstate = 10; // non-blocking loop waits for > before sending