From 0a3d2e75950ddcaa8ce7d8d952abb2cf5d2bc98d Mon Sep 17 00:00:00 2001 From: Harald Barth Date: Sat, 4 Jul 2020 21:53:44 +0200 Subject: [PATCH 1/7] Implement # command --- CVReader.ino | 6 +++--- DCCEXParser.cpp | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/CVReader.ino b/CVReader.ino index be69908..913e1b4 100644 --- a/CVReader.ino +++ b/CVReader.ino @@ -43,10 +43,10 @@ void myFilter(Print & stream, byte & opcode, byte & paramCount, int p[]) { DCC::setFn(p[0],p[1],p[2]==1); opcode=0; // tell parser to ignore this command break; - case '#': // Diagnose parser <#....> - DIAG(F("# paramCount=%d\n"),paramCount); + case '$': // Diagnose parser <$....> + DIAG(F("$ paramCount=%d\n"),paramCount); for (int i=0;i + StringFormatter::send(stream,F("<# %d>"), MAX_LOCOS); + return; default: //anything else will drop out to break; From 4aceff8b7c640f9471c6492893a0284f5a11eeb5 Mon Sep 17 00:00:00 2001 From: Asbelos Date: Sun, 5 Jul 2020 21:00:27 +0100 Subject: [PATCH 2/7] WiThrott;e FIXES --- DCC.cpp | 2 +- WiThrottle.cpp | 52 +++++++++++++++++++++++++++++++++-------------- WiThrottle.h | 5 +++-- WifiInterface.cpp | 4 ++-- 4 files changed, 43 insertions(+), 20 deletions(-) diff --git a/DCC.cpp b/DCC.cpp index 7051d35..462b5c4 100644 --- a/DCC.cpp +++ b/DCC.cpp @@ -390,7 +390,7 @@ int DCC::lookupSpeedTable(int locoId) { } if (reg==firstEmpty){ speedTable[reg].loco = locoId; - speedTable[reg].speedCode=0; + speedTable[reg].speedCode=128; // default direction forward speedTable[reg].groupFlags=0; speedTable[reg].functions=0; } diff --git a/WiThrottle.cpp b/WiThrottle.cpp index 7af7373..9aad625 100644 --- a/WiThrottle.cpp +++ b/WiThrottle.cpp @@ -51,27 +51,22 @@ WiThrottle * WiThrottle::firstThrottle=NULL; -WiThrottle* WiThrottle::getThrottle(Print & stream, int wifiClient) { +WiThrottle* WiThrottle::getThrottle( int wifiClient) { for (WiThrottle* wt=firstThrottle; wt!=NULL ; wt=wt->nextThrottle) if (wt->clientid==wifiClient) return wt; - return new WiThrottle(stream, wifiClient); + return new WiThrottle( wifiClient); } // One instance of WiTHrottle per connected client, so we know what the locos are -WiThrottle::WiThrottle(Print & stream, int wificlientid) { +WiThrottle::WiThrottle( int wificlientid) { DIAG(F("\nCreating new WiThrottle for client %d\n"),wificlientid); nextThrottle=firstThrottle; firstThrottle= this; clientid=wificlientid; - for (int loco=0;loconextTurnout){ - StringFormatter::send(stream,F("]\\[LT&d}|{%d}|{%d"), tt->data.id, tt->data.id, (bool)(tt->data.tStatus & STATUS_ACTIVE)); - } - StringFormatter::send(stream,F("\n*10\n")); - heartBeatEnable=false; // until client turns it on + heartBeatEnable=false; // until client turns it on + firstCall=true; + for (int loco=0;loconextTurnout){ + StringFormatter::send(stream,F("]\\[LT&d}|{%d}|{%d"), tt->data.id, tt->data.id, (bool)(tt->data.tStatus & STATUS_ACTIVE)); + } + StringFormatter::send(stream,F("\n*10\n")); + } + + while (cmd[0]) { switch (cmd[0]) { case '*': // heartbeat control if (cmd[1]=='+') heartBeatEnable=true; @@ -119,6 +137,10 @@ void WiThrottle::parse(Print & stream, byte * cmd) { DIAG(F("\nWiThrottle Quit")); delete this; break; + } + // skip over cmd until 0 or past \r or \n + while(*cmd !='\0' && *cmd != '\r' && *cmd !='\n') cmd++; + if (*cmd!='\0') cmd++; // skip \r or \n } } int WiThrottle::getInt(byte * cmd) { @@ -196,12 +218,12 @@ void WiThrottle::locoAction(Print & stream, byte* aval, char throttleChar, int c case 'q': if (aval[1]=='V') { //qV LOOPLOCOS(throttleChar, cab) { - StringFormatter::send(stream,F("M%cAL%d<;>V%d"), throttleChar, myLocos[loco].cab, DCC::getThrottleSpeed(myLocos[loco].cab)); + StringFormatter::send(stream,F("M%cAL%d<;>V%d\n"), throttleChar, myLocos[loco].cab, DCC::getThrottleSpeed(myLocos[loco].cab)); } } else if (aval[1]=='R') { // qR LOOPLOCOS(throttleChar, cab) { - StringFormatter::send(stream,F("M%cAL%d<;>R%d"), throttleChar, myLocos[loco].cab, DCC::getThrottleDirection(myLocos[loco].cab)); + StringFormatter::send(stream,F("M%cAL%d<;>R%d\n"), throttleChar, myLocos[loco].cab, DCC::getThrottleDirection(myLocos[loco].cab)); } } break; diff --git a/WiThrottle.h b/WiThrottle.h index 94cf3c0..d0c3f4b 100644 --- a/WiThrottle.h +++ b/WiThrottle.h @@ -29,10 +29,10 @@ class WiThrottle { public: static void loop(); void parse(Print & stream, byte * cmd); - static WiThrottle* getThrottle(Print & stream, int wifiClient); + static WiThrottle* getThrottle( int wifiClient); private: - WiThrottle(Print & stream, int wifiClientId); + WiThrottle( int wifiClientId); ~WiThrottle(); static const int MAX_MY_LOCO=10; @@ -46,6 +46,7 @@ class WiThrottle { MYLOCO myLocos[MAX_MY_LOCO]; bool heartBeatEnable; + bool firstCall; unsigned long heartBeat; void multithrottle(Print & stream, byte * cmd); diff --git a/WifiInterface.cpp b/WifiInterface.cpp index 6cbefaf..1a1196c 100644 --- a/WifiInterface.cpp +++ b/WifiInterface.cpp @@ -172,12 +172,12 @@ void WifiInterface::loop(Stream & wifiStream) { } else if (buffer[0]=='<') parser.parse(streamer,buffer, true); // tell JMRI parser that callbacks are diallowed because we dont want to handle the async - else WiThrottle::getThrottle(streamer, connectionId)->parse(streamer, buffer); + else WiThrottle::getThrottle(connectionId)->parse(streamer, buffer); if (streamer.available()) { // there is a reply to send streamer.write('\0'); - DIAG(F("WiFiInterface Responding client (%d) l(%d) %e\n"),connectionId,streamer.available()-1,buffer); + DIAG(F("\nWiFiInterface reply c(%d) l(%d) [%e]\n"),connectionId,streamer.available()-1,buffer); StringFormatter::send(wifiStream,F("AT+CIPSEND=%d,%d\r\n"),connectionId,streamer.available()-1); if (checkForOK(wifiStream,1000,PROMPT_SEARCH,true)) wifiStream.print((char *) buffer); From e27c176fdf611d1f470e9cbcdd71d073a2d9bc6d Mon Sep 17 00:00:00 2001 From: Asbelos Date: Sun, 5 Jul 2020 21:24:54 +0100 Subject: [PATCH 3/7] No reminders for F13-F28 --- DCC.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/DCC.cpp b/DCC.cpp index 462b5c4..2f9db18 100644 --- a/DCC.cpp +++ b/DCC.cpp @@ -347,10 +347,12 @@ bool DCC::issueReminder(int reg) { case 4: // remind function group 4 F13-F20 if (flags & FN_GROUP_4) setFunctionInternal(loco,222, ((functions>>13)& 0xFF)); + flags&= ~FN_GROUP_4; // dont send them again break; case 5: // remind function group 5 F21-F28 if (flags & FN_GROUP_5) setFunctionInternal(loco,223, ((functions>>21)& 0xFF)); + flags&= ~FN_GROUP_5; // dont send them again break; } loopStatus++; From 333410c368f5dd9bd9652282d0864b725f6afaf4 Mon Sep 17 00:00:00 2001 From: Asbelos Date: Sat, 11 Jul 2020 09:06:34 +0100 Subject: [PATCH 4/7] Change PROG current detect during ACK --- DCCWaveform.cpp | 5 +++-- DCCWaveform.h | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/DCCWaveform.cpp b/DCCWaveform.cpp index f0045ee..8c14c43 100644 --- a/DCCWaveform.cpp +++ b/DCCWaveform.cpp @@ -99,6 +99,7 @@ void DCCWaveform::setPowerMode(POWERMODE mode) { void DCCWaveform::checkPowerOverload() { + if (millis() - lastSampleTaken < sampleDelay) return; lastSampleTaken = millis(); @@ -109,11 +110,11 @@ void DCCWaveform::checkPowerOverload() { case POWERMODE::ON: // Check current lastCurrent = Hardware::getCurrentRaw(isMainTrack); - if (lastCurrent <= rawCurrentTripValue) sampleDelay = POWER_SAMPLE_ON_WAIT; + if (lastCurrent <= (ackPending?ACK_CURRENT_TRIP:rawCurrentTripValue)) sampleDelay = POWER_SAMPLE_ON_WAIT; else { setPowerMode(POWERMODE::OVERLOAD); unsigned int mA=Hardware::getCurrentMilliamps(isMainTrack,lastCurrent); - unsigned int maxmA=Hardware::getCurrentMilliamps(isMainTrack,rawCurrentTripValue); + unsigned int maxmA=Hardware::getCurrentMilliamps(isMainTrack,ackPending?ACK_CURRENT_TRIP:rawCurrentTripValue); DIAG(F("\n*** %S TRACK POWER OVERLOAD current=%d max=%d ***\n"), isMainTrack ? F("MAIN") : F("PROG"), mA, maxmA); sampleDelay = POWER_SAMPLE_OVERLOAD_WAIT; } diff --git a/DCCWaveform.h b/DCCWaveform.h index 537a05b..af562b0 100644 --- a/DCCWaveform.h +++ b/DCCWaveform.h @@ -94,7 +94,8 @@ class DCCWaveform { unsigned long lastSampleTaken; unsigned int sampleDelay; int rawCurrentTripValue; - + static const int ACK_CURRENT_TRIP=1000; // During ACK processing limit can be higher + // ACK management (Prog track only) bool ackPending; bool ackDetected; From ff881790ac17aae1a2f5b782016f266cc645a173 Mon Sep 17 00:00:00 2001 From: Asbelos Date: Sat, 11 Jul 2020 09:35:57 +0100 Subject: [PATCH 5/7] Increase PROG repeats refer @grbba --- DCC.cpp | 12 +++++++----- DCC.h | 1 + 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/DCC.cpp b/DCC.cpp index 2f9db18..e5e9638 100644 --- a/DCC.cpp +++ b/DCC.cpp @@ -454,9 +454,10 @@ void DCC::ackManagerLoop() { case W1: // write 1 bit { if (resets Date: Sun, 12 Jul 2020 00:08:50 +0100 Subject: [PATCH 6/7] Parse with < bug --- DCCEXParser.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/DCCEXParser.cpp b/DCCEXParser.cpp index ff16c57..48dd364 100644 --- a/DCCEXParser.cpp +++ b/DCCEXParser.cpp @@ -131,10 +131,9 @@ void DCCEXParser::parse(Print & stream, const byte *com, bool banAsync) { DIAG(F("\nPARSING:%s\n"),com); asyncBanned=banAsync; (void) EEPROM; // tell compiler not to warn thi is unused - int p[MAX_PARAMS]; + int p[MAX_PARAMS]; + while (com[0]=='<' || com[0]==' ') com++; // strip off any number of < or spaces byte params=splitValues(p, com); - - if (com[0]=='<') com++; byte opcode=com[0]; if (filterCallback) filterCallback(stream,opcode,params,p); From a245b9d119d2188c6daaa918fa5569b2a84f6510 Mon Sep 17 00:00:00 2001 From: Asbelos Date: Sun, 12 Jul 2020 00:11:30 +0100 Subject: [PATCH 7/7] Prog-Track-As-Siding --- DCC.cpp | 4 +++- DCC.h | 1 + DCCWaveform.cpp | 26 +++++++++++++++++++------- DCCWaveform.h | 4 +++- 4 files changed, 26 insertions(+), 9 deletions(-) diff --git a/DCC.cpp b/DCC.cpp index e5e9638..97564be 100644 --- a/DCC.cpp +++ b/DCC.cpp @@ -157,7 +157,9 @@ void DCC::writeCVBitMain(int cab, int cv, byte bNum, bool bValue) { DCCWaveform::mainTrack.schedulePacket(b, nB, 4); } - +void DCC::setProgTrackSyncMain(bool on) { + DCCWaveform::progTrackSyncMain=on; +} const ackOp PROGMEM WRITE_BIT0_PROG[] = { BASELINE, diff --git a/DCC.h b/DCC.h index f825e3d..4111263 100644 --- a/DCC.h +++ b/DCC.h @@ -63,6 +63,7 @@ class DCC { 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 static void readCV(int cv, ACK_CALLBACK callback); diff --git a/DCCWaveform.cpp b/DCCWaveform.cpp index 8c14c43..e6ee023 100644 --- a/DCCWaveform.cpp +++ b/DCCWaveform.cpp @@ -26,7 +26,7 @@ DCCWaveform DCCWaveform::progTrack(PREAMBLE_BITS_PROG, false, (int)(PROG_MAX_MI const int ACK_MIN_PULSE_RAW=65 / PROG_SENSE_FACTOR; - +bool DCCWaveform::progTrackSyncMain=false; void DCCWaveform::begin() { Hardware::init(); @@ -102,6 +102,8 @@ void DCCWaveform::checkPowerOverload() { if (millis() - lastSampleTaken < sampleDelay) return; lastSampleTaken = millis(); + int tripValue= rawCurrentTripValue; + if (!isMainTrack && (ackPending || progTrackSyncMain)) tripValue=ACK_CURRENT_TRIP; switch (powerMode) { case POWERMODE::OFF: @@ -110,11 +112,11 @@ void DCCWaveform::checkPowerOverload() { case POWERMODE::ON: // Check current lastCurrent = Hardware::getCurrentRaw(isMainTrack); - if (lastCurrent <= (ackPending?ACK_CURRENT_TRIP:rawCurrentTripValue)) sampleDelay = POWER_SAMPLE_ON_WAIT; + if (lastCurrent <= tripValue) sampleDelay = POWER_SAMPLE_ON_WAIT; else { setPowerMode(POWERMODE::OVERLOAD); unsigned int mA=Hardware::getCurrentMilliamps(isMainTrack,lastCurrent); - unsigned int maxmA=Hardware::getCurrentMilliamps(isMainTrack,ackPending?ACK_CURRENT_TRIP:rawCurrentTripValue); + unsigned int maxmA=Hardware::getCurrentMilliamps(isMainTrack,tripValue); DIAG(F("\n*** %S TRACK POWER OVERLOAD current=%d max=%d ***\n"), isMainTrack ? F("MAIN") : F("PROG"), mA, maxmA); sampleDelay = POWER_SAMPLE_OVERLOAD_WAIT; } @@ -140,19 +142,19 @@ bool DCCWaveform::interrupt1() { // otherwise can cause hangs in main loop waiting for the pendingBuffer. switch (state) { case 0: // start of bit transmission - Hardware::setSignal(isMainTrack, HIGH); + setSignal(HIGH); state = 1; return true; // must call interrupt2 to set currentBit case 1: // 58us after case 0 if (currentBit) { - Hardware::setSignal(isMainTrack, LOW); + setSignal(LOW); state = 0; } else state = 2; break; case 2: // 116us after case 0 - Hardware::setSignal(isMainTrack, LOW); + setSignal(LOW); state = 3; break; case 3: // finished sending zero bit @@ -168,7 +170,17 @@ bool DCCWaveform::interrupt1() { } - +void DCCWaveform::setSignal(bool high) { + if (progTrackSyncMain) { + if (!isMainTrack) return; // ignore PROG track waveform while in sync + // set both tracks to same signal + Hardware::setSignal(true, high); + Hardware::setSignal(false, high); + return; + } + Hardware::setSignal(isMainTrack,high); +} + void DCCWaveform::interrupt2() { // set currentBit to be the next bit to be sent. diff --git a/DCCWaveform.h b/DCCWaveform.h index af562b0..3fc8015 100644 --- a/DCCWaveform.h +++ b/DCCWaveform.h @@ -62,13 +62,15 @@ class DCCWaveform { 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 - + static bool progTrackSyncMain; // true when prog track is a siding switched to main + private: static void interruptHandler(); bool interrupt1(); void interrupt2(); void checkAck(); + void setSignal(bool high); bool isMainTrack;