From 02bd840a7ad8fc5ed19d8b615364a6425a87b2e1 Mon Sep 17 00:00:00 2001 From: Luc Date: Wed, 4 Jul 2018 18:56:39 +0200 Subject: [PATCH] 2.0 --- .gitlab-ci.yml | 66 + .travis.yml | 32 +- README.md | 39 +- docs/Commands.txt | 62 +- {esp3d/data => docs/Files}/404.htm | 0 {esp3d/data => docs/Files}/favicon.ico | Bin 1150 -> 1150 bytes docs/Files/index.html.gz | Bin 0 -> 92997 bytes {esp3d/data => docs/Files}/macrocfg.json | 0 docs/Readme.txt | 9 + docs/flash.docx | Bin 0 -> 15814 bytes embedded/out.h | 319 +++ embedded/tool.html.gz | Bin 4776 -> 4862 bytes embedded/www/js/script.js | 6 + embedded/www/tool.html | 3 +- esp3d/bridge.cpp | 209 -- esp3d/bridge.h | 49 - esp3d/command.cpp | 1600 -------------- esp3d/config.cpp | 1865 ---------------- esp3d/data/index.html.gz | Bin 79777 -> 0 bytes esp3d/esp3d.ino | 189 -- esp3d/nofile.h | 326 --- esp3d/storestrings.cpp | 139 -- esp3d/storestrings.h | 61 - esp3d/wificonf.cpp | 505 ----- .../basicesp3d/basicesp3d.ino | 25 +- libraries/AsyncTCP/.travis.yml | 37 + libraries/AsyncTCP/LICENSE | 165 ++ libraries/AsyncTCP/README.md | 11 + libraries/AsyncTCP/component.mk | 3 + libraries/AsyncTCP/library.json | 19 + libraries/AsyncTCP/library.properties | 9 + libraries/AsyncTCP/src/AsyncTCP.cpp | 1055 +++++++++ libraries/AsyncTCP/src/AsyncTCP.h | 191 ++ libraries/AsyncTCP/travis/common.sh | 23 + .../DHT_sensor_library_for_ESPx/DHTesp.cpp | 424 ++++ .../DHT_sensor_library_for_ESPx/DHTesp.h | 170 ++ .../DHT_sensor_library_for_ESPx/LICENSE | 8 +- .../DHT_sensor_library_for_ESPx/README.md | 149 ++ .../examples/DHT_ESP32/DHT_ESP32.ino | 172 ++ .../examples/DHT_Multi/DHT_Multi.ino | 119 + .../examples/DHT_Test/DHT_Test.ino | 38 + .../DHT_sensor_library_for_ESPx/keywords.txt | 79 + .../DHT_sensor_library_for_ESPx/library.json | 15 + .../library.properties | 10 + libraries/ESP32SSDP/ESP32SSDP.cpp | 442 ++++ libraries/ESP32SSDP/ESP32SSDP.h | 126 ++ libraries/ESP32SSDP/README.rst | 22 + libraries/ESP32SSDP/examples/SSDP/SSDP.ino | 51 + libraries/ESP32SSDP/keywords.txt | 53 + libraries/ESP32SSDP/library.properties | 9 + libraries/ESPAsyncTCP/.gitignore | 2 + libraries/ESPAsyncTCP/.travis.yml | 37 + libraries/ESPAsyncTCP/LICENSE.txt | 165 ++ libraries/ESPAsyncTCP/README.md | 30 + .../examples/SyncClient/.esp31b.skip | 0 .../examples/SyncClient/SyncClient.ino | 54 + libraries/ESPAsyncTCP/library.json | 19 + libraries/ESPAsyncTCP/library.properties | 9 + libraries/ESPAsyncTCP/src/AsyncPrinter.cpp | 187 ++ libraries/ESPAsyncTCP/src/AsyncPrinter.h | 73 + libraries/ESPAsyncTCP/src/ESPAsyncTCP.cpp | 1066 +++++++++ libraries/ESPAsyncTCP/src/ESPAsyncTCP.h | 249 +++ .../ESPAsyncTCP/src/ESPAsyncTCPbuffer.cpp | 541 +++++ libraries/ESPAsyncTCP/src/ESPAsyncTCPbuffer.h | 118 + libraries/ESPAsyncTCP/src/SyncClient.cpp | 286 +++ libraries/ESPAsyncTCP/src/SyncClient.h | 82 + libraries/ESPAsyncTCP/src/async_config.h | 11 + libraries/ESPAsyncTCP/src/tcp_axtls.c | 586 +++++ libraries/ESPAsyncTCP/src/tcp_axtls.h | 97 + libraries/ESPAsyncTCP/ssl/gen_server_cert.sh | 36 + libraries/ESPAsyncTCP/ssl/server.cer | Bin 0 -> 587 bytes libraries/ESPAsyncTCP/ssl/server.key | Bin 0 -> 611 bytes libraries/ESPAsyncTCP/travis/common.sh | 23 + libraries/ESPAsyncWebServer/.travis.yml | 39 + libraries/ESPAsyncWebServer/README.md | 1368 ++++++++++++ libraries/ESPAsyncWebServer/component.mk | 3 + .../espressif32_library.json | 23 + .../espressif8266_library.json | 23 + .../examples/ESP_AsyncFSBrowser/.esp31b.skip | 0 .../ESP_AsyncFSBrowser/ESP_AsyncFSBrowser.ino | 211 ++ .../ESP_AsyncFSBrowser/data/.exclude.files | 2 + .../ESP_AsyncFSBrowser/data/ace.js.gz | Bin 0 -> 98943 bytes .../data/ext-searchbox.js.gz | Bin 0 -> 3131 bytes .../ESP_AsyncFSBrowser}/data/favicon.ico | Bin .../ESP_AsyncFSBrowser/data/index.htm | 131 ++ .../ESP_AsyncFSBrowser/data/mode-css.js.gz | Bin 0 -> 6102 bytes .../ESP_AsyncFSBrowser/data/mode-html.js.gz | Bin 0 -> 17037 bytes .../data/mode-javascript.js.gz | Bin 0 -> 6315 bytes .../ESP_AsyncFSBrowser/data/worker-html.js.gz | Bin 0 -> 50024 bytes libraries/ESPAsyncWebServer/keywords.txt | 3 + .../ESPAsyncWebServer/library.properties | 9 + .../src/AsyncEventSource.cpp | 345 +++ .../ESPAsyncWebServer/src/AsyncEventSource.h | 114 + libraries/ESPAsyncWebServer/src/AsyncJson.h | 83 + .../ESPAsyncWebServer/src/AsyncWebSocket.cpp | 1206 +++++++++++ .../ESPAsyncWebServer/src/AsyncWebSocket.h | 306 +++ .../ESPAsyncWebServer/src/ESPAsyncWebServer.h | 448 ++++ .../ESPAsyncWebServer/src/SPIFFSEditor.cpp | 544 +++++ .../ESPAsyncWebServer/src/SPIFFSEditor.h | 23 + libraries/ESPAsyncWebServer/src/StringArray.h | 193 ++ .../src/WebAuthentication.cpp | 235 ++ .../ESPAsyncWebServer/src/WebAuthentication.h | 34 + .../ESPAsyncWebServer/src/WebHandlerImpl.h | 109 + .../ESPAsyncWebServer/src/WebHandlers.cpp | 220 ++ .../ESPAsyncWebServer/src/WebRequest.cpp | 990 +++++++++ .../ESPAsyncWebServer/src/WebResponseImpl.h | 129 ++ .../ESPAsyncWebServer/src/WebResponses.cpp | 685 ++++++ libraries/ESPAsyncWebServer/src/WebServer.cpp | 187 ++ libraries/ESPAsyncWebServer/src/edit.htm | 627 ++++++ libraries/ESPAsyncWebServer/travis/common.sh | 23 + libraries/WebServer/.travis.yml | 99 - libraries/WebServer/README.md | 9 - .../AdvancedWebServer/AdvancedWebServer.ino | 160 -- .../examples/FSBrowser/FSBrowser.ino | 345 --- .../examples/FSBrowser/data/edit.htm.gz | Bin 4116 -> 0 bytes .../examples/FSBrowser/data/graphs.js.gz | Bin 1971 -> 0 bytes .../examples/FSBrowser/data/index.htm | 97 - .../examples/HelloServer/HelloServer.ino | 91 - .../examples/HttpBasicAuth/HttpBasicAuth.ino | 47 - .../examples/SDWebServer/SDWebServer.ino | 290 --- .../SDWebServer/SdRoot/edit/index.htm | 674 ------ .../examples/SDWebServer/SdRoot/index.htm | 22 - .../examples/SDWebServer/SdRoot/pins.png | Bin 177869 -> 0 bytes .../SimpleAuthentification.ino | 137 -- .../examples/WebUpdate/WebUpdate.ino | 78 - libraries/WebServer/keywords.txt | 36 - libraries/WebServer/library.properties | 9 - libraries/WebServer/src/Parsing.cpp | 610 ------ libraries/WebServer/src/WebServer.cpp | 530 ----- libraries/WebServer/src/WebServer.h | 236 -- .../WebServer/src/detail/RequestHandler.h | 19 - .../src/detail/RequestHandlersImpl.h | 191 -- .../.gitignore | 5 +- libraries/arduinoWebSockets/.travis.yml | 40 + .../{WebServer => arduinoWebSockets}/LICENSE | 36 +- libraries/arduinoWebSockets/README.md | 98 + .../Nginx/esp8266.ssl.reverse.proxy.conf | 83 + .../WebSocketClientAVR/WebSocketClientAVR.ino | 84 + .../esp32/WebSocketClient/WebSocketClient.ino | 106 + .../WebSocketClientSSL/WebSocketClientSSL.ino | 102 + .../esp32/WebSocketServer/WebSocketServer.ino | 100 + .../WebSocketClient/WebSocketClient.ino | 92 + .../WebSocketClientSSL/WebSocketClientSSL.ino | 88 + .../WebSocketClientSocketIO.ino | 113 + .../WebSocketClientStomp.ino | 149 ++ .../WebSocketClientStompOverSockJs.ino | 150 ++ .../WebSocketServer/WebSocketServer.ino | 86 + .../WebSocketServerAllFunctionsDemo.ino | 132 ++ .../WebSocketServerFragmentation.ino | 94 + .../WebSocketServerHttpHeaderValidation.ino | 86 + .../WebSocketServer_LEDcontrol.ino | 121 ++ .../ParticleWebSocketClient/application.cpp | 46 + libraries/arduinoWebSockets/library.json | 25 + .../arduinoWebSockets/library.properties | 9 + .../arduinoWebSockets/src/WebSockets.cpp | 654 ++++++ libraries/arduinoWebSockets/src/WebSockets.h | 311 +++ .../src/WebSocketsClient.cpp | 762 +++++++ .../arduinoWebSockets/src/WebSocketsClient.h | 136 ++ .../src/WebSocketsServer.cpp | 873 ++++++++ .../arduinoWebSockets/src/WebSocketsServer.h | 212 ++ .../arduinoWebSockets/src/libb64/AUTHORS | 7 + .../arduinoWebSockets/src/libb64/LICENSE | 29 + .../arduinoWebSockets/src/libb64/cdecode.c | 98 + .../src/libb64/cdecode_inc.h | 28 + .../arduinoWebSockets/src/libb64/cencode.c | 119 + .../src/libb64/cencode_inc.h | 31 + .../arduinoWebSockets/src/libsha1/libsha1.c | 202 ++ .../arduinoWebSockets/src/libsha1/libsha1.h | 21 + .../arduinoWebSockets/tests/webSocket.html | 49 + .../tests/webSocketServer/index.js | 57 + .../tests/webSocketServer/package.json | 27 + libraries/arduinoWebSockets/travis/common.sh | 53 + libraries/oled-ssd1306/.travis.yml | 24 + libraries/oled-ssd1306/OLEDDisplay.cpp | 809 +++++++ libraries/oled-ssd1306/OLEDDisplay.h | 268 +++ libraries/oled-ssd1306/OLEDDisplayFonts.h | 1274 +++++++++++ libraries/oled-ssd1306/OLEDDisplayUi.cpp | 406 ++++ libraries/oled-ssd1306/OLEDDisplayUi.h | 305 +++ libraries/oled-ssd1306/README.md | 393 ++++ libraries/oled-ssd1306/SH1106.h | 36 + libraries/oled-ssd1306/SH1106Brzo.h | 133 ++ libraries/oled-ssd1306/SH1106Spi.h | 128 ++ libraries/oled-ssd1306/SH1106Wire.h | 152 ++ libraries/oled-ssd1306/SSD1306.h | 36 + libraries/oled-ssd1306/SSD1306Brzo.h | 149 ++ libraries/oled-ssd1306/SSD1306Spi.h | 150 ++ libraries/oled-ssd1306/SSD1306Wire.h | 147 ++ libraries/oled-ssd1306/UPGRADE-3.0.md | 125 ++ .../SSD1306ClockDemo/SSD1306ClockDemo.ino | 211 ++ .../examples/SSD1306ClockDemo/images.h | 21 + .../SSD1306DrawingDemo/SSD1306DrawingDemo.ino | 229 ++ .../SSD1306OTADemo/SSD1306OTADemo.ino | 119 + .../SSD1306SimpleDemo/SSD1306SimpleDemo.ino | 187 ++ .../examples/SSD1306SimpleDemo/images.h | 28 + .../examples/SSD1306UiDemo/SSD1306UiDemo.ino | 194 ++ .../examples/SSD1306UiDemo/images.h | 50 + libraries/oled-ssd1306/library.json | 28 + libraries/oled-ssd1306/library.properties | 9 + libraries/oled-ssd1306/license | 24 + .../oled-ssd1306/resources/DemoFrame1.jpg | Bin 0 -> 16026 bytes .../oled-ssd1306/resources/DemoFrame2.jpg | Bin 0 -> 19502 bytes .../oled-ssd1306/resources/DemoFrame3.jpg | Bin 0 -> 21777 bytes .../oled-ssd1306/resources/DemoFrame4.jpg | Bin 0 -> 25325 bytes libraries/oled-ssd1306/resources/FontTool.png | Bin 0 -> 14052 bytes .../oled-ssd1306/resources/SPI_version.jpg | Bin 0 -> 26912 bytes .../oled-ssd1306/resources/xbmPreview.png | Bin 0 -> 41692 bytes library.properties | 9 + {esp3d => src}/GenLinkedList.h | 98 +- src/asyncwebserver.cpp | 1259 +++++++++++ src/asyncwebserver.h | 48 + src/command.cpp | 1718 +++++++++++++++ {esp3d => src}/command.h | 19 +- src/config.cpp | 1927 +++++++++++++++++ {esp3d => src}/config.h | 440 ++-- src/esp3d.cpp | 317 +++ src/esp3d.h | 36 + src/esp_oled.cpp | 226 ++ src/esp_oled.h | 54 + src/espcom.cpp | 420 ++++ src/espcom.h | 57 + src/nofile.h | 333 +++ .../webinterface.cpp => src/syncwebserver.cpp | 1728 ++++++--------- src/syncwebserver.h | 47 + src/webinterface.cpp | 412 ++++ {esp3d => src}/webinterface.h | 45 +- src/wificonf.cpp | 666 ++++++ {esp3d => src}/wificonf.h | 5 +- tarvis.yml | 75 + 228 files changed, 35651 insertions(+), 10005 deletions(-) create mode 100644 .gitlab-ci.yml rename {esp3d/data => docs/Files}/404.htm (100%) rename {esp3d/data => docs/Files}/favicon.ico (53%) create mode 100644 docs/Files/index.html.gz rename {esp3d/data => docs/Files}/macrocfg.json (100%) create mode 100644 docs/Readme.txt create mode 100644 docs/flash.docx create mode 100644 embedded/out.h delete mode 100644 esp3d/bridge.cpp delete mode 100644 esp3d/bridge.h delete mode 100644 esp3d/command.cpp delete mode 100644 esp3d/config.cpp delete mode 100644 esp3d/data/index.html.gz delete mode 100644 esp3d/esp3d.ino delete mode 100644 esp3d/nofile.h delete mode 100644 esp3d/storestrings.cpp delete mode 100644 esp3d/storestrings.h delete mode 100644 esp3d/wificonf.cpp rename libraries/WebServer/src/ESP8266WebServer.h => examples/basicesp3d/basicesp3d.ino (66%) create mode 100644 libraries/AsyncTCP/.travis.yml create mode 100644 libraries/AsyncTCP/LICENSE create mode 100644 libraries/AsyncTCP/README.md create mode 100644 libraries/AsyncTCP/component.mk create mode 100644 libraries/AsyncTCP/library.json create mode 100644 libraries/AsyncTCP/library.properties create mode 100644 libraries/AsyncTCP/src/AsyncTCP.cpp create mode 100644 libraries/AsyncTCP/src/AsyncTCP.h create mode 100644 libraries/AsyncTCP/travis/common.sh create mode 100644 libraries/DHT_sensor_library_for_ESPx/DHTesp.cpp create mode 100644 libraries/DHT_sensor_library_for_ESPx/DHTesp.h rename gpl.txt => libraries/DHT_sensor_library_for_ESPx/LICENSE (99%) create mode 100644 libraries/DHT_sensor_library_for_ESPx/README.md create mode 100644 libraries/DHT_sensor_library_for_ESPx/examples/DHT_ESP32/DHT_ESP32.ino create mode 100644 libraries/DHT_sensor_library_for_ESPx/examples/DHT_Multi/DHT_Multi.ino create mode 100644 libraries/DHT_sensor_library_for_ESPx/examples/DHT_Test/DHT_Test.ino create mode 100644 libraries/DHT_sensor_library_for_ESPx/keywords.txt create mode 100644 libraries/DHT_sensor_library_for_ESPx/library.json create mode 100644 libraries/DHT_sensor_library_for_ESPx/library.properties create mode 100644 libraries/ESP32SSDP/ESP32SSDP.cpp create mode 100644 libraries/ESP32SSDP/ESP32SSDP.h create mode 100644 libraries/ESP32SSDP/README.rst create mode 100644 libraries/ESP32SSDP/examples/SSDP/SSDP.ino create mode 100644 libraries/ESP32SSDP/keywords.txt create mode 100644 libraries/ESP32SSDP/library.properties create mode 100644 libraries/ESPAsyncTCP/.gitignore create mode 100644 libraries/ESPAsyncTCP/.travis.yml create mode 100644 libraries/ESPAsyncTCP/LICENSE.txt create mode 100644 libraries/ESPAsyncTCP/README.md create mode 100644 libraries/ESPAsyncTCP/examples/SyncClient/.esp31b.skip create mode 100644 libraries/ESPAsyncTCP/examples/SyncClient/SyncClient.ino create mode 100644 libraries/ESPAsyncTCP/library.json create mode 100644 libraries/ESPAsyncTCP/library.properties create mode 100644 libraries/ESPAsyncTCP/src/AsyncPrinter.cpp create mode 100644 libraries/ESPAsyncTCP/src/AsyncPrinter.h create mode 100644 libraries/ESPAsyncTCP/src/ESPAsyncTCP.cpp create mode 100644 libraries/ESPAsyncTCP/src/ESPAsyncTCP.h create mode 100644 libraries/ESPAsyncTCP/src/ESPAsyncTCPbuffer.cpp create mode 100644 libraries/ESPAsyncTCP/src/ESPAsyncTCPbuffer.h create mode 100644 libraries/ESPAsyncTCP/src/SyncClient.cpp create mode 100644 libraries/ESPAsyncTCP/src/SyncClient.h create mode 100644 libraries/ESPAsyncTCP/src/async_config.h create mode 100644 libraries/ESPAsyncTCP/src/tcp_axtls.c create mode 100644 libraries/ESPAsyncTCP/src/tcp_axtls.h create mode 100644 libraries/ESPAsyncTCP/ssl/gen_server_cert.sh create mode 100644 libraries/ESPAsyncTCP/ssl/server.cer create mode 100644 libraries/ESPAsyncTCP/ssl/server.key create mode 100644 libraries/ESPAsyncTCP/travis/common.sh create mode 100644 libraries/ESPAsyncWebServer/.travis.yml create mode 100644 libraries/ESPAsyncWebServer/README.md create mode 100644 libraries/ESPAsyncWebServer/component.mk create mode 100644 libraries/ESPAsyncWebServer/espressif32_library.json create mode 100644 libraries/ESPAsyncWebServer/espressif8266_library.json create mode 100644 libraries/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/.esp31b.skip create mode 100644 libraries/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/ESP_AsyncFSBrowser.ino create mode 100644 libraries/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/data/.exclude.files create mode 100644 libraries/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/data/ace.js.gz create mode 100644 libraries/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/data/ext-searchbox.js.gz rename libraries/{WebServer/examples/FSBrowser => ESPAsyncWebServer/examples/ESP_AsyncFSBrowser}/data/favicon.ico (100%) create mode 100644 libraries/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/data/index.htm create mode 100644 libraries/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/data/mode-css.js.gz create mode 100644 libraries/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/data/mode-html.js.gz create mode 100644 libraries/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/data/mode-javascript.js.gz create mode 100644 libraries/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/data/worker-html.js.gz create mode 100644 libraries/ESPAsyncWebServer/keywords.txt create mode 100644 libraries/ESPAsyncWebServer/library.properties create mode 100644 libraries/ESPAsyncWebServer/src/AsyncEventSource.cpp create mode 100644 libraries/ESPAsyncWebServer/src/AsyncEventSource.h create mode 100644 libraries/ESPAsyncWebServer/src/AsyncJson.h create mode 100644 libraries/ESPAsyncWebServer/src/AsyncWebSocket.cpp create mode 100644 libraries/ESPAsyncWebServer/src/AsyncWebSocket.h create mode 100644 libraries/ESPAsyncWebServer/src/ESPAsyncWebServer.h create mode 100644 libraries/ESPAsyncWebServer/src/SPIFFSEditor.cpp create mode 100644 libraries/ESPAsyncWebServer/src/SPIFFSEditor.h create mode 100644 libraries/ESPAsyncWebServer/src/StringArray.h create mode 100644 libraries/ESPAsyncWebServer/src/WebAuthentication.cpp create mode 100644 libraries/ESPAsyncWebServer/src/WebAuthentication.h create mode 100644 libraries/ESPAsyncWebServer/src/WebHandlerImpl.h create mode 100644 libraries/ESPAsyncWebServer/src/WebHandlers.cpp create mode 100644 libraries/ESPAsyncWebServer/src/WebRequest.cpp create mode 100644 libraries/ESPAsyncWebServer/src/WebResponseImpl.h create mode 100644 libraries/ESPAsyncWebServer/src/WebResponses.cpp create mode 100644 libraries/ESPAsyncWebServer/src/WebServer.cpp create mode 100644 libraries/ESPAsyncWebServer/src/edit.htm create mode 100644 libraries/ESPAsyncWebServer/travis/common.sh delete mode 100644 libraries/WebServer/.travis.yml delete mode 100644 libraries/WebServer/README.md delete mode 100644 libraries/WebServer/examples/AdvancedWebServer/AdvancedWebServer.ino delete mode 100644 libraries/WebServer/examples/FSBrowser/FSBrowser.ino delete mode 100644 libraries/WebServer/examples/FSBrowser/data/edit.htm.gz delete mode 100644 libraries/WebServer/examples/FSBrowser/data/graphs.js.gz delete mode 100644 libraries/WebServer/examples/FSBrowser/data/index.htm delete mode 100644 libraries/WebServer/examples/HelloServer/HelloServer.ino delete mode 100644 libraries/WebServer/examples/HttpBasicAuth/HttpBasicAuth.ino delete mode 100644 libraries/WebServer/examples/SDWebServer/SDWebServer.ino delete mode 100644 libraries/WebServer/examples/SDWebServer/SdRoot/edit/index.htm delete mode 100644 libraries/WebServer/examples/SDWebServer/SdRoot/index.htm delete mode 100644 libraries/WebServer/examples/SDWebServer/SdRoot/pins.png delete mode 100644 libraries/WebServer/examples/SimpleAuthentification/SimpleAuthentification.ino delete mode 100644 libraries/WebServer/examples/WebUpdate/WebUpdate.ino delete mode 100644 libraries/WebServer/keywords.txt delete mode 100644 libraries/WebServer/library.properties delete mode 100644 libraries/WebServer/src/Parsing.cpp delete mode 100644 libraries/WebServer/src/WebServer.cpp delete mode 100644 libraries/WebServer/src/WebServer.h delete mode 100644 libraries/WebServer/src/detail/RequestHandler.h delete mode 100644 libraries/WebServer/src/detail/RequestHandlersImpl.h rename libraries/{WebServer => arduinoWebSockets}/.gitignore (87%) create mode 100644 libraries/arduinoWebSockets/.travis.yml rename libraries/{WebServer => arduinoWebSockets}/LICENSE (98%) create mode 100644 libraries/arduinoWebSockets/README.md create mode 100644 libraries/arduinoWebSockets/examples/Nginx/esp8266.ssl.reverse.proxy.conf create mode 100644 libraries/arduinoWebSockets/examples/avr/WebSocketClientAVR/WebSocketClientAVR.ino create mode 100644 libraries/arduinoWebSockets/examples/esp32/WebSocketClient/WebSocketClient.ino create mode 100644 libraries/arduinoWebSockets/examples/esp32/WebSocketClientSSL/WebSocketClientSSL.ino create mode 100644 libraries/arduinoWebSockets/examples/esp32/WebSocketServer/WebSocketServer.ino create mode 100644 libraries/arduinoWebSockets/examples/esp8266/WebSocketClient/WebSocketClient.ino create mode 100644 libraries/arduinoWebSockets/examples/esp8266/WebSocketClientSSL/WebSocketClientSSL.ino create mode 100644 libraries/arduinoWebSockets/examples/esp8266/WebSocketClientSocketIO/WebSocketClientSocketIO.ino create mode 100644 libraries/arduinoWebSockets/examples/esp8266/WebSocketClientStomp/WebSocketClientStomp.ino create mode 100644 libraries/arduinoWebSockets/examples/esp8266/WebSocketClientStompOverSockJs/WebSocketClientStompOverSockJs.ino create mode 100644 libraries/arduinoWebSockets/examples/esp8266/WebSocketServer/WebSocketServer.ino create mode 100644 libraries/arduinoWebSockets/examples/esp8266/WebSocketServerAllFunctionsDemo/WebSocketServerAllFunctionsDemo.ino create mode 100644 libraries/arduinoWebSockets/examples/esp8266/WebSocketServerFragmentation/WebSocketServerFragmentation.ino create mode 100644 libraries/arduinoWebSockets/examples/esp8266/WebSocketServerHttpHeaderValidation/WebSocketServerHttpHeaderValidation.ino create mode 100644 libraries/arduinoWebSockets/examples/esp8266/WebSocketServer_LEDcontrol/WebSocketServer_LEDcontrol.ino create mode 100644 libraries/arduinoWebSockets/examples/particle/ParticleWebSocketClient/application.cpp create mode 100644 libraries/arduinoWebSockets/library.json create mode 100644 libraries/arduinoWebSockets/library.properties create mode 100644 libraries/arduinoWebSockets/src/WebSockets.cpp create mode 100644 libraries/arduinoWebSockets/src/WebSockets.h create mode 100644 libraries/arduinoWebSockets/src/WebSocketsClient.cpp create mode 100644 libraries/arduinoWebSockets/src/WebSocketsClient.h create mode 100644 libraries/arduinoWebSockets/src/WebSocketsServer.cpp create mode 100644 libraries/arduinoWebSockets/src/WebSocketsServer.h create mode 100644 libraries/arduinoWebSockets/src/libb64/AUTHORS create mode 100644 libraries/arduinoWebSockets/src/libb64/LICENSE create mode 100644 libraries/arduinoWebSockets/src/libb64/cdecode.c create mode 100644 libraries/arduinoWebSockets/src/libb64/cdecode_inc.h create mode 100644 libraries/arduinoWebSockets/src/libb64/cencode.c create mode 100644 libraries/arduinoWebSockets/src/libb64/cencode_inc.h create mode 100644 libraries/arduinoWebSockets/src/libsha1/libsha1.c create mode 100644 libraries/arduinoWebSockets/src/libsha1/libsha1.h create mode 100644 libraries/arduinoWebSockets/tests/webSocket.html create mode 100644 libraries/arduinoWebSockets/tests/webSocketServer/index.js create mode 100644 libraries/arduinoWebSockets/tests/webSocketServer/package.json create mode 100644 libraries/arduinoWebSockets/travis/common.sh create mode 100644 libraries/oled-ssd1306/.travis.yml create mode 100644 libraries/oled-ssd1306/OLEDDisplay.cpp create mode 100644 libraries/oled-ssd1306/OLEDDisplay.h create mode 100644 libraries/oled-ssd1306/OLEDDisplayFonts.h create mode 100644 libraries/oled-ssd1306/OLEDDisplayUi.cpp create mode 100644 libraries/oled-ssd1306/OLEDDisplayUi.h create mode 100644 libraries/oled-ssd1306/README.md create mode 100644 libraries/oled-ssd1306/SH1106.h create mode 100644 libraries/oled-ssd1306/SH1106Brzo.h create mode 100644 libraries/oled-ssd1306/SH1106Spi.h create mode 100644 libraries/oled-ssd1306/SH1106Wire.h create mode 100644 libraries/oled-ssd1306/SSD1306.h create mode 100644 libraries/oled-ssd1306/SSD1306Brzo.h create mode 100644 libraries/oled-ssd1306/SSD1306Spi.h create mode 100644 libraries/oled-ssd1306/SSD1306Wire.h create mode 100644 libraries/oled-ssd1306/UPGRADE-3.0.md create mode 100644 libraries/oled-ssd1306/examples/SSD1306ClockDemo/SSD1306ClockDemo.ino create mode 100644 libraries/oled-ssd1306/examples/SSD1306ClockDemo/images.h create mode 100644 libraries/oled-ssd1306/examples/SSD1306DrawingDemo/SSD1306DrawingDemo.ino create mode 100644 libraries/oled-ssd1306/examples/SSD1306OTADemo/SSD1306OTADemo.ino create mode 100644 libraries/oled-ssd1306/examples/SSD1306SimpleDemo/SSD1306SimpleDemo.ino create mode 100644 libraries/oled-ssd1306/examples/SSD1306SimpleDemo/images.h create mode 100644 libraries/oled-ssd1306/examples/SSD1306UiDemo/SSD1306UiDemo.ino create mode 100644 libraries/oled-ssd1306/examples/SSD1306UiDemo/images.h create mode 100644 libraries/oled-ssd1306/library.json create mode 100644 libraries/oled-ssd1306/library.properties create mode 100644 libraries/oled-ssd1306/license create mode 100644 libraries/oled-ssd1306/resources/DemoFrame1.jpg create mode 100644 libraries/oled-ssd1306/resources/DemoFrame2.jpg create mode 100644 libraries/oled-ssd1306/resources/DemoFrame3.jpg create mode 100644 libraries/oled-ssd1306/resources/DemoFrame4.jpg create mode 100644 libraries/oled-ssd1306/resources/FontTool.png create mode 100644 libraries/oled-ssd1306/resources/SPI_version.jpg create mode 100644 libraries/oled-ssd1306/resources/xbmPreview.png create mode 100644 library.properties rename {esp3d => src}/GenLinkedList.h (76%) create mode 100644 src/asyncwebserver.cpp create mode 100644 src/asyncwebserver.h create mode 100644 src/command.cpp rename {esp3d => src}/command.h (61%) create mode 100644 src/config.cpp rename {esp3d => src}/config.h (58%) create mode 100644 src/esp3d.cpp create mode 100644 src/esp3d.h create mode 100644 src/esp_oled.cpp create mode 100644 src/esp_oled.h create mode 100644 src/espcom.cpp create mode 100644 src/espcom.h create mode 100644 src/nofile.h rename esp3d/webinterface.cpp => src/syncwebserver.cpp (57%) create mode 100644 src/syncwebserver.h create mode 100644 src/webinterface.cpp rename {esp3d => src}/webinterface.h (70%) create mode 100644 src/wificonf.cpp rename {esp3d => src}/wificonf.h (94%) create mode 100644 tarvis.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 00000000..d373ebd7 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,66 @@ +before_script: + - cd $HOME + - wget https://pypi.python.org/packages/df/c9/d9da7fafaf2a2b323d20eee050503ab08237c16b0119c7bbf1597d53f793/pyserial-2.7.tar.gz#md5=794506184df83ef2290de0d18803dd11 + - tar -xvf pyserial-2.7.tar.gz + - cd pyserial-2.7 + - python ./setup.py install + - wget http://downloads.arduino.cc/arduino-1.8.0-linux64.tar.xz + - tar xf ./arduino-1.8.0-linux64.tar.xz + - mv arduino-1.8.0 $HOME/arduino_ide + - cd $HOME/arduino_ide/hardware + - mkdir esp8266com + - cd esp8266com + - git clone https://github.com/esp8266/Arduino.git esp8266 + - cd esp8266/tools + - python get.py + - cd .. + - touch pt.txt + - echo 'build.flash_ld=eagle.flash.4m.ld' >> pt.txt + - echo 'build.flash_freq=40' >> pt.txt + - echo 'build.flash_size=4M' >> pt.txt + - echo 'build.f_cpu=160000000L' >> pt.txt + - echo 'build.flash_mode=dio' >> pt.txt + - cat ./platform.txt >> pt.txt + - rm -fr platform.txt + - mv pt.txt platform.txt + - mv $CI_PROJECT_DIR/libraries/SdFat/SdFat $HOME/arduino_ide/libraries/ + - mv $CI_PROJECT_DIR/libraries/IniFile $HOME/arduino_ide/libraries/ + - mv $CI_PROJECT_DIR/libraries/ESPAsyncWebServer $HOME/arduino_ide/libraries/ + - mv $CI_PROJECT_DIR/libraries/ESPAsyncTCP $HOME/arduino_ide/libraries/ + - mv $CI_PROJECT_DIR/libraries/AsyncTCP $HOME/arduino_ide/libraries/ + - mv $CI_PROJECT_DIR/libraries/oled-ssd1306 $HOME/arduino_ide/libraries/ + - mv $CI_PROJECT_DIR/libraries/ESP32SSDP $HOME/arduino_ide/libraries/ + - mv $CI_PROJECT_DIR/libraries/arduinoWebSockets $HOME/arduino_ide/libraries/ + - mv $CI_PROJECT_DIR/libraries/DHT_sensor_library_for_ESPx $HOME/arduino_ide/libraries/ + - mkdir $HOME/arduino_ide/libraries/ESP3D + - mv $CI_PROJECT_DIR/src $HOME/arduino_ide/libraries/ESP3D + - mv $CI_PROJECT_DIR/library.properties $HOME/arduino_ide/libraries/ESP3D + - cd $HOME/arduino_ide/hardware + - mkdir esp32 + - cd esp32 + - git clone https://github.com/espressif/arduino-esp32.git esp32 + - cd esp32 + - cd tools + - python get.py + - cd .. + - touch pt.txt + - echo 'build.flash_freq=80m' >> pt.txt + - cat ./platform.txt >> pt.txt + - rm -fr platform.txt + - mv pt.txt platform.txt + +job1: + script: + - cd $CI_PROJECT_DIR + - source command.sh + - export PATH="$HOME/arduino_ide:$PATH" + - arduino --get-pref + - arduino --board esp8266com:esp8266:generic --save-prefs + - sed -i "s/\/\/#define SDCARD_FEATURE /#define SDCARD_FEATURE/g" $HOME/arduino_ide/libraries/ESP3D/src/config.h + - echo "build ESP8266" + - build_sketch $CI_PROJECT_DIR/examples/basicesp3d/basicesp3d.ino + - arduino --board esp32:esp32:esp32 --save-prefs + - echo "build ESP32" + - build_sketch $CI_PROJECT_DIR/examples/basicesp3d/basicesp3d.ino + + diff --git a/.travis.yml b/.travis.yml index f5fdc0af..bc99c384 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,9 +11,9 @@ before_install: before_script: - "export DISPLAY=:99.0" - sleep 3 # give xvfb some time to start - - wget http://downloads.arduino.cc/arduino-1.8.4-linux64.tar.xz - - tar xf arduino-1.8.4-linux64.tar.xz - - mv arduino-1.8.4 $HOME/arduino_ide + - wget http://downloads.arduino.cc/arduino-1.8.5-linux64.tar.xz + - tar xf arduino-1.8.5-linux64.tar.xz + - mv arduino-1.8.5 $HOME/arduino_ide - cd $HOME/arduino_ide/hardware - mkdir esp8266com - cd esp8266com @@ -35,6 +35,16 @@ before_script: - python get.py - cd .. - echo 'build.flash_freq=40m' >> platform.txt + - mv $TRAVIS_BUILD_DIR/libraries/ESPAsyncWebServer $HOME/arduino_ide/libraries/ + - mv $TRAVIS_BUILD_DIR/libraries/ESPAsyncTCP $HOME/arduino_ide/libraries/ + - mv $TRAVIS_BUILD_DIR/libraries/AsyncTCP $HOME/arduino_ide/libraries/ + - mv $TRAVIS_BUILD_DIR/libraries/oled-ssd1306 $HOME/arduino_ide/libraries/ + - mv $TRAVIS_BUILD_DIR/libraries/ESP32SSDP $HOME/arduino_ide/libraries/ + - mv $TRAVIS_BUILD_DIR/libraries/arduinoWebSockets $HOME/arduino_ide/libraries/ + - mv $TRAVIS_BUILD_DIR/libraries/DHT_sensor_library_for_ESPx $HOME/arduino_ide/libraries/ + - mkdir $HOME/arduino_ide/libraries/ESP3D + - mv $TRAVIS_BUILD_DIR/src $HOME/arduino_ide/libraries/ESP3D + - mv $TRAVIS_BUILD_DIR/library.properties $HOME/arduino_ide/libraries/ESP3D script: @@ -43,9 +53,21 @@ script: - export PATH="$HOME/arduino_ide:$PATH" - arduino --board esp8266com:esp8266:generic --save-prefs - arduino --get-pref sketchbook.path - - build_sketch esp3d/esp3d.ino + - build_sketch $TRAVIS_BUILD_DIR/examples/basicesp3d/basicesp3d.ino - arduino --board esp32:esp32:esp32 --save-prefs - - build_sketch esp3d/esp3d.ino + - build_sketch $TRAVIS_BUILD_DIR/examples/basicesp3d/basicesp3d.ino + - sed -i "s/\/\/#define AUTHENTICATION_FEATURE /#define AUTHENTICATION_FEATURE/g" $HOME/arduino_ide/libraries/ESP3D/src/config.h + - arduino --board esp8266com:esp8266:generic --save-prefs + - arduino --get-pref sketchbook.path + - build_sketch $TRAVIS_BUILD_DIR/examples/basicesp3d/basicesp3d.ino + - arduino --board esp32:esp32:esp32 --save-prefs + - build_sketch $TRAVIS_BUILD_DIR/examples/basicesp3d/basicesp3d.ino + - sed -i "s/\/\/#define ASYNCWEBSERVER /#define ASYNCWEBSERVER/g" $HOME/arduino_ide/libraries/ESP3D/src/config.h + - arduino --board esp8266com:esp8266:generic --save-prefs + - arduino --get-pref sketchbook.path + - build_sketch $TRAVIS_BUILD_DIR/examples/basicesp3d/basicesp3d.ino + - arduino --board esp32:esp32:esp32 --save-prefs + - build_sketch $TRAVIS_BUILD_DIR/examples/basicesp3d/basicesp3d.ino notifications: email: diff --git a/README.md b/README.md index 9faa9ad3..2c864e10 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# ESP3D[![Code Climate](https://codeclimate.com/github/luc-github/ESP3D/badges/gpa.svg)](https://codeclimate.com/github/luc-github/ESP3D) +# ESP3D 2.0 [![Code Climate](https://codeclimate.com/github/luc-github/ESP3D/badges/gpa.svg)](https://codeclimate.com/github/luc-github/ESP3D) Firmware for ESP8266/ESP8285 and ESP32 used with 3D printer using [ESP8266 core version](https://github.com/esp8266/Arduino) and [ESP32 core version](https://github.com/espressif/arduino-esp32) @@ -16,7 +16,7 @@ Arduino ide 1.6.5 with stable [2.0.0](http://arduino.esp8266.com/versions/2.0.0/ Arduino ide 1.6.8 with stable [2.2.0](http://arduino.esp8266.com/versions/2.2.0/package_esp8266com_index.json) from ESP8266, please use https://github.com/luc-github/ESP3D/releases/tag/v0.6.2 Arduino ide 1.8.5 with stable [2.4.0](http://arduino.esp8266.com/versions/2.4.0/package_esp8266com_index.json) from ESP8266, please use https://github.com/luc-github/ESP3D/releases/tag/1.0 [![Build Status](https://travis-ci.org/luc-github/ESP3D.svg?branch=master)](https://travis-ci.org/luc-github/ESP3D) -[Development version for 2.0 (2.0 branch)](https://github.com/luc-github/ESP3D/tree/2.0) & [ESP-WEBUI (2.0 branch)](https://github.com/luc-github/ESP3D-WEBUI/tree/2.0): +[Development version for 2.0](https://github.com/luc-github/ESP3D/tree/2.0) & [ESP-WEBUI (2.0 branch)](https://github.com/luc-github/ESP3D-WEBUI/tree/2.0): Arduino ide 1.8.5 with git version from ESP8266 or ESP32 for 100% support of ESP32 : [![Build Status](https://travis-ci.org/luc-github/ESP3D.svg?branch=2.0)](https://travis-ci.org/luc-github/ESP3D) [All releases](https://github.com/luc-github/ESP3D/wiki) @@ -38,12 +38,13 @@ Especially if need to buy new modules for testing. * Authentication for sensitive pages, here to enable/disable [AUTHENTICATION_FEATURE](https://github.com/luc-github/ESP3D/blob/master/esp3d/config.h) * Update firmware by web browser, here to enable/disable [WEB_UPDATE_FEATURE](https://github.com/luc-github/ESP3D/blob/master/esp3d/config.h) * Control ESP module using commands on serial or data port, here to enable/disable [SERIAL_COMMAND_FEATURE](https://github.com/luc-github/ESP3D/blob/master/esp3d/config.h) -* UI fully constomizable without reflashing FW using html templates, [keywords](https://raw.githubusercontent.com/luc-github/ESP3D/master/docs/keywords.txt) and html files/images * Captive portal in Access point mode which redirect all unknow call to main page, here to enable/disable [CAPTIVE_PORTAL_FEATURE](https://github.com/luc-github/ESP3D/blob/master/esp3d/config.h) * mDNS which allows to key the name defined in web browser and connect only with bonjour installed on computer, here to enable/disable [MDNS_FEATURE](https://github.com/luc-github/ESP3D/blob/master/esp3d/config.h) * SSDP, this feature is a discovery protocol, supported on Windows out of the box, here to enable/disable [SSDP_FEATURE](https://github.com/luc-github/ESP3D/blob/master/esp3d/config.h) -* Printer monitoring / control (temperatures/speed/jog/list SDCard content/launch,pause or stop a print/etc...), here to enable/disable [MONITORING_FEATURE/INFO_MSG_FEATURE/ERROR_MSG_FEATURE/STATUS_MSG_FEATURE](https://github.com/luc-github/ESP3D/blob/master/esp3d/config.h) * Fail safe mode (Access point)is enabled if cannot connect to defined station at boot. +* Choice of web server Async or Sync +* Websocket support +* OLED screen support * The web ui add even more feature : https://github.com/luc-github/ESP3D-WEBUI/blob/master/README.md#features @@ -69,7 +70,8 @@ IP: 192.168.0.1 Mask: 255.255.255.0 GW:192.168.0.1 Baud rate: 115200 -Web port:80 +Web port:80 +On async webserver the websocket is web port => 80+1 : 81 Data port: 8888 Web Page refresh: 3 secondes User: admin @@ -84,14 +86,27 @@ Check wiki : https://github.com/luc-github/ESP3D/wiki/Direct-ESP3D-commands ## Installation 1. Please follow installation of the ESP core you want to use : [ESP8266 core version](https://github.com/esp8266/Arduino) or [ESP32 core version](https://github.com/espressif/arduino-esp32) -2. Add missing libraries if you target ESP32 present in libraries directory -* DNSServer (from https://github.com/bbx10/DNSServer_tng) -* WebServer (from https://github.com/bbx10/WebServer_tng) -* NetBIOS and SSDP are currently disabled for ESP32 as not yet supported -3. Compile project (ESP3D.ino) according target: ESP8266 board or ESP32 board, please review config.h to enable disable a feature, by default athenticatio is disabled and all others are enabled. +2. Add libraries +* ESP3D because it is now a library so copy project to your arduino library folder +If you want async webserver (currently not recommended for ESP8266, suggested for ESP32): +* ESPAsyncWebServer from @me-no-dev +if you target ESP8266 +* ESPAsyncTCP from @me-no-dev +if you target ESP32: +* AsyncTCP from @me-no-dev +Specific for ESP32 +* ESP32SSDP +If you want sync webserver (recommended for ESP8266, slow for ESP32): +* arduinoWebSockets fron @Links2004 +If you want OLED support: +* oled-ssd1306 from @squix78 +If you want DHT11/22 support: +* DHT_sensor_library_for_ESPx from @beegee-tokyo +3. Compile project from examples\basicesp3d\basicesp3d.ino) according target: ESP8266 board or ESP32 board, please review config.h to enable disable a feature, by default athenticatio is disabled and all others are enabled. * for ESP8266 set CPU freq to 160MHz for better (https://github.com/luc-github/ESP3D/wiki/Install-Instructions) 4. Upload the data content on ESP3D file system * Using SPIFFS uploader, this plugin and install instructions is available on each ESP core - please refere to it +or * Using embedded uploader (you may need to format SPIFFS using : [ESP710]FORMAT on ESP8266 first) if embedded uploader does not show up you can force it ti display using : http://your_IP_address?forcefallback=yes
@@ -99,7 +114,7 @@ if embedded uploader does not show up you can force it ti display using : http:/ ## Update * Generate a binary using the export binary menu from Arduino IDE and upload it using ESP-WEBUI or embedded interface -

:warning:Do not flash your Printer fw with ESP connected - it bring troubles, at least on DaVinci

+

:warning:Do not flash your Printer fw with ESP connected on Serial - it bring troubles, at least on DaVinci, but no issue if you update using web UI

## Contribution/customization * To style the code before pushing PR please use [astyle --style=otbs *.h *.cpp *.ino](http://astyle.sourceforge.net/) @@ -107,7 +122,6 @@ if embedded uploader does not show up you can force it ti display using : http:/ * The current UI is located [here](https://github.com/luc-github/ESP3D-WEBUI) * An optional UI is under development using old repetier UI - check [UI\repetier\testui.htm] (https://github.com/luc-github/ESP3D/blob/master/UI/repetier/testui.htm) file -Feedback/suggestion/discussions are always welcome ## Need more information about supported boards or wiring ? [Check the wiki](https://github.com/luc-github/ESP3D/wiki) @@ -120,6 +134,7 @@ Check [Wiki](https://github.com/luc-github/ESP3D/wiki/Install-Instructions) and ## ESP3D is used by : * Custom version is used on azteeg mini wifi : http://www.panucatt.com/azteeg_X5_mini_reprap_3d_printer_controller_p/ax5mini.htm +* Several boards, mostly chinese ones, but without noticed me, so I can't promote them here... * More to come... If you use ESP3D on your product, drop me a message so I can link your product page here. diff --git a/docs/Commands.txt b/docs/Commands.txt index 501fc2c7..f5c860f2 100644 --- a/docs/Commands.txt +++ b/docs/Commands.txt @@ -50,9 +50,6 @@ if authentication is on, need admin password * Get hostname [ESP112]
-* Restart time client -[ESP114] - *Get/Set pin value [ESP201]P V [PULLUP=YES RAW=YES]pwd= if no V get P value @@ -61,11 +58,22 @@ GPIO1 and GPIO3 cannot be used as they are used for serial if PULLUP=YES set input pull up, if not set input if RAW=YES do not set pinmode just read value +* Output to oled column C and line L +[ESP210]C= L= T= + +* Output to oled line 1 +[ESP211] + +* Output to oled line 2 +[ESP212] + +* Output to oled line 3 +[ESP213] + +* Output to oled line 4 +[ESP214] + -*Save data string -[ESP300] pwd= -*Get data string -[ESP301] pwd= *Get full EEPROM settings content but do not give any passwords @@ -76,6 +84,40 @@ can filter if only need wifi or printer position in EEPROM, type: B(byte), I(integer/long), S(string), A(IP address / mask) [ESP401]P= T= V= pwd= +Positions: +* EP_WIFI_MODE 0 //1 byte = flag +* EP_STA_SSID 1 //33 bytes 32+1 = string ; warning does not support multibyte char like chinese +* EP_STA_PASSWORD 34 //65 bytes 64 +1 = string ;warning does not support multibyte char like chinese +* EP_STA_IP_MODE 99 //1 byte = flag +* EP_STA_IP_VALUE 100 //4 bytes xxx.xxx.xxx.xxx +* EP_STA_MASK_VALUE 104 //4 bytes xxx.xxx.xxx.xxx +* EP_STA_GATEWAY_VALUE 108 //4 bytes xxx.xxx.xxx.xxx +* EP_BAUD_RATE 112 //4 bytes = int +* EP_STA_PHY_MODE 116 //1 byte = flag +* EP_SLEEP_MODE 117 //1 byte = flag +* EP_CHANNEL 118 //1 byte = flag +* EP_AUTH_TYPE 119 //1 byte = flag +* EP_SSID_VISIBLE 120 //1 byte = flag +* EP_WEB_PORT 121 //4 bytes = int +* EP_DATA_PORT 125 //4 bytes = int +* EP_OUTPUT_FLAG 129 //1 bytes = flag +* EP_HOSTNAME 130//33 bytes 32+1 = string ; warning does not support multibyte char like chinese +* EP_DHT_INTERVAL 164//4 bytes = int +* EP_FREE_INT2 168//4 bytes = int +* EP_FREE_INT3 172//4 bytes = int +* EP_ADMIN_PWD 176//21 bytes 20+1 = string ; warning does not support multibyte char like chinese +* EP_USER_PWD 197//21 bytes 20+1 = string ; warning does not support multibyte char like chinese +* EP_AP_SSID 218 //33 bytes 32+1 = string ; warning does not support multibyte char like chinese +* EP_AP_PASSWORD 251 //65 bytes 64 +1 = string ;warning does not support multibyte char like chinese +* EP_AP_IP_VALUE 316 //4 bytes xxx.xxx.xxx.xxx +* EP_AP_MASK_VALUE 320 //4 bytes xxx.xxx.xxx.xxx +* EP_AP_GATEWAY_VALUE 324 //4 bytes xxx.xxx.xxx.xxx +* EP_AP_IP_MODE 329 //1 byte = flag +* EP_AP_PHY_MODE 330 //1 byte = flag +* EP_FREE_STRING1 331 //129 bytes 128+1 = string ; warning does not support multibyte char like chinese +* EP_DHT_TYPE 460 //1 bytes = flag +* EP_TARGET_FW 461 //1 bytes = flag + *Get available AP list (limited to 30) output is JSON or plain text according parameter [ESP410] @@ -109,7 +151,7 @@ if no password set it use default one * Get fw target [ESP801]
-* Clear status/error/info list -cmd can be ALL, ERROR, INFO, STATUS -[ESP999] +* Check SD presence +[ESP802] + diff --git a/esp3d/data/404.htm b/docs/Files/404.htm similarity index 100% rename from esp3d/data/404.htm rename to docs/Files/404.htm diff --git a/esp3d/data/favicon.ico b/docs/Files/favicon.ico similarity index 53% rename from esp3d/data/favicon.ico rename to docs/Files/favicon.ico index b2b24df700f4915e446e0dbcaa7be6a9795b43ac..6794fd9f7f0c3cae5d15f4640439b6c14e7537d8 100644 GIT binary patch literal 1150 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

It seems you do not have any index.html neither index.html.gz, please upload it or update your firmware if necessary.

+ you can find one here :
https://github.com/luc-github/ESP3D-WEBUI
diff --git a/esp3d/bridge.cpp b/esp3d/bridge.cpp deleted file mode 100644 index 58d6d34d..00000000 --- a/esp3d/bridge.cpp +++ /dev/null @@ -1,209 +0,0 @@ -/* - bridge.cpp - esp3d bridge serial/tcp class - - Copyright (c) 2014 Luc Lebosse. All rights reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include "config.h" -#include "bridge.h" -#include "command.h" -#include "webinterface.h" - -#ifdef TCP_IP_DATA_FEATURE -WiFiServer * data_server; -WiFiClient serverClients[MAX_SRV_CLIENTS]; -#endif - -bool BRIDGE::header_sent = false; -String BRIDGE::buffer_web = ""; -void BRIDGE::print (const __FlashStringHelper *data, tpipe output) -{ - String tmp = data; - BRIDGE::print(tmp.c_str(), output); -} -void BRIDGE::print (String & data, tpipe output) -{ - BRIDGE::print(data.c_str(), output); -} -void BRIDGE::print (const char * data, tpipe output) -{ - switch(output) { - case SERIAL_PIPE: - header_sent = false; - ESP_SERIAL_OUT.print(data); - break; -#ifdef TCP_IP_DATA_FEATURE - case TCP_PIPE: - header_sent = false; - BRIDGE::send2TCP(data); - break; -#endif - case WEB_PIPE: - if (!header_sent) { - web_interface->web_server.setContentLength(CONTENT_LENGTH_UNKNOWN); - web_interface->web_server.sendHeader("Content-Type","text/html"); - web_interface->web_server.sendHeader("Cache-Control","no-cache"); - web_interface->web_server.send(200); - header_sent = true; - } - buffer_web+=data; - if (buffer_web.length() > 1200) { - //send data - web_interface->web_server.sendContent(buffer_web); - //reset buffer - buffer_web=""; - } - break; - default: - break; - } -} -void BRIDGE::println (const __FlashStringHelper *data, tpipe output) -{ - BRIDGE::print(data,output); -#ifdef TCP_IP_DATA_FEATURE - BRIDGE::print("\r",output); -#endif - BRIDGE::print("\n",output); -} -void BRIDGE::println (String & data, tpipe output) -{ - BRIDGE::print(data,output); -#ifdef TCP_IP_DATA_FEATURE - BRIDGE::print("\r",output); -#endif - BRIDGE::print("\n",output); -} -void BRIDGE::println (const char * data, tpipe output) -{ - BRIDGE::print(data,output); -#ifdef TCP_IP_DATA_FEATURE - BRIDGE::print("\r",output); -#endif - BRIDGE::print("\n",output); -} -void BRIDGE::flush (tpipe output) -{ - switch(output) { - case SERIAL_PIPE: - ESP_SERIAL_OUT.flush(); - break; -#ifdef TCP_IP_DATA_FEATURE - case TCP_PIPE: - break; -#endif - case WEB_PIPE: - if(header_sent) { - //send data - web_interface->web_server.sendContent(buffer_web); - //close line - web_interface->web_server.sendContent(""); - } - break; - default: - break; - } - header_sent = false; - buffer_web = String(); -} - - -#ifdef TCP_IP_DATA_FEATURE -void BRIDGE::send2TCP(const __FlashStringHelper *data) -{ - String tmp = data; - BRIDGE::send2TCP(tmp.c_str()); -} -void BRIDGE::send2TCP(String data) -{ - BRIDGE::send2TCP(data.c_str()); -} -void BRIDGE::send2TCP(const char * data) -{ - for(uint8_t i = 0; i < MAX_SRV_CLIENTS; i++) { - if (serverClients[i] && serverClients[i].connected()) { - serverClients[i].write(data, strlen(data)); - delay(0); - } - } -} -#endif - -bool BRIDGE::processFromSerial2TCP() -{ - uint8_t i; - //check UART for data - if(ESP_SERIAL_OUT.available()) { - size_t len = ESP_SERIAL_OUT.available(); - uint8_t sbuf[len]; - ESP_SERIAL_OUT.readBytes(sbuf, len); -#ifdef TCP_IP_DATA_FEATURE - if (WiFi.getMode()!=WIFI_OFF ) { - //push UART data to all connected tcp clients - for(i = 0; i < MAX_SRV_CLIENTS; i++) { - if (serverClients[i] && serverClients[i].connected()) { - serverClients[i].write(sbuf, len); - delay(0); - } - } - } -#endif - //process data if any - COMMAND::read_buffer_serial(sbuf, len); - return true; - } else { - return false; - } -} -#ifdef TCP_IP_DATA_FEATURE -void BRIDGE::processFromTCP2Serial() -{ - uint8_t i,data; - //check if there are any new clients - if (data_server->hasClient()) { - for(i = 0; i < MAX_SRV_CLIENTS; i++) { - //find free/disconnected spot - if (!serverClients[i] || !serverClients[i].connected()) { - if(serverClients[i]) { - serverClients[i].stop(); - } - serverClients[i] = data_server->available(); - continue; - } - } - //no free/disconnected spot so reject - WiFiClient serverClient = data_server->available(); - serverClient.stop(); - } - //check clients for data - //to avoid any pollution if Uploading file to SDCard - if ((web_interface->blockserial) == false) { - for(i = 0; i < MAX_SRV_CLIENTS; i++) { - if (serverClients[i] && serverClients[i].connected()) { - if(serverClients[i].available()) { - //get data from the tcp client and push it to the UART - while(serverClients[i].available()) { - data = serverClients[i].read(); - ESP_SERIAL_OUT.write(data); - COMMAND::read_buffer_tcp(data); - } - } - } - } - } -} -#endif diff --git a/esp3d/bridge.h b/esp3d/bridge.h deleted file mode 100644 index 6bff0f8f..00000000 --- a/esp3d/bridge.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - bridge.h - esp3d bridge serial/tcp class - - Copyright (c) 2014 Luc Lebosse. All rights reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef BRIDGE_H -#define BRIDGE_H -#include -#include "config.h" -#ifdef TCP_IP_DATA_FEATURE -extern WiFiServer * data_server; -#endif - -class BRIDGE -{ -public: - static bool header_sent; - static String buffer_web; - static bool processFromSerial2TCP(); - static void print (const __FlashStringHelper *data, tpipe output); - static void print (String & data, tpipe output); - static void print (const char * data, tpipe output); - static void println (const __FlashStringHelper *data, tpipe output); - static void println (String & data, tpipe output); - static void println (const char * data, tpipe output); - static void flush (tpipe output); -#ifdef TCP_IP_DATA_FEATURE - static void processFromTCP2Serial(); - static void send2TCP(const __FlashStringHelper *data); - static void send2TCP(String data); - static void send2TCP(const char * data); -#endif -}; -#endif diff --git a/esp3d/command.cpp b/esp3d/command.cpp deleted file mode 100644 index 9b86fe72..00000000 --- a/esp3d/command.cpp +++ /dev/null @@ -1,1600 +0,0 @@ -/* - command.cpp - ESP3D configuration class - - Copyright (c) 2014 Luc Lebosse. All rights reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ -#include "config.h" -#include "command.h" -#include "wificonf.h" -#include "webinterface.h" -#ifndef FS_NO_GLOBALS -#define FS_NO_GLOBALS -#endif -#include -#if defined(ARDUINO_ARCH_ESP32) -#include "SPIFFS.h" -#define MAX_GPIO 16 -#else -#define MAX_GPIO 37 -#endif -String COMMAND::buffer_serial; -String COMMAND::buffer_tcp; - -#define ERROR_CMD_MSG (output == WEB_PIPE)?F("Error: Wrong Command"):F("M117 Cmd Error") -#define INCORRECT_CMD_MSG (output == WEB_PIPE)?F("Error: Incorrect Command"):F("M117 Incorrect Cmd") -#define OK_CMD_MSG (output == WEB_PIPE)?F("ok"):F("M117 Cmd Ok") - -String COMMAND::get_param(String & cmd_params, const char * id, bool withspace) -{ - static String parameter; - String sid=id; - int start; - int end = -1; - parameter = ""; - //if no id it means it is first part of cmd - if (strlen(id) == 0) { - start = 0; - } - //else find id position - else { - start = cmd_params.indexOf(id); - } - //if no id found and not first part leave - if (start == -1 ) { - return parameter; - } - //password and SSID can have space so handle it - //if no space expected use space as delimiter - if (!withspace) { - end = cmd_params.indexOf(" ",start); - } -#ifdef AUTHENTICATION_FEATURE - //if space expected only one parameter but additional password may be present - else if (sid != " pwd=") { - end = cmd_params.indexOf(" pwd=",start); - } -#endif - //if no end found - take all - if (end == -1) { - end = cmd_params.length(); - } - //extract parameter - parameter = cmd_params.substring(start+strlen(id),end); - //be sure no extra space - parameter.trim(); - return parameter; -} -#ifdef AUTHENTICATION_FEATURE -//check admin password -bool COMMAND::isadmin(String & cmd_params) -{ - String adminpassword; - String sadminPassword; - if (!CONFIG::read_string(EP_ADMIN_PWD, sadminPassword, MAX_LOCAL_PASSWORD_LENGTH)) { - LOG("ERROR getting admin\r\n") - sadminPassword=FPSTR(DEFAULT_ADMIN_PWD); - } - adminpassword = get_param(cmd_params,"pwd=", true); - if (!sadminPassword.equals(adminpassword)) { - LOG("Not identified from command line\r\n") - return false; - } else { - return true; - } -} -//check user password - admin password is also valid -bool COMMAND::isuser(String & cmd_params) -{ - String userpassword; - String suserPassword; - if (!CONFIG::read_string(EP_USER_PWD, suserPassword, MAX_LOCAL_PASSWORD_LENGTH)) { - LOG("ERROR getting user\r\n") - suserPassword=FPSTR(DEFAULT_USER_PWD); - } - userpassword = get_param(cmd_params,"pwd=", true); - //it is not user password - if (!suserPassword.equals(userpassword)) { - //check admin password - return COMMAND::isadmin(cmd_params); - } else { - return true; - } -} -#endif -bool COMMAND::execute_command(int cmd,String cmd_params, tpipe output, level_authenticate_type auth_level) -{ - bool response = true; - level_authenticate_type auth_type = auth_level; -#ifdef AUTHENTICATION_FEATURE - if (isadmin(cmd_params)) { - auth_type = LEVEL_ADMIN; - LOG("admin identified\r\n"); - } - if (isuser(cmd_params) && (auth_type != LEVEL_ADMIN)) { - auth_type = LEVEL_USER; - LOG("user identified\r\n"); - } -#ifdef DEBUG_ESP3D - if ( auth_type == LEVEL_ADMIN) - { - LOG("admin identified\r\n"); - } - else { - if( auth_type == LEVEL_USER) - { - LOG("user identified\r\n"); - } - else - { - LOG("guest identified\r\n"); - } - } -#endif -#endif - //manage parameters - byte mode = 254; - String parameter; - LOG("Execute Command\r\n") - switch(cmd) { - //STA SSID - //[ESP100][pwd=] - case 100: - parameter = get_param(cmd_params,"", true); - if (!CONFIG::isSSIDValid(parameter.c_str())) { - BRIDGE::println(INCORRECT_CMD_MSG, output); - } -#ifdef AUTHENTICATION_FEATURE - if (auth_type != LEVEL_ADMIN) { - BRIDGE::println(INCORRECT_CMD_MSG, output); - } else -#endif - if(!CONFIG::write_string(EP_STA_SSID,parameter.c_str())) { - BRIDGE::println(ERROR_CMD_MSG, output); - response = false; - } else { - BRIDGE::println(OK_CMD_MSG, output); - } - break; - //STA Password - //[ESP101][pwd=] - case 101: - parameter = get_param(cmd_params,"", true); - if (!CONFIG::isPasswordValid(parameter.c_str())) { - BRIDGE::println(INCORRECT_CMD_MSG, output); - response = false; - } -#ifdef AUTHENTICATION_FEATURE - if (auth_type != LEVEL_ADMIN) { - BRIDGE::println(INCORRECT_CMD_MSG, output); - response = false; - } else -#endif - if(!CONFIG::write_string(EP_STA_PASSWORD,parameter.c_str())) { - BRIDGE::println(ERROR_CMD_MSG, output); - response = false; - } else { - BRIDGE::println(OK_CMD_MSG, output); - } - break; - //Hostname - //[ESP102][pwd=] - case 102: - parameter = get_param(cmd_params,"", true); - if (!CONFIG::isHostnameValid(parameter.c_str())) { - BRIDGE::println(INCORRECT_CMD_MSG, output); - response = false; - } -#ifdef AUTHENTICATION_FEATURE - if (auth_type != LEVEL_ADMIN) { - BRIDGE::println(INCORRECT_CMD_MSG, output); - response = false; - } else -#endif - if(!CONFIG::write_string(EP_HOSTNAME,parameter.c_str())) { - BRIDGE::println(ERROR_CMD_MSG, output); - response = false; - } else { - BRIDGE::println(OK_CMD_MSG, output); - } - break; - //Wifi mode (STA/AP) - //[ESP103][pwd=] - case 103: - parameter = get_param(cmd_params,"", true); - if (parameter == "STA") { - mode = CLIENT_MODE; - } else if (parameter == "AP") { - mode = AP_MODE; - } else { - BRIDGE::println(INCORRECT_CMD_MSG, output); - response = false; - } - if ((mode == CLIENT_MODE) || (mode == AP_MODE)) { -#ifdef AUTHENTICATION_FEATURE - if (auth_type != LEVEL_ADMIN) { - BRIDGE::println(INCORRECT_CMD_MSG, output); - response = false; - } else -#endif - if(!CONFIG::write_byte(EP_WIFI_MODE,mode)) { - BRIDGE::println(ERROR_CMD_MSG, output); - response = false; - } else { - BRIDGE::println(OK_CMD_MSG, output); - } - } - break; - //STA IP mode (DHCP/STATIC) - //[ESP104][pwd=] - case 104: - parameter = get_param(cmd_params,"", true); - if (parameter == "STATIC") { - mode = STATIC_IP_MODE; - } else if (parameter == "DHCP") { - mode = DHCP_MODE; - } else { - BRIDGE::println(INCORRECT_CMD_MSG, output); - response = false; - } - if ((mode == STATIC_IP_MODE) || (mode == DHCP_MODE)) { -#ifdef AUTHENTICATION_FEATURE - if (auth_type != LEVEL_ADMIN) { - BRIDGE::println(INCORRECT_CMD_MSG, output); - response = false; - } else -#endif - if(!CONFIG::write_byte(EP_STA_IP_MODE,mode)) { - BRIDGE::println(ERROR_CMD_MSG, output); - response = false; - } else { - BRIDGE::println(OK_CMD_MSG, output); - } - } - break; - //AP SSID - //[ESP105][pwd=] - case 105: - parameter = get_param(cmd_params,"", true); - if (!CONFIG::isSSIDValid(parameter.c_str())) { - BRIDGE::println(INCORRECT_CMD_MSG, output); - response = false; - } -#ifdef AUTHENTICATION_FEATURE - if (auth_type != LEVEL_ADMIN) { - BRIDGE::println(INCORRECT_CMD_MSG, output); - response = false; - } else -#endif - if(!CONFIG::write_string(EP_AP_SSID,parameter.c_str())) { - BRIDGE::println(ERROR_CMD_MSG, output); - response = false; - } else { - BRIDGE::println(OK_CMD_MSG, output); - } - break; - //AP Password - //[ESP106][pwd=] - case 106: - parameter = get_param(cmd_params,"", true); - if (!CONFIG::isPasswordValid(parameter.c_str())) { - BRIDGE::println(INCORRECT_CMD_MSG, output); - response = false; - } -#ifdef AUTHENTICATION_FEATURE - if (auth_type != LEVEL_ADMIN) { - BRIDGE::println(INCORRECT_CMD_MSG, output); - response = false; - } else -#endif - if(!CONFIG::write_string(EP_AP_PASSWORD,parameter.c_str())) { - BRIDGE::println(ERROR_CMD_MSG, output); - response = false; - } else { - BRIDGE::println(OK_CMD_MSG, output); - } - break; - //AP IP mode (DHCP/STATIC) - //[ESP107][pwd=] - case 107: - parameter = get_param(cmd_params,"", true); - if (parameter == "STATIC") { - mode = STATIC_IP_MODE; - } else if (parameter == "DHCP") { - mode = DHCP_MODE; - } else { - BRIDGE::println(INCORRECT_CMD_MSG, output); - response = false; - } - if ((mode == STATIC_IP_MODE) || (mode == DHCP_MODE)) { -#ifdef AUTHENTICATION_FEATURE - if (auth_type != LEVEL_ADMIN) { - BRIDGE::println(INCORRECT_CMD_MSG, output); - response = false; - } else -#endif - if(!CONFIG::write_byte(EP_AP_IP_MODE,mode)) { - BRIDGE::println(ERROR_CMD_MSG, output); - response = false; - } else { - BRIDGE::println(OK_CMD_MSG, output); - } - } - break; - // Set wifi on/off - //[ESP110][pwd=] - case 110: - parameter = get_param(cmd_params,"", true); - if (parameter == "on") { - mode = 1; - } else if (parameter == "off") { - mode = 0; - } else if (parameter == "restart") { - mode = 2; - } else { - BRIDGE::println(INCORRECT_CMD_MSG, output); - response = false; - } - if (response) { - #ifdef AUTHENTICATION_FEATURE - if (auth_type != LEVEL_ADMIN) { - BRIDGE::println(INCORRECT_CMD_MSG, output); - response = false; - } else - #endif - if (mode == 0) { - if (WiFi.getMode() !=WIFI_OFF) { - //disable wifi - ESP_SERIAL_OUT.println("M117 Disabling Wifi"); - WiFi.mode(WIFI_OFF); - wifi_config.Disable_servers(); - return response; - } else BRIDGE::println("M117 Wifi already off", output); - } - else if (mode == 1) { //restart device is the best way to start everything clean - if (WiFi.getMode() == WIFI_OFF) { - ESP_SERIAL_OUT.println("M117 Enabling Wifi"); - CONFIG::esp_restart(); - } else BRIDGE::println("M117 Wifi already on", output); - } else { //restart wifi and restart is the best way to start everything clean - ESP_SERIAL_OUT.println("M117 Enabling Wifi"); - CONFIG::esp_restart(); - } - } - break; - //Get current IP - //[ESP111]
- case 111: { - String currentIP ; - if (WiFi.getMode()==WIFI_STA) { - currentIP=WiFi.localIP().toString(); - } else { - currentIP=WiFi.softAPIP().toString(); - } - BRIDGE::print(cmd_params, output); - BRIDGE::println(currentIP, output); - LOG(cmd_params) - LOG(currentIP) - LOG("\r\n") - } - break; - //Get hostname - //[ESP112]
- case 112: { - String shost ; - if (!CONFIG::read_string(EP_HOSTNAME, shost, MAX_HOSTNAME_LENGTH)) { - shost=wifi_config.get_default_hostname(); - } - BRIDGE::print(cmd_params, output); - BRIDGE::println(shost, output); - LOG(cmd_params) - LOG(shost) - LOG("\r\n") - } - break; -#ifdef DIRECT_PIN_FEATURE - //Get/Set pin value - //[ESP201]P V [PULLUP=YES RAW=YES]pwd= - case 201: - parameter = get_param(cmd_params,"", true); -#ifdef AUTHENTICATION_FEATURE - if (auth_type == LEVEL_GUEST) { - BRIDGE::println(INCORRECT_CMD_MSG, output); - response = false; - } else -#endif - { - //check if have pin - parameter = get_param(cmd_params,"P", false); - LOG("Pin:") - LOG(parameter) - LOG("\r\n") - if (parameter == "") { - BRIDGE::println(INCORRECT_CMD_MSG, output); - response = false; - } else { - int pin = parameter.toInt(); - //check pin is valid and not serial used pins - if ((pin >= 0) && (pin <= 16) && !((pin == 1) || (pin == 3))) { - //check if is set or get - parameter = get_param(cmd_params,"V", false); - //it is a get - if (parameter == "") { - //this is to not set pin mode - parameter = get_param(cmd_params,"RAW=", false); - if (parameter !="YES") { - parameter = get_param(cmd_params,"PULLUP=", false); - if (parameter == "YES") { - //GPIO16 is different than others - if (pin < MAX_GPIO) { - LOG("Set as input pull up\r\n") - pinMode(pin, INPUT_PULLUP); - } -#ifdef ARDUINO_ARCH_ESP8266 - else { - LOG("Set as input pull down 16\r\n") - pinMode(pin, INPUT_PULLDOWN_16); - } -#endif - } else { - LOG("Set as input\r\n") - pinMode(pin, INPUT); - } - delay(100); - } - int value = digitalRead(pin); - LOG("Read:"); - LOG(String(value).c_str()) - LOG("\n"); - BRIDGE::println(String(value).c_str(), output); - } else { - //it is a set - int value = parameter.toInt(); - //verify it is a 0 or a 1 - if ((value == 0) || (value == 1)) { - pinMode(pin, OUTPUT); - delay(10); - LOG("Set:") - LOG(String((value == 0)?LOW:HIGH)) - LOG("\r\n") - digitalWrite(pin, (value == 0)?LOW:HIGH); - BRIDGE::println(OK_CMD_MSG, output); - } else { - BRIDGE::println(INCORRECT_CMD_MSG, output); - response = false; - } - } - } else { - BRIDGE::println(INCORRECT_CMD_MSG, output); - response = false; - } - } - } - break; -#endif - - //Save data string - //[ESP300]pwd= - case 300: - parameter = get_param(cmd_params,"", true); -#ifdef AUTHENTICATION_FEATURE - if (auth_type == LEVEL_GUEST) { - BRIDGE::println(INCORRECT_CMD_MSG, output); - response = false; - } else -#endif - { - if(!CONFIG::write_string(EP_DATA_STRING,parameter.c_str())) { - BRIDGE::println(ERROR_CMD_MSG, output); - response = false; - } else { - BRIDGE::println(OK_CMD_MSG, output); - } - } - break; - //get data string - //[ESP301] pwd= - case 301: - parameter = get_param(cmd_params,"", true); -#ifdef AUTHENTICATION_FEATURE - if (auth_type == LEVEL_GUEST) { - BRIDGE::println(INCORRECT_CMD_MSG, output); - response = false; - } else -#endif - { - char sbuf[MAX_DATA_LENGTH+1]; - if (CONFIG::read_string(EP_DATA_STRING, sbuf, MAX_DATA_LENGTH)) { - BRIDGE::println(sbuf, output); - } else { - BRIDGE::println(F("Error reading data"), output); - } - } - break; - //Get full EEPROM settings content - //[ESP400] - case 400: { - char sbuf[MAX_DATA_LENGTH+1]; - uint8_t ipbuf[4]; - byte bbuf=0; - int ibuf=0; - parameter = get_param(cmd_params,"", true); - delay(0); - //Start JSON - BRIDGE::println(F("{\"EEPROM\":["), output); - if (cmd_params == "network" || cmd_params == "") { - - //1- Baud Rate - BRIDGE::print(F("{\"F\":\"network\",\"P\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(EP_BAUD_RATE), output); - BRIDGE::print(F("\",\"T\":\"I\",\"V\":\""), output); - if (!CONFIG::read_buffer(EP_BAUD_RATE, (byte *)&ibuf, INTEGER_LENGTH)) { - BRIDGE::print("???", output); - } else { - BRIDGE::print((const char *)CONFIG::intTostr(ibuf), output); - } - BRIDGE::print(F("\",\"H\":\"Baud Rate\",\"O\":[{\"9600\":\"9600\"},{\"19200\":\"19200\"},{\"38400\":\"38400\"},{\"57600\":\"57600\"},{\"115200\":\"115200\"},{\"230400\":\"230400\"},{\"250000\":\"250000\"}]}"), output); - BRIDGE::println(F(","), output); - - //2-Sleep Mode - BRIDGE::print(F("{\"F\":\"network\",\"P\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(EP_SLEEP_MODE), output); - BRIDGE::print(F("\",\"T\":\"B\",\"V\":\""), output); - if (!CONFIG::read_byte(EP_SLEEP_MODE, &bbuf )) { - BRIDGE::print("???", output); - } else { - BRIDGE::print((const char *)CONFIG::intTostr(bbuf), output); - } - BRIDGE::print(F("\",\"H\":\"Sleep Mode\",\"O\":[{\"None\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(WIFI_NONE_SLEEP), output); -#ifdef ARDUINO_ARCH_ESP8266 - BRIDGE::print(F("\"},{\"Light\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(WIFI_LIGHT_SLEEP), output); -#endif - BRIDGE::print(F("\"},{\"Modem\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(WIFI_MODEM_SLEEP), output); - BRIDGE::print(F("\"}]}"), output); - BRIDGE::println(F(","), output); - - //3-Web Port - BRIDGE::print(F("{\"F\":\"network\",\"P\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(EP_WEB_PORT), output); - BRIDGE::print(F("\",\"T\":\"I\",\"V\":\""), output); - if (!CONFIG::read_buffer(EP_WEB_PORT, (byte *)&ibuf, INTEGER_LENGTH)) { - BRIDGE::print("???", output); - } else { - BRIDGE::print((const char *)CONFIG::intTostr(ibuf), output); - } - BRIDGE::print(F("\",\"H\":\"Web Port\",\"S\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(DEFAULT_MAX_WEB_PORT), output); - BRIDGE::print(F("\",\"M\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(DEFAULT_MIN_WEB_PORT), output); - BRIDGE::print(F("\"}"), output); - BRIDGE::println(F(","), output); - - //4-Data Port - BRIDGE::print(F("{\"F\":\"network\",\"P\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(EP_DATA_PORT), output); - BRIDGE::print(F("\",\"T\":\"I\",\"V\":\""), output); - if (!CONFIG::read_buffer(EP_DATA_PORT, (byte *)&ibuf, INTEGER_LENGTH)) { - BRIDGE::print("???", output); - } else { - BRIDGE::print((const char *)CONFIG::intTostr(ibuf), output); - } - BRIDGE::print(F("\",\"H\":\"Data Port\",\"S\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(DEFAULT_MAX_DATA_PORT), output); - BRIDGE::print(F("\",\"M\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(DEFAULT_MIN_DATA_PORT), output); - BRIDGE::print(F("\"}"), output); - BRIDGE::println(F(","), output); -#ifdef AUTHENTICATION_FEATURE - //5-Admin password - BRIDGE::print(F("{\"F\":\"network\",\"P\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(EP_ADMIN_PWD), output); - BRIDGE::print(F("\",\"T\":\"S\",\"V\":\""), output); - if (!CONFIG::read_string(EP_ADMIN_PWD, sbuf, MAX_LOCAL_PASSWORD_LENGTH)) { - BRIDGE::print("???", output); - } else { - BRIDGE::print("********", output); - } - BRIDGE::print(F("\",\"S\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(MAX_LOCAL_PASSWORD_LENGTH), output); - BRIDGE::print(F("\",\"H\":\"Admin Password\",\"M\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(MIN_LOCAL_PASSWORD_LENGTH), output); - BRIDGE::print(F("\"}"), output); - BRIDGE::println(F(","), output); - - //6-User password - BRIDGE::print(F("{\"F\":\"network\",\"P\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(EP_USER_PWD), output); - BRIDGE::print(F("\",\"T\":\"S\",\"V\":\""), output); - if (!CONFIG::read_string(EP_USER_PWD, sbuf, MAX_LOCAL_PASSWORD_LENGTH)) { - BRIDGE::print("???", output); - } else { - BRIDGE::print("********", output); - } - BRIDGE::print(F("\",\"S\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(MAX_LOCAL_PASSWORD_LENGTH), output); - BRIDGE::print(F("\",\"H\":\"User Password\",\"M\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(MIN_LOCAL_PASSWORD_LENGTH), output); - BRIDGE::print(F("\"}"), output); - BRIDGE::println(F(","), output); -#endif - //7-Hostname - BRIDGE::print(F("{\"F\":\"network\",\"P\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(EP_HOSTNAME), output); - BRIDGE::print(F("\",\"T\":\"S\",\"V\":\""), output); - if (!CONFIG::read_string(EP_HOSTNAME, sbuf, MAX_HOSTNAME_LENGTH)) { - BRIDGE::print("???", output); - } else { - BRIDGE::print(sbuf, output); - } - BRIDGE::print(F("\",\"H\":\"Hostname\" ,\"S\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(MAX_HOSTNAME_LENGTH), output); - BRIDGE::print(F("\", \"M\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(MIN_HOSTNAME_LENGTH), output); - BRIDGE::print(F("\"}"), output); - BRIDGE::println(F(","), output); - - //8-wifi mode - BRIDGE::print(F("{\"F\":\"network\",\"P\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(EP_WIFI_MODE), output); - BRIDGE::print(F("\",\"T\":\"B\",\"V\":\""), output); - if (!CONFIG::read_byte(EP_WIFI_MODE, &bbuf )) { - BRIDGE::print("???", output); - } else { - BRIDGE::print((const char *)CONFIG::intTostr(bbuf), output); - } - BRIDGE::print(F("\",\"H\":\"Wifi mode\",\"O\":[{\"AP\":\"1\"},{\"STA\":\"2\"}]}"), output); - BRIDGE::println(F(","), output); - - //9-STA SSID - BRIDGE::print(F("{\"F\":\"network\",\"P\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(EP_STA_SSID), output); - BRIDGE::print(F("\",\"T\":\"S\",\"V\":\""), output); - if (!CONFIG::read_string(EP_STA_SSID, sbuf, MAX_SSID_LENGTH)) { - BRIDGE::print("???", output); - } else { - BRIDGE::print(sbuf, output); - } - BRIDGE::print(F("\",\"S\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(MAX_SSID_LENGTH), output); - BRIDGE::print(F("\",\"H\":\"Station SSID\",\"M\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(MIN_SSID_LENGTH), output); - BRIDGE::print(F("\"}"), output); - BRIDGE::println(F(","), output); - - //10-STA password - BRIDGE::print(F("{\"F\":\"network\",\"P\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(EP_STA_PASSWORD), output); - BRIDGE::print(F("\",\"T\":\"S\",\"V\":\""), output); - if (!CONFIG::read_string(EP_STA_PASSWORD, sbuf, MAX_PASSWORD_LENGTH)) { - BRIDGE::print("???", output); - } else { - BRIDGE::print("********", output); - } - BRIDGE::print(F("\",\"S\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(MAX_PASSWORD_LENGTH), output); - BRIDGE::print(F("\",\"H\":\"Station Password\",\"M\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(MIN_PASSWORD_LENGTH), output); - BRIDGE::print(F("\"}"), output); - BRIDGE::println(F(","), output); - - //11-Station Network Mode - BRIDGE::print(F("{\"F\":\"network\",\"P\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(EP_STA_PHY_MODE), output); - BRIDGE::print(F("\",\"T\":\"B\",\"V\":\""), output); - if (!CONFIG::read_byte(EP_STA_PHY_MODE, &bbuf )) { - BRIDGE::print("???", output); - } else { - BRIDGE::print((const char *)CONFIG::intTostr(bbuf), output); - } - BRIDGE::print(F("\",\"H\":\"Station Network Mode\",\"O\":[{\"11b\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(WIFI_PHY_MODE_11B), output); - BRIDGE::print(F("\"},{\"11g\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(WIFI_PHY_MODE_11G), output); - BRIDGE::print(F("\"},{\"11n\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(WIFI_PHY_MODE_11N), output); - BRIDGE::print(F("\"}]}"), output); - BRIDGE::println(F(","), output); - - //12-STA IP mode - BRIDGE::print(F("{\"F\":\"network\",\"P\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(EP_STA_IP_MODE), output); - BRIDGE::print(F("\",\"T\":\"B\",\"V\":\""), output); - if (!CONFIG::read_byte(EP_STA_IP_MODE, &bbuf )) { - BRIDGE::print("???", output); - } else { - BRIDGE::print((const char *)CONFIG::intTostr(bbuf), output); - } - BRIDGE::print(F("\",\"H\":\"Station IP Mode\",\"O\":[{\"DHCP\":\"1\"},{\"Static\":\"2\"}]}"), output); - BRIDGE::println(F(","), output); - - //13-STA static IP - BRIDGE::print(F("{\"F\":\"network\",\"P\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(EP_STA_IP_VALUE), output); - BRIDGE::print(F("\",\"T\":\"A\",\"V\":\""), output); - if (!CONFIG::read_buffer(EP_STA_IP_VALUE,(byte *)ipbuf, IP_LENGTH)) { - BRIDGE::print("???", output); - } else { - BRIDGE::print(IPAddress(ipbuf).toString().c_str(), output); - } - BRIDGE::print(F("\",\"H\":\"Station Static IP\"}"), output); - BRIDGE::println(F(","), output); - - //14-STA static Mask - BRIDGE::print(F("{\"F\":\"network\",\"P\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(EP_STA_MASK_VALUE), output); - BRIDGE::print(F("\",\"T\":\"A\",\"V\":\""), output); - if (!CONFIG::read_buffer(EP_STA_MASK_VALUE,(byte *)ipbuf, IP_LENGTH)) { - BRIDGE::print("???", output); - } else { - BRIDGE::print(IPAddress(ipbuf).toString().c_str(), output); - } - BRIDGE::print(F("\",\"H\":\"Station Static Mask\"}"), output); - BRIDGE::println(F(","), output); - - //15-STA static Gateway - BRIDGE::print(F("{\"F\":\"network\",\"P\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(EP_STA_GATEWAY_VALUE), output); - BRIDGE::print(F("\",\"T\":\"A\",\"V\":\""), output); - if (!CONFIG::read_buffer(EP_STA_GATEWAY_VALUE,(byte *)ipbuf, IP_LENGTH)) { - BRIDGE::print("???", output); - } else { - BRIDGE::print(IPAddress(ipbuf).toString().c_str(), output); - } - BRIDGE::print(F("\",\"H\":\"Station Static Gateway\"}"), output); - BRIDGE::println(F(","), output); - - //16-AP SSID - BRIDGE::print(F("{\"F\":\"network\",\"P\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(EP_AP_SSID), output); - BRIDGE::print(F("\",\"T\":\"S\",\"V\":\""), output); - if (!CONFIG::read_string(EP_AP_SSID, sbuf, MAX_SSID_LENGTH)) { - BRIDGE::print("???", output); - } else { - BRIDGE::print(sbuf, output); - } - BRIDGE::print(F("\",\"S\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(MAX_SSID_LENGTH), output); - BRIDGE::print(F("\",\"H\":\"AP SSID\",\"M\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(MIN_SSID_LENGTH), output); - BRIDGE::print(F("\"}"), output); - BRIDGE::println(F(","), output); - - //17-AP password - BRIDGE::print(F("{\"F\":\"network\",\"P\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(EP_AP_PASSWORD), output); - BRIDGE::print(F("\",\"T\":\"S\",\"V\":\""), output); - if (!CONFIG::read_string(EP_AP_PASSWORD, sbuf, MAX_PASSWORD_LENGTH)) { - BRIDGE::print("???", output); - } else { - BRIDGE::print("********", output); - } - BRIDGE::print(F("\",\"S\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(MAX_PASSWORD_LENGTH), output); - BRIDGE::print(F("\",\"H\":\"AP Password\",\"M\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(MIN_PASSWORD_LENGTH), output); - BRIDGE::print(F("\"}"), output); - BRIDGE::println(F(","), output); - - //18 - AP Network Mode - BRIDGE::print(F("{\"F\":\"network\",\"P\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(EP_AP_PHY_MODE), output); - BRIDGE::print(F("\",\"T\":\"B\",\"V\":\""), output); - if (!CONFIG::read_byte(EP_AP_PHY_MODE, &bbuf )) { - BRIDGE::print("???", output); - } else { - BRIDGE::print((const char *)CONFIG::intTostr(bbuf), output); - } - BRIDGE::print(F("\",\"H\":\"AP Network Mode\",\"O\":[{\"11b\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(WIFI_PHY_MODE_11B), output); - BRIDGE::print(F("\"},{\"11g\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(WIFI_PHY_MODE_11G), output); - BRIDGE::print(F("\"}]}"), output); - BRIDGE::println(F(","), output); - - //19-AP SSID visibility - BRIDGE::print(F("{\"F\":\"network\",\"P\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(EP_SSID_VISIBLE), output); - BRIDGE::print(F("\",\"T\":\"B\",\"V\":\""), output); - if (!CONFIG::read_byte(EP_SSID_VISIBLE, &bbuf )) { - BRIDGE::print("???", output); - } else { - BRIDGE::print((const char *)CONFIG::intTostr(bbuf), output); - } - BRIDGE::print(F("\",\"H\":\"SSID Visible\",\"O\":[{\"No\":\"0\"},{\"Yes\":\"1\"}]}"), output); - BRIDGE::println(F(","), output); - - //20-AP Channel - BRIDGE::print(F("{\"F\":\"network\",\"P\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(EP_CHANNEL), output); - BRIDGE::print(F("\",\"T\":\"B\",\"V\":\""), output); - if (!CONFIG::read_byte(EP_CHANNEL, &bbuf )) { - BRIDGE::print("???", output); - } else { - BRIDGE::print((const char *)CONFIG::intTostr(bbuf), output); - } - BRIDGE::print(F("\",\"H\":\"AP Channel\",\"O\":["), output); - for (int i=1; i < 12 ; i++) { - BRIDGE::print(F("{\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(i), output); - BRIDGE::print(F("\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(i), output); - BRIDGE::print(F("\"}"), output); - if (i<11) { - BRIDGE::print(F(","), output); - } - } - BRIDGE::print(F("]}"), output); - BRIDGE::println(F(","), output); - - //21-AP Authentication - BRIDGE::print(F("{\"F\":\"network\",\"P\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(EP_AUTH_TYPE), output); - BRIDGE::print(F("\",\"T\":\"B\",\"V\":\""), output); - if (!CONFIG::read_byte(EP_AUTH_TYPE, &bbuf )) { - BRIDGE::print("???", output); - } else { - BRIDGE::print((const char *)CONFIG::intTostr(bbuf), output); - } - BRIDGE::print(F("\",\"H\":\"Authentication\",\"O\":[{\"Open\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(AUTH_OPEN), output); - BRIDGE::print(F("\"},{\"WPA\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(AUTH_WPA_PSK), output); - BRIDGE::print(F("\"},{\"WPA2\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(AUTH_WPA2_PSK), output); - BRIDGE::print(F("\"},{\"WPA/WPA2\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(AUTH_WPA_WPA2_PSK), output); - BRIDGE::print(F("\"}]}"), output); - BRIDGE::println(F(","), output); - - //22-AP IP mode - BRIDGE::print(F("{\"F\":\"network\",\"P\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(EP_AP_IP_MODE), output); - BRIDGE::print(F("\",\"T\":\"B\",\"V\":\""), output); - if (!CONFIG::read_byte(EP_AP_IP_MODE, &bbuf )) { - BRIDGE::print("???", output); - } else { - BRIDGE::print((const char *)CONFIG::intTostr(bbuf), output); - } - BRIDGE::print(F("\",\"H\":\"AP IP Mode\",\"O\":[{\"DHCP\":\"1\"},{\"Static\":\"2\"}]}"), output); - BRIDGE::println(F(","), output); - - //23-AP static IP - BRIDGE::print(F("{\"F\":\"network\",\"P\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(EP_AP_IP_VALUE), output); - BRIDGE::print(F("\",\"T\":\"A\",\"V\":\""), output); - if (!CONFIG::read_buffer(EP_AP_IP_VALUE,(byte *)ipbuf, IP_LENGTH)) { - BRIDGE::print("???", output); - } else { - BRIDGE::print(IPAddress(ipbuf).toString().c_str(), output); - } - BRIDGE::print(F("\",\"H\":\"AP Static IP\"}"), output); - BRIDGE::println(F(","), output); - - //24-AP static Mask - BRIDGE::print(F("{\"F\":\"network\",\"P\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(EP_AP_MASK_VALUE), output); - BRIDGE::print(F("\",\"T\":\"A\",\"V\":\""), output); - if (!CONFIG::read_buffer(EP_AP_MASK_VALUE,(byte *)ipbuf, IP_LENGTH)) { - BRIDGE::print("???", output); - } else { - BRIDGE::print(IPAddress(ipbuf).toString().c_str(), output); - } - BRIDGE::print(F("\",\"H\":\"AP Static Mask\"}"), output); - BRIDGE::println(F(","), output); - - //25-AP static Gateway - BRIDGE::print(F("{\"F\":\"network\",\"P\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(EP_AP_GATEWAY_VALUE), output); - BRIDGE::print(F("\",\"T\":\"A\",\"V\":\""), output); - if (!CONFIG::read_buffer(EP_AP_GATEWAY_VALUE,(byte *)ipbuf, IP_LENGTH)) { - BRIDGE::print("???", output); - } else { - BRIDGE::print(IPAddress(ipbuf).toString().c_str(), output); - } - BRIDGE::print(F("\",\"H\":\"AP Static Gateway\"}"), output); - delay(0); - } - - if (cmd_params == "printer" || cmd_params == "") { - if (cmd_params == "") { - BRIDGE::println(F(","), output); - } - //Target FW - BRIDGE::print(F("{\"F\":\"printer\",\"P\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(EP_TARGET_FW), output); - BRIDGE::print(F("\",\"T\":\"B\",\"V\":\""), output); - if (!CONFIG::read_byte(EP_TARGET_FW, &bbuf )) { - BRIDGE::print("Unknown", output); - } else { - BRIDGE::print((const char *)CONFIG::intTostr(bbuf), output); - } - BRIDGE::print(F("\",\"H\":\"Target FW\",\"O\":[{\"Repetier\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(REPETIER), output); - BRIDGE::print(F("\"},{\"Repetier for Davinci\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(REPETIER4DV), output); - BRIDGE::print(F("\"},{\"Marlin\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(MARLIN), output); - BRIDGE::print(F("\"},{\"Marlin Kimbra\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(MARLINKIMBRA), output); - BRIDGE::print(F("\"},{\"Smoothieware\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(SMOOTHIEWARE), output); - BRIDGE::print(F("\"},{\"Unknown\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(UNKNOWN_FW), output); - BRIDGE::print(F("\"}]}"), output); - BRIDGE::println(F(","), output); - - //Refresh time 1 - BRIDGE::print(F("{\"F\":\"printer\",\"P\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(EP_REFRESH_PAGE_TIME), output); - BRIDGE::print(F("\",\"T\":\"B\",\"V\":\""), output); - if (!CONFIG::read_byte(EP_REFRESH_PAGE_TIME, &bbuf )) { - BRIDGE::print("???", output); - } else { - BRIDGE::print((const char *)CONFIG::intTostr(bbuf), output); - } - BRIDGE::print(F("\",\"H\":\"Temperature Refresh Time\",\"S\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(DEFAULT_MAX_REFRESH), output); - BRIDGE::print(F("\",\"M\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(DEFAULT_MIN_REFRESH), output); - BRIDGE::print(F("\"}"), output); - BRIDGE::println(F(","), output); - - //Refresh time 2 - BRIDGE::print(F("{\"F\":\"printer\",\"P\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(EP_REFRESH_PAGE_TIME2), output); - BRIDGE::print(F("\",\"T\":\"B\",\"V\":\""), output); - if (!CONFIG::read_byte(EP_REFRESH_PAGE_TIME2, &bbuf )) { - BRIDGE::print("???", output); - } else { - BRIDGE::print((const char *)CONFIG::intTostr(bbuf), output); - } - BRIDGE::print(F("\",\"H\":\"Position Refresh Time\",\"S\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(DEFAULT_MAX_REFRESH), output); - BRIDGE::print(F("\",\"M\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(DEFAULT_MIN_REFRESH), output); - BRIDGE::print(F("\"}"), output); - BRIDGE::println(F(","), output); - - //XY feedrate - BRIDGE::print(F("{\"F\":\"printer\",\"P\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(EP_XY_FEEDRATE), output); - BRIDGE::print(F("\",\"T\":\"I\",\"V\":\""), output); - if (!CONFIG::read_buffer(EP_XY_FEEDRATE, (byte *)&ibuf, INTEGER_LENGTH)) { - BRIDGE::print("???", output); - } else { - BRIDGE::print((const char *)CONFIG::intTostr(ibuf), output); - } - BRIDGE::print(F("\",\"H\":\"XY feedrate\",\"S\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(DEFAULT_MAX_XY_FEEDRATE), output); - BRIDGE::print(F("\",\"M\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(DEFAULT_MIN_XY_FEEDRATE), output); - BRIDGE::print(F("\"}"), output); - BRIDGE::println(F(","), output); - - //Z feedrate - BRIDGE::print(F("{\"F\":\"printer\",\"P\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(EP_Z_FEEDRATE), output); - BRIDGE::print(F("\",\"T\":\"I\",\"V\":\""), output); - if (!CONFIG::read_buffer(EP_Z_FEEDRATE, (byte *)&ibuf, INTEGER_LENGTH)) { - BRIDGE::print("???", output); - } else { - BRIDGE::print((const char *)CONFIG::intTostr(ibuf), output); - } - BRIDGE::print(F("\",\"H\":\"Z feedrate\",\"S\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(DEFAULT_MAX_Z_FEEDRATE), output); - BRIDGE::print(F("\",\"M\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(DEFAULT_MIN_Z_FEEDRATE), output); - BRIDGE::print(F("\"}"), output); - BRIDGE::println(F(","), output); - - //E feedrate - BRIDGE::print(F("{\"F\":\"printer\",\"P\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(EP_E_FEEDRATE), output); - BRIDGE::print(F("\",\"T\":\"I\",\"V\":\""), output); - if (!CONFIG::read_buffer(EP_E_FEEDRATE, (byte *)&ibuf, INTEGER_LENGTH)) { - BRIDGE::print("???", output); - } else { - BRIDGE::print((const char *)CONFIG::intTostr(ibuf), output); - } - BRIDGE::print(F("\",\"H\":\"E feedrate\",\"S\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(DEFAULT_MAX_E_FEEDRATE), output); - BRIDGE::print(F("\",\"M\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(DEFAULT_MIN_E_FEEDRATE), output); - BRIDGE::print(F("\"}"), output); - BRIDGE::println(F(","), output); - - //Camera address, data string - BRIDGE::print(F("{\"F\":\"printer\",\"P\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(EP_DATA_STRING), output); - BRIDGE::print(F("\",\"T\":\"S\",\"V\":\""), output); - if (!CONFIG::read_string(EP_DATA_STRING, sbuf, MAX_DATA_LENGTH)) { - BRIDGE::print("???", output); - } else { - BRIDGE::print(sbuf, output); - } - BRIDGE::print(F("\",\"S\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(MAX_DATA_LENGTH), output); - BRIDGE::print(F("\",\"H\":\"Camera address\",\"M\":\""), output); - BRIDGE::print((const char *)CONFIG::intTostr(MIN_DATA_LENGTH), output); - BRIDGE::print(F("\"}"), output); - } - - //end JSON - BRIDGE::println(F("\n]}"), output); - delay(0); - } - break; - - //Set EEPROM setting - //[ESP401]P= T= V= pwd= - case 401: { - //check validity of parameters - String spos = get_param(cmd_params,"P=", false); - String styp = get_param(cmd_params,"T=", false); - String sval = get_param(cmd_params,"V=", true); - sval.trim(); - int pos = spos.toInt(); - if ((pos == 0 && spos != "0") || (pos > LAST_EEPROM_ADDRESS || pos < 0)) { - response = false; - } - if (!(styp == "B" || styp == "S" || styp == "A" || styp == "I")) { - response = false; - } - if (sval.length() == 0) { - response = false; - } - - -#ifdef AUTHENTICATION_FEATURE - if (response) { - //check authentication - level_authenticate_type auth_need = LEVEL_ADMIN; - for (int i = 0; i < AUTH_ENTRY_NB; i++) { - if (Setting[i][0] == pos ) { - auth_need = (level_authenticate_type)(Setting[i][1]); - i = AUTH_ENTRY_NB; - } - } - if ((auth_need == LEVEL_ADMIN && auth_type == LEVEL_USER) || (auth_type == LEVEL_GUEST)) { - response = false; - } - } -#endif - if (response) { - if (styp == "B") { - byte bbuf = sval.toInt(); - if(!CONFIG::write_byte(pos,bbuf)) { - response = false; - } else { - //dynamique refresh is better than restart the board - if (pos == EP_TARGET_FW)CONFIG::InitFirmwareTarget(); - if (pos == EP_IS_DIRECT_SD){ - CONFIG::InitDirectSD(); - if (CONFIG::is_direct_sd) CONFIG::InitPins(); - } - } - } - if (styp == "I") { - int ibuf = sval.toInt(); - if(!CONFIG::write_buffer(pos,(const byte *)&ibuf,INTEGER_LENGTH)) { - response = false; - } - } - if (styp == "S") { - if(!CONFIG::write_string(pos,sval.c_str())) { - response = false; - } - } - if (styp == "A") { - byte ipbuf[4]; - if (CONFIG::split_ip(sval.c_str(),ipbuf) < 4) { - response = false; - } else if(!CONFIG::write_buffer(pos,ipbuf,IP_LENGTH)) { - response = false; - } - } - } - if(!response) { - BRIDGE::println(INCORRECT_CMD_MSG, output); - } else { - BRIDGE::println(OK_CMD_MSG, output); - } - - } - break; - - //Get available AP list (limited to 30) - //output is JSON or plain text according parameter - //[ESP410] - case 410: { - parameter = get_param(cmd_params,"", true); - int n = WiFi.scanNetworks(); - bool plain = parameter == "plain"; - if (!plain)BRIDGE::print(F("{\"AP_LIST\":["), output); - for (int i = 0; i < n; ++i) { - if (i>0) { - if (!plain) BRIDGE::print(F(","), output); - else BRIDGE::print(F("\n"), output); - } - if (!plain)BRIDGE::print(F("{\"SSID\":\""), output); - BRIDGE::print(WiFi.SSID(i).c_str(), output); - if (!plain)BRIDGE::print(F("\",\"SIGNAL\":\""), output); - else BRIDGE::print(F("\t"), output); - BRIDGE::print(CONFIG::intTostr(wifi_config.getSignal(WiFi.RSSI(i))), output);; - //BRIDGE::print(F("%"), output); - if (!plain)BRIDGE::print(F("\",\"IS_PROTECTED\":\""), output); - if (WiFi.encryptionType(i) == ENC_TYPE_NONE) { - if (!plain)BRIDGE::print(F("0"), output); - else BRIDGE::print(F("\tOpen"), output); - } else { - if (!plain)BRIDGE::print(F("1"), output); - else BRIDGE::print(F("\tSecure"), output); - } - if (!plain)BRIDGE::print(F("\"}"), output); - } - if (!plain)BRIDGE::print(F("]}"), output); - else BRIDGE::print(F("\n"), output); - WiFi.scanDelete(); - } - break; - //Get ESP current status in plain or JSON - //[ESP420] - case 420: { - parameter = get_param(cmd_params,"", true); - CONFIG::print_config(output, (parameter == "plain")); - } - break; - //Set ESP mode - //cmd is RESET, SAFEMODE, RESTART - //[ESP444]pwd= - case 444: - parameter = get_param(cmd_params,"", true); -#ifdef AUTHENTICATION_FEATURE - if (auth_type != LEVEL_ADMIN) { - BRIDGE::println(INCORRECT_CMD_MSG, output); - response = false; - } else -#endif - { - if (parameter=="RESET") { - CONFIG::reset_config(); - BRIDGE::println(F("Reset done - restart needed"), output); - } else if (parameter=="SAFEMODE") { - wifi_config.Safe_Setup(); - BRIDGE::println(F("Set Safe Mode - restart needed"), output); - } else if (parameter=="RESTART") { - BRIDGE::println(F("Restart started"), output); - BRIDGE::flush( output); - CONFIG::esp_restart(); - } else { - BRIDGE::println(INCORRECT_CMD_MSG, output); - response = false; - } - } - break; -#ifdef AUTHENTICATION_FEATURE - //Change / Reset user password - //[ESP555]pwd= - case 555: { - if (auth_type == LEVEL_ADMIN) { - parameter = get_param(cmd_params,"", true); - if (parameter.length() == 0) { - if(CONFIG::write_string(EP_USER_PWD,FPSTR(DEFAULT_USER_PWD))) { - BRIDGE::println(OK_CMD_MSG, output); - } else { - BRIDGE::println(ERROR_CMD_MSG, output); - response = false; - } - } else { - if (CONFIG::isLocalPasswordValid(parameter.c_str())) { - if(CONFIG::write_string(EP_USER_PWD,parameter.c_str())) { - BRIDGE::println(OK_CMD_MSG, output); - } else { - BRIDGE::println(ERROR_CMD_MSG, output); - response = false; - } - } else { - BRIDGE::println(INCORRECT_CMD_MSG, output); - response = false; - } - } - } else { - BRIDGE::println(INCORRECT_CMD_MSG, output); - response = false; - } - break; - } -#endif - //[ESP700] - case 700: { //read local file - //be sure serial is locked - if ((web_interface->blockserial)) { - break; - } - cmd_params.trim() ; - if ((cmd_params.length() > 0) && (cmd_params[0] != '/')) { - cmd_params = "/" + cmd_params; - } - FS_FILE currentfile = SPIFFS.open(cmd_params, SPIFFS_FILE_READ); - if (currentfile) {//if file open success - //flush to be sure send buffer is empty - ESP_SERIAL_OUT.flush(); - //until no line in file - while (currentfile.available()) { - String currentline = currentfile.readStringUntil('\n'); - currentline.replace("\n",""); - currentline.replace("\r",""); - if (currentline.length() > 0) { - int ESPpos = currentline.indexOf("[ESP"); - if (ESPpos>-1) { - //is there the second part? - int ESPpos2 = currentline.indexOf("]",ESPpos); - if (ESPpos2>-1) { - //Split in command and parameters - String cmd_part1=currentline.substring(ESPpos+4,ESPpos2); - String cmd_part2=""; - //is there space for parameters? - if (ESPpos2 - case 710: - parameter = get_param(cmd_params,"", true); -#ifdef AUTHENTICATION_FEATURE - if (auth_type != LEVEL_ADMIN) { - BRIDGE::println(INCORRECT_CMD_MSG, output); - response = false; - } else -#endif - { - if (parameter=="FORMAT") { - BRIDGE::print(F("Formating"), output); - //SPIFFS.end(); - delay(0); - SPIFFS.format(); - //SPIFFS.begin(); - BRIDGE::println(F("...Done"), output); - } else { - BRIDGE::println(INCORRECT_CMD_MSG, output); - response = false; - } - } - break; - //SPIFFS total size and used size - //[ESP720]
- case 720: - BRIDGE::print(cmd_params, output); -#ifdef ARDUINO_ARCH_ESP8266 - fs::FSInfo info; - SPIFFS.info(info); - BRIDGE::print("SPIFFS Total:", output); - BRIDGE::print(CONFIG::formatBytes(info.totalBytes).c_str(), output); - BRIDGE::print(" Used:", output); - BRIDGE::println(CONFIG::formatBytes(info.usedBytes).c_str(), output); -#else - BRIDGE::print("SPIFFS Total:", output); - BRIDGE::print(CONFIG::formatBytes(SPIFFS.totalBytes()).c_str(), output); - BRIDGE::print(" Used:", output); - BRIDGE::println(CONFIG::formatBytes(SPIFFS.usedBytes()).c_str(), output); -#endif - break; - //get fw version firmare target and fw version - //[ESP800]
- case 800: - { - byte sd_dir = 0; - BRIDGE::print(cmd_params, output); - BRIDGE::print(F("FW version:"), output); - BRIDGE::print(FW_VERSION, output); - BRIDGE::print(F(" # FW target:"), output); - BRIDGE::print(CONFIG::GetFirmwareTargetShortName(), output); - BRIDGE::print(F(" # FW HW:"), output); - if (CONFIG::is_direct_sd) BRIDGE::print(F("Direct SD"), output); - else BRIDGE::print(F("Serial SD"), output); - BRIDGE::print(F(" # primary sd:"), output); - if (!CONFIG::read_byte(EP_PRIMARY_SD, &sd_dir )) sd_dir = DEFAULT_PRIMARY_SD; - if (sd_dir == SD_DIRECTORY) BRIDGE::print(F("/sd/"), output); - else if (sd_dir == EXT_DIRECTORY) BRIDGE::print(F("/ext/"), output); - else BRIDGE::print(F("none"), output); - BRIDGE::print(F(" # secondary sd:"), output); - if (!CONFIG::read_byte(EP_SECONDARY_SD, &sd_dir )) sd_dir = DEFAULT_SECONDARY_SD; - if (sd_dir == SD_DIRECTORY) BRIDGE::print(F("/sd/"), output); - else if (sd_dir == EXT_DIRECTORY) BRIDGE::print(F("/ext/"), output); - else BRIDGE::print(F("none"), output); - BRIDGE::print(F(" # authentication:"), output); -#ifdef AUTHENTICATION_FEATURE - BRIDGE::print(F("yes"), output); -#else - BRIDGE::print(F("no"), output); -#endif - BRIDGE::println("", output); - } - break; - //get fw target - //[ESP801]
- case 801: - BRIDGE::print(cmd_params, output); - BRIDGE::println(CONFIG::GetFirmwareTargetShortName(), output); - break; - //clear status/error/info list - case 802: - if (CONFIG::check_update_presence( )) BRIDGE::println("yes", output); - else BRIDGE::println("no", output); - break; - //[ESP999] - case 999: - cmd_params.trim(); -#ifdef ERROR_MSG_FEATURE - if (cmd_params=="ERROR") { - web_interface->error_msg.clear(); - BRIDGE::println(OK_CMD_MSG, output); - break; - } -#endif -#ifdef INFO_MSG_FEATURE - if (cmd_params=="INFO") { - web_interface->info_msg.clear(); - BRIDGE::println(OK_CMD_MSG, output); - break; - } -#endif -#ifdef STATUS_MSG_FEATURE - if (cmd_params=="STATUS") { - web_interface->status_msg.clear(); - BRIDGE::println(OK_CMD_MSG, output); - break; - } -#endif - if (cmd_params=="ALL") { -#ifdef ERROR_MSG_FEATURE - web_interface->error_msg.clear(); -#endif -#ifdef STATUS_MSG_FEATURE - web_interface->status_msg.clear(); -#endif -#ifdef INFO_MSG_FEATURE - web_interface->info_msg.clear(); -#endif - BRIDGE::println(OK_CMD_MSG, output); - break; - } - default: - BRIDGE::println(INCORRECT_CMD_MSG, output); - response = false; - } - return response; -} - -bool COMMAND::check_command(String buffer, tpipe output, bool handlelockserial) -{ - String buffer2; - LOG("Check Command:") - LOG(buffer) - LOG("\r\n") - bool is_temp = false; - if ((buffer.indexOf("T:") > -1 ) || (buffer.indexOf("B:") > -1 )) is_temp = true; - //feed the WD for safety - delay(0); - if (( CONFIG::GetFirmwareTarget() == REPETIER4DV) || (CONFIG::GetFirmwareTarget() == REPETIER)) { - //save time no need to continue - if ((buffer.indexOf("busy:") > -1) || (buffer.startsWith("wait"))) { - return false; - } - if (buffer.startsWith("ok")) { - return false; - } - } -#ifdef ERROR_MSG_FEATURE - int Errorpos = -1; -#endif -#ifdef INFO_MSG_FEATURE - int Infopos = -1; -#endif -#ifdef STATUS_MSG_FEATURE - int Statuspos = -1; -#endif -if (CONFIG::GetFirmwareTarget() == SMOOTHIEWARE) { -#ifdef ERROR_MSG_FEATURE - Errorpos= buffer.indexOf("error:"); -#endif -#ifdef INFO_MSG_FEATURE - Infopos= buffer.indexOf("info:"); -#endif -#ifdef STATUS_MSG_FEATURE - Statuspos= buffer.indexOf("warning:"); -#endif -} else { -#ifdef ERROR_MSG_FEATURE - Errorpos= buffer.indexOf("Error:"); -#endif -#ifdef INFO_MSG_FEATURE - Infopos= buffer.indexOf("Info:"); -#endif -#ifdef STATUS_MSG_FEATURE - Statuspos= -1; - if (CONFIG::GetFirmwareTarget() == MARLIN){ - Statuspos= buffer.indexOf("echo:"); - } - else { - Statuspos= buffer.indexOf("Status:"); - } - -#endif -} - -#ifdef SERIAL_COMMAND_FEATURE - String ESP_Command; - int ESPpos = buffer.indexOf("[ESP"); - if (ESPpos>-1) { - //is there the second part? - int ESPpos2 = buffer.indexOf("]",ESPpos); - if (ESPpos2>-1) { - //Split in command and parameters - String cmd_part1=buffer.substring(ESPpos+4,ESPpos2); - String cmd_part2=""; - //is there space for parameters? - if (ESPpos2-1 && !(buffer.indexOf("Format error")!=-1 || buffer.indexOf("wait")==Errorpos+6) ) { - String ss = buffer.substring(Errorpos+6); - ss.replace("\"",""); - ss.replace("'",""); - (web_interface->error_msg).add(ss.c_str()); - } -#endif -#ifdef INFO_MSG_FEATURE - //Info - if (Infopos>-1) { - String ss = buffer.substring(Errorpos+5); - ss.replace("\"",""); - ss.replace("'",""); - (web_interface->info_msg).add(ss.c_str()); - } -#endif -#ifdef STATUS_MSG_FEATURE - //Status - if (Statuspos>-1) { - String ss ; - if (CONFIG::GetFirmwareTarget() == SMOOTHIEWARE)ss = buffer.substring(Errorpos+8); - else if (CONFIG::GetFirmwareTarget() == MARLIN) ss = buffer.substring(Errorpos+5); - else ss = buffer.substring(Errorpos+7); - ss.replace("\"",""); - ss.replace("'",""); - (web_interface->info_msg).add(ss.c_str()); - } -#endif - - return is_temp; -} - -//read a buffer in an array -void COMMAND::read_buffer_serial(uint8_t *b, size_t len) -{ - for (long i = 0; i< len; i++) { - read_buffer_serial(b[i]); - //*b++; - } -} - -#ifdef TCP_IP_DATA_FEATURE -//read buffer as char -void COMMAND::read_buffer_tcp(uint8_t b) -{ - static bool previous_was_char=false; - static bool iscomment=false; -//to ensure it is continuous string, no char separated by binaries - if (!previous_was_char) { - buffer_tcp=""; - iscomment = false; - } -//is comment ? - if (char(b) == ';') { - iscomment = true; - } -//it is a char so add it to buffer - if (isPrintable(b)) { - previous_was_char=true; - //add char if not a comment - if (!iscomment) { - buffer_tcp+=char(b); - } - } else { - previous_was_char=false; //next call will reset the buffer - } -//this is not printable but end of command check if need to handle it - if (b==13 || b==10) { - //reset comment flag - iscomment = false; - //Minimum is something like M10 so 3 char - if (buffer_tcp.length()>3) { - check_command(buffer_tcp, TCP_PIPE); - } - } -} -#endif -//read buffer as char -void COMMAND::read_buffer_serial(uint8_t b) -{ - static bool previous_was_char=false; - static bool iscomment=false; -//to ensure it is continuous string, no char separated by binaries - if (!previous_was_char) { - buffer_serial=""; - iscomment = false; - } -//is comment ? - if (char(b) == ';') { - iscomment = true; - } -//it is a char so add it to buffer - if (isPrintable(b)) { - previous_was_char=true; - if (!iscomment) { - buffer_serial+=char(b); - } - } else { - previous_was_char=false; //next call will reset the buffer - } -//this is not printable but end of command check if need to handle it - if (b==13 || b==10) { - //reset comment flag - iscomment = false; - //Minimum is something like M10 so 3 char - if (buffer_serial.length()>3) { - check_command(buffer_serial, SERIAL_PIPE); - } - } -} diff --git a/esp3d/config.cpp b/esp3d/config.cpp deleted file mode 100644 index 9b55b265..00000000 --- a/esp3d/config.cpp +++ /dev/null @@ -1,1865 +0,0 @@ -/* - config.cpp- ESP3D configuration class - - Copyright (c) 2014 Luc Lebosse. All rights reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ -#include "config.h" -#include -#ifndef FS_NO_GLOBALS -#define FS_NO_GLOBALS -#endif -#include -#include -#include "wificonf.h" -#ifdef ARDUINO_ARCH_ESP8266 -extern "C" { -#include "user_interface.h" -} -#else -#include "Update.h" -#include "esp_wifi.h" -#endif -#include "bridge.h" - - -uint8_t CONFIG::FirmwareTarget = UNKNOWN_FW; - -bool CONFIG::SetFirmwareTarget(uint8_t fw){ - if ( fw <= MAX_FW_ID) { - FirmwareTarget = fw; - return true; - } else return false; -} -uint8_t CONFIG::GetFirmwareTarget() { - return FirmwareTarget; -} -const char* CONFIG::GetFirmwareTargetName() { - static String response; - if ( CONFIG::FirmwareTarget == REPETIER4DV)response = F("Repetier for Davinci"); - else if ( CONFIG::FirmwareTarget == REPETIER)response = F("Repetier"); - else if ( CONFIG::FirmwareTarget == MARLIN) response = F("Marlin"); - else if ( CONFIG::FirmwareTarget == MARLINKIMBRA) response = F("MarlinKimbra"); - else if ( CONFIG::FirmwareTarget == SMOOTHIEWARE) response = F("Smoothieware"); - else response = F("???"); - return response.c_str(); -} - -const char* CONFIG::GetFirmwareTargetShortName() { - static String response; - if ( CONFIG::FirmwareTarget == REPETIER4DV)response = F("repetier4davinci"); - else if ( CONFIG::FirmwareTarget == REPETIER)response = F("repetier"); - else if ( CONFIG::FirmwareTarget == MARLIN) response = F("marlin"); - else if ( CONFIG::FirmwareTarget == MARLINKIMBRA) response = F("marlinkimbra"); - else if ( CONFIG::FirmwareTarget == SMOOTHIEWARE) response = F("smoothieware"); - else response = F("???"); - return response.c_str(); -} - -void CONFIG::InitFirmwareTarget(){ - uint8_t b = UNKNOWN_FW; - if (!CONFIG::read_byte(EP_TARGET_FW, &b )) { - b = UNKNOWN_FW; - } - if (!SetFirmwareTarget(b))SetFirmwareTarget(UNKNOWN_FW) ; -} - -void CONFIG::InitDirectSD(){ - CONFIG::is_direct_sd = false; - -} - -bool CONFIG::InitBaudrate(){ - long baud_rate=0; - if ( !CONFIG::read_buffer(EP_BAUD_RATE, (byte *)&baud_rate, INTEGER_LENGTH)) return false; - if ( ! (baud_rate==9600 || baud_rate==19200 ||baud_rate==38400 ||baud_rate==57600 ||baud_rate==115200 ||baud_rate==230400 ||baud_rate==250000) ) return false; - //setup serial - if (ESP_SERIAL_OUT.baudRate() != baud_rate)ESP_SERIAL_OUT.begin(baud_rate); -#ifdef ARDUINO_ARCH_ESP8266 - ESP_SERIAL_OUT.setRxBufferSize(SERIAL_RX_BUFFER_SIZE); -#endif - wifi_config.baud_rate=baud_rate; - delay(1000); - return true; -} - -bool CONFIG::InitExternalPorts(){ - if (!CONFIG::read_buffer(EP_WEB_PORT, (byte *)&(wifi_config.iweb_port), INTEGER_LENGTH) || !CONFIG::read_buffer(EP_DATA_PORT, (byte *)&(wifi_config.idata_port), INTEGER_LENGTH)) return false; - if (wifi_config.iweb_port < DEFAULT_MIN_WEB_PORT ||wifi_config.iweb_port > DEFAULT_MAX_WEB_PORT || wifi_config.idata_port < DEFAULT_MIN_DATA_PORT || wifi_config.idata_port > DEFAULT_MAX_DATA_PORT) return false; - return true; -} - -#ifdef SDCARD_CONFIG_FEATURE -bool CONFIG::update_settings(){ - String filename = SDCARD_CONFIG_FILENAME; - filename.toLowerCase(); - //there is a config file - LOG("Check ") - LOG(filename) - LOG("\r\n") - bool answer = true; - if(SD.exists((const char *)filename.c_str())) { - bool success = true; - bool localerror = false; - const size_t bufferLen = 250; - char buffer[bufferLen]; - byte ip_sav[4]; - String stmp; - int itmp; - long baud_rate=0; - byte bflag; - LOG("Found config file\r\n") - String newfilename = filename; - IniFile espconfig((char *)filename.c_str()); - //validate file is correct - if (espconfig.open()) { - if (!espconfig.validate(buffer, bufferLen)) { - success = false; - LOG("Invalid config file\r\n") - } else { //file format is correct - let parse the settings - //Section [wifi] - //Hostname - //hostname = myesp - if (espconfig.getValue("network", "hostname", buffer, bufferLen)) { - if (!CONFIG::isHostnameValid(buffer)) { - success = false; - } else if(!CONFIG::write_string(EP_HOSTNAME,buffer)) { - success = false; - } - } - //baudrate = 115200 - if (espconfig.getValue("network", "baudrate", buffer, bufferLen, baud_rate)) { - if(!CONFIG::write_buffer(EP_BAUD_RATE,(const byte *)&baud_rate,INTEGER_LENGTH)) { - success = false; - } - } - //webport = 80 - if (espconfig.getValue("network", "webport", buffer, bufferLen, itmp)) { - if(!CONFIG::write_buffer(EP_WEB_PORT,(const byte *)&itmp,INTEGER_LENGTH)) { - success = false; - } - } - //dataport = 8888 - if (espconfig.getValue("network", "dataport", buffer, bufferLen, itmp)) { - if(!CONFIG::write_buffer(EP_DATA_PORT,(const byte *)&itmp,INTEGER_LENGTH)) { - success = false; - } - } - //adminpwd = admin - if (espconfig.getValue("network", "adminpwd", buffer, bufferLen)) { - if (!CONFIG::isLocalPasswordValid(buffer)) { - success = false; - } else if(!CONFIG::write_string(EP_ADMIN_PWD,buffer)) { - success = false; - } - } - //userpwd = user - if (espconfig.getValue("network", "userpwd", buffer, bufferLen)) { - if (!CONFIG::isLocalPasswordValid(buffer)) { - success = false; - } else if(!CONFIG::write_string(EP_USER_PWD,buffer)) { - success = false; - } - } - //sleep = none - if (espconfig.getValue("network", "sleep", buffer, bufferLen)) { - stmp = buffer; - localerror = false; - stmp.toLowerCase(); - bflag = 0; - if (stmp =="none") { - bflag = WIFI_NONE_SLEEP; -#ifdef ARDUINO_ARCH_ESP8266 - } else if (stmp =="light") { - bflag = WIFI_LIGHT_SLEEP; -#endif - } else if (stmp =="modem") { - bflag = WIFI_MODEM_SLEEP; - } else { - localerror = true; - success = false; - } - if (!localerror) { - if(!CONFIG::write_byte(EP_SLEEP_MODE,bflag)) { - success = false; - } - } - } - //wifimode = STA - if (espconfig.getValue("network", "wifimode", buffer, bufferLen)) { - stmp = buffer; - localerror = false; - stmp.toLowerCase(); - bflag = 0; - if (stmp =="sta") { - bflag = CLIENT_MODE; - } else if (stmp =="ap") { - bflag = AP_MODE; - } else { - localerror = true; - success = false; - } - if (!localerror) { - if(!CONFIG::write_byte(EP_WIFI_MODE,bflag)) { - success = false; - } - } - } - //STAssid = NETGEAR_2GEXT_OFFICE2 - if (espconfig.getValue("network", "STAssid", buffer, bufferLen)) { - if (!CONFIG::isSSIDValid(buffer)) { - success = false; - } else if(!CONFIG::write_string(EP_STA_SSID,buffer)) { - success = false; - } - } - //STApassword = mypassword - if (espconfig.getValue("network", "STApassword", buffer, bufferLen)) { - if (!CONFIG::isPasswordValid(buffer)) { - success = false; - } else if(!CONFIG::write_string(EP_STA_PASSWORD,buffer)) { - success = false; - } - } - //STAipmode = DHCP - if (espconfig.getValue("network", "STAipmode", buffer, bufferLen)) { - stmp = buffer; - localerror = false; - stmp.toLowerCase(); - bflag = 0; - if (stmp =="dhcp") { - bflag = DHCP_MODE; - } else if (stmp =="static") { - bflag = STATIC_IP_MODE; - } else { - localerror = true; - success = false; - } - if (!localerror) { - if(!CONFIG::write_byte(EP_STA_IP_MODE,bflag)) { - success = false; - } - } - } - //STAstatic_ip = 192.168.0.1 - if (espconfig.getValue("network", "STAstatic_ip", buffer, bufferLen)) { - if (!CONFIG::isIPValid(buffer)) { - success = false; - } else { - CONFIG::split_ip(buffer,ip_sav); - if(!CONFIG::write_buffer(EP_STA_IP_VALUE,ip_sav,IP_LENGTH)) { - success = false; - } - } - } - //STAstatic_mask = 255.255.255.0 - if (espconfig.getValue("network", "STAstatic_mask", buffer, bufferLen)) { - if (!CONFIG::isIPValid(buffer)) { - success = false; - } else { - CONFIG::split_ip(buffer,ip_sav); - if(!CONFIG::write_buffer(EP_STA_MASK_VALUE,ip_sav,IP_LENGTH)) { - success = false; - } - } - } - //STAstatic_gateway = 192.168.0.1 - if (espconfig.getValue("network", "STAstatic_gateway", buffer, bufferLen)) { - if (!CONFIG::isIPValid(buffer)) { - success = false; - } else { - CONFIG::split_ip(buffer,ip_sav); - if(!CONFIG::write_buffer(EP_STA_GATEWAY_VALUE,ip_sav,IP_LENGTH)) { - success = false; - } - } - } - //STANetwork_mode = 11g - if (espconfig.getValue("network", "STANetwork_mode", buffer, bufferLen)) { - stmp = buffer; - localerror = false; - stmp.toLowerCase(); - bflag = 0; - if (stmp =="11b") { - bflag = WIFI_PHY_MODE_11B; - } else if (stmp =="11g") { - bflag = WIFI_PHY_MODE_11G; - } else if (stmp =="11n") { - bflag = WIFI_PHY_MODE_11N; - } else { - localerror = true; - success = false; - } - if (!localerror) { - if(!CONFIG::write_byte(EP_STA_PHY_MODE,bflag)) { - success = false; - } - } - } - //APssid = NETGEAR_2GEXT_OFFICE2 - if (espconfig.getValue("network", "APssid", buffer, bufferLen)) { - if (!CONFIG::isSSIDValid(buffer)) { - success = false; - } else if(!CONFIG::write_string(EP_AP_SSID,buffer)) { - success = false; - } - } - //APpassword = 12345678 - if (espconfig.getValue("network", "APpassword", buffer, bufferLen)) { - if (!CONFIG::isPasswordValid(buffer)) { - success = false; - } else if(!CONFIG::write_string(EP_AP_PASSWORD,buffer)) { - success = false; - } - } - //APipmode = STATIC - if (espconfig.getValue("network", "APipmode", buffer, bufferLen)) { - stmp = buffer; - localerror = false; - stmp.toLowerCase(); - bflag = 0; - if (stmp =="dhcp") { - bflag = DHCP_MODE; - } else if (stmp =="static") { - bflag = STATIC_IP_MODE; - } else { - localerror = true; - success = false; - } - if (!localerror) { - if(!CONFIG::write_byte(EP_AP_IP_MODE,bflag)) { - success = false; - } - } - } - //APstatic_ip = 192.168.0.1 - if (espconfig.getValue("network", "APstatic_ip", buffer, bufferLen)) { - if (!CONFIG::isIPValid(buffer)) { - success = false; - } else { - CONFIG::split_ip(buffer,ip_sav); - if(!CONFIG::write_buffer(EP_AP_IP_VALUE,ip_sav,IP_LENGTH)) { - success = false; - } - } - } - //APstatic_mask = 255.255.255.0 - if (espconfig.getValue("network", "APstatic_mask", buffer, bufferLen)) { - if (!CONFIG::isIPValid(buffer)) { - success = false; - } else { - CONFIG::split_ip(buffer,ip_sav); - if(!CONFIG::write_buffer(EP_AP_MASK_VALUE,ip_sav,IP_LENGTH)) { - success = false; - } - } - } - //APstatic_gateway = 192.168.0.1 - if (espconfig.getValue("network", "APstatic_gateway", buffer, bufferLen)) { - if (!CONFIG::isIPValid(buffer)) { - success = false; - } else { - CONFIG::split_ip(buffer,ip_sav); - if(!CONFIG::write_buffer(EP_AP_GATEWAY_VALUE,ip_sav,IP_LENGTH)) { - success = false; - } - } - } - //AP_channel = 1 - if (espconfig.getValue("network", "AP_channel", buffer, bufferLen, itmp)) { - bflag = itmp; - if(!CONFIG::write_byte(EP_CHANNEL,bflag)) { - success = false; - } - } - //AP_visible = yes - if (espconfig.getValue("network", "AP_visible", buffer, bufferLen)) { - stmp = buffer; - localerror = false; - stmp.toLowerCase(); - bflag = 0; - if (stmp =="yes") { - bflag = 1; - } else if (stmp =="no") { - bflag = 0; - } else { - localerror = true; - success = false; - } - if (!localerror) { - if(!CONFIG::write_byte(EP_SSID_VISIBLE,bflag)) { - success = false; - } - } - } - //AP_auth = WPA - if (espconfig.getValue("network", "AP_auth", buffer, bufferLen)) { - stmp = buffer; - localerror = false; - stmp.toLowerCase(); - bflag = 0; - if (stmp =="open") { - bflag = AUTH_OPEN; - } else if (stmp =="wpa") { - bflag = AUTH_WPA_PSK; - } else if (stmp =="wpa2") { - bflag = AUTH_WPA2_PSK; - } else if (stmp =="wpa_wpa2") { - bflag = AUTH_WPA_WPA2_PSK; - } else { - localerror = true; - success = false; - } - if (!localerror) { - if(!CONFIG::write_byte(EP_AUTH_TYPE,bflag)) { - success = false; - } - } - } - //APNetwork_mode = 11g - if (espconfig.getValue("network", "APNetwork_mode", buffer, bufferLen)) { - stmp = buffer; - localerror = false; - stmp.toLowerCase(); - bflag = 0; - if (stmp =="11b") { - bflag = WIFI_PHY_MODE_11B; - } else if (stmp =="11g") { - bflag = WIFI_PHY_MODE_11G; - } else { - localerror = true; - success = false; - } - if (!localerror) { - if(!CONFIG::write_byte(EP_AP_PHY_MODE,bflag)) { - success = false; - } - } - } - - //Timezone - if (espconfig.getValue("network", "time_zone", buffer, bufferLen, itmp)) { - bflag = itmp; - if(!CONFIG::write_byte(EP_TIMEZONE,bflag)) { - success = false; - } - } - - //day saving time - if (espconfig.getValue("network", "day_st", buffer, bufferLen)) { - stmp = buffer; - localerror = false; - stmp.toLowerCase(); - bflag = 0; - if (stmp =="yes") { - bflag = 1; - } else if (stmp =="no") { - bflag = 0; - } else { - localerror = true; - success = false; - } - if (!localerror) { - if(!CONFIG::write_byte(EP_TIME_ISDST,bflag)) { - success = false; - } - } - } - //time server 1 - if (espconfig.getValue("network", "time_server_1", buffer, bufferLen)) { - if (strlen(buffer) > 128) { - success = false; - } else if(!CONFIG::write_string(EP_TIME_SERVER1,buffer)) { - success = false; - } - } - - //time server 2 - if (espconfig.getValue("network", "time_server_2", buffer, bufferLen)) { - if (strlen(buffer) > 128) { - success = false; - } else if(!CONFIG::write_string(EP_TIME_SERVER2,buffer)) { - success = false; - } - } - - //time server 3 - if (espconfig.getValue("network", "time_server_3", buffer, bufferLen)) { - if (strlen(buffer) > 128) { - success = false; - } else if(!CONFIG::write_string(EP_TIME_SERVER3,buffer)) { - success = false; - } - } - - //Section [printer] - //data = 192.168.1.1/video.cgi?user=luc&pwd=mypassword - if (espconfig.getValue("printer", "data", buffer, bufferLen)) { - if (strlen(buffer) > 128) { - success = false; - } else if(!CONFIG::write_string(EP_DATA_STRING,buffer)) { - success = false; - } - } - //refreshrate = 3 - if (espconfig.getValue("printer", "refreshrate", buffer, bufferLen, itmp)) { - bflag = itmp; - if(!CONFIG::write_byte(EP_REFRESH_PAGE_TIME,bflag)) { - success = false; - } - } - //refreshrate2 = 3 - if (espconfig.getValue("printer", "refreshrate2", buffer, bufferLen, itmp)) { - bflag = itmp; - if(!CONFIG::write_byte(EP_REFRESH_PAGE_TIME2,bflag)) { - success = false; - } - } - //XY_feedrate = 1000 - if (espconfig.getValue("printer", "XY_feedrate", buffer, bufferLen, itmp)) { - if(!CONFIG::write_buffer(EP_XY_FEEDRATE,(const byte *)&itmp,INTEGER_LENGTH)) { - success = false; - } - } - //Z_feedrate = 100 - if (espconfig.getValue("printer", "Z_feedrate", buffer, bufferLen, itmp)) { - if(!CONFIG::write_buffer(EP_Z_FEEDRATE,(const byte *)&itmp,INTEGER_LENGTH)) { - success = false; - } - } - //E_feedrate = 400 - if (espconfig.getValue("printer", "E_feedrate", buffer, bufferLen, itmp)) { - if(!CONFIG::write_buffer(EP_E_FEEDRATE,(const byte *)&itmp,INTEGER_LENGTH)) { - success = false; - } - } - - //target_printer= smoothieware - if (espconfig.getValue("printer", "target_printer", buffer, bufferLen)) { - stmp = buffer; - bflag = UNKNOWN_FW; - if ( stmp.equalsIgnoreCase(String(F("repetier"))))bflag = REPETIER; - else if ( stmp.equalsIgnoreCase(String(F("repetier4davinci"))))bflag = REPETIER4DV; - else if ( stmp.equalsIgnoreCase(String(F("marlin"))))bflag = MARLIN; - else if ( stmp.equalsIgnoreCase(String(F("marlinkimbra"))))bflag = MARLINKIMBRA; - else if ( stmp.equalsIgnoreCase(String(F("smoothieware"))))bflag = SMOOTHIEWARE; - else success = false; - if(!(success && CONFIG::write_byte(EP_TARGET_FW,bflag))) { - success = false; - } - } - - //direct sd connection - if (espconfig.getValue("printer", "direct_sd", buffer, bufferLen)) { - stmp = buffer; - localerror = false; - stmp.toLowerCase(); - bflag = 0; - if (stmp =="yes") { - bflag = 1; - } else if (stmp =="no") { - bflag = 0; - } else { - localerror = true; - success = false; - } - if (!localerror) { - if(!CONFIG::write_byte(EP_IS_DIRECT_SD,bflag)) { - success = false; - } - } - } - //sd check update at boot - if (espconfig.getValue("printer", "sd_check_update", buffer, bufferLen)) { - stmp = buffer; - localerror = false; - stmp.toLowerCase(); - bflag = 0; - if (stmp =="yes") { - bflag = 1; - } else if (stmp =="no") { - bflag = 0; - } else { - localerror = true; - success = false; - } - if (!localerror) { - if(!CONFIG::write_byte(EP_SD_CHECK_UPDATE_AT_BOOT,bflag)) { - success = false; - } - } - } - //direct sd boot check - if (espconfig.getValue("printer", "direct_sd_boot_check", buffer, bufferLen)) { - stmp = buffer; - localerror = false; - stmp.toLowerCase(); - bflag = 0; - if (stmp =="yes") { - bflag = 1; - } else if (stmp =="no") { - bflag = 0; - } else { - localerror = true; - success = false; - } - if (!localerror) { - if(!CONFIG::write_byte(EP_DIRECT_SD_CHECK,bflag)) { - success = false; - } - } - } - - //primary sd directory - if (espconfig.getValue("printer", "primary_sd ", buffer, bufferLen)) { - stmp = buffer; - localerror = false; - stmp.toLowerCase(); - bflag = 0; - if (stmp =="none") { - bflag = 0; - } else if (stmp =="sd") { - bflag = 1; - } else if (stmp =="ext") { - bflag = 2; - } else { - localerror = true; - success = false; - } - if (!localerror) { - if(!CONFIG::write_byte(EP_PRIMARY_SD,bflag)) { - success = false; - } - } - } - - //secondary sd directory - if (espconfig.getValue("printer", "secondary_sd ", buffer, bufferLen)) { - stmp = buffer; - localerror = false; - stmp.toLowerCase(); - bflag = 0; - if (stmp =="none") { - bflag = 0; - } else if (stmp =="sd") { - bflag = 1; - } else if (stmp =="ext") { - bflag = 2; - } else { - localerror = true; - success = false; - } - if (!localerror) { - if(!CONFIG::write_byte(EP_SECONDARY_SD,bflag)) { - success = false; - } - } - } - - } - espconfig.close(); - if(success) { - newfilename.replace(String(".txt"), String(".ok")); - } else { - newfilename.replace(String(".txt"), String(".bad")); - answer = false; - } - //rename if name is already used - if (!CONFIG::renameFile (newfilename)) { - LOG("Failed to rename previous file\r\n") - } - if (SD.rename((const char *)filename.c_str(),(const char *)newfilename.c_str())) { - LOG("File renamed, restarted file\r\n") - } else { - return false; - LOG("Failed to rename file\r\n") - } - } else { - return false; - LOG("Failed to open config file\r\n") - } - } else { - return false; - LOG("No config file\r\n") - } - return answer; -} -#endif -void CONFIG::esp_restart() -{ - LOG("Restarting\r\n") - ESP_SERIAL_OUT.flush(); - delay(500); -#ifdef ARDUINO_ARCH_ESP8266 - ESP_SERIAL_OUT.swap(); -#endif - delay(100); - ESP.restart(); - while (1) { - delay(1); - }; -} - -void CONFIG::InitPins(){ -#ifdef RECOVERY_FEATURE - pinMode(RESET_CONFIG_PIN, INPUT); -#endif -} - -bool CONFIG::is_direct_sd = false; - -bool CONFIG::isHostnameValid(const char * hostname) -{ - //limited size - char c; - if (strlen(hostname)>MAX_HOSTNAME_LENGTH || strlen(hostname) < MIN_HOSTNAME_LENGTH) { - return false; - } - //only letter and digit - for (int i=0; i < strlen(hostname); i++) { - c = hostname[i]; - if (!(isdigit(c) || isalpha(c) || c=='_')) { - return false; - } - if (c==' ') { - return false; - } - } - return true; -} - -bool CONFIG::isSSIDValid(const char * ssid) -{ - //limited size - //char c; - if (strlen(ssid)>MAX_SSID_LENGTH || strlen(ssid)MAX_PASSWORD_LENGTH) { - return false; - } - #if MIN_PASSWORD_LENGTH > 0 - if (strlen(password)MAX_LOCAL_PASSWORD_LENGTH)|| (strlen(password)15 || strlen(IP)==0) { - return false; - } - //cannot start with . - if (IP[0]=='.') { - return false; - } - //only letter and digit - for (int i=0; i < strlen(IP); i++) { - c = IP[i]; - if (isdigit(c)) { - //only 3 digit at once - internalcount++; - previouswasdot=false; - if (internalcount>3) { - return false; - } - } else if(c=='.') { - //cannot have 2 dots side by side - if (previouswasdot) { - return false; - } - previouswasdot=true; - internalcount=0; - dotcount++; - }//if not a dot neither a digit it is wrong - else { - return false; - } - } - //if not 3 dots then it is wrong - if (dotcount!=3) { - return false; - } - //cannot have the last dot as last char - if (IP[strlen(IP)-1]=='.') { - return false; - } - return true; -} - -char * CONFIG::intTostr(int value) -{ - static char result [12]; - sprintf(result,"%d",value); - return result; -} - -String CONFIG::formatBytes(uint32_t bytes) -{ - if (bytes < 1024) { - return String(bytes)+" B"; - } else if(bytes < (1024 * 1024)) { - return String(bytes/1024.0)+" KB"; - } else if(bytes < (1024 * 1024 * 1024)) { - return String(bytes/1024.0/1024.0)+" MB"; - } else { - return String(bytes/1024.0/1024.0/1024.0)+" GB"; - } -} - -//helper to convert string to IP -//do not use IPAddress.fromString() because lack of check point and error result -//return number of parts -byte CONFIG::split_ip (const char * ptr,byte * part) -{ - if (strlen(ptr)>15 || strlen(ptr)< 7) { - part[0]=0; - part[1]=0; - part[2]=0; - part[3]=0; - return 0; - } - - char pstart [16]; - char * ptr2; - strcpy(pstart,ptr); - ptr2 = pstart; - byte i = strlen(pstart); - byte pos = 0; - for (byte j=0; jsprintf(macstr,"%02X:%02X:%02X:%02X:%02X:%02X",mac[0],mac[1],mac[2],mac[3],mac[4],mac[5])) { - strcpy (macstr, "00:00:00:00:00:00"); - } - return macstr; -} - - -//read a string -//a string is multibyte + \0, this is won't work if 1 char is multibyte like chinese char -bool CONFIG::read_string(int pos, char byte_buffer[], int size_max) -{ - //check if parameters are acceptable - if (size_max==0 || pos+size_max+1 > EEPROM_SIZE || byte_buffer== NULL) { - LOG("Error read string\r\n") - return false; - } - EEPROM.begin(EEPROM_SIZE); - byte b = 13; // non zero for the while loop below - int i=0; - - //read until max size is reached or \0 is found - while (i < size_max && b != 0) { - b = EEPROM.read(pos+i); - byte_buffer[i]=b; - i++; - } - - // Be sure there is a 0 at the end. - if (b!=0) { - byte_buffer[i-1]=0x00; - } - EEPROM.end(); - - return true; -} - -bool CONFIG::read_string(int pos, String & sbuffer, int size_max) -{ - //check if parameters are acceptable - if (size_max==0 || pos+size_max+1 > EEPROM_SIZE ) { - LOG("Error read string\r\n") - return false; - } - byte b = 13; // non zero for the while loop below - int i=0; - sbuffer=""; - - EEPROM.begin(EEPROM_SIZE); - //read until max size is reached or \0 is found - while (i < size_max && b != 0) { - b = EEPROM.read(pos+i); - if (b!=0) { - sbuffer+=char(b); - } - i++; - } - EEPROM.end(); - - return true; -} - -//read a buffer of size_buffer -bool CONFIG::read_buffer(int pos, byte byte_buffer[], int size_buffer) -{ - //check if parameters are acceptable - if (size_buffer==0 || pos+size_buffer > EEPROM_SIZE || byte_buffer== NULL) { - LOG("Error read buffer\r\n") - return false; - } - int i=0; - EEPROM.begin(EEPROM_SIZE); - //read until max size is reached - while (i EEPROM_SIZE) { - LOG("Error read byte\r\n") - return false; - } - EEPROM.begin(EEPROM_SIZE); - value[0] = EEPROM.read(pos); - EEPROM.end(); - return true; -} - -bool CONFIG::write_string(int pos, const __FlashStringHelper *str) -{ - String stmp = str; - return write_string(pos,stmp.c_str()); -} - -bool CONFIG::check_update_presence( ){ - bool result = false; - if (CONFIG::is_direct_sd) { - long baud_rate=0; - if (!CONFIG::read_buffer(EP_BAUD_RATE, (byte *)&baud_rate, INTEGER_LENGTH)) return false; - if (ESP_SERIAL_OUT.baudRate() != baud_rate)ESP_SERIAL_OUT.begin(baud_rate); - CONFIG::InitFirmwareTarget(); - delay(500); - String cmd = "M20"; - //By default M20 should be applied - //if (CONFIG::FirmwareTarget == UNKNOWN_FW) return false; - if (CONFIG::FirmwareTarget == SMOOTHIEWARE) { - byte sd_dir = 0; - if (!CONFIG::read_byte(EP_PRIMARY_SD, &sd_dir )) sd_dir = DEFAULT_PRIMARY_SD; - if (sd_dir == SD_DIRECTORY) cmd = "ls /sd"; - else if (sd_dir == EXT_DIRECTORY) cmd = "ls /ext"; - else return false; - } - String tmp; - int count ; - //send command to serial as no need to transfer ESP command - //to avoid any pollution if Uploading file to SDCard - //block every query - //empty the serial buffer and incoming data - if(ESP_SERIAL_OUT.available()) { - BRIDGE::processFromSerial2TCP(); - delay(1); - } - //Send command - ESP_SERIAL_OUT.println(cmd); - count = 0; - String current_buffer; - String current_line; - //int pos; - int temp_counter = 0; - - //pickup the list - while (count < MAX_TRY) { - //give some time between each buffer - if (ESP_SERIAL_OUT.available()) { - count = 0; - size_t len = ESP_SERIAL_OUT.available(); - uint8_t sbuf[len+1]; - //read buffer - ESP_SERIAL_OUT.readBytes(sbuf, len); - //change buffer as string - sbuf[len]='\0'; - //add buffer to current one if any - current_buffer += (char * ) sbuf; - while (current_buffer.indexOf("\n") !=-1) { - //remove the possible "\r" - current_buffer.replace("\r",""); - //pos = current_buffer.indexOf("\n"); - //get line - current_line = current_buffer.substring(0,current_buffer.indexOf("\n")); - //if line is command ack - just exit so save the time out period - if ((current_line == "ok") || (current_line == "wait")) { - count = MAX_TRY; - break; - } - //check line - //save time no need to continue - if (current_line.indexOf("busy:") > -1 || current_line.indexOf("T:") > -1 || current_line.indexOf("B:") > -1) { - temp_counter++; - } else { - } - if (temp_counter > 5) { - break; - } - //current remove line from buffer - tmp = current_buffer.substring(current_buffer.indexOf("\n")+1,current_buffer.length()); - current_buffer = tmp; - delay(0); - } - delay (0); - } else { - delay(1); - } - //it is sending too many temp status should be heating so let's exit the loop - if (temp_counter > 5) { - count = MAX_TRY; - } - count++; - } - if(ESP_SERIAL_OUT.available()) { - BRIDGE::processFromSerial2TCP(); - delay(1); - } - } - return result; -} - - -//write a string (array of byte with a 0x00 at the end) -bool CONFIG::write_string(int pos, const char * byte_buffer) -{ - int size_buffer; - int maxsize = EEPROM_SIZE; - size_buffer= strlen(byte_buffer); - //check if parameters are acceptable - switch (pos) { - case EP_ADMIN_PWD: - case EP_USER_PWD: - maxsize = MAX_LOCAL_PASSWORD_LENGTH; - break; - case EP_AP_SSID: - case EP_STA_SSID: - maxsize = MAX_SSID_LENGTH; - break; - case EP_AP_PASSWORD: - case EP_STA_PASSWORD: - maxsize = MAX_PASSWORD_LENGTH; - break; - case EP_HOSTNAME: - maxsize = MAX_HOSTNAME_LENGTH; - break; - case EP_TIME_SERVER1: - case EP_TIME_SERVER2: - case EP_TIME_SERVER3: - case EP_DATA_STRING: - maxsize = MAX_DATA_LENGTH; - break; - default: - maxsize = EEPROM_SIZE; - break; - } - if ((size_buffer==0 && !(pos == EP_DATA_STRING)) || pos+size_buffer+1 > EEPROM_SIZE || size_buffer > maxsize || byte_buffer== NULL) { - LOG("Error write string\r\n") - return false; - } - //copy the value(s) - EEPROM.begin(EEPROM_SIZE); - for (int i = 0; i < size_buffer; i++) { - EEPROM.write(pos + i, byte_buffer[i]); - } - - //0 terminal - EEPROM.write(pos + size_buffer, 0x00); - EEPROM.commit(); - EEPROM.end(); - return true; -} - -//write a buffer -bool CONFIG::write_buffer(int pos, const byte * byte_buffer, int size_buffer) -{ - //check if parameters are acceptable - if (size_buffer==0 || pos+size_buffer > EEPROM_SIZE || byte_buffer== NULL) { - LOG("Error write buffer\r\n") - return false; - } - EEPROM.begin(EEPROM_SIZE); - //copy the value(s) - for (int i = 0; i < size_buffer; i++) { - EEPROM.write(pos + i, byte_buffer[i]); - } - EEPROM.commit(); - EEPROM.end(); - return true; -} - -//read a flag / byte -bool CONFIG::write_byte(int pos, const byte value) -{ - //check if parameters are acceptable - if (pos+1 > EEPROM_SIZE) { - LOG("Error write byte\r\n") - return false; - } - EEPROM.begin(EEPROM_SIZE); - EEPROM.write(pos, value); - EEPROM.commit(); - EEPROM.end(); - return true; -} - -bool CONFIG::reset_config() -{ - if(!CONFIG::write_string(EP_DATA_STRING,"")) { - return false; - } - if(!CONFIG::write_byte(EP_WIFI_MODE,DEFAULT_WIFI_MODE)) { - return false; - } - if(!CONFIG::write_buffer(EP_BAUD_RATE,(const byte *)&DEFAULT_BAUD_RATE,INTEGER_LENGTH)) { - return false; - } - if(!CONFIG::write_string(EP_AP_SSID,FPSTR(DEFAULT_AP_SSID))) { - return false; - } - if(!CONFIG::write_string(EP_AP_PASSWORD,FPSTR(DEFAULT_AP_PASSWORD))) { - return false; - } - if(!CONFIG::write_string(EP_STA_SSID,FPSTR(DEFAULT_STA_SSID))) { - return false; - } - if(!CONFIG::write_string(EP_STA_PASSWORD,FPSTR(DEFAULT_STA_PASSWORD))) { - return false; - } - if(!CONFIG::write_byte(EP_AP_IP_MODE,DEFAULT_AP_IP_MODE)) { - return false; - } - if(!CONFIG::write_byte(EP_STA_IP_MODE,DEFAULT_STA_IP_MODE)) { - return false; - } - if(!CONFIG::write_buffer(EP_STA_IP_VALUE,DEFAULT_IP_VALUE,IP_LENGTH)) { - return false; - } - if(!CONFIG::write_buffer(EP_STA_MASK_VALUE,DEFAULT_MASK_VALUE,IP_LENGTH)) { - return false; - } - if(!CONFIG::write_buffer(EP_STA_GATEWAY_VALUE,DEFAULT_GATEWAY_VALUE,IP_LENGTH)) { - return false; - } - if(!CONFIG::write_byte(EP_STA_PHY_MODE,DEFAULT_PHY_MODE)) { - return false; - } - if(!CONFIG::write_buffer(EP_AP_IP_VALUE,DEFAULT_IP_VALUE,IP_LENGTH)) { - return false; - } - if(!CONFIG::write_buffer(EP_AP_MASK_VALUE,DEFAULT_MASK_VALUE,IP_LENGTH)) { - return false; - } - if(!CONFIG::write_buffer(EP_AP_GATEWAY_VALUE,DEFAULT_GATEWAY_VALUE,IP_LENGTH)) { - return false; - } - if(!CONFIG::write_byte(EP_AP_PHY_MODE,DEFAULT_PHY_MODE)) { - return false; - } - if(!CONFIG::write_byte(EP_SLEEP_MODE,DEFAULT_SLEEP_MODE)) { - return false; - } - if(!CONFIG::write_byte(EP_CHANNEL,DEFAULT_CHANNEL)) { - return false; - } - if(!CONFIG::write_byte(EP_AUTH_TYPE,DEFAULT_AUTH_TYPE)) { - return false; - } - if(!CONFIG::write_byte(EP_SSID_VISIBLE,DEFAULT_SSID_VISIBLE)) { - return false; - } - if(!CONFIG::write_buffer(EP_WEB_PORT,(const byte *)&DEFAULT_WEB_PORT,INTEGER_LENGTH)) { - return false; - } - if(!CONFIG::write_buffer(EP_DATA_PORT,(const byte *)&DEFAULT_DATA_PORT,INTEGER_LENGTH)) { - return false; - } - if(!CONFIG::write_byte(EP_REFRESH_PAGE_TIME,DEFAULT_REFRESH_PAGE_TIME)) { - return false; - } - if(!CONFIG::write_byte(EP_REFRESH_PAGE_TIME2,DEFAULT_REFRESH_PAGE_TIME)) { - return false; - } - if(!CONFIG::write_string(EP_HOSTNAME,wifi_config.get_default_hostname())) { - return false; - } - if(!CONFIG::write_buffer(EP_XY_FEEDRATE,(const byte *)&DEFAULT_XY_FEEDRATE,INTEGER_LENGTH)) { - return false; - } - if(!CONFIG::write_buffer(EP_Z_FEEDRATE,(const byte *)&DEFAULT_Z_FEEDRATE,INTEGER_LENGTH)) { - return false; - } - if(!CONFIG::write_buffer(EP_E_FEEDRATE,(const byte *)&DEFAULT_E_FEEDRATE,INTEGER_LENGTH)) { - return false; - } - if(!CONFIG::write_string(EP_ADMIN_PWD,FPSTR(DEFAULT_ADMIN_PWD))) { - return false; - } - if(!CONFIG::write_string(EP_USER_PWD,FPSTR(DEFAULT_USER_PWD))) { - return false; - } - - if(!CONFIG::write_byte(EP_TARGET_FW, UNKNOWN_FW)) { - return false; - } - - if(!CONFIG::write_byte(EP_TIMEZONE, DEFAULT_TIME_ZONE)) { - return false; - } - - if(!CONFIG::write_byte(EP_TIME_ISDST, DEFAULT_TIME_DST)) { - return false; - } - - if(!CONFIG::write_byte(EP_PRIMARY_SD, DEFAULT_PRIMARY_SD)) { - return false; - } - - if(!CONFIG::write_byte(EP_SECONDARY_SD, DEFAULT_SECONDARY_SD)) { - return false; - } - - if(!CONFIG::write_byte(EP_IS_DIRECT_SD, DEFAULT_IS_DIRECT_SD)) { - return false; - } - - if(!CONFIG::write_byte(EP_DIRECT_SD_CHECK, DEFAULT_DIRECT_SD_CHECK)) { - return false; - } - - if(!CONFIG::write_byte(EP_SD_CHECK_UPDATE_AT_BOOT, DEFAULT_SD_CHECK_UPDATE_AT_BOOT)) { - return false; - } - - if(!CONFIG::write_string(EP_TIME_SERVER1,FPSTR(DEFAULT_TIME_SERVER1))) { - return false; - } - - if(!CONFIG::write_string(EP_TIME_SERVER2,FPSTR(DEFAULT_TIME_SERVER2))) { - return false; - } - - if(!CONFIG::write_string(EP_TIME_SERVER3,FPSTR(DEFAULT_TIME_SERVER3))) { - return false; - } - return true; -} - -void CONFIG::print_config(tpipe output, bool plaintext) -{ - if (!plaintext)BRIDGE::print(F("{\"chip_id\":\""), output); - else BRIDGE::print(F("Chip ID: "), output); -#ifdef ARDUINO_ARCH_ESP8266 - BRIDGE::print(String(ESP.getChipId()).c_str(), output); -#else - BRIDGE::print(String((uint16_t)(ESP.getEfuseMac()>>32)).c_str(), output); -#endif - if (!plaintext)BRIDGE::print(F("\","), output); - else BRIDGE::print(F("\n"), output); - - if (!plaintext)BRIDGE::print(F("\"cpu\":\""), output); - else BRIDGE::print(F("CPU Frequency: "), output); - BRIDGE::print(String(ESP.getCpuFreqMHz()).c_str(), output); - if (plaintext)BRIDGE::print(F("Mhz"), output); - if (!plaintext)BRIDGE::print(F("\","), output); - else BRIDGE::print(F("\n"), output); -#ifdef ARDUINO_ARCH_ESP32 - if (!plaintext)BRIDGE::print(F("\"cpu_temp\":\""), output); - else BRIDGE::print(F("CPU Temperature: "), output); - BRIDGE::print(String(temperatureRead(),1).c_str(), output); - if (plaintext)BRIDGE::print(F("C"), output); - if (!plaintext)BRIDGE::print(F("\","), output); - else BRIDGE::print(F("\n"), output); -#endif - if (!plaintext)BRIDGE::print(F("\"freemem\":\""), output); - else BRIDGE::print(F("Free memory: "), output); - BRIDGE::print(formatBytes(ESP.getFreeHeap()).c_str(), output); - if (!plaintext)BRIDGE::print(F("\","), output); - else BRIDGE::print(F("\n"), output); - - if (!plaintext)BRIDGE::print(F("\""), output); - BRIDGE::print(F("SDK"), output); - if (!plaintext)BRIDGE::print(F("\":\""), output); - else BRIDGE::print(F(": "), output); - BRIDGE::print(ESP.getSdkVersion(), output); - if (!plaintext)BRIDGE::print(F("\","), output); - else BRIDGE::print(F("\n"), output); - - if (!plaintext)BRIDGE::print(F("\"flash_size\":\""), output); - else BRIDGE::print(F("Flash Size: "), output); - BRIDGE::print(formatBytes(ESP.getFlashChipSize()).c_str(), output); - if (!plaintext)BRIDGE::print(F("\","), output); - else BRIDGE::print(F("\n"), output); -#ifdef ARDUINO_ARCH_ESP8266 - fs::FSInfo info; - SPIFFS.info(info); - if (!plaintext)BRIDGE::print(F("\"update_size\":\""), output); - else BRIDGE::print(F("Available Size for update: "), output); - uint32_t flashsize = ESP.getFlashChipSize(); - if (flashsize > 1024 * 1024) flashsize = 1024 * 1024; - BRIDGE::print(formatBytes(flashsize - ESP.getSketchSize()-info.totalBytes).c_str(), output); - if (!plaintext)BRIDGE::print(F("\","), output); - else { - if ((flashsize - ESP.getSketchSize()-info.totalBytes) > (ESP.getSketchSize())) BRIDGE::println(F("(Ok)"), output); - else BRIDGE::println(F("(Not enough)"), output); - } - - if (!plaintext)BRIDGE::print(F("\"spiffs_size\":\""), output); - else BRIDGE::print(F("Available Size for SPIFFS: "), output); - - BRIDGE::print(formatBytes(info.totalBytes).c_str(), output); - if (!plaintext)BRIDGE::print(F("\","), output); - else BRIDGE::print(F("\n"), output); -#else - if (!plaintext)BRIDGE::print(F("\"update_size\":\""), output); - else BRIDGE::print(F("Available Size for update: "), output); - uint32_t flashsize = ESP.getFlashChipSize(); -//Not OTA on 2Mb board per spec - if (flashsize > 0x20000) flashsize = 0x140000; - else flashsize = 0x0; - BRIDGE::print(formatBytes(flashsize).c_str(), output); - if (!plaintext)BRIDGE::print(F("\","), output); - else { - if (flashsize > 0x0) BRIDGE::println(F("(Ok)"), output); - else BRIDGE::print(F("(Not enough)"), output); - } - if (!plaintext)BRIDGE::print(F("\"spiffs_size\":\""), output); - else BRIDGE::print(F("Available Size for SPIFFS: "), output); - BRIDGE::print(formatBytes(SPIFFS.totalBytes()).c_str(), output); - if (!plaintext)BRIDGE::print(F("\","), output); - else BRIDGE::print(F("\n"), output); -#endif - if (!plaintext)BRIDGE::print(F("\"baud_rate\":\""), output); - else BRIDGE::print(F("Baud rate: "), output); - uint32_t br = ESP_SERIAL_OUT.baudRate(); -#ifdef ARDUINO_ARCH_ESP32 - //workaround for ESP32 - if(br == 115201)br = 115200; - if(br == 230423)br = 230400; -#endif - BRIDGE::print(String(br).c_str(), output); - if (!plaintext)BRIDGE::print(F("\","), output); - else BRIDGE::print(F("\n"), output); - - if (!plaintext)BRIDGE::print(F("\"sleep_mode\":\""), output); - else BRIDGE::print(F("Sleep mode: "), output); -#ifdef ARDUINO_ARCH_ESP32 - wifi_ps_type_t ps_type; - esp_wifi_get_ps(&ps_type); -#else - WiFiSleepType_t ps_type; - ps_type = WiFi.getSleepMode(); -#endif - if (ps_type == WIFI_NONE_SLEEP) { - BRIDGE::print(F("None"), output); -#ifdef ARDUINO_ARCH_ESP8266 - } else if (ps_type == WIFI_LIGHT_SLEEP) { - BRIDGE::print(F("Light"), output); -#endif - } else if (ps_type == WIFI_MODEM_SLEEP) { - BRIDGE::print(F("Modem"), output); - } else { - BRIDGE::print(F("???"), output); - } - if (!plaintext)BRIDGE::print(F("\","), output); - else BRIDGE::print(F("\n"), output); - - if (!plaintext)BRIDGE::print(F("\"channel\":\""), output); - else BRIDGE::print(F("Channel: "), output); - BRIDGE::print(String(WiFi.channel()).c_str(), output); - if (!plaintext)BRIDGE::print(F("\","), output); - else BRIDGE::print(F("\n"), output); -#ifdef ARDUINO_ARCH_ESP32 - uint8_t PhyMode; - if (WiFi.getMode() == WIFI_STA)esp_wifi_get_protocol(ESP_IF_WIFI_STA, &PhyMode); - else esp_wifi_get_protocol(ESP_IF_WIFI_AP, &PhyMode); -#else - WiFiPhyMode_t PhyMode = WiFi.getPhyMode(); -#endif - if (!plaintext)BRIDGE::print(F("\"phy_mode\":\""), output); - else BRIDGE::print(F("Phy Mode: "), output); - if (PhyMode == (WIFI_PHY_MODE_11G))BRIDGE::print(F("11g"), output); - else if (PhyMode == (WIFI_PHY_MODE_11B))BRIDGE::print(F("11b"), output); - else if (PhyMode == (WIFI_PHY_MODE_11N))BRIDGE::print(F("11n"), output); - else BRIDGE::print(F("???"), output); - if (!plaintext)BRIDGE::print(F("\","), output); - else BRIDGE::print(F("\n"), output); - - if (!plaintext)BRIDGE::print(F("\"web_port\":\""), output); - else BRIDGE::print(F("Web port: "), output); - BRIDGE::print(String(wifi_config.iweb_port).c_str(), output); - if (!plaintext)BRIDGE::print(F("\","), output); - else BRIDGE::print(F("\n"), output); - - if (!plaintext)BRIDGE::print(F("\"data_port\":\""), output); - else BRIDGE::print(F("Data port: "), output); -#ifdef TCP_IP_DATA_FEATURE - BRIDGE::print(String(wifi_config.idata_port).c_str(), output); -#else - BRIDGE::print(F("Disabled"), output); -#endif - if (!plaintext)BRIDGE::print(F("\","), output); - else BRIDGE::print(F("\n"), output); - - if (WiFi.getMode() == WIFI_STA || WiFi.getMode() == WIFI_AP_STA) { - if (!plaintext)BRIDGE::print(F("\"hostname\":\""), output); - else BRIDGE::print(F("Hostname: "), output); -#ifdef ARDUINO_ARCH_ESP32 - BRIDGE::print(WiFi.getHostname(), output); -#else - BRIDGE::print(WiFi.hostname().c_str(), output); -#endif - if (!plaintext)BRIDGE::print(F("\","), output); - else BRIDGE::print(F("\n"), output); - } - - if (!plaintext)BRIDGE::print(F("\"active_mode\":\""), output); - else BRIDGE::print(F("Active Mode: "), output); - if (WiFi.getMode() == WIFI_STA) { - BRIDGE::print(F("Station ("), output); - BRIDGE::print(WiFi.macAddress().c_str(), output); - BRIDGE::print(F(")"), output); - if (!plaintext)BRIDGE::print(F("\","), output); - else BRIDGE::print(F("\n"), output); - if (WiFi.isConnected()) { - if (!plaintext)BRIDGE::print(F("\"connected_ssid\":\""), output); - else BRIDGE::print(F("Connected to: "), output); - BRIDGE::print(WiFi.SSID().c_str(), output); - if (!plaintext)BRIDGE::print(F("\","), output); - else BRIDGE::print(F("\n"), output); - if (!plaintext)BRIDGE::print(F("\"connected_signal\":\""), output); - else BRIDGE::print(F("Signal: "), output); - BRIDGE::print(String(wifi_config.getSignal(WiFi.RSSI())).c_str(), output); - BRIDGE::print(F("%"), output); - if (!plaintext)BRIDGE::print(F("\","), output); - else BRIDGE::print(F("\n"), output); - } - else { - if (!plaintext)BRIDGE::print(F("\"connection_status\":\""), output); - else BRIDGE::print(F("Connection Status: "), output); - BRIDGE::print(F("Connection Status: "), output); - if (WiFi.status() == WL_DISCONNECTED) { - BRIDGE::print(F("Disconnected"), output); - } else if (WiFi.status() == WL_CONNECTION_LOST) { - BRIDGE::print(F("Connection lost"), output); - } else if (WiFi.status() == WL_CONNECT_FAILED) { - BRIDGE::print(F("Connection failed"), output); - } else if (WiFi.status() == WL_NO_SSID_AVAIL) { - BRIDGE::print(F("No connection"), output); - } else if (WiFi.status() == WL_IDLE_STATUS ) { - BRIDGE::print(F("Idle"), output); - } else BRIDGE::print(F("Unknown"), output); - if (!plaintext)BRIDGE::print(F("\","), output); - else BRIDGE::print(F("\n"), output); - } - if (!plaintext)BRIDGE::print(F("\"ip_mode\":\""), output); - else BRIDGE::print(F("IP Mode: "), output); -#ifdef ARDUINO_ARCH_ESP32 - tcpip_adapter_dhcp_status_t dhcp_status; - tcpip_adapter_dhcpc_get_status(TCPIP_ADAPTER_IF_STA, &dhcp_status); - if (dhcp_status == TCPIP_ADAPTER_DHCP_STARTED) -#else - if (wifi_station_dhcpc_status()==DHCP_STARTED) -#endif - { - BRIDGE::print(F("DHCP"), output); - } - else BRIDGE::print(F("Static"), output); - if (!plaintext)BRIDGE::print(F("\","), output); - else BRIDGE::print(F("\n"), output); - - if (!plaintext)BRIDGE::print(F("\"ip\":\""), output); - else BRIDGE::print(F("IP: "), output); - BRIDGE::print(WiFi.localIP().toString().c_str(), output); - if (!plaintext)BRIDGE::print(F("\","), output); - else BRIDGE::print(F("\n"), output); - - if (!plaintext)BRIDGE::print(F("\"gw\":\""), output); - else BRIDGE::print(F("Gateway: "), output); - BRIDGE::print(WiFi.gatewayIP().toString().c_str(), output); - if (!plaintext)BRIDGE::print(F("\","), output); - else BRIDGE::print(F("\n"), output); - - if (!plaintext)BRIDGE::print(F("\"msk\":\""), output); - else BRIDGE::print(F("Mask: "), output); - BRIDGE::print(WiFi.subnetMask().toString().c_str(), output); - if (!plaintext)BRIDGE::print(F("\","), output); - else BRIDGE::print(F("\n"), output); - - if (!plaintext)BRIDGE::print(F("\"dns\":\""), output); - else BRIDGE::print(F("DNS: "), output); - BRIDGE::print(WiFi.dnsIP().toString().c_str(), output); - if (!plaintext)BRIDGE::print(F("\","), output); - else BRIDGE::print(F("\n"), output); - - if (!plaintext)BRIDGE::print(F("\"disabled_mode\":\""), output); - else BRIDGE::print(F("Disabled Mode: "), output); - BRIDGE::print(F("Access Point ("), output); - BRIDGE::print(WiFi.softAPmacAddress().c_str(), output); - BRIDGE::print(F(")"), output); - if (!plaintext)BRIDGE::print(F("\","), output); - else BRIDGE::print(F("\n"), output); - - } else if (WiFi.getMode() == WIFI_AP) { - BRIDGE::print(F("Access Point ("), output); - BRIDGE::print(WiFi.softAPmacAddress().c_str(), output); - BRIDGE::print(F(")"), output); - if (!plaintext)BRIDGE::print(F("\","), output); - else BRIDGE::print(F("\n"), output); - - //get current config -#ifdef ARDUINO_ARCH_ESP32 - wifi_ap_config_t apconfig; - wifi_config_t conf; - esp_wifi_get_config(ESP_IF_WIFI_AP, &conf); - apconfig.ssid_hidden = conf.ap.ssid_hidden; - apconfig.authmode = conf.ap.authmode; - apconfig.max_connection = conf.ap.max_connection; -#else - struct softap_config apconfig; - wifi_softap_get_config(&apconfig); -#endif - if (!plaintext)BRIDGE::print(F("\"ap_ssid\":\""), output); - else BRIDGE::print(F("SSID: "), output); -#ifdef ARDUINO_ARCH_ESP32 - BRIDGE::print((const char*)conf.ap.ssid, output); -#else - BRIDGE::print((const char*)apconfig.ssid, output); -#endif - if (!plaintext)BRIDGE::print(F("\","), output); - else BRIDGE::print(F("\n"), output); - - if (!plaintext)BRIDGE::print(F("\"ssid_visible\":\""), output); - else BRIDGE::print(F("Visible: "), output); - BRIDGE::print((apconfig.ssid_hidden == 0)?F("Yes"):F("No"), output); - if (!plaintext)BRIDGE::print(F("\","), output); - else BRIDGE::print(F("\n"), output); - - if (!plaintext)BRIDGE::print(F("\"ssid_authentication\":\""), output); - else BRIDGE::print(F("Authentication: "), output); - if (apconfig.authmode==AUTH_OPEN) { - BRIDGE::print(F("None"), output); - } else if (apconfig.authmode==AUTH_WEP) { - BRIDGE::print(F("WEP"), output); - } else if (apconfig.authmode==AUTH_WPA_PSK) { - BRIDGE::print(F("WPA"), output); - } else if (apconfig.authmode==AUTH_WPA2_PSK) { - BRIDGE::print(F("WPA2"), output); - } else { - BRIDGE::print(F("WPA/WPA2"), output); - } - if (!plaintext)BRIDGE::print(F("\","), output); - else BRIDGE::print(F("\n"), output); - - if (!plaintext)BRIDGE::print(F("\"ssid_max_connections\":\""), output); - else BRIDGE::print(F("Max Connections: "), output); - BRIDGE::print(String(apconfig.max_connection).c_str(), output); - if (!plaintext)BRIDGE::print(F("\","), output); - else BRIDGE::print(F("\n"), output); - - if (!plaintext)BRIDGE::print(F("\"ssid_dhcp\":\""), output); - else BRIDGE::print(F("DHCP Server: "), output); -#ifdef ARDUINO_ARCH_ESP32 - tcpip_adapter_dhcp_status_t dhcp_status; - tcpip_adapter_dhcps_get_status(TCPIP_ADAPTER_IF_AP, &dhcp_status); - if (dhcp_status == TCPIP_ADAPTER_DHCP_STARTED) -#else - if(wifi_softap_dhcps_status() == DHCP_STARTED) -#endif - { - BRIDGE::print(F("Started"), output); - } - else BRIDGE::print(F("Stopped"), output); - if (!plaintext)BRIDGE::print(F("\","), output); - else BRIDGE::print(F("\n"), output); - - if (!plaintext)BRIDGE::print(F("\"ip\":\""), output); - else BRIDGE::print(F("IP: "), output); - BRIDGE::print(WiFi.softAPIP().toString().c_str(), output); - if (!plaintext)BRIDGE::print(F("\","), output); - else BRIDGE::print(F("\n"), output); -#ifdef ARDUINO_ARCH_ESP32 - tcpip_adapter_ip_info_t ip; - tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_AP, &ip); -#else - struct ip_info ip; - wifi_get_ip_info(SOFTAP_IF, &ip); -#endif - if (!plaintext)BRIDGE::print(F("\"gw\":\""), output); - else BRIDGE::print(F("Gateway: "), output); - BRIDGE::print(IPAddress(ip.gw.addr).toString().c_str(), output); - if (!plaintext)BRIDGE::print(F("\","), output); - else BRIDGE::print(F("\n"), output); - - if (!plaintext)BRIDGE::print(F("\"msk\":\""), output); - else BRIDGE::print(F("Mask: "), output); - BRIDGE::print(IPAddress(ip.netmask.addr).toString().c_str(), output); - if (!plaintext)BRIDGE::print(F("\","), output); - else BRIDGE::print(F("\n"), output); - - - if (!plaintext)BRIDGE::print(F("\"connected_clients\":["), output); - else BRIDGE::print(F("Connected clients: "), output); - int client_counter=0; -#ifdef ARDUINO_ARCH_ESP32 - wifi_sta_list_t station; - tcpip_adapter_sta_list_t tcpip_sta_list; - esp_wifi_ap_get_sta_list(&station); - tcpip_adapter_get_sta_list(&station, &tcpip_sta_list); -#else - struct station_info * station; - station = wifi_softap_get_station_info(); -#endif - String stmp =""; -#ifdef ARDUINO_ARCH_ESP32 - for (int i=0; i < station.num; i++){ -#else - while(station) { -#endif - if(stmp.length() > 0) { - if (!plaintext)stmp+=F(","); - else stmp+=F("\n"); - - } - if (!plaintext)stmp+=F("{\"bssid\":\""); - //BSSID -#ifdef ARDUINO_ARCH_ESP32 - stmp += CONFIG::mac2str(tcpip_sta_list.sta[i].mac); -#else - stmp += CONFIG::mac2str(station->bssid); -#endif - if (!plaintext)stmp+=F("\",\"ip\":\""); - else stmp += F(" "); - //IP -#ifdef ARDUINO_ARCH_ESP32 - stmp += IPAddress(tcpip_sta_list.sta[i].ip.addr).toString().c_str(); -#else - stmp += IPAddress((const uint8_t *)&station->ip).toString().c_str(); -#endif - if (!plaintext)stmp+=F("\"}"); - //increment counter - client_counter++; -#ifdef ARDUINO_ARCH_ESP32 - } -#else - //go next record - station =STAILQ_NEXT(station, next); - } - wifi_softap_free_station_info(); -#endif - if (!plaintext) { - BRIDGE::print(stmp.c_str(), output); - BRIDGE::print(F("],"), output); - } - else { - //display number of client - BRIDGE::println(String(client_counter).c_str(), output); - //display list if any - if(stmp.length() > 0)BRIDGE::println(stmp.c_str(), output); - } - - if (!plaintext)BRIDGE::print(F("\"disabled_mode\":\""), output); - else BRIDGE::print(F("Disabled Mode: "), output); - BRIDGE::print(F("Station ("), output); - BRIDGE::print(WiFi.macAddress().c_str(), output); - BRIDGE::print(F(") is disabled"), output); - if (!plaintext)BRIDGE::print(F("\","), output); - else BRIDGE::print(F("\n"), output); - - } else if (WiFi.getMode() == WIFI_AP_STA) { - BRIDGE::print(F("Mixed"), output); - if (!plaintext)BRIDGE::print(F("\","), output); - else BRIDGE::print(F("\n"), output); - if (!plaintext)BRIDGE::print(F("\"active_mode\":\""), output); - else BRIDGE::print(F("Active Mode: "), output); - BRIDGE::print(F("Access Point ("), output); - BRIDGE::print(WiFi.softAPmacAddress().c_str(), output); - BRIDGE::println(F(")"), output); - BRIDGE::print(F("Station ("), output); - BRIDGE::print(WiFi.macAddress().c_str(), output); - BRIDGE::print(F(")"), output); - if (!plaintext)BRIDGE::print(F("\","), output); - else BRIDGE::print(F("\n"), output); - } else { - BRIDGE::print("Wifi Off", output); - if (!plaintext)BRIDGE::print(F("\","), output); - else BRIDGE::print(F("\n"), output); - } - - if (!plaintext)BRIDGE::print(F("\"captive_portal\":\""), output); - else BRIDGE::print(F("Captive portal: "), output); -#ifdef CAPTIVE_PORTAL_FEATURE - BRIDGE::print(F("Enabled"), output); -#else - BRIDGE::print(F("Disabled"), output); -#endif - if (!plaintext)BRIDGE::print(F("\","), output); - else BRIDGE::print(F("\n"), output); - - if (!plaintext)BRIDGE::print(F("\"ssdp\":\""), output); - else BRIDGE::print(F("SSDP: "), output); -#ifdef SSDP_FEATURE - BRIDGE::print(F("Enabled"), output); -#else - BRIDGE::print(F("Disabled"), output); -#endif - if (!plaintext)BRIDGE::print(F("\","), output); - else BRIDGE::print(F("\n"), output); - - if (!plaintext)BRIDGE::print(F("\"netbios\":\""), output); - else BRIDGE::print(F("NetBios: "), output); -#ifdef NETBIOS_FEATURE - BRIDGE::print(F("Enabled"), output); -#else - BRIDGE::print(F("Disabled"), output); -#endif - if (!plaintext)BRIDGE::print(F("\","), output); - else BRIDGE::print(F("\n"), output); - - if (!plaintext)BRIDGE::print(F("\"mdns\":\""), output); - else BRIDGE::print(F("mDNS: "), output); -#ifdef MDNS_FEATURE - BRIDGE::print(F("Enabled"), output); -#else - BRIDGE::print(F("Disabled"), output); -#endif - if (!plaintext)BRIDGE::print(F("\","), output); - else BRIDGE::print(F("\n"), output); - - if (!plaintext)BRIDGE::print(F("\"web_update\":\""), output); - else BRIDGE::print(F("Web Update: "), output); -#ifdef WEB_UPDATE_FEATURE - BRIDGE::print(F("Enabled"), output); -#else - BRIDGE::print(F("Disabled"), output); -#endif - if (!plaintext)BRIDGE::print(F("\","), output); - else BRIDGE::print(F("\n"), output); - - if (!plaintext)BRIDGE::print(F("\"pin recovery\":\""), output); - else BRIDGE::print(F("Pin Recovery: "), output); -#ifdef RECOVERY_FEATURE - BRIDGE::print(F("Enabled"), output); -#else - BRIDGE::print(F("Disabled"), output); -#endif - if (!plaintext)BRIDGE::print(F("\","), output); - else BRIDGE::print(F("\n"), output); - - if (!plaintext)BRIDGE::print(F("\"autentication\":\""), output); - else BRIDGE::print(F("Authentication: "), output); -#ifdef AUTHENTICATION_FEATURE - BRIDGE::print(F("Enabled"), output); -#else - BRIDGE::print(F("Disabled"), output); -#endif - if (!plaintext)BRIDGE::print(F("\","), output); - else BRIDGE::print(F("\n"), output); - - if (!plaintext)BRIDGE::print(F("\"target_fw\":\""), output); - else BRIDGE::print(F("Target Firmware: "), output); - BRIDGE::print(CONFIG::GetFirmwareTargetName(), output); - if (!plaintext)BRIDGE::print(F("\","), output); - else BRIDGE::print(F("\n"), output); -#ifdef DEBUG_ESP3D - if (!plaintext)BRIDGE::print(F("\"debug\":\""), output); - else BRIDGE::print(F("Debug: "), output); - BRIDGE::print(F("Debug Enabled :"), output); -#ifdef DEBUG_OUTPUT_SPIFFS - BRIDGE::print(F("SPIFFS"), output); -#endif -#ifdef DEBUG_OUTPUT_SD - BRIDGE::print(F("SD"), output); -#endif -#ifdef DEBUG_OUTPUT_SERIAL - BRIDGE::print(F("serial"), output); -#endif -#ifdef DEBUG_OUTPUT_TCP - BRIDGE::print(F("TCP"), output); -#endif - if (plaintext)BRIDGE::print(F("\","), output); - else BRIDGE::print(F("\n"), output); -#endif - if (!plaintext)BRIDGE::print(F("\"fw\":\""), output); - else BRIDGE::print(F("FW version: "), output); - BRIDGE::print(FW_VERSION, output); - if (!plaintext)BRIDGE::print(F("\"}"), output); - else BRIDGE::print(F("\n"), output); -} diff --git a/esp3d/data/index.html.gz b/esp3d/data/index.html.gz deleted file mode 100644 index 8ed88ab79d1d30af47a66936586e2f73312d9416..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 79777 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

m8loqmgwA>d!jA-&c(w4>0eF1EP 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�IBkpQfN}ll$-$%GXIO{Q z487GdPR8DZ^qWLsjBImL(=|m6w}^X@!@gC7lnc=pyUNJEYy&D`!*0V}`gHIGpNtMp zW^{<&0?N=STX|~q9JkdU#bI<7_u9F)kY3Ie=fg0z7B{|NFb~7%);EW-zj{olmPQOV z#5eWW)eR-i_@+Do&@+q91wC)CcKaIt3d|=TI+(P;^&y>}1MH5W}HtEr-GfVZ)*52qS`^ zwEezb4xi{p!N$%vkA`%5sw|_xx!C5&=m~9w?}MG#(quQSxaqN#G~;gb28)X^xmV&X zq6#X@xi{$Q+s)W`K=e?dhG>d1a)HNnxZjpYVO3RzM=?x zQ#m~dtQCVRVzYWrus9h;$|RiT_=O>CG2JpoveN+-UBkV(bi3LvAj zT615;W?^4-7eOWiH;%`ch(8-&cirv{urMT(7!>S=QYO(7x4ZF@tqG#0-oQa<^jm^Yo zPgm|FE|a@oPC1Z9?0Qi=CZ2)%VsDBV{76h@=PD!i;}WDJt&xm?Y-*4G&|x(^_Je=O zMIZmD3jNniC?;*@PlaN_@B1p9bV(#8NuG_wq~})vd5EEA5!PYSy2F=NCD4qBOdfN9 zN3Il3P==I;`@J}*66?<5s7m^*R!)G9K9_(0*Y8phllV{CJ8KDH?p7JG7m^^4TPSv3 z%Emk@q<~D=qk0*4(T2O24_wsqVUMz2pdp{VVJuJ|Bl(`!57Xw zDi2@i<(L(laH*5cy7s+WlA(`QB;3a768y!@Z8~WNySSm9&s?Haq5Ng&iW{}P?Qm?z zk)LGi%F|eQ&XF{Z+Oy(^5qjW)kF*fvIM$K*Ohti^N4@CohPfa|N`f5e<1?q<*5yxM j{^2+Milpq}kAL{hZM%L)|GXKt%^&|CR_+xG+4cqi=UA1l literal 0 HcmV?d00001 diff --git a/esp3d/data/macrocfg.json b/docs/Files/macrocfg.json similarity index 100% rename from esp3d/data/macrocfg.json rename to docs/Files/macrocfg.json diff --git a/docs/Readme.txt b/docs/Readme.txt new file mode 100644 index 00000000..cc5623dd --- /dev/null +++ b/docs/Readme.txt @@ -0,0 +1,9 @@ +Commands.txt list all ESP commands +wconfig.txt list all parameters for SD file config +flash.docx explain how to flash +Files directory contain all files needed by ESP3D + - index.html.gz // main ui file (mandatory) + - 404.htm // custom 404 page (optional) + - favicon.ico //custom browser esp3D icon (optional) + - macrocfg.json //macro command file (optional) + \ No newline at end of file diff --git a/docs/flash.docx b/docs/flash.docx new file mode 100644 index 0000000000000000000000000000000000000000..0f4fcd44ac2d1ee7f59589ef2474fbd50e601c44 GIT binary patch literal 15814 zcmeIZ1y@~Jvo5@Gch}(V9w0cu-Q6{~ySuv++}$05YjAhB-~_ji^m+SscTV5${(y59 zW2`;)*t2TYnpDmCJhQ4~B|tz?0pI{g002M;fFcR@^92F`qQC$E6aXZ!hM={TgOQbk zj-soLk-Zk3i=_oYE+{ZXHURj2{QqA6gJ+;VK}yD-4>9PR>=mL`1!TpIVIbi)`=(f` z{IZ=+aB0ZP(B$dn98X-LG^aqlBjy{^`O_E-v;UNM@)R&P)ff4B88;eWV#~rY8l$S2 z!TTg(%z$AbGq`*UxS`Lzqv72SrvTzowv<{TQ0KvqBf$0F`ZyUJ;xwv+vo&~kq=yg~ zLA=&}tl5}J0Z_JO&8oLHf$SLR1zEJGcGCI;Lup#8bjsW1$ug)DQGG=pdJH!-w<`n% z64RZlW#OwJ{V$b+k9VuP8_!a6FRA=Zi9B48(-`ijA0teZ$60S;aFflp>Rl^ISZ)&2 zu9bm_j4DU-KTZjx;=S?1!~Q_NIHxpULpj}0q!@68kK=K2#>d_%J<4xfEIW1bN2JJC zknDW*vsF24Ryq?>?RgsQk~;}?_Sr8aFS z+3qO%)ccluy5?70YJmL_f``IXS!gAMHLBiy{0yP=G>LzH`#bxJ!#xxL@b(4*ko`yG z;>Th)UBA1d^m|~!yhpB%osoq-J>9SS|3>Wp;4uB$t4GAGh=cIM2AzX#=nZ+YuRs$` zFRhE_I1~K<2}nHwa)uwvU+(P4BWRUf(cb@gFe)>j?w>x(Rm2TmrKdKRy_l{mvhl^m zvMC%wR&7Wl&Cdi*WW3tU%6gujJ2oMQJA$z+ce^f#pM;0Vn7KMnGjOO=u{8!)3`!w7 zb`0kxqO7%Z@TUq$T59348l0KQIbXw|Dx1zcycRpQ7qs#D;%F$^5QLuf5}iJkh1h^y zq&ejc4Ymct1ZifhemOMTrdjUXjnJD;cvK(_R1Q?=#I=WG28g;gg2Pg->tGev2SPO( zbWisuLH{~>Q=a!d?7zpz(<|$Q%KI;0Kmh<;03?vJwVfgTe+7!6wSlAM`$qR`hx;>V zfZn&c_tF2eukwU$`5uP%Wq$k~K6BL)fQA>`Bb>3dDQwFf>@Z_&T9o z?{>tJ?(|0gc4o|?mMr`e=qpXD(9fN(A>Yg-D@Kto*}Pj@F_3EPN~k9JiP-q`nL67s zJNR-qo`qT}D4^AFNr_A<@$*SC1xqLfpfwj64<-8bj+oUbI~1{o_^a3xI#UHBqU}D{ zu^@RRX@{G3miS$5v`k@^Z6V#1f)0|CkO0|pULdMJ4qLO4CmG3<1x`Z*i#jJaxf-UM5D+;CHRpg`j zo952jI$dYQ16YW4_7EGttx zqkhfXBi0N9&J3%+^RWfQhJ)BMRQQ69{Ve2JMZAbg-#yH~Ip%oOaG1zD0_&gx0Fd7O z?GMNNyGx#^uUY+IL+;ecKIgm7T?8}Nc$L~_qr-i=w}3WW;8^$9rZWw#ZHX1~&EL7# zJmvZc_e6ph7e^z06^)#AmTO92uK@3u36|{*vf}VKwoSy2zu<(z}Jw0=pF0Vt6r;JMrWKjQ6d7Q&?!2na~vGX9l18zRXC^` z)4x@q+Y2*$>rS4BArLJhLYg8-$?+H$3QTqS3(^Z=IQ3+*=IX$gz7~CY^dR;N_ZCN z7?$dvZ>m2C1M`0}A32-_ePDt+NHB{=O)ODr*$y33|C(?@DW(8s)|?S&I^2lc^K{5P z?NxO>d9Fx!D#f)HY#~G}g>R;LoHfo*jAVduLbor3_$q+C1NC^*)s>C4A`H}vU(5Fm z*>2z&L6bITb&x@>j|4Ia+1{*NfSNyQK~bCKT5xyopoCjFC?H@;6iHHUYoyP-e1FC9 zXSSn*^f%T)JvC;!@Vn%(c1dPB5br=czX##HXKQ7uZ0e|wq`?46g6sc4@Hu9uFbEz-!_Kwt52#sQ; z>1&UK^pk)#NI`1`#tXfX_k@ZyXDRgutYfHAEx2)F!9uJBfisX1B}IT8C<}C~WteH~0t)Z*P^N%dnSOHr_vuWY5!4Qr+|!FwqpQeCG~TB6q-gcBYy zZkyKNZryLsG%Y&fDf6W4_6uoDMisCunzM#mPC`wTE2@V4xKS%|)oBE5MwN|2ju69kK3JY1I7!l}ig&J3F zt*(OtCp_MceHe^G$-(5x!Hth^V|d%AL;M5o6B_7 z0$vx;v-vil!>-fQy{eKy&#XZnI=bM1L229I6lXUo_wE9R5AcXafnF;a*bOwYI-@!S-y>)?@$S;Z)n24z0GBkbv}FS zc+D=os233rEK)XYsNl{n{N9qgPGj{d9piqkTq1C7y^N7aqdja>Y%DFR+bG(AH?&Bj z8)#gS?Wpznd!v&Ij_Kx=&*zDdAM*&_KY#XE7t4BbaV*U`Wz2z(bi&}7Y`)a{8h3S~Y{iQt^FqBT=RpzY{zZ$?cLmeajW&S1f+(ig_; zJ|lE8rtz$`hKvsUgYw)+u9dU(ttd*`kjt2>XDW<8{E$n?b2mMn+_!IDDfmXVgP1BO z8dCTX<-fu`c3%(eLXr&tj71O2wG#_kLRSG6?nL zB{kyUW{O*ZIK(N$DlyM5ysF<)w|ndYcncA}MJBy@e?YAGa{tZ2i8;%$jEdQPSJYfA znwco8vPn~?)i*?ggQ^Vnk?oT6~AQecDfh3G}oD<0jslzR3=v;&fO=-m_O0HacrOY_apnPz+RHYQ#O<6^h zvuRw{CV4GqXr<$myxCpM%N{whYXFKhklw2=%5(YCv)wZS*|6vwB*!u_q%I^p4XXZW zG$h1DX_Lq<+ObUzOix%VP#7si`p*)Q&r@ug{Fg|RCb@^H_SD@p%ep2Ui(4Ihc7lkj zt;7r;D#?j37RB@r4$Jy|uZ9OSmYSI9K2EQoC3-19UC zo`d&3LX{22^bUE1g2sA>Q^H(HGyMNND|hv!|;DDfsc z*`$%ssu4dsET+T;(swpf!+ zD}~c%6^w5dnzSgJ%Qr3NiL<=p1Jv897mT)O8LX$_i@sR!#InR`fj3!IEg~P+uc{r# zwis5yLxTLU^Yn)Qp`>i#Y!DU?nUGRuS^LHAyCBJ>D_?x|=^FkmeTAziRR(CvWk7ug zW$b!G93x{CmW+V$^yhDV zWWGfQ?RH)v_R4n)t(2u^HPzcXLRFcBr>Ivq)>m44Ewx(k+f-Y)gxM%ERNUcIP-}pB zg6Nv#FZ{S^?Qr9t092p*7b+()egEuTu|8~;#CL1^)v0N|oK@2!^mQa-tU|hI#=@vp zH5c6Q1CITD!?L-7{ZcnhOh5aA!kBYW8+d!{CGUEEc4bAJHX$1ir_Xx6JsA$K;(2*#6G6L> z@)a?xG=T3j0oyz|oy10rv7W4EN`EO5;>#+>e}n z4V!pCdwI|Axr;z&cH^9yit2hI*Ho#l9AZ7@`}*<&rv@IX{cYhW zgIyhB(2mRq5+avYLb!}~n9`{5Vgjhs_Rl^s(5Gke$BT~1kA4z7%7=8qc#_moO!>s* zX~yA=X0TqV%15xTP8N0U5RM#W({ACot)fHFV^jejkoQwAIlofis>I@MrzFC8fs_@C z4|OZv8)?c=T{wthigfshsx|B<0X!w7H@anOsMb113v0qr!|)ZS+I>IL6F1%Sv-jAl z2jWeVP#N&XKp^H~p4uvbZR}YE9XeltNTatt!IMU{$y9+inH`3(z#x8NMndasmu^Ps z@~6Zx&=-e8bu3aIWO-=o`A(r|HM+G8&7LrVp~G7l^JGc8lwR$wv^RDeD$oJxT+8j; z0(rQili74ZvP2w%c&#zpw*6em;r{lp-A<83-$^o2%7ALR7QXm-rGD+Qr_x;#3#XWp zm_6UDo%G}r{|E3JPWx?=eoC6iO*s=L1{<54Z^m%Qnw~;REFm_~QtoRrLISC=@TB4` z0lm3cmH8EyllRo_vlhpKAr-jDWm@=)TWFs$vRI*+K9^47n%aM+PWz^oTA?`{;%8OW zTV5H+$=uY6^c__=SR<#Ft>$Bb|1iv)Zgn*o3oE2LVf7VN#sljYjuYL_z?RNG@>XdF zU@(q|u(o^*d8XYao{Ft95(Y;yh}02qU>`SK!sf(R)zeOJY`DVXM^3O|7WdZOQRw%O zxUZ3Axl*HOD9OnsCgoPXuqLPDU)e6-4%kQs4RU~0Nvw(JqxTraR|UX5Da0=sK8&ST zXfm=x9oyXKo$?e_D?rE-&Y>s8!oe{o1_C5l$f@7#P{!QkpcNJK>cnbl!MiW2#DJU} zv?K-$w##bkB#4)tZds`dJaR)Yg}RZjYeE+XH@)ymvt{^5HJww!vUN7Cq%~F~Tlzmr zv|dG~bT8SCO+%XODHoZ39Y(i;mM8Rgr4EH?RT{BM;Oe3x+oKmvw8MOxP@H;#TIDGR zT?XONgoBB2D6IcPr`VSRU4V4+1dI)#z(t_G>4i~9SiI@C{EV?H`_}Z)#4M#gNHBl7 zh!7d|mKY66;5M5k^^hx2_0viljaU*A6Ot0LN}=)z(nk`D;xC(}>nop7`HR!d;}U`V zxv;#?+>`k8WZ6INdDv5_)!Z%P-WPFwNFU2i&tvoq0{mLrLaiIK#dOl-d^t&d<#diAugDQ&<r@qQT87&XAUr(O)0`|WN71sdy4)Iu^-OZ`4q*-Odp-5h2 zit8TcK#(C2JkW~NIqcB?>(<7VdmRjTKjl$}{u`mTH*#<=vof*&wXM}FtJ$xxA$pxl zzWE1DB)W#QE)HR-L9ZB|Gf{~5Z8zj3Bd-|qf4 zbhsOlNaknlcTWXPmZFkN_S_8BxqdLC#4rVZi7nTCN!F~3*WUGdlk99+Si?wANDkhR5I5T$$>#1g(b`c zuP-519Euixpww{Nh5+r1rz7YQsZHCSzBEYBDx+Uk51I$EQby<)Kk`L|1@dy%KVt)W zd(4!6VPHxlPOG^>_NHziy4eIR9~o^P8@aC-A(^lzOK0Zm zvkT1`l}F;GTeWu50)detEa-1;-K8fxu`q$+(86;AW;SqWHzc6x^{IWOek7K_#o+|? zu#lf|q5WaO86^D@dALvWegcnXv6M8 zVQu`%7S`U{e6HQDWTV~t(yk}U_eLde0GYVmqe(GNnBvF1MO($ox{P>;t#ZV>)vW=q zYennrYt_{ynqgpw-Q4&#oH8mY9okMT4s{c|AWO~rg~pbeWuUk^|5zXE8ixbPV5=&N<$dq!~5{-IfPQ}9Yp8o7OTiC+&lxUM}yLQC-p%s_T zn26`fY4U?tLOl5q)mr335`FTKh4DvOFs(B+wjapB3`ad?kO zeYFyNE6DQ)(xAZLu02$#CFUZ9iAh+wv|i9-EV=@kvd|=V51Z=eaKN5gtHM=vWh8>Z2LCW)25DP| z%h2eH_T<&&c~M^k@`+{BkeVcO;goXDs$i?fRtoea+TMewboH+P>7T7w-~3ufZsn&!;tll}KoX?5LJBtX*)VF-lJ?U_lY1m(g33@| zj1&@9!RQOVaO4H*OcqD3!@zRk+MX*gM|on9k2YF3ow80!Z}d9L$c+cl+^(@W&wUNYeA1|bNv?-?XM93hJ;DWFz++pk9v>ZmkiWDk+8FozQW&Dj1$FS z>0SoJ4&qCM*z*b$^=0H(A|)jx@ZjI}vRQ2!i9`Hbebs zh*dG-*Mh0(Fp{(b6MK-TL}>O!Lr$)~S=?Ce8H|h6G zjY1bdEn?Jp!m*k|{oldDIf(YdO`>ZvM>M_yblQ(m1qZ~|8@@=Le_j1coSKJ5-?L;% zq5uH)pZ`vK2UiOtdlfSWQ(xqfC*M$#H=_H;Ui^E0V?DfB1NIed3b(3yba0hFhxt?glSNI0<3Nt#Z#sQXl;5SbC#`?e< z&A9ambuC?R7tO9h2kDc2@w(1(VPf!?N}6sx=sh8p=1DMm5BBNct(gMppac7oa7tuv zW6wjrC}(_2VnDh-Eo)3pN&Y*^qT-~SYXu!Hezkg`;WWijxfR3kR zYz{yD6tGQDO?DQ*tl2_&QSd>?13|7r99PwHzz_+E2pW%q3fEvi4YUyhU4PtOYNxU`FY~Go|B_K)o(CC)!c7hpiWHji2o8ImWVR0+2-}Jh(iDvuZB3 zUDcG0tzOr)X}m&2zQk~`pWf@cQU_?|7Ce{?ZyyeM-3OHlHG=d*=$}Z9_yqe51;}oo z0O3pf&h92>ac$|iCttyWf&o<3Xgn%7@D8Dd%qhii)@#4BpS3eNr}l)mgsNU#JX})V zy1+_uvYRmbLLns6T;Ovr80Cr>PJHdHIH-NIP`l4yxVw1HayLAb%anio}APGt$l(QDtlRx82kIa5HDxO_~{2A|`fmH8BM95xi6nBi;yOT1slC z*;>(-yd;(pyarskv*LmPI}uut1TJ$Rm9yf0m6km8@p-(c$Udd-xkzsQii_0rH#tgF zDOQuQ$F<4^+)Fht$SYIxh#d{3PB?0G&OZ_gsiuz}3|k}(=%h2CqxqcC3*6brz2R~z zGF@yKRDc{EUc@uJBD(Yuq^qHesZ%{z(=T-GY6Cw#H1;;GI;&ZfFVbVlMZWMh*CZ6d z7TDqSK7My!Dg?)c6&_XclfuqeKY^lrOHa;5P;Yz4??z3uk%uLRb6ui&=Cbe5ifIe7 z!A=$BS%9<$16Hzdo>C1c*47fI76MR^4LRjl1CNj&(x-=adLS8uz1E^-Qf6g$S!kM! z3_hDiSFz2kcIzm^%DYN6d~xpf#J6_x(gqQCOEFim0pe%oZwrBWAc=ebc7f!H-4q4V z)gpJL$b}ApKgTx(A1u_ZpSO~WmjHbV$3im=FAMgi*mo}S3#(7P*d4k1b>D`sV>(c+ zgYCRx(sgk+$fTdB$)UFsw^CM4FkFU+uq*7=1Su4=scBx&NM5ed1Ibh7=ZH2|9=L2P zJXw%p4eD8d`B3yev&pIp35aeC@UGN7`iPO)$1huGg4sq9OmWPmN?Or0B;Y^L`g>s$D1wQkw-+Rt+mZgs5O39SEk z%B~dORFpJ|D@wIZs5F^kHFPPl?mx9Y5?TYx^6p9jj-}VlV_t{SeG0zAffXeUrvvh( z5Wr+p+oAZHg@SRU<`ke*4gLPcdYukr*1(8#A2CD+e<{|L`@`bkciYy6HQ=T{yuV<5 zOU~x(A5(FZ1E6|0R5bmU(ep#U8x8hrFomcVB~rq4w;+*6rhxkQuvqt z|ND$AuM(Us^?1r%-OTa}BFmm*?KWW#`Sb=6$N@2fc-O*(>s7~;SO+_Rj?vEYS%@N( zhU##5vzlVGiNHY#1YON{4ql4iajj2N!VyIj(#C_9bzuzn+*?4I2jT1aiBj!g77b?MlaIrd*~9vD;Y&!Zdfua-eV!! z8sLpA0Vjc=$kEC!1>SALBWpWX0kf}$i3r0JW3{9$o!<9iiC1#9<}H;vQ(5^n9Y(PC zYj_%NB4f?9`Y~h#QkAd-#8h~G)CcF~4x&?So+zv{WLVQ_L*Hzic*kY zceE4*D=kWQ!qka73V{`SGf~%PcLg9~@9K)dL!uRfUeS7V~m}nBlkWkZC{R znRTA(ZX?|A^#`?VFn&e>U5UX49EN{e>fA}&m(kkF%dC>o&Xrjj?u}p(4-e7mxjSna z#(3guO8XzK;4l$+XhoW;#ul-at}!2|wlTiVPD5!e9xpb`rXdB(?JwyPEwIyKYDU-UZ4{#Q9^JQU4VW@vHC18i@DEL8N>QlnqzcRoyJSx~ zaAH%jbl^v!rTO)uroq#|>_=-vVyV`p3aIE}9-^Jf2W40451Vo-mvDX6%xUH0-1Hbr z%IDOMyh(vm@#h=Dzufz2<2ayqVat-w!;ayB;m#0w<9`|$;KAo}c%wji8m_ze^aHW>$#bD5!DpC=@Fnr}GVJM=feT=07#WQ(01`;mn2Jkv%gU zu{1!ya%8e+nGu@rc&!p}OzY}eoCI+V$@7|XF+AVJB_NX`g_bJULUs!wSUMfC?}O@j zO_|nM(kP~pb5zsA!w*Rt=~Nn_w1(TWi<@|)E-Lk3AzEk%5m)`7#S3xg71MQ%qJQ<^ z{jU(P$e{_!{T`-?ZH+6=(s(ttDIR%95DyesI@hdp1hozOHCrs542{0*m6OS$=xcC{7qA5)!m4;n(j+R1ie^Qk%nJsrAsS91pK|N4VA$c5%d>Fo&Q==)6yevgF z=qa8NQXWPHghneb&hkiNt>UYxP0>vAf(2!(eiaYL9L$f_sAD-U@bQVm!R?0zEmp)#RTX7U3ml%P)VO)!eX8=Rox8N`3l(xvt=Ux@cQ?CY8pLJXUX}&SgJ= zxtjt-@L`keNXNSjO&1ot0@$^g9D?w)Y5Bv(NGRKfH#aDd9gJ|4ED`&eSKUd)X#C8u?L{s`u5j}r29Hqug^O>*RFA$;53YUd6_=uT6KPE!Zh+4kuqkQW^=MO|}tL;^A0HBnF>t;SF~rFp*@gUjdn zB7%)t!gxc2%s{SPuMCC^j#B}4KCKvBqo|JWoS|uOwGl}58F+j!iC#kS(!8dSia4+* zxApXfA_D`;L8!H&%k5*|g0qkNNpzWcHA=sf;?jkL^3D?yt$y)@+fN&~kdwRYG*5e= zzj%TOT_7@qfiKFZeFGX!SJi~X)buWP@?>XyQ!u-OLX<2Tx`1k+GnO}+Qy2GYZx;cj z#weIq0OL5P5h4a6nSkkLI0LRUq2X@tL?%N;orEj6A26Vt1|6UJbFhu?rrHo@P?N<= zVw=pEM*fAq6%jft&+7UhPc)(Q!M+6&cj(Z4O=iuv7^&z3&y4Uj{ z>wq`e)Lt6}*bTV?YyiP!XM3{+H4%o8NR-W0rYfKYaL}(*kgDN12GBMM7@e z*=#}^)BT7O=67`g?TSUX`_(*$aB##~J~7^uB4bx;bGS=>rZx$7!B;qRFh)S3{X zW!S>R_285>$zIqDHJyn*CsB&YiP$^qp_zk=OIEOQ8fE59v3vSW;%22pnVp$57-nO6 zA_cp%Jqu;0;6Z&I)Mg9i6H8e&TbrRpGT)wO12 z5Yco8?^>PC`-T)NM!qDv@w5>Kd{$L}IN}lPi@~764VK&DH&?}k6-Y0wI0pY9HuE8F zDs^<3+I6%0W{s^Gz_BtAt50j9092*+4%X5}kb|9FdLm>gMvTROZ<^Kb)|6l5tf64+9-`PTdfugANfr;N?APq-={o)5AkwZN zh{mx|>F=zjC+h!6ZNP0O(9go-s*0B3`1v|aVm8bPK;UsQguuqw?&B-eU_F&3J-PCU zbvp&&`hqU9tuC1lWWZ1L?}`cehGbudG%{>7JLqvsxOGweR!E}j)h}raKw}k zX1C6EFJ7e!I2Fsah5RY0(==II_uV=P#%z*+M7^yRo!}&{Eifp%yh7x?%$A1%DZR8- z@43w~2$~m!h^}0)1?QVx4sj_MRojL3Du2(9Go{TSjmzSpPEukO<~F=8Ucq5k2xk_J z8|i+j3-rv(LYJ~g*bJf$brr<4I$6@hpv_t(0*$fF;FTeNJb^5N*Evbf8F$-!3K#ET zzs+=iI5Wx(HW|1@&O~cV7;0VN*{~u?g!F|$7k*sUk7R(Jobm_{)O6FRcvFl@RaiW2 zTDGp8TsvLzWj)c6wo14hz6OUnD+oqSk|DT!dDv4=8P>pCYuSQC5Im<1;a*(h$thEn zLob)zp5aMgYJDJK_4z={2{Ii+Tt4qYQG6B6*|mx4@*iLHG*0sSprNF4`_W0fcr+Z6 z1b+4sV1o4@VIQPH0C^j)ucOX+R8H{WxiKVh7QkDwx7Sx0E7zTl(~NS)Ly@=2GOtv8 z;qqvML%4VOpgU@QDMrkfR6YrIj2^-dMa|BEV2U}pJ^PGv|@ z6#YRJ7L`po@!-(XzQPScOLgl)OIeQkz3$9^U!1onoJ7L}Hy3V8AS^CRVM>cqI*uYQ zDyEBp$NZ2-TGFUuz+?Po?R}s*EIZE z7vYtl_PvDR%%j*8DoXy)Pw8=UK4WKIw4o$nta#qWMB9y5I)!6dNNg~qPEw54p4n$K zpfh(;z55cf&AMF(Xu>$FQGlwJ&Q}YC)O6hsCM}f!w-1bRNu9At7KxBGQrA*s1a*s0 zd;5#a3VC;pXWk^IA(&iR+Ro>by$l=W_dXS?lzFcleKKnJ$0!P8m@A1iOTC==FB!S+ z5tkRecA@Ra{Eo_E1I`sp0lCj6%T$+gzPo&SY$IX0E6Tx= zseBVNMXyzkpc>6D3LN;Rf2=;#C~t=ZN5`%R^#PIayZD?#LzO9p%=p*CfphmI*|qw5 zadO(h=br`r`0XsT`99ut5TkejedDM&@w=z-drDL<@%wLnYKZW}P0UfH2dVCmQr<$jCFyHbW2;X0#}EI`3sPR=uGW7sSr7mK@$XDl&&K9| ziR^p8{^!b2kh0Er&(EnGd-JWOlhSO-6vkWn<^fy(ybkL2DDJqQbU+^(B~_1%tGtAk-^2@b!Q3NayuSS%4O zW_&6=$UdU5kEIp7RMJT5xgz^E4O|c8aaU>`)u-*-P0K}q!+<1wn}p~L+3Vz-tyax3 zx$hIEDVqD*|D;tkj1a%1G^^*&;8GwZTj<;d~?D!TRmA>fS#tRT0w|JeY`yJ;KQYUF2-V@#!Lt^w`qiUAhD;+HP4aX-{HO)%9 z*8v>Py?gnCWD@Upum7*gMId0>_uTBiH>&>W1Al)0OWUff#6K1MvtRB{!C#-P?~nXj z_uTJ-|7;@qyWskJE#?1TOVRI|e((DDOPBNeIlzDG0r_40_wvoZ#82OQNd6H2y_oZN z6~C9s{H0#P9O|T;Ttb1_0vO d|7QDtmU~$Vuy;2D0ASz$px!;Ti1XLC{|{;7MGgP} literal 0 HcmV?d00001 diff --git a/embedded/out.h b/embedded/out.h new file mode 100644 index 00000000..89d14862 --- /dev/null +++ b/embedded/out.h @@ -0,0 +1,319 @@ +/* + File Generated with bin2c Conversion Tool v0.14.0 - Windows - [FINAL]. + Free for any use. + Compiled on Jan 1 2017 at 05:41:46. + DO NOT MODIFY THIS FILE!!! +*/ +/* + ut.h +*/ + +const unsigned char a[4862] = { + 0x1F, 0x8B, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0xED, 0x5C, 0x7D, 0x93, 0xDA, 0x46, + 0x93, 0xFF, 0x2A, 0xB2, 0x52, 0x36, 0x70, 0x2B, 0x40, 0x12, 0xAF, 0x8B, 0x16, 0xF2, 0x24, 0xB1, + 0x7D, 0xF1, 0x95, 0x13, 0xBB, 0xBC, 0xEB, 0x7B, 0xAE, 0x2A, 0x4E, 0xB9, 0x84, 0x34, 0x80, 0xCE, + 0x42, 0xD2, 0x49, 0xC3, 0xEE, 0x62, 0xC2, 0x77, 0xBF, 0xEE, 0x79, 0x91, 0x46, 0x42, 0xB0, 0xEC, + 0x26, 0x79, 0xF2, 0xFC, 0x91, 0x60, 0x23, 0x98, 0x99, 0xEE, 0xE9, 0xE9, 0xE9, 0xFE, 0x75, 0x4F, + 0x0F, 0xCE, 0xD5, 0x8A, 0xAE, 0xC3, 0xD9, 0xD5, 0x8A, 0xB8, 0xFE, 0xEC, 0x2A, 0xA3, 0xDB, 0x90, + 0xCC, 0xB0, 0x65, 0xB7, 0x88, 0x23, 0xDA, 0x5E, 0xB8, 0xEB, 0x20, 0xDC, 0x4E, 0x32, 0x37, 0xCA, + 0xDA, 0x19, 0x49, 0x83, 0x85, 0xD3, 0x5E, 0x67, 0x6D, 0x4A, 0xEE, 0x69, 0x3B, 0x0B, 0xBE, 0x92, + 0xB6, 0xEB, 0xFF, 0xEF, 0x26, 0xA3, 0x13, 0xCB, 0x34, 0x9F, 0x3B, 0xED, 0x3B, 0x32, 0xFF, 0x12, + 0xD0, 0x23, 0xBD, 0x8C, 0x1D, 0xB6, 0xC2, 0xD7, 0xE4, 0x7E, 0x3F, 0x8F, 0xFD, 0x6D, 0x69, 0x0A, + 0xFD, 0x47, 0x12, 0xDE, 0x12, 0x1A, 0x78, 0xAE, 0xF6, 0x33, 0xD9, 0x10, 0xDD, 0xC8, 0xBF, 0x1B, + 0xDF, 0xA5, 0x81, 0x1B, 0x1A, 0x8A, 0x0C, 0x0A, 0xAF, 0x7E, 0x72, 0xEF, 0x84, 0x41, 0x44, 0xDA, + 0x2B, 0x12, 0x2C, 0x57, 0x30, 0x57, 0xA7, 0x6F, 0x8F, 0x07, 0x23, 0xAB, 0xDF, 0x73, 0xBC, 0x38, + 0x8C, 0xD3, 0xC9, 0x37, 0xBD, 0x5E, 0xCF, 0x99, 0xBB, 0xDE, 0x97, 0x65, 0x1A, 0x6F, 0x22, 0xBF, + 0x2D, 0x5A, 0x17, 0x8B, 0xC5, 0xBE, 0xE3, 0x01, 0x1F, 0x17, 0x88, 0xD3, 0xDD, 0xDA, 0x4D, 0x97, + 0x41, 0xD4, 0x4E, 0x19, 0x0F, 0x77, 0x43, 0x63, 0x47, 0xB4, 0x84, 0x64, 0x21, 0x1A, 0x12, 0xD7, + 0xF7, 0x83, 0x68, 0xC9, 0x5B, 0xAC, 0x01, 0xCC, 0x2B, 0x5B, 0x38, 0x15, 0x36, 0xED, 0xA9, 0x3B, + 0x0F, 0xC9, 0x6E, 0x1E, 0xA7, 0x3E, 0x49, 0x27, 0xA6, 0xC3, 0x3F, 0xB4, 0xB3, 0xC4, 0xF5, 0x60, + 0x20, 0x34, 0xAC, 0xDD, 0xFB, 0xF6, 0x5D, 0xE0, 0xD3, 0x15, 0x53, 0xCA, 0xBE, 0xC3, 0xC6, 0xB7, + 0xF9, 0x30, 0xE2, 0xEF, 0x8A, 0x2E, 0x41, 0x3A, 0xB1, 0x92, 0x7B, 0x2D, 0x8B, 0xC3, 0xC0, 0xD7, + 0xBE, 0xF1, 0x7D, 0x5F, 0x4A, 0x35, 0x8F, 0x29, 0x8D, 0xD7, 0x13, 0x1B, 0x35, 0x49, 0x81, 0x6C, + 0x15, 0x50, 0xC2, 0x66, 0x21, 0x93, 0x28, 0xBE, 0x4B, 0xDD, 0x44, 0xCA, 0x36, 0xB1, 0xD7, 0xEB, + 0x3D, 0x5D, 0xED, 0xD8, 0x9E, 0xB8, 0x61, 0xB0, 0x8C, 0x26, 0x28, 0xBF, 0x98, 0x78, 0x46, 0x71, + 0x1B, 0x66, 0x34, 0x9D, 0x51, 0xDF, 0x38, 0x68, 0x5A, 0xE5, 0x4D, 0xCC, 0x36, 0xCA, 0xA3, 0xF2, + 0xA6, 0xD5, 0x4E, 0x4E, 0x35, 0x3E, 0xBE, 0x15, 0xB7, 0x24, 0xC5, 0x9D, 0x0C, 0x85, 0x08, 0x34, + 0x4E, 0xA4, 0x6A, 0xE0, 0x63, 0x65, 0x8D, 0x55, 0xA5, 0xD4, 0x08, 0x59, 0xD7, 0xB7, 0x3A, 0xEC, + 0x3B, 0x10, 0xBB, 0xAE, 0x6F, 0xB5, 0xAB, 0xD5, 0xF4, 0xA1, 0x14, 0x8F, 0xE2, 0x26, 0x76, 0x48, + 0xEC, 0xB5, 0x0D, 0xDB, 0x24, 0x68, 0x32, 0x9A, 0x06, 0x89, 0x22, 0xF8, 0x24, 0xA2, 0xAB, 0x76, + 0xBC, 0x68, 0xD3, 0x6D, 0x42, 0x9A, 0xB1, 0xEF, 0xB7, 0x76, 0x35, 0xB6, 0x7A, 0x89, 0xAF, 0xFD, + 0x3F, 0xD6, 0xC4, 0x0F, 0x5C, 0xAD, 0xB9, 0x06, 0x03, 0xE0, 0x7C, 0x47, 0x43, 0xD0, 0x79, 0x6B, + 0xA7, 0xD8, 0xB1, 0x68, 0x1F, 0xA0, 0x61, 0xD4, 0x10, 0x5C, 0x5E, 0xDA, 0xB5, 0x04, 0x97, 0xA3, + 0x23, 0x04, 0x96, 0x6D, 0x9A, 0xB5, 0x14, 0x96, 0xC5, 0x49, 0x3A, 0x91, 0x7B, 0xAB, 0x9A, 0xAD, + 0x10, 0xD9, 0xF3, 0xBC, 0x8A, 0xC3, 0x98, 0x55, 0x77, 0x31, 0xC1, 0x58, 0x32, 0x70, 0x63, 0x44, + 0x1C, 0xB0, 0xDA, 0x88, 0xD4, 0x78, 0x29, 0xF3, 0x5D, 0xAE, 0xD0, 0xD4, 0xF5, 0x83, 0x4D, 0x36, + 0x19, 0x82, 0x91, 0xD5, 0x38, 0x81, 0xBB, 0x4B, 0xE2, 0x2C, 0xA0, 0x41, 0x1C, 0x4D, 0x52, 0x12, + 0xBA, 0x34, 0xB8, 0x25, 0x8E, 0x1F, 0x64, 0x49, 0xE8, 0x6E, 0x27, 0xF3, 0x30, 0xF6, 0xBE, 0xE4, + 0x0E, 0x81, 0xE8, 0xA3, 0x31, 0xF7, 0x65, 0x3E, 0xE1, 0x13, 0x2F, 0x4E, 0x5D, 0x46, 0xC8, 0x64, + 0x28, 0xE4, 0xDF, 0x77, 0x5C, 0x0F, 0xF9, 0xEC, 0x0A, 0xC4, 0xA8, 0x91, 0xD0, 0x34, 0x4D, 0x39, + 0x50, 0x73, 0x0D, 0x77, 0xB2, 0x88, 0xBD, 0x4D, 0x06, 0xCF, 0x55, 0x0C, 0x36, 0xBF, 0x53, 0xC1, + 0x26, 0x71, 0x23, 0x12, 0xEE, 0x0E, 0x65, 0xAF, 0x07, 0xA7, 0x23, 0xFE, 0x5F, 0x56, 0x06, 0x82, + 0x9F, 0x44, 0xDD, 0x79, 0x7C, 0xDF, 0xCE, 0x56, 0xAE, 0x1F, 0xDF, 0x4D, 0x4C, 0x0D, 0xA9, 0xF0, + 0x6F, 0xBA, 0x9C, 0xBB, 0x4D, 0xD3, 0xC0, 0x57, 0xC7, 0x1C, 0xB4, 0x9C, 0x73, 0x06, 0x09, 0x49, + 0xDB, 0x0C, 0xA1, 0x73, 0xAD, 0x21, 0xB8, 0x89, 0x0E, 0x34, 0x76, 0x68, 0xDB, 0x1D, 0x6A, 0xF4, + 0x34, 0xE2, 0x0E, 0xF0, 0x25, 0x57, 0x20, 0x1A, 0x95, 0x35, 0x01, 0x12, 0x70, 0xD3, 0x90, 0xAB, + 0xEB, 0xA1, 0x6E, 0x8A, 0x3E, 0x34, 0xA3, 0x9A, 0x2E, 0xA1, 0xC9, 0x8A, 0xF7, 0x86, 0xEE, 0x1C, + 0x94, 0x2D, 0x2D, 0x20, 0x88, 0x18, 0x2E, 0x71, 0x43, 0x28, 0x43, 0x70, 0xC5, 0x98, 0x70, 0x15, + 0x2C, 0xBA, 0xDC, 0x71, 0x0C, 0x1B, 0xE1, 0xF6, 0x32, 0x43, 0x09, 0xA2, 0x45, 0x2C, 0xF7, 0xB3, + 0x07, 0xC6, 0x3F, 0x86, 0x2D, 0x5D, 0xC4, 0xE9, 0xBA, 0x8D, 0x9E, 0x91, 0xC6, 0xC5, 0x64, 0x7C, + 0x16, 0x3E, 0x03, 0x0B, 0x1C, 0x02, 0x0E, 0x7B, 0xFD, 0x22, 0x64, 0xA0, 0x19, 0x6B, 0x96, 0x2D, + 0x27, 0x3B, 0x37, 0x94, 0x0D, 0x06, 0x83, 0x63, 0xD6, 0x52, 0xB4, 0x06, 0x6B, 0x77, 0x29, 0x1D, + 0xEA, 0xC0, 0x86, 0xD0, 0x2F, 0xCF, 0xB2, 0xA1, 0x20, 0xCA, 0x08, 0xD5, 0x8E, 0x18, 0xC9, 0xA8, + 0x6C, 0x4A, 0x0F, 0x8E, 0x6D, 0xC7, 0x6D, 0x9A, 0x42, 0xF8, 0xE6, 0x0E, 0xAA, 0x5A, 0x80, 0x46, + 0xDC, 0x8C, 0x80, 0x6E, 0xDB, 0xF1, 0x86, 0x6A, 0x1D, 0x6B, 0x90, 0x19, 0x05, 0xDF, 0x83, 0xBE, + 0xB2, 0xC2, 0xB9, 0xAB, 0xED, 0xCA, 0xF6, 0x34, 0x1C, 0xBA, 0x0B, 0x72, 0xE9, 0x00, 0x05, 0x6A, + 0x12, 0x02, 0xEE, 0x13, 0x96, 0x66, 0x98, 0xD0, 0x39, 0x96, 0x1D, 0x96, 0x69, 0x1B, 0xD6, 0x68, + 0x60, 0xD8, 0xBD, 0x9E, 0xD1, 0x19, 0xB6, 0x84, 0x0C, 0xA8, 0xEB, 0xA4, 0xE2, 0xCC, 0xDC, 0x47, + 0xE6, 0x34, 0x3A, 0x66, 0x77, 0xEA, 0x60, 0xB3, 0x64, 0x66, 0x7D, 0xD3, 0x74, 0x94, 0x10, 0xED, + 0x91, 0x88, 0x92, 0xB4, 0x1A, 0x35, 0xD7, 0x81, 0xEF, 0x87, 0x84, 0x27, 0x60, 0xF1, 0xC6, 0x5B, + 0xB5, 0x11, 0x76, 0x40, 0x9F, 0x6B, 0x37, 0x0A, 0x92, 0x4D, 0xC8, 0x40, 0xCC, 0x39, 0xDE, 0xE3, + 0x6D, 0xD2, 0x0C, 0x54, 0x94, 0xC4, 0x01, 0x63, 0x7E, 0xA6, 0xC5, 0xB0, 0x7D, 0x4B, 0xDC, 0x14, + 0x24, 0x72, 0x4E, 0xA4, 0x19, 0x8F, 0xB4, 0xE7, 0x1A, 0x13, 0x5C, 0xC7, 0x5F, 0xDB, 0x9B, 0x0C, + 0x93, 0x25, 0x12, 0x12, 0x8F, 0x72, 0x71, 0x70, 0xAD, 0x07, 0x8D, 0xD5, 0x06, 0xA6, 0xF3, 0x76, + 0x92, 0xC2, 0x32, 0xD2, 0xED, 0x69, 0xB4, 0xEE, 0xF5, 0x46, 0xEE, 0x7C, 0x54, 0xC1, 0x20, 0x9B, + 0x0C, 0x7D, 0xB7, 0x5F, 0xE2, 0x22, 0x10, 0xDD, 0x28, 0xB5, 0x71, 0x68, 0x2F, 0x35, 0x31, 0x94, + 0x2F, 0x35, 0x4D, 0x6A, 0x28, 0x27, 0x87, 0x94, 0x07, 0xF1, 0xA1, 0x46, 0x58, 0x7B, 0x3C, 0x34, + 0x2F, 0xCD, 0x8A, 0xB0, 0x96, 0x6D, 0xCF, 0xFB, 0xE6, 0xDE, 0x73, 0x13, 0xDC, 0x54, 0x89, 0xC1, + 0x2C, 0x8D, 0x1A, 0x2B, 0x29, 0xA9, 0xB0, 0xB2, 0x71, 0x01, 0xCA, 0xA3, 0xD1, 0xC8, 0x39, 0xC8, + 0x02, 0xDD, 0x10, 0x4C, 0xAC, 0x04, 0xF2, 0x35, 0xC1, 0xF5, 0xB4, 0x51, 0x1C, 0x6C, 0xA5, 0xE0, + 0xDA, 0xCE, 0x36, 0x9E, 0x47, 0xB2, 0xAC, 0x26, 0x9F, 0xF1, 0x17, 0x0B, 0xD3, 0x1F, 0x57, 0x23, + 0xC1, 0x90, 0x5C, 0x7A, 0xC3, 0x3C, 0x84, 0x78, 0xA3, 0x61, 0xCF, 0x97, 0xAC, 0x7C, 0x37, 0x5A, + 0x82, 0xB6, 0x6A, 0xA0, 0xCF, 0xF6, 0x89, 0x4F, 0x2A, 0x9C, 0xC8, 0xDC, 0xF3, 0x7C, 0x4B, 0x72, + 0x72, 0x2F, 0xFB, 0xFD, 0xBE, 0xBD, 0xEF, 0xAC, 0xDC, 0xAC, 0x4D, 0xD2, 0x14, 0x20, 0xA7, 0x0C, + 0xDB, 0x65, 0x5A, 0x3E, 0xFA, 0xCF, 0x06, 0xC4, 0xA3, 0xD2, 0xD4, 0x62, 0xDA, 0xB8, 0xDF, 0x1B, + 0xF4, 0xFA, 0x4F, 0x46, 0x32, 0x74, 0xCD, 0x6F, 0x3C, 0x32, 0xEE, 0x8F, 0x7B, 0x8F, 0x91, 0xB1, + 0x4A, 0x5B, 0x92, 0x59, 0x88, 0xDB, 0xE6, 0x61, 0xB6, 0x46, 0xD3, 0x62, 0xF3, 0x4F, 0xEA, 0x9A, + 0xEF, 0xF1, 0xBF, 0x46, 0xD7, 0xB5, 0xF2, 0xD4, 0x6A, 0xDB, 0x9E, 0x0F, 0xFA, 0xB6, 0xF7, 0xFB, + 0xB4, 0x3D, 0x1C, 0xCD, 0xAD, 0xE1, 0xF8, 0x69, 0xDA, 0xE6, 0xB4, 0x15, 0xA9, 0x6B, 0xF5, 0x2D, + 0x7D, 0x04, 0x61, 0x45, 0x78, 0xC8, 0x49, 0x3C, 0xF1, 0x2F, 0xC1, 0x8C, 0x16, 0x55, 0xB7, 0xEB, + 0xF7, 0x16, 0x3D, 0x57, 0x65, 0x52, 0xC2, 0x3E, 0xD1, 0xA4, 0x00, 0x98, 0x68, 0x51, 0x90, 0x8F, + 0xB7, 0x4C, 0x0E, 0xC9, 0x26, 0x07, 0x64, 0xE7, 0xC0, 0x9E, 0x77, 0xD9, 0x33, 0x6D, 0xAF, 0x22, + 0xE6, 0x68, 0x68, 0x79, 0xD6, 0x25, 0x13, 0x33, 0x58, 0x2F, 0x77, 0x22, 0x96, 0xAD, 0xDC, 0xA8, + 0x9A, 0x12, 0x0F, 0xEB, 0xF0, 0x8A, 0x27, 0xE0, 0x9C, 0x56, 0x88, 0x50, 0x83, 0x25, 0x26, 0xBE, + 0x2A, 0xF3, 0x9A, 0x20, 0xE2, 0x5F, 0xEE, 0x78, 0x20, 0x38, 0x93, 0xF4, 0xF4, 0xCA, 0x7B, 0xA6, + 0x48, 0x3F, 0xE4, 0xD8, 0x87, 0x56, 0xFA, 0xD7, 0xAF, 0x2B, 0x04, 0xD1, 0x20, 0x43, 0xF8, 0x22, + 0x0D, 0x82, 0x1D, 0xA6, 0xF2, 0xD6, 0x89, 0xB0, 0xB1, 0x45, 0x10, 0x12, 0xF6, 0x9D, 0xBB, 0x6B, + 0x3E, 0xF6, 0xB2, 0x0F, 0xBB, 0x1A, 0x44, 0xC9, 0x86, 0xFE, 0x82, 0xA7, 0xE7, 0x29, 0x8E, 0xFB, + 0x75, 0x32, 0x91, 0xCB, 0xC2, 0xAF, 0xED, 0x4D, 0x12, 0xC6, 0xAE, 0xDF, 0x9E, 0x6F, 0x20, 0x9A, + 0xFD, 0x9D, 0x97, 0xFD, 0x6B, 0xF3, 0x32, 0xE7, 0xA4, 0x9B, 0x0F, 0xE6, 0x9E, 0x79, 0x10, 0xBA, + 0xFB, 0xC3, 0xF9, 0xD8, 0x77, 0x1F, 0xB5, 0xA9, 0xC2, 0x2A, 0xFE, 0xDE, 0xDA, 0x7F, 0x9F, 0xAD, + 0xED, 0x59, 0x73, 0xD3, 0xAF, 0x9E, 0xF4, 0xAD, 0xF9, 0xD0, 0x1F, 0x0F, 0x1E, 0xB7, 0xB5, 0x1C, + 0xC0, 0xFE, 0xDE, 0xDA, 0x7F, 0xF3, 0xAD, 0xB5, 0x87, 0x97, 0xEE, 0xDC, 0xDB, 0xE7, 0x40, 0x5D, + 0x82, 0xF3, 0x32, 0x7A, 0x2B, 0x68, 0x5E, 0x4A, 0x05, 0x04, 0x9A, 0x8B, 0x0A, 0xD3, 0x22, 0x8E, + 0x41, 0xA9, 0x27, 0x0A, 0x4C, 0xAC, 0xFE, 0xF2, 0xB4, 0x1A, 0xD3, 0x41, 0x9D, 0x17, 0x0D, 0x0E, + 0xC3, 0x24, 0xDF, 0xAB, 0xBE, 0x92, 0x34, 0xF4, 0xF0, 0xA5, 0x92, 0x2A, 0x9D, 0xBD, 0xFE, 0xE5, + 0xD8, 0x9F, 0x57, 0x54, 0x3F, 0x30, 0x9F, 0x3B, 0xB2, 0x6E, 0x0A, 0xD2, 0xCA, 0x9D, 0xC2, 0xCF, + 0x60, 0x3B, 0x6B, 0x5E, 0x66, 0xCC, 0x92, 0x20, 0xD2, 0xEC, 0x4C, 0xC3, 0xCD, 0x74, 0x53, 0x2D, + 0x88, 0x16, 0x41, 0x04, 0x96, 0xB0, 0xFF, 0xC7, 0x17, 0xB2, 0x5D, 0xA4, 0xEE, 0x9A, 0x64, 0x1A, + 0x0E, 0xD9, 0x99, 0xCF, 0x77, 0xCC, 0x5C, 0x30, 0x63, 0x9D, 0xA4, 0x31, 0x75, 0x29, 0x69, 0x9A, + 0xAD, 0x3D, 0x16, 0xAD, 0x0E, 0x3B, 0x7A, 0x43, 0x00, 0xD3, 0x65, 0x6B, 0xFF, 0x97, 0x68, 0x70, + 0x1D, 0xFB, 0x6E, 0x51, 0xFF, 0x62, 0x46, 0x94, 0x57, 0x63, 0x17, 0xC1, 0x3D, 0xF1, 0x9D, 0xAF, + 0xED, 0x20, 0xF2, 0xC9, 0x3D, 0x56, 0xDC, 0xCC, 0xA2, 0x10, 0xCC, 0x78, 0x61, 0x7D, 0xD9, 0x61, + 0x25, 0x62, 0x70, 0x5A, 0x68, 0x30, 0x1D, 0xA5, 0x38, 0x27, 0x35, 0x88, 0x9F, 0xD1, 0x5C, 0x16, + 0x21, 0x24, 0x1A, 0xAC, 0xA8, 0x56, 0x5B, 0x89, 0x3D, 0x6C, 0x55, 0x93, 0x90, 0x7E, 0x4B, 0x88, + 0xCA, 0xF2, 0x7F, 0x70, 0xC1, 0x5D, 0xB1, 0xA6, 0x52, 0x75, 0xD1, 0x32, 0xCB, 0x95, 0xC7, 0x52, + 0x55, 0x52, 0xED, 0x14, 0x45, 0xFE, 0x63, 0xB4, 0xA2, 0xFB, 0x18, 0x39, 0x5E, 0x0B, 0xE4, 0xE6, + 0x24, 0x0B, 0x13, 0x4A, 0x7D, 0x16, 0x4B, 0x50, 0x16, 0x42, 0x81, 0x59, 0xCA, 0xA5, 0xEC, 0x96, + 0x73, 0x58, 0xEB, 0xE6, 0x70, 0x58, 0xBA, 0xA8, 0x9A, 0xD4, 0xA8, 0xE3, 0x9B, 0x05, 0xC1, 0x97, + 0xD4, 0x03, 0x56, 0x72, 0x15, 0x2B, 0xB1, 0xC5, 0x84, 0x4E, 0x9E, 0xFC, 0xE2, 0xAB, 0x8E, 0x8B, + 0x8D, 0xAF, 0x63, 0xC5, 0xD9, 0x47, 0xAA, 0xAF, 0x54, 0x9E, 0x5C, 0xE0, 0x4B, 0x8A, 0x57, 0xAE, + 0x40, 0x9B, 0x42, 0x3A, 0xD9, 0x5B, 0x35, 0xF1, 0xA1, 0x94, 0x5E, 0x18, 0x4D, 0xBF, 0x33, 0x20, + 0xEB, 0xC7, 0x2F, 0xE5, 0x50, 0x9C, 0xDF, 0xB9, 0xDB, 0x27, 0xEE, 0x6D, 0xCA, 0xD6, 0xC8, 0xFB, + 0x06, 0x63, 0xF5, 0x2A, 0x26, 0xF3, 0x52, 0x42, 0x22, 0x0D, 0xB2, 0x7D, 0xA0, 0xCF, 0x0B, 0xD7, + 0xA3, 0xE1, 0xE8, 0x28, 0x3D, 0xBB, 0x57, 0xDC, 0x5F, 0x75, 0xF9, 0x4D, 0xEE, 0x55, 0x97, 0xDF, + 0xEB, 0xB2, 0xDB, 0xA6, 0x2B, 0x3F, 0xB8, 0xD5, 0x58, 0xFB, 0x54, 0xCF, 0x4D, 0xC8, 0x9D, 0xC3, + 0x62, 0x37, 0x94, 0x08, 0xE7, 0xE3, 0x97, 0x33, 0xA6, 0x3E, 0xFB, 0x6F, 0xAB, 0x63, 0x6B, 0x2F, + 0xA2, 0x79, 0x96, 0x38, 0xFC, 0xFD, 0xAA, 0x0B, 0xE4, 0xB3, 0x2B, 0x1E, 0x4D, 0x67, 0x57, 0x2B, + 0x7B, 0xF6, 0x86, 0x6A, 0x19, 0x21, 0xEB, 0x4C, 0xDB, 0xC6, 0x1B, 0xCD, 0x8F, 0xB5, 0x28, 0xA6, + 0xDA, 0xCA, 0xC5, 0x8B, 0x90, 0x68, 0xAB, 0x31, 0x87, 0xEF, 0xE0, 0x4D, 0xB2, 0x16, 0x91, 0x80, + 0xAE, 0x48, 0xAA, 0x34, 0x75, 0x96, 0x5F, 0x0D, 0x2D, 0x09, 0xB1, 0xC0, 0xAB, 0xF1, 0x90, 0xAF, + 0x05, 0x54, 0x8B, 0x53, 0xF8, 0xE2, 0x03, 0x9C, 0x21, 0xC3, 0x54, 0x5B, 0x04, 0xE9, 0xFA, 0x0E, + 0x62, 0xA5, 0x16, 0x2C, 0x80, 0x05, 0x1E, 0x84, 0xB1, 0xE4, 0x06, 0x2B, 0xB2, 0x67, 0x38, 0xA1, + 0xE7, 0x46, 0x30, 0x04, 0x14, 0x03, 0x78, 0xA3, 0x01, 0x7B, 0xA2, 0x4D, 0xB4, 0x2B, 0x57, 0xF3, + 0x42, 0x37, 0xCB, 0xA6, 0x7A, 0x7E, 0x8A, 0xD0, 0xB5, 0x55, 0x4A, 0x16, 0x53, 0x7D, 0x45, 0x69, + 0x92, 0x4D, 0xBA, 0xDD, 0x25, 0xC8, 0xB2, 0x99, 0xC3, 0x89, 0x7A, 0xDD, 0x0D, 0x37, 0x5E, 0x9B, + 0x7F, 0xED, 0xBE, 0xBA, 0x7E, 0xDF, 0x7B, 0xD9, 0xFE, 0xE7, 0xAB, 0xEF, 0x3F, 0xBE, 0xD1, 0x67, + 0x67, 0x0F, 0xBD, 0xEA, 0xBA, 0xA0, 0x61, 0xA9, 0x11, 0xD4, 0xAE, 0x98, 0x9D, 0x81, 0xB0, 0xAE, + 0x05, 0xFE, 0x54, 0xBF, 0x7E, 0xFF, 0xE6, 0xF5, 0xEB, 0x6B, 0xFD, 0xB0, 0x5B, 0xDE, 0xA3, 0xE8, + 0xB3, 0xD7, 0xD0, 0xBA, 0xD2, 0x5E, 0x43, 0x60, 0xCC, 0xB6, 0x19, 0x25, 0x6B, 0xA1, 0xE9, 0x03, + 0x02, 0xDC, 0x44, 0x60, 0xC4, 0x52, 0x28, 0x8D, 0xA5, 0x50, 0x3A, 0x46, 0x53, 0x3E, 0x0F, 0x4B, + 0x9F, 0x78, 0x1C, 0xD7, 0xB5, 0x08, 0xC2, 0xC8, 0x54, 0x5F, 0x6F, 0xB1, 0x31, 0xFB, 0xE5, 0x57, + 0x5D, 0x5B, 0x6F, 0x42, 0x1A, 0x24, 0xB8, 0xF1, 0xF2, 0x93, 0x3E, 0xD3, 0x04, 0x27, 0xA9, 0x31, + 0x1A, 0x69, 0x4A, 0x85, 0x52, 0x17, 0x33, 0xF0, 0x54, 0x8C, 0xCF, 0x51, 0xCA, 0xCE, 0x74, 0x50, + 0xBC, 0x17, 0x06, 0xDE, 0x17, 0x58, 0x23, 0x89, 0x7C, 0x9C, 0xAA, 0xD9, 0x72, 0x74, 0xED, 0xD6, + 0x0D, 0x37, 0x40, 0xF7, 0x91, 0x8D, 0xD5, 0x67, 0x25, 0x13, 0x4A, 0xD2, 0x78, 0x99, 0x62, 0x45, + 0x43, 0x58, 0xE1, 0x6D, 0x90, 0x05, 0xF3, 0x20, 0x0C, 0xE8, 0x76, 0xB2, 0x82, 0x7C, 0x8C, 0x44, + 0x52, 0xF4, 0x24, 0x5D, 0xF2, 0x29, 0xD9, 0x07, 0xB0, 0xFC, 0xA9, 0x0E, 0x86, 0x0D, 0x8B, 0xEF, + 0x4A, 0x16, 0x60, 0xD3, 0x29, 0xFF, 0x7B, 0xA0, 0xF7, 0xE3, 0xAA, 0xE3, 0x97, 0xD7, 0x57, 0x14, + 0xA8, 0xA8, 0xAF, 0x31, 0x87, 0x99, 0xEA, 0xE6, 0xF3, 0x5C, 0xA9, 0xE7, 0xA9, 0xA2, 0xB4, 0xEE, + 0x1F, 0xE2, 0x35, 0x24, 0x86, 0x7E, 0xB3, 0x81, 0xB7, 0x99, 0x0D, 0xA3, 0xE1, 0x86, 0x61, 0x43, + 0x51, 0xC3, 0x07, 0xB2, 0x00, 0x69, 0x57, 0x28, 0x39, 0xF5, 0x0F, 0x66, 0x45, 0x39, 0x73, 0x6E, + 0x3F, 0xA4, 0x04, 0x6C, 0xDF, 0x0F, 0xD2, 0x66, 0x4B, 0x57, 0x24, 0x81, 0x93, 0x3C, 0x8C, 0xCC, + 0x6E, 0x97, 0x92, 0xB2, 0x6F, 0x82, 0x4D, 0x33, 0x8C, 0xE3, 0x9F, 0x6F, 0x03, 0x72, 0xF7, 0x7D, + 0x0C, 0x1A, 0xC2, 0x03, 0x76, 0x1F, 0xFF, 0xC0, 0xF8, 0x14, 0xEC, 0x40, 0x83, 0xB6, 0x81, 0xAE, + 0x6D, 0x51, 0x77, 0xBA, 0xA4, 0xEE, 0x29, 0xD4, 0x36, 0x7C, 0x4E, 0x61, 0x90, 0x0D, 0x8F, 0x2D, + 0x7B, 0xC0, 0x2E, 0x86, 0x53, 0x5D, 0xA4, 0x79, 0x7A, 0xB7, 0xE0, 0x83, 0x43, 0xB7, 0x8C, 0x9D, + 0xE0, 0x63, 0x0D, 0x0A, 0x3E, 0xF8, 0xF9, 0x01, 0x3E, 0x98, 0x8F, 0x23, 0x1F, 0x8B, 0x0B, 0x64, + 0xC3, 0x23, 0x4F, 0x6E, 0xA1, 0x75, 0x2C, 0xBE, 0xDE, 0x09, 0x8E, 0x63, 0xD8, 0x6C, 0xC1, 0x84, + 0xE5, 0xC9, 0xFA, 0xEC, 0x02, 0x14, 0x08, 0x3C, 0x40, 0x8F, 0xA0, 0x8A, 0x99, 0x70, 0x11, 0xA1, + 0x53, 0xAE, 0x48, 0x34, 0x17, 0x9E, 0xCC, 0xE5, 0xEA, 0x13, 0x5F, 0x2B, 0xC3, 0xF3, 0x25, 0x98, + 0xF9, 0x26, 0x30, 0x53, 0x73, 0xE9, 0x2A, 0xA7, 0xC4, 0xEB, 0x3E, 0x69, 0xBC, 0x2A, 0x75, 0x17, + 0x6D, 0xA7, 0x2B, 0xED, 0x08, 0x1F, 0x92, 0x82, 0x7F, 0x29, 0xDD, 0xF2, 0xEB, 0xD2, 0xCE, 0x8B, + 0x83, 0x00, 0x1A, 0x21, 0x87, 0x64, 0x66, 0x84, 0x2B, 0xD5, 0x1C, 0x6E, 0xC0, 0xCA, 0x80, 0xF7, + 0x0A, 0xDB, 0x67, 0x3F, 0x83, 0x1F, 0xE4, 0x5F, 0xAE, 0x41, 0x4B, 0xF2, 0x4B, 0xC9, 0x80, 0x2A, + 0x6D, 0x62, 0x45, 0xAC, 0x55, 0x48, 0x2A, 0x26, 0x43, 0x07, 0xC8, 0x71, 0xE2, 0x33, 0xDA, 0x2A, + 0x1B, 0xC7, 0xE3, 0x82, 0x5C, 0xCF, 0x11, 0xDC, 0xE1, 0x91, 0x96, 0xFB, 0x63, 0x06, 0xE9, 0xE6, + 0x26, 0x2B, 0x34, 0x7A, 0xF0, 0x7E, 0x8E, 0x37, 0x16, 0xC8, 0x27, 0x21, 0xFE, 0x23, 0xC3, 0xFD, + 0x07, 0x80, 0xAF, 0xE4, 0xBD, 0x47, 0x71, 0xF0, 0xEE, 0x28, 0x0A, 0x2A, 0xF6, 0xF2, 0x34, 0xE4, + 0x03, 0xDE, 0x07, 0x18, 0xC0, 0x71, 0xEE, 0x10, 0xFD, 0x70, 0x3D, 0xEA, 0x8C, 0x8F, 0x81, 0xBE, + 0xC5, 0x5D, 0x0E, 0x7E, 0xF8, 0xB1, 0x1E, 0xFE, 0x72, 0xCE, 0x70, 0x84, 0x8C, 0xD8, 0xF0, 0x75, + 0xB6, 0xD4, 0x8F, 0xB3, 0x9F, 0x7D, 0x20, 0xB0, 0x79, 0x70, 0x06, 0x8E, 0x96, 0x79, 0xEC, 0xBD, + 0x73, 0x03, 0xDA, 0x81, 0xFF, 0xC0, 0xA9, 0x80, 0x89, 0xC2, 0xCA, 0x83, 0x1C, 0x89, 0x72, 0xCF, + 0xE1, 0x3D, 0x87, 0xC6, 0x5F, 0xDD, 0x74, 0xEE, 0x7E, 0x90, 0x85, 0x26, 0x70, 0xFE, 0xCD, 0xFD, + 0x88, 0xA5, 0x28, 0x65, 0x1B, 0x28, 0x65, 0x2D, 0x75, 0x5D, 0x3C, 0x2D, 0x85, 0x9E, 0x55, 0x6F, + 0xF6, 0x06, 0x44, 0xA7, 0xC1, 0x02, 0x0E, 0xEE, 0x98, 0xAD, 0x40, 0xF0, 0xEF, 0xD5, 0x18, 0x5A, + 0x91, 0x2E, 0xEA, 0x7C, 0x0D, 0x62, 0x25, 0xA5, 0x6E, 0x44, 0x0F, 0x9D, 0x9F, 0xC0, 0x21, 0x69, + 0x26, 0xB3, 0x8F, 0x70, 0xF0, 0x9D, 0x88, 0xE5, 0x55, 0x42, 0xA1, 0x7A, 0x49, 0x20, 0xAD, 0x81, + 0x93, 0xE7, 0x8B, 0xFC, 0x8C, 0xE7, 0xE6, 0xCF, 0xBC, 0x51, 0xA8, 0xBC, 0xB8, 0xF2, 0x2F, 0xD4, + 0xB6, 0x4A, 0xCF, 0x17, 0xE8, 0x3D, 0xF4, 0xDD, 0x01, 0x50, 0x3C, 0x42, 0xA8, 0x44, 0x90, 0xA8, + 0x82, 0xC9, 0xB6, 0x87, 0x85, 0xC3, 0xE0, 0x79, 0x44, 0x97, 0xC2, 0xE5, 0xCB, 0x4E, 0x26, 0x6D, + 0xFF, 0x98, 0xDB, 0x14, 0x71, 0x71, 0x33, 0x5F, 0x07, 0xF4, 0x03, 0xF9, 0xBF, 0x0D, 0x98, 0x1C, + 0x46, 0x33, 0xE1, 0x15, 0xBC, 0xBD, 0x16, 0x3C, 0x20, 0xD1, 0x0D, 0x12, 0x3A, 0x5B, 0x6C, 0x22, + 0x56, 0x6C, 0x01, 0x5F, 0xB8, 0x9D, 0xBB, 0x10, 0x09, 0x77, 0xB7, 0x70, 0x46, 0x06, 0x52, 0xC5, + 0xF9, 0x75, 0x83, 0x4E, 0xBD, 0x4D, 0x8A, 0x45, 0x14, 0x84, 0xEC, 0x0E, 0x1C, 0x3B, 0x03, 0xDA, + 0xD4, 0xBB, 0x7A, 0xCB, 0x88, 0xA6, 0xF0, 0x30, 0x82, 0xA9, 0xE5, 0x80, 0xB6, 0x9A, 0xE4, 0x02, + 0xE9, 0x7C, 0x21, 0x6F, 0x83, 0xC7, 0xD2, 0x86, 0x96, 0xCB, 0xF9, 0x49, 0x57, 0xD8, 0x4C, 0x1B, + 0xDD, 0x86, 0xA3, 0x1D, 0x8F, 0xE8, 0x9F, 0xF4, 0x59, 0x97, 0x79, 0x81, 0xEE, 0x04, 0x57, 0xB4, + 0x13, 0x92, 0x68, 0x49, 0x57, 0x6D, 0xCB, 0x69, 0x45, 0x17, 0x53, 0xFA, 0x4B, 0xF0, 0xEB, 0x05, + 0xCE, 0x7C, 0x64, 0xC6, 0x23, 0x13, 0xEA, 0x17, 0xD1, 0x85, 0xFE, 0xD0, 0xA4, 0xFA, 0x05, 0xE7, + 0x9E, 0xFB, 0xBB, 0x90, 0xC2, 0x08, 0x2E, 0x2E, 0x9C, 0x94, 0xD0, 0x4D, 0x1A, 0x69, 0x6C, 0x5A, + 0xD5, 0x39, 0xF5, 0x7D, 0xAE, 0x48, 0xB0, 0xAF, 0x6C, 0xF5, 0x39, 0x00, 0xC3, 0x51, 0x94, 0x59, + 0x64, 0x13, 0x0D, 0xBB, 0xDF, 0x90, 0x71, 0x9C, 0x7D, 0x96, 0xD9, 0x44, 0x03, 0xB3, 0x09, 0xCB, + 0x1E, 0xE3, 0xDF, 0x06, 0x2C, 0x5A, 0x9D, 0x4A, 0x24, 0x05, 0x8D, 0x81, 0xDD, 0x80, 0x60, 0xDE, + 0xB0, 0xE0, 0x01, 0xE1, 0xBF, 0x31, 0x6C, 0x60, 0xF8, 0xC7, 0x87, 0xE4, 0x3D, 0x28, 0x78, 0x8F, + 0x1A, 0xC2, 0x14, 0x1B, 0x18, 0xD6, 0xE1, 0xE4, 0xEA, 0x3B, 0x0D, 0xAD, 0x3B, 0x13, 0x3A, 0xAB, + 0x72, 0xAC, 0xE7, 0x61, 0x97, 0x79, 0xB0, 0xCC, 0xA0, 0x8E, 0x4B, 0xCF, 0xE4, 0x5C, 0xC6, 0x47, + 0xE4, 0x1A, 0x8E, 0x0A, 0x9E, 0x80, 0xAB, 0x67, 0x49, 0x66, 0x97, 0x79, 0x5A, 0x26, 0x67, 0x8A, + 0x4F, 0xC1, 0x75, 0xAC, 0x72, 0xED, 0x3F, 0x86, 0xA9, 0x7D, 0x59, 0xCB, 0xA4, 0x77, 0xE6, 0x72, + 0xFB, 0x9C, 0x4B, 0xBF, 0xC7, 0x45, 0x1B, 0x71, 0xC9, 0x46, 0x39, 0x4F, 0x85, 0xE5, 0xF0, 0x5C, + 0x9E, 0xC3, 0x3F, 0x81, 0xE7, 0xF8, 0x8F, 0xE0, 0xC9, 0xF3, 0x3F, 0xC5, 0xC0, 0xF1, 0x4C, 0x2F, + 0xED, 0x9B, 0x1B, 0xE9, 0xF9, 0xF6, 0x6D, 0xF7, 0xE1, 0x4F, 0x03, 0x82, 0x33, 0xF8, 0xA3, 0xE6, + 0x4F, 0x1B, 0x3F, 0x8D, 0x8C, 0x9E, 0xF6, 0xD6, 0x36, 0xC6, 0xDA, 0xDB, 0x91, 0x61, 0xF5, 0xD8, + 0xBB, 0xA9, 0xBD, 0xB5, 0xC4, 0x63, 0x6C, 0x58, 0x16, 0x7F, 0x0C, 0x78, 0xE3, 0x10, 0x1E, 0x26, + 0x7B, 0x5C, 0x1A, 0xD6, 0x88, 0xBD, 0x5F, 0xB2, 0x26, 0x1B, 0x86, 0xDB, 0xE2, 0x61, 0x1B, 0xD6, + 0x98, 0x3D, 0xC6, 0xAC, 0x6D, 0x88, 0x5C, 0x87, 0xDA, 0x57, 0x5C, 0x60, 0x1A, 0x7F, 0x81, 0x15, + 0xB2, 0xB3, 0x6A, 0x83, 0xA7, 0xBB, 0x0D, 0xB6, 0xD2, 0xDA, 0x85, 0xF2, 0xB4, 0xE6, 0x33, 0x1E, + 0x10, 0x48, 0x6B, 0xA7, 0x20, 0xC9, 0xC5, 0x94, 0x30, 0xF4, 0x51, 0x71, 0x44, 0x67, 0x29, 0x9E, + 0xA1, 0x03, 0x8E, 0xE8, 0xAD, 0x82, 0x07, 0x9C, 0x65, 0xB1, 0xFC, 0x7C, 0x0D, 0xF9, 0x69, 0xB4, + 0xCC, 0x9A, 0xC4, 0xA0, 0x52, 0x69, 0x80, 0x0B, 0xA4, 0x43, 0xE3, 0xB7, 0xF1, 0x1D, 0x49, 0x7F, + 0x80, 0xDC, 0xA0, 0xD9, 0x02, 0x98, 0xA5, 0x95, 0x16, 0x72, 0x45, 0xBF, 0x6D, 0x5B, 0x13, 0x32, + 0xA3, 0xDF, 0x5A, 0x13, 0xB3, 0x60, 0x8B, 0xB5, 0x3F, 0x97, 0x7A, 0x2B, 0x96, 0x69, 0xB1, 0x0C, + 0x11, 0x45, 0x44, 0xB4, 0x81, 0x5C, 0x1E, 0x00, 0x73, 0xD1, 0x84, 0xA7, 0x7A, 0x12, 0xBC, 0x66, + 0x83, 0x26, 0x9A, 0x7E, 0x41, 0x3A, 0x9C, 0xC0, 0xA0, 0x17, 0xE5, 0x21, 0xBF, 0xA9, 0x5F, 0x6E, + 0x62, 0xEA, 0x86, 0x1A, 0x2F, 0x96, 0x33, 0x22, 0x8A, 0x0D, 0xA7, 0x69, 0x20, 0xC0, 0xFB, 0x2A, + 0x09, 0x44, 0x6C, 0xFF, 0x34, 0xC5, 0x3B, 0xCF, 0xDB, 0x24, 0xBC, 0x4A, 0xAB, 0xE9, 0x6C, 0xE8, + 0xD5, 0x9A, 0x40, 0x1C, 0xD4, 0xD6, 0x41, 0x04, 0x06, 0xD3, 0x60, 0x99, 0x18, 0x47, 0x8C, 0x15, + 0x58, 0xD4, 0xB4, 0x71, 0x09, 0x9F, 0x78, 0x6C, 0x6B, 0xE0, 0x0C, 0x71, 0x4E, 0x0F, 0xB8, 0x0E, + 0x1B, 0xC8, 0x88, 0xC5, 0x21, 0xA2, 0xDA, 0xFF, 0x5C, 0x37, 0xFC, 0xD8, 0xDB, 0xAC, 0x61, 0x0F, + 0x3B, 0x4B, 0x42, 0x5F, 0x85, 0x04, 0x3F, 0x7E, 0xBF, 0x7D, 0x03, 0x7B, 0x27, 0x92, 0xEC, 0x56, + 0x27, 0x88, 0x22, 0x92, 0xFE, 0x78, 0xF3, 0xD3, 0xDB, 0x29, 0x35, 0x50, 0x93, 0x06, 0x6C, 0xF3, + 0x33, 0x35, 0xF8, 0x71, 0x25, 0x47, 0xA5, 0x78, 0x08, 0xB1, 0x87, 0xBE, 0xC1, 0x52, 0xCB, 0xBB, + 0x05, 0x46, 0x45, 0xA3, 0xD4, 0xC7, 0xC3, 0x96, 0xDD, 0x72, 0xD8, 0xEA, 0x68, 0x2A, 0xBD, 0x4C, + 0xBD, 0x57, 0x3E, 0x11, 0xB0, 0x4A, 0x71, 0x17, 0x86, 0x90, 0xA6, 0x69, 0x44, 0x17, 0x56, 0xEB, + 0xE1, 0x38, 0x86, 0x61, 0x11, 0x82, 0x99, 0xE2, 0xAD, 0x45, 0x4C, 0x03, 0xB3, 0x0C, 0x31, 0x25, + 0x01, 0x6C, 0x68, 0xCC, 0xE0, 0x2C, 0x80, 0x09, 0xA9, 0xCC, 0x37, 0xF5, 0x3D, 0x61, 0x77, 0x06, + 0x59, 0x07, 0xE4, 0xA3, 0x4D, 0x69, 0x72, 0x25, 0xD3, 0xAD, 0x5A, 0x75, 0x07, 0x33, 0x69, 0x83, + 0xB2, 0x47, 0x6B, 0xDF, 0x62, 0xC9, 0x00, 0xEA, 0x29, 0x98, 0x9A, 0x10, 0xBC, 0x25, 0x3F, 0xAE, + 0x0B, 0x07, 0xE2, 0x68, 0x4B, 0x6F, 0x5B, 0xA0, 0x57, 0x4E, 0xDF, 0x14, 0xFD, 0x10, 0x75, 0x3B, + 0x78, 0x3A, 0x6D, 0xBD, 0x78, 0xD1, 0x64, 0xCA, 0xBA, 0xF9, 0x30, 0x13, 0x46, 0xC1, 0xB2, 0x6E, + 0x80, 0x18, 0x15, 0x57, 0x14, 0xB8, 0xA9, 0x81, 0x18, 0x6D, 0xF6, 0x89, 0x16, 0x28, 0x63, 0x19, + 0x36, 0xA0, 0x84, 0x61, 0x5B, 0x88, 0x35, 0x36, 0x7E, 0x1E, 0xF2, 0xC7, 0x88, 0xB5, 0x59, 0x88, + 0x0F, 0x6F, 0x2D, 0x5B, 0xBC, 0x5B, 0x1A, 0x0E, 0xB3, 0xCE, 0x40, 0x0C, 0xBC, 0x52, 0xD0, 0xEE, + 0x2D, 0x1E, 0x91, 0xB7, 0xF8, 0x6C, 0x68, 0xF7, 0x36, 0x3C, 0x00, 0x59, 0xB7, 0x36, 0x8B, 0x80, + 0x15, 0x0E, 0xFC, 0x6B, 0x5B, 0x08, 0x6F, 0x35, 0xBA, 0x72, 0x89, 0x39, 0xAB, 0x81, 0xE0, 0x64, + 0x0A, 0x56, 0x3D, 0xCE, 0xCA, 0x32, 0xCF, 0xE0, 0x05, 0x6B, 0x3E, 0xE0, 0xD3, 0xAF, 0xF0, 0xE9, + 0x3F, 0x91, 0xCF, 0xB8, 0xC2, 0x67, 0x7C, 0x06, 0x1F, 0x59, 0x3B, 0x60, 0xF9, 0x13, 0x2C, 0xB3, + 0x71, 0x75, 0xF3, 0x52, 0xE4, 0x6A, 0x9F, 0x44, 0xB2, 0xF6, 0xA9, 0x91, 0x57, 0x48, 0x65, 0x19, + 0x3D, 0xB9, 0x77, 0xC0, 0x7C, 0x5D, 0x51, 0x47, 0x6C, 0x80, 0x1F, 0x33, 0xD0, 0x55, 0xCC, 0x04, + 0xED, 0xEC, 0xA2, 0x01, 0x49, 0xB9, 0x9B, 0x82, 0x2B, 0x4F, 0x3F, 0x83, 0x00, 0xD1, 0x97, 0x52, + 0x56, 0x5D, 0x94, 0x23, 0x67, 0x0D, 0x9C, 0xB9, 0x42, 0xCC, 0x75, 0x2E, 0xF2, 0x61, 0xAC, 0x29, + 0xDE, 0xBC, 0x9C, 0x81, 0x6C, 0x5C, 0xCA, 0x8A, 0x3D, 0x8A, 0xB1, 0x7C, 0x84, 0x34, 0x3B, 0xF3, + 0x79, 0x43, 0x9D, 0xEF, 0x93, 0x28, 0x1C, 0x7D, 0xD2, 0x15, 0x57, 0x7E, 0x09, 0xF1, 0x83, 0x92, + 0x26, 0x43, 0xAA, 0xB2, 0xE8, 0x7A, 0xA3, 0x85, 0x99, 0x26, 0x72, 0x56, 0xD3, 0xC5, 0x92, 0x54, + 0x38, 0x1F, 0xF7, 0x49, 0x7C, 0x43, 0x5F, 0x28, 0xFC, 0x2A, 0x04, 0xBF, 0x0A, 0xAB, 0x7E, 0x15, + 0x0A, 0xBF, 0x9A, 0x56, 0xFD, 0x2A, 0xFC, 0x43, 0xFD, 0x4A, 0xF1, 0xAA, 0x4B, 0x1E, 0x9E, 0x2F, + 0x31, 0xD0, 0x42, 0x90, 0x86, 0x78, 0x2C, 0xDE, 0x06, 0x18, 0x72, 0xFB, 0xE8, 0x45, 0x7D, 0xF4, + 0xBB, 0x01, 0x73, 0x3E, 0x9B, 0x0D, 0xC5, 0x07, 0x06, 0x6A, 0x74, 0xC5, 0x1E, 0xA3, 0x1F, 0xB0, + 0x77, 0x9B, 0x7B, 0x22, 0xF4, 0x9F, 0x17, 0xA7, 0x0B, 0xA3, 0xD2, 0x71, 0x5B, 0xCA, 0x27, 0x00, + 0x2D, 0xDF, 0xFE, 0x3C, 0xAB, 0x39, 0xBC, 0x99, 0x53, 0x51, 0x57, 0x09, 0xF5, 0xCA, 0x76, 0x85, + 0xC5, 0x76, 0x39, 0x72, 0xBF, 0x2A, 0x7D, 0x25, 0xE3, 0x90, 0xF2, 0x3C, 0xD9, 0x56, 0x8E, 0xCF, + 0xFF, 0x24, 0x73, 0x39, 0x1A, 0xEF, 0x8A, 0x9A, 0x54, 0x39, 0xE4, 0x1D, 0x25, 0x60, 0xA5, 0x3A, + 0x75, 0xAC, 0x3C, 0x2E, 0x16, 0x29, 0x89, 0xB0, 0x76, 0xCC, 0x94, 0xE2, 0x08, 0xAF, 0x12, 0x9A, + 0xFA, 0x0F, 0xFC, 0x83, 0xE6, 0x63, 0x17, 0x8E, 0x89, 0x17, 0xB8, 0x99, 0x3C, 0x3D, 0x00, 0x73, + 0x2C, 0xE5, 0x4F, 0x6C, 0x10, 0x81, 0x0C, 0xF6, 0x80, 0xA7, 0x4C, 0xC0, 0x4E, 0xB1, 0x85, 0x31, + 0xB0, 0x81, 0x71, 0xBA, 0x3D, 0xC1, 0x1B, 0xC6, 0x94, 0xD9, 0x2B, 0x05, 0x60, 0x71, 0x52, 0x4B, + 0x52, 0x88, 0x6C, 0x70, 0xB6, 0x7D, 0xCF, 0xCB, 0x35, 0xEC, 0xA2, 0xA1, 0xE0, 0xCD, 0x0A, 0x46, + 0x90, 0x13, 0x80, 0x6A, 0xA3, 0x4D, 0x18, 0x3E, 0x9B, 0x92, 0xCA, 0x3C, 0x9E, 0x64, 0x08, 0xF3, + 0x74, 0xC0, 0x09, 0xD7, 0xCD, 0x96, 0x32, 0x9D, 0x3A, 0x94, 0x45, 0x53, 0x9E, 0x4A, 0x44, 0xE4, + 0x4E, 0xFB, 0x9F, 0x9F, 0xDE, 0xFE, 0x48, 0x69, 0x22, 0x4E, 0xF0, 0x70, 0xA0, 0xD6, 0xBB, 0xCC, + 0x04, 0xBE, 0xE5, 0x3F, 0x85, 0x98, 0xC2, 0x9A, 0x20, 0x6E, 0x42, 0x26, 0x85, 0xAD, 0xBC, 0x6C, + 0x75, 0x41, 0x22, 0x2F, 0xF6, 0xC9, 0xC7, 0x0F, 0x6F, 0x9A, 0xB4, 0x65, 0xB0, 0x4E, 0x96, 0x34, + 0xA8, 0x1D, 0x6A, 0xE2, 0x72, 0x7C, 0x73, 0x45, 0xD1, 0xB6, 0xD5, 0x61, 0xAE, 0xD2, 0x29, 0x2A, + 0x59, 0xA2, 0xAA, 0x15, 0xC2, 0x9A, 0xA3, 0x4E, 0x1C, 0xC1, 0xE2, 0xFC, 0x2D, 0xA6, 0x4A, 0xC4, + 0x5B, 0xE1, 0xAF, 0x0B, 0xA7, 0x79, 0x6E, 0xD0, 0xDA, 0x41, 0xC6, 0xD9, 0x9F, 0x4E, 0xA3, 0x0E, + 0x1B, 0x83, 0xC9, 0x26, 0x69, 0x41, 0x93, 0x6D, 0x9A, 0xD8, 0xC8, 0xD3, 0x2B, 0xA9, 0xE3, 0xFF, + 0xBA, 0x7E, 0xF7, 0x33, 0x20, 0x7A, 0x0A, 0x09, 0x2E, 0x8E, 0xCF, 0x92, 0x38, 0xCA, 0xC8, 0x0D, + 0xB9, 0xA7, 0x27, 0x0C, 0xF6, 0x84, 0x88, 0xA2, 0xDA, 0x66, 0xD4, 0xA6, 0xC4, 0x7B, 0x12, 0xC2, + 0x36, 0x56, 0xCA, 0x23, 0x7B, 0x5C, 0x4D, 0x42, 0xA2, 0xA6, 0xFE, 0x9F, 0xAF, 0x6E, 0xE0, 0x5C, + 0x6F, 0x3C, 0x33, 0x5B, 0xD0, 0x94, 0xC1, 0xF6, 0x34, 0x2B, 0xDB, 0xC5, 0xCB, 0x8C, 0xBB, 0xBC, + 0x8D, 0xD9, 0x37, 0x2C, 0x8C, 0x08, 0xD0, 0x85, 0xED, 0x4C, 0x36, 0xAC, 0x04, 0x20, 0xB3, 0x6F, + 0xC2, 0x7F, 0xDF, 0xE0, 0x77, 0x45, 0xCA, 0xFC, 0x1F, 0x90, 0xBD, 0x1E, 0x5F, 0x17, 0xDE, 0xB6, + 0xB4, 0x3A, 0x3C, 0xA3, 0x3D, 0xE1, 0x7E, 0xE5, 0x7B, 0x20, 0x49, 0x20, 0x4A, 0xA1, 0x80, 0x6A, + 0x5A, 0xA7, 0xD3, 0xD1, 0x2F, 0xF0, 0xF0, 0xF0, 0x1A, 0xAF, 0xFF, 0x9B, 0x66, 0x0B, 0xF3, 0xDD, + 0xFD, 0x9E, 0x8B, 0x74, 0x12, 0x06, 0x64, 0xF1, 0xB6, 0xC5, 0x31, 0x07, 0x8F, 0x0E, 0xE6, 0xB3, + 0xA9, 0xAC, 0xB7, 0xB4, 0x76, 0x4F, 0x96, 0x09, 0x45, 0x3A, 0x01, 0x28, 0x6C, 0xE1, 0xC7, 0x0D, + 0xCE, 0x29, 0x7C, 0xE3, 0x75, 0x9C, 0xAE, 0x5F, 0xBA, 0xD4, 0x75, 0xA2, 0x8E, 0x9B, 0x24, 0xB8, + 0x49, 0x1C, 0x8E, 0xD4, 0x3C, 0xBB, 0x9A, 0x72, 0x52, 0x35, 0xD9, 0xDC, 0xF1, 0x90, 0x89, 0x65, + 0x1D, 0xC3, 0x57, 0x33, 0xF7, 0x8B, 0x50, 0xE0, 0xEB, 0xB5, 0x5E, 0x30, 0xF7, 0x8D, 0x90, 0x87, + 0x4B, 0xA3, 0x98, 0xAF, 0x28, 0x69, 0x1B, 0xA1, 0x71, 0xC8, 0xA0, 0xC5, 0x14, 0xED, 0xD6, 0x78, + 0xB2, 0xE3, 0x0A, 0x4B, 0x7B, 0xFF, 0xEE, 0xFA, 0x06, 0x4F, 0x13, 0x8C, 0x8F, 0xCE, 0x2C, 0xCE, + 0xED, 0x70, 0x15, 0x76, 0x20, 0x32, 0xBD, 0xBA, 0x05, 0x8E, 0x6F, 0x01, 0x90, 0x09, 0x00, 0x2C, + 0x6A, 0x87, 0x17, 0x9D, 0x01, 0x46, 0x8C, 0x67, 0x16, 0x0E, 0x8D, 0x23, 0x1C, 0x5A, 0xF1, 0x38, + 0xE6, 0x5E, 0x53, 0x37, 0xF7, 0xAF, 0xA7, 0xED, 0xD5, 0x13, 0x76, 0x29, 0xF7, 0xB9, 0xF3, 0x2C, + 0x4B, 0x4C, 0xA7, 0x3B, 0x35, 0x3E, 0xAA, 0xA0, 0x81, 0x5B, 0x46, 0x03, 0xE1, 0xBC, 0xEC, 0x5F, + 0x24, 0x34, 0xF5, 0xEF, 0xC0, 0xF9, 0xD8, 0x6F, 0xE1, 0xF1, 0x4C, 0x07, 0x1B, 0xE0, 0x3F, 0x83, + 0x63, 0x36, 0x28, 0x86, 0x79, 0x6D, 0xD4, 0xDA, 0x17, 0x7E, 0xAB, 0x5E, 0x10, 0xFC, 0xA9, 0x9E, + 0xBB, 0xB8, 0x3B, 0xC7, 0x77, 0xF1, 0x92, 0x40, 0x8D, 0x9C, 0x0F, 0x7B, 0x2D, 0x48, 0x79, 0x10, + 0xEB, 0x2A, 0x17, 0x37, 0xDA, 0xB7, 0x7A, 0x4B, 0xCA, 0x7D, 0x7C, 0x13, 0xEE, 0x7E, 0xA7, 0x73, + 0x17, 0xD7, 0x2F, 0x4F, 0x33, 0x02, 0x65, 0xFE, 0x27, 0x90, 0x73, 0xC5, 0x9D, 0x88, 0x49, 0xE7, + 0xAB, 0xFC, 0xC4, 0x58, 0xF1, 0x73, 0x01, 0x39, 0x91, 0xF8, 0x51, 0xD5, 0x54, 0xC7, 0x5F, 0x55, + 0x9D, 0xF6, 0x0C, 0xB6, 0xFD, 0x27, 0x10, 0x4C, 0x22, 0x52, 0x19, 0xC5, 0x8C, 0x07, 0x01, 0x4A, + 0xEF, 0xEA, 0x8F, 0x04, 0x26, 0x8E, 0x4B, 0x05, 0xDD, 0x23, 0xF0, 0x88, 0xFF, 0xFE, 0x03, 0x96, + 0xF2, 0xD7, 0x40, 0x92, 0x6A, 0x61, 0xE7, 0x82, 0xD2, 0xC1, 0xEE, 0x9E, 0xB8, 0x67, 0x3B, 0xC1, + 0x46, 0xDE, 0xB8, 0x3D, 0xCD, 0xC4, 0xFE, 0x10, 0x07, 0x39, 0xC6, 0x44, 0x5E, 0x38, 0x27, 0xF7, + 0x67, 0x7A, 0x97, 0x04, 0xD8, 0x3F, 0xCD, 0x17, 0x0F, 0xC9, 0x15, 0x19, 0x9D, 0x83, 0xBC, 0xAE, + 0x82, 0xE4, 0x88, 0x3B, 0x3A, 0x16, 0x7C, 0x64, 0xED, 0xF1, 0xC5, 0x0B, 0xBD, 0x5F, 0xFE, 0xAA, + 0xF6, 0xFE, 0xF6, 0x9B, 0xC0, 0x7C, 0x81, 0x75, 0x0B, 0x17, 0x6C, 0xDC, 0xD7, 0x5B, 0x86, 0x6E, + 0xC3, 0xE1, 0x56, 0x8E, 0x6A, 0x95, 0x07, 0x79, 0x6E, 0xE4, 0x81, 0x84, 0x18, 0x16, 0x1C, 0x16, + 0x37, 0x70, 0xCE, 0x9E, 0x3A, 0x9E, 0xC3, 0xA5, 0x11, 0x4D, 0x4D, 0xF0, 0xC1, 0x87, 0x1C, 0xDB, + 0x09, 0x3A, 0x58, 0x7B, 0xEC, 0x9B, 0x06, 0x9D, 0x66, 0x84, 0xBE, 0x41, 0x53, 0x01, 0x2D, 0x37, + 0x15, 0x6B, 0x8F, 0x2E, 0xA6, 0xD6, 0xC3, 0x00, 0xC1, 0xB7, 0x26, 0x3A, 0xC7, 0x0E, 0x0B, 0x93, + 0xEE, 0x5B, 0xED, 0xC8, 0x88, 0x66, 0x7D, 0x13, 0x8E, 0xEC, 0x1E, 0x58, 0x74, 0x9A, 0xCF, 0x0F, + 0xA9, 0x7E, 0x18, 0xF3, 0xBB, 0x59, 0xD0, 0x31, 0x9A, 0x0F, 0x1E, 0x31, 0x0C, 0x8B, 0xF4, 0xCA, + 0xE1, 0xB2, 0xA4, 0x3A, 0x0C, 0x95, 0x8F, 0x8A, 0xA5, 0x45, 0x30, 0x15, 0xB8, 0xF1, 0x16, 0x6F, + 0x3A, 0x9B, 0x27, 0xDC, 0xF9, 0x9C, 0x04, 0xFD, 0x38, 0xAD, 0xBC, 0xC4, 0x3E, 0x40, 0x61, 0xF6, + 0xDB, 0x73, 0xA5, 0x24, 0x5F, 0xC9, 0xE4, 0x4F, 0xC9, 0x73, 0x94, 0x27, 0x43, 0x76, 0x61, 0xB3, + 0xA7, 0xE9, 0x95, 0x3B, 0x67, 0xB1, 0x91, 0xE2, 0x50, 0x67, 0x9C, 0x88, 0xBA, 0x75, 0x97, 0xC2, + 0x15, 0x6A, 0xBC, 0x35, 0x65, 0xC3, 0xBE, 0xFD, 0x78, 0xFD, 0xEA, 0x83, 0x7A, 0x62, 0xC3, 0xAC, + 0x04, 0xC4, 0x8B, 0x28, 0x64, 0x2B, 0x17, 0xFA, 0x8B, 0xF7, 0xDF, 0x5D, 0x5F, 0xFF, 0xF3, 0xDD, + 0x87, 0x97, 0xF5, 0x43, 0x28, 0x0E, 0xB9, 0xFE, 0xF8, 0xFD, 0x4F, 0x6F, 0x6E, 0xA6, 0x5B, 0xCC, + 0x2A, 0x83, 0x3A, 0xC4, 0x0F, 0x1E, 0x38, 0xB9, 0xC1, 0xB1, 0x2D, 0x50, 0x8E, 0x6D, 0x2F, 0x5E, + 0x00, 0x84, 0x3F, 0x83, 0x26, 0xE9, 0x9A, 0x65, 0x0B, 0xD8, 0x1B, 0x81, 0x7A, 0x76, 0x8A, 0x58, + 0xD8, 0x08, 0xE4, 0xD9, 0x09, 0x95, 0xAA, 0x16, 0xB0, 0x21, 0x24, 0x39, 0x77, 0x41, 0xE4, 0xC7, + 0x77, 0x35, 0xD1, 0xE2, 0xF8, 0xED, 0x89, 0x73, 0xD5, 0x15, 0xD7, 0xD3, 0x57, 0x5D, 0xF1, 0x83, + 0x19, 0xF6, 0xFF, 0xCC, 0xF9, 0x7F, 0xE5, 0xCC, 0x32, 0xCA, 0x3A, 0x47, 0x00, 0x00 +}; + +size_t a_SIZE = 4862; +const char * a_NAME = "ool.html.gz"; diff --git a/embedded/tool.html.gz b/embedded/tool.html.gz index de11ef0170ba9cdda845977d8bdfbb586c26aef0..4478b2f1c1fc29b2e8e690eb5e5e7919764cbe6c 100644 GIT binary patch delta 4513 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 diff --git a/embedded/www/js/script.js b/embedded/www/js/script.js index f6f7428e..c24253e3 100644 --- a/embedded/www/js/script.js +++ b/embedded/www/js/script.js @@ -131,6 +131,9 @@ var formData = new FormData(); formData.append('path', currentpath); for (var i3 = 0; i3 < files.length; i3++) { var file = files[i3]; +var arg = currentpath + file.name + "S"; + //append file size first to check updload is complete + formData.append(arg, file.size); formData.append('myfiles[]', file, currentpath+file.name);} var xmlhttp = new XMLHttpRequest(); xmlhttp.open('POST', '/files', true); @@ -175,6 +178,9 @@ document.getElementById('prgfw').style.visibility = "visible"; var formData = new FormData(); for (var i4 = 0; i4 < files.length; i4++) { var file = files[i4]; +var arg = "/" + file.name + "S"; + //append file size first to check updload is complete + formData.append(arg, file.size); formData.append('myfile[]', file, "/"+file.name);} var xmlhttp = new XMLHttpRequest(); xmlhttp.open('POST', '/updatefw', true); diff --git a/embedded/www/tool.html b/embedded/www/tool.html index 33c5cecd..ea68774e 100644 --- a/embedded/www/tool.html +++ b/embedded/www/tool.html @@ -6,11 +6,12 @@