diff --git a/.gitignore b/.gitignore index 0df67ed..369459f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +html/ build/ firmware/ espfs/mkespfsimage/*.o diff --git a/build_web.sh b/build_web.sh index ee8ce79..1495c74 100755 --- a/build_web.sh +++ b/build_web.sh @@ -2,7 +2,7 @@ echo "-- Preparing WWW files --" -rm -r html +[[ -e html ]] && rm -r html mkdir -p html/img mkdir -p html/js mkdir -p html/css diff --git a/html/about.tpl b/html/about.tpl deleted file mode 100644 index d83f202..0000000 --- a/html/about.tpl +++ /dev/null @@ -1,80 +0,0 @@ - - - - - About - ESP8266 Remote Terminal - - - - - - - -

About

- -
- -

ESP8266 Remote Terminal

- - - -

© Ondřej Hruška, 2017 <ondra@ondrovo.com>

- -

Katedra měření, FEL ČVUT
Department of Measurement, FEE CTU

-
- -
-

Firmware

- - - - - - - - - - - - - -
Firmwarev%vers_fw%, build %date% at %time%
libesphttpdv%vers_httpd%
ESP IoT SDKv%vers_sdk%
-
- -
-

Issues

-

- Please report any issues to the bugtracker or send them by e-mail. -

-

- Firmware updates can be downloaded from the releases page. - Flash the images using esptool. -

-
- -
-

Contributing

-

- Submit your improvements and ideas to the project on GitHub.
-

-
- -
-

Acknowledgements

-

- The webserver is based on a fork of the - esphttpd library by Jeroen Domburg (Sprite_tm). -

-

- Using (modified) JS library chibi.js by Kyle Barrow as a lightweight jQuery alternative. -

-
- - - - - diff --git a/html/css/app.css b/html/css/app.css deleted file mode 100644 index 409c132..0000000 --- a/html/css/app.css +++ /dev/null @@ -1,864 +0,0 @@ -/* normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */ -/** - * 1. Set default font family to sans-serif. - * 2. Prevent iOS and IE text size adjust after device orientation change, - * without disabling user zoom. - */ -*, *:before, *:after { - box-sizing: border-box; } - -html { - font-family: sans-serif; - /* 1 */ - -ms-text-size-adjust: 100%; - /* 2 */ - -webkit-text-size-adjust: 100%; - /* 2 */ } - -/** - * Remove default margin. - */ -body { - margin: 0; } - -/* HTML5 display definitions - ========================================================================== */ -/** - * Correct `block` display not defined for any HTML5 element in IE 8/9. - * Correct `block` display not defined for `details` or `summary` in IE 10/11 - * and Firefox. - * Correct `block` display not defined for `main` in IE 11. - */ -figure, -nav - { - display: block; } - -/** - * 1. Correct `inline-block` display not defined in IE 8/9. - * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera. - */ -canvas, -progress - { - display: inline-block; - /* 1 */ - vertical-align: baseline; - /* 2 */ } - -/** - * Prevent modern browsers from displaying `audio` without controls. - * Remove excess height in iOS 5 devices. - */ -/** - * Address `[hidden]` styling not present in IE 8/9/10. - * Hide the `template` element in IE 8/9/10/11, Safari, and Firefox < 22. - */ -[hidden] - { - display: none; } - -/* Links - ========================================================================== */ -/** - * Remove the gray background color from active links in IE 10. - */ -a { - background-color: transparent; } - -/** - * Improve readability of focused elements when they are also in an - * active/hover state. - */ -a:active, -a:hover { - outline: 0; } - -/* Text-level semantics - ========================================================================== */ -/** - * Address styling not present in IE 8/9/10/11, Safari, and Chrome. - */ -/** - * Address style set to `bolder` in Firefox 4+, Safari, and Chrome. - */ -b - { - font-weight: bold; } - -/** - * Address styling not present in Safari and Chrome. - */ -/** - * Address variable `h1` font-size and margin within `section` and `article` - * contexts in Firefox 4+, Safari, and Chrome. - */ -h1 { - font-size: 2em; - margin: 0.67em 0; } - -h2 { - font-size: 2em; - margin: 0.67em 0; } - -/** - * Address styling not present in IE 8/9. - */ -/** - * Address inconsistent and variable font size in all browsers. - */ -small { - font-size: 80%; } - -/** - * Prevent `sub` and `sup` affecting `line-height` in all browsers. - */ -sub, -sup { - font-size: 75%; - line-height: 0; - position: relative; - vertical-align: baseline; } - -sup { - top: -0.5em; } - -sub { - bottom: -0.25em; } - -/* Embedded content - ========================================================================== */ -/** - * Remove border when inside `a` element in IE 8/9/10. - */ -img { - border: 0; } - -/** - * Correct overflow not hidden in IE 9/10/11. - */ -svg:not(:root) { - overflow: hidden; } - -/* Grouping content - ========================================================================== */ -/** - * Address margin not present in IE 8/9 and Safari. - */ -/** - * Address differences between Firefox and other browsers. - */ -hr { - box-sizing: content-box; - height: 0; } - -/** - * Contain overflow in all browsers. - */ -pre { - overflow: auto; } - -/** - * Address odd `em`-unit font size rendering in all browsers. - */ -code, -pre - { - font-family: monospace; - font-size: 1em; } - -/* Forms - ========================================================================== */ -/** - * Known limitation: by default, Chrome and Safari on OS X allow very limited - * styling of `select`, unless a `border` property is set. - */ -/** - * 1. Correct color not being inherited. - * Known issue: affects color of disabled elements. - * 2. Correct font properties not being inherited. - * 3. Address margins set differently in Firefox 4+, Safari, and Chrome. - */ -button, -input, -select, -textarea { - color: inherit; - /* 1 */ - font: inherit; - /* 2 */ - margin: 0; - /* 3 */ } - -/** - * Address `overflow` set to `hidden` in IE 8/9/10/11. - */ -button { - overflow: visible; } - -/** - * Address inconsistent `text-transform` inheritance for `button` and `select`. - * All other form control elements do not inherit `text-transform` values. - * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera. - * Correct `select` style inheritance in Firefox. - */ -button, -select { - text-transform: none; } - -/** - * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` - * and `video` controls. - * 2. Correct inability to style clickable `input` types in iOS. - * 3. Improve usability and consistency of cursor style between image-type - * `input` and others. - */ -button, -input[type="reset"], -input[type="submit"] { - -webkit-appearance: button; - /* 2 */ - cursor: pointer; - /* 3 */ } - -/** - * Re-set default cursor for disabled elements. - */ -button[disabled], -html input[disabled] { - cursor: default; } - -/** - * Remove inner padding and border in Firefox 4+. - */ -button::-moz-focus-inner, -input::-moz-focus-inner { - border: 0; - padding: 0; } - -/** - * Address Firefox 4+ setting `line-height` on `input` using `!important` in - * the UA stylesheet. - */ -input { - line-height: normal; } - -/** - * It's recommended that you don't attempt to style these elements. - * Firefox's implementation doesn't respect box-sizing, padding, or width. - * - * 1. Address box sizing set to `content-box` in IE 8/9/10. - * 2. Remove excess padding in IE 8/9/10. - */ -input[type="checkbox"], -input[type="radio"] { - box-sizing: border-box; - /* 1 */ - padding: 0; - /* 2 */ } - -/** - * Fix the cursor style for Chrome's increment/decrement buttons. For certain - * `font-size` values of the `input`, it causes the cursor style of the - * decrement button to change from `default` to `text`. - */ -/** - * 1. Address `appearance` set to `searchfield` in Safari and Chrome. - * 2. Address `box-sizing` set to `border-box` in Safari and Chrome. - */ -/** - * Remove inner padding and search cancel button in Safari and Chrome on OS X. - * Safari (but not Chrome) clips the cancel button when the search input has - * padding (and `textfield` appearance). - */ -/** - * Define consistent border, margin, and padding. - */ -/** - * 1. Correct `color` not being inherited in IE 8/9/10/11. - * 2. Remove padding so people aren't caught out if they zero out fieldsets. - */ -legend { - border: 0; - /* 1 */ - padding: 0; - /* 2 */ } - -/** - * Remove default vertical scrollbar in IE 8/9/10/11. - */ -textarea { - overflow: auto; } - -/** - * Don't inherit the `font-weight` (applied by a rule above). - * NOTE: the default cannot safely be changed in Chrome and Safari on OS X. - */ -/* Tables - ========================================================================== */ -/** - * Remove most spacing between table cells. - */ -table { - border-collapse: collapse; - border-spacing: 0; } - -td, -th { - padding: 0; } - -html { - box-sizing: border-box; } - -*, *::after, *::before { - box-sizing: inherit; } - -.hidden { - display: none !important; } - -[onclick] { - cursor: pointer; } - -.Modal { - position: fixed; - width: 100%; - height: 100%; - left: 0; - top: 0; - right: 0; - bottom: 0; - display: flex; - justify-content: center; - align-items: center; - transition: opacity .5s; - background: rgba(0, 0, 0, 0.65); - opacity: 0; } - .Modal.visible { - opacity: 1; } - .Modal.hidden { - display: none; } - -.Dialog { - margin: 0.61805rem; - padding: 1rem; - overflow: hidden; - max-width: 100%; - max-height: 100%; - flex: 0 1 30rem; - background: #1c1c1e; - border-left: 6px solid #2972ba; - border-right: 6px solid #2972ba; - box-shadow: 0 0 2px 0 #434349, 0 0 6px 0 black; - border-radius: 6px; } - .Dialog h1, .Dialog h2 { - margin-top: 0; } - .Dialog p:last-child { - margin-bottom: 0; } - -/* -// "toast" -.NotifyMsg { - position: fixed; - bottom: dist(2); - padding: dist(-1) dist(0); - - // center horizontally - left: 50%; - @include translate(-50%,0); - // hack to remove blur in chrome - -webkit-font-smoothing: subpixel-antialiased; - -webkit-transform: translateZ(0) scale(1.0, 1.0); - - background: #37a349; - &.error { - background: #d03e42; - } - - color: white; - text-shadow: 0 0 2px black; - box-shadow: 0 0 6px 0 rgba(black, .6); - border-radius: 5px; - - max-width: 80%; - - @include media($phone) { - width: calc(100% - 1rem); - } - - transition: opacity .5s; - opacity: 0; - &.visible { opacity: 1 } - &.hidden { display: none } -} -*/ -html { - font-family: Arial, sans-serif; - color: #D0D0D0; - background: #131315; } - -html, body { - border: 0 none; - margin: 0; - padding: 0; - text-decoration: none; - width: 100%; - height: 100%; - overflow: hidden; } - -a, a:visited, a:link { - cursor: pointer; - color: #5abfff; - text-decoration: none; } - -a:hover { - color: #5abfff; - text-decoration: underline; } - -.Box { - display: block; - max-width: 900px; - margin-top: 1rem; - padding: 0.61805rem 1rem; - border-radius: 3px; - background-color: rgba(255, 255, 255, 0.07); } - @media screen and (max-width: 544px) { - .Box { - margin-top: 0.61805rem; - padding: 0.23608rem 0.38198rem; } } - .Box p:first-child { - margin-top: 0; } - -body { - position: relative; - padding: 1rem; - overflow-y: auto; } - @media screen and (max-width: 544px) { - body { - padding: 0.61805rem; } } - body > * { - margin-left: auto; - margin-right: auto; } - -h1, h2 { - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; } - -h1 { - text-align: center; - font-size: 2.02729em; - margin-top: 0; - margin-bottom: 1rem; } - @media screen and (max-width: 544px) { - h1 { - font-size: 1.42383em; - margin-bottom: 0.61805rem; } } - @media screen and (min-width: 545px) and (max-width: 1000px) { - h1 { - font-size: 1.80203em; } } - -h2 { - font-size: 1.26563em; - margin-bottom: 0.61805rem; } - -td, th { - padding: 0.38198rem; - white-space: nowrap; } - @media screen and (max-width: 544px) { - td, th { - padding: 0.23608rem; } } - -tbody th { - text-align: right; - width: 130px; - color: white; } - @media screen and (max-width: 544px) { - tbody th { - width: auto; } } - -tbody td input[type="text"], tbody td input[type="number"] { - width: 10em; } - @media screen and (max-width: 544px) { - tbody td input[type="text"], tbody td input[type="number"] { - width: 8em; } } - -#loader { - position: absolute; - right: 1.618rem; - top: 1.618rem; - transition: opacity .2s; - opacity: 0; } - @media screen and (max-width: 544px) { - #loader { - top: 1rem; - right: 1rem; } } - #loader.show { - opacity: 1; } - -ul > * { - padding-top: .1em; - padding-bottom: .1em; } - -#botnav { - padding-top: 1.5em; - text-align: center; } - #botnav a { - padding: 0 0.38198rem; - text-decoration: underline; } - #botnav a, #botnav a:visited, #botnav a:link { - color: #2e4d6e; } - #botnav a:hover { - color: #5abfff; } - -button, input[type=submit], .button { - text-align: center; - cursor: pointer; - display: inline-block; - border-radius: 2px; - padding: 0 0.6em; - border: 0 none; - outline: 0 none !important; - line-height: 1.8em; - font-size: 1.1em; - margin-bottom: 3px; - min-width: 5em; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - text-shadow: 1.5px 1.5px 2px rgba(0, 0, 0, 0.6); - background-color: #3983cd; - box-shadow: 0 3px 0 #265f98; - text-decoration: none !important; } - button:active, input[type=submit]:active, .button:active { - position: relative; - top: 2px; } - button.narrow, input[type=submit].narrow, .button.narrow { - min-width: initial; } - button, button:link, button:visited, input[type=submit], input[type=submit]:link, input[type=submit]:visited, .button, .button:link, .button:visited { - color: #FEFEFE; } - button:hover, button:active, button.active, button.selected, input[type=submit]:hover, input[type=submit]:active, input[type=submit].active, input[type=submit].selected, .button:hover, .button:active, .button.active, .button.selected { - background-color: #2076C6; - color: #FEFEFE; } - button:hover, button.selected, button.active, input[type=submit]:hover, input[type=submit].selected, input[type=submit].active, .button:hover, .button.selected, .button.active { - box-shadow: 0 3px 0 #154c80; } - button:active, input[type=submit]:active, .button:active { - box-shadow: 0 1px 0 #154c80; } - -button, input[type=submit], .button { - text-align: center; - cursor: pointer; - display: inline-block; - border-radius: 2px; - padding: 0 0.6em; - border: 0 none; - outline: 0 none !important; - line-height: 1.8em; - font-size: 1.1em; - margin-bottom: 3px; - min-width: 5em; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - text-shadow: 1.5px 1.5px 2px rgba(0, 0, 0, 0.6); - background-color: #3983cd; - box-shadow: 0 3px 0 #265f98; - text-decoration: none !important; } - button:active, input[type=submit]:active, .button:active { - position: relative; - top: 2px; } - button.narrow, input[type=submit].narrow, .button.narrow { - min-width: initial; } - button, button:link, button:visited, input[type=submit], input[type=submit]:link, input[type=submit]:visited, .button, .button:link, .button:visited { - color: #FEFEFE; } - button:hover, button:active, button.active, button.selected, input[type=submit]:hover, input[type=submit]:active, input[type=submit].active, input[type=submit].selected, .button:hover, .button:active, .button.active, .button.selected { - background-color: #2076C6; - color: #FEFEFE; } - button:hover, button.selected, button.active, input[type=submit]:hover, input[type=submit].selected, input[type=submit].active, .button:hover, .button.selected, .button.active { - box-shadow: 0 3px 0 #154c80; } - button:active, input[type=submit]:active, .button:active { - box-shadow: 0 1px 0 #154c80; } - -input[type="number"], input[type="password"], input[type="text"], textarea, select { - border: 0 none; - border-bottom: 2px solid #214e7a; - background-color: #303030; - color: white; - padding: 6px; - line-height: 1em; - outline: 0 none !important; - -moz-outline: 0 none !important; - font-weight: normal; } - input[type="number"]:focus, input[type="number"]:hover, input[type="password"]:focus, input[type="password"]:hover, input[type="text"]:focus, input[type="text"]:hover, textarea:focus, textarea:hover, select:focus, select:hover { - border-bottom-color: #2972ba; } - -#psk-modal form > *, #wificonfbox form > * { - margin-right: 0.38198rem; } - #psk-modal form > *:last-child, #wificonfbox form > *:last-child { - margin-right: 0; } - -#ap-list { - column-count: 3; - column-gap: 0; - margin: 0 -0.23608rem; } - @media screen and (min-width: 545px) and (max-width: 1000px) { - #ap-list { - column-count: 2; } } - @media screen and (max-width: 544px) { - #ap-list { - column-count: 1; } } - -#ap-loader, #ap-noscan { - background: rgba(255, 255, 255, 0.1); - border-radius: 5px; - padding: 0.38198rem; - margin-bottom: 0.38198rem; } - -#ap-noscan { - font-weight: bold; } - -#ap-box { - padding-bottom: 0.38198rem; } - -#psk-modal form { - display: flex; - align-items: center; - margin: 0.38198rem; } - #psk-modal form input[type=password] { - min-width: 5rem; } - -.AP { - break-inside: avoid-column; - max-width: 500px; - padding: 0.23608rem; } - .AP.selected .inner { - background: #42a6f9 !important; - cursor: default; - top: 0 !important; } - .AP .inner { - cursor: pointer; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - position: relative; - border-radius: 3px; - color: #222; - background: #afafaf; - transition: background-color 0.5s; - display: flex; } - .AP .inner:active { - left: 0; - top: 1px; } - .AP .inner:hover { - background: white; } - .AP .inner > * { - padding: 0.61805rem; - white-space: nowrap; - word-wrap: normal; } - .AP .inner .rssi { - min-width: 2.5rem; - flex: 0 0 15%; - text-align: right; } - .AP .inner .rssi:after { - padding-left: 0.09018rem; - content: '%'; - font-size: 0.88889em; } - .AP .inner .essid { - flex: 1 1 70%; - min-width: 0; - text-overflow: ellipsis; - overflow: hidden; - font-weight: bold; } - .AP .inner .auth { - flex: 0 0 15%; } - -.page-term h1 { - font-size: 1.80203em; } - @media screen and (max-width: 544px) { - .page-term h1 { - font-size: 1.42383em; } } -.page-term #screen { - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - font-family: monospace; - font-size: 16pt; - white-space: nowrap; - background: #111213; - padding: 6px; - display: inline-block; - border: 2px solid #3983CD; } - .page-term #screen span { - white-space: pre; - cursor: pointer; } - .page-term #screen span:hover { - outline: 1px solid rgba(255, 255, 255, 0.4); } - @media screen and (max-width: 544px) { - .page-term #screen span:hover { - outline: 0 none; } } - .page-term #screen .fg8, .page-term #screen .fg9, .page-term #screen .fg10, .page-term #screen .fg11, .page-term #screen .fg12, .page-term #screen .fg13, .page-term #screen .fg14, .page-term #screen .fg15 { - font-weight: bold; } -.page-term #buttons { - margin-top: 10px; - white-space: nowrap; } - .page-term #buttons button { - margin: 0 3px; - padding: 10px 0; - width: 18%; - max-width: 65px; - min-width: initial; - cursor: pointer; - font-weight: bold; } - -#termwrap { - text-align: center; } - -.page-about .Box { - padding-left: 1rem; - padding-right: 1rem; } - .page-about .Box a { - font-weight: bold; } -.page-about #logo { - float: right; - height: 130px; } -.page-about #logo2 { - max-width: 100%; } -.page-about td { - white-space: normal; } - -.colorprev { - margin-top: 0.38198rem; - margin-bottom: 0.38198rem; } - .colorprev span { - display: inline-block; - width: 2em; - padding: 0.38198rem 0; - text-align: center; } - -.ansiref, .ansiref td, .ansiref th { - border: 1px solid #666; } -.ansiref th, .ansiref td { - white-space: normal; } -.ansiref th { - background-color: rgba(255, 255, 255, 0.1); } -.ansiref td:nth-child(1) { - font-family: monospace; } -.ansiref.w100 { - width: 100%; } - .ansiref.w100 td:nth-child(1) { - width: 6em; } - .ansiref.w100 td:nth-child(2) { - width: 8em; } - -.fg0 { - color: #111213; } - -.bg0 { - background-color: #111213; } - -.fg1 { - color: #CC0000; } - -.bg1 { - background-color: #CC0000; } - -.fg2 { - color: #4E9A06; } - -.bg2 { - background-color: #4E9A06; } - -.fg3 { - color: #C4A000; } - -.bg3 { - background-color: #C4A000; } - -.fg4 { - color: #3465A4; } - -.bg4 { - background-color: #3465A4; } - -.fg5 { - color: #75507B; } - -.bg5 { - background-color: #75507B; } - -.fg6 { - color: #06989A; } - -.bg6 { - background-color: #06989A; } - -.fg7 { - color: #D3D7CF; } - -.bg7 { - background-color: #D3D7CF; } - -.fg8 { - color: #555753; } - -.bg8 { - background-color: #555753; } - -.fg9 { - color: #EF2929; } - -.bg9 { - background-color: #EF2929; } - -.fg10 { - color: #8AE234; } - -.bg10 { - background-color: #8AE234; } - -.fg11 { - color: #FCE94F; } - -.bg11 { - background-color: #FCE94F; } - -.fg12 { - color: #729FCF; } - -.bg12 { - background-color: #729FCF; } - -.fg13 { - color: #AD7FA8; } - -.bg13 { - background-color: #AD7FA8; } - -.fg14 { - color: #34E2E2; } - -.bg14 { - background-color: #34E2E2; } - -.fg15 { - color: #EEEEEC; } - -.bg15 { - background-color: #EEEEEC; } - -@media screen and (min-width: 545px) { - .mq-phone { - display: none; } } -@media screen and (max-width: 544px) { - .mq-tablet-min { - display: none; } } -@media screen and (min-width: 1001px) { - .mq-tablet-max { - display: none; } } -@media screen and (max-width: 1000px) { - .mq-normal-min { - display: none; } } diff --git a/html/favicon.ico b/html/favicon.ico deleted file mode 100644 index 6916039..0000000 Binary files a/html/favicon.ico and /dev/null differ diff --git a/html/help.tpl b/html/help.tpl deleted file mode 100644 index da76f63..0000000 --- a/html/help.tpl +++ /dev/null @@ -1,326 +0,0 @@ - - - - - Help - ESP8266 Remote Terminal - - - - - - - -

Quick Reference

- -
-

Wiring

- - -
- -
-

Screen

- - -
- -
-

Color Reference

- -

Color is set using \e[?m or \e[?;?m where "?" are numbers from the following tables:

- - Foreground - -
- 30 - 31 - 32 - 33 - 34 - 35 - 36 - 37 -
- -
- 90 - 91 - 92 - 93 - 94 - 95 - 96 - 97 -
- - Background - -
- 40 - 41 - 42 - 43 - 44 - 45 - 46 - 47 -
- -
- 100 - 101 - 102 - 103 - 104 - 105 - 106 - 107 -
- -

Bright foreground can also be set using the "bold" attribute 1 (eg. \e[31;1m). For more details, see the ANSI code reference below.

-
- -
-

User Input

- -

- All the user types on their keyboard is sent as-is to the UART, including ESC, ANSI sequences for arrow keys and CR-LF for Enter. - The input is limited to ASCII codes 32-126, backspace 8 and tab 9. -

- -

The buttons under the screen send ASCII codes 1, 2, 3, 4, 5.

- -

- Mouse input (click/tap) is sent as \e?;?M with row;column. You can use this for on-screen buttons, menu navigation etc. - Please note this is a custom sequence, not supported by PuTTY or other terminals. -

-
- -
-

Supported ANSI Escape Sequences

- -

Sequences are started by ASCII code 27 (ESC, \e, \x1b, \033)

- -

Instead of \a (BELL, ASCII 7) in the commands, you can use `\e\` (ESC + backslash). It's the Text Separator code.

- -

Text Attributes

- -

- All text attributes are set using \e[...m where the dots are numbers separated by semicolons. - You can combine up to 3 attributes in a single command. -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
AttributeMeaning
0Reset text attributes to default
7Inverse (fg/bg swap when printing)
27Inverse OFF
30-37, 90-97Foreground color, normal and bright
40-47, 100-107Background color, normal and bright
- -

Cursor

- -

Movement commands scroll the screen if needed. The coordinates are 1-based, origin top left.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CodeParamsMeaning
\e[?A[count]Move cursor up
\e[?B[count]Move cursor down
\e[?C[count]Move cursor forward (right)
\e[?D[count]Move cursor backward (left)
\e[?E[count]Go N line down, start of line
\e[?F[count]Go N lines up, start of line
\e[?GcolumnGo to column
\e[?;?G[row=1];[col=1]Go to row and column
\e[6n--Query cursor position. Position is sent back as \e[?;?R with row;column.
\e[s--Store position
\e[u--Restore position
\e7--Store position & attributes
\e8--Restore position & attributes
\e[?25l--Hide cursor (literal question mark, lowercase L!)
\e[?25h--Show cursor (literal question mark!)
- -

Screen

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CodeParamsMeaning
\e[?J[mode=0]Clear screen. Mode: 0 - from cursor, 1 - to cursor, 2 - all
\e[?K[mode=0]Erase line. Mode: 0 - from cursor, 1 - to cursor, 2 - all
\e[?S[lines]Scroll screen content up, add empty line at the bottom
\e[?T[lines]Scroll screen content down, add empty line at the top
\e]W?;?\arows;colsSet screen size, maximum 25x80 (resp. total 2000 characters). This also clears the screen.
- -

System Commands

- - - - - - - - - - - - - - - - - - - - - - - - - - -
CodeParamsMeaning
\ec-- - "Device Reset" - clear screen, reset attributes, show cursor & move it to 1,1. - The screen size and WiFi settings stay unchanged. -
\e]FR\a--"Factory Reset", emergency code when you mess up the WiFi, restores SSID to unique default, clears stored credentials & enters Client+AP mode.
\e[5n--Query device status, replies with \e[0n "device is OK". Can be used to check if the UART works.
-
- - - - - diff --git a/html/img/cvut.svg b/html/img/cvut.svg deleted file mode 100755 index dc015d3..0000000 --- a/html/img/cvut.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/html/img/loader.gif b/html/img/loader.gif deleted file mode 100755 index dfb5362..0000000 Binary files a/html/img/loader.gif and /dev/null differ diff --git a/html/js/app.js b/html/js/app.js deleted file mode 100644 index 675b54a..0000000 --- a/html/js/app.js +++ /dev/null @@ -1,1390 +0,0 @@ -/*!chibi 3.0.7, Copyright 2012-2016 Kyle Barrow, released under MIT license */ - -// MODIFIED VERSION. -(function () { - 'use strict'; - - var readyfn = [], - loadedfn = [], - domready = false, - pageloaded = false, - d = document, - w = window; - - // Fire any function calls on ready event - function fireReady() { - var i; - domready = true; - for (i = 0; i < readyfn.length; i += 1) { - readyfn[i](); - } - readyfn = []; - } - - // Fire any function calls on loaded event - function fireLoaded() { - var i; - pageloaded = true; - // For browsers with no DOM loaded support - if (!domready) { - fireReady(); - } - for (i = 0; i < loadedfn.length; i += 1) { - loadedfn[i](); - } - loadedfn = []; - } - - // Check DOM ready, page loaded - if (d.addEventListener) { - // Standards - d.addEventListener('DOMContentLoaded', fireReady, false); - w.addEventListener('load', fireLoaded, false); - } else if (d.attachEvent) { - // IE - d.attachEvent('onreadystatechange', fireReady); - // IE < 9 - w.attachEvent('onload', fireLoaded); - } else { - // Anything else - w.onload = fireLoaded; - } - - // Utility functions - - // Loop through node array - function nodeLoop(fn, nodes) { - var i; - // Good idea to walk up the DOM - for (i = nodes.length - 1; i >= 0; i -= 1) { - fn(nodes[i]); - } - } - - // Convert to camel case - function cssCamel(property) { - return property.replace(/-\w/g, function (result) { - return result.charAt(1).toUpperCase(); - }); - } - - // Get computed style - function computeStyle(elm, property) { - // IE, everything else or null - return (elm.currentStyle) ? elm.currentStyle[cssCamel(property)] : (w.getComputedStyle) ? w.getComputedStyle(elm, null).getPropertyValue(property) : null; - - } - - // Returns URI encoded query string pair - function queryPair(name, value) { - return encodeURIComponent(name).replace(/%20/g, '+') + '=' + encodeURIComponent(value).replace(/%20/g, '+'); - } - - // Set CSS, important to wrap in try to prevent error thown on unsupported property - function setCss(elm, property, value) { - try { - elm.style[cssCamel(property)] = value; - } catch (e) { - } - } - - // Show CSS - function showCss(elm) { - elm.style.display = ''; - // For elements still hidden by style block - if (computeStyle(elm, 'display') === 'none') { - elm.style.display = 'block'; - } - } - - // Serialize form & JSON values - function serializeData(nodes) { - var querystring = '', subelm, i, j; - if (nodes.constructor === Object) { // Serialize JSON data - for (subelm in nodes) { - if (nodes.hasOwnProperty(subelm)) { - if (nodes[subelm].constructor === Array) { - for (i = 0; i < nodes[subelm].length; i += 1) { - querystring += '&' + queryPair(subelm, nodes[subelm][i]); - } - } else { - querystring += '&' + queryPair(subelm, nodes[subelm]); - } - } - } - } else { // Serialize node data - nodeLoop(function (elm) { - if (elm.nodeName === 'FORM') { - for (i = 0; i < elm.elements.length; i += 1) { - subelm = elm.elements[i]; - - if (!subelm.disabled) { - switch (subelm.type) { - // Ignore buttons, unsupported XHR 1 form fields - case 'button': - case 'image': - case 'file': - case 'submit': - case 'reset': - break; - - case 'select-one': - if (subelm.length > 0) { - querystring += '&' + queryPair(subelm.name, subelm.value); - } - break; - - case 'select-multiple': - for (j = 0; j < subelm.length; j += 1) { - if (subelm[j].selected) { - querystring += '&' + queryPair(subelm.name, subelm[j].value); - } - } - break; - - case 'checkbox': - case 'radio': - if (subelm.checked) { - querystring += '&' + queryPair(subelm.name, subelm.value); - } - break; - - // Everything else including shinny new HTML5 input types - default: - querystring += '&' + queryPair(subelm.name, subelm.value); - } - } - } - } - }, nodes); - } - // Tidy up first & - return (querystring.length > 0) ? querystring.substring(1) : ''; - } - - // Class helper - function classHelper(classes, action, nodes) { - var classarray, search, i, replace, has = false; - if (classes) { - // Trim any whitespace - classarray = classes.split(/\s+/); - nodeLoop(function (elm) { - for (i = 0; i < classarray.length; i += 1) { - var clz = classarray[i]; - if (action === 'remove') { - elm.classList.remove(clz); - } - else if (action === 'add') { - elm.classList.add(clz); - } - else if (action === 'toggle') { - elm.classList.toggle(clz); - } - else if (action === 'has') { - if (elm.classList.contains(clz)) { - has = true; - break; - } - } - - // search = new RegExp('\\b' + classarray[i] + '\\b', 'g'); - // replace = new RegExp(' *' + classarray[i] + '\\b', 'g'); - // if (action === 'remove') { - // elm.className = elm.className.replace(search, ''); - // } else if (action === 'toggle') { - // elm.className = (elm.className.match(search)) ? elm.className.replace(replace, '') : elm.className + ' ' + classarray[i]; - // } else if (action === 'has') { - // if (elm.className.match(search)) { - // has = true; - // break; - // } - // } - } - }, nodes); - } - return has; - } - - // HTML insertion helper - function insertHtml(value, position, nodes) { - var tmpnodes, tmpnode; - if (value) { - nodeLoop(function (elm) { - // No insertAdjacentHTML support for FF < 8 and IE doesn't allow insertAdjacentHTML table manipulation, so use this instead - // Convert string to node. We can't innerHTML on a document fragment - tmpnodes = d.createElement('div'); - tmpnodes.innerHTML = value; - while ((tmpnode = tmpnodes.lastChild) !== null) { - // Catch error in unlikely case elm has been removed - try { - if (position === 'before') { - elm.parentNode.insertBefore(tmpnode, elm); - } else if (position === 'after') { - elm.parentNode.insertBefore(tmpnode, elm.nextSibling); - } else if (position === 'append') { - elm.appendChild(tmpnode); - } else if (position === 'prepend') { - elm.insertBefore(tmpnode, elm.firstChild); - } - } catch (e) { - break; - } - } - }, nodes); - } - } - - // Get nodes and return chibi - function chibi(selector) { - var cb, nodes = [], json = false, nodelist, i; - - if (selector) { - - // Element node, would prefer to use (selector instanceof HTMLElement) but no IE support - if (selector.nodeType && selector.nodeType === 1) { - nodes = [selector]; // return element as node list - } else if (typeof selector === 'object') { - // JSON, document object or node list, would prefer to use (selector instanceof NodeList) but no IE support - json = (typeof selector.length !== 'number'); - nodes = selector; - } else if (typeof selector === 'string') { - nodelist = d.querySelectorAll(selector); - - // Convert node list to array so results have full access to array methods - // Array.prototype.slice.call not supported in IE < 9 and often slower than loop anyway - for (i = 0; i < nodelist.length; i += 1) { - nodes[i] = nodelist[i]; - } - } - } - - // Only attach nodes if not JSON - cb = json ? {} : nodes; - - // Public functions - - // Executes a function on nodes - cb.each = function (fn) { - if (typeof fn === 'function') { - nodeLoop(function (elm) { - // <= IE 8 loses scope so need to apply - return fn.apply(elm, arguments); - }, nodes); - } - return cb; - }; - // Find first - cb.first = function () { - return chibi(nodes.shift()); - }; - // Find last - cb.last = function () { - return chibi(nodes.pop()); - }; - // Find odd - cb.odd = function () { - var odds = [], i; - for (i = 0; i < nodes.length; i += 2) { - odds.push(nodes[i]); - } - return chibi(odds); - }; - // Find even - cb.even = function () { - var evens = [], i; - for (i = 1; i < nodes.length; i += 2) { - evens.push(nodes[i]); - } - return chibi(evens); - }; - // Hide node - cb.hide = function () { - nodeLoop(function (elm) { - elm.style.display = 'none'; - }, nodes); - return cb; - }; - // Show node - cb.show = function () { - nodeLoop(function (elm) { - showCss(elm); - }, nodes); - return cb; - }; - // Toggle node display - cb.toggle = function (state) { - if (typeof state != 'undefined') { // ADDED - if (state) - cb.show(); - else - cb.hide(); - } else { - nodeLoop(function (elm) { - // computeStyle instead of style.display == 'none' catches elements that are hidden via style block - if (computeStyle(elm, 'display') === 'none') { - showCss(elm); - } else { - elm.style.display = 'none'; - } - - }, nodes); - } - return cb; - }; - // Remove node - cb.remove = function () { - nodeLoop(function (elm) { - // Catch error in unlikely case elm has been removed - try { - elm.parentNode.removeChild(elm); - } catch (e) { - } - }, nodes); - return chibi(); - }; - // Get/Set CSS - cb.css = function (property, value) { - if (property) { - if (value || value === '') { - nodeLoop(function (elm) { - setCss(elm, property, value); - }, nodes); - return cb; - } - if (nodes[0]) { - if (nodes[0].style[cssCamel(property)]) { - return nodes[0].style[cssCamel(property)]; - } - if (computeStyle(nodes[0], property)) { - return computeStyle(nodes[0], property); - } - } - } - }; - // Get class(es) - cb.getClass = function () { - if (nodes[0] && nodes[0].className.length > 0) { - // Weak IE trim support - return nodes[0].className.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '').replace(/\s+/, ' '); - } - }; - // Set (replaces) classes - cb.setClass = function (classes) { - if (classes || classes === '') { - nodeLoop(function (elm) { - elm.className = classes; - }, nodes); - } - return cb; - }; - // Add class - cb.addClass = function (classes) { - classHelper(classes, 'add', nodes); - // if (classes) { - // nodeLoop(function (elm) { - // elm.className += ' ' + classes; - // }, nodes); - // } - return cb; - }; - // Remove class - cb.removeClass = function (classes) { - classHelper(classes, 'remove', nodes); - return cb; - }; - // Toggle class - cb.toggleClass = function (classes) { - classHelper(classes, 'toggle', nodes); - return cb; - }; - // Has class - cb.hasClass = function (classes) { - return classHelper(classes, 'has', nodes); - }; - // Get/set HTML - cb.html = function (value) { - if (value || value === '') { - nodeLoop(function (elm) { - elm.innerHTML = value; - }, nodes); - return cb; - } - if (nodes[0]) { - return nodes[0].innerHTML; - } - }; - // Insert HTML before selector - cb.htmlBefore = function (value) { - insertHtml(value, 'before', nodes); - return cb; - }; - // Insert HTML after selector - cb.htmlAfter = function (value) { - insertHtml(value, 'after', nodes); - return cb; - }; - // Insert HTML after selector innerHTML - cb.htmlAppend = function (value) { - insertHtml(value, 'append', nodes); - return cb; - }; - // Insert HTML before selector innerHTML - cb.htmlPrepend = function (value) { - insertHtml(value, 'prepend', nodes); - return cb; - }; - // Get/Set HTML attributes - cb.attr = function (property, value) { - if (property) { - property = property.toLowerCase(); - // IE < 9 doesn't allow style or class via get/setAttribute so switch. cssText returns prettier CSS anyway - if (typeof value !== 'undefined') {//FIXED BUG HERE - nodeLoop(function (elm) { - if (property === 'style') { - elm.style.cssText = value; - } else if (property === 'class') { - elm.className = value; - } else { - elm.setAttribute(property, value); - } - }, nodes); - return cb; - } - if (nodes[0]) { - if (property === 'style') { - if (nodes[0].style.cssText) { - return nodes[0].style.cssText; - } - } else if (property === 'class') { - if (nodes[0].className) { - return nodes[0].className; - } - } else { - if (nodes[0].getAttribute(property)) { - return nodes[0].getAttribute(property); - } - } - } - } - }; - // Get/Set HTML data property - cb.data = function (key, value) { - if (key) { - return cb.attr('data-' + key, value); - } - }; - // Get/Set form element values - cb.val = function (value) { - var values, i, j; - if (typeof value != 'undefined') { // FIXED A BUG HERE - nodeLoop(function (elm) { - switch (elm.nodeName) { - case 'SELECT': - if (typeof value === 'string' || typeof value === 'number') { - value = [value]; - } - for (i = 0; i < elm.length; i += 1) { - // Multiple select - for (j = 0; j < value.length; j += 1) { - elm[i].selected = ''; - if (elm[i].value === value[j]) { - elm[i].selected = 'selected'; - break; - } - } - } - break; - case 'INPUT': - case 'TEXTAREA': - case 'BUTTON': - elm.value = value; - break; - } - }, nodes); - - return cb; - } - if (nodes[0]) { - switch (nodes[0].nodeName) { - case 'SELECT': - values = []; - for (i = 0; i < nodes[0].length; i += 1) { - if (nodes[0][i].selected) { - values.push(nodes[0][i].value); - } - } - return (values.length > 1) ? values : values[0]; - case 'INPUT': - case 'TEXTAREA': - case 'BUTTON': - return nodes[0].value; - } - } - }; - // Return matching checked checkbox or radios - cb.checked = function (check) { - if (typeof check === 'boolean') { - nodeLoop(function (elm) { - if (elm.nodeName === 'INPUT' && (elm.type === 'checkbox' || elm.type === 'radio')) { - elm.checked = check; - } - }, nodes); - return cb; - } - if (nodes[0] && nodes[0].nodeName === 'INPUT' && (nodes[0].type === 'checkbox' || nodes[0].type === 'radio')) { - return (!!nodes[0].checked); - } - }; - // Add event handler - cb.on = function (event, fn) { - if (selector === w || selector === d) { - nodes = [selector]; - } - nodeLoop(function (elm) { - if (d.addEventListener) { - elm.addEventListener(event, fn, false); - } else if (d.attachEvent) { - // <= IE 8 loses scope so need to apply, we add this to object so we can detach later (can't detach anonymous functions) - elm[event + fn] = function () { - return fn.apply(elm, arguments); - }; - elm.attachEvent('on' + event, elm[event + fn]); - } - }, nodes); - return cb; - }; - // Remove event handler - cb.off = function (event, fn) { - if (selector === w || selector === d) { - nodes = [selector]; - } - nodeLoop(function (elm) { - if (d.addEventListener) { - elm.removeEventListener(event, fn, false); - } else if (d.attachEvent) { - elm.detachEvent('on' + event, elm[event + fn]); - // Tidy up - elm[event + fn] = null; - } - }, nodes); - return cb; - }; - return cb; - } - - // Basic XHR - chibi.ajax = function (options) { // if options is a number, it's timeout in ms - var opts = extend({ - method: 'GET', - nocache: true, - timeout: 5000, - loader: true, - callback: null - }, options); - opts.method = opts.method.toUpperCase(); - - var loaderFn = opts.loader ? chibi._loader : function(){}; - var url = opts.url; - var method = opts.method; - var query = null; - - if (opts.data) { - query = serializeData(opts.data); - } - - if (query && (method === 'GET')) { - url += (url.indexOf('?') === -1) ? '?' + query : '&' + query; - query = null; - } - - var xhr = new XMLHttpRequest(); - - // prevent caching - if (opts.nocache) { - var ts = (+(new Date())).toString(36); - url += ((url.indexOf('?') === -1) ? '?' : '&') + '_=' + ts; - } - - loaderFn(true); - - xhr.open(method, url, true); - xhr.timeout = opts.timeout; - - // Abort after given timeout - var abortTmeo = setTimeout(function () { - console.error("XHR timed out."); - xhr.abort(); - loaderFn(false); - }, opts.timeout + 10); - - xhr.onreadystatechange = function () { - if (xhr.readyState === 4) { - loaderFn(false); - - opts.callback && opts.callback(xhr.responseText, xhr.status); - - clearTimeout(abortTmeo); - } - }; - - xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); - if (method === 'POST') { - xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); - } - - xhr.send(query); - return xhr; - }; - - chibi._loader = function(){}; - - // Alias to cb.ajax(url, 'get', callback) - chibi.get = function (url, callback, opts) { - opts = opts || {}; - opts.url = url; - opts.callback = callback; - opts.method = 'GET'; - return chibi.ajax(opts); - }; - - // Alias to cb.ajax(url, 'post', callback) - chibi.post = function (url, callback, opts) { - opts = opts || {}; - opts.url = url; - opts.callback = callback; - opts.method = 'POST'; - return chibi.ajax(opts); - }; - - // Fire on DOM ready - chibi.ready = function (fn) { - if (fn) { - if (domready) { - fn(); - return chibi; - } else { - readyfn.push(fn); - } - } - }; - - // Fire on page loaded - chibi.loaded = function (fn) { - if (fn) { - if (pageloaded) { - fn(); - return chibi; - } else { - loadedfn.push(fn); - } - } - }; - - var entityMap = { - '&': '&', - '<': '<', - '>': '>', - '"': '"', - "'": ''', - '/': '/', - '`': '`', - '=': '=' - }; - - chibi.htmlEscape = function(string) { - return String(string).replace(/[&<>"'`=\/]/g, function (s) { - return entityMap[s]; - }); - }; - - // Set Chibi's global namespace here ($) - w.$ = chibi; -}()); -/** Make a node */ -function mk(e) {return document.createElement(e)} - -/** Find one by query */ -function qq(s) {return document.querySelector(s)} - -/** Find all by query */ -function qa(s) {return document.querySelectorAll(s)} - -/** Convert any to bool safely */ -function bool(x) { - return (x === 1 || x === '1' || x === true || x === 'true'); -} - -function intval(x) { - return parseInt(x); -} - -/** Extend an objects with options */ -function extend(defaults, options) { - var target = {}; - - Object.keys(defaults).forEach(function(k){ - target[k] = defaults[k]; - }); - - Object.keys(options).forEach(function(k){ - target[k] = options[k]; - }); - - return target; -} - -/** Escape string for use as literal in RegExp */ -function rgxe(str) { - return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); -} - -function numfmt(x, places) { - var pow = Math.pow(10, places); - return Math.round(x*pow) / pow; -} - -function estimateLoadTime(fs, n) { - return (1000/fs)*n+1500; -} - -function msNow() { - return +(new Date); -} - -function msElapsed(start) { - return msNow() - start; -} - -Math.log10 = Math.log10 || function(x) { - return Math.log(x) / Math.LN10; -}; - -/** - * Perform a substitution in the given string. - * - * Arguments - array or list of replacements. - * Arguments numeric keys will replace {0}, {1} etc. - * Named keys also work, ie. {foo: "bar"} -> replaces {foo} with bar. - * - * Braces are added to keys if missing. - * - * @returns {String} result - */ -String.prototype.format = function () { - var out = this; - var repl = arguments; - - if (arguments.length == 1 && (Array.isArray(arguments[0]) || typeof arguments[0] == 'object')) { - repl = arguments[0]; - } - - for (var ph in repl) { - if (repl.hasOwnProperty(ph)) { - var ph_orig = ph; - - if (!ph.match(/^\{.*\}$/)) { - ph = '{' + ph + '}'; - } - - // replace all occurrences - var pattern = new RegExp(rgxe(ph), "g"); - out = out.replace(pattern, repl[ph_orig]); - } - } - - return out; -}; - -/** Module for toggling a modal overlay */ -(function () { - var modal = {}; - - modal.show = function (sel) { - var $m = $(sel); - $m.removeClass('hidden visible'); - setTimeout(function () { - $m.addClass('visible'); - }, 1); - }; - - modal.hide = function (sel) { - var $m = $(sel); - $m.removeClass('visible'); - setTimeout(function () { - $m.addClass('hidden'); - }, 500); // transition time - }; - - modal.init = function () { - // close modal by click outside the dialog - $('.Modal').on('click', function () { - if ($(this).hasClass('no-close')) return; // this is a no-close modal - modal.hide(this); - }); - - $('.Dialog').on('click', function (e) { - e.stopImmediatePropagation(); - }); - - // Hide all modals on esc - $(window).on('keydown', function (e) { - if (e.which == 27) { - modal.hide('.Modal'); - } - }); - }; - - window.Modal = modal; -})(); -/** Global generic init */ -$.ready(function () { - // loader dots... - setInterval(function () { - $('.anim-dots').each(function (x) { - var $x = $(x); - var dots = $x.html() + '.'; - if (dots.length == 5) dots = '.'; - $x.html(dots); - }); - }, 1000); - - // flipping number boxes with the mouse wheel - $('input[type=number]').on('mousewheel', function(e) { - var val = +$(this).val(); - if (isNaN(val)) val = 1; - - var step = +($(this).attr('step') || 1); - var min = +$(this).attr('min'); - var max = +$(this).attr('max'); - if(e.wheelDelta > 0) { - val += step; - } else { - val -= step; - } - - if (typeof min != 'undefined') val = Math.max(val, +min); - if (typeof max != 'undefined') val = Math.min(val, +max); - $(this).val(val); - - if ("createEvent" in document) { - var evt = document.createEvent("HTMLEvents"); - evt.initEvent("change", false, true); - $(this)[0].dispatchEvent(evt); - } else { - $(this)[0].fireEvent("onchange"); - } - - e.preventDefault(); - }); - - Modal.init(); -}); - -$._loader = function(vis) { - if(vis) - $('#loader').addClass('show'); - else - $('#loader').removeClass('show'); -}; -(function() { - /** - * Terminal module - */ - var Term = (function () { - var W, H; - var cursor = {a: false, x: 0, y: 0, suppress: false, hidden: false}; - var screen = []; - var blinkIval; - - /** Colors table */ - var CLR = [// dark gray #2E3436 - // 0 black, 1 red, 2 green, 3 yellow - // 4 blue, 5 mag, 6 cyan, 7 white - '#111213','#CC0000','#4E9A06','#C4A000', - '#3465A4','#75507B','#06989A','#D3D7CF', - // BRIGHT - // 8 black, 9 red, 10 green, 11 yellow - // 12 blue, 13 mag, 14 cyan, 15 white - '#555753','#EF2929','#8AE234','#FCE94F', - '#729FCF','#AD7FA8','#34E2E2','#EEEEEC' - ]; - - /** Clear screen */ - function cls() { - screen.forEach(function(cell, i) { - cell.t = ' '; - cell.fg = 7; - cell.bg = 0; - blit(cell); - }); - } - - /** Set text and color at XY */ - function cellAt(y, x) { - return screen[y*W+x]; - } - - /** Get cell under cursor */ - function cursorCell() { - return cellAt(cursor.y, cursor.x); - } - - /** Enable or disable cursor visibility */ - function cursorEnable(enable) { - cursor.hidden = !enable; - cursor.a &= enable; - blit(cursorCell(), cursor.a); - } - - /** Safely move cursor */ - function cursorSet(y, x) { - // Hide and prevent from showing up during the move - cursor.suppress = true; - blit(cursorCell(), false); - - cursor.x = x; - cursor.y = y; - - // Show again - cursor.suppress = false; - blit(cursorCell(), cursor.a); - } - - /** Update cell on display. inv = invert (for cursor) */ - function blit(cell, inv) { - var e = cell.e, fg, bg; - // Colors - fg = inv ? cell.bg : cell.fg; - bg = inv ? cell.fg : cell.bg; - // Update - e.innerText = (cell.t+' ')[0]; - e.classList.className = 'fg'+fg+' bg'+bg; - // e.style.color = colorHex(fg); - // e.style.backgroundColor = colorHex(bg); - // e.style.fontWeight = fg > 7 ? 'bold' : 'normal'; - } - - /** Show entire screen */ - function blitAll() { - screen.forEach(function(cell, i) { - /* Invert if under cursor & cursor active */ - var inv = cursor.a && (i == cursor.y*W+cursor.x); - blit(cell, inv); - }); - } - - /** Load screen content from a 'binary' sequence */ - function load(obj) { - cursor.x = obj.x; - cursor.y = obj.y; - cursor.hidden = !obj.cv; - - // full re-init if size changed - if (obj.w != W || obj.h != H) { - Term.init(obj); - return; - } - - // Simple compression - hexFG hexBG 'ASCII' (r/s/t/u NUM{1,2,3,4})? - // comma instead of both colors = same as before - - var i = 0, ci = 0, str = obj.screen; - var fg = 7, bg = 0; - while(i < str.length && ci 0) { - var rep = parseInt(str.substr(i+1,repchars)); - i = i + repchars + 1; - for (; rep>0 && ci 15) c = 0; - return CLR[c]; - } - - /** Init the terminal */ - function init(obj) { - W = obj.w; - H = obj.h; - - /* Build screen & show */ - var e, cell, scr = qq('#screen'); - - // Empty the screen node - while (scr.firstChild) scr.removeChild(scr.firstChild); - - screen = []; - - for(var i = 0; i < W*H; i++) { - e = mk('span'); - - (function() { - var x = i % W; - var y = Math.floor(i / W); - e.addEventListener('click', function () { - Input.onTap(y, x); - }); - })(); - - /* End of line */ - if ((i > 0) && (i % W == 0)) { - scr.appendChild(mk('br')); - } - /* The cell */ - scr.appendChild(e); - - cell = {t: ' ', fg: 7, bg: 0, e: e}; - screen.push(cell); - blit(cell); - } - - /* Cursor blinking */ - clearInterval(blinkIval); - blinkIval = setInterval(function() { - cursor.a = !cursor.a; - if (cursor.hidden) { - cursor.a = false; - } - - if (!cursor.suppress) { - blit(cursorCell(), cursor.a); - } - }, 500); - - load(obj); - } - - // publish - return { - init: init, - load: load - }; - })(); - - /** Handle connections */ - var Conn = (function() { - var ws; - - function onOpen(evt) { - console.log("CONNECTED"); - } - - function onClose(evt) { - console.error("SOCKET CLOSED"); - } - - function onMessage(evt) { - try { - console.log("RX: ", evt.data); - // Assume all our messages are screen updates - Term.load(JSON.parse(evt.data)); - } catch(e) { - console.error(e); - } - } - - function onError(evt) { - console.error(evt.data); - } - - function doSend(message) { - console.log("TX: ", message); - if (ws.readyState != 1) { - console.error("Socket not ready"); - return; - } - if (typeof message != "string") { - message = JSON.stringify(message); - } - ws.send(message); - } - - function init() { - ws = new WebSocket("ws://"+_root+"/ws/update.cgi"); - ws.onopen = onOpen; - ws.onclose = onClose; - ws.onmessage = onMessage; - ws.onerror = onError; - - console.log("Opening socket."); - } - - return { - ws: null, - init: init, - send: doSend - }; - })(); - - // - // Keyboard (& mouse) input - // - var Input = (function() { - function sendStrMsg(str) { - Conn.send("STR:"+str); - } - - function sendPosMsg(y, x) { - Conn.send("TAP:"+y+','+x); - } - - function sendBtnMsg(n) { - Conn.send("BTN:"+n); - } - - function init() { - window.addEventListener('keypress', function(e) { - var code = +e.which; - if (code >= 32 && code < 127) { - var ch = String.fromCharCode(code); - //console.log("Typed ", ch, "code", code, e); - sendStrMsg(ch); - } - }); - - window.addEventListener('keydown', function(e) { - var code = e.keyCode; - //console.log("Down ", code, e); - switch(code) { - case 8: sendStrMsg('\x08'); break; - case 13: sendStrMsg('\x0d\x0a'); break; - case 27: sendStrMsg('\x1b'); break; // this allows to directly enter control sequences - case 37: sendStrMsg('\x1b[D'); break; - case 38: sendStrMsg('\x1b[A'); break; - case 39: sendStrMsg('\x1b[C'); break; - case 40: sendStrMsg('\x1b[B'); break; - } - }); - - qa('#buttons button').forEach(function(s) { - s.addEventListener('click', function() { - sendBtnMsg(+this.dataset['n']); - }); - }); - } - - return { - init: init, - onTap: sendPosMsg - }; - })(); - - - window.termInit = function (obj) { - Term.init(obj); - Conn.init(); - Input.init(); - } -})(); -/** Wifi page */ -(function () { - var authStr = ['Open', 'WEP', 'WPA', 'WPA2', 'WPA/WPA2']; - var curSSID; - - /** Update display for received response */ - function onScan(resp, status) { - if (status != 200) { - // bad response - rescan(5000); // wait 5sm then retry - return; - } - - resp = JSON.parse(resp); - - var done = !bool(resp.result.inProgress) && (resp.result.APs.length > 0); - rescan(done ? 15000 : 1000); - if (!done) return; // no redraw yet - - // clear the AP list - var $list = $('#ap-list'); - // remove old APs - $('.AP').remove(); - - $list.toggle(done); - $('#ap-loader').toggle(!done); - - // scan done - resp.result.APs.sort(function (a, b) { - return b.rssi - a.rssi; - }).forEach(function (ap) { - ap.enc = intval(ap.enc); - - if (ap.enc > 4) return; // hide unsupported auths - - var item = document.createElement('div'); - - var $item = $(item) - .data('ssid', ap.essid) - .data('pwd', ap.enc != 0) - .addClass('AP'); - - // mark current SSID - if (ap.essid == curSSID) { - $item.addClass('selected'); - } - - var inner = document.createElement('div'); - $(inner).addClass('inner') - .htmlAppend('
{0}
'.format(ap.rssi_perc)) - .htmlAppend('
{0}
'.format($.htmlEscape(ap.essid))) - .htmlAppend('
{0}
'.format(authStr[ap.enc])); - - $item.on('click', function () { - var $th = $(this); - - // populate the form - $('#conn-essid').val($th.data('ssid')); - $('#conn-passwd').val(''); // clear - - if ($th.data('pwd')) { - // this AP needs a password - Modal.show('#psk-modal'); - } else { - Modal.show('#reset-modal'); - $('#conn-form').submit(); - } - }); - - - item.appendChild(inner); - $list[0].appendChild(item); - }); - } - - /** Ask the CGI what APs are visible (async) */ - function scanAPs() { - $.get('http://'+_root+'/wifi/scan', onScan); - } - - function rescan(time) { - setTimeout(scanAPs, time); - } - - /** Set up the WiFi page */ - window.wifiInit = function (obj) { - //var ap_json = { - // "result": { - // "inProgress": "0", - // "APs": [ - // {"essid": "Chlivek", "bssid": "88:f7:c7:52:b3:99", "rssi": "204", "enc": "4", "channel": "1"}, - // {"essid": "TyNikdy", "bssid": "5c:f4:ab:0d:f1:1b", "rssi": "164", "enc": "3", "channel": "1"}, - // ] - // } - //}; - - // Hide what should be hidden in this mode - $('.x-hide-'+obj.mode).addClass('hidden'); - obj.mode = +obj.mode; - - // Channel writable only in AP mode - if (obj.mode != 2) $('#channel').attr('readonly', 1); - - curSSID = obj.staSSID; - - // add SSID to the opmode field - if (curSSID) { - var box = $('#opmodebox'); - box.html(box.html() + ' (' + curSSID + ')'); - } - - // hide IP if IP not received - if (!obj.staIP) $('.x-hide-noip').addClass('hidden'); - - // scan if not AP - if (obj.mode != 2) { - scanAPs(); - } - - $('#modeswitch').html([ - 'Client+AP AP only', - 'Client+AP', - 'Client only AP only' - ][obj.mode-1]); - }; - - window.wifiConn = function () { - var xhr = new XMLHttpRequest(); - var abortTmeo; - - function getStatus() { - xhr.open("GET", 'http://'+_root+"/wifi/connstatus"); - xhr.onreadystatechange = function () { - if (xhr.readyState == 4 && xhr.status >= 200 && xhr.status < 300) { - clearTimeout(abortTmeo); - var data = JSON.parse(xhr.responseText); - var done = false; - var msg = '...'; - - if (data.status == "idle") { - msg = "Preparing to connect"; - } - else if (data.status == "success") { - msg = "Connected! Received IP " + data.ip + "."; - done = true; - } - else if (data.status == "working") { - msg = "Connecting to selected AP"; - } - else if (data.status == "fail") { - msg = "Connection failed, check your password and try again."; - done = true; - } - - $("#status").html(msg); - - if (done) { - $('#backbtn').removeClass('hidden'); - $('.anim-dots').addClass('hidden'); - } else { - window.setTimeout(getStatus, 1000); - } - } - }; - - abortTmeo = setTimeout(function () { - xhr.abort(); - $("#status").html("Telemetry lost, try reconnecting to the AP."); - $('#backbtn').removeClass('hidden'); - $('.anim-dots').addClass('hidden'); - }, 4000); - - xhr.send(); - } - - getStatus(); - }; -})(); diff --git a/html/term.tpl b/html/term.tpl deleted file mode 100644 index a6fc06a..0000000 --- a/html/term.tpl +++ /dev/null @@ -1,39 +0,0 @@ - - - - - ESP8266 Remote Terminal - - - - - - - -

ESP8266 Remote Terminal

- -
-
- -
- -
-
- - - - - - - diff --git a/html/wifi.tpl b/html/wifi.tpl deleted file mode 100644 index bc98d63..0000000 --- a/html/wifi.tpl +++ /dev/null @@ -1,89 +0,0 @@ - - - - - - - WiFi Settings - ESP8266 Remote Terminal - - - - - - -Loading… - -

WiFi settings

- -
- - - - - - - - - - - - - - - - - - - - - - -
WiFi mode%WiFiMode%
IP%StaIP%
Switch to
-
- -
-
-
- -
-
-

Some changes require a reboot, dropping connection. It can take a while to re-connect.

-

- If you lose access, connect GPIO0 to GND for 5 seconds to enter Client+AP mode. - If that fails, try the UART factory reset command "\e]FR\a". -

-

-
- -
-

Select AP to join

-
Scanning.
-
Can't scan in AP-only mode.
- -
- - - - - - - - diff --git a/html/wifi_conn.tpl b/html/wifi_conn.tpl deleted file mode 100755 index a9448dc..0000000 --- a/html/wifi_conn.tpl +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - Connecting… - - - - - - -

Connecting to network

- -
-

Status:
.

- -
- - - -