diff --git a/CommandStation-EX.ino b/CommandStation-EX.ino index c112c54..2b89708 100644 --- a/CommandStation-EX.ino +++ b/CommandStation-EX.ino @@ -59,6 +59,7 @@ void setup() // Responsibility 1: Start the usb connection for diagnostics // This is normally Serial but uses SerialUSB on a SAMD processor Serial.begin(115200); + Serial.setDebugOutput(true); DIAG(F("License GPLv3 fsf.org (c) dcc-ex.com")); @@ -74,7 +75,7 @@ void setup() #if WIFI_ON WifiInterface::setup(WIFI_SERIAL_LINK_SPEED, F(WIFI_SSID), F(WIFI_PASSWORD), F(WIFI_HOSTNAME), IP_PORT, WIFI_CHANNEL); #endif // WIFI_ON - + WifiESP::setup(WIFI_SSID, WIFI_PASSWORD, WIFI_HOSTNAME, 2560, 1); #if ETHERNET_ON EthernetInterface::setup(); #endif // ETHERNET_ON @@ -118,6 +119,7 @@ void loop() #if WIFI_ON WifiInterface::loop(); #endif + WifiESP::loop(); #if ETHERNET_ON EthernetInterface::loop(); #endif @@ -134,11 +136,12 @@ void loop() // Report any decrease in memory (will automatically trigger on first call) static int ramLowWatermark = __INT_MAX__; // replaced on first loop - +/* int freeNow = minimumFreeMemory(); if (freeNow < ramLowWatermark) { ramLowWatermark = freeNow; LCD(2,F("Free RAM=%5db"), ramLowWatermark); } + */ } diff --git a/DCCEX.h b/DCCEX.h index 1504490..f6668a6 100644 --- a/DCCEX.h +++ b/DCCEX.h @@ -31,6 +31,7 @@ #include "DCCEXParser.h" #include "version.h" #include "WifiInterface.h" +#include "WifiESP.h" #if ETHERNET_ON == true #include "EthernetInterface.h" #endif diff --git a/DCCTimer.cpp b/DCCTimer.cpp index 0ea7491..5228501 100644 --- a/DCCTimer.cpp +++ b/DCCTimer.cpp @@ -150,16 +150,24 @@ void DCCTimer::read(uint8_t word, uint8_t *mac, uint8_t offset) { // ESP8266 !!!!!!!!!!!!!!!!!!!!! void DCCTimer::begin(INTERRUPT_CALLBACK callback) { interruptHandler=callback; + timer1_disable(); +// ETS_FRC_TIMER1_INTR_ATTACH(NULL, NULL); +// ETS_FRC_TIMER1_NMI_INTR_ATTACH(interruptHandler); + timer1_attachInterrupt(interruptHandler); + timer1_enable(TIM_DIV1, TIM_EDGE, TIM_LOOP); + timer1_write(CLOCK_CYCLES); +/* noInterrupts(); timer1_attachInterrupt(interruptHandler); timer1_write(CLOCK_CYCLES); timer1_enable(TIM_DIV1, TIM_EDGE, TIM_LOOP); interrupts(); +*/ } -bool DCCTimer::isPWMPin(byte pin) { +IRAM_ATTR bool DCCTimer::isPWMPin(byte pin) { return false; } -void DCCTimer::setPWM(byte pin, bool high) { +void ICACHE_RAM_ATTR DCCTimer::setPWM(byte pin, bool high) { } diff --git a/DCCWaveform.cpp b/DCCWaveform.cpp index df88e5d..aaffc2a 100644 --- a/DCCWaveform.cpp +++ b/DCCWaveform.cpp @@ -53,31 +53,26 @@ void DCCWaveform::begin(MotorDriver * mainDriver, MotorDriver * progDriver) { DCCTimer::begin(DCCWaveform::interruptHandler); } -void DCCWaveform::loop(bool ackManagerActive) { +void IRAM_ATTR DCCWaveform::loop(bool ackManagerActive) { mainTrack.checkPowerOverload(false); progTrack.checkPowerOverload(ackManagerActive); } -void DCCWaveform::interruptHandler() { +void IRAM_ATTR DCCWaveform::interruptHandler() { // call the timer edge sensitive actions for progtrack and maintrack // member functions would be cleaner but have more overhead byte sigMain=signalTransform[mainTrack.state]; byte sigProg=progTrackSyncMain? sigMain : signalTransform[progTrack.state]; - // Set the signal state for both tracks mainTrack.motorDriver->setSignal(sigMain); progTrack.motorDriver->setSignal(sigProg); - // Move on in the state engine mainTrack.state=stateTransform[mainTrack.state]; progTrack.state=stateTransform[progTrack.state]; - - // WAVE_PENDING means we dont yet know what the next bit is if (mainTrack.state==WAVE_PENDING) mainTrack.interrupt2(); if (progTrack.state==WAVE_PENDING) progTrack.interrupt2(); else if (progTrack.ackPending) progTrack.checkAck(); - } @@ -197,7 +192,7 @@ const bool DCCWaveform::signalTransform[]={ /* WAVE_LOW_0 -> */ LOW, /* WAVE_PENDING (should not happen) -> */ LOW}; -void DCCWaveform::interrupt2() { +void ICACHE_RAM_ATTR DCCWaveform::interrupt2() { // calculate the next bit to be sent: // set state WAVE_MID_1 for a 1=bit // or WAVE_HIGH_0 for a 0 bit. @@ -207,7 +202,7 @@ void DCCWaveform::interrupt2() { remainingPreambles--; // Update free memory diagnostic as we don't have anything else to do this time. // Allow for checkAck and its called functions using 22 bytes more. - updateMinimumFreeMemory(22); +// might break ESP8266 updateMinimumFreeMemory(22); return; } @@ -306,7 +301,7 @@ byte DCCWaveform::getAck() { return(0); // pending set off but not detected means no ACK. } -void DCCWaveform::checkAck() { +void ICACHE_RAM_ATTR DCCWaveform::checkAck() { // This function operates in interrupt() time so must be fast and can't DIAG if (sentResetsSincePacket > 6) { //ACK timeout ackCheckDuration=millis()-ackCheckStart; diff --git a/MotorDriver.cpp b/MotorDriver.cpp index 769c7d6..c6c37cf 100644 --- a/MotorDriver.cpp +++ b/MotorDriver.cpp @@ -21,11 +21,6 @@ #include "DCCTimer.h" #include "DIAG.h" -#define setHIGH(fastpin) *fastpin.inout |= fastpin.maskHIGH -#define setLOW(fastpin) *fastpin.inout &= fastpin.maskLOW -#define isHIGH(fastpin) (*fastpin.inout & fastpin.maskHIGH) -#define isLOW(fastpin) (!isHIGH(fastpin)) - bool MotorDriver::usePWM=false; bool MotorDriver::commonFaultPin=false; @@ -109,8 +104,8 @@ void MotorDriver::setBrake(bool on) { if (on ^ invertBrake) setHIGH(fastBrakePin); else setLOW(fastBrakePin); } - -void MotorDriver::setSignal( bool high) { +/* +IRAM_ATTR void MotorDriver::setSignal( bool high) { if (usePWM) { DCCTimer::setPWM(signalPin,high); } @@ -125,7 +120,7 @@ void MotorDriver::setSignal( bool high) { } } } - +*/ #if defined(ARDUINO_TEENSY32) || defined(ARDUINO_TEENSY35)|| defined(ARDUINO_TEENSY36) volatile unsigned int overflow_count=0; #endif diff --git a/MotorDriver.h b/MotorDriver.h index ffa8387..06c19b1 100644 --- a/MotorDriver.h +++ b/MotorDriver.h @@ -42,12 +42,27 @@ struct FASTPIN { }; #endif +#define setHIGH(fastpin) *fastpin.inout |= fastpin.maskHIGH +#define setLOW(fastpin) *fastpin.inout &= fastpin.maskLOW +#define isHIGH(fastpin) (*fastpin.inout & fastpin.maskHIGH) +#define isLOW(fastpin) (!isHIGH(fastpin)) + class MotorDriver { public: MotorDriver(byte power_pin, byte signal_pin, byte signal_pin2, int8_t brake_pin, byte current_pin, float senseFactor, unsigned int tripMilliamps, byte faultPin); virtual void setPower( bool on); - virtual void setSignal( bool high); + virtual void setSignal( bool high) { + if (high) { + setHIGH(fastSignalPin); + if (dualSignal) setLOW(fastSignalPin2); + } + else { + setLOW(fastSignalPin); + if (dualSignal) setHIGH(fastSignalPin2); + } + }; + virtual void setBrake( bool on); virtual int getCurrentRaw(); virtual unsigned int raw2mA( int raw); diff --git a/WifiESP.cpp b/WifiESP.cpp index 5435ca0..e99b1a9 100644 --- a/WifiESP.cpp +++ b/WifiESP.cpp @@ -17,15 +17,111 @@ along with CommandStation. If not, see . */ +#include +#include +#include + #include "WifiESP.h" #include "DIAG.h" +#include "RingStream.h" +#include "CommandDistributor.h" +#include -bool WifiESP::setup(const FSH *wifiESSID, - const FSH *wifiPassword, - const FSH *hostname, - const int port, - const byte channel) { +static std::vector clients; // a list to hold all clients +static AsyncServer *server; +static RingStream *outboundRing = new RingStream(2048); + +static void handleError(void* arg, AsyncClient* client, int8_t error) { + DIAG(F("connection error %s from client %s"), client->errorToString(error), client->remoteIP().toString().c_str()); +} + +static void handleData(void* arg, AsyncClient* client, void *data, size_t len) { + DIAG(F("data received from client %s"), client->remoteIP().toString().c_str()); + uint8_t clientId; + for (clientId=0; clientIdspace() >= (c=outboundRing->count()) && client->canSend()) { + char cmd[c+1]; + int i; + for (i=0;iread(); + } + cmd[i]=0; + client->add(cmd, strlen(cmd)); + client->send(); + } +} + +static void handleDisconnect(void* arg, AsyncClient* client) { + DIAG(F("client %s disconnected"), client->remoteIP().toString().c_str()); +} + +static void handleTimeOut(void* arg, AsyncClient* client, uint32_t time) { + DIAG(F("client ACK timeout ip: %s"), client->remoteIP().toString().c_str()); +} + + +static void handleNewClient(void* arg, AsyncClient* client) { + DIAG(F("New client has been connected to server, ip: %s"), client->remoteIP().toString().c_str()); + + // add to list + clients.push_back(client); + + // register events + client->onData(&handleData, NULL); + client->onError(&handleError, NULL); + client->onDisconnect(&handleDisconnect, NULL); + client->onTimeout(&handleTimeOut, NULL); + +} + +bool WifiESP::setup(const char *wifiESSID, + const char *wifiPassword, + const char *hostname, + int port, + const byte channel) { + DIAG(F("START")); + // connects to access point + wifi_set_sleep_type(NONE_SLEEP_T); + WiFi.mode(WIFI_STA); + WiFi.setAutoReconnect(true); + DIAG(F("BEGIN")); + WiFi.begin(wifiESSID, wifiPassword); + DIAG(F("STATUS")); + while (WiFi.status() != WL_CONNECTED) { + Serial.print('.'); + delay(500); + } + + DIAG(F("SERVER")); + + server = new AsyncServer(port); // start listening on tcp port + + DIAG(F("CLIENT")); + server->onClient(&handleNewClient, server); + DIAG(F("SBEGIN")); + + server->begin(); + + DIAG(F("ENDSETUP")); + + return true; } void WifiESP::loop() { + static unsigned long last = 0; + if (millis() - last > 60000) { + last = millis(); + DIAG(F("+")); + } + ESP.wdtFeed(); } diff --git a/WifiESP.h b/WifiESP.h index d73c741..971ccc7 100644 --- a/WifiESP.h +++ b/WifiESP.h @@ -16,16 +16,19 @@ * You should have received a copy of the GNU General Public License * along with CommandStation. If not, see . */ + #ifndef WifiESP_h #define WifiESP_h +#include "FSH.h" + class WifiESP { public: - static bool setup(const FSH *wifiESSID, - const FSH *wifiPassword, - const FSH *hostname, + static bool setup(const char *wifiESSID, + const char *wifiPassword, + const char *hostname, const int port, const byte channel); static void loop(); diff --git a/config.example.h b/config.example.h index 1d1977a..eb7e02b 100644 --- a/config.example.h +++ b/config.example.h @@ -41,7 +41,14 @@ The configuration file for DCC-EX Command Station // | // +-----------------------v // -#define MOTOR_SHIELD_TYPE STANDARD_MOTOR_SHIELD +//#define MOTOR_SHIELD_TYPE STANDARD_MOTOR_SHIELD + +#define ESP_MOTOR_SHIELD F("ESP"), \ + new MotorDriver(D3, D5, UNUSED_PIN, UNUSED_PIN, UNUSED_PIN, 2.99, 2000, UNUSED_PIN),\ + new MotorDriver(D2, D6, UNUSED_PIN, UNUSED_PIN, UNUSED_PIN, 2.99, 2000, UNUSED_PIN) + +#define MOTOR_SHIELD_TYPE ESP_MOTOR_SHIELD + ///////////////////////////////////////////////////////////////////////////////////// // // The IP port to talk to a WIFI or Ethernet shield. @@ -53,7 +60,7 @@ The configuration file for DCC-EX Command Station // NOTE: Only supported on Arduino Mega // Set to false if you not even want it on the Arduino Mega // -#define ENABLE_WIFI true +//#define ENABLE_WIFI true ///////////////////////////////////////////////////////////////////////////////////// // diff --git a/freeMemory.cpp b/freeMemory.cpp index 6eb822e..af7bd16 100644 --- a/freeMemory.cpp +++ b/freeMemory.cpp @@ -64,9 +64,7 @@ static inline int freeMemory() { } // Return low memory value. int minimumFreeMemory() { - noInterrupts(); // Disable interrupts int retval = minimum_free_memory; - interrupts(); // interrupts return retval; } #else @@ -118,7 +116,7 @@ int minimumFreeMemory() { // So even if all of the heap is freed, the reported minimum free // memory will not increase. // -void updateMinimumFreeMemory(unsigned char extraBytes) { +void ICACHE_RAM_ATTR updateMinimumFreeMemory(unsigned char extraBytes) { int spare = freeMemory()-extraBytes; if (spare < 0) spare = 0; if (spare < minimum_free_memory) minimum_free_memory = spare;