command. The number is what you get if you use the keyword as a parameter.
+// To discover new keyword numbers , use the <$ YOURKEYWORD> command
const int HASH_KEYWORD_PROG=-29718;
const int HASH_KEYWORD_MAIN=11339;
+const int HASH_KEYWORD_JOIN=-30750;
+
int DCCEXParser::stashP[MAX_PARAMS];
bool DCCEXParser::stashBusy;
@@ -202,23 +206,35 @@ void DCCEXParser::parse(Print & stream, const byte *com, bool blocking) {
if (params>1) break;
{
POWERMODE mode= opcode=='1'?POWERMODE::ON:POWERMODE::OFF;
+ DCC::setProgTrackSyncMain(false); // Only <1 JOIN> will set this on, all others set it off
if (params==0) {
DCCWaveform::mainTrack.setPowerMode(mode);
DCCWaveform::progTrack.setPowerMode(mode);
StringFormatter::send(stream,F(""),opcode);
return;
}
- if (p[0]==HASH_KEYWORD_MAIN) {
+ switch (p[0]) {
+ case HASH_KEYWORD_MAIN:
DCCWaveform::mainTrack.setPowerMode(mode);
StringFormatter::send(stream,F("
"),opcode);
return;
- }
- if (p[0]==HASH_KEYWORD_PROG) {
+
+ case HASH_KEYWORD_PROG:
DCCWaveform::progTrack.setPowerMode(mode);
StringFormatter::send(stream,F("
"),opcode);
return;
+ case HASH_KEYWORD_JOIN:
+ DCCWaveform::mainTrack.setPowerMode(mode);
+ DCCWaveform::progTrack.setPowerMode(mode);
+ if (mode==POWERMODE::ON) {
+ DCC::setProgTrackSyncMain(true);
+ StringFormatter::send(stream,F(""),opcode);
+ }
+ else StringFormatter::send(stream,F(""));
+ return;
+
}
- DIAG(F("keyword hash=%d\n"),p[0]);
+ DIAG(F("\nUnexpected keyword hash=%d\n"),p[0]);
break;
}
return;
@@ -258,10 +274,18 @@ void DCCEXParser::parse(Print & stream, const byte *com, bool blocking) {
return;
case '#': // NUMBER OF LOCOSLOTS <#>
- StringFormatter::send(stream,F("<# %d>"), MAX_LOCOS);
- return;
-
- default: //anything else will drop out to
+ StringFormatter::send(stream,F("<# %d>"), MAX_LOCOS);
+ 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"));
+ DCC::setFn(p[0],p[1],p[2]==1);
+ return;
+
+
+ default: //anything else will diagnose and drop out to
+ DIAG(F("\nOpcode=%c params=%d\n"),opcode,params);
+ for (int i=0;i
//#include // use IDE menu Tools..Manage Libraries to locate and install TimerOne
#include // use IDE menu Tools..Manage Libraries to locate and install TimerOne
-#include "avdweb_AnalogReadFast.h"
+#include "AnalogReadFast.h"
#include "Hardware.h"
#include "Config.h"
#include "DIAG.h"
diff --git a/WiThrottle.cpp b/WiThrottle.cpp
index 3a97e74..3974b54 100644
--- a/WiThrottle.cpp
+++ b/WiThrottle.cpp
@@ -103,14 +103,14 @@ void WiThrottle::parse(Print & stream, byte * cmdx) {
StringFormatter::send(stream,F("VN2.0\nHTDCC++EX\nRL0\nPPA%x\n"),DCCWaveform::mainTrack.getPowerMode()==POWERMODE::ON);
if (annotateLeftRight) StringFormatter::send(stream,F("PTT]\\[Turnouts}|{Turnout]\\[Left}|{2]\\[Right}|{4\n"));
else StringFormatter::send(stream,F("PTT]\\[Turnouts}|{Turnout]\\[Closed}|{2]\\[Thrown}|{4\n"));
- StringFormatter::send(stream,F("*10\n"));
+ StringFormatter::send(stream,F("*%d\n"),HEARTBEAT_TIMEOUT/2);
break;
case 1: // second call... send the turnout table if we have one
callState++;
if (Turnout::firstTurnout) {
StringFormatter::send(stream,F("PTL"));
for(Turnout *tt=Turnout::firstTurnout;tt!=NULL;tt=tt->nextTurnout){
- StringFormatter::send(stream,F("]\\[DT%d}|{T%d}|{%d"), tt->data.id, tt->data.id, (bool)(tt->data.tStatus & STATUS_ACTIVE));
+ StringFormatter::send(stream,F("]\\[%d}|{T%d}|{%d"), tt->data.id, tt->data.id, (bool)(tt->data.tStatus & STATUS_ACTIVE));
}
StringFormatter::send(stream,F("\n"));
}
@@ -131,26 +131,30 @@ void WiThrottle::parse(Print & stream, byte * cmdx) {
StringFormatter::send(stream, F("PPA%c\n"),cmd[3]);
}
else if (cmd[1]=='T' && cmd[2]=='A') { // PTA accessory toggle
- // TODO... if we are given an address that is not a known Turnout...
- // should we create one or just send the DCC message.
int id=getInt(cmd+4);
bool newstate=false;
+ Turnout * tt=Turnout::get(id);
+ if (!tt) {
+ StringFormatter::send(stream, F("HMTurnout %d Unknown\n"),id);
+ break;
+ }
switch (cmd[3]) {
case 'T': newstate=true; break;
case 'C': newstate=false; break;
case '2': newstate=!Turnout::isActive(id);
}
+ // If turnout does not exist, create it
if (Turnout::activate(id,newstate) == false) {
int addr = ((id - 1) / 4) + 1;
int subaddr = (id - 1) % 4;
Turnout::create(id,addr,subaddr);
Turnout::activate(id,newstate);
}
- StringFormatter::send(stream, F("PTA%cDT%d\n"),newstate?'4':'2',id );
+ StringFormatter::send(stream, F("PTA%c%d\n"),newstate?'4':'2',id );
}
break;
case 'N': // Heartbeat (2)
- StringFormatter::send(stream, F("*10\n")); // 10 second timeout
+ StringFormatter::send(stream, F("*%d\n"),HEARTBEAT_TIMEOUT/2); // 5 second timeout
break;
case 'M': // multithrottle
multithrottle(stream, cmd);
diff --git a/WiThrottle.h b/WiThrottle.h
index b0f29f9..1e64a29 100644
--- a/WiThrottle.h
+++ b/WiThrottle.h
@@ -36,7 +36,7 @@ class WiThrottle {
~WiThrottle();
static const int MAX_MY_LOCO=10;
- static const int HEARTBEAT_TIMEOUT=10;
+ static const int HEARTBEAT_TIMEOUT=10;// Timeout after 10 seconds, heartbeat at 5
static WiThrottle* firstThrottle;
static int getInt(byte * cmd);
static int getLocoId(byte * cmd);
diff --git a/WifiInterface.cpp b/WifiInterface.cpp
index 21963bc..460630a 100644
--- a/WifiInterface.cpp
+++ b/WifiInterface.cpp
@@ -23,7 +23,6 @@
#include "WiThrottle.h"
#include "HTTPParser.h"
const char PROGMEM READY_SEARCH[] ="\r\nready\r\n";
-const char PROGMEM WIFIOK_SEARCH[] ="\r\nWIFI GOT IPready\r\n";
const char PROGMEM OK_SEARCH[] ="\r\nOK\r\n";
const char PROGMEM END_DETAIL_SEARCH[] ="@ 1000";
const char PROGMEM PROMPT_SEARCH[] =">";
@@ -54,31 +53,38 @@ bool WifiInterface::setup2(Stream & wifiStream, const __FlashStringHelper* SSid,
delay(1000);
StringFormatter::send(wifiStream,F("AT+RST\r\n")); // reset module
- //checkForOK(wifiStream,5000,END_DETAIL_SEARCH,true); // Show startup but ignore unreadable upto ready
- checkForOK(wifiStream,5000,READY_SEARCH,true);
-
-// StringFormatter::send(wifiStream,F("AT+CWMODE=3\r\n")); // configure as server or access point
-// checkForOK(wifiStream,1000,OK_SEARCH,true); // Not always OK, sometimes "no change"
-
-// StringFormatter::send(wifiStream, F("AT+CWHOSTNAME=\"%S\"\r\n"), hostname); // Set Host name for Wifi Client
-// checkForOK(wifiStream,2000, OK_SEARCH, true);
+ checkForOK(wifiStream,5000,READY_SEARCH,false); // generally not interesting to DCC
+ StringFormatter::send(wifiStream,F("AT+GMR\r\n")); // request AT version
+ checkForOK(wifiStream,2000,OK_SEARCH,true); // Makes this visible on the console
+
+ StringFormatter::send(wifiStream,F("AT+CWMODE=3\r\n")); // configure as server or access point
+ checkForOK(wifiStream,1000,OK_SEARCH,true); // Not always OK, sometimes "no change"
// Older ES versions have AT+CWJAP, newer ones have AT+CWJAP_CUR and AT+CWHOSTNAME
-// StringFormatter::send(wifiStream,F("AT+CWJAP=\"%S\",\"%S\"\r\n"),SSid,password);
-// if (!checkForOK(wifiStream,20000,OK_SEARCH,true)) {
-// StringFormatter::send(wifiStream,F("AT+CWJAP_CUR=\"%S\",\"%S\"\r\n"),SSid,password);
-// if (!checkForOK(wifiStream,20000,OK_SEARCH,true)) return false;
-// }
-
- checkForOK(wifiStream,5000,WIFIOK_SEARCH,true);
-
- StringFormatter::send(wifiStream,F("AT+CWJAP?\r\n"),SSid,password);
- if (!checkForOK(wifiStream,20000,OK_SEARCH,true)) {
- StringFormatter::send(wifiStream,F("AT+CWJAP_CUR?\r\n"),SSid,password);
- if (!checkForOK(wifiStream,20000,OK_SEARCH,true)) return false;
+ StringFormatter::send(wifiStream,F("AT+CWJAP?\r\n"));
+ if (checkForOK(wifiStream,2000,OK_SEARCH,true)) {
+ // early version supports CWJAP
+ StringFormatter::send(wifiStream,F("AT+CWJAP=\"%S\",\"%S\"\r\n"),SSid,password);
+ checkForOK(wifiStream,20000,OK_SEARCH,true); // can ignore failure as AP mode may still be ok
}
+ else {
+ // later version supports CWJAP_CUR
+ StringFormatter::send(wifiStream, F("AT+CWHOSTNAME=\"%S\"\r\n"), hostname); // Set Host name for Wifi Client
+ checkForOK(wifiStream,2000, OK_SEARCH, true); // dont care if not supported
+ StringFormatter::send(wifiStream,F("AT+CWJAP_CUR=\"%S\",\"%S\"\r\n"),SSid,password);
+ checkForOK(wifiStream,20000,OK_SEARCH,true); // can ignore failure as AP mode may still be ok
+
+ StringFormatter::send(wifiStream,F("AT+CIPRECVMODE=0\r\n"),port); // make sure transfer mode is correct
+ checkForOK(wifiStream,2000,OK_SEARCH,true);
+
+ // StringFormatter::send(wifiStream, F("AT+MDNS=1,\"%S.local\",\"%S.local\",%d\r\n"), hostname, servername, port); // Setup mDNS for Server
+ // if (!checkForOK(wifiStream,5000, OK_SEARCH, true)) return false;
+ (void)servername; // avoid compiler warning from commented out AT_MDNS above
+
+ }
+
StringFormatter::send(wifiStream,F("AT+CIFSR\r\n")); // get ip address //192.168.4.1
if (!checkForOK(wifiStream,10000,OK_SEARCH,true)) return false;
@@ -86,15 +92,9 @@ bool WifiInterface::setup2(Stream & wifiStream, const __FlashStringHelper* SSid,
StringFormatter::send(wifiStream,F("AT+CIPMUX=1\r\n")); // configure for multiple connections
if (!checkForOK(wifiStream,10000,OK_SEARCH,true)) return false;
- StringFormatter::send(wifiStream,F("AT+CIPSERVER=1,%d\r\n"),port); // turn on server on port 80
+ StringFormatter::send(wifiStream,F("AT+CIPSERVER=1,%d\r\n"),port); // turn on server on port
if (!checkForOK(wifiStream,10000,OK_SEARCH,true)) return false;
- StringFormatter::send(wifiStream,F("AT+CIPRECVMODE=0\r\n"),port); // turn on server on port 80
- if (!checkForOK(wifiStream,10000,OK_SEARCH,true)) return false;
-
- // StringFormatter::send(wifiStream, F("AT+MDNS=1,\"%S.local\",\"%S.local\",%d\r\n"), hostname, servername, port); // Setup mDNS for Server
- // if (!checkForOK(wifiStream,5000, OK_SEARCH, true)) return false;
- (void)servername; // not currently in use
return true;
}
diff --git a/avdweb_AnalogReadFast.h b/avdweb_AnalogReadFast.h
deleted file mode 100644
index ae68432..0000000
--- a/avdweb_AnalogReadFast.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
-Copyright (C) 2016 Albert van Dalen http://www.avdweb.nl
-This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
-This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
-of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License at http://www.gnu.org/licenses .
-
-AUTHOR: Albert van Dalen
-WEBSITE: http://www.avdweb.nl/arduino/libraries/fast-10-bit-adc.html
-UPDATE: https://www.avdweb.nl/arduino/adc-dac/fast-10-bit-adc
-HISTORY:
-1.0.0 7-3-2018 analogReadFast for SAMD21 (10/12bit) and AVR (10bit)
-*/
-
-#ifndef analogReadFast_H
-#define analogReadFast_H
-
-int inline analogReadFast(byte ADCpin);
-
-#if defined(__arm__)
-int inline analogReadFast(byte ADCpin) // inline library functions must be in header
-{ ADC->CTRLA.bit.ENABLE = 0; // disable ADC
- while( ADC->STATUS.bit.SYNCBUSY == 1 ); // wait for synchronization
-
- int CTRLBoriginal = ADC->CTRLB.reg;
- int AVGCTRLoriginal = ADC->AVGCTRL.reg;
- int SAMPCTRLoriginal = ADC->SAMPCTRL.reg;
-
- ADC->CTRLB.reg &= 0b1111100011111111; // mask PRESCALER bits
- ADC->CTRLB.reg |= ADC_CTRLB_PRESCALER_DIV64; // divide Clock by 64
- ADC->AVGCTRL.reg = ADC_AVGCTRL_SAMPLENUM_1 | // take 1 sample
- ADC_AVGCTRL_ADJRES(0x00ul); // adjusting result by 0
- ADC->SAMPCTRL.reg = 0x00; // sampling Time Length = 0
-
- ADC->CTRLA.bit.ENABLE = 1; // enable ADC
- while(ADC->STATUS.bit.SYNCBUSY == 1); // wait for synchronization
-
- int adc = analogRead(ADCpin);
-
- ADC->CTRLB.reg = CTRLBoriginal;
- ADC->AVGCTRL.reg = AVGCTRLoriginal;
- ADC->SAMPCTRL.reg = SAMPCTRLoriginal;
-
- return adc;
-}
-#else
-int inline analogReadFast(byte ADCpin)
-{ byte ADCSRAoriginal = ADCSRA;
- ADCSRA = (ADCSRA & B11111000) | 4;
- int adc = analogRead(ADCpin);
- ADCSRA = ADCSRAoriginal;
- return adc;
-}
-#endif
-#endif