From 5d0c3ae74410684a732d9648cbe033a16f7141dd Mon Sep 17 00:00:00 2001 From: Khoi Hoang <57012152+khoih-prog@users.noreply.github.com> Date: Tue, 23 Feb 2021 18:52:54 -0500 Subject: [PATCH] Major Releases v1.2.0 ### Major Releases v1.2.0 1. Configurable **Customs HTML Headers**, including Customs Style, Customs Head Elements, CORS Header. 2. Add functions to control Config Portal from software or Virtual Switches. Check [How to trigger a Config Portal from code #25](https://github.com/khoih-prog/Blynk_WM/issues/25) 3. Use more efficient [**FlashStorage_STM32 v1.0.1**](https://github.com/khoih-prog/FlashStorage_STM32) 4. Fix Config Portal Bug. 5. Update examples 6. Bump up to version v1.2.0 to sync with [**Ethernet_Manager**](https://github.com/khoih-prog/Ethernet_Manager) --- CONTRIBUTING.md | 2 +- README.md | 200 ++++-- keywords.txt | 22 + library.json | 16 +- library.properties | 4 +- platformio/platformio.ini | 26 +- src/Ethernet_Manager_STM32.h | 5 +- src/Ethernet_Manager_STM32_Debug.h | 70 +- src/Ethernet_Manager_STM32_Impl.h | 1041 ++++++++++++++++++++-------- 9 files changed, 1009 insertions(+), 377 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3dc4bec..55f498d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -29,7 +29,7 @@ Please ensure to specify the following: Arduino IDE version: 1.8.13 Arduino STM32 core v1.9.0 OS: Ubuntu 20.04 LTS -Linux xy-Inspiron-3593 5.4.0-51-generic #56-Ubuntu SMP Mon Oct 5 14:28:49 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux +Linux xy-Inspiron-3593 5.4.0-65-generic #73-Ubuntu SMP Mon Jan 18 17:25:17 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux Context: The board couldn't autoreconnect to Local Blynk Server after router power recycling. diff --git a/README.md b/README.md index 23a67cc..9247515 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ * [Currently supported Boards](#currently-supported-boards) * [Currently supported Ethernet shields/modules](#currently-supported-ethernet-shieldsmodules) * [Changelog](#changelog) + * [Major Releases v1.2.0](#major-releases-v120) * [Releases v1.0.1](#releases-v101) * [Releases v1.0.0](#releases-v100) * [Prerequisites](#prerequisites) @@ -39,7 +40,14 @@ * [3. How to increase W5x00 TX/RX buffer](#3-how-to-increase-w5x00-txrx-buffer) * [Not supported Libraries](#not-supported-libraries) * [How to use default Credentials and have them pre-loaded onto Config Portal](#how-to-use-default-credentials-and-have-them-pre-loaded-onto-config-portal) -* [How to add dynamic parameters from sketch](#how-to-add-dynamic-parameters-from-sketch) +* [How to use](#how-to-use) + * [1. Basic usage](#1-basic-usage) + * [2. Add custom parameters](#2-add-custom-parameters) + * [3. Not using custom parameters](#3-not-using-custom-parameters) + * [4. To open Config Portal](#4-to-open-config-portal) + * [5. To use custom HTML Style](#5-to-use-custom-html-style) + * [6. To use custom Head Elements](#6-to-use-custom-head-elements) + * [7. To use CORS Header](#7-to-use-cors-header) * [Important Notes for using Dynamic Parameters' ids](#important-notes-for-using-dynamic-parameters-ids) * [Examples](#examples) * [ 1. AM2315_Ethernet_STM32](examples/AM2315_Ethernet_STM32) @@ -139,6 +147,15 @@ New recent features: ## Changelog +### Major Releases v1.2.0 + +1. Configurable **Customs HTML Headers**, including Customs Style, Customs Head Elements, CORS Header. +2. Add functions to control Config Portal from software or Virtual Switches. Check [How to trigger a Config Portal from code #25](https://github.com/khoih-prog/Blynk_WM/issues/25) +3. Use more efficient [**FlashStorage_STM32 v1.0.1**](https://github.com/khoih-prog/FlashStorage_STM32) +4. Fix Config Portal Bug. +5. Update examples +6. Bump up to version v1.2.0 to sync with [**Ethernet_Manager**](https://github.com/khoih-prog/Ethernet_Manager) + ### Releases v1.0.1 1. Clean-up all compiler warnings possible. @@ -150,27 +167,28 @@ New recent features: 2. Provide support to W5x00, ENC28J60 and built-in LAN8742A Ethernet. 3. Supporting Ethernet, EthernetLarge, Ethernet2, Ethernet3, EthernetENC, UIPEthernet and STM32Ethernet Libraries - --- --- ## Prerequisites 1. [`Arduino IDE 1.8.13+` for Arduino](https://www.arduino.cc/en/Main/Software) - 2. [`Arduino Core for STM32 1.9.0+`](https://github.com/stm32duino/Arduino_Core_STM32) for STM32 (Use Arduino Board Manager) - 3. [`Functional-VLPP library v1.0.1+`](https://github.com/khoih-prog/functional-vlpp) to use server's lambda function. To install. check [![arduino-library-badge](https://www.ardu-badge.com/badge/Functional-Vlpp.svg?)](https://www.ardu-badge.com/Functional-Vlpp) - 4. [`DoubleResetDetector_Generic library v1.0.3+`](https://github.com/khoih-prog/DoubleResetDetector_Generic). To install. check [![arduino-library-badge](https://www.ardu-badge.com/badge/DoubleResetDetector_Generic.svg?)](https://www.ardu-badge.com/DoubleResetDetector_Generic). - 5. Depending on which Ethernet card you're using: - - [`STM32Ethernet library v1.2.0+`](https://github.com/stm32duino/STM32Ethernet) for built-in LAN8742A Ethernet on (Nucleo-144, Discovery) - - [`Ethernet library v2.0.0+`](https://www.arduino.cc/en/Reference/Ethernet) for W5100, W5200 and W5500. + 2. [`Arduino Core for STM32 v1.9.0+`](https://github.com/stm32duino/Arduino_Core_STM32) for STM32 boards. [![GitHub release](https://img.shields.io/github/release/stm32duino/Arduino_Core_STM32.svg)](https://github.com/stm32duino/Arduino_Core_STM32/releases/latest) + 3. [`EthernetWebServer_STM32 library v1.1.1+`](https://github.com/khoih-prog/EthernetWebServer_STM32). To install. check [![arduino-library-badge](https://www.ardu-badge.com/badge/EthernetWebServer_STM32.svg?)](https://www.ardu-badge.com/EthernetWebServer_STM32) + 4. [`Functional-VLPP library v1.0.2+`](https://github.com/khoih-prog/functional-vlpp) to use server's lambda function. To install. check [![arduino-library-badge](https://www.ardu-badge.com/badge/Functional-Vlpp.svg?)](https://www.ardu-badge.com/Functional-Vlpp) + 5. [`DoubleResetDetector_Generic library v1.0.3+`](https://github.com/khoih-prog/DoubleResetDetector_Generic). To install. check [![arduino-library-badge](https://www.ardu-badge.com/badge/DoubleResetDetector_Generic.svg?)](https://www.ardu-badge.com/DoubleResetDetector_Generic). + 6. For built-in LAN8742A Ethernet: + - [`STM32Ethernet library v1.2.0+`](https://github.com/stm32duino/STM32Ethernet) for built-in LAN8742A Ethernet on (Nucleo-144, Discovery). [![GitHub release](https://img.shields.io/github/release/stm32duino/STM32Ethernet.svg)](https://github.com/stm32duino/STM32Ethernet/releases/latest) + - [`LwIP library v2.1.2+`](https://github.com/stm32duino/LwIP) for built-in LAN8742A Ethernet on (Nucleo-144, Discovery). [![GitHub release](https://img.shields.io/github/release/stm32duino/LwIP.svg)](https://github.com/stm32duino/LwIP/releases/latest) + 7. For W5x00 Ethernet: + - [`Ethernet library v2.0.0+`](https://github.com/arduino-libraries/Ethernet) for W5100, W5200 and W5500. [![GitHub release](https://img.shields.io/github/release/arduino-libraries/Ethernet.svg)](https://github.com/arduino-libraries/Ethernet/releases/latest) - [`EthernetLarge library v2.0.0+`](https://github.com/OPEnSLab-OSU/EthernetLarge) for W5100, W5200 and W5500. - - [`Ethernet2 library v1.0.4+`](https://github.com/adafruit/Ethernet2) for W5500. - - [`Ethernet3 library v1.5.3+`](https://github.com/sstaub/Ethernet3) for W5500/WIZ550io/WIZ850io/USR-ES1 with Wiznet W5500 chip. - - [`EthernetENC library v2.0.0+`](https://github.com/jandrassy/EthernetENC) for ENC28J60. **New and Better** - - [`UIPEthernet library v2.0.9+`](https://github.com/UIPEthernet/UIPEthernet) for ENC28J60. - 6. [`LwIP library v2.1.2+`](https://github.com/stm32duino/LwIP) for built-in LAN8742A Ethernet on (Nucleo-144, Discovery) - - + - [`Ethernet2 library v1.0.4+`](https://github.com/khoih-prog/Ethernet2) for W5500. [![GitHub release](https://img.shields.io/github/release/adafruit/Ethernet2.svg)](https://github.com/adafruit/Ethernet2/releases/latest) + - [`Ethernet3 library v1.5.3+`](https://github.com/sstaub/Ethernet3) for W5500/WIZ550io/WIZ850io/USR-ES1 with Wiznet W5500 chip. [![GitHub release](https://img.shields.io/github/release/sstaub/Ethernet3.svg)](https://github.com/sstaub/Ethernet3/releases/latest) + 8. For ENC28J60 Ethernet: + - [`EthernetENC library v2.0.0+`](https://github.com/jandrassy/EthernetENC) for ENC28J60. [![GitHub release](https://img.shields.io/github/release/jandrassy/EthernetENC.svg)](https://github.com/jandrassy/EthernetENC/releases/latest). **New and Better** + - [`UIPEthernet library v2.0.9+`](https://github.com/UIPEthernet/UIPEthernet) for ENC28J60. [![GitHub release](https://img.shields.io/github/release/UIPEthernet/UIPEthernet.svg)](https://github.com/UIPEthernet/UIPEthernet/releases/latest) + --- ### Installation @@ -454,17 +472,35 @@ Ethernet_Configuration defaultConfig; ``` --- +--- + +### How to use -### How to add dynamic parameters from sketch +#### 1. Basic usage -- To add custom parameters, just modify from the example below +- Include in your sketch + +```cpp +// Must be before #include +#include + +Ethernet_Manager ethernet_manager; +``` + +#### 2. Add custom parameters + +- To add custom parameters, just add ``` -#define USE_DYNAMIC_PARAMETERS true +#ifndef dynamicParams_h +#define dynamicParams_h + +#include "defines.h" + +// USE_DYNAMIC_PARAMETERS defined in defined.h /////////////// Start dynamic Credentials /////////////// -//Defined in BlynkEthernet_WM.h, , /************************************** #define MAX_ID_LEN 5 #define MAX_DISPLAY_NAME_LEN 16 @@ -519,13 +555,51 @@ Ethernet_Configuration defaultConfig; /////// // End dynamic Credentials /////////// +#endif //dynamicParams_h + ``` + +#### 3. Not using custom parameters + - If you don't need to add dynamic parameters, use the following in sketch ``` -#define USE_DYNAMIC_PARAMETERS false +#define USE_DYNAMIC_PARAMETERS false +``` + +#### 4. To open Config Portal + +- When you want to open a config portal, just add + +```cpp +ethernet_manager.begin(); +``` + +#### 5. To use custom HTML Style + +``` +const char NewCustomsStyle[] /*PROGMEM*/ = ""; + +... + +ethernet_manager.setCustomsStyle(NewCustomsStyle); +``` + +#### 6. To use custom Head Elements + + +``` +ethernet_manager.setCustomsHeadElement(""); +``` + +#### 7. To use CORS Header + +``` +ethernet_manager.setCORSHeader("Your Access-Control-Allow-Origin"); ``` +--- --- ### Important Notes for using Dynamic Parameters' ids @@ -550,6 +624,7 @@ Please be noted that the following **reserved names are already used in library* 4. [MQTT_ThingStream_Ethernet_STM32](examples/MQTT_ThingStream_Ethernet_STM32) --- +--- ## So, how it works? @@ -763,6 +838,11 @@ void check_status() } } +#if USING_CUSTOMS_STYLE +const char NewCustomsStyle[] /*PROGMEM*/ = ""; +#endif + void setup() { // Debug console @@ -864,8 +944,24 @@ void setup() #endif ET_LOGWARN(F("=========================")); + ////////////////////////////////////////////// + +#if USING_CUSTOMS_STYLE + ethernet_manager.setCustomsStyle(NewCustomsStyle); +#endif + +#if USING_CUSTOMS_HEAD_ELEMENT + ethernet_manager.setCustomsHeadElement(""); +#endif + +#if USING_CORS_FEATURE + ethernet_manager.setCORSHeader("Your Access-Control-Allow-Origin"); +#endif + ethernet_manager.begin(); + ////////////////////////////////////////////// + localEthernetIP = Ethernet.localIP(); #if (USE_ETHERNET2 || USE_ETHERNET3) @@ -900,7 +996,7 @@ void displayCredentials() { Serial.println(F("\nYour stored Credentials :")); - for (int i = 0; i < NUM_MENU_ITEMS; i++) + for (uint16_t i = 0; i < NUM_MENU_ITEMS; i++) { Serial.print(myMenuItems[i].displayName); Serial.print(F(" = ")); @@ -914,7 +1010,7 @@ void displayCredentialsOnce() if (!displayedCredentials) { - for (int i = 0; i < NUM_MENU_ITEMS; i++) + for (uint16_t i = 0; i < NUM_MENU_ITEMS; i++) { if (!strlen(myMenuItems[i].pdata)) { @@ -943,6 +1039,10 @@ void loop() if (!inConfigMode) { +#if (USE_DYNAMIC_PARAMETERS) + displayCredentialsOnce(); +#endif + if (!client) { client = new PubSubClient(MQTT_SERVER, atoi(MQTT_PORT), mqtt_receive_callback, ethClient); @@ -979,10 +1079,6 @@ void loop() client->loop(); check_status(); - - #if (USE_DYNAMIC_PARAMETERS) - displayCredentialsOnce(); - #endif } } ``` @@ -1088,6 +1184,20 @@ void loop() #define EEPROM_START 0 +///////////////////////////////////////////// + +// Add customs headers from v1.2.0 +#define USING_CUSTOMS_STYLE true +#define USING_CUSTOMS_HEAD_ELEMENT true +#define USING_CORS_FEATURE true + +///////////////////////////////////////////// + +// Config Timeout 120s (default 60s) +#define CONFIG_TIMEOUT 120000L + +#define USE_DYNAMIC_PARAMETERS true + ////////////////////////////////////////// #include @@ -1128,7 +1238,7 @@ typedef struct Configuration #if TO_LOAD_DEFAULT_CONFIG_DATA -bool LOAD_DEFAULT_CONFIG_DATA = true; +bool LOAD_DEFAULT_CONFIG_DATA = false; Ethernet_Configuration defaultConfig = { @@ -1172,11 +1282,11 @@ Ethernet_Configuration defaultConfig; #include "defines.h" -#define USE_DYNAMIC_PARAMETERS true +// USE_DYNAMIC_PARAMETERS defined in defined.h /////////////// Start dynamic Credentials /////////////// -//Defined in BlynkEthernet_WM.h, , +//Defined in /************************************** #define MAX_ID_LEN 5 #define MAX_DISPLAY_NAME_LEN 16 @@ -1244,7 +1354,7 @@ This is the terminal output of an STM32F7 Nucleo-144 NUCLEO_F767ZI board with LA ``` Start Ethernet_STM32 on NUCLEO_F767ZI Ethernet Shield type : LAN8742A Ethernet & STM32Ethernet Library -Ethernet_Manager_STM32 v1.0.1 +Ethernet_Manager_STM32 v1.2.0 DoubleResetDetector_Generic v1.0.3 [ETM] ======= Start Default Config Data ======= [ETM] Header= , BoardName= @@ -1277,7 +1387,7 @@ H ```cpp Start Ethernet_STM32 on NUCLEO_F767ZI Ethernet Shield type : LAN8742A Ethernet & STM32Ethernet Library -Ethernet_Manager_STM32 v1.0.1 +Ethernet_Manager_STM32 v1.2.0 DoubleResetDetector_Generic v1.0.3 [ETM] ======= Start Default Config Data ======= [ETM] Header= , BoardName= @@ -1314,7 +1424,7 @@ This is the terminal output of STM32F7 Nucleo-144 NUCLEO_F767ZI board with W5500 ``` Start Ethernet_STM32 on NUCLEO_F767ZI Ethernet Shield type : W5x00 using Ethernet Library -Ethernet_Manager_STM32 v1.0.1 +Ethernet_Manager_STM32 v1.2.0 DoubleResetDetector_Generic v1.0.3 EEPROM size = 16384, start = 0 @@ -1339,7 +1449,7 @@ SetFlag write = 0xd0d01234 ``` Start Ethernet_STM32 on NUCLEO_F767ZI Ethernet Shield type : W5x00 using Ethernet Library -Ethernet_Manager_STM32 v1.0.1 +Ethernet_Manager_STM32 v1.2.0 DoubleResetDetector_Generic v1.0.3 EEPROM size = 16384, start = 0 @@ -1384,7 +1494,7 @@ H ``` Start Ethernet_STM32 on NUCLEO_F767ZI Ethernet Shield type : W5x00 using Ethernet Library -Ethernet_Manager_STM32 v1.0.1 +Ethernet_Manager_STM32 v1.2.0 DoubleResetDetector_Generic v1.0.3 EEPROM size = 16384, start = 0 @@ -1432,7 +1542,7 @@ This is the terminal output of STM32F7 Nucleo-144 NUCLEO_F767ZI board with ENC28 ``` Start MQTT_ThingStream_Ethernet_STM32 on NUCLEO_F767ZI Ethernet Shield type : ENC28J60 using EthernetENC Library -Ethernet_Manager_STM32 v1.0.1 +Ethernet_Manager_STM32 v1.2.0 DoubleResetDetector_Generic v1.0.3 EEPROM size = 16384, start = 0 @@ -1466,7 +1576,7 @@ ClearFlag write = 0xd0d04321 ``` Start MQTT_ThingStream_Ethernet_STM32 on NUCLEO_F767ZI Ethernet Shield type : ENC28J60 using EthernetENC Library -Ethernet_Manager_STM32 v1.0.1 +Ethernet_Manager_STM32 v1.2.0 DoubleResetDetector_Generic v1.0.3 EEPROM size = 16384, start = 0 @@ -1519,7 +1629,7 @@ This is the terminal output of STM32F7 Nucleo-144 NUCLEO_F767ZI board with W5x00 ``` Start Ethernet_STM32 on NUCLEO_F767ZI Ethernet Shield type : W5x00 using EthernetLarge Library -Ethernet_Manager_STM32 v1.0.1 +Ethernet_Manager_STM32 v1.2.0 DoubleResetDetector_Generic v1.0.3 EEPROM size = 16384, start = 0 @@ -1567,7 +1677,7 @@ This is the terminal output of STM32F7 Nucleo-144 NUCLEO_F767ZI board with LAN87 ``` Start MQTT_ThingStream_Ethernet_STM32 on NUCLEO_F767ZI Ethernet Shield type : LAN8742A Ethernet & STM32Ethernet Library -Ethernet_Manager_STM32 v1.0.1 +Ethernet_Manager_STM32 v1.2.0 DoubleResetDetector_Generic v1.0.3 EEPROM size = 16384, start = 0 @@ -1601,7 +1711,7 @@ ClearFlag write = 0xd0d04321 ``` Start MQTT_ThingStream_Ethernet_STM32 on NUCLEO_F767ZI Ethernet Shield type : LAN8742A Ethernet & STM32Ethernet Library -Ethernet_Manager_STM32 v1.0.1 +Ethernet_Manager_STM32 v1.2.0 DoubleResetDetector_Generic v1.0.3 EEPROM size = 16384, start = 0 @@ -1685,6 +1795,15 @@ Sometimes, the library will only work if you update the board core to the latest ## Releases +### Major Releases v1.2.0 + +1. Configurable **Customs HTML Headers**, including Customs Style, Customs Head Elements, CORS Header. +2. Add functions to control Config Portal from software or Virtual Switches. Check [How to trigger a Config Portal from code #25](https://github.com/khoih-prog/Blynk_WM/issues/25) +3. Use more efficient [**FlashStorage_STM32 v1.0.1**](https://github.com/khoih-prog/FlashStorage_STM32) +4. Fix Config Portal Bug. +5. Update examples +6. Bump up to version v1.2.0 to sync with [**Ethernet_Manager**](https://github.com/khoih-prog/Ethernet_Manager) + ### Releases v1.0.1 1. Clean-up all compiler warnings possible. @@ -1763,7 +1882,8 @@ Submit issues to: [Ethernet_Manager_STM32 issues](https://github.com/khoih-prog/ 13. Configurable Config Portal Title 14. Re-structure all examples to separate Credentials / Defines / Dynamic Params / Code so that you can change Credentials / Dynamic Params quickly for each device. 15. Add support to new [**`EthernetENC library`**](https://github.com/jandrassy/EthernetENC) for ENC28J60. - +16. Add Table of Contents and Version String +17. Configurable **Customs HTML Headers**, including Customs Style, Customs Head Elements, CORS Header --- diff --git a/keywords.txt b/keywords.txt index 3df501d..6d91bf4 100644 --- a/keywords.txt +++ b/keywords.txt @@ -16,12 +16,23 @@ getBoardName KEYWORD2 getFullConfigData KEYWORD2 clearConfigData KEYWORD2 resetFunc KEYWORD2 +resetAndEnterConfigPortal KEYWORD2 +resetAndEnterConfigPortalPersistent KEYWORD2 +setCustomsStyle KEYWORD2 +getCustomsStyle KEYWORD2 +setCustomsHeadElement KEYWORD2 +getCustomsHeadElement KEYWORD2 +setCORSHeader KEYWORD2 +getCORSHeader KEYWORD2 ####################################### # Literals (LITERAL1) ####################################### ETM_HTML_HEAD LITERAL1 +ETM_HTML_HEAD_START LITERAL1 +ETM_HTML_HEAD_STYLE LITERAL1 +ETM_HTML_HEAD_END LITERAL1 ETM_FLDSET_START LITERAL1 ETM_FLDSET_END LITERAL1 ETM_HTML_PARAM LITERAL1 @@ -30,3 +41,14 @@ ETM_HTML_SCRIPT LITERAL1 ETM_HTML_SCRIPT_ITEM LITERAL1 ETM_HTML_SCRIPT_END LITERAL1 ETM_HTML_END LITERAL1 + +WM_HTTP_HEAD_CL LITERAL1 +WM_HTTP_HEAD_TEXT_HTML LITERAL1 +WM_HTTP_HEAD_TEXT_PLAIN LITERAL1 +WM_HTTP_CACHE_CONTROL LITERAL1 +WM_HTTP_NO_STORE LITERAL1 +WM_HTTP_PRAGMA LITERAL1 +WM_HTTP_NO_CACHE LITERAL1 +WM_HTTP_EXPIRES LITERAL1 +WM_HTTP_CORS LITERAL1 +WM_HTTP_CORS_ALLOW_ALL LITERAL1 diff --git a/library.json b/library.json index 8136be7..03b6ed8 100644 --- a/library.json +++ b/library.json @@ -1,8 +1,8 @@ { "name": "Ethernet_Manager_STM32", - "version": "1.0.1", - "description": "Simple Ethernet Manager for STM32F/L/H/G/WB/MP1 boards with Ethernet W5x00, ENC28J60 or built-in LAN8742A shields, with or without SSL, configuration data saved in EEPROM. With DoubleResetDetect feature.", - "keywords": "communication, ethernet, data, http, W5500, W5x00, ENC28J60, STM32, Credentials, Manager, Config Portal, Double, Reset, double-reset, Detector, MQTT, DynamicParameters", + "version": "1.2.0", + "description": "Simple Ethernet Manager for STM32F/L/H/G/WB/MP1 boards with Ethernet W5x00, ENC28J60 or built-in LAN8742A shields, with or without SSL. For configuring/auto(re)connecting Ethernet W5x00, ENC28J60 or built-in LAN8742A at runtime. Use much less memory compared to full-fledge WiFiManager. Config Portal (CP) will be auto-adjusted to match the number of dynamic custom parameters. Optional default Credentials to be autoloaded into CP to use or change instead of manually input. Credentials and Configuration Data are saved in emulated-EEPROM using FlashStorage_STM32. New powerful-yet-simple-to-use feature to enable adding dynamic custom parameters from sketch and input using the same CP. DoubleDetectDetector as well as Virtual Switches feature permits entering CP as requested. Configurable Customs HTML Headers, including Customs Style, Customs Head Elements, CORS Header.", + "keywords": "communication, ethernet, data, http, W5500, W5x00, ENC28J60, LAN8742A, stm32, st32f, stm32l, stm32h, stm32g, stm32wb, stm32mp1, ST STM32, bluepill, blackpill, nucleo, Credentials, Manager, Config Portal, Double, Reset, double-reset, Detector, MQTT, DynamicParameters, dynamic-params, dynamic, customs-header", "authors": { "name": "Khoi Hoang", @@ -27,19 +27,19 @@ { "owner": "khoih-prog", "name": "EthernetWebServer_STM32", - "version": ">=1.1.0", - "platforms": ["*"] + "version": ">=1.1.1", + "platforms": ["ststm32"] }, { "owner": "khoih-prog", "name": "DoubleResetDetector_Generic", - "version": ">=1.0.2", + "version": ">=1.0.3", "platforms": ["*"] }, { "owner": "khoih-prog", "name": "Functional-Vlpp", - "version": ">=1.0.1", + "version": ">=1.0.2", "platforms": ["*"] }, { @@ -56,6 +56,6 @@ } ], "frameworks": "*", - "platforms": "*", + "platforms": "ststm32", "examples": "examples/*/*/*.ino" } diff --git a/library.properties b/library.properties index 5e6836d..6b2e047 100644 --- a/library.properties +++ b/library.properties @@ -1,10 +1,10 @@ name=Ethernet_Manager_STM32 -version=1.0.1 +version=1.2.0 author=Khoi Hoang license=MIT maintainer=Khoi Hoang sentence=Simple Ethernet Manager for STM32F/L/H/G/WB/MP1 boards with Ethernet W5x00, ENC28J60 or built-in LAN8742A shields, with or without SSL, configuration data saved in EEPROM. With DoubleResetDetect feature. -paragraph=Library for configuring/auto(re)connecting W5100/W5200/W5500, ENC28J60 and built-in LAN8742A Ethernet at runtime using Config Portal. New powerful-yet-simple-to-use feature to enable adding dynamic custom parameters from sketch and input using the same Config Portal. Config Portal will be auto-adjusted to match the number of dynamic parameters. DoubleDetectDetector is used to force Config Portal opening even if the Credentials are still valid. +paragraph=Library for configuring/auto(re)connecting Ethernet W5x00, ENC28J60 or built-in LAN8742A at runtime. Use much less memory compared to full-fledge WiFiManager. Config Portal (CP) will be auto-adjusted to match the number of dynamic custom parameters. Optional default Credentials to be autoloaded into CP to use or change instead of manually input. Credentials and Configuration Data are saved in emulated-EEPROM using FlashStorage_STM32. New powerful-yet-simple-to-use feature to enable adding dynamic custom parameters from sketch and input using the same CP. DoubleDetectDetector as well as Virtual Switches feature permits entering CP as requested. Configurable Customs HTML Headers, including Customs Style, Customs Head Elements, CORS Header. category=Communication url=https://github.com/khoih-prog/Ethernet_Manager_STM32 architectures=* diff --git a/platformio/platformio.ini b/platformio/platformio.ini index 4f39316..07d04ec 100644 --- a/platformio/platformio.ini +++ b/platformio/platformio.ini @@ -32,25 +32,27 @@ lib_deps = DoubleResetDetector_Generic@>=1.0.3 STM32duino LwIP@>=2.1.2 STM32duino STM32Ethernet@>=1.2.0 - Functional-Vlpp@>=1.0.1 + Functional-Vlpp@>=1.0.2 UIPEthernet@>=2.0.9 Ethernet@>=2.0.0 EthernetLarge@>=2.0.0 Ethernet2@>=1.0.4 Ethernet3@>=1.5.3 EthernetENC@>=2.0.0 + FlashStorage_STM32@>=1.0.1 ; PlatformIO 5.x -; khoih-prog/EthernetWebServer_STM32@>=1.1.1 -; khoih.prog/DoubleResetDetector_Generic@>=1.0.3 -; stm32duino/STM32duino LwIP@>=2.1.2 -; stm32duino/STM32duino STM32Ethernet@>=1.2.0 -; khoih-prog/Functional-Vlpp@>=1.0.1 -; UIPEthernet/UIPEthernet@>=2.0.9 -; PaulStoffregen/Ethernet@>=2.0.0 -; PaulStoffregen/EthernetLarge@>=2.0.0 -; adafruit/Ethernet2@>=1.0.4 -; sstaub/Ethernet3@>=1.5.3 -; jandrassy/EthernetENC@>=2.0.0 +; khoih-prog/EthernetWebServer_STM32@>=1.1.1 +; khoih.prog/DoubleResetDetector_Generic@>=1.0.3 +; stm32duino/STM32duino LwIP@>=2.1.2 +; stm32duino/STM32duino STM32Ethernet@>=1.2.0 +; khoih-prog/Functional-Vlpp@>=1.0.2 +; UIPEthernet/UIPEthernet@>=2.0.9 +; PaulStoffregen/Ethernet@>=2.0.0 +; PaulStoffregen/EthernetLarge@>=2.0.0 +; adafruit/Ethernet2@>=1.0.4 +; sstaub/Ethernet3@>=1.5.3 +; jandrassy/EthernetENC@>=2.0.0 +; khoih.prog/FlashStorage_STM32@>=1.0.1 build_flags = ; set your build_flags diff --git a/src/Ethernet_Manager_STM32.h b/src/Ethernet_Manager_STM32.h index ee4605a..fab6323 100644 --- a/src/Ethernet_Manager_STM32.h +++ b/src/Ethernet_Manager_STM32.h @@ -7,12 +7,13 @@ Built by Khoi Hoang https://github.com/khoih-prog/Ethernet_Manager_STM32 Licensed under MIT license - Version: 1.0.1 + Version: 1.2.0 Version Modified By Date Comments ------- ----------- ---------- ----------- 1.0.0 K Hoang 16/12/2020 Initial coding. 1.0.1 K Hoang 29/12/2020 Suppress all possible compiler warnings + 1.2.0 K Hoang 23/02/2021 Optimize code and use better FlashStorage_STM32. Add customs HTML header feature. Fix bug. *****************************************************************************************************************************/ #pragma once @@ -20,7 +21,7 @@ #ifndef Ethernet_Manager_STM32 #define Ethernet_Manager_STM32 -#define ETHERNET_MANAGER_STM32_VERSION "Ethernet_Manager_STM32 v1.0.1" +#define ETHERNET_MANAGER_STM32_VERSION "Ethernet_Manager_STM32 v1.2.0" #if ( defined(STM32F0) || defined(STM32F1) || defined(STM32F2) || defined(STM32F3) ||defined(STM32F4) || defined(STM32F7) || \ defined(STM32L0) || defined(STM32L1) || defined(STM32L4) || defined(STM32H7) ||defined(STM32G0) || defined(STM32G4) || \ diff --git a/src/Ethernet_Manager_STM32_Debug.h b/src/Ethernet_Manager_STM32_Debug.h index 5617312..8df3ce1 100644 --- a/src/Ethernet_Manager_STM32_Debug.h +++ b/src/Ethernet_Manager_STM32_Debug.h @@ -7,12 +7,13 @@ Built by Khoi Hoang https://github.com/khoih-prog/Ethernet_Manager_STM32 Licensed under MIT license - Version: 1.0.1 + Version: 1.2.0 Version Modified By Date Comments ------- ----------- ---------- ----------- 1.0.0 K Hoang 16/12/2020 Initial coding. 1.0.1 K Hoang 29/12/2020 Suppress all possible compiler warnings + 1.2.0 K Hoang 23/02/2021 Optimize code and use better FlashStorage_STM32. Add customs HTML header feature. Fix bug. *****************************************************************************************************************************/ #pragma once @@ -37,28 +38,49 @@ #define _ETHERNET_MANAGER_STM32_LOGLEVEL_ 0 #endif -#define ETM_LOGERROR(x) if(_ETHERNET_MANAGER_STM32_LOGLEVEL_>0) { ETM_DBG_PORT.print("[ETM] "); ETM_DBG_PORT.println(x); } -#define ETM_LOGERROR0(x) if(_ETHERNET_MANAGER_STM32_LOGLEVEL_>0) { ETM_DBG_PORT.print(x); } -#define ETM_LOGERROR1(x,y) if(_ETHERNET_MANAGER_STM32_LOGLEVEL_>0) { ETM_DBG_PORT.print("[ETM] "); ETM_DBG_PORT.print(x); ETM_DBG_PORT.print(" "); ETM_DBG_PORT.println(y); } -#define ETM_LOGERROR2(x,y,z) if(_ETHERNET_MANAGER_STM32_LOGLEVEL_>0) { ETM_DBG_PORT.print("[ETM] "); ETM_DBG_PORT.print(x); ETM_DBG_PORT.print(" "); ETM_DBG_PORT.print(y); ETM_DBG_PORT.print(" "); ETM_DBG_PORT.println(z); } -#define ETM_LOGERROR3(x,y,z,w) if(_ETHERNET_MANAGER_STM32_LOGLEVEL_>0) { ETM_DBG_PORT.print("[ETM] "); ETM_DBG_PORT.print(x); ETM_DBG_PORT.print(" "); ETM_DBG_PORT.print(y); ETM_DBG_PORT.print(" "); ETM_DBG_PORT.print(z); ETM_DBG_PORT.print(" "); ETM_DBG_PORT.println(w); } - -#define ETM_LOGWARN(x) if(_ETHERNET_MANAGER_STM32_LOGLEVEL_>1) { ETM_DBG_PORT.print("[ETM] "); ETM_DBG_PORT.println(x); } -#define ETM_LOGWARN0(x) if(_ETHERNET_MANAGER_STM32_LOGLEVEL_>1) { ETM_DBG_PORT.print(x); } -#define ETM_LOGWARN1(x,y) if(_ETHERNET_MANAGER_STM32_LOGLEVEL_>1) { ETM_DBG_PORT.print("[ETM] "); ETM_DBG_PORT.print(x); ETM_DBG_PORT.print(" "); ETM_DBG_PORT.println(y); } -#define ETM_LOGWARN2(x,y,z) if(_ETHERNET_MANAGER_STM32_LOGLEVEL_>1) { ETM_DBG_PORT.print("[ETM] "); ETM_DBG_PORT.print(x); ETM_DBG_PORT.print(" "); ETM_DBG_PORT.print(y); ETM_DBG_PORT.print(" "); ETM_DBG_PORT.println(z); } -#define ETM_LOGWARN3(x,y,z,w) if(_ETHERNET_MANAGER_STM32_LOGLEVEL_>1) { ETM_DBG_PORT.print("[ETM] "); ETM_DBG_PORT.print(x); ETM_DBG_PORT.print(" "); ETM_DBG_PORT.print(y); ETM_DBG_PORT.print(" "); ETM_DBG_PORT.print(z); ETM_DBG_PORT.print(" "); ETM_DBG_PORT.println(w); } - -#define ETM_LOGINFO(x) if(_ETHERNET_MANAGER_STM32_LOGLEVEL_>2) { ETM_DBG_PORT.print("[ETM] "); ETM_DBG_PORT.println(x); } -#define ETM_LOGINFO0(x) if(_ETHERNET_MANAGER_STM32_LOGLEVEL_>2) { ETM_DBG_PORT.print(x); } -#define ETM_LOGINFO1(x,y) if(_ETHERNET_MANAGER_STM32_LOGLEVEL_>2) { ETM_DBG_PORT.print("[ETM] "); ETM_DBG_PORT.print(x); ETM_DBG_PORT.print(" "); ETM_DBG_PORT.println(y); } -#define ETM_LOGINFO2(x,y,z) if(_ETHERNET_MANAGER_STM32_LOGLEVEL_>2) { ETM_DBG_PORT.print("[ETM] "); ETM_DBG_PORT.print(x); ETM_DBG_PORT.print(" "); ETM_DBG_PORT.print(y); ETM_DBG_PORT.print(" "); ETM_DBG_PORT.println(z); } -#define ETM_LOGINFO3(x,y,z,w) if(_ETHERNET_MANAGER_STM32_LOGLEVEL_>2) { ETM_DBG_PORT.print("[ETM] "); ETM_DBG_PORT.print(x); ETM_DBG_PORT.print(" "); ETM_DBG_PORT.print(y); ETM_DBG_PORT.print(" "); ETM_DBG_PORT.print(z); ETM_DBG_PORT.print(" "); ETM_DBG_PORT.println(w); } - -#define ETM_LOGDEBUG(x) if(_ETHERNET_MANAGER_STM32_LOGLEVEL_>3) { ETM_DBG_PORT.print("[ETM] "); ETM_DBG_PORT.println(x); } -#define ETM_LOGDEBUG0(x) if(_ETHERNET_MANAGER_STM32_LOGLEVEL_>3) { ETM_DBG_PORT.print(x); } -#define ETM_LOGDEBUG1(x,y) if(_ETHERNET_MANAGER_STM32_LOGLEVEL_>3) { ETM_DBG_PORT.print("[ETM] "); ETM_DBG_PORT.print(x); ETM_DBG_PORT.print(" "); ETM_DBG_PORT.println(y); } -#define ETM_LOGDEBUG2(x,y,z) if(_ETHERNET_MANAGER_STM32_LOGLEVEL_>3) { ETM_DBG_PORT.print("[ETM] "); ETM_DBG_PORT.print(x); ETM_DBG_PORT.print(" "); ETM_DBG_PORT.print(y); ETM_DBG_PORT.print(" "); ETM_DBG_PORT.println(z); } -#define ETM_LOGDEBUG3(x,y,z,w) if(_ETHERNET_MANAGER_STM32_LOGLEVEL_>3) { ETM_DBG_PORT.print("[ETM] "); ETM_DBG_PORT.print(x); ETM_DBG_PORT.print(" "); ETM_DBG_PORT.print(y); ETM_DBG_PORT.print(" "); ETM_DBG_PORT.print(z); ETM_DBG_PORT.print(" "); ETM_DBG_PORT.println(w); } +const char ETM_MARK[] = "[ETM] "; + +#define ETM_PRINT ETM_DBG_PORT.print +#define ETM_PRINTLN ETM_DBG_PORT.println + +#define ETM_PRINT_MARK ETM_PRINT(ETM_MARK) + +//////////////////////////////////////////////////// + +#define ETM_LOGERROR0(x) if(_ETHERNET_MANAGER_STM32_LOGLEVEL_>0) { ETM_PRINT(x); } +#define ETM_LOGERROR(x) if(_ETHERNET_MANAGER_STM32_LOGLEVEL_>0) { ETM_PRINT_MARK; ETM_PRINTLN(x); } +#define ETM_LOGERROR1(x,y) if(_ETHERNET_MANAGER_STM32_LOGLEVEL_>0) { ETM_PRINT_MARK; ETM_PRINT(x); ETM_PRINTLN(y); } +#define ETM_LOGERROR2(x,y,z) if(_ETHERNET_MANAGER_STM32_LOGLEVEL_>0) { ETM_PRINT_MARK; ETM_PRINT(x); ETM_PRINT(y); ETM_PRINTLN(z); } +#define ETM_LOGERROR3(x,y,z,w) if(_ETHERNET_MANAGER_STM32_LOGLEVEL_>0) { ETM_PRINT_MARK; ETM_PRINT(x); ETM_PRINT(y); ETM_PRINT(z); ETM_PRINTLN(w); } +#define ETM_LOGERROR5(x,y,z,w,xx,yy) if(_ETHERNET_MANAGER_STM32_LOGLEVEL_>0) { ETM_PRINT_MARK; ETM_PRINT(x); ETM_PRINT(y); ETM_PRINT(z); ETM_PRINT(w); ETM_PRINT(xx); ETM_PRINTLN(yy); } + +//////////////////////////////////////////////////// + +#define ETM_LOGWARN0(x) if(_ETHERNET_MANAGER_STM32_LOGLEVEL_>1) { ETM_PRINT(x); } +#define ETM_LOGWARN(x) if(_ETHERNET_MANAGER_STM32_LOGLEVEL_>1) { ETM_PRINT_MARK; ETM_PRINTLN(x); } +#define ETM_LOGWARN1(x,y) if(_ETHERNET_MANAGER_STM32_LOGLEVEL_>1) { ETM_PRINT_MARK; ETM_PRINT(x); ETM_PRINTLN(y); } +#define ETM_LOGWARN2(x,y,z) if(_ETHERNET_MANAGER_STM32_LOGLEVEL_>1) { ETM_PRINT_MARK; ETM_PRINT(x); ETM_PRINT(y); ETM_PRINTLN(z); } +#define ETM_LOGWARN3(x,y,z,w) if(_ETHERNET_MANAGER_STM32_LOGLEVEL_>1) { ETM_PRINT_MARK; ETM_PRINT(x); ETM_PRINT(y); ETM_PRINT(z); ETM_PRINTLN(w); } +#define ETM_LOGWARN5(x,y,z,w,xx,yy) if(_ETHERNET_MANAGER_STM32_LOGLEVEL_>1) { ETM_PRINT_MARK; ETM_PRINT(x); ETM_PRINT(y); ETM_PRINT(z); ETM_PRINT(w); ETM_PRINT(xx); ETM_PRINTLN(yy); } + +//////////////////////////////////////////////////// + +#define ETM_LOGINFO0(x) if(_ETHERNET_MANAGER_STM32_LOGLEVEL_>2) { ETM_PRINT(x); } +#define ETM_LOGINFO(x) if(_ETHERNET_MANAGER_STM32_LOGLEVEL_>2) { ETM_PRINT_MARK; ETM_PRINTLN(x); } +#define ETM_LOGINFO1(x,y) if(_ETHERNET_MANAGER_STM32_LOGLEVEL_>2) { ETM_PRINT_MARK; ETM_PRINT(x); ETM_PRINTLN(y); } +#define ETM_LOGINFO2(x,y,z) if(_ETHERNET_MANAGER_STM32_LOGLEVEL_>2) { ETM_PRINT_MARK; ETM_PRINT(x); ETM_PRINT(y); ETM_PRINTLN(z); } +#define ETM_LOGINFO3(x,y,z,w) if(_ETHERNET_MANAGER_STM32_LOGLEVEL_>2) { ETM_PRINT_MARK; ETM_PRINT(x); ETM_PRINT(y); ETM_PRINT(z); ETM_PRINTLN(w); } +#define ETM_LOGINFO5(x,y,z,w,xx,yy) if(_ETHERNET_MANAGER_STM32_LOGLEVEL_>2) { ETM_PRINT_MARK; ETM_PRINT(x); ETM_PRINT(y); ETM_PRINT(z); ETM_PRINT(w); ETM_PRINT(xx); ETM_PRINTLN(yy); } + +//////////////////////////////////////////////////// + +#define ETM_LOGDEBUG0(x) if(_ETHERNET_MANAGER_STM32_LOGLEVEL_>3) { ETM_PRINT(x); } +#define ETM_LOGDEBUG(x) if(_ETHERNET_MANAGER_STM32_LOGLEVEL_>3) { ETM_PRINT_MARK; ETM_PRINTLN(x); } +#define ETM_LOGDEBUG1(x,y) if(_ETHERNET_MANAGER_STM32_LOGLEVEL_>3) { ETM_PRINT_MARK; ETM_PRINT(x); ETM_PRINTLN(y); } +#define ETM_LOGDEBUG2(x,y,z) if(_ETHERNET_MANAGER_STM32_LOGLEVEL_>3) { ETM_PRINT_MARK; ETM_PRINT(x); ETM_PRINT(y); ETM_PRINTLN(z); } +#define ETM_LOGDEBUG3(x,y,z,w) if(_ETHERNET_MANAGER_STM32_LOGLEVEL_>3) { ETM_PRINT_MARK; ETM_PRINT(x); ETM_PRINT(y); ETM_PRINT(z); ETM_PRINTLN(w); } +#define ETM_LOGDEBUG5(x,y,z,w,xx,yy) if(_ETHERNET_MANAGER_STM32_LOGLEVEL_>3) { ETM_PRINT_MARK; ETM_PRINT(x); ETM_PRINT(y); ETM_PRINT(z); ETM_PRINT(w); ETM_PRINT(xx); ETM_PRINTLN(yy); } + +//////////////////////////////////////////////////// #endif //Ethernet_Manager_STM32_Debug diff --git a/src/Ethernet_Manager_STM32_Impl.h b/src/Ethernet_Manager_STM32_Impl.h index c0aa59d..fcbdb47 100644 --- a/src/Ethernet_Manager_STM32_Impl.h +++ b/src/Ethernet_Manager_STM32_Impl.h @@ -7,12 +7,13 @@ Built by Khoi Hoang https://github.com/khoih-prog/Ethernet_Manager_STM32 Licensed under MIT license - Version: 1.0.1 + Version: 1.2.0 Version Modified By Date Comments ------- ----------- ---------- ----------- 1.0.0 K Hoang 16/12/2020 Initial coding. 1.0.1 K Hoang 29/12/2020 Suppress all possible compiler warnings + 1.2.0 K Hoang 23/02/2021 Optimize code and use better FlashStorage_STM32. Add customs HTML header feature. Fix bug. *****************************************************************************************************************************/ #pragma once @@ -23,11 +24,22 @@ // Increase HTTP_UPLOAD_BUFLEN to 4K, instead of default 2K in #define HTTP_UPLOAD_BUFLEN 4096 -//Use EEPROM -#include - #include +////////////////////////////////////////// + +#ifndef USING_CUSTOMS_STYLE + #define USING_CUSTOMS_STYLE false +#endif + +#ifndef USING_CUSTOMS_HEAD_ELEMENT + #define USING_CUSTOMS_HEAD_ELEMENT false +#endif + +#ifndef USING_CORS_FEATURE + #define USING_CORS_FEATURE false +#endif + ///////// NEW for DRD ///////////// // These defines must be put before #include // to select where to store DoubleResetDetector_Generic's variable. @@ -64,18 +76,28 @@ typedef struct } MenuItem; // -///NEW -extern uint16_t NUM_MENU_ITEMS; -extern MenuItem myMenuItems []; +#if USE_DYNAMIC_PARAMETERS + #warning Using Dynamic Parameters + ///NEW + extern uint16_t NUM_MENU_ITEMS; + extern MenuItem myMenuItems []; + bool *menuItemUpdated = NULL; +#else + #warning Not using Dynamic Parameters +#endif // Configurable items besides fixed Header #define NUM_CONFIGURABLE_ITEMS ( 2 ) +#define HEADER_MAX_LEN 16 +#define STATIC_IP_MAX_LEN 16 +#define BOARD_NAME_MAX_LEN 24 + typedef struct Configuration { - char header [16]; - char static_IP [16]; - char board_name [24]; + char header [HEADER_MAX_LEN]; + char static_IP [STATIC_IP_MAX_LEN]; + char board_name [BOARD_NAME_MAX_LEN]; int checkSum; } Ethernet_Configuration; @@ -86,9 +108,13 @@ uint16_t CONFIG_DATA_SIZE = sizeof(Ethernet_Configuration); extern bool LOAD_DEFAULT_CONFIG_DATA; extern Ethernet_Configuration defaultConfig; -const char ETM_HTML_HEAD[] /*PROGMEM*/ = "Ethernet_STM32_Manager
\ +// -- HTML page fragments + +const char ETM_HTML_HEAD_START[] /*PROGMEM*/ = "Ethernet_STM32_Manager"; + +const char ETM_HTML_HEAD_STYLE[] /*PROGMEM*/ = ""; + +const char ETM_HTML_HEAD_END[] /*PROGMEM*/ = "
\
\
"; @@ -104,8 +130,25 @@ udVal('nm',document.getElementById('nm').value);"; const char ETM_HTML_SCRIPT_ITEM[] /*PROGMEM*/ = "udVal('{d}',document.getElementById('{d}').value);"; const char ETM_HTML_SCRIPT_END[] /*PROGMEM*/ = "alert('Updated');}"; const char ETM_HTML_END[] /*PROGMEM*/ = ""; -/// +////////////////////////////////////////// + +//KH Add repeatedly used const +//KH, from v1.1.0 +const char WM_HTTP_HEAD_CL[] PROGMEM = "Content-Length"; +const char WM_HTTP_HEAD_TEXT_HTML[] PROGMEM = "text/html"; +const char WM_HTTP_HEAD_TEXT_PLAIN[] PROGMEM = "text/plain"; + +const char WM_HTTP_CACHE_CONTROL[] PROGMEM = "Cache-Control"; +const char WM_HTTP_NO_STORE[] PROGMEM = "no-cache, no-store, must-revalidate"; +const char WM_HTTP_PRAGMA[] PROGMEM = "Pragma"; +const char WM_HTTP_NO_CACHE[] PROGMEM = "no-cache"; +const char WM_HTTP_EXPIRES[] PROGMEM = "Expires"; + +const char WM_HTTP_CORS[] PROGMEM = "Access-Control-Allow-Origin"; +const char WM_HTTP_CORS_ALLOW_ALL[] PROGMEM = "*"; + +////////////////////////////////////////// class Ethernet_Manager { @@ -113,11 +156,7 @@ class Ethernet_Manager public: void begin(bool initialConfig = false) - { - //Turn OFF - //pinMode(LED_BUILTIN, OUTPUT); - //digitalWrite(LED_BUILTIN, LED_OFF); - + { //// New DRD //// drd = new DoubleResetDetector_Generic(DRD_TIMEOUT, DRD_ADDRESS); bool noConfigPortal = true; @@ -131,17 +170,23 @@ class Ethernet_Manager } //// New DRD //// - ETM_LOGWARN(F("======= Start Default Config Data =======")); - displayConfigData(defaultConfig); + + if (LOAD_DEFAULT_CONFIG_DATA) + { + ETM_LOGERROR(F("======= Start Default Config Data =======")); + displayConfigData(defaultConfig); + } hadConfigData = getConfigData(); connectEthernet(); + + isForcedConfigPortal = isForcedCP(); //// New DRD //// - // noConfigPortal when getConfigData() OK and no DRD'ed - if (hadConfigData && noConfigPortal) - //// New DRD //// + // noConfigPortal when getConfigData() OK and no MRD/DRD'ed + if (hadConfigData && noConfigPortal && (!isForcedConfigPortal) ) + //// New DRD //// { hadConfigData = true; @@ -161,23 +206,38 @@ class Ethernet_Manager { // Can't do anything here ETM_LOGWARN(F("begin:Ethernet not Connected")); - // failed to connect to Blynk server, will start configuration mode + // failed to connect to Ethernet, will start configuration mode //startConfigurationMode(); } } else - { - ETM_LOGWARN1(F("begin:Stay in CfgPortal:"), noConfigPortal ? F("No CfgDat") : F("DRD")); + { + ETM_LOGERROR(isForcedConfigPortal? F("bg: isForcedConfigPortal = true") : F("bg: isForcedConfigPortal = false")); + + // If not persistent => clear the flag so that after reset. no more CP, even CP not entered and saved + if (persForcedConfigPortal) + { + ETM_LOGERROR1(F("bg:Stay forever in CP:"), isForcedConfigPortal ? F("Forced-Persistent") : (noConfigPortal ? F("No ConfigDat") : F("DRD/MRD"))); + } + else + { + ETM_LOGERROR1(F("bg:Stay forever in CP:"), isForcedConfigPortal ? F("Forced-non-Persistent") : (noConfigPortal ? F("No ConfigDat") : F("DRD/MRD"))); + clearForcedCP(); + } + + //To permit autoreset after timeout if DRD/MRD or non-persistent forced-CP + hadConfigData = isForcedConfigPortal ? true : (noConfigPortal ? false : true); - // failed to connect to Blynk server, will start configuration mode - hadConfigData = false; + // failed to connect to WiFi, will start configuration mode startConfigurationMode(); } } + + ////////////////////////////////////////// // Return true if still in CP mode bool run() - { + { //// New DRD //// // Call the double reset detector loop method every so often, // so that it can recognise when the timeout expires. @@ -185,7 +245,7 @@ class Ethernet_Manager // consider the next reset as a double reset. drd->loop(); //// New DRD //// - + // Be sure to reconnect Ethernet first if (!ethernetConnected) { @@ -201,7 +261,10 @@ class Ethernet_Manager { retryTimes = 0; - server.handleClient(); + //if (server) + { + server.handleClient(); + } } else { @@ -226,18 +289,19 @@ class Ethernet_Manager { configuration_mode = false; ETM_LOGWARN(F("run:Ethernet not OK")); - - // Turn the LED_BUILTIN OFF when out of configuration mode. - //digitalWrite(LED_BUILTIN, LED_OFF); } return configuration_mode; } + ////////////////////////////////////////// + String getBoardName() { return (String(Ethernet_Manager_config.board_name)); } + + ////////////////////////////////////////// Ethernet_Configuration* getFullConfigData(Ethernet_Configuration *configData) { @@ -251,19 +315,70 @@ class Ethernet_Manager return (configData); } + ////////////////////////////////////////// + void clearConfigData() { memset(&Ethernet_Manager_config, 0, sizeof(Ethernet_Manager_config)); - + +#if USE_DYNAMIC_PARAMETERS for (uint16_t i = 0; i < NUM_MENU_ITEMS; i++) { // Actual size of pdata is [maxlen + 1] memset(myMenuItems[i].pdata, 0, myMenuItems[i].maxlen + 1); } +#endif saveConfigData(); } + ////////////////////////////////////////////// + + bool isConfigDataValid() + { + return hadConfigData; + } + + ////////////////////////////////////////////// + + // Forced CP => Flag = 0xBEEFBEEF. Else => No forced CP + // Flag to be stored at (EEPROM_START + DRD_FLAG_DATA_SIZE + CONFIG_DATA_SIZE) + // to avoid corruption to current data + //#define FORCED_CONFIG_PORTAL_FLAG_DATA ( (uint32_t) 0xDEADBEEF) + //#define FORCED_PERS_CONFIG_PORTAL_FLAG_DATA ( (uint32_t) 0xBEEFDEAD) + + const uint32_t FORCED_CONFIG_PORTAL_FLAG_DATA = 0xDEADBEEF; + const uint32_t FORCED_PERS_CONFIG_PORTAL_FLAG_DATA = 0xBEEFDEAD; + + #define FORCED_CONFIG_PORTAL_FLAG_DATA_SIZE 4 + + void resetAndEnterConfigPortal() + { + persForcedConfigPortal = false; + + setForcedCP(false); + + // Delay then reset the ESP8266 after save data + delay(1000); + resetFunc(); + } + + ////////////////////////////////////////////// + + // This will keep CP forever, until you successfully enter CP, and Save data to clear the flag. + void resetAndEnterConfigPortalPersistent() + { + persForcedConfigPortal = true; + + setForcedCP(true); + + // Delay then reset the ESP8266 after save data + delay(1000); + resetFunc(); + } + + ////////////////////////////////////////////// + void resetFunc() { // Initialize the IWDG with 2 seconds timeout. @@ -271,6 +386,64 @@ class Ethernet_Manager // is not reloaded in approximately 2 seconds. IWatchdog.begin(2000000); } + + ////////////////////////////////////// + + // Add customs headers from v1.1.0 + + // New from v1.1.0, for configure CORS Header, default to WM_HTTP_CORS_ALLOW_ALL = "*" + +#if USING_CUSTOMS_STYLE + //sets a custom style, such as color + // ""; + void setCustomsStyle(const char* CustomsStyle = ETM_HTML_HEAD_STYLE) + { + ETM_HTML_HEAD_CUSTOMS_STYLE = CustomsStyle; + ETM_LOGDEBUG1(F("Set CustomsStyle to : "), ETM_HTML_HEAD_CUSTOMS_STYLE); + } + + const char* getCustomsStyle() + { + ETM_LOGDEBUG1(F("Get CustomsStyle = "), ETM_HTML_HEAD_CUSTOMS_STYLE); + return ETM_HTML_HEAD_CUSTOMS_STYLE; + } +#endif + +#if USING_CUSTOMS_HEAD_ELEMENT + //sets a custom element to add to head, like a new style tag + void setCustomsHeadElement(const char* CustomsHeadElement = NULL) + { + _CustomsHeadElement = CustomsHeadElement; + ETM_LOGDEBUG1(F("Set CustomsHeadElement to : "), _CustomsHeadElement); + } + + const char* getCustomsHeadElement() + { + ETM_LOGDEBUG1(F("Get CustomsHeadElement = "), _CustomsHeadElement); + return _CustomsHeadElement; + } +#endif + +#if USING_CORS_FEATURE + void setCORSHeader(const char* CORSHeaders = NULL) + { + _CORS_Header = CORSHeaders; + + ETM_LOGDEBUG1(F("Set CORS Header to : "), _CORS_Header); + } + + const char* getCORSHeader() + { + ETM_LOGDEBUG1(F("Get CORS Header = "), _CORS_Header); + return _CORS_Header; + } +#endif + + ////////////////////////////////////// + private: @@ -287,6 +460,9 @@ class Ethernet_Manager unsigned long configTimeout; bool hadConfigData = false; + + bool isForcedConfigPortal = false; + bool persForcedConfigPortal = false; Ethernet_Configuration Ethernet_Manager_config; @@ -294,7 +470,26 @@ class Ethernet_Manager uint8_t currentBlynkServerIndex = 255; +///////////////////////////////////// + + // Add customs headers from v1.1.0 + +#if USING_CUSTOMS_STYLE + const char* ETM_HTML_HEAD_CUSTOMS_STYLE = NULL; +#endif + +#if USING_CUSTOMS_HEAD_ELEMENT + const char* _CustomsHeadElement = NULL; +#endif + +#if USING_CORS_FEATURE + const char* _CORS_Header = WM_HTTP_CORS_ALLOW_ALL; //"*"; +#endif + + ////////////////////////////////////// + #define RFC952_HOSTNAME_MAXLEN 24 + char RFC952_hostname[RFC952_HOSTNAME_MAXLEN + 1]; void setRFC952_hostname(const char* iHostname = "") @@ -315,6 +510,8 @@ class Ethernet_Manager ETM_LOGWARN1(F("Hostname="), RFC952_hostname); } + + ////////////////////////////////////// char* getRFC952_hostname(const char* iHostname) { @@ -332,36 +529,62 @@ class Ethernet_Manager j++; } } + // no '-' as last char if ( isalnum(iHostname[len - 1]) || (iHostname[len - 1] != '-') ) RFC952_hostname[j] = iHostname[len - 1]; return RFC952_hostname; } + + ////////////////////////////////////// void displayConfigData(Ethernet_Configuration configData) { ETM_LOGWARN3(F("Header="), configData.header, F(", BoardName="), configData.board_name); ETM_LOGWARN1(F("StaticIP="), configData.static_IP); - + +#if USE_DYNAMIC_PARAMETERS for (uint16_t i = 0; i < NUM_MENU_ITEMS; i++) { ETM_LOGINFO3("i=", i, ",id=", myMenuItems[i].id); ETM_LOGINFO1("data=", myMenuItems[i].pdata); - } + } +#endif } + + ////////////////////////////////////// #define ETHERNET_BOARD_TYPE "STM32" #define WM_NO_CONFIG "blank" +#ifndef EEPROM_SIZE + #define EEPROM_SIZE 4096 +#else + #if (EEPROM_SIZE > 4096) + #warning EEPROM_SIZE must be <= 4096. Reset to 4096 + #undef EEPROM_SIZE + #define EEPROM_SIZE 4096 + #endif + #if (EEPROM_SIZE < CONFIG_DATA_SIZE) + #warning EEPROM_SIZE must be > CONFIG_DATA_SIZE. Reset to 512 + #undef EEPROM_SIZE + #define EEPROM_SIZE 512 + #endif +#endif + #ifndef EEPROM_START - #define EEPROM_START 0 //define 256 in DRD + #define EEPROM_START 0 #warning EEPROM_START not defined. Set to 0 +#else + #if (EEPROM_START + DRD_FLAG_DATA_SIZE + CONFIG_DATA_SIZE + FORCED_CONFIG_PORTAL_FLAG_DATA_SIZE > EEPROM_SIZE) + #error EPROM_START + DRD_FLAG_DATA_SIZE + CONFIG_DATA_SIZE + FORCED_CONFIG_PORTAL_FLAG_DATA_SIZE > EEPROM_SIZE. Please adjust. + #endif #endif // Stating positon to store Blynk8266_WM_config -#define ETHERNET_MANAGER_EEPROM_START (EEPROM_START + DRD_FLAG_DATA_SIZE) +#define CONFIG_EEPROM_START (EEPROM_START + DRD_FLAG_DATA_SIZE) int calcChecksum() { @@ -373,44 +596,88 @@ class Ethernet_Manager return checkSum; } - - //Functionality to 'get' and 'put' objects to and from EEPROM. - template< typename T > T &EEPROM_get(int idx, T &t) + +////////////////////////////////////////////// + +#if defined(DATA_EEPROM_BASE) + // For STM32 devices having integrated EEPROM. + #include + #warning STM32 devices have integrated EEPROM. Not using buffered API. +#else + /** + Most STM32 devices don't have an integrated EEPROM. To emulate a EEPROM, the STM32 Arduino core emulated + the operation of an EEPROM with the help of the embedded flash. + Writing to a flash is very expensive operation, since a whole flash page needs to be written, even if you only + want to access the flash byte-wise. + The STM32 Arduino core provides a buffered access API to the emulated EEPROM. The library has allocated the + buffer even if you don't use the buffered API, so it's strongly suggested to use the buffered API anyhow. + */ + #include // https://github.com/khoih-prog/FlashStorage_STM32 + #warning STM32 devices have no integrated EEPROM. Using buffered API with FlashStorage_STM32 library +#endif // #if defined(DATA_EEPROM_BASE) +////////////////////////////////////////////// + + void setForcedCP(bool isPersistent) { - int e = idx; - uint8_t *ptr = (uint8_t *) &t; + uint32_t readForcedConfigPortalFlag = isPersistent? FORCED_PERS_CONFIG_PORTAL_FLAG_DATA : FORCED_CONFIG_PORTAL_FLAG_DATA; + + ETM_LOGERROR(isPersistent ? F("setForcedCP Persistent") : F("setForcedCP non-Persistent")); - for (uint16_t count = sizeof(T) ; count ; --count, ++e) - { - *ptr++ = eeprom_buffered_read_byte(e); - } - return t; + EEPROM.put(CONFIG_EEPROM_START + CONFIG_DATA_SIZE, readForcedConfigPortalFlag); } + + ////////////////////////////////////////////// + + void clearForcedCP() + { + EEPROM.put(CONFIG_EEPROM_START + CONFIG_DATA_SIZE, 0); + } + + ////////////////////////////////////////////// - template< typename T > const T &EEPROM_put(int idx, const T &t) + bool isForcedCP() { - int e = idx; - const uint8_t *ptr = (const uint8_t *) &t; + uint32_t readForcedConfigPortalFlag; - for (uint16_t count = sizeof(T) ; count ; --count, ++e) - { - eeprom_buffered_write_byte(e, *ptr++); + // Return true if forced CP (0xDEADBEEF read at offset EPROM_START + DRD_FLAG_DATA_SIZE + CONFIG_DATA_SIZE) + // => set flag noForcedConfigPortal = false + EEPROM.get(CONFIG_EEPROM_START + CONFIG_DATA_SIZE, readForcedConfigPortalFlag); + + // Return true if forced CP (0xDEADBEEF read at offset EPROM_START + DRD_FLAG_DATA_SIZE + CONFIG_DATA_SIZE) + // => set flag noForcedConfigPortal = false + if (readForcedConfigPortalFlag == FORCED_CONFIG_PORTAL_FLAG_DATA) + { + persForcedConfigPortal = false; + return true; + } + else if (readForcedConfigPortalFlag == FORCED_PERS_CONFIG_PORTAL_FLAG_DATA) + { + persForcedConfigPortal = true; + return true; + } + else + { + return false; } - - eeprom_buffer_flush(); - - return t; } - - bool checkDynamicData(void) + + ////////////////////////////////////////////// + +#if USE_DYNAMIC_PARAMETERS + + bool checkDynamicData() { + // It's too bad that emulate EEPROM.read()/write() can only deal with bytes. + // Have to read/write each byte. To rewrite the library + int checkSum = 0; int readCheckSum; + uint16_t offset = CONFIG_EEPROM_START + sizeof(Ethernet_Manager_config) + FORCED_CONFIG_PORTAL_FLAG_DATA_SIZE; + #define BUFFER_LEN 128 - - uint16_t offset = ETHERNET_MANAGER_EEPROM_START + sizeof(Ethernet_Manager_config); - + char readBuffer[BUFFER_LEN + 1]; + // Find the longest pdata, then dynamically allocate buffer. Remember to free when done // This is used to store tempo data to calculate checksum to see of data is valid // We dont like to destroy myMenuItems[i].pdata with invalid data @@ -427,23 +694,29 @@ class Ethernet_Manager for (uint16_t i = 0; i < NUM_MENU_ITEMS; i++) { - char* _pointer = myMenuItems[i].pdata; - totalDataSize += myMenuItems[i].maxlen; + char* _pointer = readBuffer; - // Actual size of pdata is [maxlen + 1] - memset(myMenuItems[i].pdata, 0, myMenuItems[i].maxlen + 1); + // Prepare buffer, more than enough + memset(readBuffer, 0, sizeof(readBuffer)); + + // Read more than necessary, but OK and easier to code + EEPROM.get(offset, readBuffer); + // NULL terminated + readBuffer[myMenuItems[i].maxlen] = 0; + + ETM_LOGDEBUG3(F("ChkCrR:pdata="), readBuffer, F(",len="), myMenuItems[i].maxlen); - for (uint16_t j = 0; j < myMenuItems[i].maxlen; j++,_pointer++,offset++) - { - *_pointer = eeprom_buffered_read_byte(offset); - + for (uint16_t j = 0; j < myMenuItems[i].maxlen; j++,_pointer++) + { checkSum += *_pointer; - } + } + + offset += myMenuItems[i].maxlen; } EEPROM.get(offset, readCheckSum); - - ETM_LOGINFO3(F("ChkCrR:CrCCSum=0x"), String(checkSum, HEX), F(",CrRCSum=0x"), String(readCheckSum, HEX)); + + ETM_LOGERROR3(F("ChkCrR:CrCCsum=0x"), String(checkSum, HEX), F(",CrRCsum=0x"), String(readCheckSum, HEX)); if ( checkSum != readCheckSum) { @@ -453,14 +726,19 @@ class Ethernet_Manager return true; } - bool EEPROM_getDynamicData(void) - { - int readCheckSum; + ////////////////////////////////////////////// + + bool EEPROM_getDynamicData() + { int checkSum = 0; - uint16_t offset = ETHERNET_MANAGER_EEPROM_START + sizeof(Ethernet_Manager_config); - - totalDataSize = sizeof(Ethernet_Manager_config) + sizeof(readCheckSum); + int readCheckSum; + totalDataSize = sizeof(Ethernet_Manager_config) + sizeof(readCheckSum); + + // Using FORCED_CONFIG_PORTAL_FLAG_DATA + //offset += FORCED_CONFIG_PORTAL_FLAG_DATA_SIZE; + uint16_t offset = CONFIG_EEPROM_START + sizeof(Ethernet_Manager_config) + FORCED_CONFIG_PORTAL_FLAG_DATA_SIZE; + for (uint16_t i = 0; i < NUM_MENU_ITEMS; i++) { char* _pointer = myMenuItems[i].pdata; @@ -469,69 +747,111 @@ class Ethernet_Manager // Actual size of pdata is [maxlen + 1] memset(myMenuItems[i].pdata, 0, myMenuItems[i].maxlen + 1); - for (uint16_t j = 0; j < myMenuItems[i].maxlen; j++,_pointer++,offset++) + for (uint16_t j = 0; j < myMenuItems[i].maxlen; j++, _pointer++, offset++) { - *_pointer = eeprom_buffered_read_byte(offset); - + *_pointer = EEPROM.read(offset); checkSum += *_pointer; - } + } } - - EEPROM_get(offset, readCheckSum); - - ETM_LOGINFO3(F("CrCCSum=0x"), String(checkSum, HEX), F(",CrRCSum=0x"), String(readCheckSum, HEX)); + + EEPROM.get(offset, readCheckSum); + + ETM_LOGERROR3(F("CrCCSum="), String(checkSum, HEX), F(",CrRCSum="), String(readCheckSum, HEX)); if ( checkSum != readCheckSum) { return false; } - + return true; } - - void EEPROM_putDynamicData(void) + + ////////////////////////////////////////////// + + void EEPROM_putDynamicData() { + // It's too bad that emulate EEPROM.read()/writ() can only deal with bytes. + // Have to read/write each byte. To rewrite the library int checkSum = 0; - uint16_t offset = ETHERNET_MANAGER_EEPROM_START + sizeof(Ethernet_Manager_config); - + + // Using FORCED_CONFIG_PORTAL_FLAG_DATA + //offset += FORCED_CONFIG_PORTAL_FLAG_DATA_SIZE; + uint16_t offset = CONFIG_EEPROM_START + sizeof(Ethernet_Manager_config) + FORCED_CONFIG_PORTAL_FLAG_DATA_SIZE; + for (uint16_t i = 0; i < NUM_MENU_ITEMS; i++) { char* _pointer = myMenuItems[i].pdata; - - //ETM_LOGINFO3(F("pdata="), myMenuItems[i].pdata, F(",len="), myMenuItems[i].maxlen); - + + ETM_LOGDEBUG3(F("pdata="), myMenuItems[i].pdata, F(",len="), myMenuItems[i].maxlen); + for (uint16_t j = 0; j < myMenuItems[i].maxlen; j++,_pointer++,offset++) { - //EEPROM.write(offset, *_pointer); - eeprom_buffered_write_byte(offset, *_pointer); + EEPROM.write(offset, *_pointer); checkSum += *_pointer; - } - eeprom_buffer_flush(); + } } - - EEPROM_put(offset, checkSum); - eeprom_buffer_flush(); + + EEPROM.put(offset, checkSum); + + ETM_LOGERROR1(F("CrCCSum=0x"), String(checkSum, HEX)); - //EEPROM.commit(); + EEPROM.commit(); + } + +#endif // #if USE_DYNAMIC_PARAMETERS + + ////////////////////////////////////////////// + + void NULLTerminateConfig() + { + //#define HEADER_MAX_LEN 16 + //#define STATIC_IP_MAX_LEN 16 + //#define BOARD_NAME_MAX_LEN 24 - ETM_LOGINFO1(F("CrCCSum=0x"), String(checkSum, HEX)); + // NULL Terminating to be sure + Ethernet_Manager_config.header [HEADER_MAX_LEN - 1] = 0; + Ethernet_Manager_config.static_IP [STATIC_IP_MAX_LEN - 1] = 0; + Ethernet_Manager_config.board_name[BOARD_NAME_MAX_LEN - 1] = 0; + } + + ////////////////////////////////////////////// + + bool EEPROM_get() + { + EEPROM.get(CONFIG_EEPROM_START, Ethernet_Manager_config); + + NULLTerminateConfig(); + + return true; } + ////////////////////////////////////////////// + + void EEPROM_put() + { + EEPROM.put(CONFIG_EEPROM_START, Ethernet_Manager_config); + } + + ////////////////////////////////////////////// + void saveConfigData() { int calChecksum = calcChecksum(); Ethernet_Manager_config.checkSum = calChecksum; - ETM_LOGINFO1(F("Save,WCSum=0x"), String(calChecksum, HEX)); - - //displayConfigData(); - - EEPROM_put(ETHERNET_MANAGER_EEPROM_START, Ethernet_Manager_config); + ETM_LOGERROR5(F("SaveEEPROM,Sz="), EEPROM.length(), F(",DataSz="), totalDataSize, F(",WCSum=0x"), String(calChecksum, HEX)); + + EEPROM_put(); + +#if USE_DYNAMIC_PARAMETERS EEPROM_putDynamicData(); +#endif } - void loadAndSaveDefaultConfigData(void) + ////////////////////////////////////////////// + + void loadAndSaveDefaultConfigData() { // Load Default Config Data from Sketch memcpy(&Ethernet_Manager_config, &defaultConfig, sizeof(Ethernet_Manager_config)); @@ -539,98 +859,135 @@ class Ethernet_Manager // Including config and dynamic data, and assume valid saveConfigData(); - + ETM_LOGDEBUG(F("======= Start Loaded Config Data =======")); - displayConfigData(Ethernet_Manager_config); + displayConfigData(Ethernet_Manager_config); } + ////////////////////////////////////////////// + bool getConfigData() { - bool dynamicDataValid; + bool dynamicDataValid = true; + int calChecksum; hadConfigData = false; - - EEPROM.begin(); - EEPROM.get(ETHERNET_MANAGER_EEPROM_START, Ethernet_Manager_config); - - ETM_LOGINFO(F("======= Start Stored Config Data =======")); - displayConfigData(Ethernet_Manager_config); - - int calChecksum = calcChecksum(); - ETM_LOGWARN3(F("CCSum=0x"), String(calChecksum, HEX), - F(",RCSum=0x"), String(Ethernet_Manager_config.checkSum, HEX)); - +#if defined(DATA_EEPROM_BASE) + EEPROM.begin(); +#endif + + // Use new LOAD_DEFAULT_CONFIG_DATA logic if (LOAD_DEFAULT_CONFIG_DATA) - { - // Load default dynamicData, if checkSum OK => valid data => load - // otherwise, use default in sketch and just assume it's OK - if (checkDynamicData()) - { - ETM_LOGDEBUG(F("Valid Stored Dynamic Data")); + { + // Load Config Data from Sketch + loadAndSaveDefaultConfigData(); - EEPROM_getDynamicData(); - dynamicDataValid = true; - } - else - { - ETM_LOGWARN(F("Invalid Stored Dynamic Data. Ignored")); - dynamicDataValid = false; - } + // Don't need Config Portal anymore + return true; } else - { - dynamicDataValid = EEPROM_getDynamicData(); - } - + { + // Load stored config data from EEPROM + ETM_LOGERROR1(F("EEPROMsz:"), EEPROM_SIZE); + ETM_LOGERROR1(F("EEPROM Length():"), EEPROM.length()); + + // Get config data + EEPROM_get(); + + // Verify ChkSum + calChecksum = calcChecksum(); + + ETM_LOGERROR3(F("CCSum=0x"), String(calChecksum, HEX), + F(",RCSum=0x"), String(Ethernet_Manager_config.checkSum, HEX)); + +#if USE_DYNAMIC_PARAMETERS + // Load stored dynamic data from EEPROM + dynamicDataValid = checkDynamicData(); +#endif + + // If checksum = 0 => FlashStorage has been cleared (by uploading new FW, etc) => force to CP + if ( (calChecksum != 0) && (calChecksum == Ethernet_Manager_config.checkSum) ) + { + if (dynamicDataValid) + { +#if USE_DYNAMIC_PARAMETERS + // CkSum verified, Now get valid config/ dynamic data + EEPROM_getDynamicData(); + + ETM_LOGERROR(F("Valid Stored Dynamic Data")); +#endif + ETM_LOGERROR(F("======= Start Stored Config Data =======")); + displayConfigData(Ethernet_Manager_config); + + // Don't need Config Portal anymore + return true; + } + else + { + // Invalid Stored config data => Config Portal + ETM_LOGERROR(F("Invalid Stored Dynamic Data. Load default from Sketch")); + + // Load Default Config Data from Sketch, better than just "blank" + loadAndSaveDefaultConfigData(); + + // Need Config Portal here as data can be just dummy + // Even if you don't open CP, you're OK on next boot if your default config data is valid + return false; + } + } + } + if ( (strncmp(Ethernet_Manager_config.header, ETHERNET_BOARD_TYPE, strlen(ETHERNET_BOARD_TYPE)) != 0) || - (calChecksum != Ethernet_Manager_config.checkSum) || !dynamicDataValid ) + (calChecksum != Ethernet_Manager_config.checkSum) || !dynamicDataValid || + ( (calChecksum == 0) && (Ethernet_Manager_config.checkSum == 0) ) ) { // Including Credentials CSum - ETM_LOGINFO1(F("EEPROM Datasz="), totalDataSize); - - // doesn't have any configuration + ETM_LOGERROR1(F("InitCfgFile,sz="), sizeof(Ethernet_Manager_config)); + + // doesn't have any configuration if (LOAD_DEFAULT_CONFIG_DATA) { memcpy(&Ethernet_Manager_config, &defaultConfig, sizeof(Ethernet_Manager_config)); } else - { + { memset(&Ethernet_Manager_config, 0, sizeof(Ethernet_Manager_config)); +#if USE_DYNAMIC_PARAMETERS for (uint16_t i = 0; i < NUM_MENU_ITEMS; i++) { // Actual size of pdata is [maxlen + 1] memset(myMenuItems[i].pdata, 0, myMenuItems[i].maxlen + 1); } - - // Including Credentials CSum - ETM_LOGINFO1(F("InitEEPROM, Datasz="), totalDataSize); - - // doesn't have any configuration +#endif + strcpy(Ethernet_Manager_config.static_IP, WM_NO_CONFIG); strcpy(Ethernet_Manager_config.board_name, WM_NO_CONFIG); - + +#if USE_DYNAMIC_PARAMETERS for (uint16_t i = 0; i < NUM_MENU_ITEMS; i++) { strncpy(myMenuItems[i].pdata, WM_NO_CONFIG, myMenuItems[i].maxlen); } +#endif } - + strcpy(Ethernet_Manager_config.header, ETHERNET_BOARD_TYPE); - + +#if USE_DYNAMIC_PARAMETERS for (uint16_t i = 0; i < NUM_MENU_ITEMS; i++) { ETM_LOGDEBUG3(F("g:myMenuItems["), i, F("]="), myMenuItems[i].pdata ); } - +#endif + // Don't need Ethernet_Manager_config.checkSum = 0; - EEPROM.put(ETHERNET_MANAGER_EEPROM_START, Ethernet_Manager_config); - EEPROM_putDynamicData(); - - return false; + saveConfigData(); + + return false; } else { @@ -640,172 +997,269 @@ class Ethernet_Manager return true; } + ////////////////////////////////////////////// + // NEW void createHTML(String& root_html_template) { String pitem; - root_html_template = String(ETM_HTML_HEAD); - - if (NUM_MENU_ITEMS > 0) + root_html_template = ETM_HTML_HEAD_START; + + #if USING_CUSTOMS_STYLE + // Using Customs style when not NULL + if (ETM_HTML_HEAD_CUSTOMS_STYLE) + root_html_template += ETM_HTML_HEAD_CUSTOMS_STYLE; + else + root_html_template += ETM_HTML_HEAD_STYLE; + #else + root_html_template += ETM_HTML_HEAD_STYLE; + #endif + + #if USING_CUSTOMS_HEAD_ELEMENT + if (_CustomsHeadElement) + root_html_template += _CustomsHeadElement; + #endif + + root_html_template += String(ETM_HTML_HEAD_END) + ETM_FLDSET_START; + +#if USE_DYNAMIC_PARAMETERS + for (uint16_t i = 0; i < NUM_MENU_ITEMS; i++) { - root_html_template += String(ETM_FLDSET_START); - - for (uint16_t i = 0; i < NUM_MENU_ITEMS; i++) - { - pitem = String(ETM_HTML_PARAM); + pitem = String(ETM_HTML_PARAM); - pitem.replace("{b}", myMenuItems[i].displayName); - pitem.replace("{v}", myMenuItems[i].id); - pitem.replace("{i}", myMenuItems[i].id); - - root_html_template += pitem; - } - - root_html_template += String(ETM_FLDSET_END); + pitem.replace("{b}", myMenuItems[i].displayName); + pitem.replace("{v}", myMenuItems[i].id); + pitem.replace("{i}", myMenuItems[i].id); + + root_html_template += pitem; } +#endif - root_html_template += String(ETM_HTML_BUTTON) + String(ETM_HTML_SCRIPT); - - if (NUM_MENU_ITEMS > 0) - { - for (uint16_t i = 0; i < NUM_MENU_ITEMS; i++) - { - pitem = String(ETM_HTML_SCRIPT_ITEM); - - pitem.replace("{d}", myMenuItems[i].id); - - root_html_template += pitem; - } + root_html_template += String(ETM_FLDSET_END) + ETM_HTML_BUTTON + ETM_HTML_SCRIPT; + +#if USE_DYNAMIC_PARAMETERS + for (uint16_t i = 0; i < NUM_MENU_ITEMS; i++) + { + pitem = String(ETM_HTML_SCRIPT_ITEM); + + pitem.replace("{d}", myMenuItems[i].id); + + root_html_template += pitem; } +#endif + + root_html_template += String(ETM_HTML_SCRIPT_END) + ETM_HTML_END; + + return; + } + + ////////////////////////////////////////////// + + void serverSendHeaders() + { + ETM_LOGDEBUG3(F("serverSendHeaders:WM_HTTP_CACHE_CONTROL:"), WM_HTTP_CACHE_CONTROL, "=", WM_HTTP_NO_STORE); + server.sendHeader(WM_HTTP_CACHE_CONTROL, WM_HTTP_NO_STORE); - root_html_template += String(ETM_HTML_SCRIPT_END) + String(ETM_HTML_END); +#if USING_CORS_FEATURE + // New from v1.2.0, for configure CORS Header, default to WM_HTTP_CORS_ALLOW_ALL = "*" + ETM_LOGDEBUG3(F("serverSendHeaders:WM_HTTP_CORS:"), WM_HTTP_CORS, " : ", _CORS_Header); + server.sendHeader(WM_HTTP_CORS, _CORS_Header); +#endif + + ETM_LOGDEBUG3(F("serverSendHeaders:WM_HTTP_PRAGMA:"), WM_HTTP_PRAGMA, " : ", WM_HTTP_NO_CACHE); + server.sendHeader(WM_HTTP_PRAGMA, WM_HTTP_NO_CACHE); - return; + ETM_LOGDEBUG3(F("serverSendHeaders:WM_HTTP_EXPIRES:"), WM_HTTP_EXPIRES, " : ", "-1"); + server.sendHeader(WM_HTTP_EXPIRES, "-1"); } - //// + + ////////////////////////////////////////////// void handleRequest() { - String key = server.arg("key"); - String value = server.arg("value"); + //if (server) + { + String key = server.arg("key"); + String value = server.arg("value"); - //static int number_items_Updated = 0; - static int number_items_Updated = -1; + static int number_items_Updated = 0; - if (key == "" && value == "") - { - String result; - createHTML(result); + if (key == "" && value == "") + { + // New from v1.2.0 + serverSendHeaders(); + ////// + + String result; + createHTML(result); + + ETM_LOGDEBUG1(F("h:Repl:"), result); + + // Reset configTimeout to stay here until finished. + configTimeout = 0; + + if ( RFC952_hostname[0] != 0 ) + { + // Replace only if Hostname is valid + result.replace("Ethernet_STM32_Manager", RFC952_hostname); + } + else if ( Ethernet_Manager_config.board_name[0] != 0 ) + { + // Or replace only if board_name is valid. Otherwise, keep intact + result.replace("Ethernet_STM32_Manager", Ethernet_Manager_config.board_name); + } - ETM_LOGDEBUG1(F("h:Repl:"), result); + result.replace("[[ip]]", Ethernet_Manager_config.static_IP); + result.replace("[[nm]]", Ethernet_Manager_config.board_name); + +#if USE_DYNAMIC_PARAMETERS + for (uint16_t i = 0; i < NUM_MENU_ITEMS; i++) + { + String toChange = String("[[") + myMenuItems[i].id + "]]"; + result.replace(toChange, myMenuItems[i].pdata); + + ETM_LOGDEBUG3(F("h1:myMenuItems["), i, F("]="), myMenuItems[i].pdata ); + } +#endif - // Reset configTimeout to stay here until finished. - configTimeout = 0; + ETM_LOGDEBUG1(F("h:HTML page size:"), result.length()); + ETM_LOGDEBUG1(F("h:HTML="), result); + + server.send(200, WM_HTTP_HEAD_TEXT_HTML, result); + + return; + } - if ( RFC952_hostname[0] != 0 ) + if (number_items_Updated == 0) { - // Replace only if Hostname is valid - result.replace("Ethernet_Teensy_Manager", RFC952_hostname); + memset(&Ethernet_Manager_config, 0, sizeof(Ethernet_Manager_config)); + strcpy(Ethernet_Manager_config.header, ETHERNET_BOARD_TYPE); } - else if ( Ethernet_Manager_config.board_name[0] != 0 ) + +#if USE_DYNAMIC_PARAMETERS + if (!menuItemUpdated) { - // Or replace only if board_name is valid. Otherwise, keep intact - result.replace("Ethernet_Teensy_Manager", Ethernet_Manager_config.board_name); - } + // Don't need to free + menuItemUpdated = new bool[NUM_MENU_ITEMS]; + + if (menuItemUpdated) + { + for (uint16_t i = 0; i < NUM_MENU_ITEMS; i++) + { + // To flag item is not yet updated + menuItemUpdated[i] = false; + } + + ETM_LOGDEBUG(F("h: Init menuItemUpdated" )); + } + else + { + ETM_LOGERROR(F("h: Error can't alloc memory for menuItemUpdated" )); + } + } +#endif - result.replace("[[ip]]", Ethernet_Manager_config.static_IP); - result.replace("[[nm]]", Ethernet_Manager_config.board_name); + static bool ip_Updated = false; + static bool nm_Updated = false; - for (uint16_t i = 0; i < NUM_MENU_ITEMS; i++) + if (key == String("ip")) + { + ETM_LOGDEBUG(F("h:repl ip")); + + if (!ip_Updated) + { + ip_Updated = true; + number_items_Updated++; + } + + if (strlen(value.c_str()) < sizeof(Ethernet_Manager_config.static_IP) - 1) + strcpy(Ethernet_Manager_config.static_IP, value.c_str()); + else + strncpy(Ethernet_Manager_config.static_IP, value.c_str(), sizeof(Ethernet_Manager_config.static_IP) - 1); + } + else if (key == String("nm")) { - String toChange = String("[[") + myMenuItems[i].id + "]]"; - result.replace(toChange, myMenuItems[i].pdata); - - ETM_LOGDEBUG3(F("h1:myMenuItems["), i, F("]="), myMenuItems[i].pdata ); + ETM_LOGDEBUG(F("h:repl nm")); + + if (!nm_Updated) + { + nm_Updated = true; + number_items_Updated++; + } + + if (strlen(value.c_str()) < sizeof(Ethernet_Manager_config.board_name) - 1) + strcpy(Ethernet_Manager_config.board_name, value.c_str()); + else + strncpy(Ethernet_Manager_config.board_name, value.c_str(), sizeof(Ethernet_Manager_config.board_name) - 1); } - - server.send(200, "text/html", result); - return; - } - - if (number_items_Updated < 0) - { - number_items_Updated = 0; - memset(&Ethernet_Manager_config, 0, sizeof(Ethernet_Manager_config)); - strcpy(Ethernet_Manager_config.header, ETHERNET_BOARD_TYPE); - } - - ETM_LOGINFO1(F("h:items updated ="), number_items_Updated); - ETM_LOGINFO3(F("h:key ="), key, ", value =", value); - - if (key == String("ip")) - { - ETM_LOGINFO(F("h:ip")); - - number_items_Updated++; - if (strlen(value.c_str()) < sizeof(Ethernet_Manager_config.static_IP) - 1) - strcpy(Ethernet_Manager_config.static_IP, value.c_str()); +#if USE_DYNAMIC_PARAMETERS else - strncpy(Ethernet_Manager_config.static_IP, value.c_str(), sizeof(Ethernet_Manager_config.static_IP) - 1); - } - else if (key == String("nm")) - { - ETM_LOGINFO(F("h:nm")); - - number_items_Updated++; - if (strlen(value.c_str()) < sizeof(Ethernet_Manager_config.board_name) - 1) - strcpy(Ethernet_Manager_config.board_name, value.c_str()); - else - strncpy(Ethernet_Manager_config.board_name, value.c_str(), sizeof(Ethernet_Manager_config.board_name) - 1); - } + { + for (uint16_t i = 0; i < NUM_MENU_ITEMS; i++) + { + if (key == myMenuItems[i].id) + { + ETM_LOGDEBUG3(F("h:"), myMenuItems[i].id, F("="), value.c_str() ); + + if (!menuItemUpdated[i]) + { + menuItemUpdated[i] = true; + number_items_Updated++; + } + + // Actual size of pdata is [maxlen + 1] + memset(myMenuItems[i].pdata, 0, myMenuItems[i].maxlen + 1); + + if ((int) strlen(value.c_str()) < myMenuItems[i].maxlen) + strcpy(myMenuItems[i].pdata, value.c_str()); + else + strncpy(myMenuItems[i].pdata, value.c_str(), myMenuItems[i].maxlen); + + break; + } + } + } +#endif + + ETM_LOGDEBUG1(F("h:items updated ="), number_items_Updated); + ETM_LOGDEBUG3(F("h:key ="), key, ", value =", value); - //ETM_LOGINFO(F("h:OK")); + server.send(200, WM_HTTP_HEAD_TEXT_HTML, "OK"); - for (uint16_t i = 0; i < NUM_MENU_ITEMS; i++) - { - if (key == myMenuItems[i].id) +#if USE_DYNAMIC_PARAMETERS + if (number_items_Updated == NUM_CONFIGURABLE_ITEMS + NUM_MENU_ITEMS) +#else + if (number_items_Updated == NUM_CONFIGURABLE_ITEMS) +#endif { - //ETM_LOGDEBUG3(F("h:"), myMenuItems[i].id, F("="), value.c_str() ); - number_items_Updated++; + ETM_LOGERROR(F("h:Updating EEPROM. Please wait for reset")); - // Actual size of pdata is [maxlen + 1] - memset(myMenuItems[i].pdata, 0, myMenuItems[i].maxlen + 1); + saveConfigData(); + + // Done with CP, Clear CP Flag here if forced + if (isForcedConfigPortal) + clearForcedCP(); - if ((int) strlen(value.c_str()) < myMenuItems[i].maxlen) - strcpy(myMenuItems[i].pdata, value.c_str()); - else - strncpy(myMenuItems[i].pdata, value.c_str(), myMenuItems[i].maxlen); - - ETM_LOGINFO3(F("h2:myMenuItems["), i, F("]="), myMenuItems[i].pdata ); + ETM_LOGWARN(F("h:Rst")); + + // Delay then reset after save data + delay(1000); + resetFunc(); } } - - server.send(200, "text/html", "OK"); - - // NEW - if (number_items_Updated == NUM_CONFIGURABLE_ITEMS + NUM_MENU_ITEMS) - { - ETM_LOGWARN(F("h:Updating EEPROM. Please wait for reset")); - - saveConfigData(); + } - ETM_LOGWARN(F("h:Rst")); + ////////////////////////////////////////////// - // Delay then reset after save data - //delay(200); - resetFunc(); - } - } +#ifndef CONFIG_TIMEOUT + #warning Default CONFIG_TIMEOUT = 60s + #define CONFIG_TIMEOUT 60000L +#endif void startConfigurationMode() { -#define CONFIG_TIMEOUT 60000L - - // turn the LED_BUILTIN ON to tell us we are in configuration mode. - //digitalWrite(LED_BUILTIN, LED_ON); - //ETM_LOGWARN1(F("CfgIP="), Ethernet.localIP() ); //See https://stackoverflow.com/questions/39803135/c-unresolved-overloaded-function-type?rq=1 @@ -816,12 +1270,21 @@ class Ethernet_Manager // If there is no saved config Data, stay in config mode forever until having config Data. // or SSID, PW, Server,Token ="nothing" if (hadConfigData) + { configTimeout = millis() + CONFIG_TIMEOUT; + + ETM_LOGDEBUG3(F("s:millis() = "), millis(), F(", configTimeout = "), configTimeout); + } else - configTimeout = 0; + { + configTimeout = 0; + ETM_LOGDEBUG(F("s:configTimeout = 0")); + } configuration_mode = true; } + + ////////////////////////////////////////////// bool connectEthernet() { @@ -882,6 +1345,8 @@ class Ethernet_Manager return ethernetConnected; } + + ////////////////////////////////////////////// byte* SelectMacAddress(const byte mac[]) {