Prepare branch

This commit is contained in:
Luc 2019-01-26 09:31:25 +01:00
parent c3fbbd3c63
commit a84d146921
57 changed files with 2 additions and 13787 deletions

View File

@ -1,53 +1 @@
sudo: false
language: bash
os:
- linux
before_install:
- "/sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -ac -screen 0 1280x1024x16"
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
- 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 ..
- echo 'build.flash_ld=eagle.flash.4m.ld' >> platform.txt
- echo 'build.flash_freq=40' >> platform.txt
- echo 'build.flash_size=4M' >> platform.txt
- echo 'build.flash_mode=dio' >> platform.txt
- echo 'build.f_cpu=160000000L' >> platform.txt
- sed -i "s/generic.build.f_cpu=80000000L/generic.build.f_cpu=160000000L/g" ./boards.txt
- cd $HOME/arduino_ide/hardware
- mkdir esp32
- cd esp32
- git clone https://github.com/espressif/arduino-esp32.git esp32
- cd esp32/tools
- python get.py
- cd ..
- echo 'build.flash_freq=40m' >> platform.txt
script:
- cd $TRAVIS_BUILD_DIR
- source command.sh
- export PATH="$HOME/arduino_ide:$PATH"
- arduino --board esp8266com:esp8266:generic --save-prefs
- arduino --get-pref sketchbook.path
- build_sketch esp3d/esp3d.ino
- arduino --board esp32:esp32:esp32 --save-prefs
- build_sketch esp3d/esp3d.ino
notifications:
email:
on_success: change
on_failure: change

138
README.md
View File

@ -1,137 +1,3 @@
# ESP3D[![Code Climate](https://codeclimate.com/github/luc-github/ESP3D/badges/gpa.svg)](https://codeclimate.com/github/luc-github/ESP3D)
# ESP3D 3.0
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)
This firmware allows not only to have a cheap bridge between Wifi and serial, but also to have a web UI to configure wifi, to monitor 3D printer and even control it, and to make things easy,
UI is fully customizable without reflashing FW.
Firmware should work with any 3D printer firmware (repetier/marlin/smoothieware using GCODE) if serial connection has a correct setup.
I currently use it with my personnal flavor of [repetier for Due based boards](https://github.com/luc-github/Repetier-Firmware-0.92).
The web interface files are present in data directory but UI has it's own repository [ESP3D-WEBUI](https://github.com/luc-github/ESP3D-WEBUI).
* be aware ESP3D-WEBUI is for firmware 0.9.99 minimum - previous released version use tpl files which are no more used.
<u>Stable version (ESP8266 only):</u>
Arduino ide 1.6.5 with stable [2.0.0](http://arduino.esp8266.com/versions/2.0.0/package_esp8266com_index.json) from ESP8266, please use https://github.com/luc-github/ESP3D/releases/tag/v0.5.1
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)
<u>[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):</u>
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)
:+1:Thanks
* to @disneysw for bringing this module idea
* to @lkarlslund for suggestion about independent reset using GPIO2
* to Roy Cortes from http://www.panucatt.com for supporting and pushing me implementing great features
* to all contributors, feedbacks owners and donations.
## Donate
Every support is welcome: [<img src="https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG_global.gif" border="0" alt="PayPal The safer, easier way to pay online.">](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=Y8FFE7NA4LJWQ)
Especially if need to buy new modules for testing.
## Features
* Serial/Wifi bridge using configurable port 8888, here to enable/disable [TCP_IP_DATA_FEATURE](https://github.com/luc-github/ESP3D/blob/master/esp3d/config.h)
* Use GPIO2 to ground to reset all settings in hard way - 2-6 sec after boot / not before!! Set GPIO2 to ground before boot change boot mode and go to special boot that do not reach FW. Currently boot take 10 sec - giving 8 seconds to connect GPIO2 to GND and do an hard recovery for settings, here to enable/disable [RECOVERY_FEATURE](https://github.com/luc-github/ESP8266/blob/master/esp8266/config.h)
* Complete configuration by web browser (Station or Access point) or by Serial commands
* 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.
* The web ui add even more feature : https://github.com/luc-github/ESP3D-WEBUI/blob/master/README.md#features
## Web configuration
*Wifi Mode : Access point / Client station
*IP Generation: DHCP/Static IP
*IP/MASK/GATEWAY for static data
*Baud Rate for serial (supported : 9600, 19200, 38400, 57600, 115200, 230400, 250000)
*web port and data port
## Default Configuration
Default Settings:
AP:ESP8266
PW:12345678
Authentification: WPA
Mode: g (n is not supported by AP, just by STA)
channel: 11
AP: visible
Sleep Mode: Modem
IP Mode: Static IP
IP: 192.168.0.1
Mask: 255.255.255.0
GW:192.168.0.1
Baud rate: 115200
Web port:80
Data port: 8888
Web Page refresh: 3 secondes
User: admin
Password: admin
User:user
Password: user
## Direct commands:
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.
* 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
* 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
<img src=https://raw.githubusercontent.com/luc-github/ESP3D/master/images/docs/embedded.png><br>
## Update
* Generate a binary using the export binary menu from Arduino IDE and upload it using ESP-WEBUI or embedded interface
<H3>:warning:Do not flash your Printer fw with ESP connected - it bring troubles, at least on DaVinci</H3>
## Contribution/customization
* To style the code before pushing PR please use [astyle --style=otbs *.h *.cpp *.ino](http://astyle.sourceforge.net/)
* The embedded page is created using nodejs then gulp to generate a compressed html page (tool.html.gz), all necessary modules can be installed using the install.bat file content, then it is included using bin2c (https://sourceforge.net/projects/bin2c/) to generate the h file used to create the file nofile.h, update the array and size according new out.h.
* 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)
## :question:Any question ?
Check [Wiki](https://github.com/luc-github/ESP3D/wiki/Install-Instructions) or [![Join the chat at https://gitter.im/luc-github/ESP3D](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/luc-github/ESP3D?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
## :exclamation:Any issue/feedback ?
Check [Wiki](https://github.com/luc-github/ESP3D/wiki/Install-Instructions) and [FAQ](https://github.com/luc-github/ESP3D/issues?utf8=%E2%9C%93&q=label%3AFAQ+) or [submit ticket](https://github.com/luc-github/ESP3D/issues)
## 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
* GRBL_Esp32 a GRBL port on ESP32 done by @bdring - https://github.com/bdring/Grbl_Esp32
[![](https://img.youtube.com/vi/7vtWNn9jyDs/mqdefault.jpg)](https://www.youtube.com/watch?v=7vtWNn9jyDs)
* Marlin_ESP32 a Marlin port on ESP32 done by @simon-jouet is under sync : https://github.com/luc-github/Marlin/tree/eps32_webui
* More to come...
If you use ESP3D on your product, drop me a message so I can link your product page here.
## TODO/On going :
-- Version 2.X
-- Close open topics
-- Do testing (a lot)
-- UI Improvement
-- ESP3D V2
<H1>Coming Soon!</H1>

View File

@ -1,840 +0,0 @@
<HTML>
<HEAD>
<style type="text/css">
.sliderthumb{
position : absolute;
cursor : pointer;
}
.sliderrange{
cursor : pointer;
}
.extlist{
position : absolute;
cursor : pointer;
}
body{
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.hotspot{
cursor:pointer;
}
text.centerjog {
font-weight:600;
text-anchor:middle;
font-size:26;
font-family:sans-serif;
pointer-events:none;
}
text.home {
font-weight:800;
text-anchor:middle;
font-size:14;
font-family:sans-serif;
pointer-events:none;
}
text.positionbar {
font-weight:600;
text-anchor:middle;
font-size:16;
font-family:sans-serif;
pointer-events:none;
}
text.textpositionbar {
font-weight:400;
text-anchor:end;
font-size:12;
font-family:sans-serif;
pointer-events:none;
fill:#FF0000;
}
text.textbutton {
font-weight:400;
text-anchor:middle;
font-size:26;
font-family:sans-serif;
fill:#FFFFFF;
filter:url(#emboss);
pointer-events:none;
}
path.msk {
fill:#0052E1;
}
circle.bg2 {
stroke:#0D2F38;
fill:#B93D3D;
pointer-events:none;
stroke-width:0.5;
}
circle.bg ,
path.bg {
stroke:#0D2F38;
fill:#608B98;
pointer-events:none;
stroke-width:0.5;
}
rect.bg
{
stroke:#0D2F38;
fill:#608B98;
pointer-events:none;
stroke-width:1;
}
rect.bgpositionbar
{
stroke:#707070;
fill:#BCCED3;
pointer-events:none;
stroke-width:1;
}
path.sign{
pointer-events:none;
fill:#000000;
}
path.mskjog{
opacity:0;
fill:#0052E1;
}
</style>
</HEAD>
<BODY>
<script type="text/javascript">
function restore_x(e){
centerxytext.textContent='X/Y';
show_hide(e,0)
}
function changecolor(){
if (isDown)return;
var len = arguments.length;
if(len <2) return;
var color = arguments[len-1];
for(var i=0; i< len-1; i++)
{
arguments[i].style.fill=color;
}
}
function changestroke(){
if (isDown)return;
var len = arguments.length;
if(len <2) return;
var color = arguments[len-1];
for(var i=0; i< len-1; i++)
{
arguments[i].style.stroke=color;
}
}
function restore_z(e){
centerztext.textContent='Z';
show_hide(e,0);
}
function restore_e(e){
show_hide(extruder,1);
show_hide(centeretext,0);
show_hide(e,0);
}
function settext_e(text,e){
if (isDown)return;
show_hide(extruder,0);
centeretext.textContent=text;
show_hide(centeretext,1);
show_hide(e,0.5);
}
function show_hide(e,show){
e.style.opacity=show;
}
function settext_x(text,e){
if (isDown)return;
centerxytext.textContent=text;
show_hide(e,0.5)
}
function settext_z(text,e){
if (isDown)return;
centerztext.textContent=text;
show_hide(e,0.5);
}
var fan_on = 0;
var bed_on = 0;
var ext1_on = 0;
var ext2_on = 0;
//range functions
var offset = 0;
var isDown = false;
var active_control = null;
document.addEventListener('mouseup', function() {
isDown = false;
}, true);
//position is based on screen position value
function movethumb(pos)
{
var p = pos + offset;
var minpos =0;
var maxpos = 0;
var minvalue =0;
var maxvalue = 100;
var value=0;
var rangeelement =null;
if (active_control.hasAttribute('customrange')){
rangeelement = document.getElementById(active_control.getAttribute('customrange'));
var r = rangeelement.getBoundingClientRect();
minpos = r.left;
maxpos = r.right;
if (rangeelement.hasAttribute('min')){
minvalue = parseFloat(rangeelement.getAttribute('min'))
}
if (rangeelement.hasAttribute('max')){
maxvalue = parseFloat(rangeelement.getAttribute('max'))
}
}
var r2 = active_control.getBoundingClientRect();
if ( p >maxpos - (r2.right-r2.left)) p = maxpos - (r2.right-r2.left);
if ( p <minpos) p =minpos ;
active_control.style.left = p+ 'px';
if (active_control.hasAttribute('render')){
value = (((p-minpos) * (maxvalue-minvalue))/((maxpos-minpos)- (r2.right-r2.left)))
document.getElementById(active_control.getAttribute('render')).value = Math.round(value + minvalue) ;
}
}
//position is based on range value
function movethumbat(thumbcursor, value){
var minvalue =0;
var maxvalue = 100;
var minpos =0;
var maxpos = 0;
var rangeelement =null;
if (thumbcursor.hasAttribute('customrange')){
rangeelement = document.getElementById(thumbcursor.getAttribute('customrange'));
var r = rangeelement.getBoundingClientRect();
minpos = r.left;
maxpos = r.right;
if (rangeelement.hasAttribute('min')){
minvalue = parseFloat(rangeelement.getAttribute('min'))
}
if (rangeelement.hasAttribute('max')){
maxvalue = parseFloat(rangeelement.getAttribute('max'))
}
}
if (value > maxvalue) value = maxvalue;
if (value < minvalue) value = minvalue;
var r2 = thumbcursor.getBoundingClientRect();
var pos=0;
pos = ((value-minvalue)*((maxpos-minpos)-(r2.right-r2.left))/(maxvalue-minvalue))+minpos;
thumbcursor.style.left = pos+ 'px';
if (thumbcursor.hasAttribute('render')){
document.getElementById(thumbcursor.getAttribute('render')).value =value;
}
}
document.addEventListener('mousemove', function(event) {
//event.preventDefault();
if (isDown) {
movethumb(event.clientX);
}
}, true);
function rangeclicked(event,element)
{
if (element.hasAttribute('customthumb')){
active_control = document.getElementById(element.getAttribute('customthumb'));
offset = 0;
movethumb(event.clientX);
}
}
function initthumb( element)
{
element.addEventListener('mousedown', function(e) {
isDown = true;
offset = element.offsetLeft - e.clientX;
active_control = this;
}, true);
if (element.hasAttribute('bgimage')){
element.innerHTML = element.getAttribute('bgimage');
}
if (element.hasAttribute('customrange')){
var r = document.getElementById(element.getAttribute('customrange')).getBoundingClientRect();
element.style.top = r.top;
element.style.left = r.left;
}
}
function initrange( element)
{
if (element.hasAttribute('bgimage')){
element.innerHTML = element.getAttribute('bgimage');
}
}
</script>
<div id="positionbar">
<svg width="440" height="30" xmlns="http://www.w3.org/2000/svg" version="1.1" >
<defs>
<filter id="light" >
<feGaussianBlur in="SourceAlpha"
stdDeviation="2"
result="out1" />
<feSpecularLighting in="out1"
surfaceScale="8"
specularConstant="2"
specularExponent="12"
result="out3">
<feDistantLight azimuth="225" elevation="5" />
</feSpecularLighting>
<feComposite operator="in" in="out3" in2="SourceAlpha" result="out4"/>
<feMerge>
<feMergeNode in="SourceGraphic" />
<feMergeNode in="out4"/>
</feMerge>
</filter>
<filter id="shadow" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha"
stdDeviation="2"
result="out1" />
<feOffset in="out1"
dx="2" dy="2"
result="out2" />
<feComposite in="SourceGraphic" in2="out2"
operator="over" />
</filter>
</defs>
<g id="posxtext">
<rect class="bg" x="0" y="0" width="107" height="27" filter="url(#shadow)"/>
<rect class="bg" x="0" y="0" width="107" height="27" opacity="0.7" filter="url(#light)"/>
<text x="13" y="19.5" class="positionbar">X</text>
<rect class="bgpositionbar" x="25" y="5.5" width="72" height="17" />
<text id="posx" x="95" y="19" class="textpositionbar">0.00</text>
</g>
<g id="posytext">
<rect class="bg" x="107" y="0" width="107" height="27" filter="url(#shadow)"/>
<rect class="bg" x="107" y="0" width="107" height="27" opacity="0.7" filter="url(#light)"/>
<text x="120" y="19.5" class="positionbar">Y</text>
<rect class="bgpositionbar" x="132" y="5.5" width="72" height="17" />
<text id="posy" x="202" y="19" class="textpositionbar">100.00</text>
</g>
<g id="posztext">
<rect class="bg" x="214" y="0" width="107" height="27" filter="url(#shadow)"/>
<rect class="bg" x="214" y="0" width="107" height="27" opacity="0.7" filter="url(#light)"/>
<text x="227" y="19.5" class="positionbar">Z</text>
<rect class="bgpositionbar" x="239" y="5.5" width="72" height="17" />
<text id="posz" x="309" y="19" class="textpositionbar">0.00</text>
</g>
<g id="posextruderlist">
<rect class="bg" x="321" y="0" width="107" height="27" filter="url(#shadow)"/>
<rect class="bg" x="321" y="0" width="107" height="27" opacity="0.7" filter="url(#light)"/>
</g>
</svg>
</div>
<div id="extruderlist" class="extlist">
<select id="activeextruder">
<option value="0" selected>Extruder 1</option>
<option value="1">Extruder 2</option>
</select>
</div>
<br>
<div id="jogPanel">
<svg width="440" height="230" xmlns="http://www.w3.org/2000/svg" version="1.1" viewbox="0 0 440 230">
<defs>
<filter id="light" >
<feGaussianBlur in="SourceAlpha"
stdDeviation="2"
result="out1" />
<feSpecularLighting in="out1"
surfaceScale="8"
specularConstant="2"
specularExponent="12"
result="out3">
<feDistantLight azimuth="225" elevation="5" />
</feSpecularLighting>
<feComposite operator="in" in="out3" in2="SourceAlpha" result="out4"/>
<feMerge>
<feMergeNode in="SourceGraphic" />
<feMergeNode in="out4"/>
</feMerge>
</filter>
<filter id="shadow" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha"
stdDeviation="2"
result="out1" />
<feOffset in="out1"
dx="2" dy="2"
result="out2" />
<feComposite in="SourceGraphic" in2="out2"
operator="over" />
</filter>
<filter id="emboss" x0="-50%" y0="-50%" width="200%" height="200%">
<feMorphology in="SourceAlpha" operator="dilate" radius="1"/>
<feGaussianBlur stdDeviation="1" result="blur"/>
<feOffset dy="0.2" dx="0.2"/>
<feComposite in2="SourceAlpha" operator="arithmetic"
k2="1" k3="-1" result="hlDiff"/>
<feFlood flood-color="white" flood-opacity=".7"/>
<feComposite in2="hlDiff" operator="in"/>
<feComposite in2="SourceGraphic" operator="over" result="withGlow"/>
<feOffset in="blur" dy="-0.2" dx="-0.2"/>
<feComposite in2="SourceAlpha" operator="arithmetic"
k2="1" k3="-1" result="shadowDiff"/>
<feFlood flood-color="black" flood-opacity="1"/>
<feComposite in2="shadowDiff" operator="in"/>
<feComposite in2="withGlow" operator="over"/>
</filter>
</defs>
<g id="Jog" transform="translate(0,-30)">
<g id="homeall" transform="translate(10,175)" onmouseup="alert('all');" onmouseover="changecolor(ha1,ha2,ha3,ha4,'#2F65FF');" onmouseout="changecolor(ha1,ha2,ha3,ha4,'#608B98');">
<circle cx='17' cy='17' r='18' fill='white' />
<path class="bg" id="ha1" d="M1,15 L14,2 L16,1 L18,1 L20,2 L23,5 L23,2 L24,1 L27,1 L28,2 L28,10 L33,15 L30,18 L19,7 L15,7 L4,18 z" filter="url(#shadow)"/>
<path class="bg" id="ha2" d="M1,15 L14,2 L16,1 L18,1 L20,2 L23,5 L23,2 L24,1 L27,1 L28,2 L28,10 L33,15 L30,18 L19,7 L15,7 L4,18 z" opacity='0.7' filter="url(#light)"/>
<path class="bg" id="ha3" d="M6,19 L16,9 L18,9 L28,19 L28,28 L6,28 z" filter="url(#shadow)"/>
<path class="bg" id="ha4" d="M6,19 L16,9 L18,9 L28,19 L28,28 L6,28 z" filter="url(#shadow)" opacity='0.7' filter="url(#light)"/>
</g>
<g id="homex" transform="translate(10,35)" onmouseup="alert('X');" onmouseover="changecolor(hx1,hx2,hx3,hx4,'#2F65FF');" onmouseout="changecolor(hx1,hx2,hx3,hx4,'#608B98');">
<circle cx='17' cy='17' r='18' fill='white' />
<path class="bg" id="hx1" d="M1,15 L14,2 L16,1 L18,1 L20,2 L23,5 L23,2 L24,1 L27,1 L28,2 L28,10 L33,15 L30,18 L19,7 L15,7 L4,18 z" filter="url(#shadow)"/>
<path class="bg" id="hx2" d="M1,15 L14,2 L16,1 L18,1 L20,2 L23,5 L23,2 L24,1 L27,1 L28,2 L28,10 L33,15 L30,18 L19,7 L15,7 L4,18 z" opacity='0.7' filter="url(#light)"/>
<path class="bg" id="hx3" d="M6,19 L16,9 L18,9 L28,19 L28,28 L6,28 z" filter="url(#shadow)"/>
<path class="bg" id="hx4" d="M6,19 L16,9 L18,9 L28,19 L28,28 L6,28 z" filter="url(#shadow)" opacity='0.7' filter="url(#light)"/>
<text x="17" y="26" class="home">X</text>
</g>
<g id="homey" transform="translate(159,35)" onmouseup="alert('y');" onmouseover="changecolor(hy1,hy2,hy3,hy4,'#2F65FF');" onmouseout="changecolor(hy1,hy2,hy3,hy4,'#608B98');">
<circle cx='17' cy='17' r='18' fill='white' />
<path class="bg" id="hy1" d="M1,15 L14,2 L16,1 L18,1 L20,2 L23,5 L23,2 L24,1 L27,1 L28,2 L28,10 L33,15 L30,18 L19,7 L15,7 L4,18 z" filter="url(#shadow)"/>
<path class="bg" id="hy2" d="M1,15 L14,2 L16,1 L18,1 L20,2 L23,5 L23,2 L24,1 L27,1 L28,2 L28,10 L33,15 L30,18 L19,7 L15,7 L4,18 z" opacity='0.7' filter="url(#light)"/>
<path class="bg" id="hy3" d="M6,19 L16,9 L18,9 L28,19 L28,28 L6,28 z" filter="url(#shadow)"/>
<path class="bg" id="hy4" d="M6,19 L16,9 L18,9 L28,19 L28,28 L6,28 z" filter="url(#shadow)" opacity='0.7' filter="url(#light)"/>
<text x="17" y="26" class="home">Y</text>
</g>
<g id="homez" transform="translate(159,175)" onmouseup="alert('z');" onmouseover="changecolor(hz1,hz2,hz3,hz4,'#2F65FF');" onmouseout="changecolor(hz1,hz2,hz3,hz4,'#608B98');">
<circle cx='17' cy='17' r='18' fill='white' />
<path class="bg" id="hz1" d="M1,15 L14,2 L16,1 L18,1 L20,2 L23,5 L23,2 L24,1 L27,1 L28,2 L28,10 L33,15 L30,18 L19,7 L15,7 L4,18 z" filter="url(#shadow)"/>
<path class="bg" id="hz2" d="M1,15 L14,2 L16,1 L18,1 L20,2 L23,5 L23,2 L24,1 L27,1 L28,2 L28,10 L33,15 L30,18 L19,7 L15,7 L4,18 z" opacity='0.7' filter="url(#light)"/>
<path class="bg" id="hz3" d="M6,19 L16,9 L18,9 L28,19 L28,28 L6,28 z" filter="url(#shadow)"/>
<path class="bg" id="hz4" d="M6,19 L16,9 L18,9 L28,19 L28,28 L6,28 z" filter="url(#shadow)" opacity='0.7' filter="url(#light)"/>
<text x="17" y="26" class="home">Z</text>
</g>
<g id="topxy">
<path class="bg" d="M48,70 A 74,74 0 0,1 154,70 L126,98 A 35,35 0 0 0 76,98 z" filter="url(#shadow)" />
<path class="bg" d="M48,70 A 74,74 0 0,1 154,70 L126,98 A 35,35 0 0 0 76,98 z" opacity='0.7' filter="url(#light)"/>
<path onmouseup="alert(1);" onmouseover="settext_x('50',this);" onmouseout="restore_x(this);" class="mskjog" d="M48,70 A 74,74 0 0,1 154,70 L126,98 A 35,35 0 0 0 76,98 z" />
<path onmouseup="alert(2);" onmouseover="settext_x('10',this);" onmouseout="restore_x(this);" class="mskjog" d="M55,77 A 64,64 0 0,1 147,77 L126,98 A 35,35 0 0 0 76,98 z" />
<path onmouseup="alert(3);" onmouseover="settext_x('1',this);" onmouseout="restore_x(this);" class="mskjog" d="M62,84 A 54,54 0 0,1 140,84 L126,98 A 35,35 0 0 0 76,98 z" />
<path onmouseup="alert(4);" onmouseover="settext_x('0,1',this);" onmouseout="restore_x(this);" class="mskjog" d="M69,91 A 44,44 0 0,1 133,91 L126,98 A 35,35 0 0 0 76,98 z"/>
<path class='sign' d="M101,58 L112,76 L90,76 z" />
</g>
<g id="rightxy">
<path class="bg" d="M154,70 A 74,74 0 0,1 154,174 L126,146 A 35,35 0 0 0 126,98 z" filter="url(#shadow)"/>
<path class="bg" d="M154,70 A 74,74 0 0,1 154,174 L126,146 A 35,35 0 0 0 126,98 z" opacity=0.7 filter="url(#light)"/>
<path onmouseup="alert(13);" onmouseover="settext_x('50',this);" onmouseout="restore_x(this);" class="mskjog" d="M154,70 A 74,74 0 0,1 154,174 L126,146 A 35,35 0 0 0 126,98 z"/>
<path onmouseup="alert(14);" onmouseover="settext_x('10',this);" onmouseout="restore_x(this);" class="mskjog" d="M147,77 A 64,64 0 0,1 147,167 L126,146 A 35,35 0 0 0 126,98 z"/>
<path onmouseup="alert(15);" onmouseover="settext_x('1',this);" onmouseout="restore_x(this);" class="mskjog" d="M140,84 A 54,54 0 0,1 140,160 L126,146 A 35,35 0 0 0 126,98 z"/>
<path onmouseup="alert(16);" onmouseover="settext_x('0,1',this);" onmouseout="restore_x(this);" class="mskjog" d="M133,91 A 44,44 0 0,1 133,153 L126,146 A 35,35 0 0 0 126,98 z"/>
<path class='sign' d="M165,122 L148,112 L148,132 z" />
</g>
<g id="bottomxy">
<path class="bg" d="M48,174 A 74,74 0 0,0 154,174 L126,146 A 35,35 0 0 1 76,146 z" filter="url(#shadow)"/>
<path class="bg" d="M48,174 A 74,74 0 0,0 154,174 L126,146 A 35,35 0 0 1 76,146 z" opacity='0.7' filter="url(#light)"/>
<path onmouseup="alert(8);" onmouseover="settext_x('-50',this);" onmouseout="restore_x(this);" class="mskjog" d="M48,174 A 74,74 0 0,0 154,174 L126,146 A 35,35 0 0 1 76,146 z" />
<path onmouseup="alert(7);" onmouseover="settext_x('-10',this);" onmouseout="restore_x(this);" class="mskjog" d="M55,167 A 64,64 0 0,0 147,167 L126,146 A 35,35 0 0 1 76,146 z" />
<path onmouseup="alert(6);" onmouseover="settext_x('-1',this);" onmouseout="restore_x(this);" class="mskjog" d="M62,160 A 54,54 0 0,0 140,160 L126,146 A 35,35 0 0 1 76,146 z" />
<path onmouseup="alert(5);" onmouseover="settext_x('-0,1',this);" onmouseout="restore_x(this);" class="mskjog" d="M69,153 A 44,44 0 0,0 133,153 L126,146 A 35,35 0 0 1 76,146 z" />
<path class='sign' d="M101,186 L112,168 L90,168 z" />
</g>
<g id="leftxy">
<path class="bg" d="M48,174 A 74,74 0 0,1 48,70 L76,98 A 35,35 0 0 0 76,146 z"/>
<path class="bg" d="M48,174 A 74,74 0 0,1 48,70 L76,98 A 35,35 0 0 0 76,146 z" opacity='0.7' filter="url(#light)"/>
<path onmouseup="alert(9);" onmouseover="settext_x('-50',this);" onmouseout="restore_x(this);" class="mskjog" d="M48,174 A 74,74 0 0,1 48,70 L76,98 A 35,35 0 0 0 76,146 z" />
<path onmouseup="alert(10);" onmouseover="settext_x('-10',this);" onmouseout="restore_x(this);" class="mskjog" d="M55,167 A 64,64 0 0,1 55,77 L76,98 A 35,35 0 0 0 76,146 z" />
<path onmouseup="alert(11);" onmouseover="settext_x('-1',this);" onmouseout="restore_x(this);" class="mskjog" d="M62,160 A 54,54 0 0,1 62,84 L76,98 A 35,35 0 0 0 76,146 z" />
<path onmouseup="alert(12);" onmouseover="settext_x('-0,1',this);" onmouseout="restore_x(this);" class="mskjog" d="M69,153 A 44,44 0 0,1 69,91 L76,98 A 35,35 0 0 0 76,146 z" />
<path class='sign' d="M37,122 L54,112 L54,132 z" />
</g>
<g id=''centerxy">
<circle class="bg" cx="101" cy="122" r="34" " />
<circle class="bg" cx="101" cy="122" r="34" opacity='0.7' filter="url(#light)"/>
<text id="centerxytext" class="centerjog" x="101" y="132">X/Y</text>
</g>
<g id="topz">
<path class="bg" d="M214,56 A 74,74 0 0,1 288,56 L268,92 A 35,35 0 0 0 234,92 z" filter="url(#shadow)"/>
<path class="bg" d="M214,56 A 74,74 0 0,1 288,56 L268,92 A 35,35 0 0 0 234,92 z" opacity='0.7' filter="url(#light)"/>
<path onmouseup="alert(17);" onmouseover="settext_z('10',this);" onmouseout="restore_z(this);" class="mskjog" d="M214,56 A 74,74 0 0,1 288,56 L268,92 A 35,35 0 0 0 234,92 z" />
<path onmouseup="alert(18);" onmouseover="settext_z('1',this);" onmouseout="restore_z(this);" class="mskjog" d="M219,65 A 64,64 0 0,1 283,65 L268,92 A 35,35 0 0 0 234,92 z" />
<path onmouseup="alert(19);" onmouseover="settext_z('0,1',this);" onmouseout="restore_z(this);" class="mskjog" d="M224,74 A 54,54 0 0,1 278,74 L268,92 A 35,35 0 0 0 234,92 z" />
<path onmouseup="alert(20);" onmouseover="settext_z('0,01',this);" onmouseout="restore_z(this);" class="mskjog" d="M229,83 A 44,44 0 0,1 273,83 L268,92 A 35,35 0 0 0 234,92 z" />
<path class='sign' d="M251,58 L262,76 L240,76 z" />
</g>
<g id=''centerz">
<circle class="bg" cx="251" cy="122" r="34" filter="url(#shadow)" />
<circle class="bg" cx="251" cy="122" r="34" opacity='0.7' filter="url(#light)"/>
<text id="centerztext" class="centerjog" x="251" y="132">Z</text>
</g>
<g id="bottomz">
<path class="bg" d="M214,188 A 75,75 0 0,0 288,188 L268,152 A 36,36 0 0 1 234,152 z" filter="url(#shadow)"/>
<path class="bg" d="M214,188 A 75,75 0 0,0 288,188 L268,152 A 36,36 0 0 1 234,152 z" opacity='0.7' filter="url(#light)"/>
<path onmouseup="alert(21);" onmouseover="settext_z('-10',this);" onmouseout="restore_z(this);" class="mskjog" d="M214,188 A 74,74 0 0,0 288,188 L268,152 A 35,35 0 0 1 234,152 z" />
<path onmouseup="alert(22);" onmouseover="settext_z('-1',this);" onmouseout="restore_z(this);" class="mskjog" d="M219,179 A 64,64 0 0,0 283,179 L268,152 A 35,35 0 0 1 234,152 z" />
<path onmouseup="alert(23);" onmouseover="settext_z('-0,1',this);" onmouseout="restore_z(this);" class="mskjog" d="M224,170 A 54,54 0 0,0 278,170 L268,152 A 35,35 0 0 1 234,152 z" />
<path onmouseup="alert(24);" onmouseover="settext_z('-0,01',this);" onmouseout="restore_z(this);" class="mskjog" d="M229,161 A 44,44 0 0,0 273,161 L268,152 A 35,35 0 0 1 234,152 z" />
<path class='sign' d="M251,186 L262,168 L240,168 z"/>
</g>
<g id="tope">
<path class="bg" d="M317,56 A 74,74 0 0,1 391,56 L371,92 A 35,35 0 0 0 337,92 z" filter="url(#shadow)"/>
<path class="bg" d="M317,56 A 74,74 0 0,1 391,56 L371,92 A 35,35 0 0 0 337,92 z" opacity='0.7' filter="url(#light)"/>
<path onmouseup="alert(25);" onmouseover="settext_e('-100',this);" onmouseout="restore_e(this);" class="mskjog" d="M317,56 A 74,74 0 0,1 391,56 L371,92 A 35,35 0 0 0 337,92 z" />
<path onmouseup="alert(26);" onmouseover="settext_e('-50',this);" onmouseout="restore_e(this);" class="mskjog" d="M322,65 A 64,64 0 0,1 385,65 L371,92 A 35,35 0 0 0 337,92 z" />
<path onmouseup="alert(27);" onmouseover="settext_e('-10',this);" onmouseout="restore_e(this);" class="mskjog" d="M327,74 A 54,54 0 0,1 381,74 L371,92 A 35,35 0 0 0 337,92 z" />
<path onmouseup="alert(28);" onmouseover="settext_e('-1',this);" onmouseout="restore_e(this);" class="mskjog" d="M332,83 A 44,44 0 0,1 376,83 L371,92 A 35,35 0 0 0 337,92 z" />
<path class='sign' d="M354,58 L365,76 L343,76 z" />
</g>
<g id=''centerze">
<circle class="bg" cx="354" cy="122" r="34" filter="url(#shadow)" />
<circle class="bg" cx="354" cy="122" r="34" class="bg" opacity='0.7' filter="url(#light)" />
<text id="centeretext" class="centerjog" x="353" y="132" opacity="0"></text>
<g id="extruder">
<path class='sign' d="M350,108 L360,108 L360,128 L355,136 L350,128 z"/>
<path class='sign' d="M335,110 L338,109 L340,111 L341,111 L343,109 L346,110 L346,113 L349,113 L350,116 L348,118 L348,119 L350,121 L349,124 L346,124 L346,127 L343,128 L341,126 L340,126 L338,128 L335,127 L335,124 L332,124 L331,121 L333,119 L333,118 L331,116 L332,113 L335,113 z"/>
<circle cx="340.5" cy="118.5" r="3.5" fill="#608B98" />
</g>
</g>
<g id="bottome2">
<path class="bg"d="M317,188 A 74,74 0 0,0 354,197 L354,156.5 A 35,35 0 0 1 337,152 z" filter="url(#shadow)"/>
<path class="bg" d="M317,188 A 74,74 0 0,0 354,197 L354,156.5 A 35,35 0 0 1 337,152 z" opacity='0.7' filter="url(#light)" />
<path onmouseup="alert(29);" onmouseover="settext_e('100',this);" onmouseout="restore_e(this);" class="mskjog" d="M317,188 A 74,74 0 0,0 354,197 L354,156.5 A 35,35 0 0 1 337,152 z"/>
<path onmouseup="alert(30);" onmouseover="settext_e('50',this);" onmouseout="restore_e(this);" class="mskjog" d="M322,179 A 64,64 0 0,0 354,187 L354,156.5 A 35,35 0 0 1 337,152 z" />
<path onmouseup="alert(31);" onmouseover="settext_e('10',this);" onmouseout="restore_e(this);" class="mskjog" d="M327,170 A 54,54 0 0,0 354,177 L354,156.5 A 35,35 0 0 1 337,152 z" />
<path onmouseup="alert(32);" onmouseover="settext_e('1',this);" onmouseout="restore_e(this);" class="mskjog" d="M332,161 A 44,44 0 0,0 354,167 L354,156.5 A 35,35 0 0 1 337,152 z" />
<path class='sign' d="M337,171 L347,174 L339.5,182 z"/>
</g>
<g id="bottome1">
<path class="bg" d="M354,197 A 74,74 0 0,0 391,188 L371,152 A 35,35 0 0 1 354,156.5 z" filter="url(#shadow)"/>
<path class="bg" d="M354,197 A 74,74 0 0,0 391,188 L371,152 A 35,35 0 0 1 354,156.5 z" opacity='0.7' filter="url(#light)" />
<path onmouseup="alert(33);" onmouseover="settext_e('100',this);" onmouseout="restore_e(this);" class="mskjog" d="M354,197 A 74,74 0 0,0 391,188 L371,152 A 35,35 0 0 1 354,156.5 z"/>
<path onmouseup="alert(34);" onmouseover="settext_e('50',this);" onmouseout="restore_e(this);" class="mskjog" d="M354,187 A 64,64 0 0,0 386,179 L371,152 A 35,35 0 0 1 354,156.5 z" />
<path onmouseup="alert(35);" onmouseover="settext_e('10',this);" onmouseout="restore_e(this);" class="mskjog" d="M354,177 A 54,54 0 0,0 381,170 L371,152 A 35,35 0 0 1 354,156.5 z" />
<path onmouseup="alert(36);" onmouseover="settext_e('1',this);" onmouseout="restore_e(this);" class="mskjog" d="M354,167 A 54,54 0 0,0 376,161 L371,152 A 35,35 0 0 1 354,156.5 z" />
<path class='sign' d="M361,170 L372,167 L369.5,178 z"/>
<path class='sign' d="M364,180 L375,177 L372,188 z"/>
</g>
<g id="poweroff" transform="translate(11,220)" onmouseup="alert('power');" onmouseover="changecolor(poweroff1,poweroff2,poweroff3,poweroff4,'#2F65FF');" onmouseout="changecolor(poweroff1,poweroff2,poweroff3,poweroff4,'#608B98');">
<circle cx='17' cy='18' r='16' fill='white' />
<path id="poweroff1" class="bg" d="M8,6 A15 15 0 1 0 26,6 A 3,3 0 0 0 22,10 A 10,10 0 1 1 12,10 A 3,3 0 0 0 8,6z" filter="url(#shadow)"/>
<path id="poweroff2" class="bg" d="M8,6 A15 15 0 1 0 26,6 A 3,3 0 0 0 22,10 A 10,10 0 1 1 12,10 A 3,3 0 0 0 8,6z" opacity='0.7' filter="url(#light)"/>
<path id="poweroff3" class="bg" d="M14,2 A4,4 0 0 1 20,2 L20,15 A4,4 0 0 1 14,15z" filter="url(#shadow)" />
<path id="poweroff4" class="bg" d="M14,2 A4,4 0 0 1 20,2 L20,15 A4,4 0 0 1 14,15z" opacity='0.7' filter="url(#light)" />
</g>
<g id="button_M" transform="translate(56,220)" onmouseup="alert('Button M');" onmouseover="changecolor(buttonM1,buttonM2,buttonM3,buttonM4,buttonM5,buttonM6,'#2F65FF');" onmouseout="changecolor(buttonM1,buttonM2,buttonM3,buttonM4,buttonM5,buttonM6,'#608B98');">
<circle cx='17' cy='18' r='16' fill='white' />
<circle id="buttonM1" class='bg' cx="16" cy="16" r="15" filter="url(#shadow)"/>
<circle id="buttonM2" class='bg' cx="16" cy="16" r="15" opacity='0.7' filter="url(#light)"/>
<circle cx="16" cy="16" r="12" fill="white" stroke="#0D2F38"/>
<path id="buttonM3" class="bg" d="M5,15 L9,15 L9,12 L11,10 L24,10 L25,11 L25,21 L24,22 L11,22 L9,20 L9,17 L5,17 z" />
<path id="buttonM4" class="bg" d="M5,15 L9,15 L9,12 L11,10 L24,10 L25,11 L25,21 L24,22 L11,22 L9,20 L9,17 L5,17 z" opacity='0.7' filter="url(#light)"/>
<rect x="13" y="13" width="10" height="1" fill="white" stroke="none"/>
<rect x="12" y="16" width="11" height="1" fill="white" stroke="none"/>
<rect x="13" y="19" width="10" height="1" fill="white" stroke="none"/>
<path id="buttonM5" d="M24,4 L4,24 L7,27 L27,7 z" fill="#608B98" stroke="none" />
<path id="buttonM6" d="M24,4 L4,24 L7,27 L27,7 z" fill="#608B98" stroke="none" opacity='0.7' filter="url(#light)"/>
<line x1="22" y1="6" x2="6" y2="22" stroke="#0D2F38" />
<line x1="8" y1="25.5" x2="25.5" y2="8" stroke="#0D2F38" />
</g>
<g id="button_P" transform="translate(101,220)" onmouseup="alert('Button P');" onmouseover="changecolor(buttonP1,buttonP2,'#2F65FF');" onmouseout="changecolor(buttonP1,buttonP2,'#608B98');">
<circle cx='17' cy='18' r='16' fill='white' />
<circle id="buttonP1" class='bg' cx="16" cy="16" r="15" filter="url(#shadow)"/>
<circle id="buttonP2" class='bg' cx="16" cy="16" r="15" opacity='0.7' filter="url(#light)" />
<text class="textbutton" x="16" y="26" filter="url(#emboss)">P</text>
</g>
<g id="button_1" transform="translate(146,220)" onmouseup="alert('Button 1');" onmouseover="changecolor(button11,button12,'#2F65FF');" onmouseout="changecolor(button11,button12,'#608B98');">
<circle cx='17' cy='18' r='16' fill='white' />
<circle id="button11" class='bg' cx="16" cy="16" r="15" filter="url(#shadow)"/>
<circle id="button12" class='bg' cx="16" cy="16" r="15" opacity='0.7' filter="url(#light)" />
<text class="textbutton" x="16" y="26" filter="url(#emboss)">1</text>
</g>
<g id="button_2" transform="translate(191,220)" onmouseup="alert('Button 2');" onmouseover="changecolor(button21,button22,'#2F65FF');" onmouseout="changecolor(button21,button22,'#608B98');">
<circle cx='17' cy='18' r='16' fill='white' />
<circle id="button21" class='bg' cx="16" cy="16" r="15" filter="url(#shadow)"/>
<circle id="button22"class='bg' cx="16" cy="16" r="15" opacity='0.7' filter="url(#light)" />
<text class="textbutton" x="16" y="26" filter="url(#emboss)">2</text>
</g>
<g id="button_3" transform="translate(236,220)" onmouseup="alert('Button 3');" onmouseover="changecolor(button31,button32,'#2F65FF');" onmouseout="changecolor(button31,button32,'#608B98');">
<circle cx='17' cy='18' r='16' fill='white' />
<circle id="button31" class='bg' cx="16" cy="16" r="15" filter="url(#shadow)"/>
<circle id="button32" class='bg' cx="16" cy="16" r="15" opacity='0.7' filter="url(#light)" />
<text class="textbutton" x="16" y="26" filter="url(#emboss)">3</text>
</g>
<g id="button_4" transform="translate(281,220)" onmouseup="alert('Button 4');" onmouseover="changecolor(button41,button42,'#2F65FF');" onmouseout="changecolor(button41,button42,'#608B98');">
<circle cx='17' cy='18' r='16' fill='white' />
<circle id="button41" class='bg' cx="16" cy="16" r="15" filter="url(#shadow)"/>
<circle id="button42" class='bg' cx="16" cy="16" r="15" opacity='0.7' filter="url(#light)" />
<text class="textbutton" x="16" y="26" filter="url(#emboss)">4</text>
</g>
<g id="button_5" transform="translate(326,220)" onmouseup="alert('Button 5');" onmouseover="changecolor(button51,button52,'#2F65FF');" onmouseout="changecolor(button51,button52,'#608B98');">
<circle cx='17' cy='18' r='16' fill='white' />
<circle id="button51" class='bg' cx="16" cy="16" r="15" filter="url(#shadow)"/>
<circle id="button52" class='bg' cx="16" cy="16" r="15" opacity='0.7' filter="url(#light)" />
<text class="textbutton" x="16" y="26" filter="url(#emboss)">5</text>
</g>
<g id="button_Q" transform="translate(371,220)" onmouseup="alert('Button Q');" onmouseover="changecolor(buttonQ1,buttonQ2,'#2F65FF');" onmouseout="changecolor(buttonQ1,buttonQ2,'#B93D3D');">
<circle cx='17' cy='18' r='16' fill='white' />
<circle id="buttonQ1" class='bg2' cx="16" cy="16" r="15" filter="url(#shadow)"/>
<circle id="buttonQ2" class='bg2' cx="16" cy="16" r="15" opacity='0.7' filter="url(#light)" />
<text class="textbutton" x="16" y="26" filter="url(#emboss)">?</text>
</g>
</g>
</svg>
</div>
<br>
<div style='margin-left: 0cm;' >
<table style='border-spacing: 5px'>
<tr ><td width='auto' align='middle'>
<svg width="22" height="22" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 300 300">
<defs>
<filter id="blurMe"><feGaussianBlur in="SourceGraphic" stdDeviation="6" /></filter>
</defs>
<circle cx="263" cy="38" r="32" />
<path d="M150,176 L55,279 A 12,12 0 0 1 36,258 L186,72 L162,50 L123,91 A 9,9 0 0 1 109,74 L145,28 A 20,20 0 0 1 171,22 L229,70 A 20,20 0 0 1 230,81 L230,140 L272,143 A 8,8 0 0 1 274,167 L221,165 A 20,20 0 0 1 205,149 L205,96 L168,144 L231,207 A 20,20 0 0 1 225,234 L132,258 A 9,9 0 0 1 126,231 L188,211 z " />
<rect x="7" y="39" width="125" rx="6" ry="6" height="12" fill ="#656565" stroke-width='12' opacity="0.7" filter="url(#blurMe)"/>
<rect x="70" y="76" width="30" rx="6" ry="6" height="12" fill ="#656565" stroke-width='12' opacity="0.7" filter="url(#blurMe)"/>
<rect x="24" y="130" width="110" rx="6" ry="6" height="12" fill ="#656565" stroke-width='12' opacity="0.7" filter="url(#blurMe)"/>
<rect x="66" y="148" width="50" rx="6" ry="6" height="12" fill ="#656565" stroke-width='12' opacity="0.7" filter="url(#blurMe)"/>
<rect x="8" y="172" width="90" rx="6" ry="6" height="12" fill ="#656565" stroke-width='12' opacity="0.7" filter="url(#blurMe)"/>
</svg></td>
<td width='auto' >
<div id='rangefeedrate' min="25" max="300" class='sliderrange' onclick ="rangeclicked(event,this);" customthumb='thumbfeedrate'>
<svg width='322' height='20' viewbox='0 0 322 20'>
<defs>
<pattern id='basicPattern' x='10' y='0' width='4' height='20' patternUnits='userSpaceOnUse'>
<rect x='0' y='0' width='4' height='20' stroke-width='0.2' stroke= '#0D2F38' fill='#77AEBD'/ >
</pattern>
</defs>
<rect x='1' y='4' width='320' height='12' stroke= '#0D2F38' stroke-width='1' rx='6' ry='6' fill='url(#basicPattern)'/>
<text x='13' y='14' style='font-weight:600;font-size:10;font-family:sans-serif;fill:#000000; pointer-events:none;'>Feedrate</text>
</svg>
</div>
<div id='thumbfeedrate' class='sliderthumb' render='feedraterender' customrange='rangefeedrate'>
<svg width='8' height='20' viewbox='0 0 8 20'><path d='M 3.5,0 L7,5 L7,14 L3.5,19 L0,14 L0,5 z' /></svg>
</div>
</td><td width='auto'><input id='feedraterender' type='number' min='25' max='300' step='1' style='width: 4em;' onchange='movethumbat(thumbfeedrate, this.value);'/></td></tr>
<tr style='margin-top: 50px'><td align='middle'>
<svg width="24" height="24" xmlns="http://www.w3.org/2000/svg" version="1.1">
<rect x='2' y='2' width='3' height='10' />
<rect x='8' y='4' width='3' height='8' />
<rect x='14' y='6' width='3' height='6' />
<rect x='20' y='8' width='3' height='4' />
<path d="M2,17 L18,17 L18,14 L23,18.5 L18,23 L18,20 L2,20 z" />
</svg>
</td><td width='auto' >
<div id='rangeflowrate' min="50" max="150" class='sliderrange' onclick ="rangeclicked(event,this);" customthumb='thumbflowrate'>
<svg width='322' height='20' viewbox='0 0 322 20'>
<defs>
<pattern id='basicPattern' x='10' y='0' width='4' height='20' patternUnits='userSpaceOnUse'>
<rect x='0' y='0' width='4' height='20' stroke-width='0.2' stroke= '#0D2F38' fill='#77AEBD'/ >
</pattern>
</defs>
<rect x='1' y='4' width='320' height='12' stroke= '#0D2F38' stroke-width='1' rx='6' ry='6' fill='url(#basicPattern)'/>
<text x='13' y='14' style='font-weight:600;font-size:10;font-family:sans-serif;fill:#000000; pointer-events:none;'>Flowrate</text>
</svg>
</div>
<div id='thumbflowrate' class='sliderthumb' render='flowraterender' customrange='rangeflowrate' ><svg width='8' height='20' viewbox='0 0 8 20'><path d='M 3.5,0 L7,5 L7,14 L3.5,19 L0,14 L0,5 z' /></div>
</td><td width='auto'><input id='flowraterender' min='50' max='150' step='1' type='number' style='width: 4em;' onchange='movethumbat(thumbflowrate, this.value);'></td></tr>
<tr><td align='middle'>
<svg width="24" height="24" xmlns="http://www.w3.org/2000/svg" version="1.1">
<g id='fan' onmouseup="fan_on = fan_on===0?1:0; show_hide(red_fan,fan_on);" class='hotspot' onmouseover="changecolor(f1,'#0052E1');" onmouseout="changecolor(f1,'#000000');">
<rect x='0' y='0' width='24' height='24' fill='#FFFFFF'/>
<path id='f1' d="M10,11 L10,10 L6,10 A 7,5 0 0 1 7,1 L8,1 A 3,2.5 0 0 1 9,5 L9,9 L10,9 L10,10 L12,10 L12,6 A 5,7 0 0 1 21,7 L21,8 A 2.5,3 0 0 1 17,9 L13,9 L13,10 L12,10 L12,12 L16,12 A 7,5 0 0 1 15,21 L14,21 A 3,2.5 0 0 1 13,17 L13,13 L12,13 L12,12 L10,12 L10,16 A 5,7 0 0 1 1,15 L1,14 A 2.5,3 0 0 1 5,13 L9,13 L9,12 10,12 z" />
<polygon id='red_fan' points="19,0 21,2 2,21 0,19" fill="#FF0000" stroke="#FFFFFF" opacity='0'/>
</g>
</svg>
</td><td>
<div id='rangefanspeed' min="0" max="100" class='sliderrange' onclick ="rangeclicked(event,this);" customthumb='thumbfanspeed'>
<svg width='322' height='20' viewbox='0 0 322 20'>
<defs>
<pattern id='basicPattern' x='10' y='0' width='4' height='20' patternUnits='userSpaceOnUse'>
<rect x='0' y='0' width='4' height='20' stroke-width='0.2' stroke= '#0D2F38' fill='#77AEBD'/ >
</pattern>
</defs>
<rect x='1' y='4' width='320' height='12' stroke= '#0D2F38' stroke-width='1' rx='6' ry='6' fill='url(#basicPattern)'/>
<text x='13' y='14' style='font-weight:600;font-size:10;font-family:sans-serif;fill:#000000; pointer-events:none;'>Fan</text>
</svg>
</div>
<div id='thumbfanspeed' class='sliderthumb' render='fanspeedrender' customrange='rangefanspeed' >
<svg width='8' height='20' viewbox='0 0 8 20'><path d='M 3.5,0 L7,5 L7,14 L3.5,19 L0,14 L0,5 z' /></svg>
</div>
</td><td width='auto'><input type='number' id='fanspeedrender' min='0' max='100' step='1' style='width: 4em;' onchange='movethumbat(thumbfanspeed, this.value);'></td></tr>
<tr><td>
<svg width="29" height="25" xmlns="http://www.w3.org/2000/svg" version="1.1">
<g id='bed' onmouseup="bed_on = bed_on===0?1:0; show_hide(red_bed,bed_on);" class='hotspot' onmouseover="changestroke(b1,b2,b3,b4,b5,'#0052E1'); " onmouseout="changestroke(b1,b2,b3,b4,b5,'#000000');">
<rect x='0' y='0' width='24' height='24' fill='#FFFFFF'/>
<polygon id='b1' points="5,0 24,0 28,19 1,19" fill="none" stroke="#000000" stroke-width='2'/>
<line id='b2' x1="11" y1="0" x2="10" y2="19" stroke="#000000" stroke-width='2' />
<line id='b3' x1="18" y1="0" x2="19" y2="19" stroke="#000000" stroke-width='2' />
<line id='b4' x1="3" y1="13" x2="26" y2="13" stroke="#000000" stroke-width='2' />
<line id='b5' x1="4" y1="6" x2="25" y2="6" stroke="#000000" stroke-width='2' />
<polygon id='red_bed' points="21,0 23,2 4,21 2,19" fill="#FF0000" stroke="#FFFFFF" opacity='0'/>
</g>
</svg>
</td><td >
<div id='rangebed' min='0' max='150' class='sliderrange' onclick ='rangeclicked(event,this);' customthumb='thumbbed'>
<svg width='322' height='22' viewbox='0 0 322 22'>
<defs>
<linearGradient id='grad1' x1='0%' y1='0%' x2='100%' y2='0%'><stop offset='0%' style='stop-color:#0007FE;stop-opacity:1' />
<stop offset='100%' style='stop-color:#00FAFE;stop-opacity:1' /></linearGradient>
<linearGradient id='grad2' x1='0%' y1='0%' x2='100%' y2='0%'><stop offset='0%' style='stop-color:#00FAFE;stop-opacity:1' />
<stop offset='100%' style='stop-color:#00FF00;stop-opacity:1' /></linearGradient>
<linearGradient id='grad3' x1='0%' y1='0%' x2='100%' y2='0%'><stop offset='0%' style='stop-color:#00FF00;stop-opacity:1' />
<stop offset='100%' style='stop-color:#FAFD00;stop-opacity:1' /></linearGradient>
<linearGradient id='grad4' x1='0%' y1='0%' x2='100%' y2='0%'><stop offset='0%' style='stop-color:#FAFD00;stop-opacity:1' />
<stop offset='100%' style='stop-color:#FE0700;stop-opacity:1' /></linearGradient>
</defs>
<rect x='1' y='4' width='80' height='14' fill='url(#grad1)' />
<rect x='80' y='4' width='80' height='14' fill='url(#grad2)' />
<rect x='160' y='4' width='80' height='14' fill='url(#grad3)' />
<rect x='240' y='4' width='80' height='14' fill='url(#grad4)' />
<rect x='1' y='4' width='320' height='14' fill='none' stroke-width='1' stroke='#C3BDB5' />
<text x='13' y='14' style='font-weight:600;font-size:10;font-family:sans-serif;fill:#FFFFFF; '>Bed Temperature</text>
<text x='270' y='14' style='font-weight:600;font-size:10;font-family:sans-serif;fill:#FFFFFF; '>60.43&deg;C</text>
<path d='M150,5 L153,11 L150,17 L147,11 z' fill='#000000'>
</svg>
</div>
<div id='thumbbed' class='sliderthumb' render='bedrender' customrange='rangebed' >
<svg width='8' height='24' viewbox='0 0 8 24'><path d='M 0,0 L3,5 L3,17 L0,22 L7,22 L4,17 L4,5 L7,0 z' /></svg>
</div>
</td><td width='auto'><input type='number' id='bedrender' max='150' min='130' step='1' style='width: 4em;' onchange='movethumbat(thumbbed, this.value);'></td></tr>
<tr><td>
<svg width="26" height="26" xmlns="http://www.w3.org/2000/svg" version="1.1">
<g id='Ext1' onmouseup="ext1_on = ext1_on===0?1:0; show_hide(red_ext1,ext1_on);" class='hotspot' onmouseover="changecolor(e11,e12,'#0052E1');" onmouseout="changecolor(e11,e12,'#000000');">
<rect x='0' y='0' width='24' height='24' fill='#FFFFFF'/>
<path id='e11' d="M1,0 L8,0 L8,15 L4.5,21 L1,15 z" />
<text id='e12' x="10" y="15.5" class="slide">1</text>
<polygon id='red_ext1' points="21,0 23,2 4,21 2,19" fill="#FF0000" stroke="#FFFFFF" opacity='0'/>
</g>
</svg>
</td><td >
<div id='rangeext1' min="0" max="300" class='sliderrange' onclick ="rangeclicked(event,this);" customthumb='thumbext1'>
<svg width='322' height='22' viewbox='0 0 322 22'>
<defs>
<linearGradient id='grad1' x1='0%' y1='0%' x2='100%' y2='0%'><stop offset='0%' style='stop-color:#0007FE;stop-opacity:1' />
<stop offset='100%' style='stop-color:#00FAFE;stop-opacity:1' /></linearGradient>
<linearGradient id='grad2' x1='0%' y1='0%' x2='100%' y2='0%'><stop offset='0%' style='stop-color:#00FAFE;stop-opacity:1' />
<stop offset='100%' style='stop-color:#00FF00;stop-opacity:1' /></linearGradient>
<linearGradient id='grad3' x1='0%' y1='0%' x2='100%' y2='0%'><stop offset='0%' style='stop-color:#00FF00;stop-opacity:1' />
<stop offset='100%' style='stop-color:#FAFD00;stop-opacity:1' /></linearGradient>
<linearGradient id='grad4' x1='0%' y1='0%' x2='100%' y2='0%'><stop offset='0%' style='stop-color:#FAFD00;stop-opacity:1' />
<stop offset='100%' style='stop-color:#FE0700;stop-opacity:1' /></linearGradient>
</defs>
<rect x='1' y='4' width='80' height='14' fill='url(#grad1)' />
<rect x='80' y='4' width='80' height='14' fill='url(#grad2)' />
<rect x='160' y='4' width='80' height='14' fill='url(#grad3)' />
<rect x='240' y='4' width='80' height='14' fill='url(#grad4)' />
<rect x='1' y='4' width='320' height='14' fill='none' stroke-width='1' stroke='#C3BDB5' />
<text x='13' y='14' style='font-weight:600;font-size:10;font-family:sans-serif;fill:#FFFFFF; '>Extruder 1</text>
<text x='270' y='14' style='font-weight:600;font-size:10;font-family:sans-serif;fill:#FFFFFF; '>180.03&deg;C</text>
<path d='M150,5 L153,11 L150,17 L147,11 z' fill='#000000'>
</svg>
</div>
<div id='thumbext1' class='sliderthumb' render='ext1render' customrange='rangeext1' >
<svg width='8' height='24' viewbox='0 0 8 24'><path d='M 0,0 L3,5 L3,17 L0,22 L7,22 L4,17 L4,5 L7,0 z' /></svg></div>
</td><td width='auto'><input type='number' id='ext1render' min='0' max='300' step='1' style='width: 4em;' onchange='movethumbat(thumbext1, this.value);'></td></tr>
<tr><td>
<svg width="26" height="26" xmlns="http://www.w3.org/2000/svg" version="1.1">
<g id='Ext2' onmouseup="ext2_on = ext2_on===0?1:0; show_hide(red_ext2,ext2_on);" class='hotspot' onmouseover="changecolor(e21,e22,'#0052E1');" onmouseout="changecolor(e21,e22,'#000000');">
<rect x='0' y='0' width='24' height='24' fill='#FFFFFF'/>
<path id='e21' d="M1,0 L8,0 L8,15 L4.5,21 L1,15 z" />
<text id='e22' x="10" y="15.5" class="slide">2</text>
<polygon id='red_ext2' points="21,0 23,2 4,21 2,19" fill="#FF0000" stroke="#FFFFFF" opacity='0'/>
</g>
</svg>
</td>
<td >
<div id='rangeext2' min="0" max="300" class='sliderrange' onclick ="rangeclicked(event,this);" customthumb='thumbext2'>
<svg width='322' height='22' viewbox='0 0 322 22'>
<defs>
<linearGradient id='grad1' x1='0%' y1='0%' x2='100%' y2='0%'><stop offset='0%' style='stop-color:#0007FE;stop-opacity:1' />
<stop offset='100%' style='stop-color:#00FAFE;stop-opacity:1' /></linearGradient>
<linearGradient id='grad2' x1='0%' y1='0%' x2='100%' y2='0%'><stop offset='0%' style='stop-color:#00FAFE;stop-opacity:1' />
<stop offset='100%' style='stop-color:#00FF00;stop-opacity:1' /></linearGradient>
<linearGradient id='grad3' x1='0%' y1='0%' x2='100%' y2='0%'><stop offset='0%' style='stop-color:#00FF00;stop-opacity:1' />
<stop offset='100%' style='stop-color:#FAFD00;stop-opacity:1' /></linearGradient>
<linearGradient id='grad4' x1='0%' y1='0%' x2='100%' y2='0%'><stop offset='0%' style='stop-color:#FAFD00;stop-opacity:1' />
<stop offset='100%' style='stop-color:#FE0700;stop-opacity:1' /></linearGradient>
</defs>
<rect x='1' y='4' width='80' height='14' fill='url(#grad1)' />
<rect x='80' y='4' width='80' height='14' fill='url(#grad2)' />
<rect x='160' y='4' width='80' height='14' fill='url(#grad3)' />
<rect x='240' y='4' width='80' height='14' fill='url(#grad4)' />
<rect x='1' y='4' width='320' height='14' fill='none' stroke-width='1' stroke='#C3BDB5' />
<text x='13' y='14' style='font-weight:600;font-size:10;font-family:sans-serif;fill:#FFFFFF; '>Extruder 2</text>
<text x='270' y='14' style='font-weight:600;font-size:10;font-family:sans-serif;fill:#FFFFFF; '>180.03&deg;C</text>
<path d='M150,5 L153,11 L150,17 L147,11 z' fill='#000000'>
</svg>
</div>
<div id='thumbext2' class='sliderthumb' render='ext2render' customrange='rangeext2' >
<svg width='8' height='24' viewbox='0 0 8 24'><path d='M 0,0 L3,5 L3,17 L0,22 L7,22 L4,17 L4,5 L7,0 z' /></svg> </div>
</td><td width='auto'><input type='number' id='ext2render' min='0' max='300' step='1' style='width: 4em;' onchange='movethumbat(thumbext2, this.value);'></td></tr>
</table>
</div>
<script>
initrange( rangefeedrate);
initthumb( thumbfeedrate);
initrange( rangeflowrate);
initthumb( thumbflowrate);
initrange( rangefanspeed);
initthumb( thumbfanspeed);
initrange( rangebed);
initthumb( thumbbed);
initrange( rangeext1);
initthumb( thumbext1);
initrange( rangeext2);
initthumb(thumbext2);
extruderlist.style.left=342;
var rb = positionbar.getBoundingClientRect();
var re = extruderlist.getBoundingClientRect();
extruderlist.style.top = rb.top + (( (rb.bottom-rb.top) - (re.bottom-re.top))/2);
</script>
</BODY>
</HTML>

View File

@ -1,115 +0,0 @@
* Change STA SSID
[ESP100]<SSID>
if authentication is on, need admin password
[ESP100]<SSID>pwd=<admin password>
* Change STA Password
[ESP101]<Password>
if authentication is on, need admin password
[ESP101]<Password>pwd=<admin password>
* Change Hostname
[ESP102]<hostname>
if authentication is on, need admin password
[ESP102]<hostname>pwd=<admin password>
* Change Wifi mode (STA/AP)
[ESP103]<mode>
if authentication is on, need admin password
[ESP103]<mode>pwd=<admin password>
* Change STA IP mode (DHCP/STATIC)
[ESP104]<mode>
if authentication is on, need admin password
[ESP104]<mode>pwd=<admin password>
* Change AP SSID
[ESP105]<SSID>
if authentication is on, need admin password
[ESP105]<SSID>pwd=<admin password>
* Change AP Password
[ESP106]<Password>
if authentication is on, need admin password
[ESP106]<Password>pwd=<admin password>
* Change AP IP mode (DHCP/STATIC)
[ESP107]<mode>
if authentication is on, need admin password
[ESP107]<mode>pwd=<admin password>
* Set wifi on/off
[ESP110]<state>
state can be ON, OFF, RESTART
if authentication is on, need admin password
[ESP110]<state>pwd=<admin password>
* Get current IP
[ESP111]<header answer>
* Get hostname
[ESP112]<header answer>
* Restart time client
[ESP114]
*Get/Set pin value
[ESP201]P<pin> V<value> [PULLUP=YES RAW=YES]pwd=<admin password>
if no V<value> get P<pin> value
if V<value> 0/1 set INPUT_PULLUP value, but for GPIO16 INPUT_PULLDOWN_16
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
*Save data string
[ESP300]<data> pwd=<user/admin password>
*Get data string
[ESP301] pwd=<user/admin password>
*Get full EEPROM settings content
but do not give any passwords
can filter if only need wifi or printer
[ESP400]<network/printer>
*Set EEPROM setting
position in EEPROM, type: B(byte), I(integer/long), S(string), A(IP address / mask)
[ESP401]P=<position> T=<type> V=<value> pwd=<user/admin password>
*Get available AP list (limited to 30)
output is JSON or plain text according parameter
[ESP410]<plain>
*Get current settings of ESP3D
output is JSON or plain text according parameter
[ESP420]<plain>
* Get/Set ESP mode
cmd can be RESET, SAFEMODE, CONFIG, RESTART
[ESP444]<cmd>
if authentication is on, need admin password for RESET, RESTART and SAFEMODE
[ESP444]<cmd>pwd=<admin password>
* Change / Reset user password
[ESP555]<password>pwd=<admin password>
if no password set it use default one
* Read SPIFFS file and send each line to serial
[ESP700]<filename>
* Format SPIFFS
[ESP710]FORMAT pwd=<admin password>
* SPIFFS total size and used size
[ESP720]<header answer>
* Get fw version and basic information
[ESP800]<header answer>
* Get fw target
[ESP801]<header answer>
* Clear status/error/info list
cmd can be ALL, ERROR, INFO, STATUS
[ESP999]<cmd>

View File

@ -1 +0,0 @@
bin2c /infile tool.html.gz /outfile out.h /targetfolder .

View File

@ -1,125 +0,0 @@
var gulp = require('gulp'),
jshint = require('gulp-jshint'),
gulpif = require('gulp-if'),
concat = require('gulp-concat'),
uglify = require('gulp-uglify'),
cleanCSS = require('gulp-clean-css'),
removeCode = require('gulp-remove-code'),
merge = require('merge-stream'),
del = require('del'),
zip = require('gulp-zip'),
gzip = require('gulp-gzip'),
htmlmin = require('gulp-htmlmin'),
replace = require('gulp-replace'),
fs = require('fs'),
smoosher = require('gulp-smoosher');
var demoMode = false;
var testMode = false;
function clean() {
return del(['dist']);
}
function clean2() {
return del(['dist/js', 'dist/css']);
}
function lint() {
return gulp.src('www/js/**/script.js')
.pipe(jshint())
.pipe(jshint.reporter('default'));
}
function Copytest() {
return merge(
gulp.src(['www/tool.html'])
.pipe(removeCode({production: false}))
.pipe(gulp.dest('dist')),
gulp.src(['www/images/**/*.*'])
.pipe(gulp.dest('dist/images'))
)
}
function Copy() {
return merge(
gulp.src(['www/tool.html'])
.pipe(removeCode({production: true}))
.pipe(gulp.dest('dist')),
gulp.src(['www/images/**/*.*'])
.pipe(gulp.dest('dist/images'))
)
}
function concatApptest() {
return merge(
gulp.src([ 'www/js/**/*.js'])
.pipe(concat('script.js'))
.pipe(removeCode({production: false}))
.pipe(gulp.dest('./dist/js')),
gulp.src([ 'www/css/**/*.css'])
.pipe(concat('style.css'))
.pipe(gulp.dest('./dist/css/'))
)
}
function concatApp() {
return merge(
gulp.src([ 'www/js/**/*.js'])
.pipe(concat('script.js'))
.pipe(removeCode({production: true}))
.pipe(gulp.dest('./dist/js')),
gulp.src([ 'www/css/**/*.css'])
.pipe(concat('style.css'))
.pipe(gulp.dest('./dist/css/'))
)
}
function minifyApp() {
return merge(
gulp.src(['dist/js/script.js'])
.pipe(uglify({mangle: true}))
.pipe(gulp.dest('./dist/js/')),
gulp.src('dist/css/style.css')
.pipe(cleanCSS({debug: true}, function(details) {
console.log(details.name + ': ' + details.stats.originalSize);
console.log(details.name + ': ' + details.stats.minifiedSize);
}))
.pipe(gulp.dest('./dist/css/')),
gulp.src('dist/tool.html')
.pipe(htmlmin({collapseWhitespace: true, minifyCSS: true}))
.pipe(gulp.dest('dist'))
)
}
function smoosh() {
return gulp.src('dist/tool.html')
.pipe(smoosher())
.pipe(gulp.dest('dist'))
}
function compress() {
return gulp.src('dist/tool.html')
.pipe(gzip())
.pipe(gulp.dest('.'));
}
gulp.task(clean);
gulp.task(lint);
gulp.task(Copy);
gulp.task(Copytest);
gulp.task(concatApp);
gulp.task(concatApptest);
gulp.task(minifyApp);
gulp.task(smoosh);
gulp.task(clean2);
var defaultSeries = gulp.series(clean, lint, Copy, concatApp, smoosh);
var packageSeries = gulp.series(clean, lint, Copy, concatApp,minifyApp, smoosh, compress, clean2);
gulp.task('default', defaultSeries);
gulp.task('package', packageSeries);

View File

@ -1,15 +0,0 @@
npm install --global gulp-cli
npm install --save-dev gulp
npm install --save-dev gulp-jshint
npm install --save-dev jshint
npm install --save-dev gulp-if
npm install --save-dev gulp-concat
npm install --save-dev gulp-uglify
npm install --save-dev gulp-clean-css
npm install --save-dev gulp-remove-code
npm install --save-dev del
npm install --save-dev gulp-zip
npm install --save-dev gulp-gzip
npm install --save-dev gulp-htmlmin
npm install --save-dev gulp-replace
npm install --save-dev gulp-smoosher

View File

@ -1,30 +0,0 @@
{
"name": "embedded4ESP3D",
"description": "Embedded files for ESP3D",
"devDependencies": {
"del": "^2.2.2",
"deprecated": "0.0.1",
"fs": "0.0.1-security",
"gulp": "github:gulpjs/gulp#4.0",
"gulp-bytediff": "^1.0.0",
"gulp-cdnizer": "^1.1.7",
"gulp-clean-css": "^2.4.0",
"gulp-concat": "^2.6.1",
"gulp-gzip": "^1.4.0",
"gulp-htmlmin": "^3.0.0",
"gulp-if": "^2.0.2",
"gulp-jshint": "^2.0.4",
"gulp-ng-annotate": "^2.0.0",
"gulp-remove-code": "^1.0.2",
"gulp-replace": "^0.5.4",
"gulp-smoosher": "0.0.9",
"gulp-uglify": "^2.1.2",
"gulp-util": "^3.0.1",
"gulp-zip": "^3.2.0",
"jshint": "^2.9.5",
"merge-stream": "^1.0.1"
},
"repository": "https://github.com/luc-github/ESP3D",
"author": "Luc LEBOSSE",
"license": "(ISC OR GPL-3.0)"
}

Binary file not shown.

View File

@ -1,139 +0,0 @@
html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%; font-size:10px;}
body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333333;background-color:#ffffff;}
.container{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px;}
table{border:0px;border-spacing:0;max-width:100%;}
.table-bordered{ width:100%; border:1px solid #dddddd;margin-bottom:20px;}
td{white-space:nowrap; padding:2mm;}
th{text-align:left;}
.table>thead>tr>th,.table>tbody>tr>th,.table>thead>tr>td,.table>tbody>tr>td{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #dddddd;}
.table-bordered>thead>tr>th,.table-bordered>tbody>tr>th,.table-bordered>thead>tr>td,.table-bordered>tbody>tr>td{border:1px solid #dddddd;}
.table-bordered>thead>tr>th,.table-bordered>thead>tr>td{border-bottom-width:2px;}
.table-striped>tbody>tr:nth-of-type(odd){background-color:#f9f9f9;}
@media (min-width:768px){.container{width:750px;}}
@media (min-width:992px){.container{width:970px;}}
@media (min-width:1200px){.container{width:1170px;}}
.nav{ width:100%; color:#cccccc;padding-left:10;padding-right:10;list-style:none;background-color:#333333;border-radius:6px ;margin-bottom:20px;}
a{position:relative;display:block;padding:10px 15px;text-decoration:none;color:#cccccc;}
.active{color:#ffffff;background-color:#000000;}
.active a,a:hover,a:focus{color:#FFFFFF;}
.panel{margin-bottom:20px;background-color:#ffffff;border:1px solid #dddddd;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.05);box-shadow:0 1px 1px rgba(0,0,0,0.05);}
.panel-body{padding:15px;}
.panel-heading{padding:10px 15px;color:#333333;background-color:#f5f5f5;border-color:#dddddd;border-top-right-radius:3px;border-top-left-radius:3px;border-bottom:1px solid #dddddd;}
label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:bold;}
.text-info{color:#31708f;}
.form-control{display:block;width:auto;height:34px;padding:6px 12px;font-size:14px;line-height:1.42857143;color:#555555;background-color:#ffffff
;background-image:none;border:1px solid #cccccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);
* -webkit-transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;
* transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,0.6);
* box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,0.6);}
.form-group{margin-bottom:15px;}
.btn{display:inline-block;margin-bottom:0;font-weight:normal;text-align:center;vertical-align:middle;-ms-touch-action:manipulation; touch-action:manipulation;cursor:pointer;
background-image:none;border:1px solid transparent;white-space:nowrap;padding:6px 12px;font-size:14px;line-height:1.42857143;border-radius:4px;
* -webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;}
.btn-primary{color:#ffffff;background-color:#337ab7;border-color:#2e6da4;}
.btn-primary:focus,.btn-primary:active,.btn-primary:hover,.btn-primary.focus,.btn-primary.active,.btn-primary.hover{color:#ffffff;background-color:#286090;border-color:#122b40;}
caption{padding-top:8px;padding-bottom:8px;color:#777777;text-align:left;}
.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px;}
.alert-success{background-color:#dff0d8;border-color:#d6e9c6;color:#3c763d;}
.alert-danger{background-color:#f2dede;border-color:#ebccd1;color:#a94442;}
.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);}
.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #ce8483;}
.has-error .control-label{color:#a94442;}
.has-success .form-control {border-color: #3c763d;-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);}
.has-success .form-control:focus {border-color: #2b542c;-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168;box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168;}
.has-success .control-label{color: #3c763d;}
.btn-danger{color:#ffffff;background-color:#d9534f;border-color:#d43f3a;}
.btn-danger:focus,.btn-danger:active,.btn-danger:hover,.btn-danger.focus,.btn-danger.active,.btn-danger.hover{color: #ffffff;background-color:#c9302c;border-color:#761c19;}
.btnimg {cursor:hand; border-radius:6px ;;border:1px solid #FFFFFF;}
.btnimg:hover{background-color:#F0F0F0;border-color:#00FFFF;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #ce8483;}
.btnroundimg {cursor:hand; border-radius:30px;}
.btnroundimg:hover{background-color:#F0F0F0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #ce8483;}
.blacklink {color:#000000;}
.blacklink:hover, .filelink:focus {color:#0094FF;}
input[type="file"]::-webkit-file-upload-button{display:inline-block;margin-bottom:0;font-weight:normal;text-align:center;vertical-align:middle;-ms-touch-action:manipulation; touch-action:manipulation;cursor:pointer;
background-image:none;border:1px solid transparent;white-space:nowrap;padding:6px 12px;font-size:14px;line-height:1.42857143;border-radius:4px;
* -webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none; color: #ffffff;background-color: #5bc0de;border-color: #46b8da;}
input[type="file"]::-webkit-file-upload-button:focus{display:inline-block;margin-bottom:0;font-weight:normal;text-align:center;vertical-align:middle;-ms-touch-action:manipulation; touch-action:manipulation;cursor:pointer;
background-image:none;border:1px solid transparent;white-space:nowrap;padding:6px 12px;font-size:14px;line-height:1.42857143;border-radius:4px;
* -webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none; color: #ffffff;background-color: #31b0d5;border-color: #1b6d85;}
input[type="file"]::-webkit-file-upload-button:hover{display:inline-block;margin-bottom:0;font-weight:normal;text-align:center;vertical-align:middle;-ms-touch-action:manipulation; touch-action:manipulation;cursor:pointer;
background-image:none;border:1px solid transparent;white-space:nowrap;padding:6px 12px;font-size:14px;line-height:1.42857143;border-radius:4px;
* -webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none; color: #ffffff;background-color: #31b0d5;border-color: #269abc;}
.filelink {color:#000000;}
.filelink:hover, .filelink:focus {color:#0094FF;}
.panel-footer{padding:10px 15px;color:#31708f;background-color:#f5f5f5;border-color:#dddddd;border-top:1px solid #dddddd;}
.loader {
border: 4px solid #f3f3f3; /* Light grey */
border-top: 4px solid #3498db; /* Blue */
border-radius: 50%;
width: 12px;
height: 12px;
animation: spin 2s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.panel-footer{padding:10px 15px;color:#31708f;background-color:#f5f5f5;border-color:#dddddd;border-top:1px solid #dddddd;}
.modal {
display: none; /* Hidden by default */
position: fixed; /* Stay in place */
z-index: 10000; /* Sit on top */
padding-top: 100px; /* Location of the box */
left: 0;
top: 0;
width: 100%; /* Full width */
height: 100%; /* Full height */
overflow: auto; /* Enable scroll if needed */
background-color: rgb(0,0,0); /* Fallback color */
background-color: rgba(0,0,0,0.4); /* Black w/ opacity */
}
/* Modal Content */
.modal-content {
border-top-left-radius: 10px;
border-top-right-radius: 10px;
border-bottom-left-radius: 10px;
border-bottom-right-radius: 10px;
border: 2px solid #337AB7;
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
position: relative;
margin: auto;
padding: 0;
background-color: #fefefe;
}
.modal-header {
padding: 2px 16px;
color: #0f0f0f;
background-color: #f2f2f2;
border-top-left-radius: 10px;
border-top-right-radius: 10px;
border-bottom: 1px solid #cfcfcf;
}
.modal-body {padding: 10px 16px;}
.modal-footer {
padding: 16px 16px;
height: 4.5em;
color: #0f0f0f;
background-color: #f2f2f2;
border-top: 1px solid #cfcfcf;
border-bottom-left-radius: 10px;
border-bottom-right-radius: 10px;
}
@media (min-width: 768px) {
.modal-content {
width: 580px;
}
}
@media screen and (max-width: 767px) {
.modal-content {
width: 100%;
}
}

View File

@ -1,249 +0,0 @@
var currentpath = "/";
function navbar(){
var content="<table><tr>";
var tlist = currentpath.split("/");
var path="/";
var nb = 1;
content+="<td class='btnimg' onclick=\"currentpath='/'; SendCommand('list','all');\">/</td>";
while (nb < (tlist.length-1))
{
path+=tlist[nb] + "/";
content+="<td class='btnimg' onclick=\"currentpath='"+path+"'; SendCommand('list','all');\">"+tlist[nb] +"</td><td>/</td>";
nb++;
}
content+="</tr></table>";
return content;
}
function trash_icon(){
var content ="<svg width='24' height='24' viewBox='0 0 128 128'>";
content +="<rect x='52' y='12' rx='6' ry='6' width='25' height='7' style='fill:red;' />";
content +="<rect x='52' y='16' width='25' height='2' style='fill:white;' />";
content +="<rect x='30' y='18' rx='6' ry='6' width='67' height='100' style='fill:red;' />";
content +="<rect x='20' y='18' rx='10' ry='10' width='87' height='14' style='fill:red;' />";
content +="<rect x='20' y='29' width='87' height='3' style='fill:white;' />";
content +="<rect x='40' y='43' rx='7' ry='7' width='7' height='63' style='fill:white;' />";
content +="<rect x='60' y='43' rx='7' ry='7' width='7' height='63' style='fill:white;' />";
content +="<rect x='80' y='43' rx='7' ry='7' width='7' height='63' style='fill:white;' /></svg>";
return content;
}
function back_icon(){
var content ="<svg width='24' height='24' viewBox='0 0 24 24'><path d='M7,3 L2,8 L7,13 L7,10 L17,10 L18,11 L18,15 L17,16 L10,16 L9,17 L9,19 L10,20 L20,20 L22,18 L22,8 L20,6 L7,6 z' stroke='black' fill='white' /></svg>";
return content;
}
function select_dir(directoryname){
currentpath+=directoryname + "/";
SendCommand('list','all');
}
function compareStrings(a, b) {
// case-insensitive comparison
a = a.toLowerCase();
b = b.toLowerCase();
return (a < b) ? -1 : (a > b) ? 1 : 0;
}
function dispatchfilestatus(jsonresponse)
{
var content ="";
content ="&nbsp;&nbsp;Status: "+jsonresponse.status;
content +="&nbsp;&nbsp;|&nbsp;&nbsp;Total space: "+jsonresponse.total;
content +="&nbsp;&nbsp;|&nbsp;&nbsp;Used space: "+jsonresponse.used;
content +="&nbsp;&nbsp;|&nbsp;&nbsp;Occupation: ";
content +="<meter min='0' max='100' high='90' value='"+jsonresponse.occupation +"'></meter>&nbsp;"+jsonresponse.occupation +"%";
document.getElementById('status').innerHTML=content;
content ="";
if (currentpath!="/")
{
var pos = currentpath.lastIndexOf("/",currentpath.length-2);
var previouspath = currentpath.slice(0,pos+1);
content +="<tr style='cursor:hand;' onclick=\"currentpath='"+previouspath+"'; SendCommand('list','all');\"><td >"+back_icon()+"</td><td colspan='4'> Up..</td></tr>";
}
jsonresponse.files.sort(function(a, b) {
return compareStrings(a.name, b.name);
});
for (var i1=0;i1 <jsonresponse.files.length;i1++){
//first display files
if (String(jsonresponse.files[i1].size) != "-1")
{
content +="<TR>";
content +="<td><svg height='24' width='24' viewBox='0 0 24 24' > <path d='M1,2 L1,21 L2,22 L16,22 L17,21 L17,6 L12,6 L12,1 L2,1 z' stroke='black' fill='white' /><line x1='12' y1='1' x2='17' y2='6' stroke='black' stroke-width='1'/>";
content +="<line x1='5' y1='10' x2='13' y2='10' stroke='black' stroke-width='1'/> <line x1='5' y1='14' x2='13' y2='14' stroke='black' stroke-width='1'/> <line x1='5' y1='18' x2='13' y2='18' stroke='black' stroke-width='1'/></svg></td>";
content +="<TD class='btnimg' style=\"padding:0px;\"><a href=\""+jsonresponse.path+jsonresponse.files[i1].name+"\" target=_blank><div class=\"blacklink\">";
content +=jsonresponse.files[i1].name;
content +="</div></a></TD><TD>";
content +=jsonresponse.files[i1].size;
content +="</TD><TD width='0%'><div class=\"btnimg\" onclick=\"Delete('"+jsonresponse.files[i1].name+"')\">";
content +=trash_icon();
content +="</div></TD><td></td></TR>";
}
}
//then display directories
for (var i2=0;i2 <jsonresponse.files.length;i2++){
if (String(jsonresponse.files[i2].size) == "-1")
{
content +="<TR>";
content+="<td><svg height='24' width='24' viewBox='0 0 24 24' ><path d='M19,11 L19,8 L18,7 L8,7 L8,5 L7,4 L2,4 L1,5 L1,22 L19,22 L20,21 L23,11 L5,11 L2,21 L1,22' stroke='black' fill='white' /></svg></td>";
content +="<TD class='btnimg blacklink' style='padding:10px 15px;' onclick=\"select_dir('" + jsonresponse.files[i2].name+"');\">";
content +=jsonresponse.files[i2].name;
content +="</TD><TD>";
content +="</TD><TD width='0%'><div class=\"btnimg\" onclick=\"Deletedir('"+jsonresponse.files[i2].name+"')\">";
content +=trash_icon();
content +="</div></TD><td></td></TR>";
}
}
document.getElementById('file_list').innerHTML=content;
document.getElementById('path').innerHTML=navbar();}
function Delete(filename){
if (confirm("Confirm deletion of file: " + filename))SendCommand("delete",filename);
}
function Deletedir(filename){
if (confirm("Confirm deletion of directory: " + filename))SendCommand("deletedir",filename);
}
function Createdir(){
var filename = prompt("Please enter directory name", "");
if (filename != null) {
SendCommand("createdir",filename.trim());
}
}
function SendCommand(action,filename){
var xmlhttp = new XMLHttpRequest();
var url = "/files?action="+action;
url += "&filename="+encodeURI(filename);
url += "&path="+encodeURI(currentpath);
document.getElementById('loader').style.visibility="visible";
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 ) {
if(xmlhttp.status == 200) {
var jsonresponse = JSON.parse(xmlhttp.responseText);
document.getElementById('loader').style.visibility="hidden";
dispatchfilestatus(jsonresponse);}
else SubmitRequest ()
}
};
xmlhttp.open("GET", url, true);
xmlhttp.send();
}
function Sendfile(){
var files = document.getElementById('file-select').files;
if (files.length==0)return;
document.getElementById('upload-button').value = "Uploading...";
document.getElementById('prg').style.visibility = "visible";
var formData = new FormData();
formData.append('path', currentpath);
for (var i3 = 0; i3 < files.length; i3++) {
var file = files[i3];
formData.append('myfiles[]', file, currentpath+file.name);}
var xmlhttp = new XMLHttpRequest();
xmlhttp.open('POST', '/files', true);
//progress upload event
xmlhttp.upload.addEventListener("progress", updateProgress, false);
//progress function
function updateProgress (oEvent) {
if (oEvent.lengthComputable) {
var percentComplete = (oEvent.loaded / oEvent.total)*100;
document.getElementById('prg').value=percentComplete;
document.getElementById('upload-button').value = "Uploading ..." + percentComplete.toFixed(0)+"%" ;
} else {
// Impossible because size is unknown
}
}
xmlhttp.onload = function () {
if (xmlhttp.status === 200) {
document.getElementById('upload-button').value = 'Upload';
document.getElementById('prg').style.visibility = "hidden";
document.getElementById('file-select').value="";
var jsonresponse = JSON.parse(xmlhttp.responseText);
dispatchfilestatus(jsonresponse);
} else alert('An error occurred!');
};
xmlhttp.send(formData);
}
window.onload = function() {
SendCommand('list','all');
};
function Uploadfile(){
if (!confirm("Confirm Firmware Update ?"))return;
var files = document.getElementById('fw-select').files;
if (files.length==0)return;
document.getElementById('uploadfw-button').style.visibility = 'hidden';
document.getElementById('fw-select').style.visibility = 'hidden';
document.getElementById('msg').style.visibility = "visible";
document.getElementById('msg').innerHTML="";
document.getElementById('SPIFFS').style.display = "none";
document.getElementById('prgfw').style.visibility = "visible";
var formData = new FormData();
for (var i4 = 0; i4 < files.length; i4++) {
var file = files[i4];
formData.append('myfile[]', file, "/"+file.name);}
var xmlhttp = new XMLHttpRequest();
xmlhttp.open('POST', '/updatefw', true);
//progress upload event
xmlhttp.upload.addEventListener("progress", updateProgress, false);
//progress function
function updateProgress (oEvent) {
if (oEvent.lengthComputable) {
var percentComplete = (oEvent.loaded / oEvent.total)*100;
document.getElementById('prgfw').value=percentComplete;
document.getElementById('msg').innerHTML = "Uploading ..." + percentComplete.toFixed(0)+"%" ;
} else {
// Impossible because size is unknown
}
}
xmlhttp.onload = function () {
if (xmlhttp.status === 200) {
document.getElementById('uploadfw-button').value = 'Upload';
document.getElementById('msg').innerHTML="Restarting, please wait....";
document.getElementById('counter').style.visibility = "visible";
document.getElementById('uploadfw-button').style.visibility = 'hidden';
document.getElementById('uploadfw-button').style.width = '0px';
document.getElementById('fw-select').value="";
document.getElementById('fw-select').style.visibility = 'hidden';
document.getElementById('fw-select').style.width = '0px';
var jsonresponse = JSON.parse(xmlhttp.responseText);
if (jsonresponse.status=='1' || jsonresponse.status=='4' || jsonresponse.status=='1')alert("Update failed");
if (jsonresponse.status=='2')alert('Update canceled!');
else if (jsonresponse.status=='3')
{
var i5 = 0;
var interval;
var x = document.getElementById("prgfw");
x.max=40;
interval = setInterval(function(){
i5=i5+1;
var x = document.getElementById("prgfw");
x.value=i5;
document.getElementById('counter').innerHTML=41-i5;
if (i5>40)
{
clearInterval(interval);
location.reload();
}
},1000);
}
else alert('Update failed!');
} else alert('An error occurred!');
};
xmlhttp.send(formData);
}
function RequestLogin(){
document.getElementById('loader').style.visibility="hidden";
document.getElementById('loginpage').style.display='block';
}
function SubmitRequest (){
document.getElementById('loginpage').style.display='none';
var user = document.getElementById('login_user_text').value.trim();
var password = document.getElementById('login_password_text').value.trim();
var url = "/login?USER="+encodeURIComponent(user) + "&PASSWORD=" + encodeURIComponent(password) + "&SUBMIT=yes" ;
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status != 200) {
RequestLogin();
}
};
xmlhttp.open("GET", url, true);
xmlhttp.send();
}

View File

@ -1,100 +0,0 @@
<html>
<head>
<!-- smoosh -->
<link href="css/style.css" rel="stylesheet">
<!-- endsmoosh -->
</head>
<body>
<div style="position:absolute;top:0;right:0;">
V1.1
&nbsp;&nbsp;
</div>
<center>
<h2>It seems you do not have any index.html neither index.html.gz, please upload it or update your firmware if necessary.</h2>
</center>
<div class="panel" id="SPIFFS">
<div class="panel-heading">Flash Filesystem</div>
<div class="panel-body">
<input type="file" id="file-select" name="myfiles[]" multiple />
<input class="btn btn-primary" type="button" id="upload-button" onclick="Sendfile();" value="Upload"/>&nbsp;&nbsp;<progress style="visibility:hidden;" name='prg' id='prg' max='100'></progress>
<br><br>
<div class="panel">
<div class="panel-body">
<table>
<tr>
<td width="0%">
<input class="btn btn-primary" type="button" onclick="SendCommand('list','all');" value="Refresh"/>
</td>
<td width="0%">
<div onclick="Createdir()" class="btnimg"><svg width="40" height="40" viewBox="0 0 40 40"><rect x="5" y="10" width="30" height="20" rx="2" ry="2" fill="#31b0d5" />
<rect x="20" y="5" width="15" height="15" rx="2" ry="2" fill="#31b0d5" /><text x="15" y="25" font-size="18" font-weight="800" fill="white">+</text></svg>
</div>
</td>
<td>
<div id="loader" class="loader"></div>
</td>
<td width="100%">
<div id="path" class="info" >&nbsp;</div>
</td>
</tr>
</table>
<table class="table table-striped" style="border:1px;solid #dddddd;margin-bottom:20px;" >
<thead>
<tr>
<th width='0%'>Type</th>
<th>Name</th>
<th>Size</th>
<th width='0%'></th>
<th width='100%'></th>
</tr>
</thead>
<tbody id="file_list"></tbody>
</table>
</div>
<div class="panel-footer " id="status"></div>
</div>
</div>
</div>
<div class="panel">
<div class="panel-heading">Firmware Update</div>
<div class="panel-body">
<table>
<tr>
<td><input type="file" id="fw-select" name="myfiles[]" /></td>
<td><input class="btn btn-primary" type="button" id="uploadfw-button" onclick="Uploadfile();" value="Update"/></td>
<td><progress style="visibility:hidden;" name='prgfw' id='prgfw' max='100'></progress></td>
<td><span id='msg' style='visibility:hidden;'>Restarting, please wait....</span><span id='counter'></span></td>
</tr>
</table>
</div>
</div>
<div id="loginpage"class="modal">
<div class="modal-content" >
<div class="modal-header">
<h3>Identification</h3>
</div>
<div class="modal-body">
<span>
<span class="modal-text" translate>User:</span>
<input class='form-control' type="text" id="login_user_text" style="width:auto"/>
</span>
<hr>
<span>
<span class="modal-text" translate>Password:</span>
<input class='form-control' type="password" id="login_password_text" style="width:auto"/>
</span>
<br>
</div>
<div class="modal-footer">
<input type="button" class="btn btn-primary" onclick="SubmitRequest()" value="Submit"/>
</div>
</div>
</div>
<!-- smoosh -->
<script src="js/script.js"></script>
<!-- endsmoosh -->
</body>
</html>

View File

@ -1,340 +0,0 @@
/*
GenLinkedList.h - V1.1 - Generic LinkedList implementation
Works better with FIFO, because LIFO will need to
search the entire List to find the last one;
For instructions, go to https://github.com/ivanseidel/LinkedList
Created by Ivan Seidel Gomes, March, 2013.
Released into the public domain.
Changelog: 2015/10/05: [Luc] Change false to NULL for pointers
*/
#ifndef GenLinkedList_h
#define GenLinkedList_h
template<class T>
struct ListNode {
T data;
ListNode<T> *next;
};
template <typename T>
class GenLinkedList
{
protected:
int _size;
ListNode<T> *root;
ListNode<T> *last;
// Helps "get" method, by saving last position
ListNode<T> *lastNodeGot;
int lastIndexGot;
// isCached should be set to FALSE
// every time the list suffer changes
bool isCached;
ListNode<T>* getNode(int index);
public:
GenLinkedList();
~GenLinkedList();
/*
Returns current size of GenLinkedList
*/
virtual int size();
/*
Adds a T object in the specified index;
Unlink and link the GenLinkedList correcly;
Increment _size
*/
virtual bool add(int index, T);
/*
Adds a T object in the end of the GenLinkedList;
Increment _size;
*/
virtual bool add(T);
/*
Adds a T object in the start of the GenLinkedList;
Increment _size;
*/
virtual bool unshift(T);
/*
Set the object at index, with T;
Increment _size;
*/
virtual bool set(int index, T);
/*
Remove object at index;
If index is not reachable, returns false;
else, decrement _size
*/
virtual T remove(int index);
/*
Remove last object;
*/
virtual T pop();
/*
Remove first object;
*/
virtual T shift();
/*
Get the index'th element on the list;
Return Element if accessible,
else, return false;
*/
virtual T get(int index);
/*
Clear the entire array
*/
virtual void clear();
};
// Initialize GenLinkedList with false values
template<typename T>
GenLinkedList<T>::GenLinkedList()
{
root=NULL;
last=NULL;
_size=0;
lastNodeGot = root;
lastIndexGot = 0;
isCached = false;
}
// Clear Nodes and free Memory
template<typename T>
GenLinkedList<T>::~GenLinkedList()
{
ListNode<T>* tmp;
while(root!=NULL) {
tmp=root;
root=root->next;
delete tmp;
}
last = NULL;
_size=0;
isCached = false;
}
/*
Actually "logic" coding
*/
template<typename T>
ListNode<T>* GenLinkedList<T>::getNode(int index)
{
int _pos = 0;
ListNode<T>* current = root;
// Check if the node trying to get is
// immediately AFTER the previous got one
if(isCached && lastIndexGot <= index) {
_pos = lastIndexGot;
current = lastNodeGot;
}
while(_pos < index && current) {
current = current->next;
_pos++;
}
// Check if the object index got is the same as the required
if(_pos == index) {
isCached = true;
lastIndexGot = index;
lastNodeGot = current;
return current;
}
return NULL;
}
template<typename T>
int GenLinkedList<T>::size()
{
return _size;
}
template<typename T>
bool GenLinkedList<T>::add(int index, T _t)
{
if(index >= _size) {
return add(_t);
}
if(index == 0) {
return unshift(_t);
}
ListNode<T> *tmp = new ListNode<T>(),
*_prev = getNode(index-1);
tmp->data = _t;
tmp->next = _prev->next;
_prev->next = tmp;
_size++;
isCached = false;
return true;
}
template<typename T>
bool GenLinkedList<T>::add(T _t)
{
ListNode<T> *tmp = new ListNode<T>();
tmp->data = _t;
tmp->next = NULL;
if(root) {
// Already have elements inserted
last->next = tmp;
last = tmp;
} else {
// First element being inserted
root = tmp;
last = tmp;
}
_size++;
isCached = false;
return true;
}
template<typename T>
bool GenLinkedList<T>::unshift(T _t)
{
if(_size == 0) {
return add(_t);
}
ListNode<T> *tmp = new ListNode<T>();
tmp->next = root;
tmp->data = _t;
root = tmp;
_size++;
isCached = false;
return true;
}
template<typename T>
bool GenLinkedList<T>::set(int index, T _t)
{
// Check if index position is in bounds
if(index < 0 || index >= _size) {
return false;
}
getNode(index)->data = _t;
return true;
}
template<typename T>
T GenLinkedList<T>::pop()
{
if(_size <= 0) {
return T();
}
isCached = false;
if(_size >= 2) {
ListNode<T> *tmp = getNode(_size - 2);
T ret = tmp->next->data;
delete(tmp->next);
tmp->next = NULL;
last = tmp;
_size--;
return ret;
} else {
// Only one element left on the list
T ret = root->data;
delete(root);
root = NULL;
last = NULL;
_size = 0;
return ret;
}
}
template<typename T>
T GenLinkedList<T>::shift()
{
if(_size <= 0) {
return T();
}
if(_size > 1) {
ListNode<T> *_next = root->next;
T ret = root->data;
delete(root);
root = _next;
_size --;
isCached = false;
return ret;
} else {
// Only one left, then pop()
return pop();
}
}
template<typename T>
T GenLinkedList<T>::remove(int index)
{
if (index < 0 || index >= _size) {
return T();
}
if(index == 0) {
return shift();
}
if (index == _size-1) {
return pop();
}
ListNode<T> *tmp = getNode(index - 1);
ListNode<T> *toDelete = tmp->next;
T ret = toDelete->data;
tmp->next = tmp->next->next;
delete(toDelete);
_size--;
isCached = false;
return ret;
}
template<typename T>
T GenLinkedList<T>::get(int index)
{
ListNode<T> *tmp = getNode(index);
return (tmp ? tmp->data : T());
}
template<typename T>
void GenLinkedList<T>::clear()
{
while(size() > 0) {
shift();
}
}
#endif

View File

@ -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

View File

@ -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 <WiFiServer.h>
#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

File diff suppressed because it is too large Load Diff

View File

@ -1,43 +0,0 @@
/*
command.h - 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
*/
#ifndef COMMAND_h
#define COMMAND_h
#include <Arduino.h>
#include "bridge.h"
class COMMAND
{
public:
static String buffer_serial;
static String buffer_tcp;
static void read_buffer_serial(uint8_t *b, size_t len);
static void read_buffer_serial(uint8_t b);
#ifdef TCP_IP_DATA_FEATURE
static void read_buffer_tcp(uint8_t b);
#endif
static bool check_command(String buffer, tpipe output, bool handlelockserial = true);
static bool execute_command(int cmd,String cmd_params, tpipe output, level_authenticate_type auth_level = LEVEL_GUEST);
static String get_param(String & cmd_params, const char * id, bool withspace = false);
static bool isadmin(String & cmd_params);
static bool isuser(String & cmd_params);
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,430 +0,0 @@
/*
config.h - 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
*/
//definition
#define UNKNOWN_FW 0
#define REPETIER4DV 1
#define MARLIN 2
#define MARLINKIMBRA 3
#define SMOOTHIEWARE 4
#define REPETIER 5
#ifdef ARDUINO_ARCH_ESP32
#include "FS.h"
#include "SPIFFS.h"
#define WIFI_NONE_SLEEP WIFI_PS_NONE
#define WIFI_MODEM_SLEEP WIFI_PS_MAX_MODEM
#define WIFI_PHY_MODE_11B WIFI_PROTOCOL_11B
#define WIFI_PHY_MODE_11G WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G
#define WIFI_PHY_MODE_11N WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N
#define AUTH_OPEN WIFI_AUTH_OPEN
#define AUTH_WEP WIFI_AUTH_WEP
#define AUTH_WPA_PSK WIFI_AUTH_WPA_PSK
#define AUTH_WPA2_PSK WIFI_AUTH_WPA2_PSK
#define AUTH_WPA_WPA2_PSK WIFI_AUTH_WPA_WPA2_PSK
#define ENC_TYPE_NONE AUTH_OPEN
#define FS_FILE File
#define FS_DIR File
#define ESP_SERIAL_OUT Serial
#define SD_FILE_READ FILE_READ
#define SPIFFS_FILE_READ FILE_READ
#define SD_FILE_WRITE FILE_WRITE
#define SPIFFS_FILE_WRITE FILE_WRITE
#else
#define FS_DIR fs::Dir
#define FS_FILE fs::File
#define ESP_SERIAL_OUT Serial
#define SD_FILE_READ FILE_READ
#define SPIFFS_FILE_READ "r"
#define SD_FILE_WRITE FILE_WRITE
#define SPIFFS_FILE_WRITE "w"
#endif
#define MAX_FW_ID REPETIER
//number of clients allowed to use data port at once
#define MAX_SRV_CLIENTS 1
//comment to disable
//MDNS_FEATURE: this feature allow type the name defined
//in web browser by default: http:\\esp8266.local and connect
#define MDNS_FEATURE
//SSDD_FEATURE: this feature is a discovery protocol, supported on Windows out of the box
#define SSDP_FEATURE
//NETBIOS_FEATURE: this feature is a discovery protocol, supported on Windows out of the box
#define NETBIOS_FEATURE
#ifdef ARDUINO_ARCH_ESP32
#ifdef SSDP_FEATURE
#undef SSDP_FEATURE
#endif
#ifdef NETBIOS_FEATURE
#undef NETBIOS_FEATURE
#endif
#endif
//CAPTIVE_PORTAL_FEATURE: In SoftAP redirect all unknow call to main page
#define CAPTIVE_PORTAL_FEATURE
//AUTHENTICATION_FEATURE: protect pages by login password
//#define AUTHENTICATION_FEATURE
//WEB_UPDATE_FEATURE: allow to flash fw using web UI
#define WEB_UPDATE_FEATURE
//SERIAL_COMMAND_FEATURE: allow to send command by serial
#define SERIAL_COMMAND_FEATURE
//TCP_IP_DATA_FEATURE: allow to connect serial from TCP/IP
#define TCP_IP_DATA_FEATURE
//RECOVERY_FEATURE: allow to use GPIO2 pin as hardware reset for EEPROM, add 8s to boot time to let user to jump GPIO2 to GND
//#define RECOVERY_FEATURE
#ifdef RECOVERY_FEATURE
//pin used to reset setting
#define RESET_CONFIG_PIN 2
#endif
//DIRECT_PIN_FEATURE: allow to access pin using ESP201 command
#define DIRECT_PIN_FEATURE
//INFO_MSG_FEATURE: catch the Info msg and filter it to specific table
#define INFO_MSG_FEATURE
//ERROR_MSG_FEATURE: catch the error msg and filter it to specific table
#define ERROR_MSG_FEATURE
//STATUS_MSG_FEATURE: catch the status msg and filter it to specific table
#define STATUS_MSG_FEATURE
//Serial rx buffer size is 256 but can be extended
#define SERIAL_RX_BUFFER_SIZE 512
#ifdef ARDUINO_ARCH_ESP32
#ifdef SSDP_FEATURE
#undef SSDP_FEATURE
#endif
#ifdef NETBIOS_FEATURE
#undef NETBIOS_FEATURE
#endif
#endif
//DEBUG Flag do not do this when connected to printer !!!
//be noted all upload may failed if enabled
//#define DEBUG_ESP3D
//#define DEBUG_OUTPUT_SPIFFS
//#define DEBUG_OUTPUT_SERIAL
//#define DEBUG_OUTPUT_TCP
//store performance result in storestring variable : info_msg / status_msg
//#define DEBUG_PERFORMANCE
#define DEBUG_PERF_VARIABLE (web_interface->info_msg)
/*
#ifndef FS_NO_GLOBALS
#define FS_NO_GLOBALS
#endif
#include <FS.h>
#define DEBUG_ESP3D(string) { FS_FILE logfile = SPIFFS.open("/log.txt", "a+");logfile.print(string);logfile.close();}
*/
#ifdef DEBUG_ESP3D
#ifdef DEBUG_OUTPUT_SPIFFS
#ifndef FS_NO_GLOBALS
#define FS_NO_GLOBALS
#endif
#include <FS.h>
#define DEBUG_PIPE NO_PIPE
#define LOG(string) { FS_FILE logfile = SPIFFS.open("/log.txt", "a+");logfile.print(string);logfile.close();}
#endif
#ifdef DEBUG_OUTPUT_SERIAL
#define LOG(string) {ESP_SERIAL_OUT.print(string);}
#define DEBUG_PIPE SERIAL_PIPE
#endif
#ifdef DEBUG_OUTPUT_TCP
#include "bridge.h"
#define LOG(string) {BRIDGE::send2TCP(string);}
#define DEBUG_PIPE TCP_PIPE
#endif
#else
#define LOG(string) {}
#define DEBUG_PIPE NO_PIPE
#endif
#ifndef CONFIG_h
#define CONFIG_h
#include <Arduino.h>
#ifdef ARDUINO_ARCH_ESP8266
extern "C" {
#include "user_interface.h"
}
#else
//Nothing here
#endif
#include "wificonf.h"
//version and sources location
#define FW_VERSION "1.0"
#define REPOSITORY "https://github.com/luc-github/ESP3D"
typedef enum {
NO_PIPE = 0,
SERIAL_PIPE = 2,
SERIAL1_PIPE = 3,
#ifdef TCP_IP_DATA_FEATURE
TCP_PIPE = 4,
#endif
WEB_PIPE = 5
} tpipe;
typedef enum {
LEVEL_GUEST = 0,
LEVEL_USER = 1,
LEVEL_ADMIN = 2
} level_authenticate_type;
#define NO_SD 0
#define SD_DIRECTORY 1
#define EXT_DIRECTORY 2
//flags
#define AP_MODE 1
#define CLIENT_MODE 2
#define DHCP_MODE 1
#define STATIC_IP_MODE 2
//position in EEPROM
//AP mode = 1; Station client mode = 2
#define EP_WIFI_MODE 0 //1 byte = flag
#define EP_STA_SSID 1 //33 bytes 32+1 = string ; warning does not support multibyte char like chinese
#define EP_STA_PASSWORD 34 //65 bytes 64 +1 = string ;warning does not support multibyte char like chinese
#define EP_STA_IP_MODE 99 //1 byte = flag
#define EP_STA_IP_VALUE 100 //4 bytes xxx.xxx.xxx.xxx
#define EP_STA_MASK_VALUE 104 //4 bytes xxx.xxx.xxx.xxx
#define EP_STA_GATEWAY_VALUE 108 //4 bytes xxx.xxx.xxx.xxx
#define EP_BAUD_RATE 112 //4 bytes = int
#define EP_STA_PHY_MODE 116 //1 byte = flag
#define EP_SLEEP_MODE 117 //1 byte = flag
#define EP_CHANNEL 118 //1 byte = flag
#define EP_AUTH_TYPE 119 //1 byte = flag
#define EP_SSID_VISIBLE 120 //1 byte = flag
#define EP_WEB_PORT 121 //4 bytes = int
#define EP_DATA_PORT 125 //4 bytes = int
#define EP_REFRESH_PAGE_TIME 129 //1 bytes = flag
#define EP_HOSTNAME 130//33 bytes 32+1 = string ; warning does not support multibyte char like chinese
#define EP_XY_FEEDRATE 164//4 bytes = int
#define EP_Z_FEEDRATE 168//4 bytes = int
#define EP_E_FEEDRATE 172//4 bytes = int
#define EP_ADMIN_PWD 176//21 bytes 20+1 = string ; warning does not support multibyte char like chinese
#define EP_USER_PWD 197//21 bytes 20+1 = string ; warning does not support multibyte char like chinese
#define EP_AP_SSID 218 //33 bytes 32+1 = string ; warning does not support multibyte char like chinese
#define EP_AP_PASSWORD 251 //65 bytes 64 +1 = string ;warning does not support multibyte char like chinese
#define EP_AP_IP_VALUE 316 //4 bytes xxx.xxx.xxx.xxx
#define EP_AP_MASK_VALUE 320 //4 bytes xxx.xxx.xxx.xxx
#define EP_AP_GATEWAY_VALUE 324 //4 bytes xxx.xxx.xxx.xxx
#define EP_AP_IP_MODE 329 //1 byte = flag
#define EP_AP_PHY_MODE 330 //1 byte = flag
#define EP_DATA_STRING 331 //129 bytes 128+1 = string ; warning does not support multibyte char like chinese
#define EP_REFRESH_PAGE_TIME2 460 //1 bytes = flag
#define EP_TARGET_FW 461 //1 bytes = flag
#define EP_TIMEZONE 462//1 bytes = flag
#define EP_TIME_ISDST 463//1 bytes = flag
#define EP_TIME_SERVER1 464//129 bytes 128+1 = string ; warning does not support multibyte char like chinese
#define EP_TIME_SERVER2 593 //129 bytes 128+1 = string ; warning does not support multibyte char like chinese
#define EP_TIME_SERVER3 722 //129 bytes 128+1 = string ; warning does not support multibyte char like chinese
#define EP_IS_DIRECT_SD 850//1 bytes = flag
#define EP_PRIMARY_SD 851//1 bytes = flag
#define EP_SECONDARY_SD 852//1 bytes = flag
#define EP_DIRECT_SD_CHECK 853//1 bytes = flag
#define EP_SD_CHECK_UPDATE_AT_BOOT 854//1 bytes = flag
#define LAST_EEPROM_ADDRESS 855
//next available is 855
//space left 1024 - 855 = 169
//default values
#define DEFAULT_WIFI_MODE AP_MODE
const char DEFAULT_AP_SSID [] PROGMEM = "ESP3D";
const char DEFAULT_AP_PASSWORD [] PROGMEM = "12345678";
const char DEFAULT_STA_SSID [] PROGMEM = "ESP3D";
const char DEFAULT_STA_PASSWORD [] PROGMEM = "12345678";
const byte DEFAULT_STA_IP_MODE = DHCP_MODE;
const byte DEFAULT_AP_IP_MODE = STATIC_IP_MODE;
const byte DEFAULT_IP_VALUE[] = {192, 168, 0, 1};
const byte DEFAULT_MASK_VALUE[] = {255, 255, 255, 0};
#define DEFAULT_GATEWAY_VALUE DEFAULT_IP_VALUE
const long DEFAULT_BAUD_RATE = 115200;
const char M117_[] PROGMEM = "M117 ";
#define DEFAULT_PHY_MODE WIFI_PHY_MODE_11G
#define DEFAULT_SLEEP_MODE WIFI_MODEM_SLEEP
#define DEFAULT_CHANNEL 11
#define DEFAULT_AUTH_TYPE AUTH_WPA_PSK
#define DEFAULT_SSID_VISIBLE 1
#define DEFAULT_MAX_CONNECTIONS 4
#define DEFAULT_BEACON_INTERVAL 100
const int DEFAULT_WEB_PORT = 80;
const int DEFAULT_DATA_PORT = 8888;
#define DEFAULT_REFRESH_PAGE_TIME 3
const int DEFAULT_XY_FEEDRATE=1000;
const int DEFAULT_Z_FEEDRATE =100;
const int DEFAULT_E_FEEDRATE=400;
const char DEFAULT_ADMIN_PWD [] PROGMEM = "admin";
const char DEFAULT_USER_PWD [] PROGMEM = "user";
const char DEFAULT_ADMIN_LOGIN [] PROGMEM = "admin";
const char DEFAULT_USER_LOGIN [] PROGMEM = "user";
const char DEFAULT_TIME_SERVER1 [] PROGMEM = "time.nist.gov";
const char DEFAULT_TIME_SERVER2 [] PROGMEM = "0.pool.ntp.org";
const char DEFAULT_TIME_SERVER3 [] PROGMEM = "1.pool.ntp.org";
#define DEFAULT_TIME_ZONE 0
#define DEFAULT_TIME_DST 0
#define DEFAULT_PRIMARY_SD 1
#define DEFAULT_SECONDARY_SD 2
#define DEFAULT_DIRECT_SD_CHECK 0
#define DEFAULT_SD_CHECK_UPDATE_AT_BOOT 1
#define DEFAULT_IS_DIRECT_SD 0
const uint16_t Setting[][2] = {
{EP_WIFI_MODE, LEVEL_ADMIN},//0
{EP_STA_SSID, LEVEL_ADMIN},//1
{EP_STA_PASSWORD, LEVEL_ADMIN},//2
{EP_STA_IP_MODE, LEVEL_ADMIN},//3
{EP_STA_IP_VALUE, LEVEL_ADMIN},//4
{EP_STA_MASK_VALUE, LEVEL_ADMIN},//5
{EP_STA_GATEWAY_VALUE, LEVEL_ADMIN},//6
{EP_BAUD_RATE, LEVEL_ADMIN},//7
{EP_STA_PHY_MODE, LEVEL_ADMIN},//8
{EP_SLEEP_MODE, LEVEL_ADMIN},//9
{EP_CHANNEL, LEVEL_ADMIN},//10
{EP_AUTH_TYPE, LEVEL_ADMIN},//11
{EP_SSID_VISIBLE, LEVEL_ADMIN},//12
{EP_WEB_PORT, LEVEL_ADMIN},//13
{EP_DATA_PORT, LEVEL_ADMIN},//14
{EP_REFRESH_PAGE_TIME, LEVEL_USER},//15
{EP_HOSTNAME, LEVEL_ADMIN},//16
{EP_XY_FEEDRATE, LEVEL_USER},//17
{EP_Z_FEEDRATE, LEVEL_USER},//18
{EP_E_FEEDRATE, LEVEL_USER},//19
{EP_ADMIN_PWD, LEVEL_ADMIN},//20
{EP_USER_PWD, LEVEL_USER},//21
{EP_AP_SSID, LEVEL_ADMIN},//22
{EP_AP_PASSWORD, LEVEL_ADMIN},//23
{EP_AP_IP_VALUE, LEVEL_ADMIN},//24
{EP_AP_MASK_VALUE, LEVEL_ADMIN},//25
{EP_AP_GATEWAY_VALUE, LEVEL_ADMIN},//26
{EP_AP_IP_MODE, LEVEL_ADMIN},//27
{EP_AP_PHY_MODE, LEVEL_ADMIN},//28
{EP_DATA_STRING, LEVEL_USER},//29
{EP_REFRESH_PAGE_TIME2, LEVEL_USER},//30
{EP_TARGET_FW, LEVEL_USER},//31
{EP_TIMEZONE, LEVEL_USER},//32
{EP_TIME_ISDST, LEVEL_USER},//33
{EP_TIME_SERVER1, LEVEL_USER},//34
{EP_TIME_SERVER2, LEVEL_USER},//35
{EP_TIME_SERVER3, LEVEL_USER},//36
{EP_IS_DIRECT_SD, LEVEL_USER},//37
{EP_PRIMARY_SD, LEVEL_USER},//38
{EP_SECONDARY_SD, LEVEL_USER},//39
{EP_DIRECT_SD_CHECK, LEVEL_USER}, //40
{EP_SD_CHECK_UPDATE_AT_BOOT, LEVEL_USER} //41
};
#define AUTH_ENTRY_NB 42
//values
#define DEFAULT_MAX_REFRESH 120
#define DEFAULT_MIN_REFRESH 0
#define DEFAULT_MAX_XY_FEEDRATE 9999
#define DEFAULT_MIN_XY_FEEDRATE 1
#define DEFAULT_MAX_Z_FEEDRATE 9999
#define DEFAULT_MIN_Z_FEEDRATE 1
#define DEFAULT_MAX_E_FEEDRATE 9999
#define DEFAULT_MIN_E_FEEDRATE 1
#define DEFAULT_MAX_WEB_PORT 65001
#define DEFAULT_MIN_WEB_PORT 1
#define DEFAULT_MAX_DATA_PORT 65001
#define DEFAULT_MIN_DATA_PORT 1
#define MAX_TRY 2000
//sizes
#define EEPROM_SIZE 1024 //max is 1024
#define MAX_SSID_LENGTH 32
#define MIN_SSID_LENGTH 1
#define MAX_PASSWORD_LENGTH 64
//min size of password is 0 or upper than 8 char
//so let set min is 0
#define MIN_PASSWORD_LENGTH 0
#define MAX_LOCAL_PASSWORD_LENGTH 16
#define MIN_LOCAL_PASSWORD_LENGTH 1
#define MAX_DATA_LENGTH 128
#define MIN_DATA_LENGTH 0
#define IP_LENGTH 4
#define INTEGER_LENGTH 4
#define MAX_HOSTNAME_LENGTH 32
#define MIN_HOSTNAME_LENGTH 1
#define WL_MAC_ADDR_LENGTH 6
class CONFIG
{
public:
static bool is_direct_sd;
static bool read_string(int pos, char byte_buffer[], int size_max);
static bool read_string(int pos, String & sbuffer, int size_max);
static bool read_buffer(int pos, byte byte_buffer[], int size_buffer);
static bool read_byte(int pos, byte * value);
static bool write_string(int pos, const char * byte_buffer);
static bool write_string(int pos, const __FlashStringHelper *str);
static bool write_buffer(int pos, const byte * byte_buffer, int size_buffer);
static bool write_byte(int pos, const byte value);
static bool reset_config();
static void print_config(tpipe output, bool plaintext);
static bool SetFirmwareTarget(uint8_t fw);
static void InitFirmwareTarget();
static void InitDirectSD();
static void InitPins();
static bool InitBaudrate();
static bool InitExternalPorts();
static bool check_update_presence();
static uint8_t GetFirmwareTarget();
static const char* GetFirmwareTargetName();
static const char* GetFirmwareTargetShortName();
static bool isHostnameValid(const char * hostname);
static bool isSSIDValid(const char * ssid);
static bool isPasswordValid(const char * password);
static bool isLocalPasswordValid(const char * password);
static bool isIPValid(const char * IP);
static char * intTostr(int value);
static String formatBytes(uint32_t bytes);
static char * mac2str(uint8_t mac [WL_MAC_ADDR_LENGTH]);
static byte split_ip (const char * ptr,byte * part);
static void esp_restart();
private:
static uint8_t FirmwareTarget;
};
#endif

View File

@ -1,18 +0,0 @@
<HTML>
<HEAD>
<title>404 page</title>
</HEAD>
<BODY STYLE="background-color: lightblue;">
<CENTER>
<H1>
<svg width='24' height='24' viewBox='0 0 1300 1200'>
<g transform='translate(50,1200) scale(1, -1)'>
<path fill='red' d='M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5q0 -120 65 -225 l587 587q-105 65 -225 65zM965 819l-584 -584q104 -62 219 -62q116 0 214.5 57t155.5 155.5t57 214.5q0 115 -62 219z' />
</g>
</svg>404 Error, unknown page!</H1>
<H2>What are you doing here ?</H2>
You are not supposed to find this location...
</CENTER>
</BODY>
</HTML>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

View File

@ -1,74 +0,0 @@
[
{
"name": "",
"glyph": "",
"filename": "",
"target": "",
"class": "",
"index": 0
},
{
"name": "",
"glyph": "",
"filename": "",
"target": "",
"class": "",
"index": 1
},
{
"name": "",
"glyph": "",
"filename": "",
"target": "",
"class": "",
"index": 2
},
{
"name": "",
"glyph": "",
"filename": "",
"target": "",
"class": "",
"index": 3
},
{
"name": "",
"glyph": "",
"filename": "",
"target": "",
"class": "",
"index": 4
},
{
"name": "",
"glyph": "",
"filename": "",
"target": "",
"class": "",
"index": 5
},
{
"name": "",
"glyph": "",
"filename": "",
"target": "",
"class": "",
"index": 6
},
{
"name": "",
"glyph": "",
"filename": "",
"target": "",
"class": "",
"index": 7
},
{
"name": "",
"glyph": "",
"filename": "",
"target": "",
"class": "",
"index": 8
}
]

View File

@ -1,189 +0,0 @@
/*
This file is part of ESP3D Firmware for 3D printer.
ESP3D Firmware for 3D printer is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ESP3D Firmware for 3D printer 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this Firmware. If not, see <http://www.gnu.org/licenses/>.
This firmware is using the standard arduino IDE with module to support ESP8266:
https://github.com/esp8266/Arduino from Bootmanager
Latest version of the code and documentation can be found here :
https://github.com/luc-github/ESP3D
Main author: luc lebosse
*/
//be sure correct IDE and settings are used for ESP8266 or ESP32
#if !(defined( ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32))
#error Oops! Make sure you have 'ESP8266 or ESP32' compatible board selected from the 'Tools -> Boards' menu.
#endif
#include <EEPROM.h>
#include "config.h"
#include "wificonf.h"
#include "bridge.h"
#include "webinterface.h"
#include "command.h"
#ifdef ARDUINO_ARCH_ESP8266
#include "ESP8266WiFi.h"
#ifdef MDNS_FEATURE
#include <ESP8266mDNS.h>
#endif
#include <ESP8266WebServer.h>
#else
#include <WiFi.h>
#ifdef MDNS_FEATURE
#include <ESPmDNS.h>
#endif
#include "esp_wifi.h"
#include <WebServer.h>
#include "FS.h"
#include "SPIFFS.h"
#include "Update.h"
#endif
#include <WiFiClient.h>
#ifdef CAPTIVE_PORTAL_FEATURE
#include <DNSServer.h>
extern DNSServer dnsServer;
#endif
#ifdef SSDP_FEATURE
#ifdef ARDUINO_ARCH_ESP8266
#include <ESP8266SSDP.h>
#else
//#include <ESPSSDP.h>
#endif
#endif
#ifdef NETBIOS_FEATURE
#ifdef ARDUINO_ARCH_ESP8266
#include <ESP8266NetBIOS.h>
#else
//#include <ESPNetBIOS.h>
#endif
#endif
#ifndef FS_NO_GLOBALS
#define FS_NO_GLOBALS
#endif
#include <FS.h>
void setup()
{
bool breset_config=false;
bool directsd_check = false;
web_interface = NULL;
#ifdef TCP_IP_DATA_FEATURE
data_server = NULL;
#endif
// init:
#ifdef DEBUG_ESP3D
if (ESP_SERIAL_OUT.baudRate() != DEFAULT_BAUD_RATE)ESP_SERIAL_OUT.begin(DEFAULT_BAUD_RATE);
delay(2000);
LOG("\r\nDebug Serial set\r\n")
#endif
//WiFi.disconnect();
WiFi.mode(WIFI_OFF);
delay(8000);
CONFIG::InitDirectSD();
CONFIG::InitPins();
#ifdef RECOVERY_FEATURE
delay(8000);
//check if reset config is requested
if (digitalRead(RESET_CONFIG_PIN)==0) {
breset_config=true; //if requested =>reset settings
}
#endif
//check if EEPROM has value
if ( !CONFIG::InitBaudrate() || !CONFIG::InitExternalPorts()) {
breset_config=true; //cannot access to config settings=> reset settings
LOG("Error no EEPROM access\r\n")
}
//reset is requested
if(breset_config) {
//update EEPROM with default settings
if (ESP_SERIAL_OUT.baudRate() != DEFAULT_BAUD_RATE)ESP_SERIAL_OUT.begin(DEFAULT_BAUD_RATE);
#ifdef ARDUINO_ARCH_ESP8266
ESP_SERIAL_OUT.setRxBufferSize(SERIAL_RX_BUFFER_SIZE);
#endif
delay(2000);
ESP_SERIAL_OUT.println(F("M117 ESP EEPROM reset"));
#ifdef DEBUG_ESP3D
CONFIG::print_config(DEBUG_PIPE, true);
delay(1000);
#endif
CONFIG::reset_config();
delay(1000);
//put some default value to a void some exception at first start
WiFi.mode(WIFI_AP);
#ifdef ARDUINO_ARCH_ESP8266
WiFi.setPhyMode(WIFI_PHY_MODE_11G);
#else
esp_wifi_set_protocol(ESP_IF_WIFI_AP, WIFI_PHY_MODE_11G);
#endif
CONFIG::esp_restart();
}
#if defined(DEBUG_ESP3D) && defined(DEBUG_OUTPUT_SERIAL)
LOG("\r\n");
delay(500);
ESP_SERIAL_OUT.flush();
#endif
//get target FW
CONFIG::InitFirmwareTarget();
//Update is done if any so should be Ok
#ifdef ARDUINO_ARCH_ESP32
SPIFFS.begin(true);
#else
SPIFFS.begin();
#endif
//setup wifi according settings
if (!wifi_config.Setup()) {
ESP_SERIAL_OUT.println(F("M117 Safe mode 1"));
//try again in AP mode
if (!wifi_config.Setup(true)) {
ESP_SERIAL_OUT.println(F("M117 Safe mode 2"));
wifi_config.Safe_Setup();
}
}
delay(1000);
//setup servers
if (!wifi_config.Enable_servers()) {
ESP_SERIAL_OUT.println(F("M117 Error enabling servers"));
}
LOG("Setup Done\r\n");
}
//main loop
void loop()
{
//be sure wifi is on to proceed wifi function
if (WiFi.getMode()!=WIFI_OFF ) {
#ifdef CAPTIVE_PORTAL_FEATURE
if (WiFi.getMode()!=WIFI_STA ) {
dnsServer.processNextRequest();
}
#endif
//web requests
web_interface->web_server.handleClient();
#ifdef TCP_IP_DATA_FEATURE
BRIDGE::processFromTCP2Serial();
#endif
}
BRIDGE::processFromSerial2TCP();
//in case of restart requested
if (web_interface->restartmodule) {
CONFIG::esp_restart();
}
}

View File

@ -1,326 +0,0 @@
/*
nofile.h - ESP3D data file
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
*/
//data generated by https://github.com/AraHaan/bin2c
//bin2c Conversion Tool v0.14.0 - Windows - [FINAL].
#define PAGE_NOFILES_SIZE 4776
const char PAGE_NOFILES [] PROGMEM =
{
0x1F, 0x8B, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0xED, 0x5C, 0x7D, 0x93, 0xDA, 0x46,
0x93, 0xFF, 0x2A, 0xB2, 0x52, 0x36, 0x70, 0x2B, 0x58, 0x49, 0xBC, 0xA3, 0x05, 0x3F, 0x49, 0x1C,
0x5F, 0x7C, 0xE5, 0xC4, 0x2E, 0xEF, 0xFA, 0xEE, 0xAA, 0xE2, 0x94, 0x4B, 0x48, 0x03, 0xE8, 0xB1,
0x90, 0x74, 0xD2, 0xB0, 0xBB, 0x98, 0xF0, 0xDD, 0xAF, 0x7B, 0x5E, 0xA4, 0x91, 0x10, 0x2C, 0xBB,
0x49, 0x9E, 0x3C, 0x7F, 0x24, 0x78, 0x11, 0xCC, 0x4C, 0xF7, 0xF4, 0xF4, 0x74, 0xFF, 0xBA, 0xA7,
0x87, 0xCA, 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, 0x73, 0x93, 0xD1, 0x89, 0x65, 0x9A, 0xCF, 0x9D, 0xF6, 0x1D, 0x99, 0x7F, 0x09,
0xE8, 0x91, 0x5E, 0xC6, 0x0E, 0x5B, 0xE1, 0x6B, 0x72, 0xBF, 0x9F, 0xC7, 0xFE, 0xB6, 0x34, 0x85,
0xFE, 0x23, 0x09, 0x6F, 0x09, 0x0D, 0x3C, 0x57, 0xFB, 0x99, 0x6C, 0x88, 0x6E, 0xE4, 0xDF, 0x8D,
0x6F, 0xD3, 0xC0, 0x0D, 0x0D, 0x45, 0x06, 0x85, 0x57, 0x2F, 0xB9, 0x77, 0xC2, 0x20, 0x22, 0xED,
0x15, 0x09, 0x96, 0x2B, 0x98, 0xAB, 0xD3, 0xB3, 0x47, 0xFD, 0xA1, 0xD5, 0xEB, 0x3A, 0x5E, 0x1C,
0xC6, 0xE9, 0xE4, 0x9B, 0x6E, 0xB7, 0xEB, 0xCC, 0x5D, 0xEF, 0xCB, 0x32, 0x8D, 0x37, 0x91, 0xDF,
0x16, 0xAD, 0x8B, 0xC5, 0x62, 0xDF, 0xF1, 0x80, 0x8F, 0x0B, 0xC4, 0xE9, 0x6E, 0xED, 0xA6, 0xCB,
0x20, 0x6A, 0xA7, 0x8C, 0x87, 0xBB, 0xA1, 0xB1, 0x23, 0x5A, 0x42, 0xB2, 0x10, 0x0D, 0x89, 0xEB,
0xFB, 0x41, 0xB4, 0xE4, 0x2D, 0x56, 0x1F, 0xE6, 0x95, 0x2D, 0x9C, 0x0A, 0x9B, 0xF6, 0xD4, 0x9D,
0x87, 0x64, 0x37, 0x8F, 0x53, 0x9F, 0xA4, 0x13, 0xD3, 0xE1, 0x1F, 0xDA, 0x59, 0xE2, 0x7A, 0x30,
0x10, 0x1A, 0xD6, 0xEE, 0x7D, 0xFB, 0x2E, 0xF0, 0xE9, 0x8A, 0x29, 0x65, 0xDF, 0x61, 0xE3, 0xDB,
0x7C, 0x18, 0xF1, 0x77, 0x45, 0x97, 0x20, 0x9D, 0x58, 0xC9, 0xBD, 0x96, 0xC5, 0x61, 0xE0, 0x6B,
0xDF, 0xF8, 0xBE, 0x2F, 0xA5, 0x9A, 0xC7, 0x94, 0xC6, 0xEB, 0x89, 0x8D, 0x9A, 0xA4, 0x40, 0xB6,
0x0A, 0x28, 0x61, 0xB3, 0x90, 0x49, 0x14, 0xDF, 0xA5, 0x6E, 0x22, 0x65, 0x9B, 0xD8, 0xEB, 0xF5,
0x9E, 0xAE, 0x76, 0x6C, 0x4F, 0xDC, 0x30, 0x58, 0x46, 0x13, 0x94, 0x5F, 0x4C, 0x3C, 0xA3, 0xB8,
0x0D, 0x33, 0x9A, 0xCE, 0xA8, 0x6F, 0x1C, 0x34, 0xAD, 0xF2, 0x26, 0x66, 0x1B, 0xE5, 0x51, 0x79,
0xD3, 0x6A, 0x27, 0xA7, 0x1A, 0x1D, 0xDF, 0x8A, 0x5B, 0x92, 0xE2, 0x4E, 0x86, 0x42, 0x04, 0x1A,
0x27, 0x52, 0x35, 0xF0, 0xB1, 0xB2, 0xC6, 0xAA, 0x52, 0x6A, 0x84, 0xAC, 0xEB, 0x5B, 0x1D, 0xF6,
0x1D, 0x88, 0x5D, 0xD7, 0xB7, 0xDA, 0xD5, 0x6A, 0xFA, 0x50, 0x8A, 0x47, 0x71, 0x13, 0x3B, 0x24,
0xF6, 0xDA, 0x86, 0x6D, 0x12, 0x34, 0x19, 0x4D, 0x83, 0x44, 0x11, 0x7C, 0x12, 0xD1, 0x55, 0x3B,
0x5E, 0xB4, 0xE9, 0x36, 0x21, 0xCD, 0xD8, 0xF7, 0x5B, 0xBB, 0x1A, 0x5B, 0x1D, 0xE3, 0x6B, 0xFF,
0x8F, 0x35, 0xF1, 0x03, 0x57, 0x6B, 0xAE, 0xC1, 0x00, 0x38, 0xDF, 0xE1, 0x00, 0x74, 0xDE, 0xDA,
0x29, 0x76, 0x2C, 0xDA, 0xFB, 0x68, 0x18, 0x35, 0x04, 0xE3, 0xB1, 0x5D, 0x4B, 0x30, 0x1E, 0x1E,
0x21, 0xB0, 0x6C, 0xD3, 0xAC, 0xA5, 0xB0, 0x2C, 0x4E, 0xD2, 0x89, 0xDC, 0x5B, 0xD5, 0x6C, 0x85,
0xC8, 0x9E, 0xE7, 0x55, 0x1C, 0xC6, 0xAC, 0xBA, 0x8B, 0x09, 0xC6, 0x92, 0x81, 0x1B, 0x23, 0xE2,
0x80, 0xD5, 0x46, 0xA4, 0xC6, 0x4B, 0x99, 0xEF, 0x72, 0x85, 0xA6, 0xAE, 0x1F, 0x6C, 0xB2, 0xC9,
0x00, 0x8C, 0xAC, 0xC6, 0x09, 0xDC, 0x5D, 0x12, 0x67, 0x01, 0x0D, 0xE2, 0x68, 0x92, 0x92, 0xD0,
0xA5, 0xC1, 0x2D, 0x71, 0xFC, 0x20, 0x4B, 0x42, 0x77, 0x3B, 0x99, 0x87, 0xB1, 0xF7, 0x25, 0x77,
0x08, 0x44, 0x1F, 0x8D, 0xB9, 0x2F, 0xF3, 0x09, 0x9F, 0x78, 0x71, 0xEA, 0x32, 0x42, 0x26, 0x43,
0x21, 0xFF, 0xBE, 0xE3, 0x7A, 0xC8, 0x67, 0x57, 0x20, 0x46, 0x8D, 0x84, 0xA6, 0x69, 0xCA, 0x81,
0x9A, 0x6B, 0xB8, 0x93, 0x45, 0xEC, 0x6D, 0x32, 0x78, 0xAE, 0x62, 0xB0, 0xF9, 0x9D, 0x0A, 0x36,
0x89, 0x1B, 0x91, 0x70, 0x77, 0x28, 0x7B, 0x3D, 0x38, 0x1D, 0xF1, 0xFF, 0xB2, 0x32, 0x10, 0xFC,
0x24, 0xEA, 0xCE, 0xE3, 0xFB, 0x76, 0xB6, 0x72, 0xFD, 0xF8, 0x6E, 0x62, 0x6A, 0x48, 0x85, 0x7F,
0xE9, 0x72, 0xEE, 0x36, 0x4D, 0x03, 0x5F, 0x1D, 0xB3, 0xDF, 0x72, 0xCE, 0x19, 0x24, 0x24, 0x6D,
0x33, 0x84, 0xCE, 0xB5, 0x86, 0xE0, 0x26, 0x3A, 0xD0, 0xD8, 0xA1, 0x6D, 0x77, 0xA8, 0xD1, 0xD3,
0x88, 0xDB, 0xC7, 0x97, 0x5C, 0x81, 0x68, 0x54, 0xD6, 0x04, 0x48, 0xC0, 0x4D, 0x43, 0xAE, 0xAE,
0x8B, 0xBA, 0x29, 0xFA, 0xD0, 0x8C, 0x6A, 0xBA, 0x84, 0x26, 0x2B, 0xDE, 0x1B, 0xBA, 0x73, 0x50,
0xB6, 0xB4, 0x80, 0x20, 0x62, 0xB8, 0xC4, 0x0D, 0xA1, 0x0C, 0xC1, 0x15, 0x63, 0xC2, 0x55, 0xB0,
0xE8, 0x72, 0xC7, 0x31, 0x6C, 0x88, 0xDB, 0xCB, 0x0C, 0x25, 0x88, 0x16, 0xB1, 0xDC, 0xCF, 0x2E,
0x18, 0xFF, 0x08, 0xB6, 0x74, 0x11, 0xA7, 0xEB, 0x36, 0x7A, 0x46, 0x1A, 0x17, 0x93, 0xF1, 0x59,
0xF8, 0x0C, 0x2C, 0x70, 0x08, 0x38, 0xEC, 0xF6, 0x8A, 0x90, 0x81, 0x66, 0xAC, 0x59, 0xB6, 0x9C,
0xEC, 0xDC, 0x50, 0xD6, 0xEF, 0xF7, 0x8F, 0x59, 0x4B, 0xD1, 0x1A, 0xAC, 0xDD, 0xA5, 0x74, 0xA8,
0x03, 0x1B, 0x42, 0xBF, 0x3C, 0xCB, 0x86, 0x82, 0x28, 0x23, 0x54, 0x3B, 0x62, 0x24, 0xC3, 0xB2,
0x29, 0x3D, 0x38, 0xB6, 0x1D, 0xB7, 0x69, 0x0A, 0xE1, 0x9B, 0x3B, 0xA8, 0x6A, 0x01, 0x1A, 0x71,
0x33, 0x02, 0xBA, 0x6D, 0xC7, 0x1B, 0xAA, 0x75, 0xAC, 0x7E, 0x66, 0x14, 0x7C, 0x0F, 0xFA, 0xCA,
0x0A, 0xE7, 0xAE, 0xB6, 0x2B, 0xDB, 0xD3, 0x60, 0xE0, 0x2E, 0xC8, 0xD8, 0x01, 0x0A, 0xD4, 0x24,
0x04, 0xDC, 0x27, 0x2C, 0xCD, 0x30, 0xA1, 0x73, 0x24, 0x3B, 0x2C, 0xD3, 0x36, 0xAC, 0x61, 0xDF,
0xB0, 0xBB, 0x5D, 0xA3, 0x33, 0x68, 0x09, 0x19, 0x50, 0xD7, 0x49, 0xC5, 0x99, 0xB9, 0x8F, 0xCC,
0x69, 0x74, 0xCC, 0xEE, 0xD4, 0xC1, 0x66, 0xC9, 0xCC, 0x7A, 0xA6, 0xE9, 0x28, 0x21, 0xDA, 0x23,
0x11, 0x25, 0x69, 0x35, 0x6A, 0xAE, 0x03, 0xDF, 0x0F, 0x09, 0x4F, 0xC0, 0xE2, 0x8D, 0xB7, 0x6A,
0x23, 0xEC, 0x80, 0x3E, 0xD7, 0x6E, 0x14, 0x24, 0x9B, 0x90, 0x81, 0x98, 0x73, 0xBC, 0xC7, 0xDB,
0xA4, 0x19, 0xA8, 0x28, 0x89, 0x03, 0xC6, 0xFC, 0x4C, 0x8B, 0x61, 0xFB, 0x96, 0xB8, 0x29, 0x48,
0xE4, 0x9C, 0x48, 0x33, 0x1E, 0x69, 0xCF, 0x35, 0x26, 0xB8, 0x8E, 0xBF, 0xB6, 0x37, 0x19, 0x26,
0x4B, 0x24, 0x24, 0x1E, 0xE5, 0xE2, 0xE0, 0x5A, 0x0F, 0x1A, 0xAB, 0x0D, 0x4C, 0xE7, 0xED, 0x24,
0x85, 0x65, 0xA4, 0xDB, 0xD3, 0x68, 0xDD, 0xED, 0x0E, 0xDD, 0xF9, 0xB0, 0x82, 0x41, 0x36, 0x19,
0xF8, 0x6E, 0xAF, 0xC4, 0x45, 0x20, 0xBA, 0x51, 0x6A, 0xE3, 0xD0, 0x5E, 0x6A, 0x62, 0x28, 0x5F,
0x6A, 0x9A, 0xD4, 0x50, 0x4E, 0x0E, 0x29, 0x0F, 0xE2, 0x43, 0x8D, 0xB0, 0xF6, 0x68, 0x60, 0x8E,
0xCD, 0x8A, 0xB0, 0x96, 0x6D, 0xCF, 0x7B, 0xE6, 0xDE, 0x73, 0x13, 0xDC, 0x54, 0x89, 0xC1, 0x2C,
0x8D, 0x1A, 0x29, 0x29, 0xA9, 0xB0, 0xB2, 0x51, 0x01, 0xCA, 0xC3, 0xE1, 0xD0, 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, 0x55, 0x23, 0xC1,
0x80, 0x8C, 0xBD, 0x41, 0x1E, 0x42, 0xBC, 0xE1, 0xA0, 0xEB, 0x4B, 0x56, 0xBE, 0x1B, 0x2D, 0x41,
0x5B, 0x35, 0xD0, 0x67, 0xFB, 0xC4, 0x27, 0x15, 0x4E, 0x64, 0xEE, 0x79, 0xBE, 0x25, 0x39, 0xB9,
0xE3, 0x5E, 0xAF, 0x67, 0xEF, 0x3B, 0x2B, 0x37, 0x6B, 0x93, 0x34, 0x05, 0xC8, 0x29, 0xC3, 0x76,
0x99, 0x96, 0x8F, 0xFE, 0xB3, 0x01, 0xF1, 0xA8, 0x34, 0xB5, 0x98, 0x36, 0xEA, 0x75, 0xFB, 0xDD,
0xDE, 0x93, 0x91, 0x0C, 0x5D, 0xF3, 0x1B, 0x8F, 0x8C, 0x7A, 0xA3, 0xEE, 0x63, 0x64, 0xAC, 0xD2,
0x96, 0x64, 0x16, 0xE2, 0xB6, 0x79, 0x98, 0xAD, 0xD1, 0xB4, 0xD8, 0xFC, 0x93, 0xBA, 0xE6, 0x7B,
0xFC, 0xAF, 0xD1, 0x75, 0xAD, 0x3C, 0xB5, 0xDA, 0xB6, 0xE7, 0xFD, 0x9E, 0xED, 0xFD, 0x3E, 0x6D,
0x0F, 0x86, 0x73, 0x6B, 0x30, 0x7A, 0x9A, 0xB6, 0x39, 0x6D, 0x45, 0xEA, 0x5A, 0x7D, 0x4B, 0x1F,
0x41, 0x58, 0x11, 0x1E, 0x72, 0x12, 0x4F, 0xFC, 0x31, 0x98, 0xD1, 0xA2, 0xEA, 0x76, 0xBD, 0xEE,
0xA2, 0xEB, 0xAA, 0x4C, 0x4A, 0xD8, 0x27, 0x9A, 0x14, 0x00, 0x13, 0x2D, 0x0A, 0xF2, 0xF1, 0x96,
0xC9, 0x21, 0xD9, 0xE4, 0x80, 0xEC, 0x1C, 0xD8, 0xF3, 0xC6, 0x5D, 0xD3, 0xF6, 0x2A, 0x62, 0x0E,
0x07, 0x96, 0x67, 0x8D, 0x99, 0x98, 0xC1, 0x7A, 0xB9, 0x13, 0xB1, 0x6C, 0xE5, 0x46, 0xD5, 0x94,
0x78, 0x50, 0x87, 0x57, 0x3C, 0x01, 0xE7, 0xB4, 0x42, 0x84, 0x1A, 0x2C, 0x31, 0xF1, 0x55, 0x99,
0xD7, 0x04, 0x11, 0xFF, 0x72, 0xC7, 0x03, 0xC1, 0x99, 0xA4, 0xA7, 0x57, 0xDE, 0x35, 0x45, 0xFA,
0x21, 0xC7, 0x3E, 0xB4, 0xD2, 0xBF, 0x7E, 0x5D, 0x21, 0x88, 0x06, 0x19, 0xC2, 0x17, 0x69, 0x10,
0xEC, 0x30, 0x95, 0xB7, 0x4E, 0x84, 0x8D, 0x2D, 0x82, 0x90, 0xB0, 0xEF, 0xDC, 0x5D, 0xF3, 0xB1,
0xE3, 0x1E, 0xEC, 0x6A, 0x10, 0x25, 0x1B, 0xFA, 0x0B, 0x9E, 0x9E, 0xA7, 0x38, 0xEE, 0xD7, 0xC9,
0x44, 0x2E, 0x0B, 0xBF, 0xB6, 0x37, 0x49, 0x18, 0xBB, 0x7E, 0x7B, 0xBE, 0x81, 0x68, 0xF6, 0x77,
0x5E, 0xF6, 0xAF, 0xCD, 0xCB, 0x9C, 0x93, 0x6E, 0xDE, 0x9F, 0x7B, 0xE6, 0x41, 0xE8, 0xEE, 0x0D,
0xE6, 0x23, 0xDF, 0x7D, 0xD4, 0xA6, 0x0A, 0xAB, 0xF8, 0x7B, 0x6B, 0xFF, 0x7D, 0xB6, 0xB6, 0x6B,
0xCD, 0x4D, 0xBF, 0x7A, 0xD2, 0xB7, 0xE6, 0x03, 0x7F, 0xD4, 0x7F, 0xDC, 0xD6, 0x72, 0x00, 0xFB,
0x7B, 0x6B, 0xFF, 0xCD, 0xB7, 0xD6, 0x1E, 0x8C, 0xDD, 0xB9, 0xB7, 0xCF, 0x81, 0xBA, 0x04, 0xE7,
0x65, 0xF4, 0x56, 0xD0, 0xBC, 0x94, 0x0A, 0x08, 0x34, 0x17, 0x15, 0xA6, 0x45, 0x1C, 0x83, 0x52,
0x4F, 0x14, 0x98, 0x58, 0xFD, 0xE5, 0x69, 0x35, 0xA6, 0x83, 0x3A, 0x2F, 0x1A, 0x1C, 0x86, 0x49,
0xBE, 0x57, 0x3D, 0x25, 0x69, 0xE8, 0xE2, 0x4B, 0x25, 0x55, 0x3A, 0xBB, 0xBD, 0xF1, 0xC8, 0x9F,
0x57, 0x54, 0xDF, 0x37, 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, 0xBA, 0x03, 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, 0x5E, 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, 0x81, 0x94, 0x5E, 0x18, 0x4D, 0xAF, 0xD3, 0x27, 0xEB, 0xC7,
0x2F, 0xE5, 0x50, 0x9C, 0xDF, 0xB9, 0xDB, 0x27, 0xEE, 0x6D, 0xCA, 0xD6, 0xC8, 0xFB, 0xFA, 0x23,
0xF5, 0x2A, 0x26, 0xF3, 0x52, 0x42, 0x22, 0x0D, 0xB2, 0x7D, 0xA0, 0xCF, 0x0B, 0xD7, 0xC3, 0xC1,
0xF0, 0x28, 0x3D, 0xBB, 0x57, 0xDC, 0x5F, 0x5D, 0xF2, 0x9B, 0xDC, 0xAB, 0x4B, 0x7E, 0xAF, 0xCB,
0x6E, 0x9B, 0xAE, 0xFC, 0xE0, 0x56, 0x63, 0xED, 0x53, 0x3D, 0x37, 0x21, 0x77, 0x0E, 0x8B, 0xDD,
0x50, 0x22, 0x9C, 0x8F, 0x5F, 0xCE, 0x98, 0xFA, 0xEC, 0xBF, 0xAD, 0x8E, 0xA5, 0xBD, 0x88, 0xE6,
0x59, 0xE2, 0xF0, 0xF7, 0xAB, 0x4B, 0x20, 0x9F, 0x5D, 0xF1, 0x68, 0x3A, 0xBB, 0x5A, 0xD9, 0xB3,
0x37, 0x54, 0xCB, 0x08, 0x59, 0x67, 0xDA, 0x36, 0xDE, 0x68, 0x7E, 0xAC, 0x45, 0x31, 0xD5, 0x56,
0x2E, 0x5E, 0x84, 0x44, 0x5B, 0x8D, 0x39, 0x7C, 0x07, 0x6F, 0x92, 0xB5, 0x88, 0x04, 0x74, 0x45,
0x52, 0xA5, 0xA9, 0xB3, 0xFC, 0x6A, 0x68, 0x49, 0x88, 0x05, 0x5E, 0x8D, 0x87, 0x7C, 0x2D, 0xA0,
0x5A, 0x9C, 0xC2, 0x17, 0x1F, 0xE0, 0x0C, 0x19, 0xA6, 0xDA, 0x22, 0x48, 0xD7, 0x77, 0x10, 0x2B,
0xB5, 0x60, 0x01, 0x2C, 0xF0, 0x20, 0x8C, 0x25, 0x37, 0x58, 0x91, 0x0D, 0xCB, 0x92, 0x62, 0xE0,
0x92, 0xBC, 0xD0, 0xCD, 0x32, 0x58, 0x12, 0x22, 0x9F, 0xAE, 0x05, 0xFE, 0x54, 0xBF, 0x7E, 0xFF,
0xE6, 0xF5, 0xEB, 0x6B, 0xFD, 0xB0, 0x5B, 0x5E, 0x5E, 0xE8, 0xB3, 0xD7, 0xD0, 0xBA, 0xD2, 0x5E,
0x43, 0x34, 0xCA, 0xB6, 0x19, 0x25, 0x6B, 0xB1, 0xBC, 0x03, 0x02, 0xD4, 0x1C, 0x30, 0x62, 0x79,
0x8B, 0xC6, 0xF2, 0x16, 0x1D, 0x43, 0x18, 0x9F, 0x87, 0xE5, 0x2C, 0x3C, 0x78, 0xEA, 0x5A, 0x04,
0xD8, 0x3D, 0xD5, 0xD7, 0x5B, 0x6C, 0xCC, 0x7E, 0xF9, 0x55, 0xD7, 0xD6, 0x9B, 0x90, 0x06, 0x09,
0x6A, 0x5B, 0x7E, 0xD2, 0x67, 0x9A, 0xE0, 0x24, 0xE6, 0x80, 0xE3, 0x9A, 0xA6, 0x94, 0x05, 0x75,
0x31, 0x03, 0xCF, 0x7F, 0xF8, 0x1C, 0xA5, 0x94, 0x48, 0xD7, 0xE2, 0xC8, 0x0B, 0x03, 0xEF, 0x0B,
0xAC, 0x91, 0x44, 0x3E, 0x4E, 0xD5, 0x6C, 0x39, 0xBA, 0x76, 0xEB, 0x86, 0x1B, 0xA0, 0xFB, 0xC8,
0xC6, 0xEA, 0xB3, 0xD2, 0xBE, 0x25, 0x69, 0xBC, 0x4C, 0xB1, 0x8C, 0x20, 0xB6, 0xFE, 0x36, 0xC8,
0x82, 0x79, 0x10, 0x06, 0x74, 0x3B, 0x59, 0x41, 0x12, 0x44, 0x22, 0x29, 0x7A, 0x92, 0x2E, 0xF9,
0x94, 0xEC, 0x03, 0x98, 0xDB, 0x54, 0x07, 0x6B, 0x82, 0xC5, 0x5F, 0x4A, 0x16, 0x60, 0x48, 0x29,
0xFF, 0x3B, 0xD0, 0xFB, 0x71, 0xD5, 0xF1, 0x1B, 0xE3, 0x2B, 0x0A, 0x54, 0xD4, 0xD7, 0x98, 0x95,
0x4E, 0x75, 0xF3, 0x79, 0xAE, 0xD4, 0xF3, 0x54, 0x51, 0x5A, 0xF7, 0xF7, 0xF1, 0x1A, 0xB2, 0x31,
0xBF, 0xD9, 0xC0, 0x2B, 0xC4, 0x86, 0xD1, 0x70, 0xC3, 0xB0, 0xA1, 0xA8, 0xE1, 0x03, 0x59, 0x80,
0xB4, 0x2B, 0x94, 0x9C, 0xFA, 0x07, 0xB3, 0xA2, 0x9C, 0x39, 0xB7, 0xEF, 0x53, 0x02, 0x06, 0xE7,
0x07, 0x69, 0xB3, 0xA5, 0x2B, 0x92, 0xC0, 0xF1, 0x19, 0x46, 0x66, 0xB7, 0x4B, 0x49, 0xD9, 0x33,
0x75, 0x8D, 0x03, 0x0B, 0xFF, 0x7C, 0x1B, 0x90, 0xBB, 0xEF, 0x62, 0xD0, 0x10, 0x9E, 0x6A, 0x7B,
0xF8, 0x0F, 0xC6, 0xA7, 0x60, 0x07, 0x1A, 0xB4, 0xF5, 0x75, 0x6D, 0x8B, 0xBA, 0xD3, 0x25, 0x75,
0x57, 0xA1, 0xB6, 0xE1, 0x73, 0x0A, 0x83, 0x6C, 0x78, 0x6C, 0xD9, 0x03, 0x76, 0x31, 0x9C, 0xEA,
0x22, 0xB7, 0xD2, 0x2F, 0x0B, 0x3E, 0x38, 0x74, 0xCB, 0xD8, 0x09, 0x3E, 0x56, 0xBF, 0xE0, 0x83,
0x9F, 0x1F, 0xE0, 0x83, 0x49, 0x30, 0xF2, 0xB1, 0xB8, 0x40, 0x36, 0x3C, 0xF2, 0x8C, 0x12, 0x5A,
0x47, 0xE2, 0xEB, 0x9D, 0xE0, 0x38, 0x82, 0xCD, 0x16, 0x4C, 0x58, 0x72, 0xAA, 0xCF, 0x2E, 0x40,
0x81, 0xC0, 0x03, 0xF4, 0x08, 0xAA, 0x98, 0x09, 0x17, 0x11, 0x3A, 0xE5, 0x8A, 0x44, 0x73, 0xE1,
0x19, 0x54, 0xAE, 0x3E, 0xF1, 0xB5, 0x32, 0x3C, 0x5F, 0x82, 0x99, 0x6F, 0x02, 0x33, 0x35, 0x97,
0xAE, 0x72, 0x4A, 0xBC, 0x63, 0x93, 0xC6, 0xAB, 0x52, 0x5F, 0xA2, 0xED, 0x5C, 0x4A, 0x3B, 0xC2,
0x87, 0xA4, 0xE0, 0x5F, 0x4A, 0x57, 0xEB, 0xBA, 0xB4, 0xF3, 0x22, 0xFB, 0x46, 0x23, 0xE4, 0x38,
0xC8, 0x8C, 0x70, 0xA5, 0x9A, 0xC3, 0x0D, 0x58, 0x19, 0xF0, 0x5E, 0x61, 0xFB, 0xEC, 0x67, 0xF0,
0x83, 0xFC, 0xCB, 0x35, 0x68, 0x49, 0x7E, 0x29, 0x19, 0x50, 0xA5, 0x4D, 0xAC, 0x88, 0xB5, 0x0A,
0x49, 0xC5, 0x64, 0xE8, 0x00, 0x39, 0x4E, 0x7C, 0x46, 0x5B, 0x65, 0xE3, 0x38, 0x18, 0xCB, 0xF5,
0x1C, 0xC1, 0x1D, 0x1E, 0xDE, 0xB8, 0x3F, 0x66, 0x90, 0xE3, 0x6D, 0xB2, 0x42, 0xA3, 0x07, 0xEF,
0xE7, 0x78, 0x63, 0x81, 0x7C, 0x12, 0x57, 0x3F, 0x32, 0xB0, 0x7D, 0x00, 0xF8, 0x4A, 0xDE, 0x7B,
0x14, 0x07, 0xEF, 0x8E, 0xA2, 0xA0, 0x62, 0x2F, 0x4F, 0x43, 0x3E, 0xE0, 0x7D, 0x80, 0x01, 0x1C,
0xE7, 0x0E, 0xD1, 0x0F, 0xD7, 0xA3, 0xCE, 0xF8, 0x18, 0xE8, 0x5B, 0xDC, 0xE5, 0xE0, 0x87, 0x1F,
0xEB, 0xE1, 0x2F, 0xE7, 0x0C, 0xE7, 0xB6, 0x88, 0x0D, 0x5F, 0x67, 0x4B, 0xFD, 0x38, 0xFB, 0xD9,
0x07, 0x02, 0x9B, 0x07, 0x07, 0xCF, 0x68, 0x99, 0x07, 0xBC, 0x3B, 0x37, 0xA0, 0x1D, 0xF8, 0x0F,
0x9C, 0x0A, 0x98, 0x28, 0xAC, 0x3C, 0x48, 0x4C, 0x28, 0xF7, 0x1C, 0xDE, 0x73, 0x68, 0xFC, 0xD5,
0x4D, 0xE7, 0xEE, 0x07, 0xA9, 0x5F, 0x02, 0x87, 0xCE, 0xDC, 0x8F, 0x58, 0x5E, 0x50, 0xB6, 0x81,
0x52, 0xAA, 0x50, 0xD7, 0xC5, 0x73, 0x41, 0xE8, 0x59, 0x75, 0x67, 0x6F, 0x40, 0x74, 0x1A, 0x2C,
0xE0, 0xB4, 0x8C, 0x29, 0x02, 0x44, 0xDC, 0x6E, 0x8D, 0xA1, 0x15, 0x39, 0x9A, 0xCE, 0xD7, 0x20,
0x56, 0x52, 0xEA, 0x46, 0xF4, 0xD0, 0xF9, 0xB1, 0x17, 0x32, 0x55, 0x32, 0xFB, 0x08, 0xA7, 0xCD,
0x89, 0x58, 0x5E, 0x25, 0x14, 0xAA, 0x95, 0x79, 0x69, 0x0D, 0x9C, 0x3C, 0x5F, 0xE4, 0x67, 0x3C,
0xAC, 0x7E, 0xE6, 0x8D, 0x42, 0xE5, 0xC5, 0x3D, 0x7B, 0xA1, 0xB6, 0x55, 0x7A, 0xBE, 0x40, 0xEF,
0xA1, 0xEF, 0x0E, 0x80, 0xE2, 0x11, 0x42, 0x25, 0x82, 0x44, 0x15, 0x4C, 0xB6, 0x3D, 0x2C, 0x1C,
0x06, 0xCF, 0x23, 0xBA, 0x14, 0x2E, 0x5F, 0x76, 0x32, 0x69, 0xFB, 0xC7, 0xDC, 0xA6, 0x88, 0x8B,
0x9B, 0xF9, 0x3A, 0xA0, 0x1F, 0xC8, 0xFF, 0x6D, 0xC0, 0xE4, 0x30, 0x9A, 0x09, 0xAF, 0xE0, 0xED,
0xB5, 0xE0, 0x01, 0xD9, 0x65, 0x90, 0xD0, 0xD9, 0x62, 0x13, 0xB1, 0x0A, 0x07, 0xF8, 0xC2, 0xED,
0xDC, 0x85, 0x48, 0xB8, 0xBB, 0x85, 0x83, 0x29, 0x90, 0x2A, 0xCE, 0xAF, 0x1B, 0x74, 0xEA, 0x6D,
0x52, 0xAC, 0x5C, 0x20, 0x64, 0x77, 0xE0, 0xAC, 0x17, 0xD0, 0xA6, 0x7E, 0xA9, 0xB7, 0x8C, 0x68,
0x0A, 0x0F, 0x23, 0x98, 0x5A, 0x0E, 0x68, 0xAB, 0x49, 0x2E, 0x90, 0xCE, 0x17, 0xF2, 0x36, 0x78,
0x2C, 0x6D, 0x68, 0xB9, 0x9C, 0x9F, 0x74, 0x85, 0xCD, 0xB4, 0x71, 0xD9, 0x70, 0xB4, 0xE3, 0x11,
0xFD, 0x93, 0x3E, 0xBB, 0x64, 0x5E, 0xA0, 0x3B, 0xC1, 0x15, 0xED, 0x84, 0x24, 0x5A, 0xD2, 0x55,
0xDB, 0x72, 0x5A, 0xD1, 0xC5, 0x94, 0xFE, 0x12, 0xFC, 0x7A, 0x81, 0x33, 0x1F, 0x99, 0xF1, 0xC8,
0x84, 0xFA, 0x45, 0x74, 0xA1, 0x3F, 0x34, 0xA9, 0x7E, 0xC1, 0xB9, 0xE7, 0xFE, 0x2E, 0xA4, 0x30,
0x82, 0x8B, 0x0B, 0x27, 0x25, 0x74, 0x93, 0x46, 0x1A, 0x9B, 0x56, 0x75, 0x4E, 0x7D, 0x9F, 0x2B,
0x12, 0xEC, 0x2B, 0x5B, 0x7D, 0x0E, 0xC0, 0x70, 0x14, 0x65, 0x16, 0xD9, 0x44, 0xC3, 0xEE, 0x35,
0x64, 0x1C, 0x67, 0x9F, 0x65, 0x36, 0xD1, 0xC0, 0x6C, 0xC2, 0xB2, 0x47, 0xF8, 0xD7, 0x80, 0x45,
0xAB, 0x53, 0x89, 0xA4, 0xA0, 0xD1, 0xB7, 0x1B, 0x10, 0xCC, 0x1B, 0x16, 0x3C, 0x20, 0xFC, 0x37,
0x06, 0x0D, 0x0C, 0xFF, 0xF8, 0x90, 0xBC, 0xFB, 0x05, 0xEF, 0x61, 0x43, 0x98, 0x62, 0x03, 0xC3,
0x3A, 0x1C, 0x17, 0x7D, 0xA7, 0xA1, 0x5D, 0xCE, 0x84, 0xCE, 0xAA, 0x1C, 0xEB, 0x79, 0xD8, 0x65,
0x1E, 0x2C, 0x33, 0xA8, 0xE3, 0xD2, 0x35, 0x39, 0x97, 0xD1, 0x11, 0xB9, 0x06, 0xC3, 0x82, 0x27,
0xE0, 0xEA, 0x59, 0x92, 0xD9, 0x65, 0x9E, 0x96, 0xC9, 0x99, 0xE2, 0x53, 0x70, 0x1D, 0xA9, 0x5C,
0x7B, 0x8F, 0x61, 0x6A, 0x8F, 0x6B, 0x99, 0x74, 0xCF, 0x5C, 0x6E, 0x8F, 0x73, 0xE9, 0x75, 0xB9,
0x68, 0x43, 0x2E, 0xD9, 0x30, 0xE7, 0xA9, 0xB0, 0x1C, 0x9C, 0xCB, 0x73, 0xF0, 0x27, 0xF0, 0x1C,
0xFD, 0x11, 0x3C, 0x79, 0xFE, 0xA7, 0x18, 0x38, 0x1E, 0xA4, 0xA5, 0x7D, 0x73, 0x23, 0x3D, 0xDF,
0xBE, 0xED, 0x1E, 0xFC, 0x6B, 0x40, 0x70, 0x06, 0x7F, 0xD4, 0xFC, 0x69, 0xE3, 0xA7, 0xA1, 0xD1,
0xD5, 0xDE, 0xDA, 0xC6, 0x48, 0x7B, 0x3B, 0x34, 0xAC, 0x2E, 0x7B, 0x37, 0xB5, 0xB7, 0x96, 0x78,
0x8C, 0x0C, 0xCB, 0xE2, 0x8F, 0x3E, 0x6F, 0x1C, 0xC0, 0xC3, 0x64, 0x8F, 0xB1, 0x61, 0x0D, 0xD9,
0xFB, 0x98, 0x35, 0xD9, 0x30, 0xDC, 0x16, 0x0F, 0xDB, 0xB0, 0x46, 0xEC, 0x31, 0x62, 0x6D, 0x03,
0xE4, 0x3A, 0xD0, 0xBE, 0xE2, 0x02, 0xD3, 0xF8, 0x0B, 0xAC, 0x90, 0x5D, 0x33, 0x35, 0x78, 0xBA,
0xDB, 0x60, 0x2B, 0xAD, 0x5D, 0x28, 0x4F, 0x6B, 0x3E, 0xE3, 0x01, 0x81, 0xB4, 0x76, 0x0A, 0x92,
0x5C, 0x4C, 0x09, 0x43, 0x1F, 0x15, 0x47, 0x74, 0x96, 0xE2, 0x19, 0x3A, 0xE0, 0x88, 0xDE, 0x2A,
0x78, 0x78, 0xF1, 0x1A, 0x6B, 0xBE, 0xD7, 0x90, 0x9F, 0x46, 0xCB, 0xAC, 0x49, 0x0C, 0x2A, 0x95,
0x06, 0xB8, 0x40, 0x3A, 0x34, 0x7E, 0x1B, 0xDF, 0x91, 0xF4, 0x7B, 0xC8, 0x0D, 0x9A, 0x2D, 0x80,
0x59, 0x5A, 0x69, 0x21, 0x57, 0xF4, 0x65, 0xDB, 0x9A, 0x90, 0x19, 0x7D, 0x69, 0x4D, 0xCC, 0x82,
0x2D, 0x16, 0xDC, 0x5C, 0xEA, 0xAD, 0x58, 0xA6, 0xC5, 0x32, 0x44, 0x14, 0x11, 0xD1, 0x06, 0x72,
0x79, 0x00, 0xCC, 0x45, 0x13, 0x9E, 0xEA, 0x49, 0xF0, 0x9A, 0x0D, 0x9A, 0x68, 0xFA, 0x05, 0xE9,
0x70, 0x02, 0x83, 0x5E, 0x94, 0x87, 0xFC, 0xA6, 0x7E, 0xB9, 0x89, 0xA9, 0x1B, 0x6A, 0xBC, 0x42,
0xCD, 0x88, 0x28, 0x36, 0x9C, 0xA6, 0x81, 0x00, 0xEF, 0xAB, 0x24, 0x10, 0xB1, 0xFD, 0xD3, 0x14,
0xEF, 0x3C, 0x6F, 0x93, 0xF0, 0xD2, 0xA8, 0xA6, 0xB3, 0xA1, 0x57, 0x6B, 0x02, 0x71, 0x50, 0x5B,
0x07, 0x11, 0x18, 0x4C, 0x83, 0x65, 0x62, 0x1C, 0x31, 0x56, 0x60, 0x51, 0xD3, 0xC6, 0x18, 0x3E,
0xF1, 0xD8, 0xD6, 0xC0, 0x19, 0xE2, 0x9C, 0x1E, 0x70, 0x1D, 0x36, 0x90, 0x11, 0x8B, 0x43, 0x44,
0xB5, 0xFF, 0xB9, 0x6E, 0xF8, 0xB1, 0xB7, 0x59, 0xC3, 0x1E, 0x76, 0x96, 0x84, 0xFE, 0x10, 0x12,
0xFC, 0xF8, 0xDD, 0xF6, 0x0D, 0xEC, 0x9D, 0x48, 0xB2, 0x5B, 0x9D, 0x20, 0x8A, 0x48, 0xFA, 0xE3,
0xCD, 0x4F, 0x6F, 0xA7, 0xD4, 0x40, 0x4D, 0x1A, 0xB0, 0xCD, 0xCF, 0xD4, 0xE0, 0xC7, 0x95, 0x1C,
0x95, 0xE2, 0x21, 0xC4, 0x1E, 0xFA, 0x06, 0xEB, 0x1B, 0xEF, 0x16, 0x18, 0x15, 0x8D, 0x52, 0x1F,
0x0F, 0x5B, 0x76, 0xCB, 0x61, 0xAB, 0xA3, 0xA9, 0xF4, 0x32, 0xF5, 0x32, 0xF7, 0x44, 0xC0, 0x2A,
0xC5, 0x5D, 0x18, 0x42, 0x9A, 0xA6, 0x11, 0x5D, 0x58, 0xAD, 0x87, 0xE3, 0x18, 0x86, 0x45, 0x08,
0x66, 0x8A, 0xB7, 0x16, 0x31, 0x0D, 0xCC, 0x32, 0xC4, 0x94, 0x04, 0xB0, 0xA1, 0x31, 0x83, 0xB3,
0x00, 0x26, 0xA4, 0x32, 0xDF, 0xD4, 0xF7, 0x84, 0x15, 0xEA, 0xB3, 0x0E, 0xC8, 0x47, 0x9B, 0xD2,
0xE4, 0x4A, 0xA6, 0x5B, 0xB5, 0xEA, 0x0E, 0x66, 0xD2, 0x06, 0x65, 0x8F, 0xD6, 0xBE, 0xC5, 0x92,
0x01, 0xD4, 0x53, 0x30, 0x35, 0x21, 0x78, 0x4B, 0x7E, 0x5C, 0x17, 0x0E, 0xC4, 0xD1, 0x96, 0xDE,
0xB6, 0x40, 0xAF, 0x9C, 0xBE, 0x29, 0xFA, 0x21, 0xEA, 0x76, 0xF0, 0x74, 0xDA, 0x7A, 0xF1, 0xA2,
0xC9, 0x94, 0x75, 0xF3, 0x61, 0x26, 0x8C, 0x82, 0x65, 0xDD, 0x00, 0x31, 0x2A, 0xAE, 0x28, 0x70,
0x53, 0x03, 0x31, 0xDA, 0xEC, 0x13, 0x2D, 0x50, 0xC6, 0x32, 0x6C, 0x40, 0x09, 0xC3, 0xB6, 0x10,
0x6B, 0x6C, 0xFC, 0x3C, 0xE0, 0x8F, 0x21, 0x6B, 0xB3, 0x10, 0x1F, 0xDE, 0x5A, 0xB6, 0x78, 0xB7,
0x34, 0x1C, 0x66, 0x9D, 0x81, 0x18, 0x58, 0xC7, 0xD7, 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, 0x2E, 0xE5, 0x12, 0x73, 0x56, 0x7D, 0xC1, 0xC9, 0x14, 0xAC, 0xBA, 0x9C, 0x95, 0x65,
0x9E, 0xC1, 0x0B, 0xD6, 0x7C, 0xC0, 0xA7, 0x57, 0xE1, 0xD3, 0x7B, 0x22, 0x9F, 0x51, 0x85, 0xCF,
0xE8, 0x0C, 0x3E, 0xB2, 0x76, 0xC0, 0xF2, 0x27, 0x58, 0x66, 0xE3, 0xEA, 0xE6, 0x95, 0xC8, 0xD5,
0x3E, 0x89, 0x64, 0xED, 0x53, 0x23, 0x2F, 0x4B, 0xCA, 0xDA, 0x75, 0x72, 0xEF, 0x80, 0xF9, 0xBA,
0xDA, 0x2A, 0x25, 0x8B, 0xA9, 0xDE, 0x00, 0x3F, 0x66, 0xA0, 0xAB, 0x98, 0x09, 0xDA, 0xD9, 0x45,
0x03, 0x92, 0x72, 0x37, 0x05, 0x57, 0x9E, 0x7E, 0x06, 0x01, 0xA2, 0x2F, 0xA5, 0xAC, 0x3A, 0xFF,
0x25, 0x81, 0x3E, 0x6B, 0xE0, 0xCC, 0x15, 0x62, 0xAE, 0x73, 0x91, 0x0F, 0xBB, 0xF0, 0x77, 0xF3,
0x6A, 0x06, 0xB2, 0x71, 0x29, 0x2B, 0xF6, 0x28, 0xC6, 0xF2, 0x11, 0xD2, 0xEC, 0xCC, 0xE7, 0x0D,
0x75, 0xBE, 0x4F, 0xA2, 0x70, 0xF4, 0x49, 0x57, 0x5C, 0xF9, 0x15, 0xC4, 0x0F, 0x4A, 0x9A, 0x0C,
0xA9, 0xCA, 0xA2, 0xEB, 0x8D, 0x16, 0x66, 0x9A, 0xC8, 0x59, 0x4D, 0x17, 0x4B, 0x52, 0xE1, 0x7C,
0xDC, 0x27, 0xF1, 0x0D, 0x7D, 0xA1, 0xF0, 0xAB, 0x10, 0xFC, 0x2A, 0xAC, 0xFA, 0x55, 0x28, 0xFC,
0x6A, 0x5A, 0xF5, 0xAB, 0xF0, 0x0F, 0xF5, 0x2B, 0xC5, 0xAB, 0xC6, 0x3C, 0x3C, 0x8F, 0x31, 0xD0,
0x42, 0x90, 0x86, 0x78, 0x2C, 0xDE, 0xFA, 0x18, 0x72, 0x7B, 0xE8, 0x45, 0x3D, 0xF4, 0xBB, 0x3E,
0x73, 0x3E, 0x9B, 0x0D, 0xC5, 0x07, 0x06, 0x6A, 0x74, 0xC5, 0x2E, 0xA3, 0xEF, 0xB3, 0x77, 0x9B,
0x7B, 0x22, 0xF4, 0x9F, 0x17, 0xA7, 0x0B, 0xA3, 0xD2, 0x71, 0x5B, 0xCA, 0x27, 0x00, 0x2D, 0xDF,
0xFE, 0x3C, 0xAB, 0x39, 0xBC, 0x0E, 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, 0xEB, 0xF7, 0x4D, 0xFD, 0x7B,
0xFE, 0x41, 0xF3, 0xB1, 0x0B, 0xC7, 0xC4, 0x0B, 0xDC, 0x4C, 0x9E, 0x1E, 0x80, 0x39, 0x96, 0xF2,
0x27, 0x36, 0x88, 0x40, 0x06, 0x7B, 0xC0, 0x53, 0x26, 0x60, 0xA7, 0xD8, 0xC2, 0x18, 0xD8, 0xC0,
0x38, 0xDD, 0x9E, 0xE0, 0x0D, 0x63, 0xCA, 0xEC, 0x95, 0x02, 0xB0, 0x38, 0xA9, 0x25, 0x29, 0x44,
0x36, 0x38, 0xDB, 0xBE, 0xE7, 0xE5, 0x1A, 0x76, 0xD1, 0x50, 0xF0, 0x66, 0x05, 0x23, 0xC8, 0x09,
0x40, 0xB5, 0xD1, 0x26, 0x0C, 0x9F, 0x4D, 0x49, 0x65, 0x1E, 0x4F, 0x32, 0x84, 0x79, 0x3A, 0xE0,
0x84, 0xEB, 0x66, 0x4B, 0x99, 0x4E, 0x1D, 0xCA, 0xA2, 0x29, 0x4F, 0x25, 0x22, 0x72, 0xA7, 0xFD,
0xEF, 0x4F, 0x6F, 0x7F, 0xA4, 0x34, 0x11, 0x27, 0x78, 0x38, 0x50, 0xEB, 0x97, 0xCC, 0x04, 0x5E,
0xF2, 0xDF, 0x1F, 0x4C, 0x61, 0x4D, 0x10, 0x37, 0x21, 0x93, 0xC2, 0x56, 0x5E, 0xB6, 0xBA, 0x20,
0x91, 0x17, 0xFB, 0xE4, 0xE3, 0x87, 0x37, 0x4D, 0xDA, 0x32, 0x58, 0x27, 0x4B, 0x1A, 0xD4, 0x0E,
0x35, 0x71, 0x39, 0xBE, 0xB9, 0xA2, 0x68, 0xDB, 0xEA, 0x30, 0x57, 0xE9, 0x14, 0x95, 0x2C, 0x51,
0xD5, 0x0A, 0x61, 0xCD, 0x51, 0x27, 0x8E, 0x60, 0x71, 0xFE, 0x16, 0x53, 0x25, 0xE2, 0xAD, 0xF0,
0x27, 0x7D, 0xD3, 0x3C, 0x37, 0x68, 0xED, 0x20, 0xE3, 0xEC, 0x4D, 0xA7, 0x51, 0x87, 0x8D, 0xC1,
0x64, 0x93, 0xB4, 0xA0, 0xC9, 0x36, 0x4D, 0x6C, 0xE4, 0xE9, 0x95, 0xD4, 0xF1, 0x7F, 0x5D, 0xBF,
0xFB, 0x19, 0x10, 0x3D, 0x85, 0x04, 0x17, 0xC7, 0x67, 0x49, 0x1C, 0x65, 0xE4, 0x86, 0xDC, 0xD3,
0x13, 0x06, 0x7B, 0x42, 0x44, 0x51, 0x6D, 0x33, 0x6A, 0x53, 0xE2, 0x3D, 0x09, 0x61, 0x1B, 0x2B,
0xE5, 0x91, 0x3D, 0xAE, 0x26, 0x21, 0x51, 0x53, 0xFF, 0xCF, 0x1F, 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,
0x54, 0xE0, 0x5F, 0x8A, 0x94, 0xF9, 0x3F, 0x20, 0x7B, 0x3D, 0xBE, 0x2E, 0xBC, 0x6D, 0x69, 0x75,
0x78, 0x46, 0x7B, 0xC2, 0xFD, 0xCA, 0xF7, 0x40, 0x92, 0x40, 0x94, 0x42, 0x01, 0xD5, 0xB4, 0x4E,
0xA7, 0xA3, 0x5F, 0xE0, 0xE1, 0xE1, 0x35, 0xDE, 0xB9, 0x37, 0xCD, 0x16, 0xE6, 0xBB, 0xFB, 0x3D,
0x17, 0xE9, 0x24, 0x0C, 0xC8, 0xE2, 0x6D, 0x8B, 0x63, 0x0E, 0x1E, 0x1D, 0xCC, 0x67, 0x53, 0x59,
0x6F, 0x69, 0xED, 0x9E, 0x2C, 0x13, 0x8A, 0x74, 0x02, 0x50, 0xD8, 0xC2, 0x8F, 0x1B, 0x9C, 0x53,
0xF8, 0xC6, 0xEB, 0x38, 0x5D, 0xBF, 0x72, 0xA9, 0xEB, 0x44, 0x1D, 0x37, 0x49, 0x70, 0x93, 0x38,
0x1C, 0xA9, 0x79, 0x76, 0x35, 0xE5, 0xA4, 0x6A, 0xB2, 0xB9, 0xE3, 0x21, 0x13, 0xCB, 0x3A, 0x0A,
0x8F, 0xA2, 0x4C, 0x6D, 0x84, 0x2A, 0xAB, 0x8B, 0x50, 0xA4, 0xB1, 0x48, 0xE5, 0xD7, 0x78, 0xA7,
0xE3, 0x0B, 0xEB, 0x79, 0xFF, 0xEE, 0xFA, 0x06, 0x4F, 0x08, 0x8C, 0x8F, 0xCE, 0xAC, 0xC8, 0xEF,
0x70, 0xB5, 0x74, 0x20, 0xDA, 0xFC, 0x70, 0x0B, 0x1C, 0xDF, 0x02, 0xC8, 0x12, 0x00, 0x4D, 0x5C,
0x31, 0x2F, 0x24, 0x03, 0x34, 0x18, 0xCF, 0x2C, 0x1C, 0x1A, 0x47, 0x38, 0xB4, 0xE2, 0x45, 0xCC,
0x65, 0xA6, 0x7E, 0xEE, 0x33, 0x4F, 0xD3, 0xFF, 0x13, 0x34, 0x9F, 0xFB, 0xD1, 0x79, 0xD6, 0x22,
0xA6, 0xD3, 0x9D, 0x1A, 0xBF, 0x53, 0x3C, 0xDC, 0x2F, 0x7B, 0xB8, 0x70, 0x48, 0xF6, 0xD3, 0xFE,
0xA6, 0xFE, 0x2D, 0x38, 0x14, 0xFB, 0x51, 0x39, 0x9E, 0xD3, 0x60, 0x03, 0xFC, 0x67, 0x70, 0x74,
0x06, 0xC5, 0x30, 0x4F, 0x8C, 0x5A, 0xFB, 0xC2, 0x17, 0xD5, 0xA2, 0xFF, 0x9F, 0xEA, 0x8D, 0x8B,
0xBB, 0x73, 0xFC, 0x11, 0x0B, 0xFF, 0x6A, 0x34, 0x7C, 0xD8, 0x13, 0x41, 0xCA, 0x83, 0xF8, 0x55,
0xB9, 0x8C, 0xD1, 0x5E, 0xEA, 0x2D, 0x29, 0xF7, 0xF1, 0x4D, 0xB8, 0xFB, 0x9D, 0x0E, 0x5B, 0x5C,
0xA9, 0x3C, 0xCD, 0x08, 0x94, 0xF9, 0x9F, 0x40, 0xCE, 0x15, 0x77, 0x22, 0xCE, 0x9C, 0xAF, 0xF2,
0x13, 0x63, 0xC5, 0x4F, 0x00, 0xE4, 0x44, 0xE2, 0xD7, 0x49, 0x53, 0x1D, 0x7F, 0x9E, 0x74, 0xDA,
0x33, 0xD8, 0xF6, 0x9F, 0x40, 0x25, 0x89, 0x32, 0x65, 0x64, 0x32, 0x1E, 0x09, 0x3A, 0x1C, 0x73,
0xF4, 0x4B, 0xFD, 0xF1, 0x58, 0xC3, 0x7F, 0x24, 0x01, 0x62, 0xFE, 0x35, 0x70, 0xA3, 0x5A, 0xCF,
0xB9, 0x80, 0x73, 0xB0, 0x73, 0x27, 0xEE, 0xC5, 0x4E, 0xB0, 0x91, 0x37, 0x64, 0x4F, 0x33, 0x9F,
0x3F, 0xC4, 0xF8, 0x8F, 0x31, 0x91, 0x17, 0xC4, 0xC9, 0xFD, 0x99, 0x9E, 0x23, 0xC1, 0xF3, 0x4F,
0xF3, 0xB3, 0x43, 0x72, 0x45, 0x46, 0xE7, 0x20, 0x0F, 0xAB, 0xA0, 0x34, 0x62, 0x8A, 0x8E, 0x05,
0x1A, 0x59, 0x2B, 0x7C, 0xF1, 0x42, 0xEF, 0x95, 0xBF, 0xAA, 0xBD, 0xBF, 0xFD, 0x26, 0xF0, 0x5C,
0xE0, 0xD8, 0xC2, 0x05, 0x1B, 0xF7, 0xF5, 0x96, 0xA1, 0xDB, 0x70, 0x18, 0x95, 0xA3, 0x5A, 0xE5,
0x41, 0x9E, 0x1B, 0x79, 0x20, 0x21, 0x42, 0xBE, 0xC3, 0x62, 0x02, 0xCE, 0xD9, 0x55, 0xC7, 0x73,
0x28, 0x34, 0xA2, 0xA9, 0x09, 0xFE, 0xF5, 0x90, 0xD3, 0x3A, 0x41, 0x07, 0x6B, 0x85, 0x3D, 0xD3,
0xA0, 0xD3, 0x8C, 0xD0, 0x37, 0x68, 0x2A, 0xA0, 0xE5, 0xA6, 0x62, 0xED, 0xD1, 0xC5, 0xD4, 0x7A,
0xD8, 0xF9, 0xF9, 0xD6, 0x44, 0xE7, 0xD8, 0x61, 0x61, 0xD2, 0x3D, 0xAB, 0x1D, 0x19, 0xD1, 0xAC,
0x67, 0xC2, 0x11, 0xDB, 0x03, 0x8B, 0x4E, 0xF3, 0xF9, 0x21, 0x35, 0x0F, 0x63, 0x7E, 0x97, 0x0A,
0x3A, 0x46, 0xF3, 0xC1, 0x23, 0x81, 0x61, 0x91, 0x6E, 0x39, 0x14, 0x96, 0x54, 0x87, 0x61, 0xF0,
0x51, 0x71, 0xB2, 0x08, 0x94, 0x02, 0x37, 0xDE, 0xE2, 0xCD, 0x64, 0xF3, 0x84, 0x3B, 0x9F, 0x93,
0x50, 0x1F, 0xA7, 0x95, 0x97, 0xCE, 0x07, 0x08, 0xCB, 0x7E, 0xA0, 0xAD, 0x94, 0xD0, 0x2B, 0x99,
0xF7, 0x29, 0x79, 0x8E, 0xF2, 0x64, 0xA8, 0x2D, 0x6C, 0xF6, 0x34, 0xBD, 0x72, 0x47, 0x2C, 0x36,
0x52, 0x1C, 0xC2, 0x8C, 0x13, 0x11, 0xB5, 0xEE, 0x12, 0xB7, 0x42, 0x8D, 0xB7, 0x9C, 0x6C, 0xD8,
0xCB, 0x8F, 0xD7, 0x3F, 0x7C, 0x50, 0x4F, 0x58, 0x98, 0x71, 0x80, 0x78, 0x11, 0x85, 0x4C, 0xE4,
0x42, 0x7F, 0xF1, 0xFE, 0xDB, 0xEB, 0xEB, 0xFF, 0x79, 0xF7, 0xE1, 0x55, 0xFD, 0x10, 0x8A, 0x43,
0xAE, 0x3F, 0x7E, 0xF7, 0xD3, 0x9B, 0x9B, 0xE9, 0x16, 0x33, 0xC6, 0xA0, 0x0E, 0xF1, 0x83, 0x07,
0x4E, 0x5A, 0x70, 0xCC, 0x0A, 0x94, 0x63, 0xD6, 0x8B, 0x17, 0x00, 0xE1, 0xCF, 0xA0, 0x49, 0xBA,
0x66, 0xD9, 0x02, 0xF6, 0x46, 0xA0, 0x9E, 0x75, 0x22, 0x16, 0x36, 0x02, 0x79, 0xD6, 0x41, 0xA5,
0xAA, 0x05, 0x67, 0x08, 0x49, 0xCE, 0x5D, 0x10, 0xF9, 0xF1, 0x5D, 0x4D, 0xB4, 0x38, 0x7E, 0xDB,
0xE1, 0x5C, 0x5D, 0x8A, 0xEB, 0xE4, 0xAB, 0x4B, 0xF1, 0x03, 0x17, 0xF6, 0x3F, 0x96, 0xF9, 0x7F,
0x4B, 0x13, 0x97, 0xBB, 0x5F, 0x46, 0x00, 0x00
};

View File

@ -1,139 +0,0 @@
/*
storestrings.cpp - rolling storage 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 "storestrings.h"
//Constructor
STORESTRINGS_CLASS::STORESTRINGS_CLASS (int maxsize, int maxstringlength)
{
//for rolling buffer
//if max size is reached then remove oldest one and add the new one
_maxsize=maxsize;
//to limit the storage space
_maxstringlength=maxstringlength;
//need space for the "..."
if (_maxstringlength<4 && _maxstringlength!=-1) {
_maxstringlength=4;
}
}
//Destructor
STORESTRINGS_CLASS::~STORESTRINGS_CLASS ()
{
// clear list and content
clear();
}
bool STORESTRINGS_CLASS::setsize(int size)
{
_maxsize=size;
return true;
}
bool STORESTRINGS_CLASS::setlength(int len)
{
if (len < 4) {
return false;
}
_maxstringlength = len;
return true;
}
//Clear list and content
void STORESTRINGS_CLASS::clear()
{
//while list is not empty
while(_charlist.size()) {
//remove element
char * str = _charlist.pop();
//destroy it
delete str;
}
}
bool STORESTRINGS_CLASS::add (const __FlashStringHelper *str)
{
String stmp;
stmp=str;
return add(stmp.c_str());
}
//Add element in storage
bool STORESTRINGS_CLASS::add (const char * string)
{
//if we reach max size
if (_maxsize==_charlist.size()) {
//remove oldest one
char * str = _charlist.shift();
delete str;
}
//add new one
//get size including \0 at the end
size_t size = strlen(string)+1;
bool need_resize=false;
if ( (_maxstringlength!=-1) && (size >_maxstringlength+1 )) {
need_resize = true;
size=_maxstringlength+1;
}
//reserve memory
char * ptr = new char[size*sizeof(char)];
//copy string to storage
if (need_resize) {
//copy maximum length minus 3
strncpy(ptr,string,_maxstringlength-3);
strcpy(ptr+_maxstringlength-3,"...");
} else {
//copy as it is
strcpy(ptr,string);
}
//add storage to list
_charlist.add(ptr);
return true;
}
//Remove element at pos position
bool STORESTRINGS_CLASS::remove(int pos)
{
//be sure index is in range
if (pos<0 && pos>(_charlist.size()-1)) {
return false;
}
//remove item from list
char * str = _charlist.remove(pos);
//destroy item
delete str;
return true;
}
//Get element at pos position
const char * STORESTRINGS_CLASS::get(int pos)
{
//be sure index is in range
if (pos<0 && pos>(_charlist.size()-1)) {
return NULL;
}
return (const char *) _charlist.get(pos);
}
//Get index for defined string
int STORESTRINGS_CLASS::get_index(const char * string)
{
//parse the list until it is found
for (int p=0; p<_charlist.size(); p++) {
if (strcmp ( _charlist.get(p), string)==0) {
return p;
}
}
//if not found return -1
return -1;
}

View File

@ -1,61 +0,0 @@
/*
storestrings.h - rolling storage 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 STORESTRINGS_h
#define STORESTRINGS_h
#include <Arduino.h>
#include "GenLinkedList.h"
class STORESTRINGS_CLASS
{
public:
STORESTRINGS_CLASS (int maxsize = -1, int maxstringlength=-1);
~STORESTRINGS_CLASS ();
bool add (const char * string);
inline bool add (String & string)
{
return add(string.c_str());
};
bool add (const __FlashStringHelper *str);
bool remove(int pos);
const char * get(int pos);
int get_index(const char * string);
void clear();
inline int size()
{
return _charlist.size();
};
bool setsize(int size);
bool setlength(int len);
inline int getsize()
{
return _maxsize;
};
inline int getlength()
{
return _maxstringlength;
};
private:
int _maxsize;
int _maxstringlength;
GenLinkedList<char *> _charlist;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,90 +0,0 @@
/*
webinterface.h - 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
*/
#ifndef WEBINTERFACE_h
#define WEBINTERFACE_h
#include <Arduino.h>
#include <WiFiClient.h>
#include <WiFiServer.h>
#ifndef FS_NO_GLOBALS
#define FS_NO_GLOBALS
#endif
#include <FS.h>
#ifdef ARDUINO_ARCH_ESP8266
#include <ESP8266WebServer.h>
#else
#include <WebServer.h>
#endif
#include "storestrings.h"
#define MAX_EXTRUDERS 4
struct auth_ip {
IPAddress ip;
level_authenticate_type level;
char userID[17];
char sessionID[17];
uint32_t last_time;
auth_ip * _next;
};
class WEBINTERFACE_CLASS
{
public:
WEBINTERFACE_CLASS (int port = 80);
~WEBINTERFACE_CLASS();
#ifdef ARDUINO_ARCH_ESP8266
ESP8266WebServer web_server;
#else
WebServer web_server;
#endif
FS_FILE fsUploadFile;
#ifdef ERROR_MSG_FEATURE
STORESTRINGS_CLASS error_msg;
#endif
#ifdef INFO_MSG_FEATURE
STORESTRINGS_CLASS info_msg;
#endif
#ifdef STATUS_MSG_FEATURE
STORESTRINGS_CLASS status_msg;
#endif
bool restartmodule;
String getContentType(String filename);
level_authenticate_type is_authenticated();
bool AddAuthIP(auth_ip * item);
bool blockserial;
#ifdef AUTHENTICATION_FEATURE
level_authenticate_type ResetAuthIP(IPAddress ip,const char * sessionID);
auth_ip * GetAuth(IPAddress ip,const char * sessionID);
bool ClearAuthIP(IPAddress ip, const char * sessionID);
char * create_session_ID();
#endif
uint8_t _upload_status;
private:
auth_ip * _head;
uint8_t _nb_ip;
};
extern WEBINTERFACE_CLASS * web_interface;
#endif

View File

@ -1,505 +0,0 @@
/*
wificonf.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 "wificonf.h"
#include "bridge.h"
#include "webinterface.h"
#ifdef ARDUINO_ARCH_ESP8266
#include "ESP8266WiFi.h"
#ifdef MDNS_FEATURE
#include <ESP8266mDNS.h>
#endif
#else
#include <WiFi.h>
#include "esp_wifi.h"
#ifdef MDNS_FEATURE
#include <ESPmDNS.h>
#endif
#endif
#include "IPAddress.h"
#ifdef CAPTIVE_PORTAL_FEATURE
#include <DNSServer.h>
DNSServer dnsServer;
const byte DNS_PORT = 53;
#endif
#ifdef ARDUINO_ARCH_ESP8266
#include <ESP8266WebServer.h>
#else
#include <WebServer.h>
#endif
#ifdef SSDP_FEATURE
#include <ESP8266SSDP.h>
#endif
#ifdef NETBIOS_FEATURE
#ifdef ARDUINO_ARCH_ESP8266
#include <ESP8266NetBIOS.h>
#else
#include <ESPNetBIOS.h>
#endif
#endif
#ifdef ARDUINO_ARCH_ESP8266
extern "C" {
#include "user_interface.h"
}
#endif
#ifdef TIMESTAMP_FEATURE
#include <time.h>
#endif
WIFI_CONFIG::WIFI_CONFIG()
{
iweb_port=DEFAULT_WEB_PORT;
idata_port=DEFAULT_DATA_PORT;
baud_rate=DEFAULT_BAUD_RATE;
sleep_mode=DEFAULT_SLEEP_MODE;
_hostname[0]=0;
}
int32_t WIFI_CONFIG::getSignal(int32_t RSSI)
{
if (RSSI <= -100) {
return 0;
}
if (RSSI >= -50) {
return 100;
}
return (2* (RSSI+100));
}
const char * WIFI_CONFIG::get_hostname()
{
String hname;
#ifdef ARDUINO_ARCH_ESP8266
hname = WiFi.hostname();
#else
hname = WiFi.getHostname();
#endif
if (hname.length()==0) {
if (!CONFIG::read_string(EP_HOSTNAME, _hostname, MAX_HOSTNAME_LENGTH)) {
strcpy(_hostname,get_default_hostname());
}
} else {
strcpy(_hostname,hname.c_str());
}
return _hostname;
}
const char * WIFI_CONFIG::get_default_hostname()
{
static char hostname[13];
uint8_t mac [WL_MAC_ADDR_LENGTH];
WiFi.macAddress(mac);
if (0>sprintf(hostname,"ESP_%02X%02X%02X",mac[3],mac[4],mac[5])) {
strcpy (hostname, "ESP8266");
}
return hostname;
}
//safe setup if no connection
void WIFI_CONFIG::Safe_Setup()
{
#ifdef CAPTIVE_PORTAL_FEATURE
dnsServer.stop();
delay(100);
#endif
WiFi.disconnect();
//setup Soft AP
WiFi.mode(WIFI_AP);
IPAddress local_ip (DEFAULT_IP_VALUE[0],DEFAULT_IP_VALUE[1],DEFAULT_IP_VALUE[2],DEFAULT_IP_VALUE[3]);
IPAddress gateway (DEFAULT_GATEWAY_VALUE[0],DEFAULT_GATEWAY_VALUE[1],DEFAULT_GATEWAY_VALUE[2],DEFAULT_GATEWAY_VALUE[3]);
IPAddress subnet (DEFAULT_MASK_VALUE[0],DEFAULT_MASK_VALUE[1],DEFAULT_MASK_VALUE[2],DEFAULT_MASK_VALUE[3]);
String ssid = FPSTR(DEFAULT_AP_SSID);
String pwd = FPSTR(DEFAULT_AP_PASSWORD);
WiFi.softAP(ssid.c_str(),pwd.c_str());
delay(500);
WiFi.softAPConfig( local_ip, gateway, subnet);
delay(1000);
ESP_SERIAL_OUT.println(F("M117 Safe mode started"));
}
//Read configuration settings and apply them
bool WIFI_CONFIG::Setup(bool force_ap)
{
char pwd[MAX_PASSWORD_LENGTH+1];
char sbuf[MAX_SSID_LENGTH+1];
char hostname [MAX_HOSTNAME_LENGTH+1];
//int wstatus;
IPAddress currentIP;
byte bflag=0;
byte bmode=0;
//system_update_cpu_freq(SYS_CPU_160MHZ);
//set the sleep mode
if (!CONFIG::read_byte(EP_SLEEP_MODE, &bflag )) {
LOG("Error read Sleep mode\r\n")
return false;
}
#ifdef ARDUINO_ARCH_ESP8266
WiFi.setSleepMode ((WiFiSleepType_t)bflag);
#else
esp_wifi_set_ps((wifi_ps_type_t)bflag);
#endif
sleep_mode=bflag;
if (force_ap) {
bmode = AP_MODE;
} else {
//AP or client ?
if (!CONFIG::read_byte(EP_WIFI_MODE, &bmode ) ) {
LOG("Error read wifi mode\r\n")
return false;
}
}
if (!CONFIG::read_string(EP_HOSTNAME, hostname, MAX_HOSTNAME_LENGTH)) {
strcpy(hostname,get_default_hostname());
}
//this is AP mode
if (bmode==AP_MODE) {
LOG("Set AP mode\r\n")
if(!CONFIG::read_string(EP_AP_SSID, sbuf, MAX_SSID_LENGTH)) {
return false;
}
if(!CONFIG::read_string(EP_AP_PASSWORD, pwd, MAX_PASSWORD_LENGTH)) {
return false;
}
ESP_SERIAL_OUT.print(FPSTR(M117_));
ESP_SERIAL_OUT.print(F("SSID "));
ESP_SERIAL_OUT.println(sbuf);
LOG("SSID ")
LOG(sbuf)
LOG("\r\n")
//DHCP or Static IP ?
if (!CONFIG::read_byte(EP_AP_IP_MODE, &bflag )) {
LOG("Error IP mode\r\n")
return false;
}
LOG("IP Mode: ")
LOG(CONFIG::intTostr(bflag))
LOG("\r\n")
if (bflag==STATIC_IP_MODE) {
byte ip_buf[4];
LOG("Static mode\r\n")
//get the IP
LOG("IP value:")
if (!CONFIG::read_buffer(EP_AP_IP_VALUE,ip_buf, IP_LENGTH)) {
LOG("Error\r\n")
return false;
}
IPAddress local_ip (ip_buf[0],ip_buf[1],ip_buf[2],ip_buf[3]);
LOG(local_ip.toString())
LOG("\r\nGW value:")
//get the gateway
if (!CONFIG::read_buffer(EP_AP_GATEWAY_VALUE,ip_buf, IP_LENGTH)) {
LOG("Error\r\n")
return false;
}
IPAddress gateway (ip_buf[0],ip_buf[1],ip_buf[2],ip_buf[3]);
LOG(gateway.toString())
LOG("\r\nMask value:")
//get the mask
if (!CONFIG::read_buffer(EP_AP_MASK_VALUE,ip_buf, IP_LENGTH)) {
LOG("Error Mask value\r\n")
return false;
}
IPAddress subnet (ip_buf[0],ip_buf[1],ip_buf[2],ip_buf[3]);
LOG(subnet.toString())
LOG("\r\n")
//apply according active wifi mode
LOG("Set IP\r\n")
WiFi.softAPConfig( local_ip, gateway, subnet);
delay(100);
}
LOG("Disable STA\r\n")
WiFi.enableSTA(false);
delay(100);
LOG("Set phy mode\r\n")
//setup PHY_MODE
if (!CONFIG::read_byte(EP_AP_PHY_MODE, &bflag )) {
return false;
}
#ifdef ARDUINO_ARCH_ESP32
esp_wifi_set_protocol(ESP_IF_WIFI_AP, bflag);
#endif
LOG("Set AP\r\n")
//setup Soft AP
WiFi.mode(WIFI_AP);
delay(50);
WiFi.softAP(sbuf, pwd);
delay(100);
#ifdef ARDUINO_ARCH_ESP8266
WiFi.setPhyMode((WiFiPhyMode_t)bflag);
#endif
delay(100);
LOG("Get current config\r\n")
//get current config
#ifdef ARDUINO_ARCH_ESP32
wifi_config_t conf;
esp_wifi_get_config(ESP_IF_WIFI_AP, &conf);
#else
struct softap_config apconfig;
wifi_softap_get_config(&apconfig);
#endif
//set the chanel
if (!CONFIG::read_byte(EP_CHANNEL, &bflag )) {
return false;
}
#ifdef ARDUINO_ARCH_ESP32
conf.ap.channel=bflag;
#else
apconfig.channel=bflag;
#endif
//set Authentification type
if (!CONFIG::read_byte(EP_AUTH_TYPE, &bflag )) {
return false;
}
#ifdef ARDUINO_ARCH_ESP32
conf.ap.authmode=(wifi_auth_mode_t)bflag;
#else
apconfig.authmode=(AUTH_MODE)bflag;
#endif
//set the visibility of SSID
if (!CONFIG::read_byte(EP_SSID_VISIBLE, &bflag )) {
return false;
}
#ifdef ARDUINO_ARCH_ESP32
conf.ap.ssid_hidden=!bflag;
#else
apconfig.ssid_hidden=!bflag;
#endif
//no need to add these settings to configuration just use default ones
#ifdef ARDUINO_ARCH_ESP32
conf.ap.max_connection=DEFAULT_MAX_CONNECTIONS;
conf.ap.beacon_interval=DEFAULT_BEACON_INTERVAL;
if (esp_wifi_set_config(ESP_IF_WIFI_AP, &conf)!=ESP_OK){
ESP_SERIAL_OUT.println(F("M117 Error Wifi AP!"));
delay(1000);
}
#else
apconfig.max_connection=DEFAULT_MAX_CONNECTIONS;
apconfig.beacon_interval=DEFAULT_BEACON_INTERVAL;
//apply settings to current and to default
if (!wifi_softap_set_config(&apconfig) || !wifi_softap_set_config_current(&apconfig)) {
ESP_SERIAL_OUT.println(F("M117 Error Wifi AP!"));
delay(1000);
}
#endif
} else {
LOG("Set STA mode\r\n")
if(!CONFIG::read_string(EP_STA_SSID, sbuf, MAX_SSID_LENGTH)) {
return false;
}
if(!CONFIG::read_string(EP_STA_PASSWORD, pwd, MAX_PASSWORD_LENGTH)) {
return false;
}
ESP_SERIAL_OUT.print(FPSTR(M117_));
ESP_SERIAL_OUT.print(F("SSID "));
ESP_SERIAL_OUT.println(sbuf);
LOG("SSID ")
LOG(sbuf)
LOG("\r\n")
if (!CONFIG::read_byte(EP_STA_IP_MODE, &bflag )) {
return false;
}
if (bflag==STATIC_IP_MODE) {
byte ip_buf[4];
//get the IP
if (!CONFIG::read_buffer(EP_STA_IP_VALUE,ip_buf, IP_LENGTH)) {
return false;
}
IPAddress local_ip (ip_buf[0],ip_buf[1],ip_buf[2],ip_buf[3]);
//get the gateway
if (!CONFIG::read_buffer(EP_STA_GATEWAY_VALUE,ip_buf, IP_LENGTH)) {
return false;
}
IPAddress gateway (ip_buf[0],ip_buf[1],ip_buf[2],ip_buf[3]);
//get the mask
if (!CONFIG::read_buffer(EP_STA_MASK_VALUE,ip_buf, IP_LENGTH)) {
return false;
}
IPAddress subnet (ip_buf[0],ip_buf[1],ip_buf[2],ip_buf[3]);
//apply according active wifi mode
WiFi.config( local_ip, gateway, subnet);
}
WiFi.enableAP(false);
delay(100);
//setup PHY_MODE
if (!CONFIG::read_byte(EP_STA_PHY_MODE, &bflag )) {
return false;
}
#ifdef ARDUINO_ARCH_ESP32
esp_wifi_set_protocol(ESP_IF_WIFI_STA, bflag);
#endif
//setup station mode
WiFi.mode(WIFI_STA);
delay(100);
#ifdef ARDUINO_ARCH_ESP8266
WiFi.setPhyMode((WiFiPhyMode_t)bflag);
#endif
WiFi.begin(sbuf, pwd);
delay(100);
byte i=0;
//try to connect
byte dot = 0;
String msg;
while (WiFi.status() != WL_CONNECTED && i<40) {
switch(WiFi.status()) {
case 1:
ESP_SERIAL_OUT.print(FPSTR(M117_));
ESP_SERIAL_OUT.println(F("No SSID found!"));
break;
case 4:
ESP_SERIAL_OUT.print(FPSTR(M117_));
ESP_SERIAL_OUT.println(F("No Connection!"));
break;
default:
ESP_SERIAL_OUT.print(FPSTR(M117_));
if (dot == 0)msg = F("Connecting");
dot++;
msg.trim();
msg +=F(".");
//for smoothieware to keep position
for (byte i= 0;i< 4-dot; i++)msg +=F(" ");
if (dot == 4)dot=0;
ESP_SERIAL_OUT.println(msg);
break;
}
delay(500);
i++;
}
if (WiFi.status() != WL_CONNECTED) {
ESP_SERIAL_OUT.print(FPSTR(M117_));
ESP_SERIAL_OUT.println(F("Not Connectied!"));
return false;
}
#ifdef ARDUINO_ARCH_ESP8266
WiFi.hostname(hostname);
#else
WiFi.setHostname(hostname);
#endif
}
//Get IP
if (WiFi.getMode()==WIFI_STA) {
currentIP=WiFi.localIP();
} else {
currentIP=WiFi.softAPIP();
}
ESP_SERIAL_OUT.print(FPSTR(M117_));
ESP_SERIAL_OUT.println(currentIP);
ESP_SERIAL_OUT.flush();
return true;
}
bool WIFI_CONFIG::Enable_servers()
{
//start web interface
web_interface = new WEBINTERFACE_CLASS(wifi_config.iweb_port);
//here the list of headers to be recorded
const char * headerkeys[] = {"Cookie"} ;
size_t headerkeyssize = sizeof(headerkeys)/sizeof(char*);
//ask server to track these headers
web_interface->web_server.collectHeaders(headerkeys, headerkeyssize );
#ifdef CAPTIVE_PORTAL_FEATURE
if (WiFi.getMode()!=WIFI_STA ) {
// if DNSServer is started with "*" for domain name, it will reply with
// provided IP to all DNS request
dnsServer.setErrorReplyCode(DNSReplyCode::NoError);
dnsServer.start(DNS_PORT, "*", WiFi.softAPIP());
}
#endif
web_interface->web_server.begin();
#ifdef TCP_IP_DATA_FEATURE
//start TCP/IP interface
data_server = new WiFiServer (wifi_config.idata_port);
data_server->begin();
data_server->setNoDelay(true);
#endif
#ifdef MDNS_FEATURE
// Set up mDNS responder:
//useless in AP mode and service consuming
if (WiFi.getMode()!=WIFI_AP ){
char hostname [MAX_HOSTNAME_LENGTH+1];
if (!CONFIG::read_string(EP_HOSTNAME, hostname, MAX_HOSTNAME_LENGTH)) {
strcpy(hostname,get_default_hostname());
}
if (!mdns.begin(hostname)) {
ESP_SERIAL_OUT.print(FPSTR(M117_));
ESP_SERIAL_OUT.println(F("Error with mDNS!"));
delay(1000);
} else {
// Check for any mDNS queries and send responses
delay(100);
wifi_config.mdns.addService("http", "tcp", wifi_config.iweb_port);
}
}
#endif
#if defined(SSDP_FEATURE) || defined(NETBIOS_FEATURE)
String shost;
if (!CONFIG::read_string(EP_HOSTNAME, shost, MAX_HOSTNAME_LENGTH)) {
shost=wifi_config.get_default_hostname();
}
#endif
#ifdef SSDP_FEATURE
String stmp;
SSDP.setSchemaURL("description.xml");
SSDP.setHTTPPort( wifi_config.iweb_port);
SSDP.setName(shost.c_str());
stmp=String(ESP.getChipId());
SSDP.setSerialNumber(stmp.c_str());
SSDP.setURL("/");
SSDP.setModelName("ESP8266 01");
SSDP.setModelNumber("01");
SSDP.setModelURL("http://espressif.com/en/products/esp8266/");
SSDP.setManufacturer("Espressif Systems");
SSDP.setManufacturerURL("http://espressif.com");
SSDP.setDeviceType("upnp:rootdevice");
if (WiFi.getMode()!=WIFI_AP )SSDP.begin();
#endif
#ifdef NETBIOS_FEATURE
//useless in AP mode and service consuming
if (WiFi.getMode()!=WIFI_AP )NBNS.begin(shost.c_str());
#endif
return true;
}
bool WIFI_CONFIG::Disable_servers()
{
#ifdef TCP_IP_DATA_FEATURE
data_server->stop();
#endif
#ifdef CAPTIVE_PORTAL_FEATURE
if (WiFi.getMode()!=WIFI_STA ) {
dnsServer.stop();
}
#endif
#ifdef NETBIOS_FEATURE
//useless in AP mode and service consuming
if (WiFi.getMode()!=WIFI_AP )NBNS.end();
#endif
web_interface->web_server.stop();
return true;
}
WIFI_CONFIG wifi_config;

View File

@ -1,62 +0,0 @@
/*
wificonf.h - 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
*/
#ifndef WIFICONF_H
#define WIFICONF_H
#include <Arduino.h>
#include "config.h"
#include "IPAddress.h"
#ifdef ARDUINO_ARCH_ESP8266
#include "ESP8266WiFi.h"
#ifdef MDNS_FEATURE
#include <ESP8266mDNS.h>
#endif
#else
#include <WiFi.h>
#ifdef MDNS_FEATURE
#include <ESPmDNS.h>
#endif
#endif
class WIFI_CONFIG
{
public:
// multicast DNS responder feature
#ifdef MDNS_FEATURE
MDNSResponder mdns;
#endif
WIFI_CONFIG();
int iweb_port;
int idata_port;
long baud_rate;
int sleep_mode;
int32_t getSignal(int32_t RSSI);
bool Setup(bool force_ap = false);
void Safe_Setup();
bool Enable_servers();
bool Disable_servers();
const char * get_default_hostname();
const char * get_hostname();
private:
char _hostname[33];
};
extern WIFI_CONFIG wifi_config;
#endif

View File

@ -1,32 +0,0 @@
# Prerequisites
*.d
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Precompiled Headers
*.gch
*.pch
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
# Fortran module files
*.mod
*.smod
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
*.exe
*.out
*.app

View File

@ -1,99 +0,0 @@
sudo: false
language: python
python:
- "2.7"
os:
- linux
env:
- TESTCASE="1.8.3|esp8266|stable|esp8266:esp8266:nodemcuv2:CpuFrequency=80,FlashSize=4M3M"
- TESTCASE="1.8.3|esp8266|devel|esp8266com:esp8266:nodemcuv2:CpuFrequency=80,FlashSize=4M3M"
- TESTCASE="1.8.3|esp32|devel|espressif:esp32:esp32:FlashFreq=40"
script:
- echo -e "travis_fold:start:sketch_test_env_prepare"
- pip install pyserial
- IFS='|' read -r -a array <<< "${TESTCASE}"
- |
for index in "${!array[@]}"
do
case $index in
0) IDEVER="${array[index]}" ;;
1) PLATFORM="${array[index]}" ;;
2) RELEASE="${array[index]}" ;;
3) BOARD="${array[index]}" ;;
esac
done
- cd $HOME
- wget -O arduino.tar.xz https://downloads.arduino.cc/arduino-${IDEVER}-linux64.tar.xz
- tar xf arduino.tar.xz
- mv arduino-${IDEVER} $HOME/arduino_ide
- mkdir -p $HOME/Arduino/libraries
- IDEDIR="${HOME}/arduino_ide"
- export PATH="$IDEDIR:$PATH"
- cd ${IDEDIR}
- which arduino
- |
if [[ $PLATFORM == "esp8266" ]] && [[ $RELEASE == "stable" ]]
then
arduino --pref "boardsmanager.additional.urls=http://arduino.esp8266.com/stable/package_esp8266com_index.json" --save-prefs
arduino --install-boards "esp8266:esp8266"
fi
- |
if [[ $PLATFORM == "esp8266" ]] && [[ $RELEASE == "devel" ]]
then
mkdir -p hardware/esp8266com
cd hardware/esp8266com
git clone https://github.com/esp8266/Arduino.git esp8266
cd esp8266/tools
python get.py
fi
- |
if [[ $PLATFORM == "esp32" ]] && [[ $RELEASE == "devel" ]]
then
mkdir -p hardware/espressif
cd hardware/espressif
git clone https://github.com/espressif/arduino-esp32.git esp32
cd esp32/tools/
python get.py
fi
- arduino --pref "compiler.warning_level=all" --save-prefs
- echo -e "travis_fold:end:sketch_test_env_prepare"
- echo -e "travis_fold:start:install_library"
- cd $HOME/Arduino/libraries
- git clone https://github.com/bbx10/WebServer_tng ${HOME}/Arduino/libraries/WebServer
- echo -e "travis_fold:end:install_library"
- echo -e "travis_fold:start:AdvancedWebServer"
- cd ${HOME}/Arduino/libraries/WebServer/examples
- arduino --verbose-build --verify --board ${BOARD} AdvancedWebServer/AdvancedWebServer.ino
- echo -e "travis_fold:end:AdvancedWebServer"
- echo -e "travis_fold:start:HelloServer"
- arduino --verbose-build --verify --board ${BOARD} HelloServer/HelloServer.ino
- echo -e "travis_fold:end:HelloServer"
- echo -e "travis_fold:start:HttpBasicAuth"
- arduino --verbose-build --verify --board ${BOARD} HttpBasicAuth/HttpBasicAuth.ino
- echo -e "travis_fold:end:HttpBasicAuth"
- echo -e "travis_fold:start:SDWebServer"
- arduino --verbose-build --verify --board ${BOARD} SDWebServer/SDWebServer.ino
- echo -e "travis_fold:end:SDWebServer"
- echo -e "travis_fold:start:SimpleAuthentification"
- arduino --verbose-build --verify --board ${BOARD} SimpleAuthentification/SimpleAuthentification.ino
- echo -e "travis_fold:end:SimpleAuthentification"
- |
if [[ $PLATFORM == "esp8266" ]]
then
echo -e "travis_fold:start:FSBrowser"
arduino --verbose-build --verify --board ${BOARD} FSBrowser/FSBrowser.ino
echo -e "travis_fold:end:FSBrowser"
echo -e "travis_fold:start:WebUpdate"
arduino --verbose-build --verify --board ${BOARD} WebUpdate/WebUpdate.ino
echo -e "travis_fold:end:WebUpdate"
fi
notifications:
email:
on_success: change
on_failure: change

View File

@ -1,504 +0,0 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
(This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.)
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
{description}
Copyright (C) {year} {fullname}
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 Street, Fifth Floor, Boston, MA 02110-1301
USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random
Hacker.
{signature of Ty Coon}, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

View File

@ -1,9 +0,0 @@
# WebServer
ESP8266/ESP32 WebServer library
This is an experimental port of the ESP8266WebServer library that should work
on ESP8266 and ESP32. This is NOT an official repo supported by Espressif. Do
not depend on this code for anything important or expect it to be updated. Once
the official repo is created, this repo will be deleted.
Added Travis CI

View File

@ -1,160 +0,0 @@
/*
* Copyright (c) 2015, Majenko Technologies
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* * Neither the name of Majenko Technologies nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef ESP8266
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
ESP8266WebServer server ( 80 );
#else
#include <WiFi.h>
#include <WiFiClient.h>
#include <WebServer.h>
#include <ESPmDNS.h>
WebServer server ( 80 );
#endif
const char *ssid = "YourSSIDHere";
const char *password = "YourPSKHere";
#ifdef LED_BUILTIN
const int led = LED_BUILTIN;
#else
const int led = 13;
#endif
void handleRoot() {
digitalWrite ( led, 1 );
char temp[400];
int sec = millis() / 1000;
int min = sec / 60;
int hr = min / 60;
snprintf ( temp, 400,
"<html>\
<head>\
<meta http-equiv='refresh' content='5'/>\
<title>ESP8266/ESP32 Demo</title>\
<style>\
body { background-color: #cccccc; font-family: Arial, Helvetica, Sans-Serif; Color: #000088; }\
</style>\
</head>\
<body>\
<h1>Hello from ESP8266/ESP32!</h1>\
<p>Uptime: %02d:%02d:%02d</p>\
<img src=\"/test.svg\" />\
</body>\
</html>",
hr, min % 60, sec % 60
);
server.send ( 200, "text/html", temp );
digitalWrite ( led, 0 );
}
void handleNotFound() {
digitalWrite ( led, 1 );
String message = "File Not Found\n\n";
message += "URI: ";
message += server.uri();
message += "\nMethod: ";
message += ( server.method() == HTTP_GET ) ? "GET" : "POST";
message += "\nArguments: ";
message += server.args();
message += "\n";
for ( uint8_t i = 0; i < server.args(); i++ ) {
message += " " + server.argName ( i ) + ": " + server.arg ( i ) + "\n";
}
server.send ( 404, "text/plain", message );
digitalWrite ( led, 0 );
}
void setup ( void ) {
pinMode ( led, OUTPUT );
digitalWrite ( led, 0 );
Serial.begin ( 115200 );
WiFi.begin ( ssid, password );
Serial.println ( "" );
// Wait for connection
while ( WiFi.status() != WL_CONNECTED ) {
delay ( 500 );
Serial.print ( "." );
}
Serial.println ( "" );
Serial.print ( "Connected to " );
Serial.println ( ssid );
Serial.print ( "IP address: " );
Serial.println ( WiFi.localIP() );
#ifdef ESP8266
if ( MDNS.begin ( "esp8266" ) ) {
#else
if ( MDNS.begin ( "esp32" ) ) {
#endif
Serial.println ( "MDNS responder started" );
}
server.on ( "/", handleRoot );
server.on ( "/test.svg", drawGraph );
server.on ( "/inline", []() {
server.send ( 200, "text/plain", "this works as well" );
} );
server.onNotFound ( handleNotFound );
server.begin();
Serial.println ( "HTTP server started" );
}
void loop ( void ) {
server.handleClient();
}
void drawGraph() {
String out = "";
char temp[100];
out += "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" width=\"400\" height=\"150\">\n";
out += "<rect width=\"400\" height=\"150\" fill=\"rgb(250, 230, 210)\" stroke-width=\"1\" stroke=\"rgb(0, 0, 0)\" />\n";
out += "<g stroke=\"black\">\n";
int y = rand() % 130;
for (int x = 10; x < 390; x+= 10) {
int y2 = rand() % 130;
sprintf(temp, "<line x1=\"%d\" y1=\"%d\" x2=\"%d\" y2=\"%d\" stroke-width=\"1\" />\n", x, 140 - y, x + 10, 140 - y2);
out += temp;
y = y2;
}
out += "</g>\n</svg>\n";
server.send ( 200, "image/svg+xml", out);
}

View File

@ -1,345 +0,0 @@
/*
FSWebServer - Example WebServer with SPIFFS backend for esp8266
Copyright (c) 2015 Hristo Gochkov. All rights reserved.
This file is part of the ESP8266/ESP32 WebServer library for Arduino environment.
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
upload the contents of the data folder with MkSPIFFS Tool ("ESP8266 Sketch Data Upload" in Tools menu in Arduino IDE)
or you can upload the contents of a folder if you CD in that folder and run the following command:
for file in `ls -A1`; do curl -F "file=@$PWD/$file" esp8266fs.local/edit; done
access the sample web page at http://esp8266fs.local
edit the page by going to http://esp8266fs.local/edit
*/
/*
* Uploading html, css, javascript, etc.
* Use curl to upload the files from the SPIFFS data directory.
* cd data/
* curl -X POST -F "data=@index.htm" http://<ESP32 IP address>/edit >/dev/null
* curl -X POST -F "data=@graphs.js.gz" http://<ESP32 IP address>/edit >/dev/null
* curl -X POST -F "data=@favicon.ico" http://<ESP32 IP address>/edit >/dev/null
* curl -X POST -F "data=@edit.htm.gz" http://<ESP32 IP address>/edit >/dev/null
*/
#ifdef ESP8266
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include <FS.h>
ESP8266WebServer server(80);
#else
#include <WiFi.h>
#include <WiFiClient.h>
#include <WebServer.h>
#include <ESPmDNS.h>
#include <SPIFFS.h>
WebServer server(80);
#endif
#define DBG_OUTPUT_PORT Serial
const char* ssid = "wifi-ssid";
const char* password = "wifi-password";
const char* host = "esp8266fs";
//holds the current upload
File fsUploadFile;
//format bytes
String formatBytes(size_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";
}
}
String getContentType(String filename){
if(server.hasArg("download")) return "application/octet-stream";
else if(filename.endsWith(".htm")) return "text/html";
else if(filename.endsWith(".html")) return "text/html";
else if(filename.endsWith(".css")) return "text/css";
else if(filename.endsWith(".js")) return "application/javascript";
else if(filename.endsWith(".png")) return "image/png";
else if(filename.endsWith(".gif")) return "image/gif";
else if(filename.endsWith(".jpg")) return "image/jpeg";
else if(filename.endsWith(".ico")) return "image/x-icon";
else if(filename.endsWith(".xml")) return "text/xml";
else if(filename.endsWith(".pdf")) return "application/x-pdf";
else if(filename.endsWith(".zip")) return "application/x-zip";
else if(filename.endsWith(".gz")) return "application/x-gzip";
return "text/plain";
}
bool handleFileRead(String path){
DBG_OUTPUT_PORT.println("handleFileRead: " + path);
if(path.endsWith("/")) path += "index.htm";
String contentType = getContentType(path);
String pathWithGz = path + ".gz";
if(SPIFFS.exists(pathWithGz) || SPIFFS.exists(path)){
if(SPIFFS.exists(pathWithGz))
path += ".gz";
File file = SPIFFS.open(path, "r");
size_t sent = server.streamFile(file, contentType);
file.close();
return true;
}
return false;
}
void handleFileUpload(){
if(server.uri() != "/edit") return;
HTTPUpload& upload = server.upload();
if(upload.status == UPLOAD_FILE_START){
String filename = upload.filename;
if(!filename.startsWith("/")) filename = "/"+filename;
DBG_OUTPUT_PORT.print("handleFileUpload Name: "); DBG_OUTPUT_PORT.println(filename);
fsUploadFile = SPIFFS.open(filename, "w");
filename = String();
} else if(upload.status == UPLOAD_FILE_WRITE){
//DBG_OUTPUT_PORT.print("handleFileUpload Data: "); DBG_OUTPUT_PORT.println(upload.currentSize);
if(fsUploadFile)
fsUploadFile.write(upload.buf, upload.currentSize);
} else if(upload.status == UPLOAD_FILE_END){
if(fsUploadFile)
fsUploadFile.close();
DBG_OUTPUT_PORT.print("handleFileUpload Size: "); DBG_OUTPUT_PORT.println(upload.totalSize);
}
}
void handleFileDelete(){
if(server.args() == 0) return server.send(500, "text/plain", "BAD ARGS");
String path = server.arg(0);
DBG_OUTPUT_PORT.println("handleFileDelete: " + path);
if(path == "/")
return server.send(500, "text/plain", "BAD PATH");
if(!SPIFFS.exists(path))
return server.send(404, "text/plain", "FileNotFound");
SPIFFS.remove(path);
server.send(200, "text/plain", "");
path = String();
}
void handleFileCreate(){
if(server.args() == 0)
return server.send(500, "text/plain", "BAD ARGS");
String path = server.arg(0);
DBG_OUTPUT_PORT.println("handleFileCreate: " + path);
if(path == "/")
return server.send(500, "text/plain", "BAD PATH");
if(SPIFFS.exists(path))
return server.send(500, "text/plain", "FILE EXISTS");
File file = SPIFFS.open(path, "w");
if(file)
file.close();
else
return server.send(500, "text/plain", "CREATE FAILED");
server.send(200, "text/plain", "");
path = String();
}
void returnFail(String msg) {
server.send(500, "text/plain", msg + "\r\n");
}
#ifdef ESP8266
void handleFileList() {
if(!server.hasArg("dir")) {
returnFail("BAD ARGS");
return;
}
String path = server.arg("dir");
DBG_OUTPUT_PORT.println("handleFileList: " + path);
Dir dir = SPIFFS.openDir(path);
path = String();
String output = "[";
while(dir.next()){
File entry = dir.openFile("r");
if (output != "[") output += ',';
bool isDir = false;
output += "{\"type\":\"";
output += (isDir)?"dir":"file";
output += "\",\"name\":\"";
output += String(entry.name()).substring(1);
output += "\"}";
entry.close();
}
output += "]";
server.send(200, "text/json", output);
}
#else
void handleFileList() {
if(!server.hasArg("dir")) {
returnFail("BAD ARGS");
return;
}
String path = server.arg("dir");
if(path != "/" && !SPIFFS.exists((char *)path.c_str())) {
returnFail("BAD PATH");
return;
}
File dir = SPIFFS.open((char *)path.c_str());
path = String();
if(!dir.isDirectory()){
dir.close();
returnFail("NOT DIR");
return;
}
dir.rewindDirectory();
String output = "[";
for (int cnt = 0; true; ++cnt) {
File entry = dir.openNextFile();
if (!entry)
break;
if (cnt > 0)
output += ',';
output += "{\"type\":\"";
output += (entry.isDirectory()) ? "dir" : "file";
output += "\",\"name\":\"";
// Ignore '/' prefix
output += entry.name()+1;
output += "\"";
output += "}";
entry.close();
}
output += "]";
server.send(200, "text/json", output);
dir.close();
}
void listDir(fs::FS &fs, const char * dirname, uint8_t levels) {
DBG_OUTPUT_PORT.printf("Listing directory: %s\n", dirname);
File root = fs.open(dirname);
if (!root) {
DBG_OUTPUT_PORT.println("Failed to open directory");
return;
}
if (!root.isDirectory()) {
DBG_OUTPUT_PORT.println("Not a directory");
return;
}
File file = root.openNextFile();
while (file) {
if (file.isDirectory()) {
DBG_OUTPUT_PORT.print(" DIR : ");
DBG_OUTPUT_PORT.println(file.name());
if (levels) {
listDir(fs, file.name(), levels - 1);
}
} else {
DBG_OUTPUT_PORT.print(" FILE: ");
DBG_OUTPUT_PORT.print(file.name());
DBG_OUTPUT_PORT.print(" SIZE: ");
DBG_OUTPUT_PORT.println(file.size());
}
file = root.openNextFile();
}
}
#endif
void setup(void){
DBG_OUTPUT_PORT.begin(115200);
DBG_OUTPUT_PORT.print("\n");
DBG_OUTPUT_PORT.setDebugOutput(true);
SPIFFS.begin();
{
#ifdef ESP8266
Dir dir = SPIFFS.openDir("/");
while (dir.next()) {
String fileName = dir.fileName();
size_t fileSize = dir.fileSize();
DBG_OUTPUT_PORT.printf("FS File: %s, size: %s\n", fileName.c_str(), formatBytes(fileSize).c_str());
}
#else
listDir(SPIFFS, "/", 0);
#endif
DBG_OUTPUT_PORT.printf("\n");
}
//WIFI INIT
DBG_OUTPUT_PORT.printf("Connecting to %s\n", ssid);
if (String(WiFi.SSID()) != String(ssid)) {
WiFi.begin(ssid, password);
}
while (WiFi.status() != WL_CONNECTED) {
delay(500);
DBG_OUTPUT_PORT.print(".");
}
DBG_OUTPUT_PORT.println("");
DBG_OUTPUT_PORT.print("Connected! IP address: ");
DBG_OUTPUT_PORT.println(WiFi.localIP());
MDNS.begin(host);
DBG_OUTPUT_PORT.print("Open http://");
DBG_OUTPUT_PORT.print(host);
DBG_OUTPUT_PORT.println(".local/edit to see the file browser");
//SERVER INIT
//list directory
server.on("/list", HTTP_GET, handleFileList);
//load editor
server.on("/edit", HTTP_GET, [](){
if(!handleFileRead("/edit.htm")) server.send(404, "text/plain", "FileNotFound");
});
//create file
server.on("/edit", HTTP_PUT, handleFileCreate);
//delete file
server.on("/edit", HTTP_DELETE, handleFileDelete);
//first callback is called after the request has ended with all parsed arguments
//second callback handles file uploads at that location
server.on("/edit", HTTP_POST, [](){ server.send(200, "text/plain", ""); }, handleFileUpload);
//called when the url is not defined here
//use it to load content from SPIFFS
server.onNotFound([](){
if(!handleFileRead(server.uri()))
server.send(404, "text/plain", "FileNotFound");
});
//get heap status, analog input value and all GPIO statuses in one json call
server.on("/all", HTTP_GET, [](){
String json = "{";
json += "\"heap\":"+String(ESP.getFreeHeap());
json += ", \"analog\":"+String(analogRead(A0));
#ifdef ESP8266
json += ", \"gpio\":"+String((uint32_t)(((GPI | GPO) & 0xFFFF) | ((GP16I & 0x01) << 16)));
#endif
json += "}";
server.send(200, "text/json", json);
json = String();
});
server.begin();
DBG_OUTPUT_PORT.println("HTTP server started");
}
void loop(void){
server.handleClient();
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -1,97 +0,0 @@
<!--
FSWebServer - Example Index Page
Copyright (c) 2015 Hristo Gochkov. All rights reserved.
This file is part of the ESP8266WebServer library for Arduino environment.
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
-->
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<title>ESP Monitor</title>
<script type="text/javascript" src="graphs.js"></script>
<script type="text/javascript">
var heap,temp,digi;
var reloadPeriod = 1000;
var running = false;
function loadValues(){
if(!running) return;
var xh = new XMLHttpRequest();
xh.onreadystatechange = function(){
if (xh.readyState == 4){
if(xh.status == 200) {
var res = JSON.parse(xh.responseText);
heap.add(res.heap);
temp.add(res.analog);
digi.add(res.gpio);
if(running) setTimeout(loadValues, reloadPeriod);
} else running = false;
}
};
xh.open("GET", "/all", true);
xh.send(null);
};
function run(){
if(!running){
running = true;
loadValues();
}
}
function onBodyLoad(){
var refreshInput = document.getElementById("refresh-rate");
refreshInput.value = reloadPeriod;
refreshInput.onchange = function(e){
var value = parseInt(e.target.value);
reloadPeriod = (value > 0)?value:0;
e.target.value = reloadPeriod;
}
var stopButton = document.getElementById("stop-button");
stopButton.onclick = function(e){
running = false;
}
var startButton = document.getElementById("start-button");
startButton.onclick = function(e){
run();
}
// Example with 10K thermistor
//function calcThermistor(v) {
// var t = Math.log(((10230000 / v) - 10000));
// t = (1/(0.001129148+(0.000234125*t)+(0.0000000876741*t*t*t)))-273.15;
// return (t>120)?0:Math.round(t*10)/10;
//}
//temp = createGraph(document.getElementById("analog"), "Temperature", 100, 128, 10, 40, false, "cyan", calcThermistor);
temp = createGraph(document.getElementById("analog"), "Analog Input", 100, 128, 0, 1023, false, "cyan");
heap = createGraph(document.getElementById("heap"), "Current Heap", 100, 125, 0, 30000, true, "orange");
digi = createDigiGraph(document.getElementById("digital"), "GPIO", 100, 146, [0, 4, 5, 16], "gold");
run();
}
</script>
</head>
<body id="index" style="margin:0; padding:0;" onload="onBodyLoad()">
<div id="controls" style="display: block; border: 1px solid rgb(68, 68, 68); padding: 5px; margin: 5px; width: 362px; background-color: rgb(238, 238, 238);">
<label>Period (ms):</label>
<input type="number" id="refresh-rate"/>
<input type="button" id="start-button" value="Start"/>
<input type="button" id="stop-button" value="Stop"/>
</div>
<div id="heap"></div>
<div id="analog"></div>
<div id="digital"></div>
</body>
</html>

View File

@ -1,91 +0,0 @@
#ifdef ESP8266
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
ESP8266WebServer server(80);
#else
#include <WiFi.h>
#include <WiFiClient.h>
#include <WebServer.h>
#include <ESPmDNS.h>
WebServer server(80);
#endif
const char* ssid = "........";
const char* password = "........";
#ifdef LED_BUILTIN
const int led = LED_BUILTIN;
#else
const int led = 13;
#endif
void handleRoot() {
digitalWrite(led, 1);
#ifdef ESP8266
server.send(200, "text/plain", "hello from esp8266!");
#else
server.send(200, "text/plain", "hello from esp32!");
#endif
digitalWrite(led, 0);
}
void handleNotFound(){
digitalWrite(led, 1);
String message = "File Not Found\n\n";
message += "URI: ";
message += server.uri();
message += "\nMethod: ";
message += (server.method() == HTTP_GET)?"GET":"POST";
message += "\nArguments: ";
message += server.args();
message += "\n";
for (uint8_t i=0; i<server.args(); i++){
message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
}
server.send(404, "text/plain", message);
digitalWrite(led, 0);
}
void setup(void){
pinMode(led, OUTPUT);
digitalWrite(led, 0);
Serial.begin(115200);
WiFi.begin(ssid, password);
Serial.println("");
// Wait for connection
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
#ifdef ESP8266
if (MDNS.begin("esp8266")) {
#else
if (MDNS.begin("esp32")) {
#endif
Serial.println("MDNS responder started");
}
server.on("/", handleRoot);
server.on("/inline", [](){
server.send(200, "text/plain", "this works as well");
});
server.onNotFound(handleNotFound);
server.begin();
Serial.println("HTTP server started");
}
void loop(void){
server.handleClient();
}

View File

@ -1,47 +0,0 @@
#ifdef ESP8266
#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <ArduinoOTA.h>
#include <ESP8266WebServer.h>
ESP8266WebServer server(80);
#else
#include <WiFi.h>
#include <ESPmDNS.h>
#include <ArduinoOTA.h>
#include <WebServer.h>
WebServer server(80);
#endif
const char* ssid = "........";
const char* password = "........";
const char* www_username = "admin";
const char* www_password = "esp8266esp32";
void setup() {
Serial.begin(115200);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
if(WiFi.waitForConnectResult() != WL_CONNECTED) {
Serial.println("WiFi Connect Failed! Rebooting...");
delay(1000);
ESP.restart();
}
ArduinoOTA.begin();
server.on("/", [](){
if(!server.authenticate(www_username, www_password))
return server.requestAuthentication();
server.send(200, "text/plain", "Login OK");
});
server.begin();
Serial.print("Open http://");
Serial.print(WiFi.localIP());
Serial.println("/ in your browser to see it working");
}
void loop() {
ArduinoOTA.handle();
server.handleClient();
}

View File

@ -1,290 +0,0 @@
/*
SDWebServer - Example WebServer with SD Card backend for esp8266/esp32
Copyright (c) 2015 Hristo Gochkov. All rights reserved.
This file is part of the ESP8266/ESP32 WebServer library for Arduino environment.
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
Have a FAT Formatted SD Card connected to the SPI port of the ESP8266
The web root is the SD Card root folder
File extensions with more than 3 charecters are not supported by the SD Library
File Names longer than 8 charecters will be truncated by the SD library, so keep filenames shorter
index.htm is the default index (works on subfolders as well)
upload the contents of SdRoot to the root of the SDcard and access the editor by going to http://esp8266sd.local/edit
*/
#ifdef ESP8266
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include <SPI.h>
#include <SD.h>
ESP8266WebServer server(80);
#else
#include <WiFi.h>
#include <WiFiClient.h>
#include <WebServer.h>
#include <ESPmDNS.h>
#include <SPI.h>
#include <SD.h>
WebServer server(80);
#endif
#define DBG_OUTPUT_PORT Serial
const char* ssid = "**********";
const char* password = "**********";
const char* host = "esp8266sd";
static bool hasSD = false;
File uploadFile;
void returnOK() {
server.send(200, "text/plain", "");
}
void returnFail(String msg) {
server.send(500, "text/plain", msg + "\r\n");
}
bool loadFromSdCard(String path){
String dataType = "text/plain";
if(path.endsWith("/")) path += "index.htm";
if(path.endsWith(".src")) path = path.substring(0, path.lastIndexOf("."));
else if(path.endsWith(".htm")) dataType = "text/html";
else if(path.endsWith(".css")) dataType = "text/css";
else if(path.endsWith(".js")) dataType = "application/javascript";
else if(path.endsWith(".png")) dataType = "image/png";
else if(path.endsWith(".gif")) dataType = "image/gif";
else if(path.endsWith(".jpg")) dataType = "image/jpeg";
else if(path.endsWith(".ico")) dataType = "image/x-icon";
else if(path.endsWith(".xml")) dataType = "text/xml";
else if(path.endsWith(".pdf")) dataType = "application/pdf";
else if(path.endsWith(".zip")) dataType = "application/zip";
File dataFile = SD.open(path.c_str());
if(dataFile.isDirectory()){
path += "/index.htm";
dataType = "text/html";
dataFile = SD.open(path.c_str());
}
if (!dataFile)
return false;
if (server.hasArg("download")) dataType = "application/octet-stream";
if (server.streamFile(dataFile, dataType) != dataFile.size()) {
DBG_OUTPUT_PORT.println("Sent less data than expected!");
}
dataFile.close();
return true;
}
void handleFileUpload(){
if(server.uri() != "/edit") return;
HTTPUpload& upload = server.upload();
if(upload.status == UPLOAD_FILE_START){
if(SD.exists((char *)upload.filename.c_str())) SD.remove((char *)upload.filename.c_str());
uploadFile = SD.open(upload.filename.c_str(), FILE_WRITE);
DBG_OUTPUT_PORT.print("Upload: START, filename: "); DBG_OUTPUT_PORT.println(upload.filename);
} else if(upload.status == UPLOAD_FILE_WRITE){
if(uploadFile) uploadFile.write(upload.buf, upload.currentSize);
DBG_OUTPUT_PORT.print("Upload: WRITE, Bytes: "); DBG_OUTPUT_PORT.println(upload.currentSize);
} else if(upload.status == UPLOAD_FILE_END){
if(uploadFile) uploadFile.close();
DBG_OUTPUT_PORT.print("Upload: END, Size: "); DBG_OUTPUT_PORT.println(upload.totalSize);
}
}
void deleteRecursive(String path){
File file = SD.open((char *)path.c_str());
if(!file.isDirectory()){
file.close();
SD.remove((char *)path.c_str());
return;
}
file.rewindDirectory();
while(true) {
File entry = file.openNextFile();
if (!entry) break;
String entryPath = path + "/" +entry.name();
if(entry.isDirectory()){
entry.close();
deleteRecursive(entryPath);
} else {
entry.close();
SD.remove((char *)entryPath.c_str());
}
yield();
}
SD.rmdir((char *)path.c_str());
file.close();
}
void handleDelete(){
if(server.args() == 0) return returnFail("BAD ARGS");
String path = server.arg(0);
if(path == "/" || !SD.exists((char *)path.c_str())) {
returnFail("BAD PATH");
return;
}
deleteRecursive(path);
returnOK();
}
void handleCreate(){
if(server.args() == 0) return returnFail("BAD ARGS");
String path = server.arg(0);
if(path == "/" || SD.exists((char *)path.c_str())) {
returnFail("BAD PATH");
return;
}
if(path.indexOf('.') > 0){
File file = SD.open((char *)path.c_str(), FILE_WRITE);
if(file){
#ifdef ESP8266
file.write((const char *)0);
#else
// TODO Create file with 0 bytes???
file.write(NULL, 0);
#endif
file.close();
}
} else {
SD.mkdir((char *)path.c_str());
}
returnOK();
}
void printDirectory() {
if(!server.hasArg("dir")) return returnFail("BAD ARGS");
String path = server.arg("dir");
if(path != "/" && !SD.exists((char *)path.c_str())) return returnFail("BAD PATH");
File dir = SD.open((char *)path.c_str());
path = String();
if(!dir.isDirectory()){
dir.close();
return returnFail("NOT DIR");
}
dir.rewindDirectory();
server.setContentLength(CONTENT_LENGTH_UNKNOWN);
server.send(200, "text/json", "");
WiFiClient client = server.client();
server.sendContent("[");
for (int cnt = 0; true; ++cnt) {
File entry = dir.openNextFile();
if (!entry)
break;
String output;
if (cnt > 0)
output = ',';
output += "{\"type\":\"";
output += (entry.isDirectory()) ? "dir" : "file";
output += "\",\"name\":\"";
#ifdef ESP8266
output += entry.name();
#else
// Ignore '/' prefix
output += entry.name()+1;
#endif
output += "\"";
output += "}";
server.sendContent(output);
entry.close();
}
server.sendContent("]");
// Send zero length chunk to terminate the HTTP body
server.sendContent("");
dir.close();
}
void handleNotFound(){
if(hasSD && loadFromSdCard(server.uri())) return;
String message = "SDCARD Not Detected\n\n";
message += "URI: ";
message += server.uri();
message += "\nMethod: ";
message += (server.method() == HTTP_GET)?"GET":"POST";
message += "\nArguments: ";
message += server.args();
message += "\n";
for (uint8_t i=0; i<server.args(); i++){
message += " NAME:"+server.argName(i) + "\n VALUE:" + server.arg(i) + "\n";
}
server.send(404, "text/plain", message);
DBG_OUTPUT_PORT.print(message);
}
void setup(void){
DBG_OUTPUT_PORT.begin(115200);
DBG_OUTPUT_PORT.setDebugOutput(true);
DBG_OUTPUT_PORT.print("\n");
WiFi.begin(ssid, password);
DBG_OUTPUT_PORT.print("Connecting to ");
DBG_OUTPUT_PORT.println(ssid);
// Wait for connection
uint8_t i = 0;
while (WiFi.status() != WL_CONNECTED && i++ < 20) {//wait 10 seconds
delay(500);
}
if(i == 21){
DBG_OUTPUT_PORT.print("Could not connect to ");
DBG_OUTPUT_PORT.println(ssid);
while(1) delay(500);
}
DBG_OUTPUT_PORT.print("Connected! IP address: ");
DBG_OUTPUT_PORT.println(WiFi.localIP());
if (MDNS.begin(host)) {
MDNS.addService("http", "tcp", 80);
DBG_OUTPUT_PORT.println("MDNS responder started");
DBG_OUTPUT_PORT.print("You can now connect to http://");
DBG_OUTPUT_PORT.print(host);
DBG_OUTPUT_PORT.println(".local");
}
server.on("/list", HTTP_GET, printDirectory);
server.on("/edit", HTTP_DELETE, handleDelete);
server.on("/edit", HTTP_PUT, handleCreate);
server.on("/edit", HTTP_POST, [](){ returnOK(); }, handleFileUpload);
server.onNotFound(handleNotFound);
server.begin();
DBG_OUTPUT_PORT.println("HTTP server started");
if (SD.begin(SS)){
DBG_OUTPUT_PORT.println("SD Card initialized.");
hasSD = true;
}
}
void loop(void){
server.handleClient();
}

View File

@ -1,674 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>SD Editor</title>
<style type="text/css" media="screen">
.contextMenu {
z-index: 300;
position: absolute;
left: 5px;
border: 1px solid #444;
background-color: #F5F5F5;
display: none;
box-shadow: 0 0 10px rgba( 0, 0, 0, .4 );
font-size: 12px;
font-family: sans-serif;
font-weight:bold;
}
.contextMenu ul {
list-style: none;
top: 0;
left: 0;
margin: 0;
padding: 0;
}
.contextMenu li {
position: relative;
min-width: 60px;
cursor: pointer;
}
.contextMenu span {
color: #444;
display: inline-block;
padding: 6px;
}
.contextMenu li:hover { background: #444; }
.contextMenu li:hover span { color: #EEE; }
.css-treeview ul, .css-treeview li {
padding: 0;
margin: 0;
list-style: none;
}
.css-treeview input {
position: absolute;
opacity: 0;
}
.css-treeview {
font: normal 11px Verdana, Arial, Sans-serif;
-moz-user-select: none;
-webkit-user-select: none;
user-select: none;
}
.css-treeview span {
color: #00f;
cursor: pointer;
}
.css-treeview span:hover {
text-decoration: underline;
}
.css-treeview input + label + ul {
margin: 0 0 0 22px;
}
.css-treeview input ~ ul {
display: none;
}
.css-treeview label, .css-treeview label::before {
cursor: pointer;
}
.css-treeview input:disabled + label {
cursor: default;
opacity: .6;
}
.css-treeview input:checked:not(:disabled) ~ ul {
display: block;
}
.css-treeview label, .css-treeview label::before {
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAACgCAYAAAAFOewUAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAApxJREFUeNrslM1u00AQgGdthyalFFOK+ClIIKQKyqUVQvTEE3DmAhLwAhU8QZoH4A2Q2gMSFace4MCtJ8SPBFwAkRuiHKpA6sRN/Lu7zG5i14kctaUqRGhGXnu9O/Pt7MzsMiklvF+9t2kWTDvyIrAsA0aKRRi1T0C/hJ4LUbt5/8rNpWVlp8RSr9J40b48fxFaTQ9+ft8EZ6MJYb0Ok+dnYGpmPgXwKIAvLx8vYXc5GdMAQJgQEkpjRTh36TS2U+DWW/D17WuYgm8pwJyY1npZsZKOxImOV1I/h4+O6vEg5GCZBpgmA6hX8wHKUHDRBXQYicQ4rlc3Tf0VMs8DHBS864F2YFspjgUYjKX/Az3gsdQd2eeBHwmdGWXHcgBGSkZXOXohcEXebRoQcAgjqediNY+AVyu3Z3sAKqfKoGMsewBeEIOPgQxxPJIjcGH6qtL/0AdADzKGnuuD+2tLK7Q8DhHHbOBW+KEzcHLuYc82MkEUekLiwuvVH+guQBQzOG4XdAb8EOcRcqQvDkY2iCLuxECJ43JobMXoutqGgDa2T7UqLKwt9KRyuxKVByqVXXqIoCCUCAqhUOioTWC7G4TQEOD0APy2/7G2Xpu1J4+lxeQ4TXBbITDpoVelRN/BVFbwu5oMMJUBhoXy5tmdRcMwymP2OLQaLjx9/vnBo6V3K6izATmSnMa0Dq7ferIohJhr1p01zrlz49rZF4OMs8JkX23vVQzYp+wbYGV/KpXKjvspl8tsIKCrMNAYFxj2GKS5ZWxg4ewKsJfaGMIY5KXqPz8LBBj6+yDvVP79+yDp/9F9oIx3OisHWwe7Oal0HxCAAAQgAAEIQAACEIAABCAAAQhAAAIQgAAEIAABCEAAAhCAAAQgwD8E/BZgAP0qhKj3rXO7AAAAAElFTkSuQmCC") no-repeat;
}
.css-treeview label, .css-treeview span, .css-treeview label::before {
display: inline-block;
height: 16px;
line-height: 16px;
vertical-align: middle;
}
.css-treeview label {
background-position: 18px 0;
}
.css-treeview label::before {
content: "";
width: 16px;
margin: 0 22px 0 0;
vertical-align: middle;
background-position: 0 -32px;
}
.css-treeview input:checked + label::before {
background-position: 0 -16px;
}
/* webkit adjacent element selector bugfix */
@media screen and (-webkit-min-device-pixel-ratio:0)
{
.css-treeview{
-webkit-animation: webkit-adjacent-element-selector-bugfix infinite 1s;
}
@-webkit-keyframes webkit-adjacent-element-selector-bugfix
{
from {
padding: 0;
}
to {
padding: 0;
}
}
}
#uploader {
position: absolute;
top: 0;
right: 0;
left: 0;
height:28px;
line-height: 24px;
padding-left: 10px;
background-color: #444;
color:#EEE;
}
#tree {
position: absolute;
top: 28px;
bottom: 0;
left: 0;
width:200px;
padding: 8px;
}
#editor, #preview {
position: absolute;
top: 28px;
right: 0;
bottom: 0;
left: 200px;
}
#preview {
background-color: #EEE;
padding:5px;
}
</style>
<script>
function createFileUploader(element, tree, editor){
var xmlHttp;
var input = document.createElement("input");
input.type = "file";
input.multiple = false;
input.name = "data";
document.getElementById(element).appendChild(input);
var path = document.createElement("input");
path.id = "upload-path";
path.type = "text";
path.name = "path";
path.defaultValue = "/";
document.getElementById(element).appendChild(path);
var button = document.createElement("button");
button.innerHTML = 'Upload';
document.getElementById(element).appendChild(button);
var mkdir = document.createElement("button");
mkdir.innerHTML = 'MkDir';
document.getElementById(element).appendChild(mkdir);
var mkfile = document.createElement("button");
mkfile.innerHTML = 'MkFile';
document.getElementById(element).appendChild(mkfile);
function httpPostProcessRequest(){
if (xmlHttp.readyState == 4){
if(xmlHttp.status != 200) alert("ERROR["+xmlHttp.status+"]: "+xmlHttp.responseText);
else {
tree.refreshPath(path.value);
}
}
}
function createPath(p){
xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = httpPostProcessRequest;
var formData = new FormData();
formData.append("path", p);
xmlHttp.open("PUT", "/edit");
xmlHttp.send(formData);
}
mkfile.onclick = function(e){
if(path.value.indexOf(".") === -1) return;
createPath(path.value);
editor.loadUrl(path.value);
};
mkdir.onclick = function(e){
if(path.value.length < 2) return;
var dir = path.value
if(dir.indexOf(".") !== -1){
if(dir.lastIndexOf("/") === 0) return;
dir = dir.substring(0, dir.lastIndexOf("/"));
}
createPath(dir);
};
button.onclick = function(e){
if(input.files.length === 0){
return;
}
xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = httpPostProcessRequest;
var formData = new FormData();
formData.append("data", input.files[0], path.value);
xmlHttp.open("POST", "/edit");
xmlHttp.send(formData);
}
input.onchange = function(e){
if(input.files.length === 0) return;
var filename = input.files[0].name;
var ext = /(?:\.([^.]+))?$/.exec(filename)[1];
var name = /(.*)\.[^.]+$/.exec(filename)[1];
if(typeof name !== undefined){
if(name.length > 8) name = name.substring(0, 8);
filename = name;
}
if(typeof ext !== undefined){
if(ext === "html") ext = "htm";
else if(ext === "jpeg") ext = "jpg";
filename = filename + "." + ext;
}
if(path.value === "/" || path.value.lastIndexOf("/") === 0){
path.value = "/"+filename;
} else {
path.value = path.value.substring(0, path.value.lastIndexOf("/")+1)+filename;
}
}
}
function createTree(element, editor){
var preview = document.getElementById("preview");
var treeRoot = document.createElement("div");
treeRoot.className = "css-treeview";
document.getElementById(element).appendChild(treeRoot);
function loadDownload(path){
document.getElementById('download-frame').src = path+"?download=true";
}
function loadPreview(path){
document.getElementById("editor").style.display = "none";
preview.style.display = "block";
preview.innerHTML = '<img src="'+path+'" style="max-width:100%; max-height:100%; margin:auto; display:block;" />';
}
function fillFolderMenu(el, path){
var list = document.createElement("ul");
el.appendChild(list);
var action = document.createElement("li");
list.appendChild(action);
var isChecked = document.getElementById(path).checked;
var expnd = document.createElement("li");
list.appendChild(expnd);
if(isChecked){
expnd.innerHTML = "<span>Collapse</span>";
expnd.onclick = function(e){
document.getElementById(path).checked = false;
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(el);
};
var refrsh = document.createElement("li");
list.appendChild(refrsh);
refrsh.innerHTML = "<span>Refresh</span>";
refrsh.onclick = function(e){
var leaf = document.getElementById(path).parentNode;
if(leaf.childNodes.length == 3) leaf.removeChild(leaf.childNodes[2]);
httpGet(leaf, path);
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(el);
};
} else {
expnd.innerHTML = "<span>Expand</span>";
expnd.onclick = function(e){
document.getElementById(path).checked = true;
var leaf = document.getElementById(path).parentNode;
if(leaf.childNodes.length == 3) leaf.removeChild(leaf.childNodes[2]);
httpGet(leaf, path);
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(el);
};
}
var upload = document.createElement("li");
list.appendChild(upload);
upload.innerHTML = "<span>Upload</span>";
upload.onclick = function(e){
var pathEl = document.getElementById("upload-path");
if(pathEl){
var subPath = pathEl.value;
if(subPath.lastIndexOf("/") < 1) pathEl.value = path+subPath;
else pathEl.value = path.substring(subPath.lastIndexOf("/"))+subPath;
}
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(el);
};
var delFile = document.createElement("li");
list.appendChild(delFile);
delFile.innerHTML = "<span>Delete</span>";
delFile.onclick = function(e){
httpDelete(path);
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(el);
};
}
function fillFileMenu(el, path){
var list = document.createElement("ul");
el.appendChild(list);
var action = document.createElement("li");
list.appendChild(action);
if(isTextFile(path)){
action.innerHTML = "<span>Edit</span>";
action.onclick = function(e){
editor.loadUrl(path);
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(el);
};
} else if(isImageFile(path)){
action.innerHTML = "<span>Preview</span>";
action.onclick = function(e){
loadPreview(path);
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(el);
};
}
var download = document.createElement("li");
list.appendChild(download);
download.innerHTML = "<span>Download</span>";
download.onclick = function(e){
loadDownload(path);
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(el);
};
var delFile = document.createElement("li");
list.appendChild(delFile);
delFile.innerHTML = "<span>Delete</span>";
delFile.onclick = function(e){
httpDelete(path);
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(el);
};
}
function showContextMenu(e, path, isfile){
var divContext = document.createElement("div");
var scrollTop = document.body.scrollTop ? document.body.scrollTop : document.documentElement.scrollTop;
var scrollLeft = document.body.scrollLeft ? document.body.scrollLeft : document.documentElement.scrollLeft;
var left = e.clientX + scrollLeft;
var top = e.clientY + scrollTop;
divContext.className = 'contextMenu';
divContext.style.display = 'block';
divContext.style.left = left + 'px';
divContext.style.top = top + 'px';
if(isfile) fillFileMenu(divContext, path);
else fillFolderMenu(divContext, path);
document.body.appendChild(divContext);
var width = divContext.offsetWidth;
var height = divContext.offsetHeight;
divContext.onmouseout = function(e){
if(e.clientX < left || e.clientX > (left + width) || e.clientY < top || e.clientY > (top + height)){
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(divContext);
}
};
}
function createTreeLeaf(path, name, size){
var leaf = document.createElement("li");
leaf.id = (((path == "/")?"":path)+"/"+name).toLowerCase();
var label = document.createElement("span");
label.textContent = name.toLowerCase();
leaf.appendChild(label);
leaf.onclick = function(e){
if(isTextFile(leaf.id)){
editor.loadUrl(leaf.id);
} else if(isImageFile(leaf.id)){
loadPreview(leaf.id);
}
};
leaf.oncontextmenu = function(e){
e.preventDefault();
e.stopPropagation();
showContextMenu(e, leaf.id, true);
};
return leaf;
}
function createTreeBranch(path, name, disabled){
var leaf = document.createElement("li");
var check = document.createElement("input");
check.type = "checkbox";
check.id = (((path == "/")?"":path)+"/"+name).toLowerCase();
if(typeof disabled !== "undefined" && disabled) check.disabled = "disabled";
leaf.appendChild(check);
var label = document.createElement("label");
label.for = check.id;
label.textContent = name.toLowerCase();
leaf.appendChild(label);
check.onchange = function(e){
if(check.checked){
if(leaf.childNodes.length == 3) leaf.removeChild(leaf.childNodes[2]);
httpGet(leaf, check.id);
}
};
label.onclick = function(e){
if(!check.checked){
check.checked = true;
if(leaf.childNodes.length == 3) leaf.removeChild(leaf.childNodes[2]);
httpGet(leaf, check.id);
} else {
check.checked = false;
}
};
leaf.oncontextmenu = function(e){
e.preventDefault();
e.stopPropagation();
showContextMenu(e, check.id, false);
}
return leaf;
}
function addList(parent, path, items){
var list = document.createElement("ul");
parent.appendChild(list);
var ll = items.length;
for(var i = 0; i < ll; i++){
var item = items[i];
var itemEl;
if(item.type === "file"){
itemEl = createTreeLeaf(path, item.name, item.size);
} else {
itemEl = createTreeBranch(path, item.name);
}
list.appendChild(itemEl);
}
}
function isTextFile(path){
var ext = /(?:\.([^.]+))?$/.exec(path)[1];
if(typeof ext !== undefined){
switch(ext){
case "txt":
case "htm":
case "html":
case "js":
case "json":
case "c":
case "h":
case "cpp":
case "css":
case "xml":
return true;
}
}
return false;
}
function isImageFile(path){
var ext = /(?:\.([^.]+))?$/.exec(path)[1];
if(typeof ext !== undefined){
switch(ext){
case "png":
case "jpg":
case "gif":
case "ico":
return true;
}
}
return false;
}
this.refreshPath = function(path){
if(path.lastIndexOf('/') < 1){
path = '/';
treeRoot.removeChild(treeRoot.childNodes[0]);
httpGet(treeRoot, "/");
} else {
path = path.substring(0, path.lastIndexOf('/'));
var leaf = document.getElementById(path).parentNode;
if(leaf.childNodes.length == 3) leaf.removeChild(leaf.childNodes[2]);
httpGet(leaf, path);
}
};
function delCb(path){
return function(){
if (xmlHttp.readyState == 4){
if(xmlHttp.status != 200){
alert("ERROR["+xmlHttp.status+"]: "+xmlHttp.responseText);
} else {
if(path.lastIndexOf('/') < 1){
path = '/';
treeRoot.removeChild(treeRoot.childNodes[0]);
httpGet(treeRoot, "/");
} else {
path = path.substring(0, path.lastIndexOf('/'));
var leaf = document.getElementById(path).parentNode;
if(leaf.childNodes.length == 3) leaf.removeChild(leaf.childNodes[2]);
httpGet(leaf, path);
}
}
}
}
}
function httpDelete(filename){
xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = delCb(filename);
var formData = new FormData();
formData.append("path", filename);
xmlHttp.open("DELETE", "/edit");
xmlHttp.send(formData);
}
function getCb(parent, path){
return function(){
if (xmlHttp.readyState == 4){
//clear loading
if(xmlHttp.status == 200) addList(parent, path, JSON.parse(xmlHttp.responseText));
}
}
}
function httpGet(parent, path){
xmlHttp = new XMLHttpRequest(parent, path);
xmlHttp.onreadystatechange = getCb(parent, path);
xmlHttp.open("GET", "/list?dir="+path, true);
xmlHttp.send(null);
//start loading
}
httpGet(treeRoot, "/");
return this;
}
function createEditor(element, file, lang, theme, type){
function getLangFromFilename(filename){
var lang = "plain";
var ext = /(?:\.([^.]+))?$/.exec(filename)[1];
if(typeof ext !== undefined){
switch(ext){
case "txt": lang = "plain"; break;
case "htm": lang = "html"; break;
case "js": lang = "javascript"; break;
case "c": lang = "c_cpp"; break;
case "cpp": lang = "c_cpp"; break;
case "css":
case "scss":
case "php":
case "html":
case "json":
case "xml":
lang = ext;
}
}
return lang;
}
if(typeof file === "undefined") file = "/index.htm";
if(typeof lang === "undefined"){
lang = getLangFromFilename(file);
}
if(typeof theme === "undefined") theme = "textmate";
if(typeof type === "undefined"){
type = "text/"+lang;
if(lang === "c_cpp") type = "text/plain";
}
var xmlHttp = null;
var editor = ace.edit(element);
//post
function httpPostProcessRequest(){
if (xmlHttp.readyState == 4){
if(xmlHttp.status != 200) alert("ERROR["+xmlHttp.status+"]: "+xmlHttp.responseText);
}
}
function httpPost(filename, data, type){
xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = httpPostProcessRequest;
var formData = new FormData();
formData.append("data", new Blob([data], { type: type }), filename);
xmlHttp.open("POST", "/edit");
xmlHttp.send(formData);
}
//get
function httpGetProcessRequest(){
if (xmlHttp.readyState == 4){
document.getElementById("preview").style.display = "none";
document.getElementById("editor").style.display = "block";
if(xmlHttp.status == 200) editor.setValue(xmlHttp.responseText);
else editor.setValue("");
editor.clearSelection();
}
}
function httpGet(theUrl){
xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = httpGetProcessRequest;
xmlHttp.open("GET", theUrl, true);
xmlHttp.send(null);
}
if(lang !== "plain") editor.getSession().setMode("ace/mode/"+lang);
editor.setTheme("ace/theme/"+theme);
editor.$blockScrolling = Infinity;
editor.getSession().setUseSoftTabs(true);
editor.getSession().setTabSize(2);
editor.setHighlightActiveLine(true);
editor.setShowPrintMargin(false);
editor.commands.addCommand({
name: 'saveCommand',
bindKey: {win: 'Ctrl-S', mac: 'Command-S'},
exec: function(editor) {
httpPost(file, editor.getValue()+"", type);
},
readOnly: false
});
editor.commands.addCommand({
name: 'undoCommand',
bindKey: {win: 'Ctrl-Z', mac: 'Command-Z'},
exec: function(editor) {
editor.getSession().getUndoManager().undo(false);
},
readOnly: false
});
editor.commands.addCommand({
name: 'redoCommand',
bindKey: {win: 'Ctrl-Shift-Z', mac: 'Command-Shift-Z'},
exec: function(editor) {
editor.getSession().getUndoManager().redo(false);
},
readOnly: false
});
httpGet(file);
editor.loadUrl = function(filename){
file = filename;
lang = getLangFromFilename(file);
type = "text/"+lang;
if(lang !== "plain") editor.getSession().setMode("ace/mode/"+lang);
httpGet(file);
}
return editor;
}
function onBodyLoad(){
var vars = {};
var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m,key,value) { vars[key] = value; });
var editor = createEditor("editor", vars.file, vars.lang, vars.theme);
var tree = createTree("tree", editor);
createFileUploader("uploader", tree, editor);
};
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.1.9/ace.js" type="text/javascript" charset="utf-8"></script>
</head>
<body onload="onBodyLoad();">
<div id="uploader"></div>
<div id="tree"></div>
<div id="editor"></div>
<div id="preview" style="display:none;"></div>
<iframe id=download-frame style='display:none;'></iframe>
</body>
</html>

View File

@ -1,22 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<title>ESP Index</title>
<style>
body {
background-color:black;
color:white;
}
</style>
<script type="text/javascript">
function onBodyLoad(){
console.log("we are loaded!!");
}
</script>
</head>
<body id="index" onload="onBodyLoad()">
<h1>ESP8266 Pin Functions</h1>
<img src="pins.png" />
</body>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 174 KiB

View File

@ -1,137 +0,0 @@
#ifdef ESP8266
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
ESP8266WebServer server(80);
#else
#include <WiFi.h>
#include <WiFiClient.h>
#include <WebServer.h>
WebServer server(80);
#endif
const char* ssid = "........";
const char* password = "........";
//Check if header is present and correct
bool is_authentified(){
Serial.println("Enter is_authentified");
if (server.hasHeader("Cookie")){
Serial.print("Found cookie: ");
String cookie = server.header("Cookie");
Serial.println(cookie);
if (cookie.indexOf("ESPSESSIONID=1") != -1) {
Serial.println("Authentification Successful");
return true;
}
}
Serial.println("Authentification Failed");
return false;
}
//login page, also called for disconnect
void handleLogin(){
String msg;
if (server.hasHeader("Cookie")){
Serial.print("Found cookie: ");
String cookie = server.header("Cookie");
Serial.println(cookie);
}
if (server.hasArg("DISCONNECT")){
Serial.println("Disconnection");
server.sendHeader("Location","/login");
server.sendHeader("Cache-Control","no-cache");
server.sendHeader("Set-Cookie","ESPSESSIONID=0");
server.send(301);
return;
}
if (server.hasArg("USERNAME") && server.hasArg("PASSWORD")){
if (server.arg("USERNAME") == "admin" && server.arg("PASSWORD") == "admin" ){
server.sendHeader("Location","/");
server.sendHeader("Cache-Control","no-cache");
server.sendHeader("Set-Cookie","ESPSESSIONID=1");
server.send(301);
Serial.println("Log in Successful");
return;
}
msg = "Wrong username/password! try again.";
Serial.println("Log in Failed");
}
String content = "<html><body><form action='/login' method='POST'>To log in, please use : admin/admin<br>";
content += "User:<input type='text' name='USERNAME' placeholder='user name'><br>";
content += "Password:<input type='password' name='PASSWORD' placeholder='password'><br>";
content += "<input type='submit' name='SUBMIT' value='Submit'></form>" + msg + "<br>";
content += "You also can go <a href='/inline'>here</a></body></html>";
server.send(200, "text/html", content);
}
//root page can be accessed only if authentification is ok
void handleRoot(){
Serial.println("Enter handleRoot");
String header;
if (!is_authentified()){
server.sendHeader("Location","/login");
server.sendHeader("Cache-Control","no-cache");
server.send(301);
return;
}
String content = "<html><body><H2>hello, you successfully connected to esp8266/esp32!</H2><br>";
if (server.hasHeader("User-Agent")){
content += "the user agent used is : " + server.header("User-Agent") + "<br><br>";
}
content += "You can access this page until you <a href=\"/login?DISCONNECT=YES\">disconnect</a></body></html>";
server.send(200, "text/html", content);
}
//no need authentification
void handleNotFound(){
String message = "File Not Found\n\n";
message += "URI: ";
message += server.uri();
message += "\nMethod: ";
message += (server.method() == HTTP_GET)?"GET":"POST";
message += "\nArguments: ";
message += server.args();
message += "\n";
for (uint8_t i=0; i<server.args(); i++){
message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
}
server.send(404, "text/plain", message);
}
void setup(void){
Serial.begin(115200);
WiFi.begin(ssid, password);
Serial.println("");
// Wait for connection
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
server.on("/", handleRoot);
server.on("/login", handleLogin);
server.on("/inline", [](){
server.send(200, "text/plain", "this works without need of authentification");
});
server.onNotFound(handleNotFound);
//here the list of headers to be recorded
const char * headerkeys[] = {"User-Agent","Cookie"} ;
size_t headerkeyssize = sizeof(headerkeys)/sizeof(char*);
//ask server to track these headers
server.collectHeaders(headerkeys, headerkeyssize );
server.begin();
Serial.println("HTTP server started");
}
void loop(void){
server.handleClient();
}

View File

@ -1,78 +0,0 @@
/*
To upload through terminal you can use: curl -F "image=@firmware.bin" esp8266-webupdate.local/update
*/
#ifdef ESP8266
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
ESP8266WebServer server(80);
const char* host = "esp8266-webupdate";
#else
#include <WiFi.h>
#include <WiFiClient.h>
#include <WebServer.h>
#include <ESPmDNS.h>
WebServer server(80);
const char* host = "esp32-webupdate";
#endif
const char* ssid = "........";
const char* password = "........";
const char* serverIndex = "<form method='POST' action='/update' enctype='multipart/form-data'><input type='file' name='update'><input type='submit' value='Update'></form>";
void setup(void){
Serial.begin(115200);
Serial.println();
Serial.println("Booting Sketch...");
WiFi.mode(WIFI_AP_STA);
WiFi.begin(ssid, password);
if(WiFi.waitForConnectResult() == WL_CONNECTED){
MDNS.begin(host);
server.on("/", HTTP_GET, [](){
server.sendHeader("Connection", "close");
server.send(200, "text/html", serverIndex);
});
server.on("/update", HTTP_POST, [](){
server.sendHeader("Connection", "close");
server.send(200, "text/plain", (Update.hasError())?"FAIL":"OK");
ESP.restart();
},[](){
HTTPUpload& upload = server.upload();
if(upload.status == UPLOAD_FILE_START){
Serial.setDebugOutput(true);
WiFiUDP::stopAll();
Serial.printf("Update: %s\n", upload.filename.c_str());
uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000;
if(!Update.begin(maxSketchSpace)){//start with max available size
Update.printError(Serial);
}
} else if(upload.status == UPLOAD_FILE_WRITE){
if(Update.write(upload.buf, upload.currentSize) != upload.currentSize){
Update.printError(Serial);
}
} else if(upload.status == UPLOAD_FILE_END){
if(Update.end(true)){ //true to set the size to the current progress
Serial.printf("Update Success: %u\nRebooting...\n", upload.totalSize);
} else {
Update.printError(Serial);
}
Serial.setDebugOutput(false);
}
yield();
});
server.begin();
MDNS.addService("http", "tcp", 80);
Serial.printf("Ready! Open http://%s.local in your browser\n", host);
} else {
Serial.println("WiFi Failed");
}
}
void loop(void){
server.handleClient();
delay(1);
}

View File

@ -1,36 +0,0 @@
#######################################
# Syntax Coloring Map For Ultrasound
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
ESP8266WebServer KEYWORD1
HTTPMethod KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
begin KEYWORD2
handleClient KEYWORD2
on KEYWORD2
addHandler KEYWORD2
uri KEYWORD2
method KEYWORD2
client KEYWORD2
send KEYWORD2
arg KEYWORD2
argName KEYWORD2
args KEYWORD2
hasArg KEYWORD2
onNotFound KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################
HTTP_GET LITERAL1
HTTP_POST LITERAL1
HTTP_ANY LITERAL1

View File

@ -1,9 +0,0 @@
name=WebServer
version=1.0
author=Ivan Grokhotkov
maintainer=Ivan Grokhtkov <ivan@esp8266.com>
sentence=Simple web server library
paragraph=The library supports HTTP GET and POST requests, provides argument parsing, handles one client at a time.
category=Communication
url=
architectures=esp8266,esp32

View File

@ -1,29 +0,0 @@
/*
ESP8266WebServer.h - Dead simple web-server.
Supports only one simultaneous client, knows how to handle GET and POST.
Copyright (c) 2014 Ivan Grokhotkov. 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
Modified 8 May 2015 by Hristo Gochkov (proper post and file upload handling)
*/
#ifndef ESP8266WEBSERVER_H
#define ESP8266WEBSERVER_H
#include <WebServer.h>
#endif //ESP8266WEBSERVER_H

View File

@ -1,610 +0,0 @@
/*
Parsing.cpp - HTTP request parsing.
Copyright (c) 2015 Ivan Grokhotkov. 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
Modified 8 May 2015 by Hristo Gochkov (proper post and file upload handling)
*/
#include <Arduino.h>
#include "WiFiServer.h"
#include "WiFiClient.h"
#include "WebServer.h"
//#define DEBUG_ESP_HTTP_SERVER
#ifdef DEBUG_ESP_PORT
#define DEBUG_OUTPUT DEBUG_ESP_PORT
#else
#define DEBUG_OUTPUT Serial
#endif
static char* readBytesWithTimeout(WiFiClient& client, size_t maxLength, size_t& dataLength, int timeout_ms)
{
char *buf = nullptr;
dataLength = 0;
while (dataLength < maxLength) {
int tries = timeout_ms;
size_t newLength;
while (!(newLength = client.available()) && tries--) delay(1);
if (!newLength) {
break;
}
if (!buf) {
buf = (char *) malloc(newLength + 1);
if (!buf) {
return nullptr;
}
}
else {
char* newBuf = (char *) realloc(buf, dataLength + newLength + 1);
if (!newBuf) {
free(buf);
return nullptr;
}
buf = newBuf;
}
client.readBytes(buf + dataLength, newLength);
dataLength += newLength;
buf[dataLength] = '\0';
}
return buf;
}
bool WebServer::_parseRequest(WiFiClient& client) {
// Read the first line of HTTP request
String req = client.readStringUntil('\r');
client.readStringUntil('\n');
//reset header value
for (int i = 0; i < _headerKeysCount; ++i) {
_currentHeaders[i].value =String();
}
// First line of HTTP request looks like "GET /path HTTP/1.1"
// Retrieve the "/path" part by finding the spaces
int addr_start = req.indexOf(' ');
int addr_end = req.indexOf(' ', addr_start + 1);
if (addr_start == -1 || addr_end == -1) {
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("Invalid request: ");
DEBUG_OUTPUT.println(req);
#endif
return false;
}
String methodStr = req.substring(0, addr_start);
String url = req.substring(addr_start + 1, addr_end);
String versionEnd = req.substring(addr_end + 8);
_currentVersion = atoi(versionEnd.c_str());
String searchStr = "";
int hasSearch = url.indexOf('?');
if (hasSearch != -1){
searchStr = url.substring(hasSearch + 1);
url = url.substring(0, hasSearch);
}
_currentUri = url;
_chunked = false;
HTTPMethod method = HTTP_GET;
if (methodStr == "POST") {
method = HTTP_POST;
} else if (methodStr == "DELETE") {
method = HTTP_DELETE;
} else if (methodStr == "OPTIONS") {
method = HTTP_OPTIONS;
} else if (methodStr == "PUT") {
method = HTTP_PUT;
} else if (methodStr == "PATCH") {
method = HTTP_PATCH;
}
_currentMethod = method;
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("method: ");
DEBUG_OUTPUT.print(methodStr);
DEBUG_OUTPUT.print(" url: ");
DEBUG_OUTPUT.print(url);
DEBUG_OUTPUT.print(" search: ");
DEBUG_OUTPUT.println(searchStr);
#endif
//attach handler
RequestHandler* handler;
for (handler = _firstHandler; handler; handler = handler->next()) {
if (handler->canHandle(_currentMethod, _currentUri))
break;
}
_currentHandler = handler;
String formData;
// below is needed only when POST type request
if (method == HTTP_POST || method == HTTP_PUT || method == HTTP_PATCH || method == HTTP_DELETE){
String boundaryStr;
String headerName;
String headerValue;
bool isForm = false;
bool isEncoded = false;
uint32_t contentLength = 0;
//parse headers
while(1){
req = client.readStringUntil('\r');
client.readStringUntil('\n');
if (req == "") break;//no moar headers
int headerDiv = req.indexOf(':');
if (headerDiv == -1){
break;
}
headerName = req.substring(0, headerDiv);
headerValue = req.substring(headerDiv + 1);
headerValue.trim();
_collectHeader(headerName.c_str(),headerValue.c_str());
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("headerName: ");
DEBUG_OUTPUT.println(headerName);
DEBUG_OUTPUT.print("headerValue: ");
DEBUG_OUTPUT.println(headerValue);
#endif
if (headerName.equalsIgnoreCase("Content-Type")){
if (headerValue.startsWith("text/plain")){
isForm = false;
} else if (headerValue.startsWith("application/x-www-form-urlencoded")){
isForm = false;
isEncoded = true;
} else if (headerValue.startsWith("multipart/")){
boundaryStr = headerValue.substring(headerValue.indexOf('=')+1);
isForm = true;
}
} else if (headerName.equalsIgnoreCase("Content-Length")){
contentLength = headerValue.toInt();
} else if (headerName.equalsIgnoreCase("Host")){
_hostHeader = headerValue;
}
}
if (!isForm){
size_t plainLength;
char* plainBuf = readBytesWithTimeout(client, contentLength, plainLength, HTTP_MAX_POST_WAIT);
if (plainLength < contentLength) {
free(plainBuf);
return false;
}
if (contentLength > 0) {
if (searchStr != "") searchStr += '&';
if(isEncoded){
//url encoded form
String decoded = urlDecode(plainBuf);
size_t decodedLen = decoded.length();
memcpy(plainBuf, decoded.c_str(), decodedLen);
plainBuf[decodedLen] = 0;
searchStr += plainBuf;
}
_parseArguments(searchStr);
if(!isEncoded){
//plain post json or other data
RequestArgument& arg = _currentArgs[_currentArgCount++];
arg.key = "plain";
arg.value = String(plainBuf);
}
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("Plain: ");
DEBUG_OUTPUT.println(plainBuf);
#endif
free(plainBuf);
} else {
// No content - but we can still have arguments in the URL.
_parseArguments(searchStr);
}
}
if (isForm){
_parseArguments(searchStr);
if (!_parseForm(client, boundaryStr, contentLength)) {
return false;
}
}
} else {
String headerName;
String headerValue;
//parse headers
while(1){
req = client.readStringUntil('\r');
client.readStringUntil('\n');
if (req == "") break;//no moar headers
int headerDiv = req.indexOf(':');
if (headerDiv == -1){
break;
}
headerName = req.substring(0, headerDiv);
headerValue = req.substring(headerDiv + 2);
_collectHeader(headerName.c_str(),headerValue.c_str());
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("headerName: ");
DEBUG_OUTPUT.println(headerName);
DEBUG_OUTPUT.print("headerValue: ");
DEBUG_OUTPUT.println(headerValue);
#endif
if (headerName.equalsIgnoreCase("Host")){
_hostHeader = headerValue;
}
}
_parseArguments(searchStr);
}
client.flush();
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("Request: ");
DEBUG_OUTPUT.println(url);
DEBUG_OUTPUT.print(" Arguments: ");
DEBUG_OUTPUT.println(searchStr);
#endif
return true;
}
bool WebServer::_collectHeader(const char* headerName, const char* headerValue) {
for (int i = 0; i < _headerKeysCount; i++) {
if (_currentHeaders[i].key.equalsIgnoreCase(headerName)) {
_currentHeaders[i].value=headerValue;
return true;
}
}
return false;
}
void WebServer::_parseArguments(String data) {
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("args: ");
DEBUG_OUTPUT.println(data);
#endif
if (_currentArgs)
delete[] _currentArgs;
_currentArgs = 0;
if (data.length() == 0) {
_currentArgCount = 0;
_currentArgs = new RequestArgument[1];
return;
}
_currentArgCount = 1;
for (int i = 0; i < (int)data.length(); ) {
i = data.indexOf('&', i);
if (i == -1)
break;
++i;
++_currentArgCount;
}
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("args count: ");
DEBUG_OUTPUT.println(_currentArgCount);
#endif
_currentArgs = new RequestArgument[_currentArgCount+1];
int pos = 0;
int iarg;
for (iarg = 0; iarg < _currentArgCount;) {
int equal_sign_index = data.indexOf('=', pos);
int next_arg_index = data.indexOf('&', pos);
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("pos ");
DEBUG_OUTPUT.print(pos);
DEBUG_OUTPUT.print("=@ ");
DEBUG_OUTPUT.print(equal_sign_index);
DEBUG_OUTPUT.print(" &@ ");
DEBUG_OUTPUT.println(next_arg_index);
#endif
if ((equal_sign_index == -1) || ((equal_sign_index > next_arg_index) && (next_arg_index != -1))) {
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("arg missing value: ");
DEBUG_OUTPUT.println(iarg);
#endif
if (next_arg_index == -1)
break;
pos = next_arg_index + 1;
continue;
}
RequestArgument& arg = _currentArgs[iarg];
arg.key = data.substring(pos, equal_sign_index);
arg.value = urlDecode(data.substring(equal_sign_index + 1, next_arg_index));
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("arg ");
DEBUG_OUTPUT.print(iarg);
DEBUG_OUTPUT.print(" key: ");
DEBUG_OUTPUT.print(arg.key);
DEBUG_OUTPUT.print(" value: ");
DEBUG_OUTPUT.println(arg.value);
#endif
++iarg;
if (next_arg_index == -1)
break;
pos = next_arg_index + 1;
}
_currentArgCount = iarg;
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("args count: ");
DEBUG_OUTPUT.println(_currentArgCount);
#endif
}
void WebServer::_uploadWriteByte(uint8_t b){
if (_currentUpload.currentSize == HTTP_UPLOAD_BUFLEN){
if(_currentHandler && _currentHandler->canUpload(_currentUri))
_currentHandler->upload(*this, _currentUri, _currentUpload);
_currentUpload.totalSize += _currentUpload.currentSize;
_currentUpload.currentSize = 0;
}
_currentUpload.buf[_currentUpload.currentSize++] = b;
}
uint8_t WebServer::_uploadReadByte(WiFiClient& client){
int res = client.read();
if(res == -1){
while(!client.available() && client.connected())
yield();
res = client.read();
}
return (uint8_t)res;
}
bool WebServer::_parseForm(WiFiClient& client, String boundary, uint32_t len){
(void) len;
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("Parse Form: Boundary: ");
DEBUG_OUTPUT.print(boundary);
DEBUG_OUTPUT.print(" Length: ");
DEBUG_OUTPUT.println(len);
#endif
String line;
int retry = 0;
do {
line = client.readStringUntil('\r');
++retry;
} while (line.length() == 0 && retry < 3);
client.readStringUntil('\n');
//start reading the form
if (line == ("--"+boundary)){
RequestArgument* postArgs = new RequestArgument[32];
int postArgsLen = 0;
while(1){
String argName;
String argValue;
String argType;
String argFilename;
bool argIsFile = false;
line = client.readStringUntil('\r');
client.readStringUntil('\n');
if (line.length() > 19 && line.substring(0, 19).equalsIgnoreCase("Content-Disposition")){
int nameStart = line.indexOf('=');
if (nameStart != -1){
argName = line.substring(nameStart+2);
nameStart = argName.indexOf('=');
if (nameStart == -1){
argName = argName.substring(0, argName.length() - 1);
} else {
argFilename = argName.substring(nameStart+2, argName.length() - 1);
argName = argName.substring(0, argName.indexOf('"'));
argIsFile = true;
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("PostArg FileName: ");
DEBUG_OUTPUT.println(argFilename);
#endif
//use GET to set the filename if uploading using blob
if (argFilename == "blob" && hasArg("filename")) argFilename = arg("filename");
}
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("PostArg Name: ");
DEBUG_OUTPUT.println(argName);
#endif
argType = "text/plain";
line = client.readStringUntil('\r');
client.readStringUntil('\n');
if (line.length() > 12 && line.substring(0, 12).equalsIgnoreCase("Content-Type")){
argType = line.substring(line.indexOf(':')+2);
//skip next line
client.readStringUntil('\r');
client.readStringUntil('\n');
}
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("PostArg Type: ");
DEBUG_OUTPUT.println(argType);
#endif
if (!argIsFile){
while(1){
line = client.readStringUntil('\r');
client.readStringUntil('\n');
if (line.startsWith("--"+boundary)) break;
if (argValue.length() > 0) argValue += "\n";
argValue += line;
}
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("PostArg Value: ");
DEBUG_OUTPUT.println(argValue);
DEBUG_OUTPUT.println();
#endif
RequestArgument& arg = postArgs[postArgsLen++];
arg.key = argName;
arg.value = argValue;
if (line == ("--"+boundary+"--")){
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.println("Done Parsing POST");
#endif
break;
}
} else {
_currentUpload.status = UPLOAD_FILE_START;
_currentUpload.name = argName;
_currentUpload.filename = argFilename;
_currentUpload.type = argType;
_currentUpload.totalSize = 0;
_currentUpload.currentSize = 0;
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("Start File: ");
DEBUG_OUTPUT.print(_currentUpload.filename);
DEBUG_OUTPUT.print(" Type: ");
DEBUG_OUTPUT.println(_currentUpload.type);
#endif
if(_currentHandler && _currentHandler->canUpload(_currentUri))
_currentHandler->upload(*this, _currentUri, _currentUpload);
_currentUpload.status = UPLOAD_FILE_WRITE;
uint8_t argByte = _uploadReadByte(client);
readfile:
while(argByte != 0x0D){
if (!client.connected()) return _parseFormUploadAborted();
_uploadWriteByte(argByte);
argByte = _uploadReadByte(client);
}
argByte = _uploadReadByte(client);
if (!client.connected()) return _parseFormUploadAborted();
if (argByte == 0x0A){
argByte = _uploadReadByte(client);
if (!client.connected()) return _parseFormUploadAborted();
if ((char)argByte != '-'){
//continue reading the file
_uploadWriteByte(0x0D);
_uploadWriteByte(0x0A);
goto readfile;
} else {
argByte = _uploadReadByte(client);
if (!client.connected()) return _parseFormUploadAborted();
if ((char)argByte != '-'){
//continue reading the file
_uploadWriteByte(0x0D);
_uploadWriteByte(0x0A);
_uploadWriteByte((uint8_t)('-'));
goto readfile;
}
}
uint8_t endBuf[boundary.length()];
client.readBytes(endBuf, boundary.length());
if (strstr((const char*)endBuf, boundary.c_str()) != NULL){
if(_currentHandler && _currentHandler->canUpload(_currentUri))
_currentHandler->upload(*this, _currentUri, _currentUpload);
_currentUpload.totalSize += _currentUpload.currentSize;
_currentUpload.status = UPLOAD_FILE_END;
if(_currentHandler && _currentHandler->canUpload(_currentUri))
_currentHandler->upload(*this, _currentUri, _currentUpload);
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("End File: ");
DEBUG_OUTPUT.print(_currentUpload.filename);
DEBUG_OUTPUT.print(" Type: ");
DEBUG_OUTPUT.print(_currentUpload.type);
DEBUG_OUTPUT.print(" Size: ");
DEBUG_OUTPUT.println(_currentUpload.totalSize);
#endif
line = client.readStringUntil(0x0D);
client.readStringUntil(0x0A);
if (line == "--"){
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.println("Done Parsing POST");
#endif
break;
}
continue;
} else {
_uploadWriteByte(0x0D);
_uploadWriteByte(0x0A);
_uploadWriteByte((uint8_t)('-'));
_uploadWriteByte((uint8_t)('-'));
uint32_t i = 0;
while(i < boundary.length()){
_uploadWriteByte(endBuf[i++]);
}
argByte = _uploadReadByte(client);
goto readfile;
}
} else {
_uploadWriteByte(0x0D);
goto readfile;
}
break;
}
}
}
}
int iarg;
int totalArgs = ((32 - postArgsLen) < _currentArgCount)?(32 - postArgsLen):_currentArgCount;
for (iarg = 0; iarg < totalArgs; iarg++){
RequestArgument& arg = postArgs[postArgsLen++];
arg.key = _currentArgs[iarg].key;
arg.value = _currentArgs[iarg].value;
}
if (_currentArgs) delete[] _currentArgs;
_currentArgs = new RequestArgument[postArgsLen];
for (iarg = 0; iarg < postArgsLen; iarg++){
RequestArgument& arg = _currentArgs[iarg];
arg.key = postArgs[iarg].key;
arg.value = postArgs[iarg].value;
}
_currentArgCount = iarg;
if (postArgs) delete[] postArgs;
return true;
}
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("Error: line: ");
DEBUG_OUTPUT.println(line);
#endif
return false;
}
String WebServer::urlDecode(const String& text)
{
String decoded = "";
char temp[] = "0x00";
unsigned int len = text.length();
unsigned int i = 0;
while (i < len)
{
char decodedChar;
char encodedChar = text.charAt(i++);
if ((encodedChar == '%') && (i + 1 < len))
{
temp[2] = text.charAt(i++);
temp[3] = text.charAt(i++);
decodedChar = strtol(temp, NULL, 16);
}
else {
if (encodedChar == '+')
{
decodedChar = ' ';
}
else {
decodedChar = encodedChar; // normal ascii char
}
}
decoded += decodedChar;
}
return decoded;
}
bool WebServer::_parseFormUploadAborted(){
_currentUpload.status = UPLOAD_FILE_ABORTED;
if(_currentHandler && _currentHandler->canUpload(_currentUri))
_currentHandler->upload(*this, _currentUri, _currentUpload);
return false;
}

View File

@ -1,530 +0,0 @@
/*
WebServer.cpp - Dead simple web-server.
Supports only one simultaneous client, knows how to handle GET and POST.
Copyright (c) 2014 Ivan Grokhotkov. 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
Modified 8 May 2015 by Hristo Gochkov (proper post and file upload handling)
*/
#include <Arduino.h>
#include <libb64/cencode.h>
#include "WiFiServer.h"
#include "WiFiClient.h"
#include "WebServer.h"
#include "FS.h"
#include "detail/RequestHandlersImpl.h"
//#define DEBUG_ESP_HTTP_SERVER
#ifdef DEBUG_ESP_PORT
#define DEBUG_OUTPUT DEBUG_ESP_PORT
#else
#define DEBUG_OUTPUT Serial
#endif
const char * AUTHORIZATION_HEADER = "Authorization";
WebServer::WebServer(IPAddress addr, int port)
: _server(addr, port)
, _currentMethod(HTTP_ANY)
, _currentVersion(0)
, _currentStatus(HC_NONE)
, _statusChange(0)
, _currentHandler(0)
, _firstHandler(0)
, _lastHandler(0)
, _currentArgCount(0)
, _currentArgs(0)
, _headerKeysCount(0)
, _currentHeaders(0)
, _contentLength(0)
, _chunked(false)
{
}
WebServer::WebServer(int port)
: _server(port)
, _currentMethod(HTTP_ANY)
, _currentVersion(0)
, _currentStatus(HC_NONE)
, _statusChange(0)
, _currentHandler(0)
, _firstHandler(0)
, _lastHandler(0)
, _currentArgCount(0)
, _currentArgs(0)
, _headerKeysCount(0)
, _currentHeaders(0)
, _contentLength(0)
, _chunked(false)
{
}
WebServer::~WebServer() {
if (_currentHeaders)
delete[]_currentHeaders;
_headerKeysCount = 0;
RequestHandler* handler = _firstHandler;
while (handler) {
RequestHandler* next = handler->next();
delete handler;
handler = next;
}
close();
}
void WebServer::begin() {
_currentStatus = HC_NONE;
_server.begin();
if(!_headerKeysCount)
collectHeaders(0, 0);
}
bool WebServer::authenticate(const char * username, const char * password){
if(hasHeader(AUTHORIZATION_HEADER)){
String authReq = header(AUTHORIZATION_HEADER);
if(authReq.startsWith("Basic")){
authReq = authReq.substring(6);
authReq.trim();
char toencodeLen = strlen(username)+strlen(password)+1;
char *toencode = new char[toencodeLen + 1];
if(toencode == NULL){
authReq = String();
return false;
}
char *encoded = new char[base64_encode_expected_len(toencodeLen)+1];
if(encoded == NULL){
authReq = String();
delete[] toencode;
return false;
}
sprintf(toencode, "%s:%s", username, password);
if(base64_encode_chars(toencode, toencodeLen, encoded) > 0 && authReq.equals(encoded)){
authReq = String();
delete[] toencode;
delete[] encoded;
return true;
}
delete[] toencode;
delete[] encoded;
}
authReq = String();
}
return false;
}
void WebServer::requestAuthentication(){
sendHeader("WWW-Authenticate", "Basic realm=\"Login Required\"");
send(401);
}
void WebServer::on(const String &uri, WebServer::THandlerFunction handler) {
on(uri, HTTP_ANY, handler);
}
void WebServer::on(const String &uri, HTTPMethod method, WebServer::THandlerFunction fn) {
on(uri, method, fn, _fileUploadHandler);
}
void WebServer::on(const String &uri, HTTPMethod method, WebServer::THandlerFunction fn, WebServer::THandlerFunction ufn) {
_addRequestHandler(new FunctionRequestHandler(fn, ufn, uri, method));
}
void WebServer::addHandler(RequestHandler* handler) {
_addRequestHandler(handler);
}
void WebServer::_addRequestHandler(RequestHandler* handler) {
if (!_lastHandler) {
_firstHandler = handler;
_lastHandler = handler;
}
else {
_lastHandler->next(handler);
_lastHandler = handler;
}
}
void WebServer::serveStatic(const char* uri, FS& fs, const char* path, const char* cache_header) {
_addRequestHandler(new StaticRequestHandler(fs, path, uri, cache_header));
}
void WebServer::handleClient() {
if (_currentStatus == HC_NONE) {
WiFiClient client = _server.available();
if (!client) {
return;
}
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.println("New client");
#endif
_currentClient = client;
_currentStatus = HC_WAIT_READ;
_statusChange = millis();
}
if (!_currentClient.connected()) {
_currentClient = WiFiClient();
_currentStatus = HC_NONE;
return;
}
// Wait for data from client to become available
if (_currentStatus == HC_WAIT_READ) {
if (!_currentClient.available()) {
if (millis() - _statusChange > HTTP_MAX_DATA_WAIT) {
_currentClient = WiFiClient();
_currentStatus = HC_NONE;
}
yield();
return;
}
if (!_parseRequest(_currentClient)) {
_currentClient = WiFiClient();
_currentStatus = HC_NONE;
return;
}
_currentClient.setTimeout(HTTP_MAX_SEND_WAIT);
_contentLength = CONTENT_LENGTH_NOT_SET;
_handleRequest();
if (!_currentClient.connected()) {
_currentClient = WiFiClient();
_currentStatus = HC_NONE;
return;
} else {
_currentStatus = HC_WAIT_CLOSE;
_statusChange = millis();
return;
}
}
if (_currentStatus == HC_WAIT_CLOSE) {
if (millis() - _statusChange > HTTP_MAX_CLOSE_WAIT) {
_currentClient = WiFiClient();
_currentStatus = HC_NONE;
} else {
yield();
return;
}
}
}
void WebServer::close() {
#ifdef ESP8266
_server.stop();
#else
// TODO add ESP32 WiFiServer::stop()
_server.end();
#endif
}
void WebServer::stop() {
close();
}
void WebServer::sendHeader(const String& name, const String& value, bool first) {
String headerLine = name;
headerLine += ": ";
headerLine += value;
headerLine += "\r\n";
if (first) {
_responseHeaders = headerLine + _responseHeaders;
}
else {
_responseHeaders += headerLine;
}
}
void WebServer::setContentLength(size_t contentLength) {
_contentLength = contentLength;
}
void WebServer::_prepareHeader(String& response, int code, const char* content_type, size_t contentLength) {
response = "HTTP/1."+String(_currentVersion)+" ";
response += String(code);
response += " ";
response += _responseCodeToString(code);
response += "\r\n";
if (!content_type)
content_type = "text/html";
sendHeader("Content-Type", content_type, true);
if (_contentLength == CONTENT_LENGTH_NOT_SET) {
sendHeader("Content-Length", String(contentLength));
} else if (_contentLength != CONTENT_LENGTH_UNKNOWN) {
sendHeader("Content-Length", String(_contentLength));
} else if(_contentLength == CONTENT_LENGTH_UNKNOWN && _currentVersion){ //HTTP/1.1 or above client
//let's do chunked
_chunked = true;
sendHeader("Accept-Ranges","none");
sendHeader("Transfer-Encoding","chunked");
}
sendHeader("Connection", "close");
response += _responseHeaders;
response += "\r\n";
_responseHeaders = String();
}
void WebServer::send(int code, const char* content_type, const String& content) {
String header;
// Can we asume the following?
//if(code == 200 && content.length() == 0 && _contentLength == CONTENT_LENGTH_NOT_SET)
// _contentLength = CONTENT_LENGTH_UNKNOWN;
_prepareHeader(header, code, content_type, content.length());
_currentClient.write(header.c_str(), header.length());
if(content.length())
sendContent(content);
}
void WebServer::send_P(int code, PGM_P content_type, PGM_P content) {
size_t contentLength = 0;
if (content != NULL) {
contentLength = strlen_P(content);
}
String header;
char type[64];
memccpy_P((void*)type, (PGM_VOID_P)content_type, 0, sizeof(type));
_prepareHeader(header, code, (const char* )type, contentLength);
_currentClient.write(header.c_str(), header.length());
sendContent_P(content);
}
void WebServer::send_P(int code, PGM_P content_type, PGM_P content, size_t contentLength) {
String header;
char type[64];
memccpy_P((void*)type, (PGM_VOID_P)content_type, 0, sizeof(type));
_prepareHeader(header, code, (const char* )type, contentLength);
sendContent(header);
sendContent_P(content, contentLength);
}
void WebServer::send(int code, char* content_type, const String& content) {
send(code, (const char*)content_type, content);
}
void WebServer::send(int code, const String& content_type, const String& content) {
send(code, (const char*)content_type.c_str(), content);
}
void WebServer::sendContent(const String& content) {
const char * footer = "\r\n";
size_t len = content.length();
if(_chunked) {
char * chunkSize = (char *)malloc(11);
if(chunkSize){
sprintf(chunkSize, "%x%s", len, footer);
_currentClient.write(chunkSize, strlen(chunkSize));
free(chunkSize);
}
}
_currentClient.write(content.c_str(), len);
if(_chunked){
_currentClient.write(footer, 2);
}
}
void WebServer::sendContent_P(PGM_P content) {
sendContent_P(content, strlen_P(content));
}
void WebServer::sendContent_P(PGM_P content, size_t size) {
const char * footer = "\r\n";
if(_chunked) {
char * chunkSize = (char *)malloc(11);
if(chunkSize){
sprintf(chunkSize, "%x%s", size, footer);
_currentClient.write(chunkSize, strlen(chunkSize));
free(chunkSize);
}
}
_currentClient.write_P(content, size);
if(_chunked){
_currentClient.write(footer, 2);
}
}
String WebServer::arg(String name) {
for (int i = 0; i < _currentArgCount; ++i) {
if ( _currentArgs[i].key == name )
return _currentArgs[i].value;
}
return String();
}
String WebServer::arg(int i) {
if (i < _currentArgCount)
return _currentArgs[i].value;
return String();
}
String WebServer::argName(int i) {
if (i < _currentArgCount)
return _currentArgs[i].key;
return String();
}
int WebServer::args() {
return _currentArgCount;
}
bool WebServer::hasArg(String name) {
for (int i = 0; i < _currentArgCount; ++i) {
if (_currentArgs[i].key == name)
return true;
}
return false;
}
String WebServer::header(String name) {
for (int i = 0; i < _headerKeysCount; ++i) {
if (_currentHeaders[i].key.equalsIgnoreCase(name))
return _currentHeaders[i].value;
}
return String();
}
void WebServer::collectHeaders(const char* headerKeys[], const size_t headerKeysCount) {
_headerKeysCount = headerKeysCount + 1;
if (_currentHeaders)
delete[]_currentHeaders;
_currentHeaders = new RequestArgument[_headerKeysCount];
_currentHeaders[0].key = AUTHORIZATION_HEADER;
for (int i = 1; i < _headerKeysCount; i++){
_currentHeaders[i].key = headerKeys[i-1];
}
}
String WebServer::header(int i) {
if (i < _headerKeysCount)
return _currentHeaders[i].value;
return String();
}
String WebServer::headerName(int i) {
if (i < _headerKeysCount)
return _currentHeaders[i].key;
return String();
}
int WebServer::headers() {
return _headerKeysCount;
}
bool WebServer::hasHeader(String name) {
for (int i = 0; i < _headerKeysCount; ++i) {
if ((_currentHeaders[i].key.equalsIgnoreCase(name)) && (_currentHeaders[i].value.length() > 0))
return true;
}
return false;
}
String WebServer::hostHeader() {
return _hostHeader;
}
void WebServer::onFileUpload(THandlerFunction fn) {
_fileUploadHandler = fn;
}
void WebServer::onNotFound(THandlerFunction fn) {
_notFoundHandler = fn;
}
void WebServer::_handleRequest() {
bool handled = false;
if (!_currentHandler){
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.println("request handler not found");
#endif
}
else {
handled = _currentHandler->handle(*this, _currentMethod, _currentUri);
#ifdef DEBUG_ESP_HTTP_SERVER
if (!handled) {
DEBUG_OUTPUT.println("request handler failed to handle request");
}
#endif
}
if (!handled) {
if(_notFoundHandler) {
_notFoundHandler();
}
else {
send(404, "text/plain", String("Not found: ") + _currentUri);
}
}
_currentUri = String();
}
String WebServer::_responseCodeToString(int code) {
switch (code) {
case 100: return F("Continue");
case 101: return F("Switching Protocols");
case 200: return F("OK");
case 201: return F("Created");
case 202: return F("Accepted");
case 203: return F("Non-Authoritative Information");
case 204: return F("No Content");
case 205: return F("Reset Content");
case 206: return F("Partial Content");
case 300: return F("Multiple Choices");
case 301: return F("Moved Permanently");
case 302: return F("Found");
case 303: return F("See Other");
case 304: return F("Not Modified");
case 305: return F("Use Proxy");
case 307: return F("Temporary Redirect");
case 400: return F("Bad Request");
case 401: return F("Unauthorized");
case 402: return F("Payment Required");
case 403: return F("Forbidden");
case 404: return F("Not Found");
case 405: return F("Method Not Allowed");
case 406: return F("Not Acceptable");
case 407: return F("Proxy Authentication Required");
case 408: return F("Request Time-out");
case 409: return F("Conflict");
case 410: return F("Gone");
case 411: return F("Length Required");
case 412: return F("Precondition Failed");
case 413: return F("Request Entity Too Large");
case 414: return F("Request-URI Too Large");
case 415: return F("Unsupported Media Type");
case 416: return F("Requested range not satisfiable");
case 417: return F("Expectation Failed");
case 500: return F("Internal Server Error");
case 501: return F("Not Implemented");
case 502: return F("Bad Gateway");
case 503: return F("Service Unavailable");
case 504: return F("Gateway Time-out");
case 505: return F("HTTP Version not supported");
default: return "";
}
}

View File

@ -1,236 +0,0 @@
/*
WebServer.h - Dead simple web-server.
Supports only one simultaneous client, knows how to handle GET and POST.
Copyright (c) 2014 Ivan Grokhotkov. 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
Modified 8 May 2015 by Hristo Gochkov (proper post and file upload handling)
*/
#ifndef WEBSERVER_H
#define WEBSERVER_H
#include <functional>
#ifdef ESP8266
#define WebServer ESP8266WebServer
#include <ESP8266WiFi.h>
#else
#include <WiFi.h>
#define write_P write
#endif
enum HTTPMethod { HTTP_ANY, HTTP_GET, HTTP_POST, HTTP_PUT, HTTP_PATCH, HTTP_DELETE, HTTP_OPTIONS };
enum HTTPUploadStatus { UPLOAD_FILE_START, UPLOAD_FILE_WRITE, UPLOAD_FILE_END,
UPLOAD_FILE_ABORTED };
enum HTTPClientStatus { HC_NONE, HC_WAIT_READ, HC_WAIT_CLOSE };
#define HTTP_DOWNLOAD_UNIT_SIZE 1460
#ifndef HTTP_UPLOAD_BUFLEN
#define HTTP_UPLOAD_BUFLEN 2048
#endif
#define HTTP_MAX_DATA_WAIT 1000 //ms to wait for the client to send the request
#define HTTP_MAX_POST_WAIT 1000 //ms to wait for POST data to arrive
#define HTTP_MAX_SEND_WAIT 5000 //ms to wait for data chunk to be ACKed
#define HTTP_MAX_CLOSE_WAIT 2000 //ms to wait for the client to close the connection
#define CONTENT_LENGTH_UNKNOWN ((size_t) -1)
#define CONTENT_LENGTH_NOT_SET ((size_t) -2)
class WebServer;
typedef struct {
HTTPUploadStatus status;
String filename;
String name;
String type;
size_t totalSize; // file size
size_t currentSize; // size of data currently in buf
uint8_t buf[HTTP_UPLOAD_BUFLEN];
} HTTPUpload;
#include "detail/RequestHandler.h"
namespace fs {
class FS;
}
class WebServer
{
public:
WebServer(IPAddress addr, int port = 80);
WebServer(int port = 80);
~WebServer();
void begin();
void handleClient();
void close();
void stop();
bool authenticate(const char * username, const char * password);
void requestAuthentication();
typedef std::function<void(void)> THandlerFunction;
void on(const String &uri, THandlerFunction handler);
void on(const String &uri, HTTPMethod method, THandlerFunction fn);
void on(const String &uri, HTTPMethod method, THandlerFunction fn, THandlerFunction ufn);
void addHandler(RequestHandler* handler);
void serveStatic(const char* uri, fs::FS& fs, const char* path, const char* cache_header = NULL );
void onNotFound(THandlerFunction fn); //called when handler is not assigned
void onFileUpload(THandlerFunction fn); //handle file uploads
String uri() { return _currentUri; }
HTTPMethod method() { return _currentMethod; }
WiFiClient client() { return _currentClient; }
HTTPUpload& upload() { return _currentUpload; }
String arg(String name); // get request argument value by name
String arg(int i); // get request argument value by number
String argName(int i); // get request argument name by number
int args(); // get arguments count
bool hasArg(String name); // check if argument exists
void collectHeaders(const char* headerKeys[], const size_t headerKeysCount); // set the request headers to collect
String header(String name); // get request header value by name
String header(int i); // get request header value by number
String headerName(int i); // get request header name by number
int headers(); // get header count
bool hasHeader(String name); // check if header exists
String hostHeader(); // get request host header if available or empty String if not
// send response to the client
// code - HTTP response code, can be 200 or 404
// content_type - HTTP content type, like "text/plain" or "image/png"
// content - actual content body
void send(int code, const char* content_type = NULL, const String& content = String(""));
void send(int code, char* content_type, const String& content);
void send(int code, const String& content_type, const String& content);
void send_P(int code, PGM_P content_type, PGM_P content);
void send_P(int code, PGM_P content_type, PGM_P content, size_t contentLength);
void setContentLength(size_t contentLength);
void sendHeader(const String& name, const String& value, bool first = false);
void sendContent(const String& content);
void sendContent_P(PGM_P content);
void sendContent_P(PGM_P content, size_t size);
static String urlDecode(const String& text);
#ifdef ESP8266
template<typename T> size_t streamFile(T &file, const String& contentType){
setContentLength(file.size());
if (String(file.name()).endsWith(".gz") &&
contentType != "application/x-gzip" &&
contentType != "application/octet-stream"){
sendHeader("Content-Encoding", "gzip");
}
send(200, contentType, "");
return _currentClient.write(file);
}
#else
template<typename T> size_t streamFile(T &file, const String& contentType){
#define STREAMFILE_BUFSIZE 2*1460
setContentLength(file.size());
if (String(file.name()).endsWith(".gz") &&
contentType != "application/x-gzip" &&
contentType != "application/octet-stream") {
sendHeader("Content-Encoding", "gzip");
}
send(200, contentType, "");
uint8_t *buf = (uint8_t *)malloc(STREAMFILE_BUFSIZE);
if (buf == NULL) {
//DBG_OUTPUT_PORT.printf("streamFile malloc failed");
return 0;
}
size_t totalBytesOut = 0;
while (client().connected() && (file.available() > 0)) {
int bytesOut;
int bytesIn = file.read(buf, STREAMFILE_BUFSIZE);
if (bytesIn <= 0) break;
while (1) {
bytesOut = 0;
if (!client().connected()) break;
bytesOut = client().write(buf, bytesIn);
if (bytesIn == bytesOut) break;
//DBG_OUTPUT_PORT.printf("bytesIn %d != bytesOut %d\r\n",
//bytesIn, bytesOut);
delay(1);
}
totalBytesOut += bytesOut;
yield();
}
if (totalBytesOut != file.size()) {
//DBG_OUTPUT_PORT.printf("file size %d bytes out %d\r\n",
// file.size(), totalBytesOut);
}
free(buf);
return totalBytesOut;
}
#endif
protected:
void _addRequestHandler(RequestHandler* handler);
void _handleRequest();
bool _parseRequest(WiFiClient& client);
void _parseArguments(String data);
static String _responseCodeToString(int code);
bool _parseForm(WiFiClient& client, String boundary, uint32_t len);
bool _parseFormUploadAborted();
void _uploadWriteByte(uint8_t b);
uint8_t _uploadReadByte(WiFiClient& client);
void _prepareHeader(String& response, int code, const char* content_type, size_t contentLength);
bool _collectHeader(const char* headerName, const char* headerValue);
struct RequestArgument {
String key;
String value;
};
WiFiServer _server;
WiFiClient _currentClient;
HTTPMethod _currentMethod;
String _currentUri;
uint8_t _currentVersion;
HTTPClientStatus _currentStatus;
unsigned long _statusChange;
RequestHandler* _currentHandler;
RequestHandler* _firstHandler;
RequestHandler* _lastHandler;
THandlerFunction _notFoundHandler;
THandlerFunction _fileUploadHandler;
int _currentArgCount;
RequestArgument* _currentArgs;
HTTPUpload _currentUpload;
int _headerKeysCount;
RequestArgument* _currentHeaders;
size_t _contentLength;
String _responseHeaders;
String _hostHeader;
bool _chunked;
};
#endif //WEBSERVER_H

View File

@ -1,19 +0,0 @@
#ifndef REQUESTHANDLER_H
#define REQUESTHANDLER_H
class RequestHandler {
public:
virtual ~RequestHandler() { }
virtual bool canHandle(HTTPMethod method, String uri) { (void) method; (void) uri; return false; }
virtual bool canUpload(String uri) { (void) uri; return false; }
virtual bool handle(WebServer& server, HTTPMethod requestMethod, String requestUri) { (void) server; (void) requestMethod; (void) requestUri; return false; }
virtual void upload(WebServer& server, String requestUri, HTTPUpload& upload) { (void) server; (void) requestUri; (void) upload; }
RequestHandler* next() { return _next; }
void next(RequestHandler* r) { _next = r; }
private:
RequestHandler* _next = nullptr;
};
#endif //REQUESTHANDLER_H

View File

@ -1,191 +0,0 @@
#ifndef REQUESTHANDLERSIMPL_H
#define REQUESTHANDLERSIMPL_H
#include "RequestHandler.h"
#ifdef ESP8266
// Table of extension->MIME strings stored in PROGMEM, needs to be global due to GCC section typing rules
static const struct {const char endsWith[16]; const char mimeType[32];} mimeTable[] ICACHE_RODATA_ATTR = {
#else
static const struct {const char endsWith[16]; const char mimeType[32];} mimeTable[] = {
#endif
{ ".html", "text/html" },
{ ".htm", "text/html" },
{ ".css", "text/css" },
{ ".txt", "text/plain" },
{ ".js", "application/javascript" },
{ ".json", "application/json" },
{ ".png", "image/png" },
{ ".gif", "image/gif" },
{ ".jpg", "image/jpeg" },
{ ".ico", "image/x-icon" },
{ ".svg", "image/svg+xml" },
{ ".ttf", "application/x-font-ttf" },
{ ".otf", "application/x-font-opentype" },
{ ".woff", "application/font-woff" },
{ ".woff2", "application/font-woff2" },
{ ".eot", "application/vnd.ms-fontobject" },
{ ".sfnt", "application/font-sfnt" },
{ ".xml", "text/xml" },
{ ".pdf", "application/pdf" },
{ ".zip", "application/zip" },
{ ".gz", "application/x-gzip" },
{ ".appcache", "text/cache-manifest" },
{ "", "application/octet-stream" } };
class FunctionRequestHandler : public RequestHandler {
public:
FunctionRequestHandler(WebServer::THandlerFunction fn, WebServer::THandlerFunction ufn, const String &uri, HTTPMethod method)
: _fn(fn)
, _ufn(ufn)
, _uri(uri)
, _method(method)
{
}
bool canHandle(HTTPMethod requestMethod, String requestUri) override {
if (_method != HTTP_ANY && _method != requestMethod)
return false;
if (requestUri != _uri)
return false;
return true;
}
bool canUpload(String requestUri) override {
if (!_ufn || !canHandle(HTTP_POST, requestUri))
return false;
return true;
}
bool handle(WebServer& server, HTTPMethod requestMethod, String requestUri) override {
(void) server;
if (!canHandle(requestMethod, requestUri))
return false;
_fn();
return true;
}
void upload(WebServer& server, String requestUri, HTTPUpload& upload) override {
(void) server;
(void) upload;
if (canUpload(requestUri))
_ufn();
}
protected:
WebServer::THandlerFunction _fn;
WebServer::THandlerFunction _ufn;
String _uri;
HTTPMethod _method;
};
class StaticRequestHandler : public RequestHandler {
public:
StaticRequestHandler(FS& fs, const char* path, const char* uri, const char* cache_header)
: _fs(fs)
, _uri(uri)
, _path(path)
, _cache_header(cache_header)
{
_isFile = fs.exists(path);
#ifdef ESP8266
DEBUGV("StaticRequestHandler: path=%s uri=%s isFile=%d, cache_header=%s\r\n", path, uri, _isFile, cache_header);
#else
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.printf("StaticRequestHandler: path=%s uri=%s isFile=%d, cache_header=%s\r\n", path, uri, _isFile, cache_header);
#endif
#endif
_baseUriLength = _uri.length();
}
bool canHandle(HTTPMethod requestMethod, String requestUri) override {
if (requestMethod != HTTP_GET)
return false;
if ((_isFile && requestUri != _uri) || !requestUri.startsWith(_uri))
return false;
return true;
}
bool handle(WebServer& server, HTTPMethod requestMethod, String requestUri) override {
if (!canHandle(requestMethod, requestUri))
return false;
#ifdef ESP8266
DEBUGV("StaticRequestHandler::handle: request=%s _uri=%s\r\n", requestUri.c_str(), _uri.c_str());
#else
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.printf("StaticRequestHandler::handle: request=%s _uri=%s\r\n", requestUri.c_str(), _uri.c_str());
#endif
#endif
String path(_path);
if (!_isFile) {
// Base URI doesn't point to a file.
// If a directory is requested, look for index file.
if (requestUri.endsWith("/")) requestUri += "index.htm";
// Append whatever follows this URI in request to get the file path.
path += requestUri.substring(_baseUriLength);
}
#ifdef ESP8266
DEBUGV("StaticRequestHandler::handle: path=%s, isFile=%d\r\n", path.c_str(), _isFile);
#else
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.printf("StaticRequestHandler::handle: path=%s, isFile=%d\r\n", path.c_str(), _isFile);
#endif
#endif
String contentType = getContentType(path);
// look for gz file, only if the original specified path is not a gz. So part only works to send gzip via content encoding when a non compressed is asked for
// if you point the the path to gzip you will serve the gzip as content type "application/x-gzip", not text or javascript etc...
if (!path.endsWith(".gz") && !_fs.exists(path)) {
String pathWithGz = path + ".gz";
if(_fs.exists(pathWithGz))
path += ".gz";
}
File f = _fs.open(path, "r");
if (!f)
return false;
if (_cache_header.length() != 0)
server.sendHeader("Cache-Control", _cache_header);
server.streamFile(f, contentType);
return true;
}
static String getContentType(const String& path) {
char buff[sizeof(mimeTable[0].mimeType)];
// Check all entries but last one for match, return if found
for (size_t i=0; i < sizeof(mimeTable)/sizeof(mimeTable[0])-1; i++) {
strcpy_P(buff, mimeTable[i].endsWith);
if (path.endsWith(buff)) {
strcpy_P(buff, mimeTable[i].mimeType);
return String(buff);
}
}
// Fall-through and just return default type
strcpy_P(buff, mimeTable[sizeof(mimeTable)/sizeof(mimeTable[0])-1].mimeType);
return String(buff);
}
protected:
FS _fs;
String _uri;
String _path;
String _cache_header;
bool _isFile;
size_t _baseUriLength;
};
#endif //REQUESTHANDLERSIMPL_H