return and only react totriggers. **********************************************************************/ - +#include#include "DCCpp_Uno.h" #include "Sensor.h" #include "EEStore.h" #include -#include "Comm.h" + +extern WiFiClient client; +extern WiFiServer server; /////////////////////////////////////////////////////////////////////////////// @@ -71,14 +73,14 @@ void Sensor::check(){ if(!tt->active && tt->signal<0.5){ tt->active=true; - INTERFACE.print(" data.snum); - INTERFACE.print(">"); + client.print("data.snum); + client.print(">"); } else if(tt->active && tt->signal>0.9){ tt->active=false; - INTERFACE.print("data.snum); - INTERFACE.print(">"); + client.print("data.snum); + client.print(">"); } } // loop over all sensors @@ -102,7 +104,7 @@ Sensor *Sensor::create(int snum, int pin, int pullUp, int v){ if(tt==NULL){ // problem allocating memory if(v==1) - INTERFACE.print(""); + client.print(" "); return(tt); } @@ -115,7 +117,7 @@ Sensor *Sensor::create(int snum, int pin, int pullUp, int v){ 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 if(v==1) - INTERFACE.print(" "); + client.print(" "); return(tt); } @@ -135,7 +137,7 @@ void Sensor::remove(int n){ for(tt=firstSensor;tt!=NULL && tt->data.snum!=n;pp=tt,tt=tt->nextSensor); if(tt==NULL){ - INTERFACE.print(" "); + client.print(" "); return; } @@ -146,7 +148,7 @@ void Sensor::remove(int n){ free(tt); - INTERFACE.print(" "); + client.print(" "); } /////////////////////////////////////////////////////////////////////////////// @@ -155,18 +157,18 @@ void Sensor::show(){ Sensor *tt; if(firstSensor==NULL){ - INTERFACE.print(" "); + client.print(" "); return; } for(tt=firstSensor;tt!=NULL;tt=tt->nextSensor){ - INTERFACE.print(" data.snum); - INTERFACE.print(" "); - INTERFACE.print(tt->data.pin); - INTERFACE.print(" "); - INTERFACE.print(tt->data.pullUp); - INTERFACE.print(">"); + client.print("data.snum); + client.print(" "); + client.print(tt->data.pin); + client.print(" "); + client.print(tt->data.pullUp); + client.print(">"); } } @@ -176,14 +178,14 @@ void Sensor::status(){ Sensor *tt; if(firstSensor==NULL){ - INTERFACE.print(""); + client.print(" "); return; } for(tt=firstSensor;tt!=NULL;tt=tt->nextSensor){ - INTERFACE.print(tt->active?" data.snum); - INTERFACE.print(">"); + client.print(tt->active?"data.snum); + client.print(">"); } } @@ -208,7 +210,7 @@ void Sensor::parse(char *c){ break; case 2: // invalid number of arguments - INTERFACE.print(""); + client.print(" "); break; } } diff --git a/DCCpp_Uno/SerialCommand.cpp b/DCCpp_Uno/SerialCommand.cpp index 4d3f9b2..5fb33bb 100644 --- a/DCCpp_Uno/SerialCommand.cpp +++ b/DCCpp_Uno/SerialCommand.cpp @@ -14,67 +14,44 @@ Part of DCC++ BASE STATION for the Arduino // See SerialCommand::parse() below for defined text commands. +#include #include "SerialCommand.h" #include "DCCpp_Uno.h" -#include "Accessories.h" #include "Sensor.h" -#include "Outputs.h" #include "EEStore.h" -#include "Comm.h" -extern int __heap_start, *__brkval; +extern WiFiClient client; +extern WiFiServer server; /////////////////////////////////////////////////////////////////////////////// char SerialCommand::commandString[MAX_COMMAND_LENGTH+1]; -volatile RegisterList *SerialCommand::mRegs; -volatile RegisterList *SerialCommand::pRegs; -CurrentMonitor *SerialCommand::mMonitor; - -/////////////////////////////////////////////////////////////////////////////// - -void SerialCommand::init(volatile RegisterList *_mRegs, volatile RegisterList *_pRegs, CurrentMonitor *_mMonitor){ - mRegs=_mRegs; - pRegs=_pRegs; - mMonitor=_mMonitor; - sprintf(commandString,""); -} // SerialCommand:SerialCommand /////////////////////////////////////////////////////////////////////////////// void SerialCommand::process(){ char c; - #if COMM_TYPE == 0 - - while(INTERFACE.available()>0){ // while there is data on the serial line - c=INTERFACE.read(); - if(c=='<') // start of new command - sprintf(commandString,""); - else if(c=='>') // end of new command - parse(commandString); - else if(strlen(commandString) ') - } // while - - #elif COMM_TYPE == 1 - - EthernetClient client=INTERFACE.available(); + client = server.available(); if(client){ - while(client.connected() && client.available()){ // while there is data on the network - c=client.read(); - if(c=='<') // start of new command - sprintf(commandString,""); - else if(c=='>') // end of new command - parse(commandString); - else if(strlen(commandString) ') +// Serial.print("^" ); + while( client.connected() ) { + if( client.available()){ // while there is data on the network + c=client.read(); + if(c=='<') // start of new command + sprintf(commandString,""); + else if(c=='>') { // end of new command +// Serial.print(commandString); + parse(commandString); + } + else if(strlen(commandString) ') + } + Sensor::check(); } // while + // Serial.print( "x" ); } - - #endif - } // SerialCommand:process /////////////////////////////////////////////////////////////////////////////// @@ -82,124 +59,10 @@ void SerialCommand::process(){ void SerialCommand::parse(char *com){ switch(com[0]){ - -/***** SET ENGINE THROTTLES USING 128-STEP SPEED CONTROL ****/ - - case 't': // -/* - * sets the throttle for a given register/cab combination - * - * REGISTER: an internal register number, from 1 through MAX_MAIN_REGISTERS (inclusive), to store the DCC packet used to control this throttle setting - * CAB: the short (1-127) or long (128-10293) address of the engine decoder - * SPEED: throttle speed from 0-126, or -1 for emergency stop (resets SPEED to 0) - * DIRECTION: 1=forward, 0=reverse. Setting direction when speed=0 or speed=-1 only effects directionality of cab lighting for a stopped train - * - * returns: - * - */ - mRegs->setThrottle(com+1); - break; - -/***** OPERATE ENGINE DECODER FUNCTIONS F0-F28 ****/ - - case 'f': // -/* - * turns on and off engine decoder functions F0-F28 (F0 is sometimes called FL) - * NOTE: setting requests transmitted directly to mobile engine decoder --- current state of engine functions is not stored by this program - * - * CAB: the short (1-127) or long (128-10293) address of the engine decoder - * - * To set functions F0-F4 on (=1) or off (=0): - * - * BYTE1: 128 + F1*1 + F2*2 + F3*4 + F4*8 + F0*16 - * BYTE2: omitted - * - * To set functions F5-F8 on (=1) or off (=0): - * - * BYTE1: 176 + F5*1 + F6*2 + F7*4 + F8*8 - * BYTE2: omitted - * - * To set functions F9-F12 on (=1) or off (=0): - * - * BYTE1: 160 + F9*1 +F10*2 + F11*4 + F12*8 - * BYTE2: omitted - * - * To set functions F13-F20 on (=1) or off (=0): - * - * BYTE1: 222 - * BYTE2: F13*1 + F14*2 + F15*4 + F16*8 + F17*16 + F18*32 + F19*64 + F20*128 - * - * To set functions F21-F28 on (=1) of off (=0): - * - * BYTE1: 223 - * BYTE2: F21*1 + F22*2 + F23*4 + F24*8 + F25*16 + F26*32 + F27*64 + F28*128 - * - * returns: NONE - * - */ - mRegs->setFunction(com+1); - break; - -/***** OPERATE STATIONARY ACCESSORY DECODERS ****/ - - case 'a': // -/* - * turns an accessory (stationary) decoder on or off - * - * ADDRESS: the primary address of the decoder (0-511) - * SUBADDRESS: the subaddress of the decoder (0-3) - * ACTIVATE: 1=on (set), 0=off (clear) - * - * Note that many decoders and controllers combine the ADDRESS and SUBADDRESS into a single number, N, - * from 1 through a max of 2044, where - * - * N = (ADDRESS - 1) * 4 + SUBADDRESS + 1, for all ADDRESS>0 - * - * OR - * - * ADDRESS = INT((N - 1) / 4) + 1 - * SUBADDRESS = (N - 1) % 4 - * - * returns: NONE - */ - mRegs->setAccessory(com+1); - break; - -/***** CREATE/EDIT/REMOVE/SHOW & OPERATE A TURN-OUT ****/ - - case 'T': // -/* - * : sets turnout ID to either the "thrown" or "unthrown" position - * - * ID: the numeric ID (0-32767) of the turnout to control - * THROW: 0 (unthrown) or 1 (thrown) - * - * returns: or if turnout ID does not exist - * - * *** SEE ACCESSORIES.CPP FOR COMPLETE INFO ON THE DIFFERENT VARIATIONS OF THE "T" COMMAND - * USED TO CREATE/EDIT/REMOVE/SHOW TURNOUT DEFINITIONS - */ - Turnout::parse(com+1); - break; - -/***** CREATE/EDIT/REMOVE/SHOW & OPERATE AN OUTPUT PIN ****/ - - case 'Z': // -/* - * : sets output ID to either the "active" or "inactive" state - * - * ID: the numeric ID (0-32767) of the output to control - * ACTIVATE: 0 (active) or 1 (inactive) - * - * returns: or if output ID does not exist - * - * *** SEE OUTPUTS.CPP FOR COMPLETE INFO ON THE DIFFERENT VARIATIONS OF THE "O" COMMAND - * USED TO CREATE/EDIT/REMOVE/SHOW TURNOUT DEFINITIONS - */ - Output::parse(com+1); + case 'T': // process turnouts + case 'Z': // process outputs + client.print(" "); // nothing defined for now break; - -/***** CREATE/EDIT/REMOVE/SHOW A SENSOR ****/ case 'S': /* @@ -218,99 +81,13 @@ void SerialCommand::parse(char *com){ Sensor::status(); break; -/***** WRITE CONFIGURATION VARIABLE BYTE TO ENGINE DECODER ON MAIN OPERATIONS TRACK ****/ - - case 'w': // -/* - * writes, without any verification, a Configuration Variable to the decoder of an engine on the main operations track - * - * CAB: the short (1-127) or long (128-10293) address of the engine decoder - * CV: the number of the Configuration Variable memory location in the decoder to write to (1-1024) - * VALUE: the value to be written to the Configuration Variable memory location (0-255) - * - * returns: NONE -*/ - mRegs->writeCVByteMain(com+1); - break; - -/***** WRITE CONFIGURATION VARIABLE BIT TO ENGINE DECODER ON MAIN OPERATIONS TRACK ****/ - - case 'b': // -/* - * writes, without any verification, a single bit within a Configuration Variable to the decoder of an engine on the main operations track - * - * CAB: the short (1-127) or long (128-10293) address of the engine decoder - * CV: the number of the Configuration Variable memory location in the decoder to write to (1-1024) - * BIT: the bit number of the Configurarion Variable regsiter to write (0-7) - * VALUE: the value of the bit to be written (0-1) - * - * returns: NONE -*/ - mRegs->writeCVBitMain(com+1); - break; - -/***** WRITE CONFIGURATION VARIABLE BYTE TO ENGINE DECODER ON PROGRAMMING TRACK ****/ - - case 'W': // -/* - * writes, and then verifies, a Configuration Variable to the decoder of an engine on the programming track - * - * CV: the number of the Configuration Variable memory location in the decoder to write to (1-1024) - * VALUE: the value to be written to the Configuration Variable memory location (0-255) - * CALLBACKNUM: an arbitrary integer (0-32767) that is ignored by the Base Station and is simply echoed back in the output - useful for external programs that call this function - * CALLBACKSUB: a second arbitrary integer (0-32767) that is ignored by the Base Station and is simply echoed back in the output - useful for external programs (e.g. DCC++ Interface) that call this function - * - * returns: writeCVByte(com+1); - break; - -/***** WRITE CONFIGURATION VARIABLE BIT TO ENGINE DECODER ON PROGRAMMING TRACK ****/ - - case 'B': // -/* - * writes, and then verifies, a single bit within a Configuration Variable to the decoder of an engine on the programming track - * - * CV: the number of the Configuration Variable memory location in the decoder to write to (1-1024) - * BIT: the bit number of the Configurarion Variable memory location to write (0-7) - * VALUE: the value of the bit to be written (0-1) - * CALLBACKNUM: an arbitrary integer (0-32767) that is ignored by the Base Station and is simply echoed back in the output - useful for external programs that call this function - * CALLBACKSUB: a second arbitrary integer (0-32767) that is ignored by the Base Station and is simply echoed back in the output - useful for external programs (e.g. DCC++ Interface) that call this function - * - * returns: writeCVBit(com+1); - break; - -/***** READ CONFIGURATION VARIABLE BYTE FROM ENGINE DECODER ON PROGRAMMING TRACK ****/ - - case 'R': // -/* - * reads a Configuration Variable from the decoder of an engine on the programming track - * - * CV: the number of the Configuration Variable memory location in the decoder to read from (1-1024) - * CALLBACKNUM: an arbitrary integer (0-32767) that is ignored by the Base Station and is simply echoed back in the output - useful for external programs that call this function - * CALLBACKSUB: a second arbitrary integer (0-32767) that is ignored by the Base Station and is simply echoed back in the output - useful for external programs (e.g. DCC++ Interface) that call this function - * - * returns: readCV(com+1); - break; - -/***** TURN ON POWER FROM MOTOR SHIELD TO TRACKS ****/ - case '1': // <1> /* * enables power from the motor shield to the main operations and programming tracks * * returns: */ - digitalWrite(SIGNAL_ENABLE_PIN_PROG,HIGH); - digitalWrite(SIGNAL_ENABLE_PIN_MAIN,HIGH); - INTERFACE.print(" "); + client.print(" "); break; /***** TURN OFF POWER FROM MOTOR SHIELD TO TRACKS ****/ @@ -321,78 +98,34 @@ void SerialCommand::parse(char *com){ * * returns: */ - digitalWrite(SIGNAL_ENABLE_PIN_PROG,LOW); - digitalWrite(SIGNAL_ENABLE_PIN_MAIN,LOW); - INTERFACE.print(" "); + client.print(" "); break; -/***** READ MAIN OPERATIONS TRACK CURRENT ****/ - - case 'c': // -/* - * reads current being drawn on main operations track - * - * returns: - * where CURRENT = 0-1024, based on exponentially-smoothed weighting scheme - */ - INTERFACE.print("current)); - INTERFACE.print(">"); - break; - /***** READ STATUS OF DCC++ BASE STATION ****/ case 's': // /* * returns status messages containing track power status, throttle status, turn-out status, and a version number - * NOTE: this is very useful as a first command for an interface to send to this sketch in order to verify connectivity and update any GUI to reflect actual throttle and turn-out settings + * NOTE: this is very useful as a first command for an client to send to this sketch in order to verify connectivity and update any GUI to reflect actual throttle and turn-out settings * - * returns: series of status messages that can be read by an interface to determine status of DCC++ Base Station and important settings + * returns: series of status messages that can be read by an client to determine status of DCC++ Base Station and important settings */ - if(digitalRead(SIGNAL_ENABLE_PIN_PROG)==LOW) // could check either PROG or MAIN - INTERFACE.print(""); - else - INTERFACE.print(" "); - - for(int i=1;i<=MAX_MAIN_REGISTERS;i++){ - if(mRegs->speedTable[i]==0) - continue; - INTERFACE.print(" speedTable[i]>0){ - INTERFACE.print(mRegs->speedTable[i]); - INTERFACE.print(" 1>"); - } else{ - INTERFACE.print(-mRegs->speedTable[i]); - INTERFACE.print(" 0>"); - } - } - INTERFACE.print(" "); - - INTERFACE.print(" "); - #elif COMM_TYPE == 1 - INTERFACE.print(Ethernet.localIP()); - INTERFACE.print(">"); - #endif - - Turnout::show(); - Output::show(); - + client.print(" "); + client.print(" "); + client.print(" "); + break; /***** STORE SETTINGS IN EEPROM ****/ @@ -405,13 +138,13 @@ void SerialCommand::parse(char *com){ */ EEStore::store(); - INTERFACE.print(" data.nTurnouts); - INTERFACE.print(" "); - INTERFACE.print(EEStore::eeStore->data.nSensors); - INTERFACE.print(" "); - INTERFACE.print(EEStore::eeStore->data.nOutputs); - INTERFACE.print(">"); + client.print(" data.nTurnouts); + client.print(" "); + client.print(EEStore::eeStore->data.nSensors); + client.print(" "); + client.print(EEStore::eeStore->data.nOutputs); + client.print(">"); break; /***** CLEAR SETTINGS IN EEPROM ****/ @@ -424,7 +157,7 @@ void SerialCommand::parse(char *com){ */ EEStore::clear(); - INTERFACE.print(" "); + client.print(" "); break; /***** PRINT CARRIAGE RETURN IN SERIAL MONITOR WINDOW ****/ @@ -435,134 +168,9 @@ void SerialCommand::parse(char *com){ * * returns: a carriage return */ - INTERFACE.println(""); + client.println(""); break; -/// -/// THE FOLLOWING COMMANDS ARE NOT NEEDED FOR NORMAL OPERATIONS AND ARE ONLY USED FOR TESTING AND DEBUGGING PURPOSES -/// PLEASE SEE SPECIFIC WARNINGS IN EACH COMMAND BELOW -/// - -/***** ENTER DIAGNOSTIC MODE ****/ - - case 'D': // -/* - * changes the clock speed of the chip and the pre-scaler for the timers so that you can visually see the DCC signals flickering with an LED - * SERIAL COMMUNICAITON WILL BE INTERUPTED ONCE THIS COMMAND IS ISSUED - MUST RESET BOARD OR RE-OPEN SERIAL WINDOW TO RE-ESTABLISH COMMS - */ - - Serial.println("\nEntering Diagnostic Mode..."); - delay(1000); - - bitClear(TCCR1B,CS12); // set Timer 1 prescale=8 - SLOWS NORMAL SPEED BY FACTOR OF 8 - bitSet(TCCR1B,CS11); - bitClear(TCCR1B,CS10); - - #ifdef ARDUINO_AVR_UNO // Configuration for UNO - - bitSet(TCCR0B,CS02); // set Timer 0 prescale=256 - SLOWS NORMAL SPEED BY A FACTOR OF 4 - bitClear(TCCR0B,CS01); - bitClear(TCCR0B,CS00); - - #else // Configuration for MEGA - - bitClear(TCCR3B,CS32); // set Timer 3 prescale=8 - SLOWS NORMAL SPEED BY A FACTOR OF 8 - bitSet(TCCR3B,CS31); - bitClear(TCCR3B,CS30); - - #endif - - CLKPR=0x80; // THIS SLOWS DOWN SYSYEM CLOCK BY FACTOR OF 256 - CLKPR=0x08; // BOARD MUST BE RESET TO RESUME NORMAL OPERATIONS - - break; - -/***** WRITE A DCC PACKET TO ONE OF THE REGSITERS DRIVING THE MAIN OPERATIONS TRACK ****/ - - case 'M': // -/* - * writes a DCC packet of two, three, four, or five hexidecimal bytes to a register driving the main operations track - * FOR DEBUGGING AND TESTING PURPOSES ONLY. DO NOT USE UNLESS YOU KNOW HOW TO CONSTRUCT NMRA DCC PACKETS - YOU CAN INADVERTENTLY RE-PROGRAM YOUR ENGINE DECODER - * - * REGISTER: an internal register number, from 0 through MAX_MAIN_REGISTERS (inclusive), to write (if REGISTER=0) or write and store (if REGISTER>0) the packet - * BYTE1: first hexidecimal byte in the packet - * BYTE2: second hexidecimal byte in the packet - * BYTE3: optional third hexidecimal byte in the packet - * BYTE4: optional fourth hexidecimal byte in the packet - * BYTE5: optional fifth hexidecimal byte in the packet - * - * returns: NONE - */ - mRegs->writeTextPacket(com+1); - break; - -/***** WRITE A DCC PACKET TO ONE OF THE REGSITERS DRIVING THE MAIN OPERATIONS TRACK ****/ - - case 'P': // -/* - * writes a DCC packet of two, three, four, or five hexidecimal bytes to a register driving the programming track - * FOR DEBUGGING AND TESTING PURPOSES ONLY. DO NOT USE UNLESS YOU KNOW HOW TO CONSTRUCT NMRA DCC PACKETS - YOU CAN INADVERTENTLY RE-PROGRAM YOUR ENGINE DECODER - * - * REGISTER: an internal register number, from 0 through MAX_MAIN_REGISTERS (inclusive), to write (if REGISTER=0) or write and store (if REGISTER>0) the packet - * BYTE1: first hexidecimal byte in the packet - * BYTE2: second hexidecimal byte in the packet - * BYTE3: optional third hexidecimal byte in the packet - * BYTE4: optional fourth hexidecimal byte in the packet - * BYTE5: optional fifth hexidecimal byte in the packet - * - * returns: NONE - */ - pRegs->writeTextPacket(com+1); - break; - -/***** ATTEMPTS TO DETERMINE HOW MUCH FREE SRAM IS AVAILABLE IN ARDUINO ****/ - - case 'F': //
-/* - * measure amount of free SRAM memory left on the Arduino based on trick found on the internet. - * Useful when setting dynamic array sizes, considering the Uno only has 2048 bytes of dynamic SRAM. - * Unfortunately not very reliable --- would be great to find a better method - * - * returns: - * where MEM is the number of free bytes remaining in the Arduino's SRAM - */ - int v; - INTERFACE.print(" "); - break; - -/***** LISTS BIT CONTENTS OF ALL INTERNAL DCC PACKET REGISTERS ****/ - - case 'L': // -/* - * lists the packet contents of the main operations track registers and the programming track registers - * FOR DIAGNOSTIC AND TESTING USE ONLY - */ - INTERFACE.println(""); - for(Register *p=mRegs->reg;p<=mRegs->maxLoadedReg;p++){ - INTERFACE.print("M"); INTERFACE.print((int)(p-mRegs->reg)); INTERFACE.print(":\t"); - INTERFACE.print((int)p); INTERFACE.print("\t"); - INTERFACE.print((int)p->activePacket); INTERFACE.print("\t"); - INTERFACE.print(p->activePacket->nBits); INTERFACE.print("\t"); - for(int i=0;i<10;i++){ - INTERFACE.print(p->activePacket->buf[i],HEX); INTERFACE.print("\t"); - } - INTERFACE.println(""); - } - for(Register *p=pRegs->reg;p<=pRegs->maxLoadedReg;p++){ - INTERFACE.print("P"); INTERFACE.print((int)(p-pRegs->reg)); INTERFACE.print(":\t"); - INTERFACE.print((int)p); INTERFACE.print("\t"); - INTERFACE.print((int)p->activePacket); INTERFACE.print("\t"); - INTERFACE.print(p->activePacket->nBits); INTERFACE.print("\t"); - for(int i=0;i<10;i++){ - INTERFACE.print(p->activePacket->buf[i],HEX); INTERFACE.print("\t"); - } - INTERFACE.println(""); - } - INTERFACE.println(""); - break; - } // switch }; // SerialCommand::parse diff --git a/DCCpp_Uno/SerialCommand.h b/DCCpp_Uno/SerialCommand.h index 510ce15..6fa92e0 100644 --- a/DCCpp_Uno/SerialCommand.h +++ b/DCCpp_Uno/SerialCommand.h @@ -10,16 +10,10 @@ Part of DCC++ BASE STATION for the Arduino #ifndef SerialCommand_h #define SerialCommand_h -#include "PacketRegister.h" -#include "CurrentMonitor.h" - #define MAX_COMMAND_LENGTH 30 struct SerialCommand{ static char commandString[MAX_COMMAND_LENGTH+1]; - static volatile RegisterList *mRegs, *pRegs; - static CurrentMonitor *mMonitor; - static void init(volatile RegisterList *, volatile RegisterList *, CurrentMonitor *); static void parse(char *); static void process(); }; // SerialCommand From d09e4b9037a567b8d33d8652fda49a5bb76e6cd1 Mon Sep 17 00:00:00 2001 From: dtworth <36244729+dtworth@users.noreply.github.com> Date: Sat, 10 Mar 2018 16:20:42 -0500 Subject: [PATCH 2/7] Renamed from Uno to NodeMCU Also edited the description in contained within the DCCpp_NodeMCU.ino file. --- {DCCpp_Uno => DCCpp_NodeMCU}/Config.h | 0 .../DCCpp_NodeMCU.h | 0 DCCpp_NodeMCU/DCCpp_NodeMCU.ino | 158 +++++++++++ {DCCpp_Uno => DCCpp_NodeMCU}/EEStore.cpp | 2 +- {DCCpp_Uno => DCCpp_NodeMCU}/EEStore.h | 0 {DCCpp_Uno => DCCpp_NodeMCU}/Sensor.cpp | 2 +- {DCCpp_Uno => DCCpp_NodeMCU}/Sensor.h | 0 .../SerialCommand.cpp | 2 +- {DCCpp_Uno => DCCpp_NodeMCU}/SerialCommand.h | 0 DCCpp_Uno/DCCpp_Uno.ino | 252 ------------------ 10 files changed, 161 insertions(+), 255 deletions(-) rename {DCCpp_Uno => DCCpp_NodeMCU}/Config.h (100%) rename DCCpp_Uno/DCCpp_Uno.h => DCCpp_NodeMCU/DCCpp_NodeMCU.h (100%) create mode 100644 DCCpp_NodeMCU/DCCpp_NodeMCU.ino rename {DCCpp_Uno => DCCpp_NodeMCU}/EEStore.cpp (98%) rename {DCCpp_Uno => DCCpp_NodeMCU}/EEStore.h (100%) rename {DCCpp_Uno => DCCpp_NodeMCU}/Sensor.cpp (99%) rename {DCCpp_Uno => DCCpp_NodeMCU}/Sensor.h (100%) rename {DCCpp_Uno => DCCpp_NodeMCU}/SerialCommand.cpp (99%) rename {DCCpp_Uno => DCCpp_NodeMCU}/SerialCommand.h (100%) delete mode 100644 DCCpp_Uno/DCCpp_Uno.ino diff --git a/DCCpp_Uno/Config.h b/DCCpp_NodeMCU/Config.h similarity index 100% rename from DCCpp_Uno/Config.h rename to DCCpp_NodeMCU/Config.h diff --git a/DCCpp_Uno/DCCpp_Uno.h b/DCCpp_NodeMCU/DCCpp_NodeMCU.h similarity index 100% rename from DCCpp_Uno/DCCpp_Uno.h rename to DCCpp_NodeMCU/DCCpp_NodeMCU.h diff --git a/DCCpp_NodeMCU/DCCpp_NodeMCU.ino b/DCCpp_NodeMCU/DCCpp_NodeMCU.ino new file mode 100644 index 0000000..5ca3f9e --- /dev/null +++ b/DCCpp_NodeMCU/DCCpp_NodeMCU.ino @@ -0,0 +1,158 @@ +/********************************************************************** + +DCC++ BASE STATION +COPYRIGHT (c) 2013-2016 Gregg E. Berman + + 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 for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see http://www.gnu.org/licenses + +**********************************************************************/ +/********************************************************************** + +DCC++ BASE STATION is a C++ program written for the Arduino Uno and Arduino Mega +using the Arduino IDE 1.6.6. + +It allows a standard Arduino Uno or Mega with an Arduino Motor Shield (as well as others) +to be used as a fully-functioning digital command and control (DCC) base station +for controlling model train layouts that conform to current National Model +Railroad Association (NMRA) DCC standards. + +This stripped-down version of DCC++ BASE STATION only supports sensor inputs connected +to the NodeMCU. + +DCC++ BASE STATION is controlled with simple text commands received via +the NodeMCU WiFi interface. + +Neither DCC++ BASE STATION nor DCC++ CONTROLLER use any known proprietary or +commercial hardware, software, interfaces, specifications, or methods related +to the control of model trains using NMRA DCC standards. Both programs are wholly +original, developed by the author, and are not derived from any known commercial, +free, or open-source model railroad control packages by any other parties. + +However, DCC++ BASE STATION and DCC++ CONTROLLER do heavily rely on the IDEs and +embedded libraries associated with Arduino and Processing. Tremendous thanks to those +responsible for these terrific open-source initiatives that enable programs like +DCC++ to be developed and distributed in the same fashion. + +REFERENCES: + + NMRA DCC Standards: http://www.nmra.org/index-nmra-standards-and-recommended-practices + Arduino: http://www.arduino.cc/ + Processing: http://processing.org/ + GNU General Public License: http://opensource.org/licenses/GPL-3.0 + +BRIEF NOTES ON THE THEORY AND OPERATION OF DCC++ BASE STATION: + + +DCC++ BASE STATION in split into multiple modules, each with its own header file: + + DCCpp_NodeMCU: declares required global objects and contains initial Arduino setup() + and Arduino loop() functions, as well as and optional array of Sensors + + SerialCommand: contains methods to read and interpret text commands from the WiFi interface, + process those instructions. + + Sensor: contains methods to monitor and report on the status of optionally-defined infrared + sensors embedded in the Main Track and connected to various pins on the NodeMCU + + EEStore: contains methods to store, update, and the sensor settings in the EEPROM for + recall after power-up + +DCC++ BASE STATION is configured through the Config.h file that contains all user-definable parameters + +**********************************************************************/ + +// BEGIN BY INCLUDING THE HEADER FILES FOR EACH MODULE + +#include +#include "Config.h" +#include "DCCpp_NodeMCU.h" +#include "Sensor.h" +#include "EEstore.h" +#include "SerialCommand.h" + +WiFiServer server(ETHERNET_PORT); +WiFiClient client; + +void connectToWiFi() +{ + Serial.print("\n\nConnecting to "); + Serial.println(_SSID); + WiFi.mode(WIFI_STA); + WiFi.disconnect(); + WiFi.begin( _SSID, _PASSWORD ); + WiFi.hostname( _HOSTNAME ); + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println("\nWiFi connected"); + Serial.print("IP address: "); + Serial.println(WiFi.localIP()); + WiFi.disconnect(); + + Serial.println( WiFi.softAP( _HOSTNAME, _PASSWORD, 6) ? "AP Started": "AP failed" ); + Serial.print("\n\nConnecting to "); + Serial.println( _SSID ); + WiFi.mode(WIFI_AP); + WiFi.begin( _SSID, _PASSWORD ); + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println("\nWiFi connected"); + server.begin(); +} + + +/////////////////////////////////////////////////////////////////////////////// +// MAIN ARDUINO LOOP +/////////////////////////////////////////////////////////////////////////////// + +void loop(){ + + SerialCommand::process(); // check for, and process, and new serial commands + Sensor::check(); // check sensors for activate/de-activate + +} // loop + +/////////////////////////////////////////////////////////////////////////////// +// INITIAL SETUP +/////////////////////////////////////////////////////////////////////////////// + +void setup(){ + + Serial.begin(115200); // configure serial interface + Serial.flush(); + + EEStore::init(); // initialize and load Turnout and Sensor definitions stored in EEPROM + + Serial.print(" "); + + Serial.print(" "); +} // setup diff --git a/DCCpp_Uno/EEStore.cpp b/DCCpp_NodeMCU/EEStore.cpp similarity index 98% rename from DCCpp_Uno/EEStore.cpp rename to DCCpp_NodeMCU/EEStore.cpp index 01b6488..fc9a6b4 100644 --- a/DCCpp_Uno/EEStore.cpp +++ b/DCCpp_NodeMCU/EEStore.cpp @@ -7,7 +7,7 @@ Part of DCC++ BASE STATION for the Arduino **********************************************************************/ -#include "DCCpp_Uno.h" +#include "DCCpp_NodeMCU.h" #include "EEStore.h" #include "Sensor.h" #include diff --git a/DCCpp_Uno/EEStore.h b/DCCpp_NodeMCU/EEStore.h similarity index 100% rename from DCCpp_Uno/EEStore.h rename to DCCpp_NodeMCU/EEStore.h diff --git a/DCCpp_Uno/Sensor.cpp b/DCCpp_NodeMCU/Sensor.cpp similarity index 99% rename from DCCpp_Uno/Sensor.cpp rename to DCCpp_NodeMCU/Sensor.cpp index af63ef1..20c7f96 100644 --- a/DCCpp_Uno/Sensor.cpp +++ b/DCCpp_NodeMCU/Sensor.cpp @@ -55,7 +55,7 @@ decide to ignore the return and only react totriggers. **********************************************************************/ #include-#include "DCCpp_Uno.h" +#include "DCCpp_NodeMCU.h" #include "Sensor.h" #include "EEStore.h" #include diff --git a/DCCpp_Uno/Sensor.h b/DCCpp_NodeMCU/Sensor.h similarity index 100% rename from DCCpp_Uno/Sensor.h rename to DCCpp_NodeMCU/Sensor.h diff --git a/DCCpp_Uno/SerialCommand.cpp b/DCCpp_NodeMCU/SerialCommand.cpp similarity index 99% rename from DCCpp_Uno/SerialCommand.cpp rename to DCCpp_NodeMCU/SerialCommand.cpp index 5fb33bb..37134c9 100644 --- a/DCCpp_Uno/SerialCommand.cpp +++ b/DCCpp_NodeMCU/SerialCommand.cpp @@ -16,7 +16,7 @@ Part of DCC++ BASE STATION for the Arduino #include #include "SerialCommand.h" -#include "DCCpp_Uno.h" +#include "DCCpp_NodeMCU.h" #include "Sensor.h" #include "EEStore.h" diff --git a/DCCpp_Uno/SerialCommand.h b/DCCpp_NodeMCU/SerialCommand.h similarity index 100% rename from DCCpp_Uno/SerialCommand.h rename to DCCpp_NodeMCU/SerialCommand.h diff --git a/DCCpp_Uno/DCCpp_Uno.ino b/DCCpp_Uno/DCCpp_Uno.ino deleted file mode 100644 index 50c736e..0000000 --- a/DCCpp_Uno/DCCpp_Uno.ino +++ /dev/null @@ -1,252 +0,0 @@ -/********************************************************************** - -DCC++ BASE STATION -COPYRIGHT (c) 2013-2016 Gregg E. Berman - - 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 for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see http://www.gnu.org/licenses - -**********************************************************************/ -/********************************************************************** - -DCC++ BASE STATION is a C++ program written for the Arduino Uno and Arduino Mega -using the Arduino IDE 1.6.6. - -It allows a standard Arduino Uno or Mega with an Arduino Motor Shield (as well as others) -to be used as a fully-functioning digital command and control (DCC) base station -for controlling model train layouts that conform to current National Model -Railroad Association (NMRA) DCC standards. - -This version of DCC++ BASE STATION supports: - - * 2-byte and 4-byte locomotive addressing - * Simultaneous control of multiple locomotives - * 128-step speed throttling - * Cab functions F0-F28 - * Activate/de-activate accessory functions using 512 addresses, each with 4 sub-addresses - - includes optional functionailty to monitor and store of the direction of any connected turnouts - * Programming on the Main Operations Track - - write configuration variable bytes - - set/clear specific configuration variable bits - * Programming on the Programming Track - - write configuration variable bytes - - set/clear specific configuration variable bits - - read configuration variable bytes - -DCC++ BASE STATION is controlled with simple text commands received via -the Arduino's serial interface. Users can type these commands directly -into the Arduino IDE Serial Monitor, or can send such commands from another -device or computer program. - -When compiled for the Arduino Mega, an Ethernet Shield can be used for network -communications instead of using serial communications. - -DCC++ CONTROLLER, available separately under a similar open-source -license, is a Java program written using the Processing library and Processing IDE -that provides a complete and configurable graphic interface to control model train layouts -via the DCC++ BASE STATION. - -With the exception of a standard 15V power supply that can be purchased in -any electronics store, no additional hardware is required. - -Neither DCC++ BASE STATION nor DCC++ CONTROLLER use any known proprietary or -commercial hardware, software, interfaces, specifications, or methods related -to the control of model trains using NMRA DCC standards. Both programs are wholly -original, developed by the author, and are not derived from any known commercial, -free, or open-source model railroad control packages by any other parties. - -However, DCC++ BASE STATION and DCC++ CONTROLLER do heavily rely on the IDEs and -embedded libraries associated with Arduino and Processing. Tremendous thanks to those -responsible for these terrific open-source initiatives that enable programs like -DCC++ to be developed and distributed in the same fashion. - -REFERENCES: - - NMRA DCC Standards: http://www.nmra.org/index-nmra-standards-and-recommended-practices - Arduino: http://www.arduino.cc/ - Processing: http://processing.org/ - GNU General Public License: http://opensource.org/licenses/GPL-3.0 - -BRIEF NOTES ON THE THEORY AND OPERATION OF DCC++ BASE STATION: - -DCC++ BASE STATION for the Uno configures the OC0B interrupt pin associated with Timer 0, -and the OC1B interupt pin associated with Timer 1, to generate separate 0-5V -unipolar signals that each properly encode zero and one bits conforming with -DCC timing standards. When compiled for the Mega, DCC++ BASE STATION uses OC3B instead of OC0B. - -Series of DCC bit streams are bundled into Packets that each form the basis of -a standard DCC instruction. Packets are stored in Packet Registers that contain -methods for updating and queuing according to text commands sent by the user -(or another program) over the serial interface. There is one set of registers that controls -the main operations track and one that controls the programming track. - -For the main operations track, packets to store cab throttle settings are stored in -registers numbered 1 through MAX_MAIN_REGISTERS (as defined in DCCpp_Uno.h). -It is generally considered good practice to continuously send throttle control packets -to every cab so that if an engine should momentarily lose electrical connectivity with the tracks, -it will very quickly receive another throttle control signal as soon as connectivity is -restored (such as when a trin passes over rough portion of track or the frog of a turnout). - -DCC++ Base Station therefore sequentially loops through each main operations track packet regsiter -that has been loaded with a throttle control setting for a given cab. For each register, it -transmits the appropriate DCC packet bits to the track, then moves onto the next register -without any pausing to ensure continuous bi-polar power is being provided to the tracks. -Updates to the throttle setting stored in any given packet register are done in a double-buffered -fashion and the sequencer is pointed to that register immediately after being changes so that updated DCC bits -can be transmitted to the appropriate cab without delay or any interruption in the bi-polar power signal. -The cabs identified in each stored throttle setting should be unique across registers. If two registers -contain throttle setting for the same cab, the throttle in the engine will oscillate between the two, -which is probably not a desireable outcome. - -For both the main operations track and the programming track there is also a special packet register with id=0 -that is used to store all other DCC packets that do not require continious transmittal to the tracks. -This includes DCC packets to control decoder functions, set accessory decoders, and read and write Configuration Variables. -It is common practice that transmittal of these one-time packets is usually repeated a few times to ensure -proper receipt by the receiving decoder. DCC decoders are designed to listen for repeats of the same packet -and provided there are no other packets received in between the repeats, the DCC decoder will not repeat the action itself. -Some DCC decoders actually require receipt of sequential multiple identical one-time packets as a way of -verifying proper transmittal before acting on the instructions contained in those packets - -An Arduino Motor Shield (or similar), powered by a standard 15V DC power supply and attached -on top of the Arduino Uno or Mega, is used to transform the 0-5V DCC logic signals -produced by the Uno's Timer interrupts into proper 0-15V bi-polar DCC signals. - -This is accomplished on the Uno by using one small jumper wire to connect the Uno's OC1B output (pin 10) -to the Motor Shield's DIRECTION A input (pin 12), and another small jumper wire to connect -the Uno's OC0B output (pin 5) to the Motor Shield's DIRECTION B input (pin 13). - -For the Mega, the OC1B output is produced directly on pin 12, so no jumper is needed to connect to the -Motor Shield's DIRECTION A input. However, one small jumper wire is needed to connect the Mega's OC3B output (pin 2) -to the Motor Shield's DIRECTION B input (pin 13). - -Other Motor Shields may require different sets of jumper or configurations (see Config.h and DCCpp_Uno.h for details). - -When configured as such, the CHANNEL A and CHANNEL B outputs of the Motor Shield may be -connected directly to the tracks. This software assumes CHANNEL A is connected -to the Main Operations Track, and CHANNEL B is connected to the Programming Track. - -DCC++ BASE STATION in split into multiple modules, each with its own header file: - - DCCpp_Uno: declares required global objects and contains initial Arduino setup() - and Arduino loop() functions, as well as interrput code for OC0B and OC1B. - Also includes declarations of optional array of Turn-Outs and optional array of Sensors - - SerialCommand: contains methods to read and interpret text commands from the serial line, - process those instructions, and, if necessary call appropriate Packet RegisterList methods - to update either the Main Track or Programming Track Packet Registers - - PacketRegister: contains methods to load, store, and update Packet Registers with DCC instructions - - CurrentMonitor: contains methods to separately monitor and report the current drawn from CHANNEL A and - CHANNEL B of the Arduino Motor Shield's, and shut down power if a short-circuit overload - is detected - - Accessories: contains methods to operate and store the status of any optionally-defined turnouts controlled - by a DCC stationary accessory decoder. - - Sensor: contains methods to monitor and report on the status of optionally-defined infrared - sensors embedded in the Main Track and connected to various pins on the Arudino Uno - - Outputs: contains methods to configure one or more Arduino pins as an output for your own custom use - - EEStore: contains methods to store, update, and load various DCC settings and status - (e.g. the states of all defined turnouts) in the EEPROM for recall after power-up - -DCC++ BASE STATION is configured through the Config.h file that contains all user-definable parameters - -**********************************************************************/ - -// BEGIN BY INCLUDING THE HEADER FILES FOR EACH MODULE - -#include -#include "Config.h" -#include "DCCpp_Uno.h" -#include "Sensor.h" -#include "EEstore.h" -#include "SerialCommand.h" - -WiFiServer server(ETHERNET_PORT); -WiFiClient client; - -void connectToWiFi() -{ - Serial.print("\n\nConnecting to "); - Serial.println(_SSID); - WiFi.mode(WIFI_STA); - WiFi.disconnect(); - WiFi.begin( _SSID, _PASSWORD ); - WiFi.hostname( _HOSTNAME ); - while (WiFi.status() != WL_CONNECTED) { - delay(500); - Serial.print("."); - } - Serial.println("\nWiFi connected"); - Serial.print("IP address: "); - Serial.println(WiFi.localIP()); - WiFi.disconnect(); - - Serial.println( WiFi.softAP( _HOSTNAME, _PASSWORD, 6) ? "AP Started": "AP failed" ); - Serial.print("\n\nConnecting to "); - Serial.println( _SSID ); - WiFi.mode(WIFI_AP); - WiFi.begin( _SSID, _PASSWORD ); - while (WiFi.status() != WL_CONNECTED) { - delay(500); - Serial.print("."); - } - Serial.println("\nWiFi connected"); - server.begin(); -} - - -/////////////////////////////////////////////////////////////////////////////// -// MAIN ARDUINO LOOP -/////////////////////////////////////////////////////////////////////////////// - -void loop(){ - - SerialCommand::process(); // check for, and process, and new serial commands - Sensor::check(); // check sensors for activate/de-activate - -} // loop - -/////////////////////////////////////////////////////////////////////////////// -// INITIAL SETUP -/////////////////////////////////////////////////////////////////////////////// - -void setup(){ - - Serial.begin(115200); // configure serial interface - Serial.flush(); - - EEStore::init(); // initialize and load Turnout and Sensor definitions stored in EEPROM - - Serial.print(" "); - - Serial.print(" "); -} // setup From 99e923ad9ca21e33828b1231aa98f0cb9232d8a7 Mon Sep 17 00:00:00 2001 From: Dan Worth <36244729+dtworth@users.noreply.github.com> Date: Sat, 10 Mar 2018 16:28:05 -0500 Subject: [PATCH 3/7] Update README.md --- README.md | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 9b63ac8..c69071b 100644 --- a/README.md +++ b/README.md @@ -12,26 +12,12 @@ The DCC++ Controller provides operators with a customizable GUI to control their What’s in this Repository ------------------------- -This repository, BaseStation-Uno, contains a complete DCC++ Base Station sketch designed for compiling and uploading into an Arduino Uno. All sketch files are in the folder named DCCpp_Uno. More information about the sketch can be found in the included PDF file. +This repository, BaseStation-NodeMCU, contains a stripped-down DCC++ Base Station sketch designed for compiling and uploading into a NodeMCU. All sketch files are in the folder named DCCpp_NodeMCU. More information about the sketch can be found in the included PDF file. -To utilize this sketch, simply download a zip file of this repository and open the file DCCpp_Uno.ino within the DCCpp_Uno folder using your Arduino IDE. Please do not rename the folder containing the sketch code, nor add any files to that folder. The Arduino IDE relies on the structure and name of the folder to properly display and compile the code. +To utilize this sketch, simply download a zip file of this repository and open the file DCCpp_NodeMCU.ino within the DCCpp_NodeMCU folder using your Arduino IDE. Please do not rename the folder containing the sketch code, nor add any files to that folder. The Arduino IDE relies on the structure and name of the folder to properly display and compile the code. -The latest production release of the Master branch is 1.2.1: - -* Supports both the Arduino Uno and Arduino Mega -* Built-in configuration for both the original Arduino Motor Shield as well as a Pololu MC33926 Motor Shield -* Built-in configuration and support of Ethernet Shields (for use with Mega only) +This particular version only supports sensor inputs. For more information on the overall DCC++ system, please follow the links in the PDF file. -Detailed diagrams showing pin mappings and required jumpers for the Motor Shields can be found in the Documentation Repository - -The Master branch contains all of the Base Station functionality showed in the DCC++ YouTube channel with the exception of 2 layout-specific modules: - -* Control for an RGB LED Light Strip using pins 44, 45, and 46 on the Mega -* An embedded AutoPilot routine that randomly selects a train to run through the entire layout, after which it is brought back into its original siding and the the patterns repeats with another randomly-selected train. This is the AutoPilot routine showed on the DCC++ YouTube channel. It does not require any computer, not DCC++ Controller to be running (DCC++ Controller contains a much more complicated 3-train Auto Pilot mode, also as shown on the DCC++ YouTube channel). - -Since these modules are very layout-specififc, they are not included in the Master branch. However, they are included in the Development branch. Please feel free to download and copy any relevant code to customize your own version of DCC++ Base Station. - --December 27, 2015 - +-March 10, 2017 From 2952f81283ee6f4fa115788951c73cb5eb5204f6 Mon Sep 17 00:00:00 2001 From: dtworth <36244729+dtworth@users.noreply.github.com> Date: Thu, 5 Apr 2018 18:00:33 -0400 Subject: [PATCH 4/7] Implimented multiple clients on WiFi --- DCCpp_NodeMCU/Config.h | 3 +- DCCpp_NodeMCU/DCCpp_NodeMCU.ino | 50 +------ DCCpp_NodeMCU/EEStore.cpp | 2 - DCCpp_NodeMCU/Sensor.cpp | 51 ++++--- DCCpp_NodeMCU/SerialCommand.cpp | 179 ------------------------ DCCpp_NodeMCU/SerialCommand.h | 25 ---- DCCpp_NodeMCU/WiFiCommand.cpp | 241 ++++++++++++++++++++++++++++++++ DCCpp_NodeMCU/WiFiCommand.h | 26 ++++ 8 files changed, 301 insertions(+), 276 deletions(-) delete mode 100644 DCCpp_NodeMCU/SerialCommand.cpp delete mode 100644 DCCpp_NodeMCU/SerialCommand.h create mode 100644 DCCpp_NodeMCU/WiFiCommand.cpp create mode 100644 DCCpp_NodeMCU/WiFiCommand.h diff --git a/DCCpp_NodeMCU/Config.h b/DCCpp_NodeMCU/Config.h index 98b40a2..9282618 100644 --- a/DCCpp_NodeMCU/Config.h +++ b/DCCpp_NodeMCU/Config.h @@ -11,6 +11,7 @@ Part of DCC++ BASE STATION for the Arduino // // DEFINE PORT TO USE FOR ETHERNET COMMUNICATIONS INTERFACE // +///////////////////////////////////////////////////////////////////////////////////// #define ETHERNET_PORT 2560 @@ -22,4 +23,4 @@ Part of DCC++ BASE STATION for the Arduino #define _SSID "" #define _PASSWORD "" -#define _HOSTNAME "block01" +#define _HOSTNAME "sensor02" diff --git a/DCCpp_NodeMCU/DCCpp_NodeMCU.ino b/DCCpp_NodeMCU/DCCpp_NodeMCU.ino index 5ca3f9e..39db3ed 100644 --- a/DCCpp_NodeMCU/DCCpp_NodeMCU.ino +++ b/DCCpp_NodeMCU/DCCpp_NodeMCU.ino @@ -59,7 +59,7 @@ DCC++ BASE STATION in split into multiple modules, each with its own header file DCCpp_NodeMCU: declares required global objects and contains initial Arduino setup() and Arduino loop() functions, as well as and optional array of Sensors - SerialCommand: contains methods to read and interpret text commands from the WiFi interface, + WiFiCommand: contains methods to read and interpret text commands from the WiFi interface, process those instructions. Sensor: contains methods to monitor and report on the status of optionally-defined infrared @@ -79,41 +79,7 @@ DCC++ BASE STATION is configured through the Config.h file that contains all use #include "DCCpp_NodeMCU.h" #include "Sensor.h" #include "EEstore.h" -#include "SerialCommand.h" - -WiFiServer server(ETHERNET_PORT); -WiFiClient client; - -void connectToWiFi() -{ - Serial.print("\n\nConnecting to "); - Serial.println(_SSID); - WiFi.mode(WIFI_STA); - WiFi.disconnect(); - WiFi.begin( _SSID, _PASSWORD ); - WiFi.hostname( _HOSTNAME ); - while (WiFi.status() != WL_CONNECTED) { - delay(500); - Serial.print("."); - } - Serial.println("\nWiFi connected"); - Serial.print("IP address: "); - Serial.println(WiFi.localIP()); - WiFi.disconnect(); - - Serial.println( WiFi.softAP( _HOSTNAME, _PASSWORD, 6) ? "AP Started": "AP failed" ); - Serial.print("\n\nConnecting to "); - Serial.println( _SSID ); - WiFi.mode(WIFI_AP); - WiFi.begin( _SSID, _PASSWORD ); - while (WiFi.status() != WL_CONNECTED) { - delay(500); - Serial.print("."); - } - Serial.println("\nWiFi connected"); - server.begin(); -} - +#include "WiFiCommand.h" /////////////////////////////////////////////////////////////////////////////// // MAIN ARDUINO LOOP @@ -121,8 +87,8 @@ void connectToWiFi() void loop(){ - SerialCommand::process(); // check for, and process, and new serial commands - Sensor::check(); // check sensors for activate/de-activate + WiFiCommand::process(); // check for, and process, and new WiFi commands + Sensor::check(); // check sensors for activate/de-activate } // loop @@ -136,7 +102,8 @@ void setup(){ Serial.flush(); EEStore::init(); // initialize and load Turnout and Sensor definitions stored in EEPROM - + WiFiCommand::init(); + Serial.print(" "); - Serial.print(" "); + Serial.println(">"); } // setup diff --git a/DCCpp_NodeMCU/EEStore.cpp b/DCCpp_NodeMCU/EEStore.cpp index fc9a6b4..25bceba 100644 --- a/DCCpp_NodeMCU/EEStore.cpp +++ b/DCCpp_NodeMCU/EEStore.cpp @@ -15,8 +15,6 @@ Part of DCC++ BASE STATION for the Arduino /////////////////////////////////////////////////////////////////////////////// void EEStore::init(){ - - eeStore=(EEStore *)calloc(1,sizeof(EEStore)); EEPROM.begin( 4096 ); diff --git a/DCCpp_NodeMCU/Sensor.cpp b/DCCpp_NodeMCU/Sensor.cpp index 20c7f96..93463f6 100644 --- a/DCCpp_NodeMCU/Sensor.cpp +++ b/DCCpp_NodeMCU/Sensor.cpp @@ -55,14 +55,13 @@ decide to ignore the return and only react totriggers. **********************************************************************/ #include+#include "Config.h" #include "DCCpp_NodeMCU.h" #include "Sensor.h" #include "EEStore.h" +#include "WiFiCommand.h" #include -extern WiFiClient client; -extern WiFiServer server; - /////////////////////////////////////////////////////////////////////////////// void Sensor::check(){ @@ -73,14 +72,14 @@ void Sensor::check(){ if(!tt->active && tt->signal<0.5){ tt->active=true; - client.print(" data.snum); - client.print(">"); + WiFiCommand::print("data.snum); + WiFiCommand::print(">"); } else if(tt->active && tt->signal>0.9){ tt->active=false; - client.print("data.snum); - client.print(">"); + WiFiCommand::print("data.snum); + WiFiCommand::print(">"); } } // loop over all sensors @@ -104,7 +103,7 @@ Sensor *Sensor::create(int snum, int pin, int pullUp, int v){ if(tt==NULL){ // problem allocating memory if(v==1) - client.print(""); + WiFiCommand::print(" "); return(tt); } @@ -117,7 +116,7 @@ Sensor *Sensor::create(int snum, int pin, int pullUp, int v){ 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 if(v==1) - client.print(" "); + WiFiCommand::print(" "); return(tt); } @@ -137,7 +136,7 @@ void Sensor::remove(int n){ for(tt=firstSensor;tt!=NULL && tt->data.snum!=n;pp=tt,tt=tt->nextSensor); if(tt==NULL){ - client.print(" "); + WiFiCommand::print(" "); return; } @@ -148,7 +147,7 @@ void Sensor::remove(int n){ free(tt); - client.print(" "); + WiFiCommand::print(" "); } /////////////////////////////////////////////////////////////////////////////// @@ -157,18 +156,18 @@ void Sensor::show(){ Sensor *tt; if(firstSensor==NULL){ - client.print(" "); + WiFiCommand::print(" "); return; } for(tt=firstSensor;tt!=NULL;tt=tt->nextSensor){ - client.print(" data.snum); - client.print(" "); - client.print(tt->data.pin); - client.print(" "); - client.print(tt->data.pullUp); - client.print(">"); + WiFiCommand::print("data.snum); + WiFiCommand::print(" "); + WiFiCommand::print(tt->data.pin); + WiFiCommand::print(" "); + WiFiCommand::print(tt->data.pullUp); + WiFiCommand::print(">"); } } @@ -178,14 +177,14 @@ void Sensor::status(){ Sensor *tt; if(firstSensor==NULL){ - client.print(""); + WiFiCommand::print(" "); return; } for(tt=firstSensor;tt!=NULL;tt=tt->nextSensor){ - client.print(tt->active?" data.snum); - client.print(">"); + WiFiCommand::print(tt->active?"data.snum); + WiFiCommand::print(">"); } } @@ -210,7 +209,7 @@ void Sensor::parse(char *c){ break; case 2: // invalid number of arguments - client.print(""); + WiFiCommand::print(" "); break; } } diff --git a/DCCpp_NodeMCU/SerialCommand.cpp b/DCCpp_NodeMCU/SerialCommand.cpp deleted file mode 100644 index 37134c9..0000000 --- a/DCCpp_NodeMCU/SerialCommand.cpp +++ /dev/null @@ -1,179 +0,0 @@ -/********************************************************************** - -SerialCommand.cpp -COPYRIGHT (c) 2013-2016 Gregg E. Berman - -Part of DCC++ BASE STATION for the Arduino - -**********************************************************************/ - -// DCC++ BASE STATION COMMUNICATES VIA THE SERIAL PORT USING SINGLE-CHARACTER TEXT COMMANDS -// WITH OPTIONAL PARAMTERS, AND BRACKETED BY < AND > SYMBOLS. SPACES BETWEEN PARAMETERS -// ARE REQUIRED. SPACES ANYWHERE ELSE ARE IGNORED. A SPACE BETWEEN THE SINGLE-CHARACTER -// COMMAND AND THE FIRST PARAMETER IS ALSO NOT REQUIRED. - -// See SerialCommand::parse() below for defined text commands. - -#include -#include "SerialCommand.h" -#include "DCCpp_NodeMCU.h" -#include "Sensor.h" -#include "EEStore.h" - -extern WiFiClient client; -extern WiFiServer server; - -/////////////////////////////////////////////////////////////////////////////// - -char SerialCommand::commandString[MAX_COMMAND_LENGTH+1]; - -/////////////////////////////////////////////////////////////////////////////// - -void SerialCommand::process(){ - char c; - - client = server.available(); - - if(client){ -// Serial.print("^" ); - while( client.connected() ) { - if( client.available()){ // while there is data on the network - c=client.read(); - if(c=='<') // start of new command - sprintf(commandString,""); - else if(c=='>') { // end of new command -// Serial.print(commandString); - parse(commandString); - } - else if(strlen(commandString) ') - } - Sensor::check(); - } // while - // Serial.print( "x" ); - } -} // SerialCommand:process - -/////////////////////////////////////////////////////////////////////////////// - -void SerialCommand::parse(char *com){ - - switch(com[0]){ - case 'T': // process turnouts - case 'Z': // process outputs - client.print(" "); // nothing defined for now - break; - - case 'S': -/* - * *** SEE SENSOR.CPP FOR COMPLETE INFO ON THE DIFFERENT VARIATIONS OF THE "S" COMMAND - * USED TO CREATE/EDIT/REMOVE/SHOW SENSOR DEFINITIONS - */ - Sensor::parse(com+1); - break; - -/***** SHOW STATUS OF ALL SENSORS ****/ - - case 'Q': // -/* - * returns: the status of each sensor ID in the form(active) or(not active) - */ - Sensor::status(); - break; - - case '1': // <1> -/* - * enables power from the motor shield to the main operations and programming tracks - * - * returns:- */ - client.print(" "); - break; - -/***** TURN OFF POWER FROM MOTOR SHIELD TO TRACKS ****/ - - case '0': // <0> -/* - * disables power from the motor shield to the main operations and programming tracks - * - * returns: - */ - client.print(" "); - break; - -/***** READ STATUS OF DCC++ BASE STATION ****/ - - case 's': // -/* - * returns status messages containing track power status, throttle status, turn-out status, and a version number - * NOTE: this is very useful as a first command for an client to send to this sketch in order to verify connectivity and update any GUI to reflect actual throttle and turn-out settings - * - * returns: series of status messages that can be read by an client to determine status of DCC++ Base Station and important settings - */ - client.print(""); - client.print(" "); - client.print(" "); - - break; - -/***** STORE SETTINGS IN EEPROM ****/ - - case 'E': // -/* - * stores settings for turnouts and sensors EEPROM - * - * returns: -*/ - - EEStore::store(); - client.print(" data.nTurnouts); - client.print(" "); - client.print(EEStore::eeStore->data.nSensors); - client.print(" "); - client.print(EEStore::eeStore->data.nOutputs); - client.print(">"); - break; - -/***** CLEAR SETTINGS IN EEPROM ****/ - - case 'e': // -/* - * clears settings for Turnouts in EEPROM - * - * returns: -*/ - - EEStore::clear(); - client.print(" "); - break; - -/***** PRINT CARRIAGE RETURN IN SERIAL MONITOR WINDOW ****/ - - case ' ': // < > -/* - * simply prints a carriage return - useful when interacting with Ardiuno through serial monitor window - * - * returns: a carriage return -*/ - client.println(""); - break; - - } // switch -}; // SerialCommand::parse - -/////////////////////////////////////////////////////////////////////////////// - - diff --git a/DCCpp_NodeMCU/SerialCommand.h b/DCCpp_NodeMCU/SerialCommand.h deleted file mode 100644 index 6fa92e0..0000000 --- a/DCCpp_NodeMCU/SerialCommand.h +++ /dev/null @@ -1,25 +0,0 @@ -/********************************************************************** - -SerialCommand.h -COPYRIGHT (c) 2013-2016 Gregg E. Berman - -Part of DCC++ BASE STATION for the Arduino - -**********************************************************************/ - -#ifndef SerialCommand_h -#define SerialCommand_h - -#define MAX_COMMAND_LENGTH 30 - -struct SerialCommand{ - static char commandString[MAX_COMMAND_LENGTH+1]; - static void parse(char *); - static void process(); -}; // SerialCommand - -#endif - - - - diff --git a/DCCpp_NodeMCU/WiFiCommand.cpp b/DCCpp_NodeMCU/WiFiCommand.cpp new file mode 100644 index 0000000..fd23451 --- /dev/null +++ b/DCCpp_NodeMCU/WiFiCommand.cpp @@ -0,0 +1,241 @@ +/********************************************************************** + +WiFiCommand.cpp +COPYRIGHT (c) 2013-2016 Gregg E. Berman + +Part of DCC++ BASE STATION for the Arduino + +**********************************************************************/ + +// DCC++ BASE STATION COMMUNICATES VIA WIFI USING SINGLE-CHARACTER TEXT COMMANDS +// WITH OPTIONAL PARAMTERS, AND BRACKETED BY < AND > SYMBOLS. SPACES BETWEEN PARAMETERS +// ARE REQUIRED. SPACES ANYWHERE ELSE ARE IGNORED. A SPACE BETWEEN THE SINGLE-CHARACTER +// COMMAND AND THE FIRST PARAMETER IS ALSO NOT REQUIRED. + +// See WiFiCommand::parse() below for defined text commands. + +#include +#include "Config.h" +#include "DCCpp_NodeMCU.h" +#include "WiFiCommand.h" +#include "Sensor.h" +#include "EEStore.h" + +WiFiServer server(ETHERNET_PORT); +WiFiClient client[MAX_CLIENTS]; + +/////////////////////////////////////////////////////////////////////////////// + +char WiFiCommand::commandString[MAX_CLIENTS][MAX_COMMAND_LENGTH+1]; + +/////////////////////////////////////////////////////////////////////////////// + +void WiFiCommand::init(){ + Serial.print("\n\nConnecting to "); + Serial.println(_SSID); + WiFi.mode(WIFI_STA); + WiFi.disconnect(); + WiFi.begin( _SSID, _PASSWORD ); + WiFi.hostname( _HOSTNAME ); + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println("\nWiFi connected"); + Serial.print("IP address: "); + Serial.println(WiFi.localIP()); + WiFi.disconnect(); + + Serial.println( WiFi.softAP( _HOSTNAME, _PASSWORD, 6) ? "AP Started": "AP failed" ); + Serial.print("\n\nConnecting to "); + Serial.println( _SSID ); + WiFi.mode(WIFI_AP); + WiFi.begin( _SSID, _PASSWORD ); + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println("\nWiFi connected"); + + server.begin(); +} + + +void WiFiCommand::process(){ + char c; + + if (server.hasClient()) { + for (int i = 0; i < MAX_CLIENTS; i++) { + if (!client[i] || !client[i].connected()) { + if (client[i]) { + client[i].stop(); + } + client[i] = server.available(); + continue; + } + } + server.available().stop(); + } + for (int i = 0; i < MAX_CLIENTS; i++) + if (client[i] && client[i].connected()) { + if( client[i].connected() ) { + if( client[i].available()){ // while there is data on the network + c=client[i].read(); + if(c=='<') // start of new command + sprintf(commandString[i],""); + else if(c=='>') { // end of new command +// Serial.print(commandString); + parse(commandString[i]); + } + else if(strlen(commandString[i]) ') + } +// Sensor::check(); + } // while + } +} // WiFiCommand:process + +/////////////////////////////////////////////////////////////////////////////// + +void WiFiCommand::parse(char *com){ + + switch(com[0]){ + case 'T': // process turnouts + case 'Z': // process outputs + WiFiCommand::print(" "); // nothing defined for now + break; + + case 'S': +/* + * *** SEE SENSOR.CPP FOR COMPLETE INFO ON THE DIFFERENT VARIATIONS OF THE "S" COMMAND + * USED TO CREATE/EDIT/REMOVE/SHOW SENSOR DEFINITIONS + */ + Sensor::parse(com+1); + break; + +/***** SHOW STATUS OF ALL SENSORS ****/ + + case 'Q': // +/* + * returns: the status of each sensor ID in the form(active) or(not active) + */ + Sensor::status(); + break; + + case '1': // <1> +/* + * enables power from the motor shield to the main operations and programming tracks + * + * returns:+ */ + WiFiCommand::print(" "); + break; + +/***** TURN OFF POWER FROM MOTOR SHIELD TO TRACKS ****/ + + case '0': // <0> +/* + * disables power from the motor shield to the main operations and programming tracks + * + * returns: + */ + WiFiCommand::print(" "); + break; + +/***** READ STATUS OF DCC++ BASE STATION ****/ + + case 's': // +/* + * returns status messages containing track power status, throttle status, turn-out status, and a version number + * NOTE: this is very useful as a first command for an client to send to this sketch in order to verify connectivity and update any GUI to reflect actual throttle and turn-out settings + * + * returns: series of status messages that can be read by an client to determine status of DCC++ Base Station and important settings + */ + WiFiCommand::print(""); + WiFiCommand::print(" "); + WiFiCommand::print(" "); + + break; + +/***** STORE SETTINGS IN EEPROM ****/ + + case 'E': // +/* + * stores settings for turnouts and sensors EEPROM + * + * returns: +*/ + + EEStore::store(); + WiFiCommand::print(" data.nTurnouts); + WiFiCommand::print(" "); + WiFiCommand::print(EEStore::eeStore->data.nSensors); + WiFiCommand::print(" "); + WiFiCommand::print(EEStore::eeStore->data.nOutputs); + WiFiCommand::print(">"); + break; + +/***** CLEAR SETTINGS IN EEPROM ****/ + + case 'e': // +/* + * clears settings for Turnouts in EEPROM + * + * returns: +*/ + + EEStore::clear(); + WiFiCommand::print(" "); + break; + +/***** PRINT CARRIAGE RETURN IN SERIAL MONITOR WINDOW ****/ + + case ' ': // < > +/* + * simply prints a carriage return - useful when interacting with Ardiuno through serial monitor window + * + * returns: a carriage return +*/ + WiFiCommand::print("\r"); + break; + + } // switch +}; // WiFiCommand::parse + +/////////////////////////////////////////////////////////////////////////////// + +void WiFiCommand::print( char * string ) { + for (int i = 0; i < MAX_CLIENTS; i++) + if (client[i] && client[i].connected()) { + client[i].print(string); + delay(1); + } +} + + +void WiFiCommand::print(const char * string ) { + char buffer[30]; + strcpy( buffer, string ); + WiFiCommand::print( buffer ); +} + + +void WiFiCommand::print(int num) { + char buffer[30]; + itoa( num, buffer, 10 ); + WiFiCommand::print( buffer ); +} + diff --git a/DCCpp_NodeMCU/WiFiCommand.h b/DCCpp_NodeMCU/WiFiCommand.h new file mode 100644 index 0000000..554d5d0 --- /dev/null +++ b/DCCpp_NodeMCU/WiFiCommand.h @@ -0,0 +1,26 @@ +/********************************************************************** + +WiFiCommand.h +COPYRIGHT (c) 2013-2016 Gregg E. Berman + +Part of DCC++ BASE STATION for the Arduino + +**********************************************************************/ + +#ifndef WiFiCommand_h +#define WiFiCommand_h + +#define MAX_COMMAND_LENGTH 30 +#define MAX_CLIENTS 8 + +struct WiFiCommand{ + static char commandString[MAX_CLIENTS][MAX_COMMAND_LENGTH+1]; + static void init(); + static void parse(char *); + static void process(); + static void print(char *); + static void print(const char * ); + static void print(int); +}; // WiFiCommand + +#endif From 47db0d2a40d68466ea327d1dc357078617790e0a Mon Sep 17 00:00:00 2001 From: Dan Worth <36244729+dtworth@users.noreply.github.com> Date: Thu, 5 Apr 2018 18:10:26 -0400 Subject: [PATCH 5/7] Update README.md --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c69071b..54cea75 100644 --- a/README.md +++ b/README.md @@ -20,4 +20,8 @@ This particular version only supports sensor inputs. For more information on the overall DCC++ system, please follow the links in the PDF file. --March 10, 2017 +-March 10, 2018 + +Support for multiple WiFi clients has been added + +-April 5, 2018 From 37cc9bff03b9dfc9c18ae0e93612c69f3fb3422d Mon Sep 17 00:00:00 2001 From: dtworth <36244729+dtworth@users.noreply.github.com> Date: Sat, 7 Apr 2018 16:11:24 -0400 Subject: [PATCH 6/7] Remote Sensors now supported Similar to the way it is implemented in DCC++32 --- DCCpp_NodeMCU/Config.h | 8 ++ DCCpp_NodeMCU/DCCpp_NodeMCU.ino | 3 +- DCCpp_NodeMCU/RemoteSensor.cpp | 190 ++++++++++++++++++++++++++++++++ DCCpp_NodeMCU/RemoteSensor.h | 38 +++++++ DCCpp_NodeMCU/Sensor.cpp | 40 ++++--- DCCpp_NodeMCU/Sensor.h | 2 +- DCCpp_NodeMCU/WiFiCommand.cpp | 12 +- 7 files changed, 274 insertions(+), 19 deletions(-) create mode 100644 DCCpp_NodeMCU/RemoteSensor.cpp create mode 100644 DCCpp_NodeMCU/RemoteSensor.h diff --git a/DCCpp_NodeMCU/Config.h b/DCCpp_NodeMCU/Config.h index 9282618..e439980 100644 --- a/DCCpp_NodeMCU/Config.h +++ b/DCCpp_NodeMCU/Config.h @@ -24,3 +24,11 @@ Part of DCC++ BASE STATION for the Arduino #define _SSID "" #define _PASSWORD "" #define _HOSTNAME "sensor02" + +///////////////////////////////////////////////////////////////////////////////////// +// +// DEFINE REMOTE SENSOR PARAMETERS +// +///////////////////////////////////////////////////////////////////////////////////// + +#define REMOTE_SENSORS_FIRST_SENSOR 100 diff --git a/DCCpp_NodeMCU/DCCpp_NodeMCU.ino b/DCCpp_NodeMCU/DCCpp_NodeMCU.ino index 39db3ed..73c57d0 100644 --- a/DCCpp_NodeMCU/DCCpp_NodeMCU.ino +++ b/DCCpp_NodeMCU/DCCpp_NodeMCU.ino @@ -78,6 +78,7 @@ DCC++ BASE STATION is configured through the Config.h file that contains all use #include "Config.h" #include "DCCpp_NodeMCU.h" #include "Sensor.h" +#include "RemoteSensor.h" #include "EEstore.h" #include "WiFiCommand.h" @@ -88,8 +89,8 @@ DCC++ BASE STATION is configured through the Config.h file that contains all use void loop(){ WiFiCommand::process(); // check for, and process, and new WiFi commands + RemoteSensor::check(); // check remotesensors for inactivity Sensor::check(); // check sensors for activate/de-activate - } // loop /////////////////////////////////////////////////////////////////////////////// diff --git a/DCCpp_NodeMCU/RemoteSensor.cpp b/DCCpp_NodeMCU/RemoteSensor.cpp new file mode 100644 index 0000000..b8feef8 --- /dev/null +++ b/DCCpp_NodeMCU/RemoteSensor.cpp @@ -0,0 +1,190 @@ +/********************************************************************** + +RemoteSensor.cpp +COPYRIGHT (c) 2018 Dan Worth + +Part of DCC++ BASE STATION for the Arduino + +**********************************************************************/ +/********************************************************************** + +DCC++ BASE STATION supports remote RemoteSensor inputs that are connected via a +WiFi connection. Remote RemoteSensors are dynamically created during startup or by a +remote RemoteSensor reporting its state. + +During startup, the base station scans for Access Points that have a name +starting with REMOTE_RemoteSensorS_PREFIX defined in Config.h, ie: "RemoteSensor01". If no +Access Points are found matching this prefix during startup they will be created +automatically when the RemoteSensor reports its state to the base station. + +Note: Remote RemoteSensors should not maintain a persistent connection. Instead they +should connect when a change occurs that should be reported. It is not necessary +for Remote RemoteSensors to report when they are INACTIVE. If a Remote RemoteSensor does not +report within REMOTE_RemoteSensorS_DECAY milliseconds the base station will +automatically transition the Remote RemoteSensor to INACTIVE state if it was +previously ACTIVE. + +To have this sketch monitor one or more for remote RemoteSensor triggers, first define/edit/delete +RemoteSensor definitions using the following variation of the "RS" command: + + : Informs the base station of the status of a remote RemoteSensor. + : Deletes remote RemoteSensor ID. + : Lists all defined remote RemoteSensors. + returns: for each defined remote RemoteSensor or + if no remote RemoteSensors have been defined/found. +where + + ID: the numeric ID (0-32667) of the remote RemoteSensor. + STATE: State of the RemoteSensors, zero is INACTIVE, non-zero is ACTIVE. + Usage is remote RemoteSensor dependent. + +If a Remote RemoteSensor Pin is found to have transitioned from one state to another, one of the following messages are generated: + + - for transition of RemoteSensor ID from HIGH state to LOW state (i.e. the RemoteSensor is triggered) +- for transition of RemoteSensor ID from LOW state to HIGH state (i.e. the RemoteSensor is no longer triggered) + +Depending on whether the physical RemoteSensor is acting as an "event-trigger" or a "detection-RemoteSensor," you may +decide to ignore thereturn and only react totriggers. + +**********************************************************************/ +#include+#include "Config.h" +#include "DCCpp_NodeMCU.h" +#include "RemoteSensor.h" +#include "EEStore.h" +#include "WiFiCommand.h" +#include + +/////////////////////////////////////////////////////////////////////////////// + +void RemoteSensor::check(){ + RemoteSensor *tt; + Sensor *stt; + + for(tt=firstRemoteSensor;tt!=NULL;tt=tt->nextRemoteSensor) + if( millis() > tt->lastUpdate + REMOTE_SENSORS_DECAY ) + if( stt = Sensor::get( tt->data.snum + REMOTE_SENSORS_FIRST_SENSOR ) ) + stt->signal = 1.0; // set to inactive on the next sensor check + else + Serial.println( "sensor not found after timeout" ); + +} // RemoteSensor::check + +/////////////////////////////////////////////////////////////////////////////// + +RemoteSensor *RemoteSensor::create(int snum, int value ){ + RemoteSensor *tt; + Sensor *stt; + + if(firstRemoteSensor==NULL){ + firstRemoteSensor=(RemoteSensor *)calloc(1,sizeof(RemoteSensor)); + tt=firstRemoteSensor; + } else if((tt=get(snum))==NULL){ + tt=firstRemoteSensor; + while(tt->nextRemoteSensor!=NULL) + tt=tt->nextRemoteSensor; + tt->nextRemoteSensor=(RemoteSensor *)calloc(1,sizeof(RemoteSensor)); + tt=tt->nextRemoteSensor; + } + + if(tt==NULL){ // problem allocating memory + WiFiCommand::print(" "); + return(tt); + } + + tt->lastUpdate = millis(); + tt->data.snum=snum; + tt->data.value=value; + if( !(stt = Sensor::get( snum + REMOTE_SENSORS_FIRST_SENSOR ) ) ) + stt = Sensor::create(snum + REMOTE_SENSORS_FIRST_SENSOR, -1, 0, 0 ); + + if( stt ) { + stt->active=value?false:true; // force a state change on the next sensor check + stt->signal=value?0.0:1.0; + } + else + Serial.println( "no sensor created or found" ); + WiFiCommand::print(" "); + return(tt); +} + +/////////////////////////////////////////////////////////////////////////////// + +RemoteSensor* RemoteSensor::get(int n){ + RemoteSensor *tt; + for(tt=firstRemoteSensor;tt!=NULL && tt->data.snum!=n;tt=tt->nextRemoteSensor); + return(tt); +} +/////////////////////////////////////////////////////////////////////////////// + +void RemoteSensor::remove(int n){ + RemoteSensor *tt,*pp; + + for(tt=firstRemoteSensor;tt!=NULL && tt->data.snum!=n;pp=tt,tt=tt->nextRemoteSensor); + + if(tt==NULL){ + WiFiCommand::print(" "); + return; + } + Sensor::remove( tt->data.snum + REMOTE_SENSORS_FIRST_SENSOR ); + + if(tt==firstRemoteSensor) + firstRemoteSensor=tt->nextRemoteSensor; + else + pp->nextRemoteSensor=tt->nextRemoteSensor; + + + free(tt); + + WiFiCommand::print(" "); +} + +/////////////////////////////////////////////////////////////////////////////// + +void RemoteSensor::show(){ + RemoteSensor *tt; + + if(firstRemoteSensor==NULL){ + WiFiCommand::print(" "); + return; + } + + for(tt=firstRemoteSensor;tt!=NULL;tt=tt->nextRemoteSensor){ + WiFiCommand::print(" data.snum); + WiFiCommand::print(" "); + WiFiCommand::print(tt->data.value); + WiFiCommand::print(">"); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +void RemoteSensor::parse(char *c){ + int n,s,m; + RemoteSensor *t; + + switch(sscanf(c,"%d %d",&n,&s)){ + + case 2: // argument is string with id number of RemoteSensor followed by a value + create(n,s); + break; + + case 1: // argument is a string with id number only + remove(n); + break; + + case -1: // no arguments + show(); + break; + + default: // invalid number of arguments + WiFiCommand::print(" "); + break; + } +} + +/////////////////////////////////////////////////////////////////////////////// + +RemoteSensor *RemoteSensor::firstRemoteSensor=NULL; + diff --git a/DCCpp_NodeMCU/RemoteSensor.h b/DCCpp_NodeMCU/RemoteSensor.h new file mode 100644 index 0000000..aacbfe6 --- /dev/null +++ b/DCCpp_NodeMCU/RemoteSensor.h @@ -0,0 +1,38 @@ +/********************************************************************** + +Sensor.h +COPYRIGHT (c) 2018 Dan Worth + +Part of DCC++ BASE STATION for the Arduino + +**********************************************************************/ + +#ifndef RemoteSensor_h +#define RemoteSensor_h + +#include "Sensor.h" + +#define REMOTE_SENSORS_PREFIX "sensor" +#define REMOTE_SENSORS_DECAY 10000 + +struct RemoteSensorData { + int snum; + int value; +}; + +struct RemoteSensor{ + static RemoteSensor *firstRemoteSensor; + RemoteSensorData data; + long lastUpdate; + RemoteSensor *nextRemoteSensor; + static RemoteSensor *create(int, int); + static RemoteSensor* get(int); + static void remove(int); +// static void status(); + static void show(); + static void parse(char *c); + static void check(); +}; // Remote Sensor + +#endif + diff --git a/DCCpp_NodeMCU/Sensor.cpp b/DCCpp_NodeMCU/Sensor.cpp index 93463f6..e644dfd 100644 --- a/DCCpp_NodeMCU/Sensor.cpp +++ b/DCCpp_NodeMCU/Sensor.cpp @@ -68,14 +68,15 @@ void Sensor::check(){ Sensor *tt; for(tt=firstSensor;tt!=NULL;tt=tt->nextSensor){ - tt->signal=tt->signal*(1.0-SENSOR_DECAY)+digitalRead(tt->data.pin)*SENSOR_DECAY; + if( tt->data.pin >= 0 ) // not for remote sensors + tt->signal=tt->signal*(1.0-SENSOR_DECAY)+digitalRead(tt->data.pin)*SENSOR_DECAY; - if(!tt->active && tt->signal<0.5){ + if(!tt->active && (tt->signal<0.5) ){ tt->active=true; WiFiCommand::print("