diff --git a/DCCEXParser.cpp b/DCCEXParser.cpp index ece2842..64e1213 100644 --- a/DCCEXParser.cpp +++ b/DCCEXParser.cpp @@ -96,6 +96,7 @@ void DCCEXParser::loop(Stream &stream) buffer[bufferLength++] = ch; } } + Sensor::checkAll(&stream); // Update and print changes } int DCCEXParser::splitValues(int result[MAX_PARAMS], const byte *cmd) @@ -359,11 +360,7 @@ void DCCEXParser::parse(Print *stream, byte *com, bool blocking) return; case 'Q': // SENSORS - Sensor::checkAll(); - for (Sensor *tt = Sensor::firstSensor; tt != NULL; tt = tt->nextSensor) - { - StringFormatter::send(stream, F("<%c %d>"), tt->active ? 'Q' : 'q', tt->data.snum); - } + Sensor::printAll(stream); return; case 's': // @@ -426,7 +423,7 @@ bool DCCEXParser::parseZ(Print *stream, int params, int p[]) switch (params) { - + case 2: // { Output *o = Output::get(p[0]); @@ -438,11 +435,16 @@ bool DCCEXParser::parseZ(Print *stream, int params, int p[]) return true; case 3: // - Output::create(p[0], p[1], p[2], 1); + if (!Output::create(p[0], p[1], p[2], 1)) + return false; + StringFormatter::send(stream, F("")); return true; case 1: // - return Output::remove(p[0]); + if (!Output::remove(p[0])) + return false; + StringFormatter::send(stream, F("")); + return true; case 0: // { @@ -550,15 +552,20 @@ bool DCCEXParser::parseS(Print *stream, int params, int p[]) switch (params) { case 3: // create sensor. pullUp indicator (0=LOW/1=HIGH) - Sensor::create(p[0], p[1], p[2]); + if (!Sensor::create(p[0], p[1], p[2])) + return false; + StringFormatter::send(stream, F("")); return true; case 1: // S id> remove sensor - if (Sensor::remove(p[0])) - return true; - break; + if (!Sensor::remove(p[0])) + return false; + StringFormatter::send(stream, F("")); + return true; case 0: // lit sensor states + if (Sensor::firstSensor == NULL) + return false; for (Sensor *tt = Sensor::firstSensor; tt != NULL; tt = tt->nextSensor) { StringFormatter::send(stream, F(""), tt->data.snum, tt->data.pin, tt->data.pullUp); diff --git a/EEStore.cpp b/EEStore.cpp index a3d2d55..14ed925 100644 --- a/EEStore.cpp +++ b/EEStore.cpp @@ -1,3 +1,23 @@ +/* + * © 2013-2016 Gregg E. Berman + * © 2020, Chris Harlow. All rights reserved. + * © 2020, Harald Barth. + * + * This file is part of Asbelos DCC API + * + * This 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. + * + * It 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 for more details. + * + * You should have received a copy of the GNU General Public License + * along with CommandStation. If not, see . + */ #include "EEStore.h" #include "Turnouts.h" #include "Sensors.h" @@ -77,7 +97,7 @@ void EEStore::dump(int num) { DIAG(F("\nAddr 0x char\n")); for (int n=0 ; n0) EEPROM.put(num,data.oStatus); - } /////////////////////////////////////////////////////////////////////////////// diff --git a/Sensors.cpp b/Sensors.cpp index 3f55c5f..c914996 100644 --- a/Sensors.cpp +++ b/Sensors.cpp @@ -65,27 +65,62 @@ decide to ignore the return and only react to triggers. **********************************************************************/ - +#include "StringFormatter.h" #include "Sensors.h" #include "EEStore.h" +/////////////////////////////////////////////////////////////////////////////// +// +// checks one defined sensors and prints _changed_ sensor state +// to stream unless stream is NULL in which case only internal +// state is updated. Then advances to next sensor which will +// be checked att next invocation. +// /////////////////////////////////////////////////////////////////////////////// -void Sensor::checkAll(){ - - for(Sensor * tt=firstSensor;tt!=NULL;tt=tt->nextSensor){ - tt->signal=tt->signal*(1.0-SENSOR_DECAY)+digitalRead(tt->data.pin)*SENSOR_DECAY; +void Sensor::checkAll(Print *stream){ - if(!tt->active && tt->signal<0.5){ - tt->active=true; - } else if(tt->active && tt->signal>0.9){ - tt->active=false; + if (firstSensor == NULL) return; + if (readingSensor == NULL) readingSensor=firstSensor; + + bool sensorstate = digitalRead(readingSensor->data.pin); + + if (!sensorstate == readingSensor->active) { // active==true means sensorstate=0/false so sensor unchanged + // no change + if (readingSensor->latchdelay != 0) { + // enable if you want to debug contact jitter + //if (stream != NULL) StringFormatter::send(stream, F("JITTER %d %d\n"), + // readingSensor->latchdelay, readingSensor->data.snum); + readingSensor->latchdelay=0; // reset } - } // loop over all sensors + } else if (readingSensor->latchdelay < 127) { // byte, max 255, good value unknown yet + // change but first increase anti-jitter counter + readingSensor->latchdelay++; + } else { + // make the change + readingSensor->active = !sensorstate; + readingSensor->latchdelay=0; // reset + if (stream != NULL) StringFormatter::send(stream, F("<%c %d>"), readingSensor->active ? 'Q' : 'q', readingSensor->data.snum); + } + readingSensor=readingSensor->nextSensor; } // Sensor::checkAll +/////////////////////////////////////////////////////////////////////////////// +// +// prints all sensor states to stream +// +/////////////////////////////////////////////////////////////////////////////// + +void Sensor::printAll(Print *stream){ + + for(Sensor * tt=firstSensor;tt!=NULL;tt=tt->nextSensor){ + if (stream != NULL) + StringFormatter::send(stream, F("<%c %d>"), tt->active ? 'Q' : 'q', tt->data.snum); + } // loop over all sensors +} // Sensor::printAll + /////////////////////////////////////////////////////////////////////////////// Sensor *Sensor::create(int snum, int pin, int pullUp){ @@ -108,7 +143,7 @@ Sensor *Sensor::create(int snum, int pin, int pullUp){ tt->data.pin=pin; tt->data.pullUp=(pullUp==0?LOW:HIGH); tt->active=false; - tt->signal=1; + tt->latchdelay=0; pinMode(pin,INPUT); // set mode to input digitalWrite(pin,pullUp); // don't use Arduino's internal pull-up resistors for external infrared sensors --- each sensor must have its own 1K external pull-up resistor @@ -137,6 +172,7 @@ bool Sensor::remove(int n){ else pp->nextSensor=tt->nextSensor; + if (readingSensor==tt) readingSensor=tt->nextSensor; free(tt); return true; @@ -174,3 +210,4 @@ void Sensor::store(){ /////////////////////////////////////////////////////////////////////////////// Sensor *Sensor::firstSensor=NULL; +Sensor *Sensor::readingSensor=NULL; diff --git a/Sensors.h b/Sensors.h index 71f60ba..36e8157 100644 --- a/Sensors.h +++ b/Sensors.h @@ -31,16 +31,18 @@ struct SensorData { struct Sensor{ static Sensor *firstSensor; + static Sensor *readingSensor; SensorData data; boolean active; - float signal; + byte latchdelay; Sensor *nextSensor; static void load(); static void store(); static Sensor *create(int, int, int); static Sensor* get(int); static bool remove(int); - static void checkAll(); + static void checkAll(Print *); + static void printAll(Print *); }; // Sensor #endif diff --git a/WifiInterface.cpp b/WifiInterface.cpp index be17b02..422af7a 100644 --- a/WifiInterface.cpp +++ b/WifiInterface.cpp @@ -57,7 +57,7 @@ bool WifiInterface::setup(long serial_link_speed, const __FlashStringHelper *hostname, const int port) { - bool wifiUp = false; + wifiSerialState wifiUp = WIFI_NOAT; #if NUM_SERIAL == 0 // no warning about unused parameters. @@ -75,7 +75,7 @@ bool WifiInterface::setup(long serial_link_speed, // Other serials are tried, depending on hardware. #if NUM_SERIAL > 1 - if (!wifiUp) + if (wifiUp == WIFI_NOAT) { Serial2.begin(serial_link_speed); wifiUp = setup(Serial2, wifiESSID, wifiPassword, hostname, port); @@ -83,23 +83,29 @@ bool WifiInterface::setup(long serial_link_speed, #endif #if NUM_SERIAL > 2 - if (!wifiUp) + if (wifiUp == WIFI_NOAT) { Serial3.begin(serial_link_speed); wifiUp = setup(Serial3, wifiESSID, wifiPassword, hostname, port); } #endif -DCCEXParser::setAtCommandCallback(ATCommand); + if (wifiUp == WIFI_NOAT) // here and still not AT commands found + return false; -// CAUTION... ONLY CALL THIS ONCE -WifiInboundHandler::setup(wifiStream); - -return wifiUp; + DCCEXParser::setAtCommandCallback(ATCommand); + // CAUTION... ONLY CALL THIS ONCE + WifiInboundHandler::setup(wifiStream); + if (wifiUp == WIFI_CONNECTED) + connected = true; + else + connected = false; + return connected; } -bool WifiInterface::setup(Stream & setupStream, const __FlashStringHelper* SSid, const __FlashStringHelper* password, - const __FlashStringHelper* hostname, int port) { +wifiSerialState WifiInterface::setup(Stream & setupStream, const __FlashStringHelper* SSid, const __FlashStringHelper* password, + const __FlashStringHelper* hostname, int port) { + wifiSerialState wifiState; static uint8_t ntry = 0; ntry++; @@ -107,20 +113,25 @@ bool WifiInterface::setup(Stream & setupStream, const __FlashStringHelper* SSid DIAG(F("\n++ Wifi Setup Try %d ++\n"), ntry); - connected = setup2( SSid, password, hostname, port); + wifiState = setup2( SSid, password, hostname, port); + + if (wifiState == WIFI_NOAT) { + DIAG(F("\n++ Wifi Setup NO AT ++\n")); + return wifiState; + } - if (connected) { + if (wifiState == WIFI_CONNECTED) { StringFormatter::send(wifiStream, F("ATE0\r\n")); // turn off the echo checkForOK(200, OK_SEARCH, true); } - DIAG(F("\n++ Wifi Setup %S ++\n"), connected ? F("OK") : F("FAILED")); - return connected; + DIAG(F("\n++ Wifi Setup %S ++\n"), wifiState == WIFI_CONNECTED ? F("CONNECTED") : F("DISCONNECTED")); + return wifiState; } -bool WifiInterface::setup2(const __FlashStringHelper* SSid, const __FlashStringHelper* password, - const __FlashStringHelper* hostname, int port) { +wifiSerialState WifiInterface::setup2(const __FlashStringHelper* SSid, const __FlashStringHelper* password, + const __FlashStringHelper* hostname, int port) { bool ipOK = false; bool oldCmd = false; @@ -132,12 +143,12 @@ bool WifiInterface::setup2(const __FlashStringHelper* SSid, const __FlashStringH if (checkForOK(200,IPD_SEARCH, true)) { DIAG(F("\nPreconfigured Wifi already running with data waiting\n")); // loopstate=4; // carry on from correct place... or not as the case may be - return true; + return WIFI_CONNECTED; } StringFormatter::send(wifiStream, F("AT\r\n")); // Is something here that understands AT? if(!checkForOK(200, OK_SEARCH, true)) - return false; // No AT compatible WiFi module here + return WIFI_NOAT; // No AT compatible WiFi module here StringFormatter::send(wifiStream, F("ATE1\r\n")); // Turn on the echo, se we can see what's happening checkForOK(2000, OK_SEARCH, true); // Makes this visible on the console @@ -223,8 +234,9 @@ bool WifiInterface::setup2(const __FlashStringHelper* SSid, const __FlashStringH if (oldCmd) { while (wifiStream->available()) StringFormatter::printEscape( wifiStream->read()); /// THIS IS A DIAG IN DISGUISE - StringFormatter::send(wifiStream, F("AT+CWSAP=\"DCCEX_%s\",\"PASS_%s\",1,4\r\n"), macTail, macTail); - checkForOK(16000, OK_SEARCH, true); // can ignore failure as AP mode may still be ok + int i=0; + do StringFormatter::send(wifiStream, F("AT+CWSAP=\"DCCEX_%s\",\"PASS_%s\",1,4\r\n"), macTail, macTail); + while (i++<2 && !checkForOK(16000, OK_SEARCH, true)); // do twice if necessary but ignore failure as AP mode may still be ok } else { @@ -240,16 +252,16 @@ bool WifiInterface::setup2(const __FlashStringHelper* SSid, const __FlashStringH checkForOK(10000, OK_SEARCH, true); // ignore result in case it already was off StringFormatter::send(wifiStream, F("AT+CIPMUX=1\r\n")); // configure for multiple connections - if (!checkForOK(10000, OK_SEARCH, true)) return false; + if (!checkForOK(10000, OK_SEARCH, true)) return WIFI_DISCONNECTED; StringFormatter::send(wifiStream, F("AT+CIPSERVER=1,%d\r\n"), port); // turn on server on port - if (!checkForOK(10000, OK_SEARCH, true)) return false; + if (!checkForOK(10000, OK_SEARCH, true)) return WIFI_DISCONNECTED; StringFormatter::send(wifiStream, F("AT+CIFSR\r\n")); // Display ip addresses to the DIAG - if (!checkForOK(10000, OK_SEARCH, true, false)) return false; + if (!checkForOK(10000, OK_SEARCH, true, false)) return WIFI_DISCONNECTED; DIAG(F("\nPORT=%d\n"),port); - return true; + return WIFI_CONNECTED; } diff --git a/WifiInterface.h b/WifiInterface.h index 57dd469..6411f6c 100644 --- a/WifiInterface.h +++ b/WifiInterface.h @@ -23,6 +23,8 @@ #include #include +enum wifiSerialState { WIFI_NOAT, WIFI_DISCONNECTED, WIFI_CONNECTED }; + class WifiInterface { @@ -36,11 +38,11 @@ public: static void ATCommand(const byte *command); private: - static bool setup(Stream &setupStream, const __FlashStringHelper *SSSid, const __FlashStringHelper *password, + static wifiSerialState setup(Stream &setupStream, const __FlashStringHelper *SSSid, const __FlashStringHelper *password, const __FlashStringHelper *hostname, int port); static Stream *wifiStream; static DCCEXParser parser; - static bool setup2(const __FlashStringHelper *SSSid, const __FlashStringHelper *password, + static wifiSerialState setup2(const __FlashStringHelper *SSSid, const __FlashStringHelper *password, const __FlashStringHelper *hostname, int port); static bool checkForOK(const unsigned int timeout, const char *waitfor, bool echo, bool escapeEcho = true); static bool connected;