diff --git a/Firmware/CustomHandlers.cpp b/Firmware/CustomHandlers.cpp index 8b008a6..e7f26a8 100644 --- a/Firmware/CustomHandlers.cpp +++ b/Firmware/CustomHandlers.cpp @@ -177,15 +177,7 @@ void HandleAPConfigPage() { String ssid = wifiConfig.getSSID(); String pass = wifiConfig.getPassword(); String url = wifiConfig.getURL(); - //String ntp = wifiConfig.getNTPServerName(); - char _onref[6], _offref[6], _autoOff[6]; - - snprintf(_onref, sizeof(_onref), "%d", wifiConfig.getOnRef()); - snprintf(_offref, sizeof(_offref), "%d", wifiConfig.getOffRef()); - snprintf(_autoOff, sizeof(_autoOff), "%d", wifiConfig.getAutoOff()); - String onref = String(_onref); - String offref = String(_offref); - String autooff = String(_autoOff); + String ntp = wifiConfig.getNTPServerName(); if (server.hasArg("ssid") && server.hasArg("pass")) { String _ssid = server.hasArg("_ssid") ? server.arg("_ssid") : ""; @@ -194,10 +186,7 @@ void HandleAPConfigPage() { ssid = server.arg("ssid"); pass = server.arg("pass"); url = server.hasArg("url") ? server.arg("url") : ""; - onref = server.hasArg("onref") ? server.arg("onref") : ""; - offref = server.hasArg("offref") ? server.arg("offref") : ""; - autooff = server.hasArg("autooff") ? server.arg("autooff") : ""; - //ntp = server.hasArg("ntp") ? server.arg("ntp") : ""; + ntp = server.hasArg("ntp") ? server.arg("ntp") : ""; if (ssid == "reset" && pass == "reset") { FactoryReset(true); } @@ -205,10 +194,7 @@ void HandleAPConfigPage() { wifiConfig.setSSID(ssid); wifiConfig.setPassword(pass); wifiConfig.setURL(url); - wifiConfig.setOnRef(onref.toInt()); - wifiConfig.setOffRef(offref.toInt()); - wifiConfig.setAutoOff(autooff.toInt()); - //wifiConfig.setNTPServerName(ntp); + wifiConfig.setNTPServerName(ntp); wifiConfig.save(); Serial.println("Settings saved."); if (ssid != _ssid || pass != _pass) { @@ -262,18 +248,6 @@ void HandleAPConfigPage() { // " NTP Server\n" // " \n" // " \n" - " \n" - " Auto-Off\n" - " (time in seconds when non-zero)\n" - " \n" - " \n" - " On Reference\n" - " (sense above this indicates power is on)\n" - " \n" - " \n" - " Off Reference\n" - " (sense below this indicates power is off)\n" - " \n" " \n" "  \n" " \n" diff --git a/Firmware/DNSServer.cpp b/Firmware/DNSServer.cpp new file mode 100644 index 0000000..d8b00ae --- /dev/null +++ b/Firmware/DNSServer.cpp @@ -0,0 +1,146 @@ +#include "./DNSServer.h" +#include +#include + +//#define DEBUG +#define DEBUG_OUTPUT Serial + +DNSServer::DNSServer() { + _ttl = htonl(60); + _errorReplyCode = DNSReplyCode::NonExistentDomain; +} + +bool DNSServer::start(const uint16_t &port, const String &domainName, + const IPAddress &resolvedIP) { + _port = port; + _domainName = domainName; + _resolvedIP[0] = resolvedIP[0]; + _resolvedIP[1] = resolvedIP[1]; + _resolvedIP[2] = resolvedIP[2]; + _resolvedIP[3] = resolvedIP[3]; + downcaseAndRemoveWwwPrefix(_domainName); + return _udp.begin(_port) == 1; +} + +void DNSServer::setErrorReplyCode(const DNSReplyCode &replyCode) { + _errorReplyCode = replyCode; +} + +void DNSServer::setTTL(const uint32_t &ttl) { + _ttl = htonl(ttl); +} + +void DNSServer::stop() { + _udp.stop(); +} + +void DNSServer::downcaseAndRemoveWwwPrefix(String &domainName) { + domainName.toLowerCase(); + domainName.replace("www.", ""); +} + +void DNSServer::processNextRequest() { + _currentPacketSize = _udp.parsePacket(); + if (_currentPacketSize) { + _buffer = (unsigned char*) malloc(_currentPacketSize * sizeof(char)); + if (_buffer == NULL) { + Serial.printf("ERROR in %s line %d\n", __FILE__, __LINE__); + } else { + _udp.read(_buffer, _currentPacketSize); + _dnsHeader = (DNSHeader*) _buffer; + + if (_dnsHeader->QR == DNS_QR_QUERY && + _dnsHeader->OPCode == DNS_OPCODE_QUERY && + requestIncludesOnlyOneQuestion() && + (_domainName == "*" || getDomainNameWithoutWwwPrefix() == _domainName) + ) { + replyWithIP(); + } else if (_dnsHeader->QR == DNS_QR_QUERY) { + replyWithCustomCode(); + } + } + free(_buffer); + } +} + +bool DNSServer::requestIncludesOnlyOneQuestion() { + return ntohs(_dnsHeader->QDCount) == 1 && + _dnsHeader->ANCount == 0 && + _dnsHeader->NSCount == 0 && + _dnsHeader->ARCount == 0; +} + +String DNSServer::getDomainNameWithoutWwwPrefix() { + String parsedDomainName = ""; + unsigned char *start = _buffer + 12; + if (*start == 0) { + return parsedDomainName; + } + int pos = 0; + while (true) { + unsigned char labelLength = *(start + pos); + for (int i = 0; i < labelLength; i++) { + pos++; + parsedDomainName += (char)*(start + pos); + } + pos++; + if (*(start + pos) == 0) { + downcaseAndRemoveWwwPrefix(parsedDomainName); + return parsedDomainName; + } else { + parsedDomainName += "."; + } + } +} + +void DNSServer::replyWithIP() { + _dnsHeader->QR = DNS_QR_RESPONSE; + _dnsHeader->ANCount = _dnsHeader->QDCount; + _dnsHeader->QDCount = _dnsHeader->QDCount; + //_dnsHeader->RA = 1; + + _udp.beginPacket(_udp.remoteIP(), _udp.remotePort()); + _udp.write(_buffer, _currentPacketSize); + + _udp.write((uint8_t) 192); // answer name is a pointer + _udp.write((uint8_t) 12); // pointer to offset at 0x00c + + _udp.write((uint8_t) 0); // 0x0001 answer is type A query (host address) + _udp.write((uint8_t) 1); + + _udp.write((uint8_t) 0); //0x0001 answer is class IN (internet address) + _udp.write((uint8_t) 1); + + _udp.write((unsigned char*) &_ttl, 4); + + // Length of RData is 4 bytes (because, in this case, RData is IPv4) + _udp.write((uint8_t) 0); + _udp.write((uint8_t) 4); + _udp.write(_resolvedIP, sizeof(_resolvedIP)); + _udp.endPacket(); + + + + #ifdef DEBUG + DEBUG_OUTPUT.print("DNS responds: "); + DEBUG_OUTPUT.print(_resolvedIP[0]); + DEBUG_OUTPUT.print("."); + DEBUG_OUTPUT.print(_resolvedIP[1]); + DEBUG_OUTPUT.print("."); + DEBUG_OUTPUT.print(_resolvedIP[2]); + DEBUG_OUTPUT.print("."); + DEBUG_OUTPUT.print(_resolvedIP[3]); + DEBUG_OUTPUT.print(" for "); + DEBUG_OUTPUT.println(getDomainNameWithoutWwwPrefix()); + #endif +} + +void DNSServer::replyWithCustomCode() { + _dnsHeader->QR = DNS_QR_RESPONSE; + _dnsHeader->RCode = (unsigned char) _errorReplyCode; + _dnsHeader->QDCount = 0; + + _udp.beginPacket(_udp.remoteIP(), _udp.remotePort()); + _udp.write(_buffer, sizeof(DNSHeader)); + _udp.endPacket(); +} diff --git a/Firmware/DNSServer.h b/Firmware/DNSServer.h new file mode 100644 index 0000000..691fec6 --- /dev/null +++ b/Firmware/DNSServer.h @@ -0,0 +1,68 @@ +#ifndef DNSServer_h +#define DNSServer_h +#include + +#define DNS_QR_QUERY 0 +#define DNS_QR_RESPONSE 1 +#define DNS_OPCODE_QUERY 0 + +enum class DNSReplyCode { + NoError = 0, + FormError = 1, + ServerFailure = 2, + NonExistentDomain = 3, + NotImplemented = 4, + Refused = 5, + YXDomain = 6, + YXRRSet = 7, + NXRRSet = 8 +}; + +struct DNSHeader { + uint16_t ID; // identification number + unsigned char RD : 1; // recursion desired + unsigned char TC : 1; // truncated message + unsigned char AA : 1; // authoritive answer + unsigned char OPCode : 4; // message_type + unsigned char QR : 1; // query/response flag + unsigned char RCode : 4; // response code + unsigned char Z : 3; // its z! reserved + unsigned char RA : 1; // recursion available + uint16_t QDCount; // number of question entries + uint16_t ANCount; // number of answer entries + uint16_t NSCount; // number of authority entries + uint16_t ARCount; // number of resource entries +}; + +class DNSServer { +public: + DNSServer(); + void processNextRequest(); + void setErrorReplyCode(const DNSReplyCode &replyCode); + void setTTL(const uint32_t &ttl); + + // Returns true if successful, false if there are no sockets available + bool start(const uint16_t &port, + const String &domainName, + const IPAddress &resolvedIP); + // stops the DNS server + void stop(); + +private: + WiFiUDP _udp; + uint16_t _port; + String _domainName; + unsigned char _resolvedIP[4]; + int _currentPacketSize; + unsigned char* _buffer; + DNSHeader* _dnsHeader; + uint32_t _ttl; + DNSReplyCode _errorReplyCode; + + void downcaseAndRemoveWwwPrefix(String &domainName); + String getDomainNameWithoutWwwPrefix(); + bool requestIncludesOnlyOneQuestion(); + void replyWithIP(); + void replyWithCustomCode(); +}; +#endif // DNSServer_h diff --git a/Firmware/Firmware.ses b/Firmware/Firmware.ses new file mode 100644 index 0000000..c4dfcc2 --- /dev/null +++ b/Firmware/Firmware.ses @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Firmware/GrowController.ses b/Firmware/GrowController.ses deleted file mode 100644 index 3258f31..0000000 --- a/Firmware/GrowController.ses +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Firmware/PlantModel.cpp b/Firmware/PlantModel.cpp index 02dc719..316acf8 100644 --- a/Firmware/PlantModel.cpp +++ b/Firmware/PlantModel.cpp @@ -161,7 +161,7 @@ void simulation() { // Simulate Ambient temp rising and falling if (lastMinutesToday != minutesToday) { lastMinutesToday = minutesToday; - Serial.printf("%02u:%02u, Ambient %3.1f\n", hoursToday, minutesToday % 60, plant.AmbientTemp_C); + //Serial.printf("%02u:%02u, Ambient %3.1f\n", hoursToday, minutesToday % 60, plant.AmbientTemp_C); if (hoursToday < 15) { // warming part of the day diff --git a/Firmware/Utility.cpp b/Firmware/Utility.cpp index 622c469..8973501 100644 --- a/Firmware/Utility.cpp +++ b/Firmware/Utility.cpp @@ -7,23 +7,51 @@ #include "Utility.h" -static String macToStr(const uint8_t * mac); +static String macToStr(const uint8_t * mac, char padd = ':'); -String GetMacString() { +String GetMacString(char padd) { unsigned char mac[6]; WiFi.macAddress(mac); - String clientMac(macToStr(mac)); + String clientMac(macToStr(mac, padd)); return clientMac; } -String macToStr(const uint8_t * mac) { +static String macToStr(const uint8_t * mac, char padd) { String result; for (int i = 0; i < 6; ++i) { result += String(mac[i], 16); - if (i < 5) - result += ':'; + if (i < 5) { + if (padd) + result += padd; + } } return result; } +void HexDump(const char * title, const uint8_t * p, int count) +{ + int i; + char buf[100] = "0000: "; + char asc[17] = " "; + + if (*title) { + printf("%s [@%08X]\n", title, (uint32_t)p); + } + for (i=0; i // Returns the MAC Address as a string object -String GetMacString(); +String GetMacString(char padd = ':'); + +// Dump a block of memory as a hex title-named listing +// +void HexDump(const char * title, const uint8_t * p, int count); + + +// A macro to generate a build error on the condition +// +// Example: +// BUILD_BUG_ON(sizeof(something) > limit); +// +#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)])) + +// And the more positive direction +// +// Example: +// COMPILER_ASSERT(sizeof(something) <= limit); +// +#define COMPILER_ASSERT(condition) ((void)sizeof(char[-!(condition)])) + +#endif // UTILITY_H diff --git a/Firmware/WiFiConfiguration.h b/Firmware/WiFiConfiguration.h index 314ea26..546a1fa 100644 --- a/Firmware/WiFiConfiguration.h +++ b/Firmware/WiFiConfiguration.h @@ -9,16 +9,20 @@ #define CFG_NAMESIZE 32 #define CFG_SSIDSIZE 32 #define CFG_PASSSIZE 64 -#define CFG_UURLSIZE 64 +#define CFG_UPDURLSIZE 64 +#define CFG_NTPSSIZE 64 -/// Provides a handy interface for WiFi configuration. +/// Provides a handy interface for WiFi configuration and user NV data. +/// +/// Because the WiFi needs to have its configuration managed through +/// non-volatile memory. /// /// @code /// WiFiConfiguration config; /// ... /// config.load(); -/// ssid = config.getSSID(); -/// pass = config.getPassword(); +/// String ssid = config.getSSID(); +/// String pass = config.getPassword(); /// ... /// WiFi.begin(ssid.c_str(), pass.c_str()); /// @@ -26,29 +30,174 @@ /// class ConfigManager { public: - ConfigManager(); - void load(); - void save(); - void factoryReset(); - String getName(); - void setName(String _name); - String getSSID(); - void setSSID(String _ssid); - String getPassword(); - void setPassword(String _password); - String getURL(); - void setURL(String _url); - uint16_t getOnRef(); - void setOnRef(uint16 onR); - uint16_t getOffRef(); - void setOffRef(uint16 offR); - uint16_t getAutoOff(); - void setAutoOff(uint16 autoOff); - #if 0 - String getNTPServerName(); - void setNTPServerName(String _name); - #endif + + /// Data structure that is used for 'factory reset' of this node, + /// where all setup data is erased. This reset state can include + /// specific settings, such as the device name (as it will appear + /// on the network, and the default software update server, and so on. + typedef struct { + const char * name; ///< the device name + const char * UPDURL; ///< the URL of a SW update server + const char * NTPURL; ///< The URL of an NTP server + } ConfigDefaults_t; + + /// load checks the version of the image for validity. + /// + typedef enum { + MATCHING, ///< The current version matches the expected version + IS_OLDER, ///< [Newer firmware] detected an older configuration + IS_NEWER, ///< detected a configuration that is newer than this app knows. + IS_BROKEN, ///< format check failed, this image is bad. + } FirmwareCheck_t; + + /// Instantiate the WiFi Configuration Manager, which also manages + /// user non-volatile storage. + /// + /// This creates a RAM cache (typically 512B), where information is + /// held. This is then saved to non-volatile (save), or overwritten + /// from non-volatile (load). + /// + /// Instantiation does not automatically load from non-volatile. + /// + /// @param[in] defaults is an optional pointer to the default information. + /// + ConfigManager(const ConfigDefaults_t * defaults = NULL); + + /// Destructor, which is usually not used in an embedded system. + /// + ~ConfigManager(); + + /// loads the information from non-volatile storage into RAM + /// + /// @returns status of the firmware check. @see FirmwareCheck_t + /// + FirmwareCheck_t load(); + + /// get the current firmware version + /// + /// specific software may be able to upgrade (or even downgrade) the + /// non-volatile data storage format. + /// + /// @returns the format version number (only useful if load is not broken. + /// + uint8_t getFormatVersion(); + + + /// saves the information to non-volatile. + /// + void save(); + + /// Resets the RAM information to factory defaults, completely wiping + /// all data, so it cannot be extracted. + /// + /// To complete the wipe, be sure to issue to the save command. + /// + void factoryReset(); + + /// get the name of this device, as it will appear on the network. + /// + /// @returns string of the name. + /// + String getName(); + + /// set the name of this device, to a maximum length of CFG_NAMESIZE. + /// + /// @param[in] _name is the name to assign it. + /// + void setName(String _name); + + /// get the ssid that this node is assigned to. + /// + /// @returns the SSID, or a pointer to NULL if none set. + /// + String getSSID(); + + /// set the ssid that this node is assigned to. + /// + /// @param[in] _ssid to assign this device to, to a maximum length of CFG_SSIDSIZE + /// + void setSSID(String _ssid); + + /// get the passcode that this node will use with the joined ssid. + /// + /// @returns the passcode. + /// + String getPassword(); + + /// set the passcode that this node uses. + /// + /// @param[in] passcode to assign this device to, to a maximum length of CFG_PASSSIZE + /// + void setPassword(String _password); + + /// get the URL that this node will use for software updates + /// + /// @returns the url. + /// + String getURL(); + + /// set the URL that this node will use for software updates + /// + /// @param[in] _url to assign this device to, to a maximum length of CFG_UPDURLSIZE + /// + void setURL(String _url); + + /// get the URL of the NTP server that this node will use for setting the clock + /// + /// @returns the url. + /// + String getNTPServerName(); + + /// set the URL of the NTP server that this node will use for software updates + /// + /// @param[in] _url to assign this device to, to a maximum length of CFG_NTPSSIZE + /// + void setNTPServerName(String _url); + + /// get a pointer to the portion of the data that will be saved to non-volatile + /// + /// This points to the block of memory that is for user settings. The user code + /// will typically create a structure, and overlay it on this location. + /// + /// The size is fixed at compile time, but may be queried with getUserDataSize() + /// to ensure that there is no buffer overrun. + /// + /// @returns the pointer to the memory for the user to use. + /// + uint8_t * getUserDataHandle(); + + /// get the size of the user data block that can be saved to non-volatile. + /// + /// @returns the size (in bytes) of the user space. + /// + int getUserDataSize(); + private: + + #define EEROM_SIZE 512 + + // Change this when it is required to force a reinitialization + // + #define EXPECTED_FMT 0x04 + + #define SYSTEMSIZE (2 + CFG_NAMESIZE + CFG_SSIDSIZE + CFG_PASSSIZE + CFG_UPDURLSIZE + CFG_NTPSSIZE) + #define USERSIZE (EEROM_SIZE - SYSTEMSIZE) + + typedef struct { + uint8_t format[2]; // Format of this data structure, and ~format check + struct info { + char name[CFG_NAMESIZE]; // Network Discoverable Name of this node + char ssid[CFG_SSIDSIZE]; // SSID of the saved network [max length defined by standard] + char pass[CFG_PASSSIZE]; // PASScode of the saved network + char UPDURL[CFG_UPDURLSIZE]; // URL of the trusted server with code updates + char NTPURL[CFG_NTPSSIZE]; // Name or IP of the NTP Server + } info; + uint8_t userData[USERSIZE]; // User data here and to the EEROM_SIZE end. + } NVConfig_04_t; // This layout matches EXPECTED_FMT == 04 + + NVConfig_04_t Configuration; // the instantiation of the Configuration + + const ConfigDefaults_t * defaults; }; #endif // !WIFICONFIGURATION_H diff --git a/Firmware/WifiConfiguration.cpp b/Firmware/WifiConfiguration.cpp index 384824c..0cde2fa 100644 --- a/Firmware/WifiConfiguration.cpp +++ b/Firmware/WifiConfiguration.cpp @@ -1,156 +1,162 @@ // // This file hosts all the non-volatile configuration options for this node // -#include "WiFiConfiguration.h" #include -#define EEROM_SIZE 512 +#include "WiFiConfiguration.h" +#include "Utility.h" -// Change this when it is required to force a reinitialization -// -#define EXPECTED_FMT 0x03 - -typedef struct { - uint8_t format[2]; // Format of this data structure, and ~format - struct info { - char name[CFG_NAMESIZE]; // Network Discoverable Name of this node - char ssid[CFG_SSIDSIZE]; // SSID of the saved network [max length defined by standard] - char pass[CFG_PASSSIZE]; // PASScode of the saved network - char updateURL[CFG_UURLSIZE]; // URL of the trusted server with code updates - uint16_t onRef; // A/D reference above which the output is considered 'On' - uint16_t offRef; // A/D reference below which the output is considered 'Off' - uint16_t autoOff; // When non-zero, this is the # minutes until auto-turn off - //char NTPIP[64]; // Name or IP of the NTP Server - char Padding[10]; - } info; -} Config_t; -#define OFS_FORMAT (0) -#define OFS_NAME (OFS_FORMAT + 2) -#define OFS_SSID (OFS_NAME + CFG_NAMESIZE) -#define OFS_PASS (OFS_SSID + CFG_SSIDSIZE) -#define OFS_URL (OFS_PASS + CFG_PASSSIZE) -#define OFS_ONREF (OFS_URL + CFG_UURLSIZE) -#define OFS_OFFREF (OFS_ONREF + sizeof(uint16_t)) -#define OFS_AUTOOFF (OFS_OFFREF + sizeof(uint16_t)) -//#define OFS_NTPIP (OFS_OFFREF + 2) - -Config_t Configuration; - -ConfigManager::ConfigManager() { +ConfigManager::ConfigManager(const ConfigDefaults_t * _defaults) { + (void)_defaults; +// defaults = _defaults; + COMPILER_ASSERT(sizeof(NVConfig_04_t) <= EEROM_SIZE); + EEPROM.begin(EEROM_SIZE); // Set for the max expected size + // Here we could perform a 'load()' followed by a format check, + // and it could then do a graceful update from one version to another, + // and then commit it back to the rest of the program doesn't notice. + int ret = load(); + switch (ret) { + case MATCHING: + // life is good, continue. + break; + case IS_OLDER: + //if (getFormatVersion() == 3) { + // Upgrade(); + // save(); + //} else { + // factoryReset(); + // save(); + //} + break; + case IS_NEWER: + // can't politely downgrade, so factory reset it. + case IS_BROKEN: + default: +// factoryReset(); // Can't fix it, so factory reset it. +// save(); + break; + } } +// Quite likely that this never runs... +ConfigManager::~ConfigManager() { + EEPROM.end(); +} + + +uint8_t ConfigManager::getFormatVersion() { + return Configuration.format[0]; +} + +uint8_t * ConfigManager::getUserDataHandle() { + return Configuration.userData; +} + +int ConfigManager::getUserDataSize() { + return USERSIZE; +} + + void ConfigManager::factoryReset() { - Configuration.format[0] = EXPECTED_FMT; - Configuration.format[1] = ~EXPECTED_FMT; - strcpy(Configuration.info.name, "3-Way Switch"); - Configuration.info.ssid[0] = '\0'; - Configuration.info.pass[0] = '\0'; - //Configuration.info.updateURL[0] = '\0'; - strcpy(Configuration.info.updateURL, "https://192.168.1.201/mbed/ESP.php"); - Configuration.info.onRef = 150; - Configuration.info.offRef = 100; - Configuration.info.autoOff = 0; - //Configuration.info.NTPIP[0] = '\0'; + memset(&Configuration, 0, sizeof(NVConfig_04_t)); // Wipe them to be more secure + Configuration.format[0] = EXPECTED_FMT; // put back the minimal + Configuration.format[1] = ~EXPECTED_FMT; + if (defaults) { + strcpy(Configuration.info.name, defaults->name); + strcpy(Configuration.info.UPDURL, defaults->UPDURL); + strcpy(Configuration.info.NTPURL, defaults->NTPURL); + } + HexDump("factoryReset", (uint8_t *)&Configuration, sizeof(Configuration)); } -void ConfigManager::load() { - EEPROM.begin(512); - uint8_t * ptr = (uint8_t *) &Configuration; - uint8_t i = 0; - do { - *ptr++ = EEPROM.read(OFS_FORMAT + i++); - } while (i < sizeof(Configuration)); - if ((Configuration.format[0] & 0xFF) != (~Configuration.format[1] & 0xFF)) { - // Factory default - Serial.printf("Bad Configuration - reset to factory defaults\n"); - factoryReset(); - return; - } - Serial.printf("Loading from EEROM\n"); - Serial.printf("Node Name: %s\n", Configuration.info.name); - Serial.printf("SSID: %s\n", Configuration.info.ssid); - Serial.printf("PASS: %s\n", Configuration.info.pass); - Serial.printf("URL : %s\n", Configuration.info.updateURL); - Serial.printf("On Ref: %d\n", Configuration.info.onRef); - Serial.printf("Off Ref: %d\n", Configuration.info.offRef); - Serial.printf("Auto Off: %d\n", Configuration.info.autoOff); - //Serial.printf("NTP Svr: %s\n", Configuration.info.NTPIP); - delay(500); + +ConfigManager::FirmwareCheck_t ConfigManager::load() { + uint8_t * ptr = (uint8_t *)&Configuration; + size_t i = 0; + do { + *ptr++ = EEPROM.read(i++); + } while (i < sizeof(Configuration)); +// if ((Configuration.format[0] & 0xFF) != (~Configuration.format[1] & 0xFF)) { +// // Factory default +// Serial.printf("Bad Configuration\n"); +// return IS_BROKEN; // Fatal and restored to factory default. +// } else if (Configuration.format[0] < EXPECTED_FMT) { +// Serial.printf("Old Configuration. It needs an update!\n"); +// return IS_OLDER; +// } else if (Configuration.format[0] > EXPECTED_FMT) { +// Serial.printf("Too new a configuration.\n"); +// return IS_NEWER; +// } + Serial.printf("Loading from EEROM\n"); + Serial.printf("Node Name: %s\n", Configuration.info.name); + Serial.printf("SSID: %s\n", Configuration.info.ssid); + Serial.printf("PASS: %s\n", Configuration.info.pass); + Serial.printf("URL : %s\n", Configuration.info.UPDURL); + Serial.printf("NTP : %s\n", Configuration.info.NTPURL); + HexDump("After Load", (uint8_t *)&Configuration, sizeof(Configuration)); +// //delay(500); + return MATCHING; // no error } + void ConfigManager::save(void) { - EEPROM.begin(512); - uint8_t * ptr = (uint8_t *) &Configuration; - uint8_t i = 0; - do { - EEPROM.write(OFS_FORMAT + i++, *ptr++); - } while (i < sizeof(Configuration)); - EEPROM.commit(); - delay(500); + uint8_t * ptr = (uint8_t *)&Configuration; + size_t i = 0; + do { + EEPROM.write(i++, *ptr++); + } while (i < sizeof(Configuration)); + if (EEPROM.commit()) { + Serial.printf("EEPROM.commit() success.\n"); + } else { + Serial.printf("EEPROM.commit() FAILED !!!!!!!! FAILED !!!!!!!! FAILED !!!!!!!!\n"); + } + HexDump("After Save", (uint8_t *)&Configuration, sizeof(Configuration)); + //delay(500); } -#if 0 + String ConfigManager::getNTPServerName() { - return String(Configuration.info.NTPIP); + return String(Configuration.info.NTPURL); } void ConfigManager::setNTPServerName(String _name) { - strncpy(Configuration.info.NTPIP, _name.c_str(), sizeof(Configuration.info.NTPIP)); - Serial.printf("setNTPServerName(%s)\n", Configuration.info.NTPIP); + strncpy(Configuration.info.NTPURL, _name.c_str(), sizeof(Configuration.info.NTPURL)); + Serial.printf("setNTPServerName(%s)\n", Configuration.info.NTPURL); } -#endif String ConfigManager::getName() { - return String(Configuration.info.name); + return String(Configuration.info.name); } void ConfigManager::setName(String _name) { - strncpy(Configuration.info.name, _name.c_str(), sizeof(Configuration.info.name)); - Serial.printf("setName(%s)\n", Configuration.info.name); + strncpy(Configuration.info.name, _name.c_str(), sizeof(Configuration.info.name)); + Serial.printf("setName(%s)\n", Configuration.info.name); } String ConfigManager::getSSID() { - return String(Configuration.info.ssid); + return String(Configuration.info.ssid); } void ConfigManager::setSSID(String _ssid) { - strncpy(Configuration.info.ssid, _ssid.c_str(), sizeof(Configuration.info.ssid)); - Serial.printf("setSSID(%s)\n", Configuration.info.ssid); + strncpy(Configuration.info.ssid, _ssid.c_str(), sizeof(Configuration.info.ssid)); + Serial.printf("setSSID(%s)\n", Configuration.info.ssid); } String ConfigManager::getPassword() { - return String(Configuration.info.pass); + return String(Configuration.info.pass); } void ConfigManager::setPassword(String _password) { - strncpy(Configuration.info.pass, _password.c_str(), sizeof(Configuration.info.pass)); - Serial.printf("setPass(%s)\n", Configuration.info.pass); + strncpy(Configuration.info.pass, _password.c_str(), sizeof(Configuration.info.pass)); + Serial.printf("setPass(%s)\n", Configuration.info.pass); } String ConfigManager::getURL() { - return String(Configuration.info.updateURL); + return String(Configuration.info.UPDURL); } void ConfigManager::setURL(String _url) { - strncpy(Configuration.info.updateURL, _url.c_str(), sizeof(Configuration.info.updateURL)); - Serial.printf("setURL (%s)\n", Configuration.info.updateURL); + strncpy(Configuration.info.UPDURL, _url.c_str(), sizeof(Configuration.info.UPDURL)); + Serial.printf("setURL (%s)\n", Configuration.info.UPDURL); } -uint16_t ConfigManager::getOnRef() { - return Configuration.info.onRef; -} -void ConfigManager::setOnRef(uint16 onR) { - Configuration.info.onRef = onR; -} -uint16_t ConfigManager::getOffRef() { - return Configuration.info.offRef; -} -void ConfigManager::setOffRef(uint16 offR) { - Configuration.info.offRef = offR; -} -uint16_t ConfigManager::getAutoOff() { - return Configuration.info.autoOff; -} -void ConfigManager::setAutoOff(uint16 autoOff) { - Configuration.info.autoOff = autoOff; -}