diff --git a/CommandStation-EX.ino b/CommandStation-EX.ino index 77e8f40..cd3caf1 100644 --- a/CommandStation-EX.ino +++ b/CommandStation-EX.ino @@ -52,6 +52,10 @@ #include "DCCEX.h" #include "Display_Implementation.h" +#ifdef ARDUINO_ARCH_ESP32 + #include +#endif // ARDUINO_ARCH_ESP32 + #ifdef CPU_TYPE_ERROR #error CANNOT COMPILE - DCC++ EX ONLY WORKS WITH THE ARCHITECTURES LISTED IN defines.h #endif @@ -76,7 +80,7 @@ void setup() DIAG(F("License GPLv3 fsf.org (c) dcc-ex.com")); -// Initialise HAL layer before reading EEprom or setting up MotorDrivers +// Initialise HAL layer before reading EEprom or setting up MotorDrivers IODevice::begin(); // As the setup of a motor shield may require a read of the current sense input from the ADC, @@ -101,12 +105,15 @@ void setup() #else // ESP32 needs wifi on always WifiESP::setup(WIFI_SSID, WIFI_PASSWORD, WIFI_HOSTNAME, IP_PORT, WIFI_CHANNEL, WIFI_FORCE_AP); + #if OTA_AUTO_INIT + Diag::OTA = true; + #endif // OTA_AUTO_INIT #endif // ARDUINO_ARCH_ESP32 #if ETHERNET_ON EthernetInterface::setup(); #endif // ETHERNET_ON - + // Responsibility 3: Start the DCC engine. DCC::begin(); @@ -150,6 +157,50 @@ void loop() #ifndef WIFI_TASK_ON_CORE0 WifiESP::loop(); #endif + // Responsibility 4: Optionally handle Arduino OTA updates + if (Diag::OTA) { + static bool otaInitialised = false; + // Initialise OTA if not already done + if (!otaInitialised) { + ArduinoOTA.setHostname(WIFI_HOSTNAME); + // Prevent locos from moving during OTA + ArduinoOTA.onStart([]() { + // Emergency stop all locos + DCC::setThrottle(0,1,1); + // Disable tracks power + TrackManager::setMainPower(POWERMODE::OFF); + TrackManager::setProgPower(POWERMODE::OFF); + // Broadcast power status + CommandDistributor::broadcastPower(); + DISPLAY_START ( + LCD(0,F("OTA update")); + LCD(1,F("In progress...")); + ); + }); + ArduinoOTA.onEnd([]() { + DISPLAY_START ( + LCD(0,F("OTA update")); + LCD(1,F("Complete")); + ); + }); + ArduinoOTA.onError([](ota_error_t error) { + DISPLAY_START ( + LCD(0,F("OTA update")); + LCD(1,F("Error: %d"), error); + ); + }); + // Set OTA password if defined + #ifdef OTA_AUTH + ArduinoOTA.setPassword(OTA_AUTH); + #endif // OTA_AUTH + ArduinoOTA.begin(); + otaInitialised = true; + } + // Handle OTA if initialised + else { + ArduinoOTA.handle(); + } + } #endif //ARDUINO_ARCH_ESP32 #if ETHERNET_ON EthernetInterface::loop(); diff --git a/DCCEXParser.cpp b/DCCEXParser.cpp index 04c0b6d..9dbb3cf 100644 --- a/DCCEXParser.cpp +++ b/DCCEXParser.cpp @@ -9,7 +9,7 @@ * © 2020-2021 Chris Harlow * © 2022 Colin Murdoch * All rights reserved. - * + * * This file is part of CommandStation-EX * * This is free software: you can redistribute it and/or modify @@ -116,13 +116,13 @@ Once a new OPCODE is decided upon, update this list. #include "EXRAIL2.h" // This macro can't be created easily as a portable function because the -// flashlist requires a far pointer for high flash access. +// flashlist requires a far pointer for high flash access. #define SENDFLASHLIST(stream,flashList) \ for (int16_t i=0;;i+=sizeof(flashList[0])) { \ int16_t value=GETHIGHFLASHW(flashList,i); \ if (value==INT16_MAX) break; \ StringFormatter::send(stream,F(" %d"),value); \ - } + } // These keywords are used in the <1> command. The number is what you get if you use the keyword as a parameter. @@ -168,6 +168,7 @@ const int16_t HASH_KEYWORD_ANOUT = -26399; const int16_t HASH_KEYWORD_WIFI = -5583; const int16_t HASH_KEYWORD_ETHERNET = -30767; const int16_t HASH_KEYWORD_WIT = 31594; +const int16_t HASH_KEYWORD_OTA = 22938; int16_t DCCEXParser::stashP[MAX_COMMAND_PARAMS]; bool DCCEXParser::stashBusy; @@ -265,10 +266,10 @@ void DCCEXParser::setAtCommandCallback(AT_COMMAND_CALLBACK callback) atCommandCallback = callback; } -// Parse an F() string +// Parse an F() string void DCCEXParser::parse(const FSH * cmd) { DIAG(F("SETUP(\"%S\")"),cmd); - int size=STRLEN_P((char *)cmd)+1; + int size=STRLEN_P((char *)cmd)+1; char buffer[size]; STRCPY_P(buffer,(char *)cmd); parse(&USB_SERIAL,(byte *)buffer,NULL); @@ -305,7 +306,7 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream) com++; // strip off any number of < or spaces byte opcode = com[0]; byte params = splitValues(p, com, opcode=='M' || opcode=='P'); - + if (filterCallback) filterCallback(stream, opcode, params, p); if (filterRMFTCallback && opcode!='\0') @@ -319,22 +320,22 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream) case 't': // THROTTLE { if (params==1) { // display state - + int16_t slot=DCC::lookupSpeedTable(p[0],false); if (slot>=0) { DCC::LOCO * sp=&DCC::speedTable[slot]; StringFormatter::send(stream,F("\n"), sp->loco,slot,sp->speedCode,sp->functions); } - else // send dummy state speed 0 fwd no functions. + else // send dummy state speed 0 fwd no functions. StringFormatter::send(stream,F("\n"),p[0]); - return; + return; } - + int16_t cab; int16_t tspeed; int16_t direction; - + if (params == 4) { // cab = p[1]; @@ -379,7 +380,7 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream) break; case 'a': // ACCESSORY or - { + { int address; byte subaddress; byte activep; @@ -405,7 +406,7 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream) onoff=p[3]; } else break; // invalid no of parameters - + if ( ((address & 0x01FF) != address) // invalid address (limit 9 bits) || ((subaddress & 0x03) != subaddress) // invalid subaddress (limit 2 bits) @@ -419,25 +420,25 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream) #endif } return; - + case 'T': // TURNOUT if (parseT(stream, params, p)) return; break; case 'z': // direct pin manipulation - if (p[0]==0) break; - if (params==1) { // + if (p[0]==0) break; + if (params==1) { // if (p[0]>0) IODevice::write(p[0],HIGH); else IODevice::write(-p[0],LOW); return; } - if (params>=2 && params<=4) { // - // unused params default to 0 + if (params>=2 && params<=4) { // + // unused params default to 0 IODevice::writeAnalogue(p[0],p[1],p[2],p[3]); return; } - break; + break; case 'Z': // OUTPUT if (parseZ(stream, params, p)) @@ -473,10 +474,10 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream) packet[i]=(byte)p[i+1]; if (Diag::CMD) DIAG(F("packet[%d]=%d (0x%x)"), i, packet[i], packet[i]); } - (opcode=='M'?DCCWaveform::mainTrack:DCCWaveform::progTrack).schedulePacket(packet,params,3); + (opcode=='M'?DCCWaveform::mainTrack:DCCWaveform::progTrack).schedulePacket(packet,params,3); } return; - + #ifndef DISABLE_PROG case 'W': // WRITE CV ON PROG if (!stashCallback(stream, p, ringStream)) @@ -622,7 +623,7 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream) CommandDistributor::broadcastPower(); // is the only "get power status" command we have Turnout::printAll(stream); //send all Turnout states Sensor::printAll(stream); //send all Sensor states - return; + return; #ifndef DISABLE_EEPROM case 'E': // STORE EPROM @@ -660,7 +661,7 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream) return; case 'F': // New command to call the new Loco Function API - if(params!=3) break; + if(params!=3) break; if (Diag::CMD) DIAG(F("Setting loco %d F%d %S"), p[0], p[1], p[2] ? F("ON") : F("OFF")); if (DCC::setFn(p[0], p[1], p[2] == 1)) return; @@ -674,7 +675,7 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream) return; } break; -#endif +#endif case 'J' : // throttle info access { @@ -690,15 +691,15 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream) } CommandDistributor::setClockTime(p[1], p[2], 1); return; - + case HASH_KEYWORD_G: // current gauge limits if (params>1) break; - TrackManager::reportGauges(stream); // + TrackManager::reportGauges(stream); // return; - + case HASH_KEYWORD_I: // current values if (params>1) break; - TrackManager::reportCurrent(stream); // + TrackManager::reportCurrent(stream); // return; case HASH_KEYWORD_A: // returns automations/routes @@ -710,19 +711,19 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream) #endif } else { // - StringFormatter::send(stream,F(" %d %c \"%S\""), - id, + StringFormatter::send(stream,F(" %d %c \"%S\""), + id, #ifdef EXRAIL_ACTIVE RMFT2::getRouteType(id), // A/R RMFT2::getRouteDescription(id) -#else +#else 'X',F("") -#endif +#endif ); } - StringFormatter::send(stream, F(">\n")); - return; - case HASH_KEYWORD_R: // returns rosters + StringFormatter::send(stream, F(">\n")); + return; + case HASH_KEYWORD_R: // returns rosters StringFormatter::send(stream, F("\n")); - return; - case HASH_KEYWORD_T: // returns turnout list +#endif + StringFormatter::send(stream, F(">\n")); + return; + case HASH_KEYWORD_T: // returns turnout list StringFormatter::send(stream, F(" - for ( Turnout * t=Turnout::first(); t; t=t->next()) { - if (t->isHidden()) continue; + for ( Turnout * t=Turnout::first(); t; t=t->next()) { + if (t->isHidden()) continue; StringFormatter::send(stream, F(" %d"),t->getId()); } } @@ -766,7 +767,7 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream) } StringFormatter::send(stream, F(">\n")); return; - default: break; + default: break; } // switch(p[1]) break; // case J } @@ -788,7 +789,7 @@ bool DCCEXParser::parseZ(Print *stream, int16_t params, int16_t p[]) switch (params) { - + case 2: // { Output *o = Output::get(p[0]); @@ -844,14 +845,14 @@ bool DCCEXParser::parsef(Print *stream, int16_t params, int16_t p[]) return (funcmap(p[0], p[1], 5, 8)); else return (funcmap(p[0], p[1], 9, 12)); - } + } } if (params == 3) { if (p[1] == 222) { return (funcmap(p[0], p[2], 13, 20)); } else if (p[1] == 223) { return (funcmap(p[0], p[2], 21, 28)); - } + } } (void)stream; // NO RESPONSE return false; @@ -880,7 +881,7 @@ bool DCCEXParser::parseT(Print *stream, int16_t params, int16_t p[]) StringFormatter::send(stream, F("\n")); return true; - case 2: // + case 2: // { bool state = false; switch (p[1]) { @@ -913,10 +914,10 @@ bool DCCEXParser::parseT(Print *stream, int16_t params, int16_t p[]) if (params == 6 && p[1] == HASH_KEYWORD_SERVO) { // if (!ServoTurnout::create(p[0], (VPIN)p[2], (uint16_t)p[3], (uint16_t)p[4], (uint8_t)p[5])) return false; - } else + } else if (params == 3 && p[1] == HASH_KEYWORD_VPIN) { // if (!VpinTurnout::create(p[0], p[2])) return false; - } else + } else if (params >= 3 && p[1] == HASH_KEYWORD_DCC) { // 0<=addr<=511, 0<=subadd<=3 (like command). if (params==4 && p[2]>=0 && p[2]<512 && p[3]>=0 && p[3]<4) { // @@ -926,14 +927,14 @@ bool DCCEXParser::parseT(Print *stream, int16_t params, int16_t p[]) if (!DCCTurnout::create(p[0], (p[2]-1)/4+1, (p[2]-1)%4)) return false; } else return false; - } else + } else if (params==3) { // legacy for DCC accessory if (p[1]>=0 && p[1]<512 && p[2]>=0 && p[2]<4) { if (!DCCTurnout::create(p[0], p[1], p[2])) return false; } else return false; - } - else + } + else if (params==4) { // legacy for Servo if (!ServoTurnout::create(p[0], (VPIN)p[1], (uint16_t)p[2], (uint16_t)p[3], 1)) return false; } else @@ -1042,8 +1043,8 @@ bool DCCEXParser::parseD(Print *stream, int16_t params, int16_t p[]) #endif case HASH_KEYWORD_RESET: DCCTimer::reset(); - break; // and if we didnt restart - + break; // and if we didnt restart + #ifndef DISABLE_EEPROM case HASH_KEYWORD_EEPROM: // @@ -1072,8 +1073,8 @@ bool DCCEXParser::parseD(Print *stream, int16_t params, int16_t p[]) break; #if !defined(IO_NO_HAL) - case HASH_KEYWORD_HAL: - if (p[1] == HASH_KEYWORD_SHOW) + case HASH_KEYWORD_HAL: + if (p[1] == HASH_KEYWORD_SHOW) IODevice::DumpAll(); else if (p[1] == HASH_KEYWORD_RESET) IODevice::reset(); @@ -1084,6 +1085,11 @@ bool DCCEXParser::parseD(Print *stream, int16_t params, int16_t p[]) IODevice::writeAnalogue(p[1], p[2], params>3 ? p[3] : 0); break; + case HASH_KEYWORD_OTA: // + Diag::OTA = onOff; + DIAG(F("OTA=%S"), onOff ? F("ON") : F("OFF")); + return true; + default: // invalid/unknown break; } @@ -1132,7 +1138,7 @@ void DCCEXParser::callback_W4(int16_t result) void DCCEXParser::callback_B(int16_t result) { - StringFormatter::send(getAsyncReplyStream(), + StringFormatter::send(getAsyncReplyStream(), F("\n"), stashP[3], stashP[4], stashP[0], stashP[1], result == 1 ? stashP[2] : -1); commitAsyncReplyStream(); } diff --git a/StringFormatter.cpp b/StringFormatter.cpp index c475ef0..c145726 100644 --- a/StringFormatter.cpp +++ b/StringFormatter.cpp @@ -1,6 +1,6 @@ /* * © 2020, Chris Harlow. All rights reserved. - * + * * This file is part of Asbelos DCC API * * This is free software: you can redistribute it and/or modify @@ -26,10 +26,11 @@ bool Diag::WIFI=false; bool Diag::WITHROTTLE=false; bool Diag::ETHERNET=false; bool Diag::LCN=false; +bool Diag::OTA=false; + - void StringFormatter::diag( const FSH* input...) { - USB_SERIAL.print(F("<* ")); + USB_SERIAL.print(F("<* ")); va_list args; va_start(args, input); send2(&USB_SERIAL,input,args); @@ -44,8 +45,8 @@ void StringFormatter::lcd(byte row, const FSH* input...) { va_start(args, input); send2(&USB_SERIAL,input,args); send(&USB_SERIAL,F(" *>\n")); - - DisplayInterface::setRow(row); + + DisplayInterface::setRow(row); va_start(args, input); send2(DisplayInterface::getDisplayHandler(),input,args); } @@ -53,7 +54,7 @@ void StringFormatter::lcd(byte row, const FSH* input...) { void StringFormatter::lcd2(uint8_t display, byte row, const FSH* input...) { va_list args; - DisplayInterface::setRow(display, row); + DisplayInterface::setRow(display, row); va_start(args, input); send2(DisplayInterface::getDisplayHandler(),input,args); } @@ -71,7 +72,7 @@ void StringFormatter::send(Print & stream, const FSH* input...) { } void StringFormatter::send2(Print * stream,const FSH* format, va_list args) { - + // thanks to Jan Turoň https://arduino.stackexchange.com/questions/56517/formatting-strings-in-arduino-for-output char* flash=(char*)format; @@ -82,9 +83,9 @@ void StringFormatter::send2(Print * stream,const FSH* format, va_list args) { bool formatContinues=false; byte formatWidth=0; - bool formatLeft=false; + bool formatLeft=false; do { - + formatContinues=false; i++; c=GETFLASH(flash+i); @@ -95,16 +96,16 @@ void StringFormatter::send2(Print * stream,const FSH* format, va_list args) { case 'e': printEscapes(stream,va_arg(args, char*)); break; case 'E': printEscapes(stream,(const FSH*)va_arg(args, char*)); break; case 'S': - { + { const FSH* flash= (const FSH*)va_arg(args, char*); #if WIFI_ON | ETHERNET_ON // RingStream has special logic to handle flash strings // but is not implemented unless wifi or ethernet are enabled. - // The define prevents RingStream code being added unnecessariliy. + // The define prevents RingStream code being added unnecessariliy. if (stream->availableForWrite()==RingStream::THIS_IS_A_RINGSTREAM) ((RingStream *)stream)->printFlash(flash); - else + else #endif stream->print(flash); break; @@ -137,20 +138,20 @@ void StringFormatter::send2(Print * stream,const FSH* format, va_list args) { break; //case 'f': stream->print(va_arg(args, double), 2); break; //format width prefix - case '-': + case '-': formatLeft=true; formatContinues=true; - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': formatWidth=formatWidth * 10 + (c-'0'); formatContinues=true; break; @@ -170,7 +171,7 @@ void StringFormatter::printEscapes(Print * stream,char * input) { } void StringFormatter::printEscapes(Print * stream, const FSH * input) { - + if (!stream) return; char* flash=(char*)input; for(int i=0; ; ++i) { @@ -187,35 +188,35 @@ void StringFormatter::printEscape( char c) { void StringFormatter::printEscape(Print * stream, char c) { if (!stream) return; switch(c) { - case '\n': stream->print(F("\\n")); break; - case '\r': stream->print(F("\\r")); break; - case '\0': stream->print(F("\\0")); return; + case '\n': stream->print(F("\\n")); break; + case '\r': stream->print(F("\\r")); break; + case '\0': stream->print(F("\\0")); return; case '\t': stream->print(F("\\t")); break; case '\\': stream->print(F("\\\\")); break; default: stream->write(c); } } - + void StringFormatter::printPadded(Print* stream, long value, byte width, bool formatLeft) { if (width==0) { stream->print(value, DEC); return; } - + int digits=(value <= 0)? 1: 0; // zero and negative need extra digot long v=value; while (v) { v /= 10; digits++; } - + if (formatLeft) stream->print(value, DEC); while(digitsprint(' '); digits++; } - if (!formatLeft) stream->print(value, DEC); + if (!formatLeft) stream->print(value, DEC); } - + diff --git a/StringFormatter.h b/StringFormatter.h index 6923c10..8d65416 100644 --- a/StringFormatter.h +++ b/StringFormatter.h @@ -1,6 +1,6 @@ /* * © 2020, Chris Harlow. All rights reserved. - * + * * This file is part of Asbelos DCC API * * This is free software: you can redistribute it and/or modify @@ -30,7 +30,7 @@ class Diag { static bool WITHROTTLE; static bool ETHERNET; static bool LCN; - + static bool OTA; }; class StringFormatter @@ -38,7 +38,7 @@ class StringFormatter public: static void send(Print * serial, const FSH* input...); static void send(Print & serial, const FSH* input...); - + static void printEscapes(Print * serial,char * input); static void printEscapes(Print * serial,const FSH* input); static void printEscape(Print * serial, char c); @@ -50,7 +50,7 @@ class StringFormatter static void printEscapes(char * input); static void printEscape( char c); - private: + private: static void send2(Print * serial, const FSH* input,va_list args); static void printPadded(Print* stream, long value, byte width, bool formatLeft); diff --git a/config.example.h b/config.example.h index 0f136f9..f272758 100644 --- a/config.example.h +++ b/config.example.h @@ -5,7 +5,7 @@ * © 2020-2021 Fred Decker * © 2020-2021 Chris Harlow * © 2023 Nathan Kellenicki - * + * * This file is part of CommandStation-EX * * This is free software: you can redistribute it and/or modify @@ -32,7 +32,7 @@ The configuration file for DCC-EX Command Station // If you want to add your own motor driver definition(s), add them here // For example MY_SHIELD with display name "MINE": // (remove comment start and end marker if you want to edit and use that) -/* +/* #define MY_SHIELD F("MINE"), \ new MotorDriver( 3, 12, UNUSED_PIN, 9, A0, 5.08, 3000, A4), \ new MotorDriver(11, 13, UNUSED_PIN, 8, A1, 5.08, 1500, A5) @@ -50,7 +50,7 @@ The configuration file for DCC-EX Command Station // STANDARD_MOTOR_SHIELD : Arduino Motor shield Rev3 based on the L298 with 18V 2A per channel // POLOLU_MOTOR_SHIELD : Pololu MC33926 Motor Driver (not recommended for prog track) // FUNDUMOTO_SHIELD : Fundumoto Shield, no current sensing (not recommended, no short protection) -// FIREBOX_MK1 : The Firebox MK1 +// FIREBOX_MK1 : The Firebox MK1 // FIREBOX_MK1S : The Firebox MK1S // IBT_2_WITH_ARDUINO : Arduino Motor Shield for PROG and IBT-2 for MAIN // EX8874_SHIELD : DCC-EX TI DRV8874 based motor shield @@ -96,7 +96,7 @@ The configuration file for DCC-EX Command Station //#define DONT_TOUCH_WIFI_CONF // // WIFI_SSID is the network name IF you want to use your existing home network. -// Do NOT change this if you want to use the WiFi in Access Point (AP) mode. +// Do NOT change this if you want to use the WiFi in Access Point (AP) mode. // // If you do NOT set the WIFI_SSID and do NOT set the WIFI_PASSWORD, // then the WiFi chip will first try to connect to the previously @@ -112,14 +112,17 @@ The configuration file for DCC-EX Command Station // // WIFI_PASSWORD is the network password for your home network or if // you want to change the password from default AP mode password -// to the AP password you want. +// to the AP password you want. // Your password may not contain ``"'' (double quote, ASCII 0x22). #define WIFI_PASSWORD "Your network passwd" // // WIFI_HOSTNAME: You probably don't need to change this +// Note: If you're using OTA updates (OTA_ENABLED == true), and decide +// to modify this name, remember to concurrently update the "upload_port" +// in the corresponding environment within the platformio.ini file. #define WIFI_HOSTNAME "dccex" // -// WIFI_CHANNEL: If the line "#define ENABLE_WIFI true" is uncommented, +// WIFI_CHANNEL: If the line "#define ENABLE_WIFI true" is uncommented, // WiFi will be enabled (Mega only). The default channel is set to "1" whether // this line exists or not. If you need to use an alternate channel (we recommend // using only 1,6, or 11) you may change it here. @@ -129,6 +132,21 @@ The configuration file for DCC-EX Command Station // true. Otherwise it is assumed that you'd like to connect to an existing network // with that SSID. #define WIFI_FORCE_AP false +// +// OTA_AUTO_INIT: Set this to true if you want OTA updates to be initialized +// automatically upon startup. If set to false, OTA updates will remain +// unavailable until the "" command is executed. +// Please note that this feature requires the use of ARDUINO_ARCH_ESP32 as your board. +#define OTA_AUTO_INIT false +// +// OTA_AUTH: Set this to your desired password if you wish to secure OTA updates. +// If not set, OTA updates will be password-free. +// Note: Upon modifying the OTA password, ensure to update the "upload_flags → --auth" +// in the relevant environment within the platformio.ini file. +// To deactivate OTA authorization, comment out the line below and comment out +// the "upload_flags" line in the platformio.ini file. +// #define OTA_AUTH "dccex-ota" + ///////////////////////////////////////////////////////////////////////////////////// // @@ -186,7 +204,7 @@ The configuration file for DCC-EX Command Station // If you do not need programming capability, you can disable all programming related // commands. You might want to do that if you are using an Arduino UNO and still want // to use EXRAIL automation, as the Uno is lacking in RAM and Flash to run both. -// +// // Note this disables all programming functionality, including EXRAIL. // // #define DISABLE_PROG @@ -195,9 +213,9 @@ The configuration file for DCC-EX Command Station // REDEFINE WHERE SHORT/LONG ADDR break is. According to NMRA the last short address // is 127 and the first long address is 128. There are manufacturers which have // another view. Lenz CS for example have considered addresses long from 100. If -// you want to change to that mode, do +// you want to change to that mode, do //#define HIGHEST_SHORT_ADDR 99 -// If you want to run all your locos addressed long format, you could even do a +// If you want to run all your locos addressed long format, you could even do a //#define HIGHEST_SHORT_ADDR 0 // We do not support to use the same address, for example 100(long) and 100(short) // at the same time, there must be a border. @@ -208,7 +226,7 @@ The configuration file for DCC-EX Command Station // // According to norm RCN-213 a DCC packet with a 1 is closed/straight // and one with a 0 is thrown/diverging. In DCC++ Classic, and in previous -// versions of DCC++EX, a turnout throw command was implemented in the packet as +// versions of DCC++EX, a turnout throw command was implemented in the packet as // '1' and a close command as '0'. The #define below makes the states // match with the norm. But we don't want to cause havoc on existent layouts, // so we define this only for new installations. If you don't want this, @@ -227,7 +245,7 @@ The configuration file for DCC-EX Command Station // you can use this to reverse the sense of all accessory commmands sent // over DCC++. This #define likewise inverts the behaviour of the command // for triggering DCC Accessory Decoders, so that generates a -// DCC packet with D=1 (close turnout) and generates D=0 +// DCC packet with D=1 (close turnout) and generates D=0 // (throw turnout). //#define DCC_ACCESSORY_RCN_213 // diff --git a/platformio.ini b/platformio.ini index 1a87770..36ae0c7 100644 --- a/platformio.ini +++ b/platformio.ini @@ -9,7 +9,7 @@ ; https://docs.platformio.org/page/projectconf.html [platformio] -default_envs = +default_envs = mega2560 uno mega328 @@ -66,7 +66,7 @@ build_flags = -std=c++17 ; -DI2C_USE_WIRE -DDIAG_LOOPTIMES -DDIAG_IO platform = atmelavr board = megaatmega2560 framework = arduino -lib_deps = +lib_deps = ${env.lib_deps} arduino-libraries/Ethernet SPI @@ -78,19 +78,19 @@ build_flags = -DDIAG_IO=2 -DDIAG_LOOPTIMES platform = atmelavr board = megaatmega2560 framework = arduino -lib_deps = +lib_deps = ${env.lib_deps} arduino-libraries/Ethernet SPI monitor_speed = 115200 monitor_echo = yes -build_flags = -DIO_NO_HAL +build_flags = -DIO_NO_HAL [env:mega2560-I2C-wire] platform = atmelavr board = megaatmega2560 framework = arduino -lib_deps = +lib_deps = ${env.lib_deps} arduino-libraries/Ethernet SPI @@ -102,7 +102,7 @@ build_flags = -DI2C_USE_WIRE platform = atmelavr board = megaatmega2560 framework = arduino -lib_deps = +lib_deps = ${env.lib_deps} arduino-libraries/Ethernet SPI @@ -114,7 +114,7 @@ build_flags = ; -DDIAG_LOOPTIMES platform = atmelavr board = uno framework = arduino -lib_deps = +lib_deps = ${env.lib_deps} arduino-libraries/Ethernet SPI @@ -125,7 +125,7 @@ monitor_echo = yes platform = atmelmegaavr board = uno_wifi_rev2 framework = arduino -lib_deps = +lib_deps = ${env.lib_deps} arduino-libraries/Ethernet SPI @@ -137,20 +137,20 @@ build_flags = "-DF_CPU=16000000L -DARDUINO=10813 -DARDUINO_AVR_UNO_WIFI_DEV_ED - platform = atmelmegaavr board = nano_every framework = arduino -lib_deps = +lib_deps = ${env.lib_deps} arduino-libraries/Ethernet SPI monitor_speed = 115200 monitor_echo = yes upload_speed = 19200 -build_flags = +build_flags = [env:uno] platform = atmelavr board = uno framework = arduino -lib_deps = +lib_deps = ${env.lib_deps} arduino-libraries/Ethernet SPI @@ -176,6 +176,19 @@ build_flags = -std=c++17 monitor_speed = 115200 monitor_echo = yes +[env:ESP32-OTA] +platform = espressif32 +board = esp32dev +framework = arduino +lib_deps = ${env.lib_deps} +build_flags = -std=c++17 +monitor_speed = 115200 +monitor_echo = yes +upload_protocol = espota +upload_port = dccex +upload_flags = + --auth=dccex-ota + [env:Nucleo-F411RE] platform = ststm32 board = nucleo_f411re @@ -190,7 +203,7 @@ platform = ststm32 board = nucleo_f446re framework = arduino lib_deps = ${env.lib_deps} -build_flags = -std=c++17 -Os -g2 -Wunused-variable ; -DDIAG_LOOPTIMES ; -DDIAG_IO +build_flags = -std=c++17 -Os -g2 -Wunused-variable ; -DDIAG_LOOPTIMES ; -DDIAG_IO monitor_speed = 115200 monitor_echo = yes @@ -232,5 +245,5 @@ board = teensy41 framework = arduino build_flags = -std=c++17 -Os -g2 lib_deps = ${env.lib_deps} -lib_ignore = +lib_ignore =