├── docker ├── BUILD_DOCKER_IMAGE.sh ├── FORCE_REBUILD_DOCKER_IMAGE.sh ├── RUN_PLATFORMIO.sh ├── Dockerfile └── README.md ├── docs ├── img │ ├── img01.png │ ├── img02.png │ ├── img03.png │ ├── img04.png │ ├── img05.png │ ├── img06.png │ ├── img07.png │ └── img08.png └── README.md ├── lib ├── WebPages │ ├── Test1Page.cpp │ ├── SystemRestart.cpp │ ├── BackupConfiguration.cpp │ ├── MaintenancePage.cpp │ ├── RestoreConfiguration.cpp │ ├── ResetFirmware.cpp │ ├── FirmwareUploadSuccess.cpp │ ├── FileConfigUpload.cpp │ ├── JsonUtil.cpp │ ├── WebPages.h │ ├── SetAPI.cpp │ ├── InfoPage.cpp │ ├── FirmwareUpload.cpp │ ├── SaveConfig.cpp │ ├── RootPage.cpp │ └── SetupPage.cpp ├── App │ ├── DeviceConfig.hpp │ ├── DefaultAppConfig.h │ ├── ConfigAttributes.hpp │ └── App.hpp ├── OtaHandler │ ├── OtaHandler.hpp │ └── OtaHandler.cpp ├── WebHandler │ ├── WebHandler.hpp │ └── WebHandler.cpp ├── AsyncPing │ ├── library.properties │ ├── keywords.txt │ ├── readme.md │ ├── src │ │ ├── AsyncPing.h │ │ └── AsyncPing.cpp │ ├── examples │ │ ├── ping │ │ │ └── ping.ino │ │ └── ping_interval │ │ │ └── ping_interval.ino │ └── LICENSE.txt ├── LinkedList │ ├── LinkedList.hpp │ └── LinkedList.cpp ├── MqttHandler │ ├── MqttHandler.hpp │ └── MqttHandler.cpp ├── Util │ ├── Util.hpp │ └── Util.cpp ├── WifiHandler │ ├── WifiHandler.hpp │ └── WifiHandler.cpp ├── TuringPiHandler │ ├── TuringPiHandler.hpp │ └── TuringPiHandler.cpp ├── readme.txt ├── MicroJson │ ├── MicroJson.hpp │ └── MicroJson.cpp ├── uzlib │ ├── uzlib_conf.h │ ├── defl_static.h │ ├── tinfgzip.c │ ├── uzlib.h │ ├── defl_static.c │ └── tinflate.c └── TelnetStream │ ├── TelnetStream.h │ └── TelnetStream.cpp ├── firmware ├── firmware-0.10.5.d1_mini.bin.gz ├── firmware-0.11.4.d1_mini.bin.gz ├── firmware-0.12.1.d1_mini.bin.gz ├── firmware-0.8.2.d1_mini.bin.gz ├── firmware-0.9.1.d1_mini.bin.gz ├── USB_UPLOAD.sh ├── firmware-0.10.5.d1_mini_2m.bin.gz ├── firmware-0.11.4.d1_mini_2m.bin.gz ├── firmware-0.12.1.d1_mini_2m.bin.gz ├── firmware-0.8.2.d1_mini_2m.bin.gz ├── firmware-0.8.2.d1_mini_pro.bin.gz ├── firmware-0.9.1.d1_mini_2m.bin.gz ├── firmware-0.9.1.d1_mini_pro.bin.gz ├── firmware-0.10.5.d1_mini_lite.bin.gz ├── firmware-0.10.5.d1_mini_pro.bin.gz ├── firmware-0.11.4.d1_mini_lite.bin.gz ├── firmware-0.11.4.d1_mini_pro.bin.gz ├── firmware-0.12.1.d1_mini_lite.bin.gz ├── firmware-0.12.1.d1_mini_pro.bin.gz ├── firmware-0.8.2.d1_mini_lite.bin.gz ├── firmware-0.9.1.d1_mini_lite.bin.gz ├── OTA_UPLOAD.sh └── README.md ├── config └── Development.h ├── .gitignore ├── boards └── d1_mini_2m.json ├── include └── html │ ├── header2_gz.h │ ├── header3_gz.h │ ├── favicon_ico.h │ ├── footer_gz.h │ ├── maintenance.h │ └── setup.h ├── extra_script.py ├── src └── main.cpp ├── platformio.ini ├── README.md ├── CHANGES.md └── LICENSE /docker/BUILD_DOCKER_IMAGE.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | docker build -t platformio . 3 | -------------------------------------------------------------------------------- /docker/FORCE_REBUILD_DOCKER_IMAGE.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | docker build --no-cache -t platformio . 3 | -------------------------------------------------------------------------------- /docs/img/img01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thorsten-l/ESP8266-TuringPi-WiFi-Controller/HEAD/docs/img/img01.png -------------------------------------------------------------------------------- /docs/img/img02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thorsten-l/ESP8266-TuringPi-WiFi-Controller/HEAD/docs/img/img02.png -------------------------------------------------------------------------------- /docs/img/img03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thorsten-l/ESP8266-TuringPi-WiFi-Controller/HEAD/docs/img/img03.png -------------------------------------------------------------------------------- /docs/img/img04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thorsten-l/ESP8266-TuringPi-WiFi-Controller/HEAD/docs/img/img04.png -------------------------------------------------------------------------------- /docs/img/img05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thorsten-l/ESP8266-TuringPi-WiFi-Controller/HEAD/docs/img/img05.png -------------------------------------------------------------------------------- /docs/img/img06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thorsten-l/ESP8266-TuringPi-WiFi-Controller/HEAD/docs/img/img06.png -------------------------------------------------------------------------------- /docs/img/img07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thorsten-l/ESP8266-TuringPi-WiFi-Controller/HEAD/docs/img/img07.png -------------------------------------------------------------------------------- /docs/img/img08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thorsten-l/ESP8266-TuringPi-WiFi-Controller/HEAD/docs/img/img08.png -------------------------------------------------------------------------------- /lib/WebPages/Test1Page.cpp: -------------------------------------------------------------------------------- 1 | #include "WebPages.h" 2 | #include 3 | #include 4 | 5 | void handleTest1Page() 6 | { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /firmware/firmware-0.10.5.d1_mini.bin.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thorsten-l/ESP8266-TuringPi-WiFi-Controller/HEAD/firmware/firmware-0.10.5.d1_mini.bin.gz -------------------------------------------------------------------------------- /firmware/firmware-0.11.4.d1_mini.bin.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thorsten-l/ESP8266-TuringPi-WiFi-Controller/HEAD/firmware/firmware-0.11.4.d1_mini.bin.gz -------------------------------------------------------------------------------- /firmware/firmware-0.12.1.d1_mini.bin.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thorsten-l/ESP8266-TuringPi-WiFi-Controller/HEAD/firmware/firmware-0.12.1.d1_mini.bin.gz -------------------------------------------------------------------------------- /firmware/firmware-0.8.2.d1_mini.bin.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thorsten-l/ESP8266-TuringPi-WiFi-Controller/HEAD/firmware/firmware-0.8.2.d1_mini.bin.gz -------------------------------------------------------------------------------- /firmware/firmware-0.9.1.d1_mini.bin.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thorsten-l/ESP8266-TuringPi-WiFi-Controller/HEAD/firmware/firmware-0.9.1.d1_mini.bin.gz -------------------------------------------------------------------------------- /firmware/USB_UPLOAD.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | $HOME/.platformio/packages/tool-esptool/esptool -cd ck -cb 115200 \ 3 | -cp /dev/cu.SLAB_USBtoUART -cf firmware.bin 4 | -------------------------------------------------------------------------------- /firmware/firmware-0.10.5.d1_mini_2m.bin.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thorsten-l/ESP8266-TuringPi-WiFi-Controller/HEAD/firmware/firmware-0.10.5.d1_mini_2m.bin.gz -------------------------------------------------------------------------------- /firmware/firmware-0.11.4.d1_mini_2m.bin.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thorsten-l/ESP8266-TuringPi-WiFi-Controller/HEAD/firmware/firmware-0.11.4.d1_mini_2m.bin.gz -------------------------------------------------------------------------------- /firmware/firmware-0.12.1.d1_mini_2m.bin.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thorsten-l/ESP8266-TuringPi-WiFi-Controller/HEAD/firmware/firmware-0.12.1.d1_mini_2m.bin.gz -------------------------------------------------------------------------------- /firmware/firmware-0.8.2.d1_mini_2m.bin.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thorsten-l/ESP8266-TuringPi-WiFi-Controller/HEAD/firmware/firmware-0.8.2.d1_mini_2m.bin.gz -------------------------------------------------------------------------------- /firmware/firmware-0.8.2.d1_mini_pro.bin.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thorsten-l/ESP8266-TuringPi-WiFi-Controller/HEAD/firmware/firmware-0.8.2.d1_mini_pro.bin.gz -------------------------------------------------------------------------------- /firmware/firmware-0.9.1.d1_mini_2m.bin.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thorsten-l/ESP8266-TuringPi-WiFi-Controller/HEAD/firmware/firmware-0.9.1.d1_mini_2m.bin.gz -------------------------------------------------------------------------------- /firmware/firmware-0.9.1.d1_mini_pro.bin.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thorsten-l/ESP8266-TuringPi-WiFi-Controller/HEAD/firmware/firmware-0.9.1.d1_mini_pro.bin.gz -------------------------------------------------------------------------------- /firmware/firmware-0.10.5.d1_mini_lite.bin.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thorsten-l/ESP8266-TuringPi-WiFi-Controller/HEAD/firmware/firmware-0.10.5.d1_mini_lite.bin.gz -------------------------------------------------------------------------------- /firmware/firmware-0.10.5.d1_mini_pro.bin.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thorsten-l/ESP8266-TuringPi-WiFi-Controller/HEAD/firmware/firmware-0.10.5.d1_mini_pro.bin.gz -------------------------------------------------------------------------------- /firmware/firmware-0.11.4.d1_mini_lite.bin.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thorsten-l/ESP8266-TuringPi-WiFi-Controller/HEAD/firmware/firmware-0.11.4.d1_mini_lite.bin.gz -------------------------------------------------------------------------------- /firmware/firmware-0.11.4.d1_mini_pro.bin.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thorsten-l/ESP8266-TuringPi-WiFi-Controller/HEAD/firmware/firmware-0.11.4.d1_mini_pro.bin.gz -------------------------------------------------------------------------------- /firmware/firmware-0.12.1.d1_mini_lite.bin.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thorsten-l/ESP8266-TuringPi-WiFi-Controller/HEAD/firmware/firmware-0.12.1.d1_mini_lite.bin.gz -------------------------------------------------------------------------------- /firmware/firmware-0.12.1.d1_mini_pro.bin.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thorsten-l/ESP8266-TuringPi-WiFi-Controller/HEAD/firmware/firmware-0.12.1.d1_mini_pro.bin.gz -------------------------------------------------------------------------------- /firmware/firmware-0.8.2.d1_mini_lite.bin.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thorsten-l/ESP8266-TuringPi-WiFi-Controller/HEAD/firmware/firmware-0.8.2.d1_mini_lite.bin.gz -------------------------------------------------------------------------------- /firmware/firmware-0.9.1.d1_mini_lite.bin.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thorsten-l/ESP8266-TuringPi-WiFi-Controller/HEAD/firmware/firmware-0.9.1.d1_mini_lite.bin.gz -------------------------------------------------------------------------------- /firmware/OTA_UPLOAD.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | $HOME/.platformio/penv/bin/python \ 3 | $HOME/.platformio/packages/framework-arduinoespressif8266/tools/espota.py \ 4 | --debug --progress -i "tpictl.local" \ 5 | --auth="otapass" -f "firmware.bin" 6 | -------------------------------------------------------------------------------- /lib/App/DeviceConfig.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __DEVICE_CONFIG_HPP__ 2 | #define __DEVICE_CONFIG_HPP__ 3 | 4 | #ifdef BOARD_TYPE_DEV1 5 | #define WIFI_LED LED_BUILTIN // D4, GPIO2 6 | #define WIFI_LED_ON 0 7 | #define WIFI_LED_OFF 1 8 | #endif 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /lib/OtaHandler/OtaHandler.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __OTA_HANDLER_HPP__ 2 | #define __OTA_HANDLER_HPP__ 3 | 4 | class OtaHandler 5 | { 6 | private: 7 | bool initialized; 8 | void setup(); 9 | 10 | public: 11 | void handle(); 12 | }; 13 | 14 | extern OtaHandler otaHandler; 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /lib/WebHandler/WebHandler.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __WEB_HANDLER_H__ 2 | #define __WEB_HANDLER_H__ 3 | 4 | class WebHandler 5 | { 6 | private: 7 | bool initialized; 8 | void setup(); 9 | 10 | public: 11 | WebHandler(); 12 | 13 | void handle(); 14 | }; 15 | 16 | extern WebHandler webHandler; 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /config/Development.h: -------------------------------------------------------------------------------- 1 | #ifndef __DEVELOPMENT_H__ 2 | #define __DEVELOPMENT_H__ 3 | 4 | #undef OVERRIDE_WIFI_SETTINGS 5 | #define OVERRIDE_WIFI_MODE WIFI_STA 6 | #define OVERRIDE_WIFI_SSID "" 7 | #define OVERRIDE_WIFI_PASSWORD "" 8 | #define OVERRIDE_OTA_ENABLED true 9 | 10 | #endif -------------------------------------------------------------------------------- /lib/AsyncPing/library.properties: -------------------------------------------------------------------------------- 1 | name=AsyncPing(esp8266) 2 | version=1.1.0 3 | author=Jes 4 | maintainer=jes 5 | sentence=Enables asynchronous ping. For Espressif's ESP8266 MCUs. 6 | paragraph=based on lwip pbuf library 7 | category=Communication 8 | url=https://github.com/akaJes/AsyncPing 9 | architectures=* -------------------------------------------------------------------------------- /docker/RUN_PLATFORMIO.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | cd .. 3 | docker run -it --rm \ 4 | -v `pwd`:/workdir \ 5 | --name platformio platformio \ 6 | /usr/local/bin/platformio run \ 7 | -e d1_mini \ 8 | -e d1_mini_lite \ 9 | -e d1_mini_pro \ 10 | -e d1_mini_2m 11 | 12 | cp .pio/build/*/firmware-*.bin firmware 13 | gzip -9 firmware/*.bin 14 | -------------------------------------------------------------------------------- /lib/WebPages/SystemRestart.cpp: -------------------------------------------------------------------------------- 1 | #include "WebPages.h" 2 | 3 | void handleSystemRestart() 4 | { 5 | sendAuthentication(); 6 | sendHeader(APP_NAME " - System restart", true); 7 | sendPrint("
"); 8 | sendLegend("System restart."); 9 | sendPrint("

Restart takes about 30sec.

"); 10 | sendPrint("
"); 11 | sendFooter(); 12 | ESP.restart(); 13 | } 14 | -------------------------------------------------------------------------------- /lib/LinkedList/LinkedList.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __LINKED_LIST_HPP__ 2 | #define __LINKED_LIST_HPP__ 3 | 4 | #include 5 | 6 | struct ListNode 7 | { 8 | String* value; 9 | ListNode* next = NULL; 10 | }; 11 | 12 | class SimpleLinkedList 13 | { 14 | 15 | private: 16 | ListNode *rootNode = NULL; 17 | 18 | public: 19 | void put( String value ); 20 | ListNode* getRootNode(); 21 | }; 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /lib/WebPages/BackupConfiguration.cpp: -------------------------------------------------------------------------------- 1 | #include "WebPages.h" 2 | #include 3 | #include 4 | 5 | void handleBackupConfiguration() 6 | { 7 | sendAuthentication(); 8 | server.sendHeader( "Content-Disposition", 9 | "attachment; filename=\"tpictl-config.json\""); 10 | LittleFS.begin(); 11 | File configFile = LittleFS.open( APP_CONFIG_FILE_JSON, "r"); 12 | server.streamFile(configFile, "application/json"); 13 | configFile.close(); 14 | LittleFS.end(); 15 | } 16 | -------------------------------------------------------------------------------- /lib/MqttHandler/MqttHandler.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __MQTT_HANDLER_H__ 2 | #define __MQTT_HANDLER_H__ 3 | 4 | class MqttHandler 5 | { 6 | private: 7 | bool initialized; 8 | bool reconnect(); 9 | void setup(); 10 | unsigned long lastPublishTimestamp; 11 | 12 | public: 13 | MqttHandler(); 14 | void handle( unsigned long now ); 15 | void sendValue( const char* topic, const char* value ); 16 | void sendValue( const char* topic, const float value ); 17 | }; 18 | 19 | extern MqttHandler mqttHandler; 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /lib/WebPages/MaintenancePage.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "WebPages.h" 6 | 7 | static const char *setupProcessor(const char *var) 8 | { 9 | if (strcmp(var, "pioenv_name") == 0) 10 | return PIOENV_NAME; 11 | return nullptr; 12 | } 13 | 14 | void handleMaintenancePage() 15 | { 16 | sendAuthentication(); 17 | sendHeader(APP_NAME " - Maintenance", false, MAINTENANCE_STYLE); 18 | sendHtmlTemplate(MAINTENANCE_HTML_TEMPLATE, setupProcessor); 19 | sendFooter(); 20 | } 21 | -------------------------------------------------------------------------------- /lib/WebPages/RestoreConfiguration.cpp: -------------------------------------------------------------------------------- 1 | #include "WebPages.h" 2 | 3 | void handleRestoreConfiguration() 4 | { 5 | sendAuthentication(); 6 | sendHeader(APP_NAME " - Restore Config", true); 7 | sendPrint("
"); 8 | sendLegend("Configuration successfully restored."); 9 | sendPrint("

Restarting System ... takes about 30s

"); 10 | sendFooter(); 11 | 12 | if (app.loadJsonConfig(APP_CONFIG_FILE_JSON) == false) 13 | { 14 | memcpy(&appcfgWR, &appcfgRD, sizeof(appcfg)); 15 | } 16 | 17 | app.delayedSystemRestart(); 18 | } 19 | -------------------------------------------------------------------------------- /lib/WebPages/ResetFirmware.cpp: -------------------------------------------------------------------------------- 1 | #include "WebPages.h" 2 | 3 | void handleResetFirmware() 4 | { 5 | sendAuthentication(); 6 | sendHeader(APP_NAME " - Reset Firmware", true); 7 | sendPrint("
"); 8 | sendLegend("Reset Firmware."); 9 | 10 | if (strcmp("true", server.arg(0).c_str()) == 0) 11 | { 12 | sendPrint("

Resetting firmware... restart takes about 30sec.

"); 13 | app.firmwareReset(); 14 | } 15 | else 16 | { 17 | sendPrint("If you really want to reset to system defaults, you must select 'Yes' on the maintenance page."); 18 | } 19 | 20 | sendPrint("
"); 21 | sendFooter(); 22 | } 23 | -------------------------------------------------------------------------------- /lib/Util/Util.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __UTIL_HPP__ 2 | #define __UTIL_HPP__ 3 | 4 | #include 5 | 6 | #define MAX_MESSAGE_LENGTH 200 7 | #define MESSAGE_BUFFER_LINES 11 8 | #define BUFFER_LENGTH 4096 9 | #define BUFFER2_LENGTH 256 10 | 11 | extern char messageBuffer[]; 12 | extern int messageStartIndex; 13 | extern int messageEndIndex; 14 | 15 | extern int getBootDevice(void); 16 | extern void alterPin(int pin); 17 | extern void showChipInfo(); 18 | extern void fillBuffer(const char *message); 19 | 20 | extern void sendHtmlTemplate(const char *htmlTemplate, const char *(*setupProcessor)(const char *)); 21 | 22 | extern char buffer[]; 23 | extern char buffer2[]; 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # PlatformIO 2 | .pio 3 | .pioenvs 4 | .piolibdeps 5 | .clang_complete 6 | .gcc-flags.json 7 | 8 | # Private directory 9 | private/ 10 | 11 | # Visual Studio Code 12 | .vscode 13 | 14 | # Prerequisites 15 | *.d 16 | 17 | # Compiled Object files 18 | *.slo 19 | *.lo 20 | *.o 21 | *.obj 22 | 23 | # Precompiled Headers 24 | *.gch 25 | *.pch 26 | 27 | # Compiled Dynamic libraries 28 | *.so 29 | *.dylib 30 | *.dll 31 | 32 | # Fortran module files 33 | *.mod 34 | *.smod 35 | 36 | # Compiled Static libraries 37 | *.lai 38 | *.la 39 | *.a 40 | 41 | # Executables 42 | *.exe 43 | *.out 44 | *.app 45 | 46 | # macOS 47 | .DS_Store 48 | 49 | # KiCad 50 | *~ 51 | *.bak 52 | *-bak 53 | _autosave* 54 | rescue-backup/ 55 | -------------------------------------------------------------------------------- /lib/WifiHandler/WifiHandler.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __WIFI_HANDLER_H__ 2 | #define __WIFI_HANDLER_H__ 3 | 4 | #include "LinkedList.hpp" 5 | 6 | class WifiHandler 7 | { 8 | private: 9 | bool connected; 10 | int connectCounter = 0; 11 | char networkBuffer[1024]; 12 | const char* scanNetworks(); 13 | byte mac[6]; 14 | char macAddress[20]; 15 | 16 | public: 17 | void setup(); 18 | const bool isReady(); 19 | const bool isConnected(); 20 | const bool isInStationMode(); 21 | ListNode* getScannedNetworks(); 22 | const bool handle( time_t timestamp ); 23 | const char *getLocalIP(); 24 | int getConnectCounter(); 25 | const char* getMacAddress(); 26 | const char* getPhyMode(); 27 | const char *getHostname(); 28 | }; 29 | 30 | extern WifiHandler wifiHandler; 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /lib/WebPages/FirmwareUploadSuccess.cpp: -------------------------------------------------------------------------------- 1 | #include "WebPages.h" 2 | 3 | extern bool firmwareUploadFailed; 4 | extern char *firmwareUploadErrorMessage; 5 | 6 | void handleFirmwareUploadSuccess() 7 | { 8 | sendAuthentication(); 9 | sendHeader(APP_NAME " - Firmware upload", true); 10 | sendPrint("
"); 11 | 12 | if (firmwareUploadFailed) 13 | { 14 | sendLegend("Firmware upload FAILED!"); 15 | sendPrint("

ERROR: "); 16 | sendPrint(firmwareUploadErrorMessage); 17 | sendPrint(".

"); 18 | sendFooter(); 19 | } 20 | else 21 | { 22 | sendLegend("Firmware successfully uploaded."); 23 | sendPrint("

Restarting System ... takes about 30s

"); 24 | sendFooter(); 25 | delay(1000); 26 | ESP.restart(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /boards/d1_mini_2m.json: -------------------------------------------------------------------------------- 1 | { 2 | "build": { 3 | "arduino": { 4 | "ldscript": "eagle.flash.2m64.ld" 5 | }, 6 | "core": "esp8266", 7 | "extra_flags": "-DESP8266 -DARDUINO_ARCH_ESP8266 -DARDUINO_ESP8266_WEMOS_D1MINILITE", 8 | "f_cpu": "80000000L", 9 | "f_flash": "40000000L", 10 | "flash_mode": "dout", 11 | "mcu": "esp8266", 12 | "variant": "d1_mini" 13 | }, 14 | "connectivity": [ 15 | "wifi" 16 | ], 17 | "frameworks": [ 18 | "arduino" 19 | ], 20 | "name": "WeMos D1 mini lite 2M", 21 | "upload": { 22 | "maximum_ram_size": 81920, 23 | "maximum_size": 2097152, 24 | "require_upload_port": true, 25 | "resetmethod": "nodemcu", 26 | "speed": 115200 27 | }, 28 | "url": "https://wiki.wemos.cc/products:d1:d1_mini_lite", 29 | "vendor": "WEMOS" 30 | } 31 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Documentation 2 | 3 | ## Root page 4 | 5 | - slot 1-4 are ON and running a pingable OS. 6 | - slot 5 is ON and a module is installed but it was last seen at 12:37. 7 | - slot 6 is OFF 8 | - slot 7 is ON but no compute module is installed 9 | 10 | ![root page](./img/img01.png) 11 | 12 | ## Setup 13 | 14 | ### Admin password 15 | 16 | ![admin password](./img/img02.png) 17 | 18 | ### Network settings 19 | 20 | ![network settings](./img/img03.png) 21 | 22 | ## Services 23 | 24 | ![services](./img/img04.png) 25 | 26 | ## Maintenance 27 | 28 | ### Backup & Restore Configuration 29 | 30 | ![services](./img/img06.png) 31 | 32 | ### Firmware 33 | 34 | ![services](./img/img07.png) 35 | 36 | ### Restart System 37 | 38 | ![services](./img/img08.png) 39 | 40 | ## Info Page 41 | 42 | ![services](./img/img05.png) 43 | -------------------------------------------------------------------------------- /lib/LinkedList/LinkedList.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "LinkedList.hpp" 4 | 5 | void SimpleLinkedList::put( String value ) 6 | { 7 | if ( rootNode == NULL ) 8 | { 9 | rootNode = new ListNode(); 10 | rootNode->value = new String(value); 11 | } 12 | else 13 | { 14 | ListNode* currentListNode = NULL; 15 | 16 | do 17 | { 18 | if ( currentListNode == NULL ) 19 | { 20 | currentListNode = rootNode; 21 | } 22 | else 23 | { 24 | currentListNode = currentListNode->next; 25 | } 26 | 27 | if ( *currentListNode->value == value ) 28 | return; // make list unique 29 | } 30 | while(currentListNode->next != NULL ); 31 | currentListNode->next = new ListNode(); 32 | currentListNode->next->value = new String(value); 33 | } 34 | } 35 | 36 | ListNode *SimpleLinkedList::getRootNode() 37 | { 38 | return rootNode; 39 | } 40 | -------------------------------------------------------------------------------- /lib/TuringPiHandler/TuringPiHandler.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __TURING_PI_HANDLER_H__ 2 | #define __TURING_PI_HANDLER_H__ 3 | 4 | #define SLOT_STATE_UNKNOWN 0 5 | #define SLOT_STATE_INSTALLED 1 6 | #define SLOT_STATE_EMPTY 2 7 | 8 | class TuringPiHandler 9 | { 10 | private: 11 | uint8_t control; 12 | uint8_t status; 13 | time_t lastTimestamp = 0l; 14 | time_t rtcnow; 15 | 16 | uint8_t readRegister( uint8_t bus_addr, uint8_t register_addr); 17 | void writeRegister(uint8_t bus_addr, uint8_t register_addr, uint8_t value); 18 | 19 | public: 20 | void setup(); 21 | void handle(); 22 | void readRegisters(); 23 | void setPower( int slot, bool on ); 24 | bool getPower( int slot ); 25 | int getState( int slot ); // 0=unknown, 1=installed, 2=empty 26 | const char* getDateTime(); 27 | time_t getTime(); 28 | uint16_t getPingLastRecv( int slot ); 29 | time_t getPingLastSeen( int slot ); 30 | }; 31 | 32 | extern TuringPiHandler turingPiHandler; 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:20.04 2 | 3 | RUN apt-get update && apt-get install -y --no-install-recommends wget unzip git make \ 4 | srecord bc xz-utils gcc python curl python3-pip python-dev build-essential \ 5 | && pip3 install --upgrade setuptools 6 | 7 | RUN pip3 install -U platformio 8 | RUN pio platform install espressif8266@2.6.2 --with-package framework-arduinoespressif8266 9 | RUN pio platform install espressif8266 --with-package framework-arduinoespressif8266 10 | 11 | RUN /usr/local/bin/platformio update 12 | 13 | # now this pio project is dealing with platformio 4.0 features 14 | RUN /usr/local/bin/platformio upgrade --dev 15 | 16 | # Prebuild one project to install the complete environment 17 | RUN git clone https://github.com/thorsten-l/ESP8266-Arduino-Info.git 18 | WORKDIR /ESP8266-Arduino-Info 19 | RUN /usr/local/bin/platformio run 20 | RUN rm -fr /ESP8266-Arduino-Info 21 | 22 | RUN mkdir /workdir 23 | WORKDIR /workdir 24 | 25 | CMD ["/bin/bash"] 26 | # CMD [ "/usr/local/bin/platformio", "run" ] 27 | -------------------------------------------------------------------------------- /docker/README.md: -------------------------------------------------------------------------------- 1 | # Build this project in a Docker container 2 | 3 | If you like to have always a clean PlatformIO development, Docker is a good choice for this requirement. 4 | 5 | ## Install Docker 6 | 7 | - Docker Desktop (Mac,PC) [https://www.docker.com/products/docker-desktop](https://www.docker.com/products/docker-desktop) 8 | 9 | - About Docker CE (Linux also) [https://docs.docker.com/install/](https://docs.docker.com/install/) 10 | 11 | ## Build PlatformIO Docker image 12 | 13 | Simply start `./BUILD_DOCKER_IMAGE.sh` on a Mac or Linux system in this directory. 14 | If you like to rebuild the complete image from scratch start `./FORCE_REBUILD_DOCKER_IMAGE.sh` 15 | 16 | ## Build the firmware with the `platformio` Docker image 17 | 18 | - Edit the `RUN_PLATFORMIO.sh` file and remove all unwanted environments. ( ... -e ``) 19 | - Start `./RUN_PLATFORMIO.sh` in this directory. 20 | - Find the builded firmwares in the `/.pio/build/` directories. (I'm now using PIO 4.0) 21 | -------------------------------------------------------------------------------- /lib/readme.txt: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for the project specific (private) libraries. 3 | PlatformIO will compile them to static libraries and link to executable file. 4 | 5 | The source code of each library should be placed in separate directory, like 6 | "lib/private_lib/[here are source files]". 7 | 8 | For example, see how can be organized `Foo` and `Bar` libraries: 9 | 10 | |--lib 11 | | |--Bar 12 | | | |--docs 13 | | | |--examples 14 | | | |--src 15 | | | |- Bar.c 16 | | | |- Bar.h 17 | | |--Foo 18 | | | |- Foo.c 19 | | | |- Foo.h 20 | | |- readme.txt --> THIS FILE 21 | |- platformio.ini 22 | |--src 23 | |- main.c 24 | 25 | Then in `src/main.c` you should use: 26 | 27 | #include 28 | #include 29 | 30 | // rest H/C/CPP code 31 | 32 | PlatformIO will find your libraries automatically, configure preprocessor's 33 | include paths and build them. 34 | 35 | More information about PlatformIO Library Dependency Finder 36 | - http://docs.platformio.org/page/librarymanager/ldf.html 37 | -------------------------------------------------------------------------------- /include/html/header2_gz.h: -------------------------------------------------------------------------------- 1 | #ifndef __HEADER2_GZ_H__ 2 | #define __HEADER2_GZ_H__ 3 | 4 | #include 5 | 6 | const unsigned char header2_html_gz[] PROGMEM = { 7 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0xb3, 0xd1, 8 | 0xcf, 0x48, 0x4d, 0x4c, 0xb1, 0xe3, 0xb2, 0x49, 0xca, 0x4f, 0xa9, 0xb4, 9 | 0xe3, 0x52, 0x00, 0x02, 0x9b, 0x94, 0xcc, 0x32, 0x85, 0xe4, 0x9c, 0xc4, 10 | 0xe2, 0x62, 0x5b, 0xf5, 0xe4, 0xd2, 0xe2, 0x92, 0xfc, 0x5c, 0xdd, 0xdc, 11 | 0xd4, 0xbc, 0x52, 0xdd, 0xf2, 0xa2, 0xc4, 0x82, 0x82, 0xd4, 0x22, 0x75, 12 | 0x88, 0x2a, 0xa0, 0x42, 0x05, 0x64, 0x95, 0x05, 0xa5, 0x45, 0xa9, 0x60, 13 | 0x75, 0x0a, 0x48, 0x7a, 0x90, 0xd9, 0xba, 0x25, 0xf9, 0x05, 0x48, 0x7a, 14 | 0xe1, 0xfa, 0x33, 0x53, 0x6c, 0xd5, 0x93, 0x8a, 0x12, 0xf3, 0x52, 0x74, 15 | 0x4b, 0x32, 0x4b, 0x72, 0x52, 0xd5, 0x61, 0x56, 0xc3, 0x0d, 0xd4, 0x05, 16 | 0xb9, 0x30, 0x33, 0x2f, 0x1d, 0xc5, 0x30, 0x90, 0x8e, 0x14, 0x75, 0x3b, 17 | 0x00, 0x98, 0x0c, 0x1d, 0x81, 0xbf, 0x00, 0x00, 0x00 18 | }; 19 | const unsigned int header2_html_gz_len = 129; 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /lib/MicroJson/MicroJson.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __MICRO_JSON_HPP__ 2 | #define __MICRO_JSON_HPP__ 3 | 4 | #include 5 | #include 6 | 7 | class uJson 8 | { 9 | private: 10 | File file; 11 | bool firstEntry; 12 | char buffer[128]; 13 | 14 | bool findChar( const int c ); 15 | int nextNotWhiteSpaceChar(); 16 | void writeAttributeName( String entryName ); 17 | 18 | public: 19 | uJson( File _file ); 20 | 21 | void writeHeader(); 22 | void writeEntry( String entryName, bool value ); 23 | void writeEntry( String entryName, int value ); 24 | void writeEntry( String entryName, unsigned long value ); 25 | void writeEntry( String entryName, const char *value ); 26 | void writeFooter(); 27 | 28 | bool readHeader(); 29 | bool readAttributeName( char *attributeName ); 30 | bool readEntryBoolean( const char* n1, const char* n2, bool *value ); 31 | bool readEntryInteger( const char* n1, const char* n2, int *value ); 32 | bool readEntryULong( const char* n1, const char* n2, unsigned long *value ); 33 | bool readEntryChars( const char* n1, const char* n2, char *value ); 34 | bool readFooter(); 35 | }; 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /extra_script.py: -------------------------------------------------------------------------------- 1 | import os 2 | from shutil import copyfile 3 | 4 | Import("env") 5 | pioEnv = env['PIOENV'] 6 | 7 | def copyFirmware(source, target, env): 8 | print ( "------------------------------------------------------------------------------" ) 9 | buildFlags = env.ParseFlags(env['BUILD_FLAGS']) 10 | cppDefines = buildFlags.get( "CPPDEFINES" ) 11 | 12 | appVersion = "0.0.0" 13 | 14 | i = 0 15 | 16 | while i < len(cppDefines): 17 | if len(cppDefines[i]) == 2: 18 | if "APP_VERSION" == cppDefines[i][0]: 19 | appVersion = cppDefines[i][1] 20 | l = len(appVersion) 21 | appVersion = appVersion[1:l-1] 22 | break 23 | i += 1 24 | 25 | firmwarePath = os.path.abspath(os.path.join( os.path.join( target[0].path, os.pardir), ( "firmware-%s.%s.bin" % ( appVersion, pioEnv )))) 26 | 27 | print ( "PIOENV = " + pioEnv ) 28 | print ( "copy firmware to file:" ) 29 | print ( firmwarePath ) 30 | copyfile( target[0].path, firmwarePath ) 31 | print ( "size=%d bytes" % os.path.getsize( firmwarePath )) 32 | 33 | env.AddPostAction( "$BUILD_DIR/firmware.bin", copyFirmware ) 34 | env.Append(CPPDEFINES=[("PIOENV", "\\\"" + env['PIOENV'] + "\\\"")]) 35 | -------------------------------------------------------------------------------- /lib/uzlib/uzlib_conf.h: -------------------------------------------------------------------------------- 1 | /* 2 | * uzlib - tiny deflate/inflate library (deflate, gzip, zlib) 3 | * 4 | * Copyright (c) 2014-2018 by Paul Sokolovsky 5 | */ 6 | 7 | #ifndef UZLIB_CONF_H_INCLUDED 8 | #define UZLIB_CONF_H_INCLUDED 9 | 10 | #ifndef UZLIB_CONF_DEBUG_LOG 11 | /* Debug logging level 0, 1, 2, etc. */ 12 | #define UZLIB_CONF_DEBUG_LOG 0 13 | #endif 14 | 15 | #ifndef UZLIB_CONF_PARANOID_CHECKS 16 | /* Perform extra checks on the input stream, even if they aren't proven 17 | to be strictly required (== lack of them wasn't proven to lead to 18 | crashes). */ 19 | #define UZLIB_CONF_PARANOID_CHECKS 0 20 | #endif 21 | 22 | #ifndef UZLIB_CONF_USE_MEMCPY 23 | /* Use memcpy() for copying data out of LZ window or uncompressed blocks, 24 | instead of doing this byte by byte. For well-compressed data, this 25 | may noticeably increase decompression speed. But for less compressed, 26 | it can actually deteriorate it (due to the fact that many memcpy() 27 | implementations are optimized for large blocks of data, and have 28 | too much overhead for short strings of just a few bytes). */ 29 | #define UZLIB_CONF_USE_MEMCPY 0 30 | #endif 31 | 32 | #endif /* UZLIB_CONF_H_INCLUDED */ 33 | -------------------------------------------------------------------------------- /lib/WebPages/FileConfigUpload.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "WebPages.h" 5 | 6 | static File fsUploadFile; 7 | 8 | void handleConfigFileUpload() 9 | { 10 | HTTPUpload &upload = server.upload(); 11 | 12 | if (upload.status == UPLOAD_FILE_START) 13 | { 14 | String filename = upload.filename; 15 | 16 | if (!filename.startsWith("/")) 17 | filename = "/" + filename; 18 | 19 | Serial.print("handleFileUpload Name: "); 20 | Serial.println(filename); 21 | 22 | LittleFS.begin(); 23 | fsUploadFile = LittleFS.open(APP_CONFIG_FILE_JSON, "w"); 24 | filename = String(); 25 | } 26 | else if (upload.status == UPLOAD_FILE_WRITE) 27 | { 28 | if (fsUploadFile) 29 | fsUploadFile.write(upload.buf, upload.currentSize); // Write the received bytes to the file 30 | } 31 | else if (upload.status == UPLOAD_FILE_END) 32 | { 33 | if (fsUploadFile) 34 | { 35 | fsUploadFile.close(); 36 | Serial.print("handleFileUpload Size: "); 37 | Serial.println(upload.totalSize); 38 | } 39 | else 40 | { 41 | server.send(500, "text/plain", "500: couldn't upload file"); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /lib/AsyncPing/keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map For AsyncPing 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | 9 | AsyncPing KEYWORD1 10 | AsyncPingResponse KEYWORD1 11 | 12 | ####################################### 13 | # Methods and Functions (KEYWORD2) 14 | ####################################### 15 | 16 | on KEYWORD2 17 | begin KEYWORD2 18 | cancel KEYWORD2 19 | response KEYWORD2 20 | 21 | answer KEYWORD2 22 | 23 | addr KEYWORD2 24 | time KEYWORD2 25 | icmp_seq KEYWORD2 26 | ttl KEYWORD2 27 | size KEYWORD2 28 | 29 | total_sent KEYWORD2 30 | total_recv KEYWORD2 31 | total_time KEYWORD2 32 | timeout KEYWORD2 33 | mac KEYWORD2 34 | 35 | ###################################### 36 | # Instances (KEYWORD2) 37 | ####################################### 38 | 39 | 40 | ####################################### 41 | # Constants (LITERAL1) 42 | ####################################### 43 | -------------------------------------------------------------------------------- /firmware/README.md: -------------------------------------------------------------------------------- 1 | # Firmware Binary 2 | If you do not wish to compile this firmware by your own, you can use the 3 | precompiled firmware in this directory. 4 | 5 | --- 6 | 7 | ## USB_UPLOAD script 8 | A sample script to upload the firmware via USB connection. 9 | 10 | **Change the USB device in the script 11 | to your device path.** 12 | 13 | ### esptool 14 | The [esptool](https://github.com/espressif/esptool) is needed to upload the firmware over USB. 15 | I used the `esptool` comes with [PlatformIO](https://platformio.org/). 16 | 17 | ### Warning 18 | Some esp8266 have problems with OTA upload after an USB upload. Press the reset button or do a power cycle after an USB upload if you like to do OTA upload. 19 | 20 | --- 21 | 22 | ## OTA_UPLOAD script 23 | A sample script to upload the firmware **o**ver **t**he **a**ir via WiFi connection. 24 | 25 | **Change hostname and auth password to your WiFi Socket NG settings** 26 | 27 | ### espota.py 28 | The [espota.py](https://github.com/esp8266/Arduino/blob/master/tools/espota.py) Python script is needed to upload the firmware over the air. 29 | Again i used the `espota.py` comes with [PlatformIO](https://platformio.org/). 30 | 31 | ## References 32 | - [PlatformIO](https://platformio.org/) 33 | - [esptool](https://github.com/espressif/esptool) 34 | - [espota.py](https://github.com/esp8266/Arduino/blob/master/tools/espota.py) 35 | -------------------------------------------------------------------------------- /lib/WebPages/JsonUtil.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "WebPages.h" 7 | 8 | extern ESP8266WebServer server; 9 | 10 | void buildJsonMessage() 11 | { 12 | turingPiHandler.readRegisters(); 13 | 14 | int idx = sprintf(buffer, "{\"state\":["); 15 | 16 | for (int slot = 1; slot < 8; slot++) 17 | { 18 | idx += sprintf(buffer + idx, 19 | "{\"slot\":%d,\"power_on\":%s," 20 | "\"status\":%d," 21 | "\"ping_last_recv\":%d,\"ping_last_seen\":%lu" 22 | "}", 23 | slot, 24 | (turingPiHandler.getPower(slot)) ? "true" : "false", 25 | turingPiHandler.getState(slot), 26 | turingPiHandler.getPingLastRecv(slot), 27 | turingPiHandler.getPingLastSeen(slot)); 28 | 29 | if (slot < 7) 30 | { 31 | buffer[idx++] = ','; 32 | buffer[idx] = 0; 33 | } 34 | } 35 | 36 | sprintf(buffer + idx, "], \"rtc\":\"%s\", \"rtc_now\":%ld}", 37 | turingPiHandler.getDateTime(), turingPiHandler.getTime()); 38 | } 39 | 40 | void handleJsonStatusState() 41 | { 42 | server.sendHeader("Access-Control-Allow-Origin", "*"); 43 | sendHeaderNoCache(); 44 | buildJsonMessage(); 45 | server.send(200, "application/json", buffer); 46 | } 47 | -------------------------------------------------------------------------------- /lib/WebPages/WebPages.h: -------------------------------------------------------------------------------- 1 | #ifndef __WEB_PAGES_H__ 2 | #define __WEB_PAGES_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #define JSON_RELAY_ON 1 9 | #define JSON_RELAY_OFF 2 10 | #define JSON_RELAY_STATE 3 11 | 12 | extern ESP8266WebServer server; 13 | 14 | extern void handleRootPage(); 15 | extern void handleInfoPage(); 16 | extern void handleSetupPage(); 17 | extern void handleMaintenancePage(); 18 | extern void handleSaveConfigPage(); 19 | extern void handleBackupConfiguration(); 20 | extern void handleRestoreConfiguration(); 21 | extern void handleConfigFileUpload(); 22 | extern void handleFirmwareUpload(); 23 | extern void handleFirmwareUploadSuccess(); 24 | extern void handleResetFirmware(); 25 | extern void handleSystemRestart(); 26 | extern void handleJsonStatusState(); 27 | 28 | extern void handleSetAPI(); 29 | extern void handleTest1Page(); 30 | 31 | extern void sendAuthentication(); 32 | extern void sendHeaderNoCache(); 33 | extern void sendHeader(const char *title); 34 | extern void sendHeader(const char *title, bool sendMetaRefresh); 35 | extern void sendHeader(const char *title, bool sendMetaRefresh, const char *style); 36 | extern void sendFooter(); 37 | extern void sendPrintf(const char *format, ...); 38 | extern void sendPrint(const char *message); 39 | extern void sendLegend(const char *name); 40 | 41 | extern void buildJsonMessage(); 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /lib/WebPages/SetAPI.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "WebPages.h" 5 | 6 | void handleSetAPI() 7 | { 8 | server.sendHeader("Access-Control-Allow-Origin", "*"); 9 | sendHeaderNoCache(); 10 | sendAuthentication(); 11 | 12 | bool requestFailed = true; 13 | 14 | if ( server.args() == 2 15 | && server.argName(0) == "slot" 16 | && server.argName(1) == "power_on" ) 17 | { 18 | int slot = atoi(server.arg(0).c_str()); 19 | 20 | if ( slot >=1 && slot <= 7 ) 21 | { 22 | bool validValue = false; 23 | bool power_on = false; 24 | 25 | String p = server.arg(1); 26 | if ( p == "0" || p == "false" ) 27 | { 28 | validValue = true; 29 | } 30 | if ( p == "1" || p == "true" ) 31 | { 32 | power_on = true; 33 | validValue = true; 34 | } 35 | 36 | if ( validValue ) 37 | { 38 | sprintf( buffer, "OK: slot=%d power_on=%s", slot, (power_on) ? "true" : "false" ); 39 | turingPiHandler.setPower( slot, power_on ); 40 | requestFailed = false; 41 | } 42 | } 43 | } 44 | 45 | if( requestFailed ) 46 | { 47 | server.send ( 500, "text/plain", "ERROR: Wrong or missing parameters ?slot=[1..7]&power_on=[1|0]"); 48 | } 49 | else 50 | { 51 | server.send ( 200, "text/plain", buffer ); 52 | } 53 | 54 | server.client().stop(); 55 | } 56 | -------------------------------------------------------------------------------- /lib/AsyncPing/readme.md: -------------------------------------------------------------------------------- 1 | ## AsyncPing 2 | This is a fully asynchronous Ping library for Espressif's ESP8266 MCUs. 3 | have full ping statistic and hardware MAC address 4 | 5 | tested on 2.3.0 esp8266/Arduino 6 | patched for 2.4.x 7 | 8 | to install: 9 | `git clone https://github.com/akaJes/AsyncPing.git ~/Arduino/libraries/AsyncPing` 10 | 11 | usage 12 | ``` 13 | AsyncPing ping; 14 | 15 | /* callback for each answer/timeout of ping */ 16 | ping.on(true,[](const AsyncPingResponse& response){ 17 | IPAddress addr(response.addr); //to prevent with no const toString() in 2.3.0 18 | if (response.answer) 19 | Serial.printf("%d bytes from %s: icmp_seq=%d ttl=%d time=%d ms\n", response.size, addr.toString().c_str(), response.icmp_seq, response.ttl, response.time); 20 | else 21 | Serial.printf("no answer yet for %s icmp_seq=%d\n", addr.toString().c_str(), response.icmp_seq); 22 | return false; //do not stop 23 | }); 24 | 25 | /* callback for end of ping */ 26 | ping.on(false,[](const AsyncPingResponse& response){ 27 | IPAddress addr(response.addr); //to prevent with no const toString() in 2.3.0 28 | Serial.printf("total answer from %s sent %d recevied %d time %d ms\n",addr.toString().c_str(),response.total_sent,response.total_recv,response.total_time); 29 | if (response.mac) 30 | Serial.printf("detected eth address " MACSTR "\n",MAC2STR(response.mac->addr)); 31 | return true; //doesn't matter 32 | }); 33 | 34 | ping.begin(WiFi.gatewayIP()); 35 | ``` 36 | -------------------------------------------------------------------------------- /lib/App/DefaultAppConfig.h: -------------------------------------------------------------------------------- 1 | #ifndef __DEFAULT_APP_CONFIG_H__ 2 | #define __DEFAULT_APP_CONFIG_H__ 3 | 4 | #include 5 | 6 | #define DEFAULT_WIFI_SSID "tpictl-%06x" 7 | #define DEFAULT_WIFI_PASSWORD "12345678" 8 | #define DEFAULT_WIFI_MODE WIFI_AP 9 | 10 | #define DEFAULT_NET_MODE NET_MODE_DHCP 11 | #define DEFAULT_NET_HOST "192.168.192.1" 12 | #define DEFAULT_NET_MASK "255.255.255.0" 13 | #define DEFAULT_NET_GATEWAY "192.168.192.1" 14 | #define DEFAULT_NET_DNS "192.168.192.1" 15 | 16 | #define DEFAULT_OTA_ENABLED false 17 | #define DEFAULT_OTA_HOSTNAME "tpictl-%06x" 18 | #define DEFAULT_OTA_PASSWORD "otapass" 19 | 20 | #define DEFAULT_ADMIN_PASSWORD "admin" 21 | 22 | #define DEFAULT_MQTT_ENABLED false 23 | #define DEFAULT_MQTT_CLIENTID "tpictl-%06x" 24 | #define DEFAULT_MQTT_HOST "192.168.1.1" 25 | #define DEFAULT_MQTT_PORT 1883 26 | #define DEFAULT_MQTT_USEAUTH true 27 | #define DEFAULT_MQTT_USER "user" 28 | #define DEFAULT_MQTT_PASSWORD "password" 29 | #define DEFAULT_MQTT_INTOPIC "tpictl/%06x/in" 30 | #define DEFAULT_MQTT_OUTTOPIC "tpictl/%06x/out" 31 | #define DEFAULT_MQTT_SENDING_INTERVAL 60 32 | 33 | #define DEFAULT_TELNET_ENABLED true 34 | 35 | #define DEFAULT_NTP_ENABLED true 36 | #define DEFAULT_NTP_TIMEZONE "CET-1CEST-2,M3.5.0/02:00:00,M10.5.0/03:00:00" 37 | #define DEFAULT_NTP_SERVER1 "0.pool.ntp.org" 38 | #define DEFAULT_NTP_SERVER2 "1.pool.ntp.org" 39 | #define DEFAULT_NTP_SERVER3 "2.pool.ntp.org" 40 | 41 | #define DEFAULT_PING_ENABLED false 42 | #define DEFAULT_PING_INTERVAL 120 43 | #define DEFAULT_PING_IP "-" 44 | 45 | #endif -------------------------------------------------------------------------------- /lib/App/ConfigAttributes.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __CONFIG_ATTRIBUTES_HPP__ 2 | #define __CONFIG_ATTRIBUTES_HPP__ 3 | 4 | #define A_wifi_ssid "wifi_ssid" 5 | #define A_wifi_password "wifi_password" 6 | #define A_wifi_mode "wifi_mode" 7 | 8 | #define A_net_mode "net_mode" 9 | #define A_net_host "net_host" 10 | #define A_net_mask "net_mask" 11 | #define A_net_gateway "net_gateway" 12 | #define A_net_dns "net_dns" 13 | 14 | #define A_ota_enabled "ota_enabled" 15 | #define A_ota_hostname "ota_hostname" 16 | #define A_ota_password "ota_password" 17 | 18 | #define A_admin_password "admin_password" 19 | 20 | #define A_mqtt_enabled "mqtt_enabled" 21 | #define A_mqtt_clientid "mqtt_clientid" 22 | #define A_mqtt_host "mqtt_host" 23 | #define A_mqtt_port "mqtt_port" 24 | #define A_mqtt_intopic "mqtt_intopic" 25 | #define A_mqtt_outtopic "mqtt_outtopic" 26 | #define A_mqtt_useauth "mqtt_useauth" 27 | #define A_mqtt_user "mqtt_user" 28 | #define A_mqtt_password "mqtt_password" 29 | #define A_mqtt_sending_interval "mqtt_sending_interval" 30 | 31 | #define A_telnet_enabled "telnet_enabled" 32 | 33 | #define A_ntp_enabled "ntp_enabled" 34 | #define A_ntp_timezone "ntp_timezone" 35 | #define A_ntp_server1 "ntp_server1" 36 | #define A_ntp_server2 "ntp_server2" 37 | #define A_ntp_server3 "ntp_server3" 38 | 39 | #define A_ping_enabled "ping_enabled" 40 | #define A_ping_interval "ping_interval" 41 | #define A_ping_ip_slot1 "ping_ip_slot1" 42 | #define A_ping_ip_slot2 "ping_ip_slot2" 43 | #define A_ping_ip_slot3 "ping_ip_slot3" 44 | #define A_ping_ip_slot4 "ping_ip_slot4" 45 | #define A_ping_ip_slot5 "ping_ip_slot5" 46 | #define A_ping_ip_slot6 "ping_ip_slot6" 47 | #define A_ping_ip_slot7 "ping_ip_slot7" 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /lib/uzlib/defl_static.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) uzlib authors 3 | * 4 | * This software is provided 'as-is', without any express 5 | * or implied warranty. In no event will the authors be 6 | * held liable for any damages arising from the use of 7 | * this software. 8 | * 9 | * Permission is granted to anyone to use this software 10 | * for any purpose, including commercial applications, 11 | * and to alter it and redistribute it freely, subject to 12 | * the following restrictions: 13 | * 14 | * 1. The origin of this software must not be 15 | * misrepresented; you must not claim that you 16 | * wrote the original software. If you use this 17 | * software in a product, an acknowledgment in 18 | * the product documentation would be appreciated 19 | * but is not required. 20 | * 21 | * 2. Altered source versions must be plainly marked 22 | * as such, and must not be misrepresented as 23 | * being the original software. 24 | * 25 | * 3. This notice may not be removed or altered from 26 | * any source distribution. 27 | */ 28 | 29 | /* This files contains type declaration and prototypes for defl_static.c. 30 | They may be altered/distinct from the originals used in PuTTY source 31 | code. */ 32 | 33 | struct Outbuf { 34 | unsigned char *outbuf; 35 | int outlen, outsize; 36 | unsigned long outbits; 37 | int noutbits; 38 | int comp_disabled; 39 | }; 40 | 41 | void outbits(struct Outbuf *out, unsigned long bits, int nbits); 42 | void zlib_start_block(struct Outbuf *ctx); 43 | void zlib_finish_block(struct Outbuf *ctx); 44 | void zlib_literal(struct Outbuf *ectx, unsigned char c); 45 | void zlib_match(struct Outbuf *ectx, int distance, int len); 46 | -------------------------------------------------------------------------------- /lib/OtaHandler/OtaHandler.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "OtaHandler.hpp" 5 | 6 | OtaHandler otaHandler; 7 | 8 | void OtaHandler::setup() 9 | { 10 | LOG0("OTA Setup started...\n"); 11 | 12 | ArduinoOTA.setHostname(appcfg.ota_hostname); 13 | ArduinoOTA.setPassword(appcfg.ota_password); 14 | 15 | ArduinoOTA.onStart([]() 16 | { 17 | Serial.println("\nOTA Start"); 18 | }); 19 | 20 | ArduinoOTA.onEnd([]() 21 | { 22 | app.wifiLedOff(); 23 | Serial.println("\nOTA End\n"); 24 | }); 25 | 26 | ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) 27 | { 28 | Serial.printf("\rOTA Progress: %u%%", (progress / (total / 100))); 29 | app.wifiLedToggle(); 30 | }); 31 | 32 | ArduinoOTA.onError([](ota_error_t error) 33 | { 34 | Serial.printf("OTA Error[%u]: ", error); 35 | 36 | if (error == OTA_AUTH_ERROR) 37 | Serial.println("OTA Auth Failed"); 38 | else 39 | if (error == OTA_BEGIN_ERROR) 40 | Serial.println("OTA Begin Failed"); 41 | else 42 | if (error == OTA_CONNECT_ERROR) 43 | Serial.println("OTA Connect Failed"); 44 | else 45 | if (error == OTA_RECEIVE_ERROR) 46 | Serial.println("OTA Receive Failed"); 47 | else 48 | if (error == OTA_END_ERROR) 49 | Serial.println("OTA End Failed"); 50 | }); 51 | 52 | ArduinoOTA.begin(); 53 | MDNS.addServiceTxt("arduino", "tcp", "fw_name", APP_NAME ); 54 | MDNS.addServiceTxt("arduino", "tcp", "fw_version", APP_VERSION ); 55 | initialized = true; 56 | } 57 | 58 | void OtaHandler::handle() 59 | { 60 | if( ! initialized ) 61 | { 62 | setup(); 63 | } 64 | 65 | ArduinoOTA.handle(); 66 | } 67 | -------------------------------------------------------------------------------- /lib/WebPages/InfoPage.cpp: -------------------------------------------------------------------------------- 1 | #include "WebPages.h" 2 | 3 | void handleInfoPage() 4 | { 5 | sendHeader(APP_NAME " - Info"); 6 | sendPrint("
"); 7 | sendLegend("Application"); 8 | sendPrint( 9 | "

Name: " APP_NAME "

" 10 | "

Version: " APP_VERSION "

" 11 | "

PlatformIO Environment: " PIOENV "

" 12 | "

Author: Dr. Thorsten Ludewig <t.ludewig@gmail.com>

"); 13 | 14 | sendLegend("Build"); 15 | sendPrint("

Date: " __DATE__ "

" 16 | "

Time: " __TIME__ "

"); 17 | 18 | sendLegend("RESTful API"); 19 | 20 | sendPrintf( 21 | "

http://%s/espinfo - ESP8266 Info

", 22 | WiFi.localIP().toString().c_str(), WiFi.localIP().toString().c_str()); 23 | 24 | sendPrintf( 25 | "

http://%s/state - Slot info

", 26 | WiFi.localIP().toString().c_str(), WiFi.localIP().toString().c_str()); 27 | 28 | sendPrintf( 29 | "

http://%s/set?slot=[1..7]&power_on=[1|0|true|false] - Set slot power ON|OFF (admin authentication required)

", 30 | WiFi.localIP().toString().c_str(), WiFi.localIP().toString().c_str()); 31 | 32 | sendLegend("Services"); 33 | 34 | sendPrintf("

OTA Enabled: %s

", 35 | (appcfg.ota_enabled) ? "true" : "false"); 36 | sendPrintf("

MQTT Enabled: %s

", 37 | (appcfg.mqtt_enabled) ? "true" : "false"); 38 | sendPrintf("

Telnet Enabled: %s

", 39 | (appcfg.telnet_enabled) ? "true" : "false"); 40 | sendPrintf("

NTP (Timeservice) Enabled: %s

", 41 | (appcfg.ntp_enabled) ? "true" : "false"); 42 | 43 | sendPrint("
"); 44 | sendFooter(); 45 | } 46 | -------------------------------------------------------------------------------- /lib/TelnetStream/TelnetStream.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2017 Juraj Andrassy 3 | repository https://github.com/jandrassy 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Affero General Public License as published 7 | by the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU Affero General Public License for more details. 14 | 15 | You should have received a copy of the GNU Affero General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #ifndef _TELNETSTREAM_H_ 20 | #define _TELNETSTREAM_H_ 21 | 22 | #ifdef ESP8266 23 | #include 24 | #else 25 | #include 26 | #endif 27 | 28 | class TelnetStreamClass : public Stream 29 | { 30 | 31 | private: 32 | WiFiServer server; 33 | WiFiClient client; 34 | 35 | boolean disconnected(); 36 | boolean isConnected; 37 | 38 | void printHelp(); 39 | void printBanner(); 40 | 41 | char commandLine[32]; 42 | int commandIndex; 43 | 44 | public: 45 | TelnetStreamClass(uint16_t port); 46 | 47 | void begin(); 48 | void stop(); 49 | void handle(); 50 | 51 | // Stream implementation 52 | int read(); 53 | int available(); 54 | int peek(); 55 | 56 | // Print implementation 57 | size_t write(uint8_t val); 58 | using Print::write; // pull in write(str) and write(buf, size) from Print 59 | void flush(); 60 | }; 61 | 62 | extern TelnetStreamClass TelnetStream; 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /lib/AsyncPing/src/AsyncPing.h: -------------------------------------------------------------------------------- 1 | #include "IPAddress.h" 2 | #include 3 | #include "core_version.h" 4 | 5 | extern "C" { 6 | #include 7 | #include 8 | #include 9 | } 10 | 11 | class AsyncPingResponse{ 12 | public: 13 | bool answer; 14 | u16_t size; 15 | u16_t icmp_seq; 16 | u16_t ttl; 17 | u32_t time; 18 | struct eth_addr *mac; 19 | u16_t total_sent; 20 | u16_t total_recv; 21 | u32_t total_time; 22 | u32_t timeout; 23 | IPAddress addr; 24 | time_t last_seen; 25 | u16_t last_recv; 26 | }; 27 | 28 | #ifdef ARDUINO_ESP8266_RELEASE_2_3_0 29 | #define C_IP_ADDR 30 | #else 31 | #define C_IP_ADDR const 32 | #endif 33 | class AsyncPing{ 34 | public: 35 | typedef std::function< bool (const AsyncPingResponse& ) > THandlerFunction; 36 | AsyncPing(); 37 | void on(bool mode, THandlerFunction handler); 38 | bool begin(const IPAddress &addr, u8_t count = 3, u32_t timeout = 1000); 39 | bool begin(const char *host, u8_t count = 3, u32_t timeout = 1000); 40 | void cancel(); 41 | ~AsyncPing(); 42 | const AsyncPingResponse& response() { return _response; } 43 | 44 | private: 45 | AsyncPingResponse _response; 46 | 47 | os_timer_t _timer; 48 | static void _s_timer (void*arg); 49 | void timer(); 50 | 51 | os_timer_t _timer_recv; 52 | static void _s_timer_recv (void*arg); 53 | 54 | ip_addr_t ping_target; 55 | u8_t count_down; 56 | struct raw_pcb *ping_pcb; 57 | u16_t ping_id; 58 | u32_t ping_start; 59 | u32_t ping_sent; 60 | 61 | void done(); 62 | void send_packet(); 63 | void ping_send(struct raw_pcb *raw, ip_addr_t *addr); 64 | void ping_prepare_echo( struct icmp_echo_hdr *iecho, u16_t len); 65 | u8_t ping_recv (raw_pcb*pcb, pbuf*p, C_IP_ADDR ip_addr_t *addr); 66 | static u8_t _s_ping_recv (void*arg, raw_pcb*tpcb, pbuf*pb, C_IP_ADDR ip_addr_t *addr); 67 | THandlerFunction _on_recv; 68 | THandlerFunction _on_sent; 69 | }; 70 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | unsigned long lifeTicker; 13 | unsigned long maxLoopTime; 14 | unsigned long lastLoopTimestamp; 15 | unsigned long thisLoopTimestamp; 16 | 17 | void setup() 18 | { 19 | app.setup(); 20 | app.writeConfig(); 21 | app.printConfig(appcfg); 22 | 23 | Serial.println("\n"); 24 | LOG1("I2C SCL=%d\n", SCL); 25 | LOG1(" SDA=%d\n", SDA); 26 | 27 | byte count = 0; 28 | 29 | Wire.begin(); 30 | 31 | for (byte i = 8; i < 120; i++) 32 | { 33 | Wire.beginTransmission(i); // Begin I2C transmission Address (i) 34 | if (Wire.endTransmission() == 0) // Receive 0 = success (ACK response) 35 | { 36 | LOG1("Found address: %d (0x%02X)\n", i, i); 37 | count++; 38 | } 39 | } 40 | LOG1("Found %d device(s).\n\n", count); 41 | 42 | wifiHandler.setup(); 43 | turingPiHandler.setup(); 44 | maxLoopTime = 0l; 45 | lifeTicker = lastLoopTimestamp = millis(); 46 | uzlib_init(); 47 | } 48 | 49 | void loop() 50 | { 51 | thisLoopTimestamp = millis(); 52 | maxLoopTime = max(maxLoopTime, thisLoopTimestamp - lastLoopTimestamp); 53 | lastLoopTimestamp = thisLoopTimestamp; 54 | 55 | if ((thisLoopTimestamp - lifeTicker) >= 10000) 56 | { 57 | LOG1("max loop time = %ld\n", maxLoopTime); 58 | LOG1("wifi is connected %d\n", wifiHandler.isConnected()); 59 | LOG1("free heap %d\n", ESP.getFreeHeap()); 60 | maxLoopTime = 0l; 61 | lifeTicker = thisLoopTimestamp; 62 | } 63 | 64 | if (wifiHandler.handle(thisLoopTimestamp)) 65 | { 66 | otaHandler.handle(); 67 | webHandler.handle(); 68 | turingPiHandler.handle(); 69 | mqttHandler.handle(thisLoopTimestamp); 70 | if (appcfg.telnet_enabled) 71 | { 72 | TelnetStream.handle(); 73 | } 74 | } 75 | 76 | app.handle(thisLoopTimestamp); 77 | 78 | delay(20); // time for IP stack 79 | } 80 | -------------------------------------------------------------------------------- /include/html/header3_gz.h: -------------------------------------------------------------------------------- 1 | #ifndef __HEADER3_GZ_H__ 2 | #define __HEADER3_GZ_H__ 3 | 4 | #include 5 | 6 | const unsigned char header3_html_gz[] PROGMEM = { 7 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0xb3, 0xd1, 8 | 0x4f, 0xc9, 0x2c, 0xb3, 0xb3, 0x49, 0x54, 0xc8, 0x28, 0x4a, 0x4d, 0xb3, 9 | 0x55, 0x57, 0x56, 0x57, 0x48, 0xce, 0x49, 0x2c, 0x2e, 0xb6, 0x55, 0x4f, 10 | 0x2e, 0x2d, 0x2e, 0xc9, 0xcf, 0xd5, 0xcd, 0x4d, 0xcd, 0x2b, 0xd5, 0x2d, 11 | 0xc9, 0x4f, 0x4f, 0xcf, 0x49, 0x55, 0x57, 0xc8, 0x4c, 0xb1, 0x55, 0x87, 12 | 0xb2, 0xed, 0x6c, 0x8a, 0x61, 0x2a, 0x93, 0x12, 0x8b, 0xd4, 0xed, 0x6c, 13 | 0xf4, 0x8b, 0xb1, 0x0a, 0xe9, 0x27, 0x02, 0xa5, 0x40, 0x56, 0x70, 0x29, 14 | 0x40, 0x81, 0x0d, 0x90, 0x07, 0xd3, 0x5a, 0x50, 0x5a, 0x94, 0x0a, 0xb6, 15 | 0x42, 0x01, 0xce, 0xd2, 0xcd, 0xc8, 0x2f, 0xca, 0xac, 0xca, 0xcf, 0x2b, 16 | 0x49, 0xcc, 0x41, 0x12, 0x2c, 0x4e, 0x2e, 0xca, 0xcf, 0xc9, 0x49, 0x4c, 17 | 0xca, 0x49, 0x55, 0x40, 0x72, 0x18, 0x32, 0x5b, 0x37, 0x29, 0xbf, 0x04, 18 | 0xe8, 0x60, 0x14, 0xa1, 0x92, 0xd2, 0xe4, 0xec, 0xd4, 0x14, 0xa8, 0xbb, 19 | 0xc1, 0x6c, 0x5f, 0xa0, 0x77, 0xd4, 0xed, 0xe0, 0x6e, 0x01, 0x39, 0x09, 20 | 0xd9, 0x3d, 0x48, 0x66, 0xeb, 0x02, 0xad, 0x4c, 0x4d, 0xcd, 0x03, 0xf9, 21 | 0x0c, 0xe8, 0x60, 0x34, 0x2d, 0xa5, 0x39, 0x18, 0x3e, 0xd0, 0xcd, 0xc9, 22 | 0x2c, 0x2e, 0x41, 0x33, 0x1a, 0x6c, 0x7c, 0x4e, 0x26, 0xa6, 0xda, 0xcc, 23 | 0x92, 0xd4, 0x5c, 0xa0, 0xc9, 0xb0, 0x50, 0xd7, 0x87, 0x87, 0x3a, 0x22, 24 | 0x18, 0x72, 0x32, 0xf3, 0xb2, 0xd5, 0xed, 0x3c, 0xf2, 0x73, 0x53, 0x6d, 25 | 0xc0, 0x61, 0x98, 0x93, 0x89, 0xea, 0x06, 0xa2, 0xcd, 0x2e, 0x4e, 0x2d, 26 | 0x29, 0x2d, 0xd0, 0xcb, 0x28, 0xc9, 0xcd, 0xc1, 0x69, 0x4b, 0x30, 0x48, 27 | 0x09, 0x85, 0xd6, 0xe4, 0x26, 0x66, 0xe6, 0x95, 0xa4, 0xe6, 0x25, 0xe6, 28 | 0x25, 0xa7, 0xe2, 0xb7, 0xcc, 0x17, 0xa1, 0x90, 0x42, 0x2b, 0x33, 0xf3, 29 | 0xd2, 0xf2, 0xf1, 0xdb, 0xe5, 0x09, 0x54, 0x81, 0xdd, 0x12, 0x1b, 0xfd, 30 | 0xd2, 0x1c, 0x44, 0x80, 0x42, 0x72, 0x01, 0x38, 0x59, 0x20, 0x33, 0x81, 31 | 0x11, 0x0f, 0x8b, 0x3b, 0x90, 0xf7, 0x90, 0x62, 0x17, 0x25, 0xd1, 0x00, 32 | 0x13, 0x6b, 0x6a, 0x1e, 0x30, 0xee, 0xb9, 0x00, 0xe1, 0x73, 0x52, 0x6b, 33 | 0x4d, 0x03, 0x00, 0x00 34 | }; 35 | const unsigned int header3_html_gz_len = 316; 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /lib/AsyncPing/examples/ping/ping.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include "AsyncPing.h" 3 | 4 | AsyncPing Pings[3]; 5 | 6 | void setup() { 7 | Serial.begin(115200); 8 | delay(10); 9 | WiFi.disconnect(true); 10 | WiFi.mode(WIFI_STA); 11 | // We start by connecting to a WiFi network 12 | WiFi.begin("SIID", "password"); 13 | 14 | Serial.println(); 15 | Serial.println(); 16 | Serial.print("Wait for WiFi... "); 17 | 18 | while (WiFi.status() != WL_CONNECTED) { 19 | delay(500); 20 | Serial.print("."); 21 | } 22 | 23 | Serial.println(""); 24 | Serial.println("WiFi connected"); 25 | Serial.println("IP address: "); 26 | Serial.println(WiFi.localIP()); 27 | Serial.println("gateway IP address: "); 28 | Serial.println(WiFi.gatewayIP()); 29 | 30 | const char *ips[]={NULL,"google.com","8.8.8.8"}; 31 | 32 | for (int i = 0; i < 3 ; i++){ 33 | IPAddress addr; 34 | if (ips[i]){ 35 | if (!WiFi.hostByName(ips[i], addr)) 36 | addr.fromString(ips[i]); 37 | }else 38 | addr = WiFi.gatewayIP(); 39 | 40 | Pings[i].on(true,[](const AsyncPingResponse& response){ 41 | IPAddress addr(response.addr); //to prevent with no const toString() in 2.3.0 42 | if (response.answer) 43 | Serial.printf("%d bytes from %s: icmp_seq=%d ttl=%d time=%d ms\n", response.size, addr.toString().c_str(), response.icmp_seq, response.ttl, response.time); 44 | else 45 | Serial.printf("no answer yet for %s icmp_seq=%d\n", addr.toString().c_str(), response.icmp_seq); 46 | return false; //do not stop 47 | }); 48 | Pings[i].on(false,[](const AsyncPingResponse& response){ 49 | IPAddress addr(response.addr); //to prevent with no const toString() in 2.3.0 50 | Serial.printf("total answer from %s sent %d recevied %d time %d ms\n",addr.toString().c_str(),response.total_sent,response.total_recv,response.total_time); 51 | if (response.mac) 52 | Serial.printf("detected eth address " MACSTR "\n",MAC2STR(response.mac->addr)); 53 | return true; 54 | }); 55 | Serial.printf("started ping to %s:\n",addr.toString().c_str()); 56 | Pings[i].begin(addr); 57 | } 58 | } 59 | void loop() { 60 | 61 | } -------------------------------------------------------------------------------- /lib/AsyncPing/examples/ping_interval/ping_interval.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include "AsyncPing.h" 3 | #include "Ticker.h" 4 | 5 | Ticker timer; 6 | 7 | AsyncPing Pings[3]; 8 | IPAddress addrs[3]; 9 | 10 | const char *ips[]={NULL,"google.com","8.8.8.8"}; 11 | 12 | void setup() { 13 | Serial.begin(115200); 14 | delay(10); 15 | WiFi.disconnect(true); 16 | WiFi.mode(WIFI_STA); 17 | // We start by connecting to a WiFi network 18 | WiFi.begin("SIID", "password"); 19 | 20 | Serial.println(); 21 | Serial.println(); 22 | Serial.print("Wait for WiFi... "); 23 | 24 | while (WiFi.status() != WL_CONNECTED) { 25 | delay(500); 26 | Serial.print("."); 27 | } 28 | 29 | Serial.println(""); 30 | Serial.println("WiFi connected"); 31 | Serial.println("IP address: "); 32 | Serial.println(WiFi.localIP()); 33 | Serial.println("gateway IP address: "); 34 | Serial.println(WiFi.gatewayIP()); 35 | 36 | for (int i = 0; i < 3 ; i++){ 37 | if (ips[i]){ 38 | if (!WiFi.hostByName(ips[i], addrs[i])) 39 | addrs[i].fromString(ips[i]); 40 | }else 41 | addrs[i] = WiFi.gatewayIP(); 42 | 43 | Pings[i].on(true,[](const AsyncPingResponse& response){ 44 | IPAddress addr(response.addr); //to prevent with no const toString() in 2.3.0 45 | if (response.answer) 46 | Serial.printf("%d bytes from %s: icmp_seq=%d ttl=%d time=%d ms\n", response.size, addr.toString().c_str(), response.icmp_seq, response.ttl, response.time); 47 | else 48 | Serial.printf("no answer yet for %s icmp_seq=%d\n", addr.toString().c_str(), response.icmp_seq); 49 | return false; //do not stop 50 | }); 51 | 52 | Pings[i].on(false,[](const AsyncPingResponse& response){ 53 | IPAddress addr(response.addr); //to prevent with no const toString() in 2.3.0 54 | Serial.printf("total answer from %s sent %d recevied %d time %d ms\n",addr.toString().c_str(),response.total_sent,response.total_recv,response.total_time); 55 | if (response.mac) 56 | Serial.printf("detected eth address " MACSTR "\n",MAC2STR(response.mac->addr)); 57 | return true; 58 | }); 59 | } 60 | ping(); 61 | timer.attach(10,ping); 62 | } 63 | void ping(){ 64 | for (int i = 0; i < 3 ; i++){ 65 | Serial.printf("started ping to %s:\n",addrs[i].toString().c_str()); 66 | Pings[i].begin(addrs[i]); 67 | } 68 | } 69 | void loop() { 70 | 71 | } -------------------------------------------------------------------------------- /include/html/favicon_ico.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define FAVICON_ICO_GZ_LEN 367 4 | const char FAVICON_ICO_GZ[] PROGMEM = { 5 | 0x1f, 0x8b, 0x08, 0x08, 0x08, 0x39, 0xf0, 0x5c, 0x02, 0x03, 0x66, 0x61, 6 | 0x76, 0x69, 0x63, 0x6f, 0x6e, 0x2e, 0x69, 0x63, 0x6f, 0x00, 0xa5, 0xd3, 7 | 0xbd, 0x4a, 0xc3, 0x60, 0x14, 0x06, 0xe0, 0x53, 0x94, 0x66, 0xed, 0xa0, 8 | 0x25, 0x38, 0x39, 0x7a, 0x11, 0x5e, 0x40, 0x7b, 0x13, 0xe2, 0x28, 0xae, 9 | 0x22, 0xe8, 0xa4, 0x93, 0xe8, 0x66, 0x4a, 0xdd, 0x94, 0x36, 0x96, 0x36, 10 | 0x58, 0x30, 0x3f, 0xc6, 0xfc, 0x34, 0x49, 0xbf, 0xa4, 0xa9, 0x82, 0xe0, 11 | 0x05, 0xb8, 0x8a, 0x9d, 0xf5, 0x06, 0x32, 0xd4, 0xef, 0x6d, 0x8d, 0x88, 12 | 0x58, 0x48, 0xe2, 0x29, 0x27, 0x7c, 0x9c, 0xf3, 0x3e, 0xa5, 0x34, 0x09, 13 | 0x51, 0x89, 0x7f, 0x2a, 0x15, 0xe2, 0xd7, 0x75, 0xda, 0x59, 0x26, 0xaa, 14 | 0x12, 0xd1, 0x06, 0x6f, 0x3e, 0xe2, 0x93, 0xf9, 0x7c, 0x56, 0x7c, 0xe7, 15 | 0xaf, 0xce, 0xfb, 0x77, 0xdd, 0x9c, 0x9d, 0x90, 0x7c, 0xb8, 0x2f, 0x98, 16 | 0x72, 0xbb, 0xe6, 0x6a, 0xaa, 0xe2, 0xdb, 0xd6, 0x24, 0x70, 0xdd, 0x04, 17 | 0x8d, 0x33, 0x66, 0xd8, 0x21, 0x83, 0x6c, 0x5a, 0x7b, 0x6b, 0x2b, 0x64, 18 | 0x2b, 0x5d, 0x52, 0x9b, 0x92, 0xc8, 0x33, 0xd2, 0xd0, 0xf3, 0x3e, 0xc2, 19 | 0x30, 0x9c, 0xfe, 0xd5, 0xd8, 0x21, 0x83, 0x2c, 0x0c, 0xac, 0xd9, 0xba, 20 | 0x24, 0xfd, 0xe2, 0x5c, 0xf4, 0x4c, 0x43, 0x0f, 0x19, 0x9b, 0x2e, 0xb2, 21 | 0xdf, 0xcd, 0x33, 0xc8, 0xc2, 0xc0, 0x76, 0x76, 0xb7, 0xca, 0x9e, 0xae, 22 | 0x4a, 0x99, 0xec, 0xcf, 0xef, 0xe0, 0x06, 0xd6, 0xe9, 0xb6, 0xeb, 0xcc, 23 | 0xf7, 0xde, 0x33, 0xdb, 0xaf, 0x86, 0x81, 0xf5, 0x0d, 0xad, 0x97, 0xd7, 24 | 0xa6, 0x0d, 0x3b, 0x74, 0xac, 0xb7, 0xa2, 0x1e, 0x96, 0x0d, 0xdc, 0xa4, 25 | 0xa8, 0x87, 0x65, 0xde, 0x3f, 0x3c, 0xb7, 0xcc, 0x2d, 0xfe, 0xfb, 0x67, 26 | 0xd6, 0x2c, 0xfe, 0xff, 0xc1, 0x46, 0x7d, 0xb9, 0x1e, 0x06, 0xf9, 0xef, 27 | 0x1f, 0x0c, 0xec, 0xf8, 0x68, 0xbb, 0x1c, 0xdd, 0xe7, 0x7f, 0x7e, 0x60, 28 | 0x60, 0xe3, 0xfe, 0x15, 0x8d, 0xaf, 0x25, 0x31, 0x72, 0xee, 0x32, 0x3f, 29 | 0xbf, 0xc8, 0xc2, 0xc0, 0xbe, 0x6c, 0x56, 0x29, 0x36, 0x7a, 0xf4, 0xd8, 30 | 0x69, 0x88, 0x23, 0x4b, 0x95, 0xa2, 0x60, 0xf1, 0xfb, 0x83, 0x1d, 0x32, 31 | 0xc8, 0xc2, 0xc0, 0xa6, 0xf5, 0xd4, 0x3a, 0xa5, 0xe7, 0xe6, 0x81, 0xf0, 32 | 0x70, 0x2b, 0xd7, 0x62, 0x5b, 0x53, 0x46, 0x03, 0x6b, 0x12, 0xf9, 0x6e, 33 | 0x82, 0xc6, 0x19, 0x33, 0xec, 0x90, 0x41, 0x36, 0xad, 0x57, 0x81, 0x28, 34 | 0x5a, 0x22, 0x3a, 0x2e, 0x51, 0xe6, 0x42, 0x16, 0x06, 0xf6, 0x13, 0xd8, 35 | 0x85, 0x92, 0x3c, 0x7e, 0x04, 0x00, 0x00 36 | }; 37 | -------------------------------------------------------------------------------- /platformio.ini: -------------------------------------------------------------------------------- 1 | ; PlatformIO Project Configuration File 2 | ; 3 | ; Build options: build flags, source filter 4 | ; Upload options: custom upload port, speed and extra flags 5 | ; Library options: dependencies, extra library storages 6 | ; Advanced options: extra scripting 7 | ; 8 | ; Please visit documentation for the other options and examples 9 | ; http://docs.platformio.org/page/projectconf.html 10 | 11 | [platformio] 12 | default_envs = d1_mini_pro 13 | 14 | [common] 15 | platform = espressif8266@2.6.2 16 | framework = arduino 17 | 18 | build_flags = -DAPP_VERSION=\"0.13.1\" 19 | -Iprivate 20 | -Iconfig 21 | -Iinclude 22 | -D PIOENV=\"$PIOENV\" 23 | -D PIOPLATFORM=\"$PIOPLATFORM\" 24 | -D PIOFRAMEWORK=\"$PIOFRAMEWORK\" 25 | -D MQTT_MAX_PACKET_SIZE=800 26 | 27 | lib_deps = 28 | Wire 29 | PubSubClient@2.8 30 | 31 | [env:d1_mini] 32 | build_type = release 33 | board = d1_mini 34 | platform = ${common.platform} 35 | framework = ${common.framework} 36 | build_flags = ${common.build_flags} -DPIOENV_NAME=\"d1_mini\" -DBOARD_TYPE_DEV1 37 | lib_deps = ${common.lib_deps} 38 | extra_scripts = post:extra_script.py 39 | monitor_speed = 74880 40 | upload_speed = 460800 41 | 42 | [env:d1_mini_lite] 43 | build_type = release 44 | board = d1_mini_lite 45 | platform = ${common.platform} 46 | framework = ${common.framework} 47 | build_flags = ${common.build_flags} -DPIOENV_NAME=\"d1_mini_lite\" -DBOARD_TYPE_DEV1 48 | lib_deps = ${common.lib_deps} 49 | extra_scripts = post:extra_script.py 50 | monitor_speed = 74880 51 | upload_speed = 460800 52 | 53 | [env:d1_mini_pro] 54 | build_type = release 55 | board = d1_mini_pro 56 | platform = ${common.platform} 57 | framework = ${common.framework} 58 | build_flags = ${common.build_flags} -DGITHUB_FIRMWARE_DOWNLOAD -DPIOENV_NAME=\"d1_mini_pro\" -DBOARD_TYPE_DEV1 59 | board_build.ldscript = eagle.flash.4m1m.ld 60 | lib_deps = ${common.lib_deps} 61 | extra_scripts = post:extra_script.py 62 | monitor_speed = 74880 63 | upload_speed = 460800 64 | ;upload_port = dummy 65 | ;upload_command = ./private/OTA_UPLOAD_D1_MINI_PRO.sh 66 | 67 | [env:d1_mini_2m] 68 | build_type = release 69 | board = d1_mini_2m 70 | platform = ${common.platform} 71 | framework = ${common.framework} 72 | build_flags = ${common.build_flags} -DPIOENV_NAME=\"d1_mini_2m\" -DBOARD_TYPE_DEV1 73 | lib_deps = ${common.lib_deps} 74 | extra_scripts = post:extra_script.py 75 | monitor_speed = 74880 76 | upload_speed = 460800 77 | upload_port = dummy 78 | upload_command = ./private/OTA_UPLOAD_D1_MINI_2M.sh 79 | 80 | ; For OTA firmware upload over the air you have to uncommend 81 | ; the following two lines 82 | ; upload_protocol = espota 83 | ; upload_port = tpictl.local 84 | ; upload_flags = --auth=otapass 85 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ESP8266 Turing Pi WiFi Controller 2 | 3 | A WiFi Controller for the [Turing Pi V1 cluster board](https://turingpi.com/) connected via the onboard I2C bus. With this contoller you are able to switch the power on or off of each individual Turing Pi slot. 4 | It provides a Web, REST and telnet interface. MQTT is not implemented yet. 5 | 6 | ![root page](./docs/img/img01.png) 7 | 8 | ## !!! ATTENTION !!! 9 | 10 | At this point there is no warning of turning a slot ON/OFF, just one click and the slot is ON or OFF! 11 | 12 | ## Screenshots 13 | 14 | Find screenshots of all available web pages in the [docs](./docs/) directory. 15 | 16 | ## Precompiled Firmware 17 | 18 | Find the precompiled firmware in the [firmware](./firmware/) directory. 19 | 20 | ## Compile 21 | 22 | This is a [PlatformIO](https://platformio.org/) project. 23 | 24 | ### Docker as PlatformIO build environment 25 | 26 | If you need a clean PlatformIO build environment, use the scripts in the `docker` directory. 27 | 28 | ## Default Network Settings 29 | 30 | After a firmware reset the following values are set. 31 | 32 | | | value | description | 33 | | -------------------------- | --------------------- | ------------------------------------- | 34 | | Admin user | admin | Setup admin user | 35 | | Admin password | admin | Setup admin password | 36 | | WiFi Mode | AP | Accesspoint- or Station-Mode | 37 | | WiFi SSID | tpictl-`esp-id` | SSID in accesspoint mode | 38 | | WiFi Password | 12345678 | Default WiFi password | 39 | | Network Mode | DHCP | Network mode STATIC or DHCP \*1 | 40 | | Network IP-Address | 192.168.192.1 | device ip address \*2 | 41 | | Network Mask | 255.255.255.0 | Subnet mask \*2 | 42 | | Network Gateway | 192.168.192.1 | Default gateway \*2 | 43 | | Network DNS | 192.168.192.1 | DNS server address \*2 | 44 | 45 | \*1 In WiFi Station-Mode only 46 | 47 | \*2 will be overwritten with DHCP-Response 48 | 49 | 50 | ## References 51 | 52 | - [PlatformIO](https://platformio.org/) 53 | - [Arduino core for ESP8266 WiFi chip](https://github.com/esp8266/Arduino) 54 | - [Arduino-pubsubclient - A client library for the ESP8266 that provides support for MQTT](https://github.com/knolleary/pubsubclient) 55 | - [Pure.CSS - A nice CSS, as GZIP it is less than 4k so it is useful for embedded devices](https://purecss.io/) 56 | -------------------------------------------------------------------------------- /lib/App/App.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __APP_H__ 2 | #define __APP_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define LOG0( format ) Serial.printf( "(%lu) " format, millis()) 10 | #define LOG1( format, ... ) Serial.printf( "(%lu) " format, millis(), ##__VA_ARGS__ ) 11 | 12 | #define APP_NAME "Turing Pi WiFi Controller" 13 | #define APP_AUTHOR "Dr. Thorsten Ludewig " 14 | #define APP_CONFIG_FILE_JSON "/config.json" 15 | 16 | // Network mode 17 | #define NET_MODE_STATIC 1 18 | #define NET_MODE_DHCP 2 19 | 20 | extern void appShowHeader(Stream &out); 21 | extern const char *appUptime(); 22 | extern const char *appDateTime(); 23 | extern const char *appDateTime(time_t now); 24 | extern void logMessage(const char *message); 25 | extern void logMessage(String format, ...); 26 | 27 | typedef struct appconfig 28 | { 29 | char wifi_ssid[64]; 30 | char wifi_password[64]; 31 | int wifi_mode; 32 | 33 | int net_mode; 34 | char net_host[64]; 35 | char net_mask[64]; 36 | char net_gateway[64]; 37 | char net_dns[64]; 38 | 39 | bool ota_enabled; 40 | char ota_hostname[64]; 41 | char ota_password[64]; 42 | 43 | char admin_password[64]; 44 | 45 | bool mqtt_enabled; 46 | char mqtt_clientid[64]; 47 | char mqtt_host[64]; 48 | int mqtt_port; 49 | bool mqtt_useauth; 50 | char mqtt_user[64]; 51 | char mqtt_password[64]; 52 | char mqtt_intopic[64]; 53 | char mqtt_outtopic[64]; 54 | unsigned long mqtt_sending_interval; 55 | 56 | bool telnet_enabled; 57 | 58 | bool ntp_enabled; 59 | char ntp_timezone[64]; 60 | char ntp_server1[64]; 61 | char ntp_server2[64]; 62 | char ntp_server3[64]; 63 | 64 | bool ping_enabled; 65 | unsigned long ping_interval; 66 | char ping_addr[7][32]; 67 | 68 | } AppConfig; 69 | 70 | class App 71 | { 72 | private: 73 | char initFilename[32]; 74 | bool initialized = false; 75 | bool doSystemRestart; 76 | unsigned long systemRestartTimestamp; 77 | unsigned int systemRestartCounter; 78 | bool initSPIFFS = false; 79 | unsigned long ledStateTimestamp; 80 | int wifiLedState; 81 | 82 | void formatSPIFFS(); 83 | void loadConfig(); 84 | void restartSystem(); 85 | 86 | public: 87 | size_t fsTotalBytes; 88 | size_t fsUsedBytes; 89 | 90 | App(); 91 | 92 | void setup(); 93 | void firmwareReset(); 94 | void defaultConfig(); 95 | void writeConfig(); 96 | bool loadJsonConfig( const char *filename ); 97 | void printConfig(AppConfig ac); 98 | void delayedSystemRestart(); 99 | void handle( unsigned long timestamp ); 100 | // 101 | void showLeds(); 102 | void wifiLedOn(); 103 | void wifiLedOff(); 104 | void wifiLedToggle(); 105 | }; 106 | 107 | extern App app; 108 | extern AppConfig appcfg; 109 | extern AppConfig appcfgWR; 110 | extern AppConfig appcfgRD; 111 | 112 | #endif 113 | -------------------------------------------------------------------------------- /include/html/footer_gz.h: -------------------------------------------------------------------------------- 1 | #ifndef __FOOTER_GZ_H__ 2 | #define __FOOTER_GZ_H__ 3 | 4 | #include 5 | 6 | const unsigned char footer_html_gz[] PROGMEM = { 7 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x53, 0x80, 8 | 0x02, 0x1b, 0xfd, 0x94, 0xcc, 0x32, 0x3b, 0x2e, 0x10, 0x0f, 0xca, 0x84, 9 | 0xb0, 0x8b, 0x93, 0x8b, 0x32, 0x0b, 0x4a, 0x20, 0x12, 0x20, 0x49, 0x8d, 10 | 0xb4, 0xd2, 0xbc, 0xe4, 0x92, 0xcc, 0xfc, 0x3c, 0x8d, 0xf2, 0xcc, 0xbc, 11 | 0x94, 0xfc, 0x72, 0x1d, 0x85, 0x94, 0xfc, 0xe4, 0xd2, 0xdc, 0xd4, 0xbc, 12 | 0x12, 0x4d, 0x85, 0x6a, 0xb0, 0x16, 0x90, 0x2a, 0x10, 0x86, 0x89, 0xeb, 13 | 0xa5, 0xa7, 0x96, 0xb8, 0xe6, 0xa4, 0x82, 0x94, 0x38, 0x55, 0x7a, 0xa6, 14 | 0x68, 0xa8, 0x97, 0xe4, 0xa7, 0xa7, 0xe7, 0xa4, 0xaa, 0x6b, 0xea, 0x25, 15 | 0xa6, 0xa4, 0xb8, 0x96, 0x01, 0x75, 0xfa, 0x64, 0x16, 0x97, 0xa4, 0xe6, 16 | 0xa5, 0x16, 0x69, 0xa8, 0x27, 0xe7, 0x64, 0x26, 0x67, 0xab, 0xeb, 0x28, 17 | 0xc0, 0x2d, 0x49, 0x45, 0x37, 0x15, 0xbf, 0xc9, 0xa5, 0xc9, 0xd9, 0xa9, 18 | 0x29, 0xbe, 0xa9, 0x79, 0xa5, 0x40, 0xd3, 0x93, 0x73, 0x12, 0x8b, 0x8b, 19 | 0x41, 0x46, 0xeb, 0x41, 0x2c, 0x04, 0x9a, 0x5e, 0x5a, 0x5c, 0x92, 0x9f, 20 | 0xab, 0x0b, 0x74, 0x49, 0xa9, 0x6e, 0x49, 0x29, 0x48, 0xa9, 0xba, 0xa6, 21 | 0x35, 0x8a, 0x9b, 0xf1, 0x9b, 0x0e, 0x73, 0x37, 0xa6, 0xc9, 0x15, 0xe8, 22 | 0x06, 0xd5, 0x22, 0x19, 0x5c, 0xab, 0xa9, 0x51, 0x92, 0x91, 0x59, 0xac, 23 | 0xa3, 0x00, 0x22, 0xf5, 0x60, 0xc1, 0x02, 0x55, 0x60, 0xa3, 0x0f, 0x0b, 24 | 0x61, 0xb0, 0x43, 0x6c, 0x20, 0x3c, 0x85, 0x92, 0xca, 0x82, 0x54, 0x5b, 25 | 0xf5, 0x92, 0xd4, 0x8a, 0x12, 0xfd, 0xac, 0xc4, 0xb2, 0x44, 0x88, 0xa8, 26 | 0x3a, 0x22, 0x1a, 0xca, 0x12, 0x8b, 0x14, 0x32, 0x75, 0x14, 0x12, 0x93, 27 | 0x93, 0x15, 0x6c, 0xe1, 0x31, 0x80, 0x14, 0xd2, 0xc5, 0x4e, 0x95, 0xce, 28 | 0x20, 0xff, 0xfb, 0x25, 0xe6, 0xa6, 0x6a, 0xa8, 0x03, 0x95, 0xe5, 0x17, 29 | 0xa5, 0x00, 0x23, 0x0d, 0xd9, 0x99, 0x69, 0xf9, 0x45, 0x0a, 0x1a, 0x99, 30 | 0x40, 0xed, 0x06, 0xd6, 0x0a, 0x99, 0x0a, 0x36, 0x20, 0xb3, 0xf4, 0x72, 31 | 0x52, 0xf3, 0xd2, 0x4b, 0x32, 0x80, 0x7c, 0x6d, 0x6d, 0x4d, 0x90, 0x40, 32 | 0x74, 0x66, 0x2c, 0x31, 0xb1, 0x84, 0x1e, 0x49, 0x60, 0x8f, 0x62, 0x86, 33 | 0x52, 0x62, 0x72, 0x49, 0x66, 0x19, 0x30, 0xe2, 0x51, 0xc3, 0x1c, 0xe4, 34 | 0x95, 0x54, 0xa0, 0x33, 0xc0, 0x9a, 0xf2, 0x80, 0x3e, 0x76, 0x85, 0x24, 35 | 0x96, 0xe0, 0xcc, 0xa4, 0x9c, 0xcc, 0xbc, 0x74, 0x54, 0xc5, 0xea, 0x49, 36 | 0x39, 0xf9, 0xc0, 0x14, 0xa2, 0x60, 0x6b, 0x6b, 0xab, 0x90, 0xaa, 0x57, 37 | 0x5c, 0x52, 0x99, 0x93, 0xaa, 0x97, 0x92, 0x59, 0x5c, 0x90, 0x93, 0x58, 38 | 0xa9, 0x60, 0x8f, 0x21, 0x62, 0xab, 0xa0, 0x9e, 0x97, 0x9f, 0x97, 0xaa, 39 | 0xae, 0x60, 0x85, 0x4d, 0x0a, 0x62, 0x14, 0x38, 0xd8, 0x41, 0xf1, 0x0e, 40 | 0x8b, 0x32, 0x44, 0x8c, 0xd8, 0xe8, 0x27, 0xe5, 0xa7, 0x54, 0xda, 0x71, 41 | 0xd9, 0xe8, 0x67, 0x94, 0xe4, 0xe6, 0xd8, 0x01, 0x00, 0xde, 0x6e, 0x63, 42 | 0x0a, 0x2b, 0x03, 0x00, 0x00 43 | }; 44 | const unsigned int footer_html_gz_len = 425; 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /CHANGES.md: -------------------------------------------------------------------------------- 1 | # CHANGES 2 | 3 | ## release 2.8.2 4 | 5 | - LED night mode, switch off all leds after a specified timeout, for Robert :-) 6 | 7 | ## release 2.8.1 8 | 9 | - root page state is more responsive 10 | 11 | ## release 2.8.0 12 | 13 | - captive portal implementation 14 | - captive portal DNS server for AP mode 15 | - OpenHAB callback performance improvements 16 | - check for invalid firmware filename implemented 17 | - copy firmware.bin to firmware-version.pioenv.bin 18 | - refresh to root page after 30s 19 | - implementation for Shelly 1 OS switch 20 | 21 | ## release 2.7.0 22 | 23 | - simple favicon added 24 | - reorder openhab settings 25 | - show millis as comment in setup page 26 | - relpace all inline strings with define macros 27 | - detailed WiFi info added to /state restful info 28 | - new functions for backup and restore 29 | - remove maintenance from setup page, now it has an own page 30 | - Using JSON file format to store config 31 | 32 | ## release 2.6.0 33 | 34 | - Implementation for BlitzWolf SHP6 inclusive energy monitor 35 | - platform updated to version espressif8266@2.2.0 36 | - own board definitions 37 | 38 | ## release 2.5.0 39 | 40 | - reset firmware to system defaults added in setup page 41 | - paramBool function moved to WebUtils 42 | 43 | ## release 2.4.2 44 | 45 | - show chipinfo added 46 | - new dns setting 47 | - platform version 2.0.4 48 | - initial travis configuration 49 | - additional vscode exceptions 50 | 51 | ## release 2.4.1 52 | 53 | - Pin initialization for development version was missing 54 | 55 | ## release 2.4.0 56 | 57 | - html redesign of the setup page 58 | 59 | ## release 2.3.1 60 | 61 | - show PIOENV_NAME in firmware upload label 62 | 63 | ## release 2.3.0 64 | 65 | - update firmware over HTTP in setup page 66 | - optimized platformio file structure 67 | - web pages (handler) are now in seperate files 68 | - added PIOENV_NAME to every platformio env 69 | - show pioenv_name, hostname, spiffs_total and spiffs_used in info json 70 | 71 | ## release 2.2.2 72 | 73 | - debug code removed 74 | - remove unused code 75 | 76 | ## release 2.2.1 77 | 78 | - using CPP macro for WIFI_LED ON / OFF 79 | - complete rewriting of the setup page code 80 | - dev1lite added 81 | 82 | ## release 2.1.0 83 | 84 | - remove development firmware 85 | - easier wifi network seletion, firmware is now available for both obi socket versions 86 | - more information in info call 87 | - show free heap in /info restful call 88 | 89 | ## release 2.0.6 90 | 91 | - syslog messages added 92 | - syslog enabled added to info page 93 | - network and syslog added printConfig 94 | - flashing esp info 95 | - new screenshots for docs 96 | - wrong default mqtt port in readme 97 | - wrong default syslog port in readme 98 | 99 | ## release 2.0.5 100 | 101 | - code modifications for fauxmoesp lib 3.1.0 (alexa) 102 | - static network config and syslog config added 103 | -------------------------------------------------------------------------------- /lib/WebPages/FirmwareUpload.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "WebPages.h" 4 | 5 | bool firmwareUploadFailed; 6 | const char *firmwareUploadErrorMessage; 7 | 8 | static const char ERROR_UNDEFINED[] = "Undefined"; 9 | static const char ERROR_FILE_SIZE_ZERO[] = "Firmware file size is zero"; 10 | static const char ERROR_INVALID_FILENAME[] = "Invalid firmware filename"; 11 | static const char ERROR_NOT_ENOUGH_MEMORY[] = "Not enough memory"; 12 | static const char ERROR_WRONG_FILE_FORMAT[] = "Wrong file format"; 13 | 14 | static bool uploadError; 15 | 16 | void handleFirmwareUpload() 17 | { 18 | HTTPUpload &upload = server.upload(); 19 | 20 | if (upload.status == UPLOAD_FILE_START) 21 | { 22 | uploadError = false; 23 | firmwareUploadErrorMessage = ERROR_UNDEFINED; 24 | firmwareUploadFailed = true; 25 | 26 | Serial.setDebugOutput(true); 27 | WiFiUDP::stopAll(); 28 | Serial.printf("Update: %s\n", upload.filename.c_str()); 29 | 30 | if (upload.filename.endsWith(String("." PIOENV_NAME ".bin")) == true) 31 | { 32 | uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000; 33 | 34 | if (!Update.begin(maxSketchSpace)) 35 | { 36 | Update.printError(Serial); 37 | firmwareUploadErrorMessage = ERROR_NOT_ENOUGH_MEMORY; 38 | uploadError = true; 39 | } 40 | } 41 | else 42 | { 43 | Serial.println(ERROR_INVALID_FILENAME); 44 | firmwareUploadErrorMessage = ERROR_INVALID_FILENAME; 45 | uploadError = true; 46 | } 47 | 48 | Serial.println(); 49 | } 50 | else if (upload.status == UPLOAD_FILE_WRITE) 51 | { 52 | size_t p = upload.totalSize * 100 / upload.contentLength; 53 | Serial.printf("\rupload progress = %u%%", p); 54 | Serial.flush(); 55 | 56 | if (uploadError == false && Update.write(upload.buf, upload.currentSize) != upload.currentSize) 57 | { 58 | int errorCode = Update.getError(); 59 | 60 | if (errorCode == 4) 61 | { 62 | firmwareUploadErrorMessage = ERROR_NOT_ENOUGH_MEMORY; 63 | } 64 | if (errorCode == 10) 65 | { 66 | firmwareUploadErrorMessage = ERROR_WRONG_FILE_FORMAT; 67 | } 68 | 69 | Update.printError(Serial); 70 | } 71 | } 72 | else if (upload.status == UPLOAD_FILE_END) 73 | { 74 | if (Update.getError() == 10) 75 | { 76 | firmwareUploadErrorMessage = ERROR_WRONG_FILE_FORMAT; 77 | } 78 | 79 | if (Update.end(true)) 80 | { 81 | if (uploadError == false && upload.totalSize > 0) 82 | { 83 | firmwareUploadFailed = false; 84 | Serial.printf("\n\nUpdate Success: %u\nRebooting...\n\n", upload.totalSize); 85 | } 86 | else 87 | { 88 | Serial.println(ERROR_FILE_SIZE_ZERO); 89 | firmwareUploadErrorMessage = ERROR_FILE_SIZE_ZERO; 90 | } 91 | } 92 | else 93 | { 94 | Update.printError(Serial); 95 | } 96 | Serial.setDebugOutput(false); 97 | } 98 | yield(); 99 | } 100 | -------------------------------------------------------------------------------- /lib/uzlib/tinfgzip.c: -------------------------------------------------------------------------------- 1 | /* 2 | * uzlib - tiny deflate/inflate library (deflate, gzip, zlib) 3 | * 4 | * Copyright (c) 2003 by Joergen Ibsen / Jibz 5 | * All Rights Reserved 6 | * 7 | * http://www.ibsensoftware.com/ 8 | * 9 | * Copyright (c) 2014-2018 by Paul Sokolovsky 10 | * 11 | * This software is provided 'as-is', without any express 12 | * or implied warranty. In no event will the authors be 13 | * held liable for any damages arising from the use of 14 | * this software. 15 | * 16 | * Permission is granted to anyone to use this software 17 | * for any purpose, including commercial applications, 18 | * and to alter it and redistribute it freely, subject to 19 | * the following restrictions: 20 | * 21 | * 1. The origin of this software must not be 22 | * misrepresented; you must not claim that you 23 | * wrote the original software. If you use this 24 | * software in a product, an acknowledgment in 25 | * the product documentation would be appreciated 26 | * but is not required. 27 | * 28 | * 2. Altered source versions must be plainly marked 29 | * as such, and must not be misrepresented as 30 | * being the original software. 31 | * 32 | * 3. This notice may not be removed or altered from 33 | * any source distribution. 34 | */ 35 | 36 | #include "uzlib.h" 37 | 38 | #define FTEXT 1 39 | #define FHCRC 2 40 | #define FEXTRA 4 41 | #define FNAME 8 42 | #define FCOMMENT 16 43 | 44 | void tinf_skip_bytes(struct uzlib_uncomp *d, int num); 45 | uint16_t tinf_get_uint16(struct uzlib_uncomp *d); 46 | 47 | void tinf_skip_bytes(struct uzlib_uncomp *d, int num) 48 | { 49 | while (num--) uzlib_get_byte(d); 50 | } 51 | 52 | uint16_t tinf_get_uint16(struct uzlib_uncomp *d) 53 | { 54 | unsigned int v = uzlib_get_byte(d); 55 | v = (uzlib_get_byte(d) << 8) | v; 56 | return v; 57 | } 58 | 59 | int uzlib_gzip_parse_header(struct uzlib_uncomp *d) 60 | { 61 | unsigned char flg; 62 | 63 | /* -- check format -- */ 64 | 65 | /* check id bytes */ 66 | if (uzlib_get_byte(d) != 0x1f || uzlib_get_byte(d) != 0x8b) return TINF_DATA_ERROR; 67 | 68 | /* check method is deflate */ 69 | if (uzlib_get_byte(d) != 8) return TINF_DATA_ERROR; 70 | 71 | /* get flag byte */ 72 | flg = uzlib_get_byte(d); 73 | 74 | /* check that reserved bits are zero */ 75 | if (flg & 0xe0) return TINF_DATA_ERROR; 76 | 77 | /* -- find start of compressed data -- */ 78 | 79 | /* skip rest of base header of 10 bytes */ 80 | tinf_skip_bytes(d, 6); 81 | 82 | /* skip extra data if present */ 83 | if (flg & FEXTRA) 84 | { 85 | unsigned int xlen = tinf_get_uint16(d); 86 | tinf_skip_bytes(d, xlen); 87 | } 88 | 89 | /* skip file name if present */ 90 | if (flg & FNAME) { while (uzlib_get_byte(d)); } 91 | 92 | /* skip file comment if present */ 93 | if (flg & FCOMMENT) { while (uzlib_get_byte(d)); } 94 | 95 | /* check header crc if present */ 96 | if (flg & FHCRC) 97 | { 98 | /*unsigned int hcrc =*/ tinf_get_uint16(d); 99 | 100 | // TODO: Check! 101 | // if (hcrc != (tinf_crc32(src, start - src) & 0x0000ffff)) 102 | // return TINF_DATA_ERROR; 103 | } 104 | 105 | /* initialize for crc32 checksum */ 106 | d->checksum_type = TINF_CHKSUM_CRC; 107 | d->checksum = ~0; 108 | 109 | return TINF_OK; 110 | } 111 | -------------------------------------------------------------------------------- /lib/MqttHandler/MqttHandler.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "MqttHandler.hpp" 10 | 11 | MqttHandler mqttHandler; 12 | 13 | static WiFiClient wifiClient; 14 | static PubSubClient client(wifiClient); 15 | static long lastReconnectAttempt = 0; 16 | 17 | static void callback(char *topic, byte *payload, unsigned int length) 18 | { 19 | // set_slot 1 power_on 0 20 | char command[32]; 21 | char subcommand[32]; 22 | int slot = -1; 23 | int power_on = -1; 24 | 25 | unsigned int i; 26 | for (i = 0; i < length; i++) 27 | { 28 | buffer2[i] = (char)payload[i]; 29 | } 30 | buffer2[i] = 0; 31 | buffer2[31] = 0; // truncate 32 | logMessage("MQTT: message arrived [%s] = %s", topic, buffer2); 33 | sscanf( buffer2, "%s %d %s %d", command, &slot, subcommand, &power_on ); 34 | if ( strcmp( "set_slot", command ) == 0 35 | && strcmp( "power_on", subcommand ) == 0 36 | && slot >= 1 && slot <= 7 37 | && power_on >= 0 && power_on <= 1 38 | ) 39 | { 40 | logMessage("MQTT: turning slot %d to power %s.", slot, (power_on==1)?"on":"off"); 41 | turingPiHandler.setPower( slot, power_on == 1 ); 42 | } 43 | else 44 | { 45 | logMessage("MQTT(ERROR): unknown command"); 46 | } 47 | 48 | } 49 | 50 | MqttHandler::MqttHandler() 51 | { 52 | initialized = false; 53 | lastPublishTimestamp = 0l; 54 | } 55 | 56 | bool MqttHandler::reconnect() 57 | { 58 | if ((appcfg.mqtt_useauth && 59 | client.connect(appcfg.mqtt_clientid, appcfg.mqtt_user, 60 | appcfg.mqtt_password)) || 61 | (!appcfg.mqtt_useauth && client.connect(appcfg.mqtt_clientid))) 62 | { 63 | LOG0("mqtt broker connected\n"); 64 | client.subscribe(appcfg.mqtt_intopic); 65 | } 66 | 67 | return client.connected(); 68 | } 69 | 70 | //////// 71 | 72 | void MqttHandler::setup() 73 | { 74 | LOG0("MQTT Setup...\n"); 75 | client.setServer(appcfg.mqtt_host, appcfg.mqtt_port); 76 | client.setCallback(callback); 77 | initialized = true; 78 | } 79 | 80 | void MqttHandler::handle(unsigned long now) 81 | { 82 | if (appcfg.mqtt_enabled && wifiHandler.isReady()) 83 | { 84 | if (initialized == false) 85 | { 86 | setup(); 87 | } 88 | 89 | if (!client.connected()) 90 | { 91 | now = millis(); 92 | 93 | if (now - lastReconnectAttempt > 5000) 94 | { 95 | lastReconnectAttempt = now; 96 | reconnect(); 97 | } 98 | } 99 | else 100 | { 101 | client.loop(); 102 | 103 | if (appcfg.mqtt_sending_interval > 0 104 | && (now - lastPublishTimestamp) >= (appcfg.mqtt_sending_interval * 1000)) 105 | { 106 | buildJsonMessage(); 107 | sendValue(appcfg.mqtt_outtopic, buffer); 108 | lastPublishTimestamp = now; 109 | } 110 | } 111 | } 112 | } 113 | 114 | void MqttHandler::sendValue(const char *topic, const char *value) 115 | { 116 | if (appcfg.mqtt_enabled && wifiHandler.isReady() && client.connected()) 117 | { 118 | if (topic != NULL && value != NULL && strlen(topic) > 0 && topic[0] != '-') 119 | { 120 | client.publish(topic, value); 121 | } 122 | } 123 | } 124 | 125 | void MqttHandler::sendValue(const char *topic, const float value) 126 | { 127 | char buffer[32]; 128 | sprintf(buffer, "%0.2f", value); 129 | sendValue(topic, buffer); 130 | } 131 | -------------------------------------------------------------------------------- /lib/Util/Util.cpp: -------------------------------------------------------------------------------- 1 | #include "Util.hpp" 2 | #include 3 | 4 | extern void sendPrint(const char *message); 5 | 6 | char buffer[BUFFER_LENGTH+1]; 7 | char buffer2[BUFFER2_LENGTH+1]; 8 | 9 | #define MAX_MESSAGE_LENGTH 200 10 | #define MESSAGE_BUFFER_LINES 11 11 | char messageBuffer[(MAX_MESSAGE_LENGTH + 1) * MESSAGE_BUFFER_LINES]; 12 | int messageStartIndex = 0; 13 | int messageEndIndex = 0; 14 | 15 | /* 16 | Find the description about the boot device code here: 17 | https://www.sigmdel.ca/michel/program/esp8266/arduino/watchdogs2_en.html 18 | */ 19 | int getBootDevice(void) 20 | { 21 | int bootmode = 0; 22 | asm("movi %0, 0x60000200\n\t" 23 | "l32i %0, %0, 0x118\n\t" 24 | : "+r"(bootmode) /* Output */ 25 | : /* Inputs (none) */ 26 | : "memory" /* Clobbered */ 27 | ); 28 | return ((bootmode >> 0x10) & 0x7); 29 | } 30 | 31 | void alterPin(int pin) 32 | { 33 | digitalWrite(pin, 1 ^ digitalRead(pin)); 34 | } 35 | 36 | void showChipInfo() 37 | { 38 | Serial.println("-- CHIPINFO --"); 39 | Serial.printf("Chip Id = %08X\n", ESP.getChipId()); 40 | 41 | Serial.printf("CPU Frequency = %dMHz\n", ESP.getCpuFreqMHz()); 42 | 43 | uint32_t realSize = ESP.getFlashChipRealSize(); 44 | uint32_t ideSize = ESP.getFlashChipSize(); 45 | FlashMode_t ideMode = ESP.getFlashChipMode(); 46 | 47 | Serial.printf("\nFlash real id: %08X\n", ESP.getFlashChipId()); 48 | Serial.printf("Flash real size: %u\n", realSize); 49 | Serial.printf("Flash ide size: %u\n", ideSize); 50 | Serial.printf("Flash chip speed: %u\n", ESP.getFlashChipSpeed()); 51 | Serial.printf("Flash ide mode: %s\n", (ideMode == FM_QIO ? "QIO" 52 | : ideMode == FM_QOUT ? "QOUT" 53 | : ideMode == FM_DIO ? "DIO" 54 | : ideMode == FM_DOUT ? "DOUT" 55 | : "UNKNOWN")); 56 | 57 | if (ideSize != realSize) 58 | { 59 | Serial.println("Flash Chip configuration wrong!\n"); 60 | } 61 | else 62 | { 63 | Serial.println("Flash Chip configuration ok.\n"); 64 | } 65 | 66 | Serial.printf("Free Heap : %u\n", ESP.getFreeHeap()); 67 | Serial.printf("Sketch Size : %u\n", ESP.getSketchSize()); 68 | Serial.printf("Free Sketch Space : %u\n", ESP.getFreeSketchSpace()); 69 | 70 | Serial.println(); 71 | } 72 | 73 | void fillBuffer(const char *message) 74 | { 75 | strncpy(buffer, message, BUFFER_LENGTH - 1); 76 | buffer[BUFFER_LENGTH - 1] = 0; 77 | } 78 | 79 | void sendHtmlTemplate(const char *htmlTemplate, const char *(*setupProcessor)(const char *)) 80 | { 81 | unsigned int s = 0; 82 | unsigned int d = 0; 83 | char c; 84 | int state = 0; 85 | 86 | while ((c = pgm_read_byte(htmlTemplate + (s++))) > 0) 87 | { 88 | switch (state) 89 | { 90 | case 0: 91 | { 92 | if (c == '%') 93 | { 94 | sendPrint(buffer); 95 | d = 0; 96 | state = 1; 97 | break; 98 | } 99 | 100 | buffer[d++] = c; 101 | buffer[d] = 0; 102 | 103 | if (c == '\n') 104 | { 105 | sendPrint(buffer); 106 | d = 0; 107 | } 108 | break; 109 | } 110 | 111 | case 1: 112 | { 113 | if (c == '%') 114 | { 115 | const char *val = (*setupProcessor)(buffer); 116 | 117 | if (val != nullptr && strlen(val) > 0) 118 | { 119 | sendPrint(val); 120 | } 121 | 122 | d = 0; 123 | state = 0; 124 | break; 125 | } 126 | 127 | buffer[d++] = c; 128 | buffer[d] = 0; 129 | break; 130 | } 131 | } 132 | } 133 | 134 | if (d > 0) 135 | { 136 | sendPrint(buffer); 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /lib/uzlib/uzlib.h: -------------------------------------------------------------------------------- 1 | /* 2 | * uzlib - tiny deflate/inflate library (deflate, gzip, zlib) 3 | * 4 | * Copyright (c) 2003 by Joergen Ibsen / Jibz 5 | * All Rights Reserved 6 | * http://www.ibsensoftware.com/ 7 | * 8 | * Copyright (c) 2014-2018 by Paul Sokolovsky 9 | * 10 | * This software is provided 'as-is', without any express 11 | * or implied warranty. In no event will the authors be 12 | * held liable for any damages arising from the use of 13 | * this software. 14 | * 15 | * Permission is granted to anyone to use this software 16 | * for any purpose, including commercial applications, 17 | * and to alter it and redistribute it freely, subject to 18 | * the following restrictions: 19 | * 20 | * 1. The origin of this software must not be 21 | * misrepresented; you must not claim that you 22 | * wrote the original software. If you use this 23 | * software in a product, an acknowledgment in 24 | * the product documentation would be appreciated 25 | * but is not required. 26 | * 27 | * 2. Altered source versions must be plainly marked 28 | * as such, and must not be misrepresented as 29 | * being the original software. 30 | * 31 | * 3. This notice may not be removed or altered from 32 | * any source distribution. 33 | */ 34 | 35 | #ifndef UZLIB_H_INCLUDED 36 | #define UZLIB_H_INCLUDED 37 | 38 | #include 39 | #include 40 | #include 41 | 42 | #include "defl_static.h" 43 | 44 | #include "uzlib_conf.h" 45 | #if UZLIB_CONF_DEBUG_LOG 46 | #include 47 | #endif 48 | 49 | /* calling convention */ 50 | #ifndef TINFCC 51 | #ifdef __WATCOMC__ 52 | #define TINFCC __cdecl 53 | #else 54 | #define TINFCC 55 | #endif 56 | #endif 57 | 58 | #ifdef __cplusplus 59 | extern "C" { 60 | #endif 61 | 62 | /* ok status, more data produced */ 63 | #define TINF_OK 0 64 | /* end of compressed stream reached */ 65 | #define TINF_DONE 1 66 | #define TINF_DATA_ERROR (-3) 67 | #define TINF_CHKSUM_ERROR (-4) 68 | #define TINF_DICT_ERROR (-5) 69 | 70 | /* checksum types */ 71 | #define TINF_CHKSUM_NONE 0 72 | #define TINF_CHKSUM_ADLER 1 73 | #define TINF_CHKSUM_CRC 2 74 | 75 | /* helper macros */ 76 | #define TINF_ARRAY_SIZE(arr) (sizeof(arr) / sizeof(*(arr))) 77 | 78 | /* data structures */ 79 | 80 | typedef struct { 81 | unsigned short table[16]; /* table of code length counts */ 82 | unsigned short trans[288]; /* code -> symbol translation table */ 83 | } TINF_TREE; 84 | 85 | struct uzlib_uncomp { 86 | /* Pointer to the next byte in the input buffer */ 87 | const unsigned char *source; 88 | /* Pointer to the next byte past the input buffer (source_limit = source + len) */ 89 | const unsigned char *source_limit; 90 | /* If source_limit == NULL, or source >= source_limit, this function 91 | will be used to read next byte from source stream. The function may 92 | also return -1 in case of EOF (or irrecoverable error). Note that 93 | besides returning the next byte, it may also update source and 94 | source_limit fields, thus allowing for buffered operation. */ 95 | int (*source_read_cb)(struct uzlib_uncomp *uncomp); 96 | 97 | unsigned int tag; 98 | unsigned int bitcount; 99 | 100 | /* Destination (output) buffer start */ 101 | unsigned char *dest_start; 102 | /* Current pointer in dest buffer */ 103 | unsigned char *dest; 104 | /* Pointer past the end of the dest buffer, similar to source_limit */ 105 | unsigned char *dest_limit; 106 | 107 | /* Accumulating checksum */ 108 | unsigned int checksum; 109 | char checksum_type; 110 | bool eof; 111 | 112 | int btype; 113 | int bfinal; 114 | unsigned int curlen; 115 | int lzOff; 116 | unsigned char *dict_ring; 117 | unsigned int dict_size; 118 | unsigned int dict_idx; 119 | 120 | TINF_TREE ltree; /* dynamic length/symbol tree */ 121 | TINF_TREE dtree; /* dynamic distance tree */ 122 | }; 123 | 124 | #define TINF_PUT(d, c) \ 125 | { \ 126 | *d->dest++ = c; \ 127 | if (d->dict_ring) { d->dict_ring[d->dict_idx++] = c; if (d->dict_idx == d->dict_size) d->dict_idx = 0; } \ 128 | } 129 | 130 | unsigned char TINFCC uzlib_get_byte(struct uzlib_uncomp *d); 131 | 132 | /* Decompression API */ 133 | 134 | void TINFCC uzlib_init(void); 135 | void TINFCC uzlib_uncompress_init(struct uzlib_uncomp *d, void *dict, unsigned int dictLen); 136 | int TINFCC uzlib_uncompress(struct uzlib_uncomp *d); 137 | int TINFCC uzlib_gzip_parse_header(struct uzlib_uncomp *d); 138 | 139 | #ifdef __cplusplus 140 | } /* extern "C" */ 141 | #endif 142 | 143 | #endif /* UZLIB_H_INCLUDED */ 144 | -------------------------------------------------------------------------------- /lib/WebPages/SaveConfig.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "WebPages.h" 4 | 5 | void paramChars(char *dest, const char *paramName, const char *name, const char *value) 6 | { 7 | if (strcmp(name, paramName) == 0) 8 | { 9 | strncpy(dest, value, 63); 10 | dest[63] = 0; 11 | } 12 | } 13 | 14 | void paramInt(int *dest, const char *paramName, const char *name, const char *value) 15 | { 16 | if (strcmp(name, paramName) == 0) 17 | { 18 | int v = 0; 19 | 20 | if (value != 0 && strlen(value) > 0) 21 | { 22 | v = atoi(value); 23 | } 24 | 25 | *dest = v; 26 | } 27 | } 28 | 29 | void paramUnsignedLong(unsigned long *dest, const char *paramName, const char *name, 30 | const char *value) 31 | { 32 | if (strcmp(name, paramName) == 0) 33 | { 34 | unsigned long v = 0; 35 | 36 | if (value != 0 && strlen(value) > 0) 37 | { 38 | v = atol(value); 39 | } 40 | 41 | *dest = v; 42 | } 43 | } 44 | 45 | void paramBool(bool *dest, const char *paramName, const char *name, const char *value) 46 | { 47 | if (strcmp(name, paramName) == 0) 48 | { 49 | if (value != 0 && strlen(value) > 0) 50 | { 51 | *dest = strcmp("true", value) == 0; 52 | } 53 | } 54 | } 55 | 56 | void storeConfigValue(const char *name, const char *value) 57 | { 58 | // Security 59 | paramChars(appcfgWR.admin_password, A_admin_password, name, value); 60 | 61 | // OTA 62 | paramBool(&appcfgWR.ota_enabled, A_ota_enabled, name, value); 63 | paramChars(appcfgWR.ota_hostname, A_ota_hostname, name, value); 64 | paramChars(appcfgWR.ota_password, A_ota_password, name, value); 65 | 66 | // WIFI 67 | paramInt(&appcfgWR.wifi_mode, A_wifi_mode, name, value); 68 | paramChars(appcfgWR.wifi_ssid, A_wifi_ssid, name, value); 69 | paramChars(appcfgWR.wifi_password, A_wifi_password, name, value); 70 | 71 | // Network 72 | paramInt(&appcfgWR.net_mode, A_net_mode, name, value); 73 | paramChars(appcfgWR.net_host, A_net_host, name, value); 74 | paramChars(appcfgWR.net_gateway, A_net_gateway, name, value); 75 | paramChars(appcfgWR.net_mask, A_net_mask, name, value); 76 | paramChars(appcfgWR.net_dns, A_net_dns, name, value); 77 | 78 | // MQTT 79 | paramBool(&appcfgWR.mqtt_enabled, A_mqtt_enabled, name, value); 80 | paramChars(appcfgWR.mqtt_clientid, A_mqtt_clientid, name, value); 81 | paramChars(appcfgWR.mqtt_host, A_mqtt_host, name, value); 82 | paramInt(&appcfgWR.mqtt_port, A_mqtt_port, name, value); 83 | paramBool(&appcfgWR.mqtt_useauth, A_mqtt_useauth, name, value); 84 | paramChars(appcfgWR.mqtt_user, A_mqtt_user, name, value); 85 | paramChars(appcfgWR.mqtt_password, A_mqtt_password, name, value); 86 | paramChars(appcfgWR.mqtt_intopic, A_mqtt_intopic, name, value); 87 | paramChars(appcfgWR.mqtt_outtopic, A_mqtt_outtopic, name, value); 88 | 89 | paramUnsignedLong(&appcfgWR.mqtt_sending_interval, A_mqtt_sending_interval, name, 90 | value); 91 | 92 | // Telnet 93 | paramBool(&appcfgWR.telnet_enabled, A_telnet_enabled, name, value); 94 | 95 | // NTP 96 | paramBool(&appcfgWR.ntp_enabled, A_ntp_enabled, name, value); 97 | paramChars(appcfgWR.ntp_timezone, A_ntp_timezone, name, value); 98 | paramChars(appcfgWR.ntp_server1, A_ntp_server1, name, value); 99 | paramChars(appcfgWR.ntp_server2, A_ntp_server2, name, value); 100 | paramChars(appcfgWR.ntp_server3, A_ntp_server3, name, value); 101 | 102 | // Ping 103 | paramBool(&appcfgWR.ping_enabled, A_ping_enabled, name, value); 104 | paramUnsignedLong(&appcfgWR.ping_interval, A_ping_interval, name, 105 | value); 106 | paramChars(appcfgWR.ping_addr[0], A_ping_ip_slot1, name, value); 107 | paramChars(appcfgWR.ping_addr[1], A_ping_ip_slot2, name, value); 108 | paramChars(appcfgWR.ping_addr[2], A_ping_ip_slot3, name, value); 109 | paramChars(appcfgWR.ping_addr[3], A_ping_ip_slot4, name, value); 110 | paramChars(appcfgWR.ping_addr[4], A_ping_ip_slot5, name, value); 111 | paramChars(appcfgWR.ping_addr[5], A_ping_ip_slot6, name, value); 112 | paramChars(appcfgWR.ping_addr[6], A_ping_ip_slot7, name, value); 113 | } 114 | 115 | void handleSaveConfigPage() 116 | { 117 | sendAuthentication(); 118 | sendHeader(APP_NAME " - Save Config", true); 119 | sendPrint("
"); 120 | sendLegend("Configuration saved."); 121 | 122 | int numberOfArguments = server.args(); 123 | sendPrint("
");
124 | 
125 |   memset(&appcfgWR, 0, sizeof(appcfgWR));
126 | 
127 |   for (int i = 0; i < numberOfArguments - 1; i++)
128 |   {
129 |     const char *argName = server.argName(i).c_str();
130 |     const char *argValue = server.arg(i).c_str();
131 |     storeConfigValue(argName, argValue);
132 |     sendPrintf("%2d. %s = %s\n", (i + 1), argName, argValue);
133 |   }
134 | 
135 |   sendPrint("

Restarting System ... takes about 30s

"); 136 | sendFooter(); 137 | app.delayedSystemRestart(); 138 | } 139 | -------------------------------------------------------------------------------- /lib/TuringPiHandler/TuringPiHandler.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "TuringPiHandler.hpp" 8 | 9 | /* 10 | (11950) I2C SCL=5 11 | (11953) SDA=4 12 | (11965) Found address: 87 (0x57) Port Extender 13 | (11966) Found address: 92 (0x5C) Switch 14 | (11968) Found address: 111 (0x6F) Real Time Clock DS1307 15 | (11969) Found 3 device(s). 16 | */ 17 | 18 | #define I2C_PE_ADDRESS 0x57 19 | #define I2C_RTC_ADDRESS 0x6F 20 | #define I2C_TPI_REGISTER_CONTROL 0xf2 21 | #define I2C_TPI_REGISTER_STATUS 0xf8 22 | 23 | #define I2C_READ_INTERVAL 10000 24 | 25 | static char datetime_buffer[20]; 26 | static const int daysOfMonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; 27 | 28 | // turing pi 1 slots - 1 2 3 4 5 6 7 29 | static const int slot_masks[] = {0x00, 0x02, 0x04, 0x08, 0x10, 0x80, 0x40, 0x20}; 30 | 31 | // one ping hander for each slot 32 | static AsyncPing pingHandler[7]; 33 | 34 | TuringPiHandler turingPiHandler; 35 | 36 | void TuringPiHandler::setup() 37 | { 38 | 39 | } 40 | 41 | void TuringPiHandler::handle() 42 | { 43 | if ( appcfg.ping_enabled && appcfg.ping_interval > 0 && 44 | (millis() - lastTimestamp) >= (appcfg.ping_interval * 1000)) 45 | { 46 | for (int i = 0; i < 7; i++) 47 | { 48 | if (appcfg.ping_addr[i][0] != 0 && appcfg.ping_addr[i][0] != '-') 49 | { 50 | pingHandler[i].begin(appcfg.ping_addr[i]); 51 | } 52 | } 53 | lastTimestamp = millis(); 54 | } 55 | } 56 | 57 | uint16_t TuringPiHandler::getPingLastRecv(int slot) 58 | { 59 | return pingHandler[slot - 1].response().last_recv; 60 | } 61 | 62 | time_t TuringPiHandler::getPingLastSeen(int slot) 63 | { 64 | return pingHandler[slot - 1].response().last_seen; 65 | } 66 | 67 | uint8_t TuringPiHandler::readRegister(uint8_t bus_addr, uint8_t register_addr) 68 | { 69 | Wire.beginTransmission(bus_addr); 70 | Wire.write(register_addr); 71 | Wire.endTransmission(); 72 | Wire.requestFrom(bus_addr, ((uint8_t)1)); 73 | return Wire.read(); 74 | } 75 | 76 | void TuringPiHandler::writeRegister(uint8_t bus_addr, uint8_t register_addr, uint8_t value) 77 | { 78 | Wire.beginTransmission(bus_addr); 79 | Wire.write(register_addr); 80 | Wire.write(value); 81 | Wire.endTransmission(); 82 | } 83 | 84 | void TuringPiHandler::readRegisters() 85 | { 86 | control = readRegister(I2C_PE_ADDRESS, I2C_TPI_REGISTER_CONTROL); 87 | status = readRegister(I2C_PE_ADDRESS, I2C_TPI_REGISTER_STATUS); 88 | } 89 | 90 | void TuringPiHandler::setPower(int slot, bool power_on) 91 | { 92 | control = readRegister(I2C_PE_ADDRESS, I2C_TPI_REGISTER_CONTROL); 93 | 94 | uint8_t data; 95 | 96 | if (power_on) 97 | { 98 | data = control | slot_masks[slot]; 99 | } 100 | else 101 | { 102 | data = 0xff ^ slot_masks[slot]; 103 | data &= control; 104 | } 105 | 106 | writeRegister(I2C_PE_ADDRESS, I2C_TPI_REGISTER_CONTROL, data); 107 | control = data; 108 | } 109 | 110 | bool TuringPiHandler::getPower(int slot) 111 | { 112 | return (control & slot_masks[slot]) != 0; 113 | } 114 | 115 | // 0=unknown, 1=installed, 2=empty 116 | int TuringPiHandler::getState(int slot) 117 | { 118 | int slot_state = SLOT_STATE_UNKNOWN; 119 | 120 | if (getPower(slot)) 121 | { 122 | if ((status & slot_masks[slot]) != 0) 123 | { 124 | slot_state = SLOT_STATE_INSTALLED; 125 | } 126 | else 127 | { 128 | slot_state = SLOT_STATE_EMPTY; 129 | } 130 | } 131 | else 132 | { 133 | slot_state = SLOT_STATE_UNKNOWN; 134 | } 135 | 136 | return slot_state; 137 | } 138 | 139 | static uint8_t bcd2uint8_t(uint8_t bcd) 140 | { 141 | return 10 * ((bcd & 0x70) >> 4) + (bcd & 0x0f); 142 | } 143 | 144 | const char *TuringPiHandler::getDateTime() 145 | { 146 | Wire.beginTransmission(I2C_RTC_ADDRESS); 147 | Wire.write(0); 148 | Wire.endTransmission(); 149 | Wire.requestFrom(I2C_RTC_ADDRESS, 7); 150 | 151 | uint8_t sec = bcd2uint8_t(Wire.read()); 152 | uint8_t min = bcd2uint8_t(Wire.read()); 153 | uint8_t hou = bcd2uint8_t(Wire.read()); 154 | Wire.read(); // day of week 155 | uint8_t dat = bcd2uint8_t(Wire.read()); 156 | uint8_t mon = bcd2uint8_t(Wire.read()); 157 | uint8_t yea = bcd2uint8_t(Wire.read()); 158 | 159 | datetime_buffer[0] = 0; 160 | sprintf(datetime_buffer, "20%02d-%02d-%02d %02d:%02d:%02d", 161 | yea, mon, dat, hou, min, sec); 162 | datetime_buffer[19] = 0; 163 | 164 | // calc now 165 | int days = dat; 166 | for (int i = 1; i < mon; ++i) 167 | { 168 | days += daysOfMonth[i - 1]; 169 | } 170 | if (mon > 2 && yea % 4 == 0) 171 | { 172 | days++; 173 | } 174 | days = days + 365 * yea + (yea + 3) / 4 - 1; 175 | rtcnow = ((days * 24UL + hou) * 60 + min) * 60 + sec; 176 | rtcnow += 946684800; 177 | 178 | return datetime_buffer; 179 | } 180 | 181 | time_t TuringPiHandler::getTime() 182 | { 183 | return rtcnow; 184 | } 185 | -------------------------------------------------------------------------------- /lib/MicroJson/MicroJson.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "MicroJson.hpp" 5 | 6 | uJson::uJson(File _file) 7 | { 8 | file = _file; 9 | firstEntry = true; 10 | } 11 | 12 | void uJson::writeAttributeName(String entryName) 13 | { 14 | if (firstEntry == false) 15 | { 16 | file.write(",\n"); 17 | } 18 | else 19 | { 20 | firstEntry = false; 21 | } 22 | 23 | file.write(" \""); 24 | file.write(entryName.c_str()); 25 | file.write("\": "); 26 | } 27 | 28 | void uJson::writeHeader() { file.write("{\n"); } 29 | 30 | void uJson::writeEntry(String entryName, bool value) 31 | { 32 | writeAttributeName(entryName); 33 | file.write((value) ? "true" : "false"); 34 | } 35 | 36 | void uJson::writeEntry(String entryName, int value) 37 | { 38 | writeAttributeName(entryName); 39 | sprintf(buffer, "%d", value); 40 | file.write((const char *)buffer); 41 | } 42 | 43 | void uJson::writeEntry(String entryName, unsigned long value) 44 | { 45 | writeAttributeName(entryName); 46 | sprintf(buffer, "%lu", value); 47 | file.write((const char *)buffer); 48 | } 49 | 50 | void uJson::writeEntry(String entryName, const char *value) 51 | { 52 | writeAttributeName(entryName); 53 | file.write("\""); 54 | file.write(value); 55 | file.write("\""); 56 | } 57 | 58 | void uJson::writeFooter() { file.write("\n}\n"); } 59 | 60 | bool uJson::findChar(const int c) 61 | { 62 | return nextNotWhiteSpaceChar() == c; 63 | } 64 | 65 | int uJson::nextNotWhiteSpaceChar() 66 | { 67 | int r; 68 | while ((r = file.read()) >= 0 && (r == ' ' || r == '\r' || r == '\n' || r == '\t' || r == ',' )); 69 | return r; 70 | } 71 | 72 | bool uJson::readHeader() { return findChar('{'); } 73 | 74 | bool uJson::readEntryBoolean(const char *n1, const char *n2, bool *value) 75 | { 76 | if (strcmp(n1, n2) == 0) 77 | { 78 | char nbuffer[16]; 79 | int i = 0; 80 | int r = nextNotWhiteSpaceChar(); 81 | 82 | while( r > 0 && i < 16 && r != ' ' && r != '\t' && r != '\r' && r != '\n' && r != ',' ) 83 | { 84 | nbuffer[i++] = r; 85 | r = file.read(); 86 | } 87 | 88 | if ( r > 0 && i < 16 ) 89 | { 90 | nbuffer[i] = 0; 91 | 92 | if (strcmp("true", nbuffer) == 0) 93 | { 94 | *value = true; 95 | return false; 96 | } 97 | if (strcmp("false", nbuffer) == 0) 98 | { 99 | *value = false; 100 | return false; 101 | } 102 | } 103 | } 104 | else 105 | { 106 | return false; 107 | } 108 | 109 | return true; 110 | } 111 | 112 | bool uJson::readEntryInteger(const char *n1, const char *n2, int *value) 113 | { 114 | if (strcmp(n1, n2) == 0) 115 | { 116 | char nbuffer[32]; 117 | int i = 0; 118 | int r = nextNotWhiteSpaceChar(); 119 | 120 | while( r > 0 && i < 32 && r != ' ' && r != '\t' && r != '\r' && r != '\n' && r != ',' ) 121 | { 122 | nbuffer[i++] = r; 123 | r = file.read(); 124 | } 125 | 126 | if ( r > 0 && i < 32 ) 127 | { 128 | nbuffer[i] = 0; 129 | if ( sscanf( nbuffer, "%d", value ) == 1 ) 130 | { 131 | return false; 132 | } 133 | } 134 | } 135 | else 136 | { 137 | return false; 138 | } 139 | 140 | return true; 141 | } 142 | 143 | bool uJson::readEntryULong(const char *n1, const char *n2, 144 | unsigned long *value) 145 | { 146 | if (strcmp(n1, n2) == 0) 147 | { 148 | char nbuffer[32]; 149 | int i = 0; 150 | int r = nextNotWhiteSpaceChar(); 151 | 152 | while( r > 0 && i < 32 && r != ' ' && r != '\t' && r != '\r' && r != '\n' && r != ',' ) 153 | { 154 | nbuffer[i++] = r; 155 | r = file.read(); 156 | } 157 | 158 | if ( r > 0 && i < 32 ) 159 | { 160 | nbuffer[i] = 0; 161 | if ( sscanf( nbuffer, "%lu", value ) == 1 ) 162 | { 163 | return false; 164 | } 165 | } 166 | } 167 | else 168 | { 169 | return false; 170 | } 171 | 172 | return true; 173 | } 174 | 175 | bool uJson::readEntryChars(const char *n1, const char *n2, char *value) 176 | { 177 | if (strcmp(n1, n2) == 0 && findChar('"')) 178 | { 179 | int i = 0; 180 | int r; 181 | while ((r = file.read()) >= 0 && r != '"' && i < 64) 182 | { 183 | value[i++] = r; 184 | } 185 | if (r == '"' && i < 64) 186 | { 187 | value[i] = 0; 188 | return false; 189 | } 190 | } 191 | else 192 | { 193 | return false; 194 | } 195 | 196 | return true; 197 | } 198 | 199 | bool uJson::readAttributeName(char *attributeName) 200 | { 201 | bool attributeNameFound = false; 202 | if (findChar('"') == true) 203 | { 204 | int i = 0; 205 | int r; 206 | while ((r = file.read()) >= 0 && r != '"' && i < 128) 207 | { 208 | attributeName[i++] = r; 209 | } 210 | if (r == '"' && i < 128 && findChar(':')) 211 | { 212 | attributeName[i] = 0; 213 | attributeNameFound = true; 214 | } 215 | } 216 | 217 | return attributeNameFound; 218 | } 219 | -------------------------------------------------------------------------------- /include/html/maintenance.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | const char MAINTENANCE_STYLE[] PROGMEM = 4 | "\n"; 13 | 14 | const char MAINTENANCE_HTML_TEMPLATE[] PROGMEM = 15 | 16 | "
\n" 17 | "
\n" 18 | "

Firmware upload in progress...

\n" 19 | "
\n" 20 | "
\n" 21 | 22 | "
Backup & Restore Configuration
\n" 23 | "
\n" 24 | 25 | "
\n" 26 | "
\n" 27 | "Backup Configuration\n" 28 | "

\n" 29 | "
\n" 30 | "
\n" 31 | 32 | "
\n" 33 | "
\n" 34 | "Restore Configuration\n" 35 | "
\n" 36 | "\n" 37 | "\n" 38 | "
\n" 39 | "

\n" 40 | "
\n" 41 | "
\n" 42 | "
\n" 43 | "\n" 44 | 45 | "
Firmware
\n" 46 | "
\n" 47 | 48 | "
\n" 49 | "
\n" 50 | "Upload new firmware\n" 51 | "
\n" 52 | "\n" 53 | "\n" 54 | "
\n" 55 | "

\n" 56 | "
\n" 57 | "
\n" 58 | 59 | "
\n" 60 | "
\n" 61 | "Firmware Reset\n" 62 | "
\n" 63 | "
\n" 64 | "
\n" 65 | "

\n" 66 | "
\n" 67 | "
\n" 68 | 69 | "
\n" 70 | 71 | "
System
\n" 72 | "
\n" 73 | "
\n" 74 | "
\n" 75 | "Restart system\n" 76 | "

\n" 77 | "
\n" 78 | "
\n" 79 | "
\n" 80 | 81 | "

 

\n" 82 | 83 | "\n" 92 | ; -------------------------------------------------------------------------------- /lib/AsyncPing/src/AsyncPing.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "AsyncPing.h" 3 | #include "ESP8266WiFi.h" 4 | 5 | extern "C" { 6 | #include 7 | #include 8 | #include 9 | } 10 | 11 | #define PING_DATA_SIZE 64 - 8 12 | 13 | AsyncPing::AsyncPing() { 14 | ping_id = random(1 << 31); 15 | ping_pcb = NULL; 16 | _on_recv = NULL; 17 | _on_sent = NULL; 18 | count_down = 0; 19 | _response.last_seen = 0; 20 | _response.last_recv = 0; 21 | _response.total_recv = 0; 22 | memset(&_timer, 0, sizeof(_timer)); 23 | memset(&_timer_recv, 0, sizeof(_timer_recv)); 24 | } 25 | 26 | AsyncPing::~AsyncPing() { 27 | os_timer_disarm(&_timer); 28 | os_timer_disarm(&_timer_recv); 29 | done(); 30 | } 31 | 32 | void AsyncPing::on(bool mode, THandlerFunction fn) { 33 | if(mode) 34 | _on_recv=fn; 35 | else 36 | _on_sent=fn; 37 | } 38 | 39 | bool AsyncPing::begin(const IPAddress &addr,u8_t count,u32_t timeout) { 40 | if(!count || count_down) 41 | return false; 42 | _response.icmp_seq = 0; 43 | _response.total_sent = 0; 44 | _response.total_recv = 0; 45 | _response.total_time = 0; 46 | _response.addr = addr; 47 | _response.timeout = timeout; 48 | _response.mac = NULL; 49 | count_down = count; 50 | if (!ping_pcb) { 51 | ping_pcb = raw_new(IP_PROTO_ICMP); 52 | raw_recv(ping_pcb, _s_ping_recv, reinterpret_cast(this)); 53 | raw_bind(ping_pcb, IP_ADDR_ANY); 54 | } 55 | ping_target.addr = addr; 56 | ping_sent = sys_now(); // micro? system_get_time(); 57 | send_packet(); 58 | return true; 59 | } 60 | 61 | bool AsyncPing::begin(const char *host, u8_t count, u32_t timeout) { 62 | IPAddress ip; 63 | if (WiFi.hostByName(host, ip)) 64 | return begin(ip, count, timeout); 65 | return false; 66 | } 67 | 68 | void AsyncPing::send_packet() { 69 | _response.answer = false; 70 | ping_send(ping_pcb, &ping_target); 71 | _response.total_sent++; 72 | count_down--; 73 | os_timer_disarm(&_timer); 74 | os_timer_setfn(&_timer, reinterpret_cast(_s_timer), reinterpret_cast(this)); 75 | os_timer_arm(&_timer, _response.timeout, 0); 76 | } 77 | 78 | void AsyncPing::cancel() { 79 | count_down = 0; 80 | } 81 | 82 | void AsyncPing::timer() { 83 | os_timer_disarm(&_timer); 84 | if(!_response.answer) 85 | if(_on_recv) 86 | if(_on_recv(_response)) 87 | cancel(); 88 | if(count_down){ 89 | send_packet(); 90 | }else{ 91 | _response.total_time = sys_now() - ping_sent; //micro? system_get_time() 92 | if(_on_sent) 93 | _on_sent(_response); 94 | done(); 95 | } 96 | } 97 | 98 | void AsyncPing::done() { 99 | _response.last_recv = _response.total_recv; 100 | if (ping_pcb) { 101 | raw_remove(ping_pcb); 102 | ping_pcb = NULL; 103 | } 104 | } 105 | 106 | void AsyncPing::ping_send(struct raw_pcb *raw, ip_addr_t *addr) { 107 | struct pbuf *p = NULL; 108 | struct icmp_echo_hdr *iecho = NULL; 109 | _response.size = sizeof(struct icmp_echo_hdr) + PING_DATA_SIZE; 110 | 111 | p = pbuf_alloc(PBUF_IP, (u16_t)_response.size, PBUF_RAM); 112 | if (!p) { 113 | return; 114 | } 115 | if ((p->len == p->tot_len) && (p->next == NULL)) { 116 | iecho = (struct icmp_echo_hdr *)p->payload; 117 | 118 | ping_prepare_echo(iecho, (u16_t)_response.size); 119 | raw_sendto(raw, p, addr); 120 | ping_start = sys_now(); 121 | } 122 | pbuf_free(p); 123 | } 124 | 125 | void AsyncPing::ping_prepare_echo(struct icmp_echo_hdr *iecho, u16_t len) { 126 | size_t i = 0; 127 | size_t data_len = len - sizeof(struct icmp_echo_hdr); 128 | 129 | ICMPH_TYPE_SET(iecho, ICMP_ECHO); 130 | ICMPH_CODE_SET(iecho, 0); 131 | iecho->chksum = 0; 132 | iecho->id = ping_id; 133 | ++ _response.icmp_seq; 134 | if (_response.icmp_seq == 0x7fff) 135 | _response.icmp_seq = 0; 136 | 137 | iecho->seqno = htons(_response.icmp_seq); 138 | 139 | /* fill the additional data buffer with some data */ 140 | for(i = 0; i < data_len; i++) { 141 | ((char*)iecho)[sizeof(struct icmp_echo_hdr) + i] = (char)i; 142 | } 143 | 144 | iecho->chksum = inet_chksum(iecho, len); 145 | } 146 | 147 | u8_t AsyncPing::ping_recv (raw_pcb*pcb, pbuf*p, C_IP_ADDR ip_addr_t *addr) { 148 | struct icmp_echo_hdr *iecho = NULL; 149 | struct ip_hdr *ip = (struct ip_hdr *)p->payload; 150 | if (pbuf_header( p, -PBUF_IP_HLEN) == 0) { 151 | iecho = (struct icmp_echo_hdr *)p->payload; 152 | if ((iecho->id == ping_id) && (iecho->seqno == htons(_response.icmp_seq)) && iecho->type == ICMP_ER) { 153 | _response.time = sys_now() - ping_start; 154 | _response.ttl = ip->_ttl; 155 | _response.answer = true; 156 | _response.total_recv++; 157 | _response.last_seen = time(nullptr); 158 | C_IP_ADDR ip_addr_t *unused_ipaddr; 159 | if (_response.mac == NULL) 160 | etharp_find_addr(NULL, addr, &_response.mac, &unused_ipaddr); 161 | if (_on_recv){ 162 | os_timer_disarm(&_timer_recv); 163 | os_timer_setfn(&_timer_recv, reinterpret_cast(_s_timer_recv), reinterpret_cast(this)); 164 | os_timer_arm(&_timer_recv, 1, 0); 165 | } 166 | pbuf_free(p); 167 | return 1; /* eat the packet */ 168 | } 169 | } 170 | pbuf_header( p, PBUF_IP_HLEN); 171 | return 0; /* don't eat the packet */ 172 | } 173 | 174 | u8_t AsyncPing::_s_ping_recv (void*arg, raw_pcb*tpcb, pbuf*pb, C_IP_ADDR ip_addr_t *addr){ 175 | return reinterpret_cast(arg)->ping_recv(tpcb, pb, addr); 176 | } 177 | 178 | void AsyncPing::_s_timer (void*arg){ 179 | return reinterpret_cast(arg)->timer(); 180 | } 181 | void AsyncPing::_s_timer_recv (void*arg){ 182 | AsyncPing &host = *reinterpret_cast(arg); 183 | os_timer_disarm(&host._timer_recv); 184 | if (host._on_recv) 185 | if(host._on_recv(host._response)) 186 | host.cancel(); 187 | } 188 | -------------------------------------------------------------------------------- /lib/WebPages/RootPage.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "WebPages.h" 3 | 4 | static char titleBuffer[100]; 5 | 6 | const char ROOT_STYLE[] PROGMEM = 7 | "\n"; 17 | 18 | const char SLOT_STATES_SCRIPT[] PROGMEM = 19 | "\n"; 68 | 69 | void handleRootPage() 70 | { 71 | sprintf(titleBuffer, APP_NAME " - %s", appcfg.ota_hostname ); 72 | sendHeader(titleBuffer, false, ROOT_STYLE); 73 | 74 | sendPrint("
"); 75 | 76 | sendLegend("Slots"); 77 | sendPrint("
"); 78 | sendLegend("Real Time Clock"); 79 | sendPrint("
"); 80 | sendPrint("
\n"); 81 | 82 | sendPrint(SLOT_STATES_SCRIPT); 83 | 84 | sendFooter(); 85 | } 86 | -------------------------------------------------------------------------------- /lib/TelnetStream/TelnetStream.cpp: -------------------------------------------------------------------------------- 1 | #include "App.hpp" 2 | #include "Util.hpp" 3 | #include 4 | #include "TelnetStream.h" 5 | 6 | static String tpiStatusStr[] = {"-", "installed", "emtpy"}; 7 | static bool escape; 8 | 9 | void testFn() 10 | { 11 | TelnetStream.println("Test Function"); 12 | } 13 | 14 | extern const char *getJsonStatus(WiFiClient *client); 15 | 16 | void TelnetStreamClass::printHelp() 17 | { 18 | TelnetStream.println("\n\nHELP page\n" 19 | "help : this help\n" 20 | "info : Turing Pi slot information\n" 21 | "set_slot [1..7] power_on [0|1] : turn a slot power on/off \n" 22 | "banner : print banner\n" 23 | "uptime : uptime\n" 24 | "json : json status\n" 25 | "quit,exit : quit / exit this session\n"); 26 | } 27 | 28 | void TelnetStreamClass::printBanner() 29 | { 30 | appShowHeader(TelnetStream); 31 | TelnetStream.printf("Uptime : %s\n", appUptime()); 32 | TelnetStream.printf("Client IP-Address = %s\n\n", 33 | client.remoteIP().toString().c_str()); 34 | } 35 | 36 | TelnetStreamClass::TelnetStreamClass(uint16_t port) : server(port) 37 | { 38 | } 39 | 40 | void TelnetStreamClass::begin() 41 | { 42 | escape = false; 43 | commandIndex = 0; 44 | commandLine[0] = 0; 45 | isConnected = false; 46 | server.begin(); 47 | client = server.available(); 48 | LOG0("Telnet server startet\n"); 49 | } 50 | 51 | void TelnetStreamClass::handle() 52 | { 53 | TelnetStream.available(); 54 | 55 | if (client && client.connected()) 56 | { 57 | if (isConnected == false) 58 | { 59 | isConnected = true; 60 | printBanner(); 61 | } 62 | 63 | if (TelnetStream.available()) 64 | { 65 | int c = TelnetStream.read(); 66 | 67 | if (escape == false && (c == 10 || c == 13 || (c > 31 && c < 127))) 68 | { 69 | if ((c == 10 || c == 13) && commandIndex > 0) 70 | { 71 | // logMessage("command = <%s>", commandLine); 72 | 73 | int cmd = commandLine[0] & 0x00df; 74 | 75 | switch (cmd) 76 | { 77 | case 'B': 78 | printBanner(); 79 | break; 80 | 81 | case 'U': 82 | TelnetStream.printf("\nTime : %s\n", appDateTime()); 83 | TelnetStream.printf("Uptime : %s\n", appUptime()); 84 | TelnetStream.printf("Free Heap : %u\n", ESP.getFreeHeap()); 85 | TelnetStream.println(); 86 | break; 87 | 88 | case 'J': 89 | TelnetStream.println(getJsonStatus(&client)); 90 | break; 91 | 92 | case 'H': 93 | printHelp(); 94 | break; 95 | 96 | case 'I': 97 | { 98 | TelnetStream.printf("RTC: (%lu) %s (UTC)\n", 99 | turingPiHandler.getTime(), turingPiHandler.getDateTime()); 100 | TelnetStream.printf("NTP: (%lu) %s\n\n", 101 | time(nullptr), appDateTime()); 102 | turingPiHandler.readRegisters(); 103 | for (int slot = 1; slot < 8; slot++) 104 | { 105 | TelnetStream.printf("slot #%d : %s : %s (%d : %s)\n", slot, 106 | (turingPiHandler.getPower(slot)) ? "ON " : "OFF", 107 | tpiStatusStr[turingPiHandler.getState(slot)].c_str(), 108 | turingPiHandler.getPingLastRecv(slot), 109 | appDateTime(turingPiHandler.getPingLastSeen(slot))); 110 | } 111 | } 112 | break; 113 | 114 | case 'S': 115 | { 116 | char command[32]; 117 | char subcommand[32]; 118 | int slot = -1; 119 | int power_on = -1; 120 | 121 | sscanf(commandLine, "%s %d %s %d", command, &slot, subcommand, &power_on); 122 | if (strcmp("set_slot", command) == 0 123 | && strcmp("power_on", subcommand) == 0 124 | && slot >= 1 && slot <= 7 && power_on >= 0 && power_on <= 1) 125 | { 126 | logMessage("Turning slot %d to power %s.", slot, (power_on == 1) ? "on" : "off"); 127 | turingPiHandler.setPower(slot, power_on == 1); 128 | } 129 | else 130 | { 131 | logMessage("unknown command"); 132 | } 133 | } 134 | break; 135 | 136 | case 'Q': 137 | case 'E': 138 | isConnected = false; 139 | stop(); 140 | break; 141 | } 142 | 143 | commandLine[0] = 0; 144 | commandIndex = 0; 145 | } 146 | else 147 | { 148 | if (commandIndex < 31 && c > 31) 149 | { 150 | commandLine[commandIndex++] = c; 151 | commandLine[commandIndex] = 0; 152 | } 153 | } 154 | } 155 | 156 | escape = c > 127; 157 | } 158 | } 159 | } 160 | 161 | void TelnetStreamClass::stop() 162 | { 163 | client.stop(); 164 | } 165 | 166 | boolean TelnetStreamClass::disconnected() 167 | { 168 | #ifdef ESP32 169 | if (!server) 170 | return true; 171 | #else 172 | if (server.status() == CLOSED) 173 | return true; 174 | #endif 175 | if (!client) 176 | { 177 | client = server.available(); 178 | } 179 | if (client) 180 | { 181 | if (client.connected()) 182 | return false; 183 | client.stop(); 184 | client = server.available(); 185 | } 186 | isConnected = false; 187 | return true; 188 | } 189 | 190 | int TelnetStreamClass::read() 191 | { 192 | if (disconnected()) 193 | return -1; 194 | return client.read(); 195 | } 196 | 197 | int TelnetStreamClass::available() 198 | { 199 | if (disconnected()) 200 | return 0; 201 | return client.available(); 202 | } 203 | 204 | int TelnetStreamClass::peek() 205 | { 206 | if (disconnected()) 207 | return -1; 208 | return client.peek(); 209 | } 210 | 211 | size_t TelnetStreamClass::write(uint8_t val) 212 | { 213 | if (disconnected()) 214 | return 1; 215 | return client.write(val); 216 | } 217 | 218 | void TelnetStreamClass::flush() 219 | { 220 | if (disconnected()) 221 | return; 222 | client.flush(); 223 | } 224 | 225 | TelnetStreamClass TelnetStream(23); 226 | -------------------------------------------------------------------------------- /lib/AsyncPing/LICENSE.txt: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /lib/WifiHandler/WifiHandler.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "WifiHandler.hpp" 9 | 10 | WifiHandler wifiHandler; 11 | 12 | SimpleLinkedList wifiNetworkLists; 13 | const char *phyModes[] = {"11B", "11G", "11N"}; 14 | char ipBuffer[32]; 15 | DNSServer dnsServer; 16 | 17 | static time_t lastTimestamp; 18 | 19 | static void wifiOff() 20 | { 21 | app.wifiLedOff(); 22 | WiFi.persistent(false); 23 | WiFi.mode(WIFI_OFF); 24 | WiFi.setOutputPower(0.0f); 25 | WiFi.hostname(appcfg.ota_hostname); 26 | } 27 | 28 | static void wifiInitStationMode() 29 | { 30 | WiFi.persistent(false); 31 | WiFi.disconnect(true); 32 | delay(200); 33 | WiFi.begin(); 34 | WiFi.mode(WIFI_STA); 35 | WiFi.hostname(appcfg.ota_hostname); 36 | WiFi.setSleepMode(WIFI_NONE_SLEEP); 37 | 38 | LOG0("Starting Wifi in Station Mode\n"); 39 | LOG1(" - Connecting to %s\n", appcfg.wifi_ssid); 40 | 41 | if (appcfg.net_mode == NET_MODE_STATIC) 42 | { 43 | LOG0("use static ip address"); 44 | IPAddress host; 45 | host.fromString(appcfg.net_host); 46 | IPAddress gateway; 47 | gateway.fromString(appcfg.net_gateway); 48 | IPAddress mask; 49 | mask.fromString(appcfg.net_mask); 50 | IPAddress dns; 51 | dns.fromString(appcfg.net_dns); 52 | WiFi.config(host, gateway, mask, dns); 53 | // DNS WiFi.dnsIP(dns); // platform <= espressif8266@1.8.0 54 | } 55 | else 56 | { 57 | LOG0("use dhcp server"); 58 | } 59 | 60 | configTime(appcfg.ntp_timezone, appcfg.ntp_server1, appcfg.ntp_server2, appcfg.ntp_server3); 61 | WiFi.begin(appcfg.wifi_ssid, appcfg.wifi_password); 62 | } 63 | 64 | void WifiHandler::setup() 65 | { 66 | LOG0("WiFi Setup started...\n"); 67 | connected = false; 68 | lastTimestamp = 0; 69 | 70 | wifiOff(); 71 | 72 | scanNetworks(); 73 | 74 | wifiOff(); 75 | 76 | if (isInStationMode()) 77 | { 78 | wifiInitStationMode(); 79 | } 80 | else 81 | { 82 | LOG0("Starting Wifi Access Point Mode\n"); 83 | char buffer[64]; 84 | sprintf(buffer, DEFAULT_WIFI_SSID, ESP.getChipId()); 85 | strcpy(appcfg.wifi_ssid, buffer); 86 | 87 | WiFi.mode(WIFI_AP); 88 | 89 | IPAddress host; 90 | host.fromString(appcfg.net_host); 91 | IPAddress gateway; 92 | gateway.fromString(appcfg.net_gateway); 93 | IPAddress mask; 94 | mask.fromString(appcfg.net_mask); 95 | 96 | WiFi.softAPConfig(host, gateway, mask); 97 | WiFi.softAP(appcfg.wifi_ssid, appcfg.wifi_password); 98 | Serial.print("AP IP address: "); 99 | Serial.println(WiFi.softAPIP()); 100 | 101 | dnsServer.setErrorReplyCode(DNSReplyCode::NoError); 102 | dnsServer.start(53, "*", WiFi.softAPIP()); 103 | LOG0("DNS server started.\n"); 104 | 105 | app.wifiLedOn(); 106 | connected = true; 107 | } 108 | 109 | WiFi.macAddress(mac); 110 | sprintf(macAddress, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], 111 | mac[1], mac[2], mac[3], mac[4], mac[5]); 112 | } 113 | 114 | const bool WifiHandler::handle(time_t timestamp) 115 | { 116 | if (isInStationMode()) 117 | { 118 | if (timestamp - lastTimestamp >= 500) 119 | { 120 | lastTimestamp = timestamp; 121 | int status = WiFi.status(); 122 | 123 | if (connected) 124 | { 125 | if (status == WL_CONNECTED) 126 | { 127 | return true; 128 | } 129 | else 130 | { 131 | LOG0("WARNING: WiFi connection lost!\n"); 132 | 133 | wifiOff(); 134 | wifiInitStationMode(); 135 | 136 | connected = false; 137 | } 138 | } 139 | else 140 | { 141 | if (status == WL_CONNECTED) 142 | { 143 | Serial.println("\n"); 144 | Serial.printf("WiFi connected to %s\n", appcfg.wifi_ssid); 145 | 146 | connectCounter++; 147 | 148 | if (appcfg.net_mode == NET_MODE_DHCP) 149 | { 150 | Serial.println("copy wifi config from dhcp response"); 151 | strncpy(appcfg.net_host, WiFi.localIP().toString().c_str(), 63); 152 | strncpy(appcfg.net_gateway, WiFi.gatewayIP().toString().c_str(), 63); 153 | strncpy(appcfg.net_mask, WiFi.subnetMask().toString().c_str(), 63); 154 | strncpy(appcfg.net_dns, WiFi.dnsIP().toString().c_str(), 63); 155 | } 156 | 157 | Serial.printf(" - host ip address: %s\n", WiFi.localIP().toString().c_str()); 158 | Serial.printf(" - gateway: %s\n", WiFi.gatewayIP().toString().c_str()); 159 | Serial.printf(" - mask: %s\n", WiFi.subnetMask().toString().c_str()); 160 | Serial.printf(" - dns server: %s\n", WiFi.dnsIP().toString().c_str()); 161 | Serial.printf(" - WiFi Channel: %d\n", WiFi.channel()); 162 | Serial.printf(" - WiFi phy mode: %s\n", getPhyMode()); 163 | Serial.printf(" - WiFi MAC Address: %s\n", macAddress); 164 | Serial.printf(" - WiFi Hostname: %s\n", WiFi.hostname().c_str()); 165 | 166 | Serial.println(); 167 | app.wifiLedOn(); 168 | connected = true; 169 | MDNS.update(); 170 | 171 | if (appcfg.telnet_enabled) 172 | { 173 | TelnetStream.begin(); 174 | } 175 | 176 | bool timeNotSet = true; 177 | 178 | if (appcfg.ntp_enabled) 179 | { 180 | struct tm timeinfo; 181 | 182 | for (int i = 0; i < 15; i++) 183 | { 184 | time_t now = time(nullptr); 185 | localtime_r(&now, &timeinfo); 186 | if (timeinfo.tm_year >= 120) 187 | { 188 | timeNotSet = false; 189 | break; 190 | } 191 | else 192 | { 193 | delay(1000); 194 | } 195 | } 196 | } 197 | 198 | logMessage("Time : %s", appDateTime()); 199 | 200 | if (timeNotSet) 201 | { 202 | logMessage("Time not set"); 203 | } 204 | else 205 | { 206 | if (getenv("TZ") != nullptr) 207 | { 208 | logMessage("Timezone : %s", getenv("TZ")); 209 | } 210 | else 211 | { 212 | logMessage("Timezone not set"); 213 | } 214 | } 215 | 216 | Serial.println(); 217 | } 218 | else 219 | { 220 | Serial.print("."); 221 | app.wifiLedToggle(); 222 | } 223 | } 224 | } 225 | } 226 | else // AP-Mode 227 | { 228 | dnsServer.processNextRequest(); 229 | } 230 | 231 | return connected; 232 | } 233 | 234 | const bool WifiHandler::isInStationMode() 235 | { 236 | return (appcfg.wifi_mode == WIFI_STA); 237 | } 238 | 239 | const bool WifiHandler::isConnected() 240 | { 241 | return connected; 242 | } 243 | 244 | const bool WifiHandler::isReady() 245 | { 246 | return isConnected() && isInStationMode(); 247 | } 248 | 249 | const char *WifiHandler::scanNetworks() 250 | { 251 | networkBuffer[0] = 0; 252 | 253 | Serial.println("\nScanning WiFi networks..."); 254 | int n = WiFi.scanNetworks(false, false); 255 | Serial.println("done."); 256 | 257 | if (n == 0) 258 | { 259 | Serial.println("no networks found"); 260 | strcpy(networkBuffer, "no networks found"); 261 | } 262 | else 263 | { 264 | Serial.print(n); 265 | Serial.println(" networks found"); 266 | int l = 0; 267 | 268 | for (int i = 0; i < n; ++i) 269 | { 270 | l += sprintf(networkBuffer + l, "%2d: %s (%d)%s\n", i + 1, 271 | WiFi.SSID(i).c_str(), WiFi.RSSI(i), 272 | (WiFi.encryptionType(i) == ENC_TYPE_NONE) ? " " : "*"); 273 | wifiNetworkLists.put(WiFi.SSID(i).c_str()); 274 | delay(5); 275 | } 276 | } 277 | 278 | Serial.println("----------------------------------------------"); 279 | Serial.print(networkBuffer); 280 | Serial.println("----------------------------------------------"); 281 | 282 | return networkBuffer; 283 | } 284 | 285 | ListNode *WifiHandler::getScannedNetworks() 286 | { 287 | return wifiNetworkLists.getRootNode(); 288 | } 289 | 290 | const char *WifiHandler::getLocalIP() 291 | { 292 | strncpy(ipBuffer, WiFi.localIP().toString().c_str(), 31); 293 | ipBuffer[31] = 0; 294 | return ipBuffer; 295 | } 296 | 297 | int WifiHandler::getConnectCounter() 298 | { 299 | return connectCounter; 300 | } 301 | 302 | const char *WifiHandler::getMacAddress() 303 | { 304 | return macAddress; 305 | } 306 | 307 | const char *WifiHandler::getPhyMode() 308 | { 309 | return phyModes[WiFi.getPhyMode() - 1]; 310 | } 311 | 312 | const char *WifiHandler::getHostname() 313 | { 314 | return appcfg.ota_hostname; 315 | } 316 | -------------------------------------------------------------------------------- /include/html/setup.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | const char SETUP_HTML_TEMPLATE[] PROGMEM = 4 | "\n" 5 | "
\n" 6 | 7 | "
Turing Pi
\n" 8 | "
\n" 9 | "
\n" 10 | 11 | "
Ping
\n" 12 | "
\n" 13 | "
\n" 14 | "
\n" 15 | "
\n" 16 | "
\n" 17 | "
\n" 18 | "
\n" 19 | "
\n" 20 | "
\n" 21 | "
\n" 22 | "
\n" 23 | "
\n" 24 | 25 | "
Security
\n" 26 | "
\n" 27 | "
\n" 28 | 29 | "
Setup 'admin' user
\n" 30 | "
\n" 31 | "
\n" 32 | "
\n" 33 | "
\n" 34 | 35 | "
Network
\n" 36 | "
\n" 37 | "
\n" 38 | "
General
\n" 39 | "
\n" 40 | "
\n" 41 | "
\n" 42 | 43 | "
WiFi
\n" 44 | "
\n" 45 | "
\n" 46 | "
\n" 47 | "
\n" 48 | "
\n" 49 | "
\n" 50 | 51 | "
Interface
\n" 52 | "
\n" 53 | "
\n" 54 | "
\n" 55 | "
\n" 56 | "
\n" 57 | "
\n" 58 | "
\n" 59 | "
\n" 60 | 61 | "
Services
\n" 62 | "
\n" 63 | "
\n" 64 | 65 | "
MQTT
\n" 66 | "
\n" 67 | "
\n" 68 | "
\n" 69 | "
\n" 70 | "
\n" 71 | "
\n" 72 | "
\n" 73 | "
\n" 74 | "
\n" 75 | "
\n" 76 | "
\n" 77 | "
\n" 78 | 79 | "
Telnet
\n" 80 | "
\n" 81 | "
\n" 82 | "
\n" 83 | 84 | "
Over The Air - firmware update (OTA)
\n" 85 | "
\n" 86 | "
\n" 87 | "
\n" 88 | "
\n" 89 | 90 | "
NTP (Timeservice)
\n" 91 | "
\n" 92 | "
\n" 93 | "
\n" 94 | "
\n" 95 | "
\n" 96 | "
\n" 97 | "
\n" 98 | 99 | "
\n" 100 | "\n

\n" 101 | "
\n" 102 | 103 | "

 

\n" 104 | ; 105 | -------------------------------------------------------------------------------- /lib/WebHandler/WebHandler.cpp: -------------------------------------------------------------------------------- 1 | #include "WebHandler.hpp" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | const char META_REFRESH30[] PROGMEM = 25 | ""; 26 | 27 | static struct uzlib_uncomp uzLibDecompressor; 28 | static uint32_t uzlib_bytesleft; 29 | 30 | size_t fsTotalBytes; 31 | size_t fsUsedBytes; 32 | 33 | WebHandler webHandler; 34 | ESP8266WebServer server(80); 35 | 36 | const char *getJsonStatus(WiFiClient *client) 37 | { 38 | int remotePort = 0; 39 | char remoteAddress[32] = {0}; 40 | 41 | if (client != NULL) 42 | { 43 | remotePort = client->remotePort(); 44 | strncpy(remoteAddress, client->remoteIP().toString().c_str(), 31); 45 | } 46 | else 47 | { 48 | remotePort = server.client().remotePort(); 49 | strncpy(remoteAddress, server.client().remoteIP().toString().c_str(), 31); 50 | } 51 | 52 | sprintf(buffer, 53 | "{" 54 | "\"millis\":%lu," 55 | "\"uptime\":\"%s\"," 56 | "\"host_name\":\"%s.local\"," 57 | "\"esp_full_version\":\"%s\"," 58 | "\"esp_core_version\":\"%s\"," 59 | "\"esp_sdk_version\":\"%s\"," 60 | "\"platformio_env\":\"%s\"," 61 | "\"platformio_platform\":\"%s\"," 62 | "\"platformio_framework\":\"%s\"," 63 | "\"arduino_board\":\"%s\"," 64 | "\"chip_id\":\"%08X\"," 65 | "\"cpu_freq\":\"%dMhz\"," 66 | "\"flash_size\":%u," 67 | "\"flash_speed\":%u," 68 | "\"ide_size\":%u," 69 | "\"fw_name\":\"%s\"," 70 | "\"fw_version\":\"%s\"," 71 | "\"build_date\":\"%s\"," 72 | "\"build_time\":\"%s\"," 73 | "\"wifi_ssid\":\"%s\"," 74 | "\"wifi_reconnect_counter\":%d," 75 | "\"wifi_channel\":%d," 76 | "\"wifi_phy_mode\":\"%s\"," 77 | "\"wifi_mac_address\":\"%s\"," 78 | "\"wifi_hostname\":\"%s\"," 79 | "\"wifi_ip_address\":\"%s\"," 80 | "\"wifi_gateway_ip\":\"%s\"," 81 | "\"wifi_subnet_mask\":\"%s\"," 82 | "\"wifi_dns_ip\":\"%s\"," 83 | "\"spiffs_total\":%u," 84 | "\"spiffs_used\":%u," 85 | "\"free_heap\":%u," 86 | "\"sketch_size\":%u," 87 | "\"free_sketch_space\":%u," 88 | "\"remote_client_ip\":\"%s\"," 89 | "\"remote_client_port\":%u" 90 | "}", 91 | millis(), appUptime(), wifiHandler.getHostname(), 92 | ESP.getFullVersion().c_str(), ESP.getCoreVersion().c_str(), 93 | ESP.getSdkVersion(), PIOENV, PIOPLATFORM, PIOFRAMEWORK, 94 | ARDUINO_BOARD, ESP.getChipId(), ESP.getCpuFreqMHz(), 95 | ESP.getFlashChipRealSize(), ESP.getFlashChipSpeed(), 96 | ESP.getFlashChipSize(), APP_NAME, APP_VERSION, __DATE__, __TIME__, 97 | appcfg.wifi_ssid, wifiHandler.getConnectCounter(), WiFi.channel(), 98 | wifiHandler.getPhyMode(), wifiHandler.getMacAddress(), 99 | WiFi.hostname().c_str(), WiFi.localIP().toString().c_str(), 100 | WiFi.gatewayIP().toString().c_str(), 101 | WiFi.subnetMask().toString().c_str(), 102 | WiFi.dnsIP().toString().c_str(), fsTotalBytes, fsUsedBytes, 103 | ESP.getFreeHeap(), ESP.getSketchSize(), ESP.getFreeSketchSpace(), 104 | remoteAddress, remotePort ); 105 | 106 | return buffer; 107 | } 108 | 109 | int sendUncompressed( const uint8_t *compressedData, const uint32_t compressedDataLength) 110 | { 111 | uzlib_init(); 112 | uzLibDecompressor.source = compressedData; 113 | uzLibDecompressor.source_limit = compressedData + compressedDataLength; 114 | 115 | uzlib_bytesleft = 0; 116 | for( int i=1; i<5; i++ ) 117 | { 118 | uzlib_bytesleft <<= 8; 119 | uzlib_bytesleft |= pgm_read_byte( compressedData + compressedDataLength - i ); 120 | } 121 | // Serial.printf("decompressed file length = %u\n", uzlib_bytesleft ); 122 | 123 | uzlib_uncompress_init(&uzLibDecompressor, buffer, BUFFER_LENGTH ); 124 | 125 | int res = uzlib_gzip_parse_header(&uzLibDecompressor); 126 | 127 | if (res != 0) { 128 | Serial.println("[ERROR] in gzUncompress: uzlib_gzip_parse_header failed!"); 129 | return res; 130 | } 131 | 132 | while( uzlib_bytesleft > 0 ) { 133 | uzLibDecompressor.dest_start = (unsigned char *)buffer2; 134 | uzLibDecompressor.dest = (unsigned char *)buffer2; 135 | int to_read = ( uzlib_bytesleft > BUFFER2_LENGTH) ? BUFFER2_LENGTH : uzlib_bytesleft; 136 | uzLibDecompressor.dest_limit = (unsigned char *)buffer2 + to_read; 137 | uzlib_uncompress(&uzLibDecompressor); 138 | buffer2[to_read] = 0; 139 | server.sendContent(buffer2); 140 | uzlib_bytesleft -= to_read; 141 | } 142 | return 0; 143 | } 144 | 145 | void sendHeader(const char *title, bool sendMetaRefresh, const char *style) 146 | { 147 | server.sendHeader("Access-Control-Allow-Origin", "*"); 148 | server.chunkedResponseModeStart(200, "text/html"); 149 | 150 | sendUncompressed(header_html_gz, header_html_gz_len); 151 | 152 | if (sendMetaRefresh) 153 | { 154 | server.sendContent_P(META_REFRESH30); 155 | } 156 | 157 | if (style != nullptr) 158 | { 159 | server.sendContent_P(style); 160 | } 161 | 162 | sprintf(buffer, "%s\n", title); 163 | server.sendContent(buffer); 164 | sendUncompressed(header2_html_gz, header2_html_gz_len); 165 | server.sendContent(title); 166 | sendUncompressed(header3_html_gz, header3_html_gz_len); 167 | } 168 | 169 | void sendHeader(const char *title, bool sendMetaRefresh) 170 | { 171 | sendHeader(title, sendMetaRefresh, nullptr); 172 | } 173 | 174 | void sendHeader(const char *title) 175 | { 176 | sendHeader(title, false); 177 | } 178 | 179 | void sendHeaderNoCache() 180 | { 181 | server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); 182 | server.sendHeader("Pragma", "no-cache"); 183 | server.sendHeader("Expires", "0"); 184 | } 185 | 186 | void sendAuthentication() 187 | { 188 | if (!server.authenticate("admin", appcfg.admin_password)) 189 | { 190 | return server.requestAuthentication(); 191 | } 192 | sendHeaderNoCache(); 193 | } 194 | 195 | void sendFooter() 196 | { 197 | sendUncompressed(footer_html_gz, footer_html_gz_len); 198 | server.chunkedResponseFinalize(); 199 | server.client().stop(); 200 | } 201 | 202 | void sendPrintf(const char *format, ...) 203 | { 204 | va_list myargs; 205 | va_start(myargs, format); 206 | vsprintf(buffer, format, myargs); 207 | va_end(myargs); 208 | server.sendContent(buffer); 209 | } 210 | 211 | void sendPrint(const char *message) 212 | { 213 | server.sendContent(message); 214 | } 215 | 216 | void sendLegend(const char *name) 217 | { 218 | sendPrintf("%s", name); 219 | } 220 | 221 | WebHandler::WebHandler() 222 | { 223 | initialized = false; 224 | } 225 | 226 | void WebHandler::setup() 227 | { 228 | LOG0("HTTP server setup...\n"); 229 | 230 | fsTotalBytes = 0; 231 | fsUsedBytes = 0; 232 | 233 | if (LittleFS.begin()) 234 | { 235 | FSInfo fs_info; 236 | LittleFS.info(fs_info); 237 | fsTotalBytes = fs_info.totalBytes; 238 | fsUsedBytes = fs_info.usedBytes; 239 | LittleFS.end(); 240 | } 241 | 242 | server.on("/espinfo", []() { 243 | server.sendHeader("Access-Control-Allow-Origin", "*"); 244 | sendHeaderNoCache(); 245 | String message(getJsonStatus(NULL)); 246 | server.send(200, "application/json", message); 247 | server.client().stop(); 248 | }); 249 | 250 | server.on("/favicon.ico", []() { 251 | server.sendHeader("Content-Encoding", "gzip"); 252 | server.sendHeader("Cache-Control", "max-age=31536000"); 253 | server.send( 200, "image/x-icon", FAVICON_ICO_GZ, FAVICON_ICO_GZ_LEN ); 254 | server.client().stop(); 255 | }); 256 | 257 | server.on("/state", handleJsonStatusState ); 258 | server.on("/set", handleSetAPI ); 259 | 260 | server.on("/", handleRootPage); 261 | server.on("/info.html", handleInfoPage); 262 | server.on("/setup.html", handleSetupPage ); 263 | server.on("/maintenance.html", handleMaintenancePage ); 264 | server.on("/system-restart", handleSystemRestart ); 265 | server.on("/config-backup", handleBackupConfiguration); 266 | server.on("/config-restore", HTTP_POST, handleRestoreConfiguration, handleConfigFileUpload); 267 | server.on("/update-firmware", HTTP_POST, handleFirmwareUploadSuccess, handleFirmwareUpload); 268 | server.on("/reset-firmware", handleResetFirmware); 269 | server.on("/savecfg", handleSaveConfigPage); 270 | server.on("/test1", handleTest1Page); 271 | 272 | if ( appcfg.wifi_mode == WIFI_AP ) 273 | { 274 | server.on("/captive.html", HTTP_GET, []() { 275 | server.send(200, "text/html", 276 | F("Please enter http://turing.pi or http://192.168.192.1 into your browser.")); 277 | server.client().stop(); 278 | }); 279 | } 280 | 281 | server.onNotFound([]{ 282 | if ( appcfg.wifi_mode == WIFI_AP ) 283 | { 284 | server.sendHeader( "Location", "http://turing.pi/captive.html", true ); 285 | server.send( 302, "text/plain", ""); 286 | server.client().stop(); 287 | } 288 | else 289 | { 290 | sprintf( buffer, "

ERROR(404): Page not found.

URI=%s", server.uri().c_str()); 291 | server.send(404, "text/html", buffer); 292 | server.client().stop(); 293 | } 294 | }); 295 | 296 | if (appcfg.ota_enabled == false) 297 | { 298 | MDNS.begin(appcfg.ota_hostname); 299 | } 300 | 301 | MDNS.addService("http", "tcp", 80); 302 | MDNS.addServiceTxt("http", "tcp", "path", "/"); 303 | MDNS.addServiceTxt("http", "tcp", "fw_name", APP_NAME); 304 | MDNS.addServiceTxt("http", "tcp", "fw_version", APP_VERSION); 305 | 306 | if (appcfg.ota_enabled == false) 307 | { 308 | MDNS.update(); 309 | } 310 | 311 | server.begin(); 312 | LOG0("HTTP server started\n"); 313 | initialized = true; 314 | } 315 | 316 | void WebHandler::handle() 317 | { 318 | if (!initialized) 319 | { 320 | setup(); 321 | } 322 | else 323 | { 324 | server.handleClient(); 325 | MDNS.update(); 326 | } 327 | } 328 | 329 | -------------------------------------------------------------------------------- /lib/WebPages/SetupPage.cpp: -------------------------------------------------------------------------------- 1 | #include "WebPages.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | const char *selected = "selected"; 10 | const char *checked = "checked"; 11 | const char *blank = ""; 12 | 13 | static const char *setupProcessor(const char *var) 14 | { 15 | if (strcmp(var, A_admin_password) == 0) 16 | return appcfg.admin_password; 17 | 18 | // Wifi 19 | 20 | if (strcmp(var, "wifi_mode_ap") == 0 && appcfg.wifi_mode == WIFI_AP) 21 | return selected; 22 | if (strcmp(var, "wifi_mode_station") == 0 && appcfg.wifi_mode == WIFI_STA) 23 | return selected; 24 | 25 | if (strcmp(var, "scanned_network_options") == 0) 26 | { 27 | ListNode *node = wifiHandler.getScannedNetworks(); 28 | String options = ""; 29 | 30 | if (node == NULL) 31 | { 32 | LOG0("node==NULL\n"); 33 | } 34 | 35 | while (node != NULL) 36 | { 37 | options += F(""); 40 | node = node->next; 41 | } 42 | 43 | fillBuffer(options.c_str()); 44 | return buffer; 45 | } 46 | 47 | if (strcmp(var, A_wifi_ssid) == 0) 48 | return appcfg.wifi_ssid; 49 | if (strcmp(var, A_wifi_password) == 0) 50 | return appcfg.wifi_password; 51 | 52 | // Network 53 | if (strcmp(var, "net_mode_dhcp") == 0 && appcfg.net_mode == NET_MODE_DHCP) 54 | return selected; 55 | if (strcmp(var, "net_mode_static") == 0 && appcfg.net_mode == NET_MODE_STATIC) 56 | return selected; 57 | if (strcmp(var, A_net_host) == 0) 58 | return appcfg.net_host; 59 | if (strcmp(var, A_net_gateway) == 0) 60 | return appcfg.net_gateway; 61 | if (strcmp(var, A_net_mask) == 0) 62 | return appcfg.net_mask; 63 | if (strcmp(var, A_net_dns) == 0) 64 | return appcfg.net_dns; 65 | 66 | // OTA 67 | if (strcmp(var, A_ota_hostname) == 0) 68 | return appcfg.ota_hostname; 69 | if (strcmp(var, A_ota_password) == 0) 70 | return appcfg.ota_password; 71 | if (strcmp(var, A_ota_enabled) == 0 && appcfg.ota_enabled == true) 72 | return checked; 73 | 74 | // MQTT 75 | if (strcmp(var, A_mqtt_enabled) == 0 && appcfg.mqtt_enabled == true) 76 | return checked; 77 | if (strcmp(var, A_mqtt_clientid) == 0) 78 | return appcfg.mqtt_clientid; 79 | if (strcmp(var, A_mqtt_host) == 0) 80 | return appcfg.mqtt_host; 81 | if (strcmp(var, A_mqtt_port) == 0) 82 | { 83 | sprintf(buffer, "%d", appcfg.mqtt_port); 84 | return buffer; 85 | } 86 | 87 | if (strcmp(var, A_mqtt_useauth) == 0 && appcfg.mqtt_useauth == true) 88 | return checked; 89 | if (strcmp(var, A_mqtt_user) == 0) 90 | return appcfg.mqtt_user; 91 | if (strcmp(var, A_mqtt_password) == 0) 92 | return appcfg.mqtt_password; 93 | if (strcmp(var, A_mqtt_intopic) == 0) 94 | return appcfg.mqtt_intopic; 95 | if (strcmp(var, A_mqtt_outtopic) == 0) 96 | return appcfg.mqtt_outtopic; 97 | if (strcmp(var, A_mqtt_sending_interval) == 0) 98 | { 99 | sprintf(buffer, "%lu", appcfg.mqtt_sending_interval); 100 | return buffer; 101 | } 102 | 103 | // Telnet 104 | if (strcmp(var, A_telnet_enabled) == 0 && appcfg.telnet_enabled == true) 105 | return checked; 106 | 107 | // NTP 108 | if (strcmp(var, A_ntp_enabled) == 0 && appcfg.ntp_enabled == true) 109 | return checked; 110 | if (strcmp(var, A_ntp_timezone) == 0) 111 | return appcfg.ntp_timezone; 112 | if (strcmp(var, A_ntp_server1) == 0) 113 | return appcfg.ntp_server1; 114 | if (strcmp(var, A_ntp_server2) == 0) 115 | return appcfg.ntp_server2; 116 | if (strcmp(var, A_ntp_server3) == 0) 117 | return appcfg.ntp_server3; 118 | 119 | // Ping 120 | if (strcmp(var, A_ping_enabled) == 0 && appcfg.ping_enabled == true) 121 | return checked; 122 | if (strcmp(var, A_ping_interval) == 0) 123 | { 124 | sprintf(buffer, "%lu", appcfg.ping_interval); 125 | return buffer; 126 | } 127 | if (strcmp(var, A_ping_ip_slot1) == 0) return appcfg.ping_addr[0]; 128 | if (strcmp(var, A_ping_ip_slot2) == 0) return appcfg.ping_addr[1]; 129 | if (strcmp(var, A_ping_ip_slot3) == 0) return appcfg.ping_addr[2]; 130 | if (strcmp(var, A_ping_ip_slot4) == 0) return appcfg.ping_addr[3]; 131 | if (strcmp(var, A_ping_ip_slot5) == 0) return appcfg.ping_addr[4]; 132 | if (strcmp(var, A_ping_ip_slot6) == 0) return appcfg.ping_addr[5]; 133 | if (strcmp(var, A_ping_ip_slot7) == 0) return appcfg.ping_addr[6]; 134 | 135 | return nullptr; 136 | } 137 | 138 | void handleSetupPage() 139 | { 140 | sendAuthentication(); 141 | sendHeader(APP_NAME " - Setup"); 142 | sendHtmlTemplate(SETUP_HTML_TEMPLATE, setupProcessor); 143 | sendFooter(); 144 | } 145 | 146 | 147 | /* 148 | String setupProcessor(const String &var) 149 | { 150 | String selected = F("selected"); 151 | String checked = F("checked"); 152 | 153 | if (var == A_admin_password) 154 | return String(appcfg.admin_password); 155 | 156 | // Wifi 157 | if (var == "wifi_mode_ap" && appcfg.wifi_mode == WIFI_AP) 158 | return selected; 159 | if (var == "wifi_mode_station" && appcfg.wifi_mode == WIFI_STA) 160 | return selected; 161 | 162 | if (var == "scanned_network_options") 163 | { 164 | ListNode *node = wifiHandler.getScannedNetworks(); 165 | String options = ""; 166 | 167 | while (node != NULL) 168 | { 169 | options += F(""); 172 | node = node->next; 173 | } 174 | 175 | return options; 176 | } 177 | 178 | if (var == A_wifi_ssid) 179 | return String(appcfg.wifi_ssid); 180 | if (var == A_wifi_password) 181 | return String(appcfg.wifi_password); 182 | 183 | // Network 184 | if (var == "net_mode_dhcp" && appcfg.net_mode == NET_MODE_DHCP) 185 | return selected; 186 | if (var == "net_mode_static" && appcfg.net_mode == NET_MODE_STATIC) 187 | return selected; 188 | if (var == A_net_host) 189 | return String(appcfg.net_host); 190 | if (var == A_net_gateway) 191 | return String(appcfg.net_gateway); 192 | if (var == A_net_mask) 193 | return String(appcfg.net_mask); 194 | if (var == A_net_dns) 195 | return String(appcfg.net_dns); 196 | 197 | // OTA 198 | if (var == A_ota_hostname) 199 | return String(appcfg.ota_hostname); 200 | if (var == A_ota_password) 201 | return String(appcfg.ota_password); 202 | 203 | // OpenHAB 204 | if (var == A_ohab_enabled && appcfg.ohab_enabled == true) 205 | return checked; 206 | if (var == "ohab_v1" && appcfg.ohab_version == 1) 207 | return selected; 208 | if (var == "ohab_v2" && appcfg.ohab_version == 2) 209 | return selected; 210 | if (var == A_ohab_itemname) 211 | return String(appcfg.ohab_itemname); 212 | if (var == A_ohab_host) 213 | return String(appcfg.ohab_host); 214 | if (var == A_ohab_port) 215 | return String(appcfg.ohab_port); 216 | if (var == A_ohab_useauth && appcfg.ohab_useauth == true) 217 | return checked; 218 | if (var == A_ohab_user) 219 | return String(appcfg.ohab_user); 220 | if (var == A_ohab_password) 221 | return String(appcfg.ohab_password); 222 | 223 | #ifdef HAVE_ENERGY_SENSOR 224 | if (var == A_ohab_item_voltage) 225 | return String(appcfg.ohab_item_voltage); 226 | if (var == A_ohab_item_current) 227 | return String(appcfg.ohab_item_current); 228 | if (var == A_ohab_item_power) 229 | return String(appcfg.ohab_item_power); 230 | if (var == A_ohab_sending_interval) 231 | return String(appcfg.ohab_sending_interval); 232 | #endif 233 | 234 | // Alexa 235 | if (var == A_alexa_enabled && appcfg.alexa_enabled == true) 236 | return checked; 237 | if (var == A_alexa_devicename) 238 | return String(appcfg.alexa_devicename); 239 | 240 | // MQTT 241 | if (var == A_mqtt_enabled && appcfg.mqtt_enabled == true) 242 | return checked; 243 | if (var == A_mqtt_clientid) 244 | return String(appcfg.mqtt_clientid); 245 | if (var == A_mqtt_host) 246 | return String(appcfg.mqtt_host); 247 | if (var == A_mqtt_port) 248 | return String(appcfg.mqtt_port); 249 | if (var == A_mqtt_useauth && appcfg.mqtt_useauth == true) 250 | return checked; 251 | if (var == A_mqtt_user) 252 | return String(appcfg.mqtt_user); 253 | if (var == A_mqtt_password) 254 | return String(appcfg.mqtt_password); 255 | if (var == A_mqtt_intopic) 256 | return String(appcfg.mqtt_intopic); 257 | if (var == A_mqtt_outtopic) 258 | return String(appcfg.mqtt_outtopic); 259 | #ifdef HAVE_ENERGY_SENSOR 260 | if (var == A_mqtt_topic_voltage) 261 | return String(appcfg.mqtt_topic_voltage); 262 | if (var == A_mqtt_topic_current) 263 | return String(appcfg.mqtt_topic_current); 264 | if (var == A_mqtt_topic_power) 265 | return String(appcfg.mqtt_topic_power); 266 | if (var == A_mqtt_topic_json) 267 | return String(appcfg.mqtt_topic_json); 268 | if (var == A_mqtt_sending_interval) 269 | return String(appcfg.mqtt_sending_interval); 270 | #endif 271 | 272 | // Syslog 273 | if (var == A_syslog_enabled && appcfg.syslog_enabled == true) 274 | return checked; 275 | if (var == A_syslog_host) 276 | return String(appcfg.syslog_host); 277 | if (var == A_syslog_port) 278 | return String(appcfg.syslog_port); 279 | if (var == A_syslog_app_name) 280 | return String(appcfg.syslog_app_name); 281 | 282 | if (var == "millis") 283 | return String(millis()); 284 | 285 | #ifdef POWER_BUTTON_IS_MULTIMODE 286 | // Power Button Mode 287 | if (var == "power_button_mode_switch" && appcfg.power_button_mode == POWER_BUTTON_MODE_SWITCH) 288 | return selected; 289 | if (var == "power_button_mode_toggle" && appcfg.power_button_mode == POWER_BUTTON_MODE_TOGGLE) 290 | return selected; 291 | if (var == "power_button_mode_toggle_switch" && appcfg.power_button_mode == POWER_BUTTON_MODE_TOGGLE_SWITCH) 292 | return selected; 293 | #endif 294 | 295 | #ifdef WIFI_LED 296 | if (var == A_led_night_mode_enabled && appcfg.led_night_mode_enabled == true) 297 | return checked; 298 | if (var == A_led_night_mode_timeout) 299 | return String(appcfg.led_night_mode_timeout); 300 | #endif 301 | 302 | if (var == A_inet_check_enabled && appcfg.inet_check_enabled == true) 303 | return checked; 304 | if (var == A_inet_check_period) 305 | return String(appcfg.inet_check_period); 306 | 307 | String ica = String( A_inet_check_action ); 308 | ica += "_"; 309 | ica += appcfg.inet_check_action; 310 | 311 | if ( var == ica ) 312 | return selected; 313 | 314 | return String(); 315 | } 316 | 317 | void handleSetupPage(AsyncWebServerRequest *request) 318 | { 319 | LOG0("handleSetupPage\n"); 320 | if (!request->authenticate("admin", appcfg.admin_password)) 321 | { 322 | LOG0("authenticate\n"); 323 | return request->requestAuthentication(); 324 | } 325 | 326 | LOG0("build response\n"); 327 | AsyncWebServerResponse *response = 328 | request->beginResponse_P(200, "text/html", SETUP_HTML, setupProcessor); 329 | response->addHeader("Cache-Control", "no-cache, no-store, must-revalidate"); 330 | response->addHeader("Pragma", "no-cache"); 331 | response->addHeader("Expires", "0"); 332 | 333 | LOG0("send response\n"); 334 | request->send(response); 335 | } 336 | 337 | */ 338 | -------------------------------------------------------------------------------- /lib/uzlib/defl_static.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Routines in this file are based on: 4 | Zlib (RFC1950 / RFC1951) compression for PuTTY. 5 | 6 | PuTTY is copyright 1997-2014 Simon Tatham. 7 | 8 | Portions copyright Robert de Bath, Joris van Rantwijk, Delian 9 | Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas Barry, 10 | Justin Bradford, Ben Harris, Malcolm Smith, Ahmad Khalifa, Markus 11 | Kuhn, Colin Watson, and CORE SDI S.A. 12 | 13 | Permission is hereby granted, free of charge, to any person 14 | obtaining a copy of this software and associated documentation files 15 | (the "Software"), to deal in the Software without restriction, 16 | including without limitation the rights to use, copy, modify, merge, 17 | publish, distribute, sublicense, and/or sell copies of the Software, 18 | and to permit persons to whom the Software is furnished to do so, 19 | subject to the following conditions: 20 | 21 | The above copyright notice and this permission notice shall be 22 | included in all copies or substantial portions of the Software. 23 | 24 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 27 | NONINFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE 28 | FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 29 | CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 30 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 31 | */ 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include "defl_static.h" 38 | 39 | #define snew(type) ( (type *) malloc(sizeof(type)) ) 40 | #define snewn(n, type) ( (type *) malloc((n) * sizeof(type)) ) 41 | #define sresize(x, n, type) ( (type *) realloc((x), (n) * sizeof(type)) ) 42 | #define sfree(x) ( free((x)) ) 43 | 44 | #ifndef FALSE 45 | #define FALSE 0 46 | #define TRUE (!FALSE) 47 | #endif 48 | 49 | /* ---------------------------------------------------------------------- 50 | * Zlib compression. We always use the static Huffman tree option. 51 | * Mostly this is because it's hard to scan a block in advance to 52 | * work out better trees; dynamic trees are great when you're 53 | * compressing a large file under no significant time constraint, 54 | * but when you're compressing little bits in real time, things get 55 | * hairier. 56 | * 57 | * I suppose it's possible that I could compute Huffman trees based 58 | * on the frequencies in the _previous_ block, as a sort of 59 | * heuristic, but I'm not confident that the gain would balance out 60 | * having to transmit the trees. 61 | */ 62 | 63 | void outbits(struct Outbuf *out, unsigned long bits, int nbits) 64 | { 65 | assert(out->noutbits + nbits <= 32); 66 | out->outbits |= bits << out->noutbits; 67 | out->noutbits += nbits; 68 | while (out->noutbits >= 8) { 69 | if (out->outlen >= out->outsize) { 70 | out->outsize = out->outlen + 64; 71 | out->outbuf = sresize(out->outbuf, out->outsize, unsigned char); 72 | } 73 | out->outbuf[out->outlen++] = (unsigned char) (out->outbits & 0xFF); 74 | out->outbits >>= 8; 75 | out->noutbits -= 8; 76 | } 77 | } 78 | 79 | static const unsigned char mirrorbytes[256] = { 80 | 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 81 | 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, 82 | 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 83 | 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 84 | 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 85 | 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, 86 | 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 87 | 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, 88 | 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 89 | 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, 90 | 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 91 | 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, 92 | 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 93 | 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, 94 | 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 95 | 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 96 | 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, 97 | 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, 98 | 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 99 | 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, 100 | 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 101 | 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, 102 | 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 103 | 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, 104 | 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 105 | 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, 106 | 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 107 | 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, 108 | 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, 109 | 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, 110 | 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 111 | 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff, 112 | }; 113 | 114 | typedef struct { 115 | uint8_t extrabits; 116 | uint8_t min, max; 117 | } len_coderecord; 118 | 119 | typedef struct { 120 | uint8_t code, extrabits; 121 | uint16_t min, max; 122 | } dist_coderecord; 123 | 124 | #define TO_LCODE(x, y) x - 3, y - 3 125 | #define FROM_LCODE(x) (x + 3) 126 | 127 | static const len_coderecord lencodes[] = { 128 | {0, TO_LCODE(3, 3)}, 129 | {0, TO_LCODE(4, 4)}, 130 | {0, TO_LCODE(5, 5)}, 131 | {0, TO_LCODE(6, 6)}, 132 | {0, TO_LCODE(7, 7)}, 133 | {0, TO_LCODE(8, 8)}, 134 | {0, TO_LCODE(9, 9)}, 135 | {0, TO_LCODE(10, 10)}, 136 | {1, TO_LCODE(11, 12)}, 137 | {1, TO_LCODE(13, 14)}, 138 | {1, TO_LCODE(15, 16)}, 139 | {1, TO_LCODE(17, 18)}, 140 | {2, TO_LCODE(19, 22)}, 141 | {2, TO_LCODE(23, 26)}, 142 | {2, TO_LCODE(27, 30)}, 143 | {2, TO_LCODE(31, 34)}, 144 | {3, TO_LCODE(35, 42)}, 145 | {3, TO_LCODE(43, 50)}, 146 | {3, TO_LCODE(51, 58)}, 147 | {3, TO_LCODE(59, 66)}, 148 | {4, TO_LCODE(67, 82)}, 149 | {4, TO_LCODE(83, 98)}, 150 | {4, TO_LCODE(99, 114)}, 151 | {4, TO_LCODE(115, 130)}, 152 | {5, TO_LCODE(131, 162)}, 153 | {5, TO_LCODE(163, 194)}, 154 | {5, TO_LCODE(195, 226)}, 155 | {5, TO_LCODE(227, 257)}, 156 | {0, TO_LCODE(258, 258)}, 157 | }; 158 | 159 | static const dist_coderecord distcodes[] = { 160 | {0, 0, 1, 1}, 161 | {1, 0, 2, 2}, 162 | {2, 0, 3, 3}, 163 | {3, 0, 4, 4}, 164 | {4, 1, 5, 6}, 165 | {5, 1, 7, 8}, 166 | {6, 2, 9, 12}, 167 | {7, 2, 13, 16}, 168 | {8, 3, 17, 24}, 169 | {9, 3, 25, 32}, 170 | {10, 4, 33, 48}, 171 | {11, 4, 49, 64}, 172 | {12, 5, 65, 96}, 173 | {13, 5, 97, 128}, 174 | {14, 6, 129, 192}, 175 | {15, 6, 193, 256}, 176 | {16, 7, 257, 384}, 177 | {17, 7, 385, 512}, 178 | {18, 8, 513, 768}, 179 | {19, 8, 769, 1024}, 180 | {20, 9, 1025, 1536}, 181 | {21, 9, 1537, 2048}, 182 | {22, 10, 2049, 3072}, 183 | {23, 10, 3073, 4096}, 184 | {24, 11, 4097, 6144}, 185 | {25, 11, 6145, 8192}, 186 | {26, 12, 8193, 12288}, 187 | {27, 12, 12289, 16384}, 188 | {28, 13, 16385, 24576}, 189 | {29, 13, 24577, 32768}, 190 | }; 191 | 192 | void zlib_literal(struct Outbuf *out, unsigned char c) 193 | { 194 | if (out->comp_disabled) { 195 | /* 196 | * We're in an uncompressed block, so just output the byte. 197 | */ 198 | outbits(out, c, 8); 199 | return; 200 | } 201 | 202 | if (c <= 143) { 203 | /* 0 through 143 are 8 bits long starting at 00110000. */ 204 | outbits(out, mirrorbytes[0x30 + c], 8); 205 | } else { 206 | /* 144 through 255 are 9 bits long starting at 110010000. */ 207 | outbits(out, 1 + 2 * mirrorbytes[0x90 - 144 + c], 9); 208 | } 209 | } 210 | 211 | void zlib_match(struct Outbuf *out, int distance, int len) 212 | { 213 | const dist_coderecord *d; 214 | const len_coderecord *l; 215 | int i, j, k; 216 | int lcode; 217 | 218 | assert(!out->comp_disabled); 219 | 220 | while (len > 0) { 221 | int thislen; 222 | 223 | /* 224 | * We can transmit matches of lengths 3 through 258 225 | * inclusive. So if len exceeds 258, we must transmit in 226 | * several steps, with 258 or less in each step. 227 | * 228 | * Specifically: if len >= 261, we can transmit 258 and be 229 | * sure of having at least 3 left for the next step. And if 230 | * len <= 258, we can just transmit len. But if len == 259 231 | * or 260, we must transmit len-3. 232 | */ 233 | thislen = (len > 260 ? 258 : len <= 258 ? len : len - 3); 234 | len -= thislen; 235 | 236 | /* 237 | * Binary-search to find which length code we're 238 | * transmitting. 239 | */ 240 | i = -1; 241 | j = sizeof(lencodes) / sizeof(*lencodes); 242 | while (1) { 243 | assert(j - i >= 2); 244 | k = (j + i) / 2; 245 | if (thislen < FROM_LCODE(lencodes[k].min)) 246 | j = k; 247 | else if (thislen > FROM_LCODE(lencodes[k].max)) 248 | i = k; 249 | else { 250 | l = &lencodes[k]; 251 | break; /* found it! */ 252 | } 253 | } 254 | 255 | lcode = l - lencodes + 257; 256 | 257 | /* 258 | * Transmit the length code. 256-279 are seven bits 259 | * starting at 0000000; 280-287 are eight bits starting at 260 | * 11000000. 261 | */ 262 | if (lcode <= 279) { 263 | outbits(out, mirrorbytes[(lcode - 256) * 2], 7); 264 | } else { 265 | outbits(out, mirrorbytes[0xc0 - 280 + lcode], 8); 266 | } 267 | 268 | /* 269 | * Transmit the extra bits. 270 | */ 271 | if (l->extrabits) 272 | outbits(out, thislen - FROM_LCODE(l->min), l->extrabits); 273 | 274 | /* 275 | * Binary-search to find which distance code we're 276 | * transmitting. 277 | */ 278 | i = -1; 279 | j = sizeof(distcodes) / sizeof(*distcodes); 280 | while (1) { 281 | assert(j - i >= 2); 282 | k = (j + i) / 2; 283 | if (distance < distcodes[k].min) 284 | j = k; 285 | else if (distance > distcodes[k].max) 286 | i = k; 287 | else { 288 | d = &distcodes[k]; 289 | break; /* found it! */ 290 | } 291 | } 292 | 293 | /* 294 | * Transmit the distance code. Five bits starting at 00000. 295 | */ 296 | outbits(out, mirrorbytes[d->code * 8], 5); 297 | 298 | /* 299 | * Transmit the extra bits. 300 | */ 301 | if (d->extrabits) 302 | outbits(out, distance - d->min, d->extrabits); 303 | } 304 | } 305 | 306 | void zlib_start_block(struct Outbuf *out) 307 | { 308 | // outbits(out, 0x9C78, 16); 309 | outbits(out, 1, 1); /* Final block */ 310 | outbits(out, 1, 2); /* Static huffman block */ 311 | } 312 | 313 | void zlib_finish_block(struct Outbuf *out) 314 | { 315 | outbits(out, 0, 7); /* close block */ 316 | outbits(out, 0, 7); /* Make sure all bits are flushed */ 317 | } 318 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /lib/uzlib/tinflate.c: -------------------------------------------------------------------------------- 1 | /* 2 | * uzlib - tiny deflate/inflate library (deflate, gzip, zlib) 3 | * 4 | * Copyright (c) 2003 by Joergen Ibsen / Jibz 5 | * All Rights Reserved 6 | * http://www.ibsensoftware.com/ 7 | * 8 | * Copyright (c) 2014-2018 by Paul Sokolovsky 9 | * 10 | * This software is provided 'as-is', without any express 11 | * or implied warranty. In no event will the authors be 12 | * held liable for any damages arising from the use of 13 | * this software. 14 | * 15 | * Permission is granted to anyone to use this software 16 | * for any purpose, including commercial applications, 17 | * and to alter it and redistribute it freely, subject to 18 | * the following restrictions: 19 | * 20 | * 1. The origin of this software must not be 21 | * misrepresented; you must not claim that you 22 | * wrote the original software. If you use this 23 | * software in a product, an acknowledgment in 24 | * the product documentation would be appreciated 25 | * but is not required. 26 | * 27 | * 2. Altered source versions must be plainly marked 28 | * as such, and must not be misrepresented as 29 | * being the original software. 30 | * 31 | * 3. This notice may not be removed or altered from 32 | * any source distribution. 33 | */ 34 | 35 | #include 36 | #include 37 | #include "uzlib.h" 38 | 39 | #define UZLIB_DUMP_ARRAY(heading, arr, size) \ 40 | { \ 41 | printf("%s", heading); \ 42 | for (int i = 0; i < size; ++i) { \ 43 | printf(" %d", (arr)[i]); \ 44 | } \ 45 | printf("\n"); \ 46 | } 47 | 48 | uint32_t tinf_get_le_uint32(struct uzlib_uncomp *d); 49 | uint32_t tinf_get_be_uint32(struct uzlib_uncomp *d); 50 | 51 | /* --------------------------------------------------- * 52 | * -- uninitialized global data (static structures) -- * 53 | * --------------------------------------------------- */ 54 | 55 | #ifdef RUNTIME_BITS_TABLES 56 | 57 | /* extra bits and base tables for length codes */ 58 | unsigned char length_bits[30]; 59 | unsigned short length_base[30]; 60 | 61 | /* extra bits and base tables for distance codes */ 62 | unsigned char dist_bits[30]; 63 | unsigned short dist_base[30]; 64 | 65 | #else 66 | 67 | const unsigned char length_bits[30] = { 68 | 0, 0, 0, 0, 0, 0, 0, 0, 69 | 1, 1, 1, 1, 2, 2, 2, 2, 70 | 3, 3, 3, 3, 4, 4, 4, 4, 71 | 5, 5, 5, 5 72 | }; 73 | const unsigned short length_base[30] = { 74 | 3, 4, 5, 6, 7, 8, 9, 10, 75 | 11, 13, 15, 17, 19, 23, 27, 31, 76 | 35, 43, 51, 59, 67, 83, 99, 115, 77 | 131, 163, 195, 227, 258 78 | }; 79 | 80 | const unsigned char dist_bits[30] = { 81 | 0, 0, 0, 0, 1, 1, 2, 2, 82 | 3, 3, 4, 4, 5, 5, 6, 6, 83 | 7, 7, 8, 8, 9, 9, 10, 10, 84 | 11, 11, 12, 12, 13, 13 85 | }; 86 | const unsigned short dist_base[30] = { 87 | 1, 2, 3, 4, 5, 7, 9, 13, 88 | 17, 25, 33, 49, 65, 97, 129, 193, 89 | 257, 385, 513, 769, 1025, 1537, 2049, 3073, 90 | 4097, 6145, 8193, 12289, 16385, 24577 91 | }; 92 | 93 | #endif 94 | 95 | /* special ordering of code length codes */ 96 | const unsigned char clcidx[] = { 97 | 16, 17, 18, 0, 8, 7, 9, 6, 98 | 10, 5, 11, 4, 12, 3, 13, 2, 99 | 14, 1, 15 100 | }; 101 | 102 | /* ----------------------- * 103 | * -- utility functions -- * 104 | * ----------------------- */ 105 | 106 | #ifdef RUNTIME_BITS_TABLES 107 | /* build extra bits and base tables */ 108 | static void tinf_build_bits_base(unsigned char *bits, unsigned short *base, int delta, int first) 109 | { 110 | int i, sum; 111 | 112 | /* build bits table */ 113 | for (i = 0; i < delta; ++i) bits[i] = 0; 114 | for (i = 0; i < 30 - delta; ++i) bits[i + delta] = i / delta; 115 | 116 | /* build base table */ 117 | for (sum = first, i = 0; i < 30; ++i) 118 | { 119 | base[i] = sum; 120 | sum += 1 << bits[i]; 121 | } 122 | } 123 | #endif 124 | 125 | /* build the fixed huffman trees */ 126 | static void tinf_build_fixed_trees(TINF_TREE *lt, TINF_TREE *dt) 127 | { 128 | int i; 129 | 130 | /* build fixed length tree */ 131 | for (i = 0; i < 7; ++i) lt->table[i] = 0; 132 | 133 | lt->table[7] = 24; 134 | lt->table[8] = 152; 135 | lt->table[9] = 112; 136 | 137 | for (i = 0; i < 24; ++i) lt->trans[i] = 256 + i; 138 | for (i = 0; i < 144; ++i) lt->trans[24 + i] = i; 139 | for (i = 0; i < 8; ++i) lt->trans[24 + 144 + i] = 280 + i; 140 | for (i = 0; i < 112; ++i) lt->trans[24 + 144 + 8 + i] = 144 + i; 141 | 142 | /* build fixed distance tree */ 143 | for (i = 0; i < 5; ++i) dt->table[i] = 0; 144 | 145 | dt->table[5] = 32; 146 | 147 | for (i = 0; i < 32; ++i) dt->trans[i] = i; 148 | } 149 | 150 | /* given an array of code lengths, build a tree */ 151 | static void tinf_build_tree(TINF_TREE *t, const unsigned char *lengths, unsigned int num) 152 | { 153 | unsigned short offs[16]; 154 | unsigned int i, sum; 155 | 156 | /* clear code length count table */ 157 | for (i = 0; i < 16; ++i) t->table[i] = 0; 158 | 159 | /* scan symbol lengths, and sum code length counts */ 160 | for (i = 0; i < num; ++i) t->table[lengths[i]]++; 161 | 162 | #if UZLIB_CONF_DEBUG_LOG >= 2 163 | UZLIB_DUMP_ARRAY("codelen counts:", t->table, TINF_ARRAY_SIZE(t->table)); 164 | #endif 165 | 166 | /* In the lengths array, 0 means unused code. So, t->table[0] now contains 167 | number of unused codes. But table's purpose is to contain # of codes of 168 | particular length, and there're 0 codes of length 0. */ 169 | t->table[0] = 0; 170 | 171 | /* compute offset table for distribution sort */ 172 | for (sum = 0, i = 0; i < 16; ++i) 173 | { 174 | offs[i] = sum; 175 | sum += t->table[i]; 176 | } 177 | 178 | #if UZLIB_CONF_DEBUG_LOG >= 2 179 | UZLIB_DUMP_ARRAY("codelen offsets:", offs, TINF_ARRAY_SIZE(offs)); 180 | #endif 181 | 182 | /* create code->symbol translation table (symbols sorted by code) */ 183 | for (i = 0; i < num; ++i) 184 | { 185 | if (lengths[i]) t->trans[offs[lengths[i]]++] = i; 186 | } 187 | } 188 | 189 | /* ---------------------- * 190 | * -- decode functions -- * 191 | * ---------------------- */ 192 | 193 | unsigned char uzlib_get_byte(struct uzlib_uncomp *d) 194 | { 195 | /* If end of source buffer is not reached, return next byte from source 196 | buffer. */ 197 | if (d->source < d->source_limit) { 198 | // return *d->source++; 199 | 200 | // progmem 201 | return pgm_read_byte( d->source++ ); 202 | } 203 | 204 | /* Otherwise if there's callback and we haven't seen EOF yet, try to 205 | read next byte using it. (Note: the callback can also update ->source 206 | and ->source_limit). */ 207 | if (d->source_read_cb && !d->eof) { 208 | int val = d->source_read_cb(d); 209 | if (val >= 0) { 210 | return (unsigned char)val; 211 | } 212 | } 213 | 214 | /* Otherwise, we hit EOF (either from ->source_read_cb() or from exhaustion 215 | of the buffer), and it will be "sticky", i.e. further calls to this 216 | function will end up here too. */ 217 | d->eof = true; 218 | 219 | return 0; 220 | } 221 | 222 | uint32_t tinf_get_le_uint32(struct uzlib_uncomp *d) 223 | { 224 | uint32_t val = 0; 225 | int i; 226 | for (i = 4; i--;) { 227 | val = val >> 8 | ((uint32_t)uzlib_get_byte(d)) << 24; 228 | } 229 | return val; 230 | } 231 | 232 | uint32_t tinf_get_be_uint32(struct uzlib_uncomp *d) 233 | { 234 | uint32_t val = 0; 235 | int i; 236 | for (i = 4; i--;) { 237 | val = val << 8 | uzlib_get_byte(d); 238 | } 239 | return val; 240 | } 241 | 242 | /* get one bit from source stream */ 243 | static int tinf_getbit(struct uzlib_uncomp *d) 244 | { 245 | unsigned int bit; 246 | 247 | /* check if tag is empty */ 248 | if (!d->bitcount--) 249 | { 250 | /* load next tag */ 251 | d->tag = uzlib_get_byte(d); 252 | d->bitcount = 7; 253 | } 254 | 255 | /* shift bit out of tag */ 256 | bit = d->tag & 0x01; 257 | d->tag >>= 1; 258 | 259 | return bit; 260 | } 261 | 262 | /* read a num bit value from a stream and add base */ 263 | static unsigned int tinf_read_bits(struct uzlib_uncomp *d, int num, int base) 264 | { 265 | unsigned int val = 0; 266 | 267 | /* read num bits */ 268 | if (num) 269 | { 270 | unsigned int limit = 1 << (num); 271 | unsigned int mask; 272 | 273 | for (mask = 1; mask < limit; mask *= 2) 274 | if (tinf_getbit(d)) val += mask; 275 | } 276 | 277 | return val + base; 278 | } 279 | 280 | /* given a data stream and a tree, decode a symbol */ 281 | static int tinf_decode_symbol(struct uzlib_uncomp *d, TINF_TREE *t) 282 | { 283 | int sum = 0, cur = 0, len = 0; 284 | 285 | /* get more bits while code value is above sum */ 286 | do { 287 | 288 | cur = 2*cur + tinf_getbit(d); 289 | 290 | if (++len == TINF_ARRAY_SIZE(t->table)) { 291 | return TINF_DATA_ERROR; 292 | } 293 | 294 | sum += t->table[len]; 295 | cur -= t->table[len]; 296 | 297 | } while (cur >= 0); 298 | 299 | sum += cur; 300 | #if UZLIB_CONF_PARANOID_CHECKS 301 | if (sum < 0 || sum >= TINF_ARRAY_SIZE(t->trans)) { 302 | return TINF_DATA_ERROR; 303 | } 304 | #endif 305 | 306 | return t->trans[sum]; 307 | } 308 | 309 | /* given a data stream, decode dynamic trees from it */ 310 | static int tinf_decode_trees(struct uzlib_uncomp *d, TINF_TREE *lt, TINF_TREE *dt) 311 | { 312 | /* code lengths for 288 literal/len symbols and 32 dist symbols */ 313 | unsigned char lengths[288+32]; 314 | unsigned int hlit, hdist, hclen, hlimit; 315 | unsigned int i, num, length; 316 | 317 | /* get 5 bits HLIT (257-286) */ 318 | hlit = tinf_read_bits(d, 5, 257); 319 | 320 | /* get 5 bits HDIST (1-32) */ 321 | hdist = tinf_read_bits(d, 5, 1); 322 | 323 | /* get 4 bits HCLEN (4-19) */ 324 | hclen = tinf_read_bits(d, 4, 4); 325 | 326 | for (i = 0; i < 19; ++i) lengths[i] = 0; 327 | 328 | /* read code lengths for code length alphabet */ 329 | for (i = 0; i < hclen; ++i) 330 | { 331 | /* get 3 bits code length (0-7) */ 332 | unsigned int clen = tinf_read_bits(d, 3, 0); 333 | 334 | lengths[clcidx[i]] = clen; 335 | } 336 | 337 | /* build code length tree, temporarily use length tree */ 338 | tinf_build_tree(lt, lengths, 19); 339 | 340 | /* decode code lengths for the dynamic trees */ 341 | hlimit = hlit + hdist; 342 | for (num = 0; num < hlimit; ) 343 | { 344 | int sym = tinf_decode_symbol(d, lt); 345 | unsigned char fill_value = 0; 346 | int lbits, lbase = 3; 347 | 348 | /* error decoding */ 349 | if (sym < 0) return sym; 350 | 351 | switch (sym) 352 | { 353 | case 16: 354 | /* copy previous code length 3-6 times (read 2 bits) */ 355 | if (num == 0) return TINF_DATA_ERROR; 356 | fill_value = lengths[num - 1]; 357 | lbits = 2; 358 | break; 359 | case 17: 360 | /* repeat code length 0 for 3-10 times (read 3 bits) */ 361 | lbits = 3; 362 | break; 363 | case 18: 364 | /* repeat code length 0 for 11-138 times (read 7 bits) */ 365 | lbits = 7; 366 | lbase = 11; 367 | break; 368 | default: 369 | /* values 0-15 represent the actual code lengths */ 370 | lengths[num++] = sym; 371 | /* continue the for loop */ 372 | continue; 373 | } 374 | 375 | /* special code length 16-18 are handled here */ 376 | length = tinf_read_bits(d, lbits, lbase); 377 | if (num + length > hlimit) return TINF_DATA_ERROR; 378 | for (; length; --length) 379 | { 380 | lengths[num++] = fill_value; 381 | } 382 | } 383 | 384 | #if UZLIB_CONF_DEBUG_LOG >= 2 385 | printf("lit code lengths (%d):", hlit); 386 | UZLIB_DUMP_ARRAY("", lengths, hlit); 387 | printf("dist code lengths (%d):", hdist); 388 | UZLIB_DUMP_ARRAY("", lengths + hlit, hdist); 389 | #endif 390 | 391 | #if UZLIB_CONF_PARANOID_CHECKS 392 | /* Check that there's "end of block" symbol */ 393 | if (lengths[256] == 0) { 394 | return TINF_DATA_ERROR; 395 | } 396 | #endif 397 | 398 | /* build dynamic trees */ 399 | tinf_build_tree(lt, lengths, hlit); 400 | tinf_build_tree(dt, lengths + hlit, hdist); 401 | 402 | return TINF_OK; 403 | } 404 | 405 | /* ----------------------------- * 406 | * -- block inflate functions -- * 407 | * ----------------------------- */ 408 | 409 | /* given a stream and two trees, inflate next chunk of output (a byte or more) */ 410 | static int tinf_inflate_block_data(struct uzlib_uncomp *d, TINF_TREE *lt, TINF_TREE *dt) 411 | { 412 | if (d->curlen == 0) { 413 | unsigned int offs; 414 | int dist; 415 | int sym = tinf_decode_symbol(d, lt); 416 | //printf("huff sym: %02x\n", sym); 417 | 418 | if (d->eof) { 419 | return TINF_DATA_ERROR; 420 | } 421 | 422 | /* literal byte */ 423 | if (sym < 256) { 424 | TINF_PUT(d, sym); 425 | return TINF_OK; 426 | } 427 | 428 | /* end of block */ 429 | if (sym == 256) { 430 | return TINF_DONE; 431 | } 432 | 433 | /* substring from sliding dictionary */ 434 | sym -= 257; 435 | if (sym >= 29) { 436 | return TINF_DATA_ERROR; 437 | } 438 | 439 | /* possibly get more bits from length code */ 440 | d->curlen = tinf_read_bits(d, length_bits[sym], length_base[sym]); 441 | 442 | dist = tinf_decode_symbol(d, dt); 443 | if (dist >= 30) { 444 | return TINF_DATA_ERROR; 445 | } 446 | 447 | /* possibly get more bits from distance code */ 448 | offs = tinf_read_bits(d, dist_bits[dist], dist_base[dist]); 449 | 450 | /* calculate and validate actual LZ offset to use */ 451 | if (d->dict_ring) { 452 | if (offs > d->dict_size) { 453 | return TINF_DICT_ERROR; 454 | } 455 | /* Note: unlike full-dest-in-memory case below, we don't 456 | try to catch offset which points to not yet filled 457 | part of the dictionary here. Doing so would require 458 | keeping another variable to track "filled in" size 459 | of the dictionary. Appearance of such an offset cannot 460 | lead to accessing memory outside of the dictionary 461 | buffer, and clients which don't want to leak unrelated 462 | information, should explicitly initialize dictionary 463 | buffer passed to uzlib. */ 464 | 465 | d->lzOff = d->dict_idx - offs; 466 | if (d->lzOff < 0) { 467 | d->lzOff += d->dict_size; 468 | } 469 | } else { 470 | /* catch trying to point before the start of dest buffer */ 471 | if (offs > d->dest - d->dest_start) { 472 | return TINF_DATA_ERROR; 473 | } 474 | d->lzOff = -offs; 475 | } 476 | } 477 | 478 | /* copy next byte from dict substring */ 479 | if (d->dict_ring) { 480 | TINF_PUT(d, d->dict_ring[d->lzOff]); 481 | if ((unsigned)++d->lzOff == d->dict_size) { 482 | d->lzOff = 0; 483 | } 484 | } else { 485 | #if UZLIB_CONF_USE_MEMCPY 486 | /* copy as much as possible, in one memcpy() call */ 487 | unsigned int to_copy = d->curlen, dest_len = d->dest_limit - d->dest; 488 | if (to_copy > dest_len) { 489 | to_copy = dest_len; 490 | } 491 | memcpy(d->dest, d->dest + d->lzOff, to_copy); 492 | d->dest += to_copy; 493 | d->curlen -= to_copy; 494 | return TINF_OK; 495 | #else 496 | d->dest[0] = d->dest[d->lzOff]; 497 | d->dest++; 498 | #endif 499 | } 500 | d->curlen--; 501 | return TINF_OK; 502 | } 503 | 504 | /* inflate next byte from uncompressed block of data */ 505 | static int tinf_inflate_uncompressed_block(struct uzlib_uncomp *d) 506 | { 507 | if (d->curlen == 0) { 508 | unsigned int length, invlength; 509 | 510 | /* get length */ 511 | length = uzlib_get_byte(d); 512 | length += 256 * uzlib_get_byte(d); 513 | /* get one's complement of length */ 514 | invlength = uzlib_get_byte(d); 515 | invlength += 256 * uzlib_get_byte(d); 516 | /* check length */ 517 | if (length != (~invlength & 0x0000ffff)) return TINF_DATA_ERROR; 518 | 519 | /* increment length to properly return TINF_DONE below, without 520 | producing data at the same time */ 521 | d->curlen = length + 1; 522 | 523 | /* make sure we start next block on a byte boundary */ 524 | d->bitcount = 0; 525 | } 526 | 527 | if (--d->curlen == 0) { 528 | return TINF_DONE; 529 | } 530 | 531 | unsigned char c = uzlib_get_byte(d); 532 | TINF_PUT(d, c); 533 | return TINF_OK; 534 | } 535 | 536 | /* ---------------------- * 537 | * -- public functions -- * 538 | * ---------------------- */ 539 | 540 | /* initialize global (static) data */ 541 | void uzlib_init(void) 542 | { 543 | #ifdef RUNTIME_BITS_TABLES 544 | /* build extra bits and base tables */ 545 | tinf_build_bits_base(length_bits, length_base, 4, 3); 546 | tinf_build_bits_base(dist_bits, dist_base, 2, 1); 547 | 548 | /* fix a special case */ 549 | length_bits[28] = 0; 550 | length_base[28] = 258; 551 | #endif 552 | } 553 | 554 | /* initialize decompression structure */ 555 | void uzlib_uncompress_init(struct uzlib_uncomp *d, void *dict, unsigned int dictLen) 556 | { 557 | d->eof = 0; 558 | d->bitcount = 0; 559 | d->bfinal = 0; 560 | d->btype = -1; 561 | d->dict_size = dictLen; 562 | d->dict_ring = dict; 563 | d->dict_idx = 0; 564 | d->curlen = 0; 565 | } 566 | 567 | /* inflate next output bytes from compressed stream */ 568 | int uzlib_uncompress(struct uzlib_uncomp *d) 569 | { 570 | do { 571 | int res; 572 | 573 | /* start a new block */ 574 | if (d->btype == -1) { 575 | int old_btype; 576 | next_blk: 577 | old_btype = d->btype; 578 | /* read final block flag */ 579 | d->bfinal = tinf_getbit(d); 580 | /* read block type (2 bits) */ 581 | d->btype = tinf_read_bits(d, 2, 0); 582 | 583 | #if UZLIB_CONF_DEBUG_LOG >= 1 584 | printf("Started new block: type=%d final=%d\n", d->btype, d->bfinal); 585 | #endif 586 | 587 | if (d->btype == 1 && old_btype != 1) { 588 | /* build fixed huffman trees */ 589 | tinf_build_fixed_trees(&d->ltree, &d->dtree); 590 | } else if (d->btype == 2) { 591 | /* decode trees from stream */ 592 | res = tinf_decode_trees(d, &d->ltree, &d->dtree); 593 | if (res != TINF_OK) { 594 | return res; 595 | } 596 | } 597 | } 598 | 599 | /* process current block */ 600 | switch (d->btype) 601 | { 602 | case 0: 603 | /* decompress uncompressed block */ 604 | res = tinf_inflate_uncompressed_block(d); 605 | break; 606 | case 1: 607 | case 2: 608 | /* decompress block with fixed/dynamic huffman trees */ 609 | /* trees were decoded previously, so it's the same routine for both */ 610 | res = tinf_inflate_block_data(d, &d->ltree, &d->dtree); 611 | break; 612 | default: 613 | return TINF_DATA_ERROR; 614 | } 615 | 616 | if (res == TINF_DONE && !d->bfinal) { 617 | /* the block has ended (without producing more data), but we 618 | can't return without data, so start procesing next block */ 619 | goto next_blk; 620 | } 621 | 622 | if (res != TINF_OK) { 623 | return res; 624 | } 625 | 626 | } while (d->dest < d->dest_limit); 627 | 628 | return TINF_OK; 629 | } 630 | --------------------------------------------------------------------------------