mirror of
https://git.mirrors.martin98.com/https://github.com/luc-github/ESP3D.git
synced 2025-07-30 02:21:59 +08:00
Prepare branch
This commit is contained in:
parent
c3fbbd3c63
commit
a84d146921
52
.travis.yml
52
.travis.yml
@ -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
138
README.md
@ -1,137 +1,3 @@
|
||||
# ESP3D[](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 [](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 : [](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 [](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://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>
|
||||
|
@ -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°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°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°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>
|
@ -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>
|
||||
|
@ -1 +0,0 @@
|
||||
bin2c /infile tool.html.gz /outfile out.h /targetfolder .
|
@ -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);
|
||||
|
@ -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
|
@ -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.
@ -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%;
|
||||
}
|
||||
}
|
@ -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 =" Status: "+jsonresponse.status;
|
||||
content +=" | Total space: "+jsonresponse.total;
|
||||
content +=" | Used space: "+jsonresponse.used;
|
||||
content +=" | Occupation: ";
|
||||
content +="<meter min='0' max='100' high='90' value='"+jsonresponse.occupation +"'></meter> "+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();
|
||||
}
|
@ -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
|
||||
|
||||
</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"/> <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" > </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>
|
||||
|
||||
|
@ -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
|
209
esp3d/bridge.cpp
209
esp3d/bridge.cpp
@ -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
|
@ -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
|
1600
esp3d/command.cpp
1600
esp3d/command.cpp
File diff suppressed because it is too large
Load Diff
@ -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
|
1865
esp3d/config.cpp
1865
esp3d/config.cpp
File diff suppressed because it is too large
Load Diff
430
esp3d/config.h
430
esp3d/config.h
@ -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
|
@ -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.
@ -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
|
||||
}
|
||||
]
|
189
esp3d/esp3d.ino
189
esp3d/esp3d.ino
@ -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();
|
||||
}
|
||||
}
|
326
esp3d/nofile.h
326
esp3d/nofile.h
@ -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
|
||||
};
|
@ -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;
|
||||
}
|
||||
|
@ -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
@ -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
|
@ -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;
|
@ -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
|
32
libraries/WebServer/.gitignore
vendored
32
libraries/WebServer/.gitignore
vendored
@ -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
|
@ -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
|
||||
|
@ -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!
|
@ -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
|
@ -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);
|
||||
}
|
@ -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.
Binary file not shown.
Before Width: | Height: | Size: 1.1 KiB |
Binary file not shown.
@ -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>
|
@ -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();
|
||||
}
|
@ -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();
|
||||
}
|
@ -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();
|
||||
}
|
@ -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>
|
@ -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 |
@ -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();
|
||||
}
|
@ -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);
|
||||
}
|
@ -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
|
@ -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
|
@ -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
|
@ -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;
|
||||
}
|
@ -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 "";
|
||||
}
|
||||
}
|
@ -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
|
@ -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
|
@ -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
|
Loading…
x
Reference in New Issue
Block a user