Compare commits

..
56 Commits
Author SHA1 Message Date
MightyPork c5670c09bb update frontend ref 2017-10-08 12:57:36 +02:00
MightyPork 4e74d1cd79 updated front-end ref 2017-10-08 12:54:26 +02:00
MightyPork 4c8360dbb5 Merge remote-tracking branch 'origin/work' 2017-10-08 12:35:21 +02:00
MightyPork c0adc253b4 add cgi for setting background image 2017-10-08 12:34:50 +02:00
MightyPork be3e06aac1 version bump 2017-10-08 11:21:11 +02:00
MightyPork 992c927490 Merge remote-tracking branch 'origin/work' 2017-10-08 11:16:44 +02:00
MightyPork ef3b02e68c added new chars to cp 1 2017-10-07 00:46:19 +02:00
MightyPork 1c556457c7 Merge branch 'new-codepages' into work 2017-10-07 00:15:34 +02:00
MightyPork e49a8b0adf added codepages 2 and 3 2017-10-06 23:25:01 +02:00
MightyPork 81c3e426e7 added quarter blocks to codepage 1 2017-10-06 22:28:36 +02:00
MightyPorkandGitHub c90de79a34 Update README.md 2017-10-06 00:12:28 +02:00
MightyPork df404f5f63 2.1.1 - patched cslang 2017-10-04 21:47:32 +02:00
MightyPork 00153656f1 flip front-end back to "work" 2017-10-04 00:22:08 +02:00
MightyPork aa920aee27 Merge branch 'master' into work 2017-10-04 00:21:45 +02:00
MightyPork 7b8c936559 Version bump 2017-10-04 00:13:14 +02:00
MightyPork 17c18ed1c9 update front-end to latest master 2017-10-04 00:12:47 +02:00
MightyPork 274e3b359b Merge branch 'work' 2017-10-04 00:11:26 +02:00
MightyPork 73c98eb2d1 some logging adjustments 2017-10-04 00:10:54 +02:00
MightyPork 022e882001 added IP to answerback message 2017-10-03 22:16:07 +02:00
MightyPork dc08512397 one timezone is probably enough in the release readme 2017-10-03 20:58:00 +02:00
MightyPork 6c1ab28e75 improved build script, automatic version fetch from source 2017-10-03 20:30:53 +02:00
MightyPork 2796709624 version bump to beta2 2017-10-03 01:55:46 +02:00
MightyPork d2edcd7fd5 added new release system 2017-10-03 00:59:21 +02:00
MightyPork 76272530ec improved ENQ response, now includes hashes and ID. Added ID to boot msg 2017-10-02 22:55:56 +02:00
MightyPork a514601897 use async buffer for apars respond other than http 2017-10-02 22:20:38 +02:00
MightyPork 935e05a56a Disable Rx pin pull-up, caused malfunction with cheap adapters 2017-10-02 19:51:58 +02:00
MightyPork a72e2bed63 makefile improvements 2017-10-02 03:18:43 +02:00
MightyPork 679f0adbae Merge branch 'http-comm' into work 2017-10-02 01:40:45 +02:00
MightyPork 791f6e716f finished basic d2d and external, adde flags etc 2017-10-02 01:40:26 +02:00
MightyPork 9a5bc0a274 Add codename 2017-10-01 22:56:13 +02:00
MightyPork dca02976a7 Fixed a horrible MegaBug and added HTTP message sending + D2D sending (no Rx yet) 2017-10-01 19:46:14 +02:00
MightyPork 6665b5c183 CAN and SUB correctly abort current sequence, including string. Start of adding PM's 2017-10-01 14:09:39 +02:00
MightyPork 55afcca955 fix incorrect DCS command handling 2017-10-01 13:47:22 +02:00
MightyPork 7ffc947f1a added client + testing command ESC#7 2017-10-01 12:54:52 +02:00
MightyPork 0eeed9c7d9 add %debugbar% to terminal page 2017-10-01 03:42:15 +02:00
MightyPork 253473daed version bump for next rel 2017-10-01 03:35:52 +02:00
MightyPork 9321cd4ebb made it survive idiots cat'ing image files etc 2017-10-01 03:35:31 +02:00
MightyPork faffa68794 use binary messages and fix bugs in utf sanitizer 2017-10-01 03:23:04 +02:00
MightyPork a6ee808a1d add SKIP tag to defines 2017-09-30 22:59:46 +02:00
MightyPork 5150cc32eb align serializer with front-end changes 2017-09-30 22:57:40 +02:00
MightyPork 42d5f6bc89 decopt 12 configurable 2017-09-30 19:11:34 +02:00
MightyPork d2fe37403f Fix htop display bugs - wrong serialization 2017-09-30 17:48:42 +02:00
MightyPork f6c2b06d8a notify about mouse attrs change 2017-09-30 15:10:52 +02:00
MightyPork b6c5648690 allow zero redraw delay 2017-09-30 15:02:19 +02:00
MightyPork 062b0e6188 fix messed up bg color encoding 2017-09-30 13:52:28 +02:00
MightyPork c83b68405f Merge branch 'partial-updates' into work 2017-09-30 02:55:54 +02:00
MightyPork 97552b30c3 fix some bugs + optimize stuff 2017-09-30 02:40:24 +02:00
MightyPork 1c23e79c59 partial update, may be a bit buggy in places 2017-09-30 01:18:03 +02:00
MightyPork b70c65868b dump context and stop listening for a bit on rx of bad UTF 2017-09-29 21:57:20 +02:00
MightyPork 1614194d76 Removed one NOTIFY_LOCK() that shouldn't have been there 2017-09-29 20:49:52 +02:00
MightyPork 7bca46384e Merge branch 'new-message-format' into work 2017-09-28 23:11:28 +02:00
MightyPork 03c7f4d0ad removed bugs 2017-09-28 22:09:30 +02:00
MightyPork da6c5bf5be re-arranged attr bits and changed string encoding for labels and title to use terminator rather than byte length 2017-09-28 21:50:51 +02:00
MightyPork 2e0648be8e re-ordered cell attr bits for shorter serialize word length 2017-09-28 21:13:10 +02:00
MightyPork 404ccaeb20 new message format 2017-09-28 20:58:45 +02:00
MightyPork 7300e0003c Merge branch 'master' into work 2017-09-26 17:42:55 +02:00
51 changed files with 2157 additions and 686 deletions
+1
View File
@@ -20,3 +20,4 @@ cmake-build-debug/
.sass-cache
*.map
.gitignore
+38 -7
View File
@@ -56,6 +56,8 @@ set(SOURCE_FILES
libesphttpd/util/cgiwebsocket.c
libesphttpd/util/cgiflash.c
libesphttpd/util/captdns.c
libesphttpd/esphttpclient/httpclient.c
libesphttpd/include/httpclient.h
esp_iot_sdk_v1.5.2/include/user_interface.h
esp_iot_sdk_v1.5.2/include/upgrade.h
@@ -85,9 +87,9 @@ set(SOURCE_FILES
esp_iot_sdk_v1.5.2/include/json/jsontree.h
esp_iot_sdk_v1.5.2/include/json/jsonparse.h
esp_iot_sdk_v1.5.2/include/json/json.h
include/user_config.h
include/ets_sys_extra.h
include/helpers.h
user/io.c
user/io.h
user/cgi_wifi.c
@@ -121,7 +123,6 @@ set(SOURCE_FILES
user/wifimgr.h
user/persist.c
user/persist.h
include/helpers.h
user/syscfg.c
user/syscfg.h
user/ascii.h
@@ -139,9 +140,18 @@ set(SOURCE_FILES
user/apars_osc.c
user/apars_osc.h
user/apars_dcs.c
user/apars_dcs.h user/uart_buffer.c user/uart_buffer.h user/jstring.c user/jstring.h user/character_sets.h user/utf8.h user/utf8.c user/cgi_logging.h)
user/apars_dcs.h
user/uart_buffer.c
user/uart_buffer.h
user/jstring.c
user/jstring.h
user/character_sets.h
user/utf8.h
user/utf8.c
user/cgi_logging.h)
include_directories(include)
include_directories(libesphttpd/esphttpclient)
include_directories(user)
include_directories(libesphttpd/include)
include_directories(libesphttpd/espfs)
@@ -160,13 +170,34 @@ add_definitions(
-DICACHE_FLASH_ATTR=
-DICACHE_RODATA_ATTR=
-DFLAG_GZIP=2
-DADMIN_PASSWORD="asdf"
-DESP_LANG="en"
-DGIT_HASH_BACKEND="asdf"
-DGIT_HASH_FRONTEND="asdf"
-DGIT_HASH="blabla"
-DDEBUG_HEAP=1
-DDEBUG_MALLOC=1
-D__TIMEZONE__="UTC"
-DESPFS_HEATSHRINK)
-DESPFS_HEATSHRINK
-DDEBUG_ANSI=1
-DDEBUG_ANSI_NOIMPL=1
-DDEBUG_CAPTDNS=1
-DDEBUG_CGI=0
-DDEBUG_ESPFS=1
-DDEBUG_HEAP=1
-DDEBUG_HTTP=1
-DDEBUG_HTTPC=1
-DDEBUG_INPUT=1
-DDEBUG_MALLOC=1
-DDEBUG_PERSIST=1
-DDEBUG_ROUTER=1
-DDEBUG_UTFCACHE=1
-DDEBUG_WIFI=1
-DDEBUG_WS=1
-DDEBUG_ROUTER=1
)
# all the debug keys should be listed here ^ so clion thinks they are used
# and doesn't mess up the formatting and inspections
add_executable(ESPTerm ${SOURCE_FILES})
+13 -2
View File
@@ -62,6 +62,10 @@ LIBS = c gcc hal phy pp net80211 wpa main lwip crypto
#Add in esphttpd lib
LIBS += esphttpd
ifndef ESP_LANG
ESP_LANG = en
endif
# compiler flags using during compilation of source files -ggdb
CFLAGS = -Os -std=gnu99 -Werror -Wpointer-arith -Wundef -Wall -Wl,-EL -fno-inline-functions \
-nostdlib -mlongcalls -mtext-section-literals -D__ets__ -DICACHE_FLASH \
@@ -69,7 +73,7 @@ CFLAGS = -Os -std=gnu99 -Werror -Wpointer-arith -Wundef -Wall -Wl,-EL -fno-inli
CFLAGS += -DGIT_HASH_BACKEND='"$(shell git rev-parse --short HEAD)"'
CFLAGS += -DGIT_HASH_FRONTEND='"$(shell cd front-end && git rev-parse --short HEAD)"'
CFLAGS += -D__TIMEZONE__='"$(shell date +%Z)"'
CFLAGS += -D__TIMEZONE__='"$(shell date +%Z)"' -DESP_LANG='"$(ESP_LANG)"'
ifdef GLOBAL_CFLAGS
CFLAGS += $(GLOBAL_CFLAGS)
@@ -194,6 +198,10 @@ endef
web:
$(Q) ./build_web.sh
updweb:
$(Q) cd front-end && git pull
$(Q) ./build_web.sh
parser:
$(Q) ./build_parser.sh
@@ -206,13 +214,16 @@ espmac:
all: checkdirs
$(Q) make actual_all -j4 -B
release:
$(Q) ./release.sh
actual_all: parser $(TARGET_OUT) $(FW_BASE)
libesphttpd/Makefile:
$(Q) [[ -e "libesphttpd/Makefile" ]] || echo -e "\e[31mlibesphttpd submodule missing.\nIf build fails, run \"git submodule init\" and \"git submodule update\".\e[0m"
libesphttpd: libesphttpd/Makefile
$(Q) make -C libesphttpd USE_OPENSDK=$(USE_OPENSDK) SERVERNAME_PREFIX="ESPTerm " -j4
$(Q) make -C libesphttpd USE_OPENSDK=$(USE_OPENSDK) -j4
$(APP_AR): libesphttpd $(OBJ)
$(vecho) "AR $@"
+33 -20
View File
@@ -5,21 +5,24 @@
![Photo][photo-hw]<br>
*Fig 1: Breadboard adapter developed for ESPTerm*
As of release 1.0, ESPTerm **passes most of VTTEST test cases** (from the main menu and some Xterm specific), making it
functionally comparable to eg. gnome-terminal, terminator, konsole, GtkTerm or PuTTY.
ESPTerm **passes most of VTTEST test cases**, making it functionally comparable to eg.
gnome-terminal, terminator, konsole, GtkTerm or PuTTY.
ESPTerm is **capable of running Midnight Commander** through agetty, **including full
mouse support**, provided agetty is made to believe it's Xterm, which shows ESPTerm is sufficiently well
implemented to work with ncurses.
mouse support**, provided agetty is made to believe it's Xterm, which shows ESPTerm
is compatible with ncurses.
In addition to control sequences that manipulate the terminal or user input, there
is a set of simple **networking commands** for device-to-device message exchange and
interacting with remote servers.
To see what escape sequences are supported, check out this [annotated Xterm manual page][xterm-compare]
which was used for reference, or the built-in help page ([online demo][demo-help])
The terminal screen can be accessed using any web browser, even on a phone or tablet.
It works with ESP-01, ESP-01S, ESP-12 and likely many other modules (I use an ESP-12
on a LoLin NodeMCU board from eBay for development).
It works with ESP-01, ESP-01S, ESP-12 and likely many other modules.
With ESPTerm, you can add remote access via WiFi to any embeded project, all you need is
a serial port and some imagination!
UART and some imagination!
## Try it online
@@ -48,6 +51,8 @@ It **does not work with**:
- Internet Explorer (any version) - crashes, missing JS features
- Opera Mini - crashes, missing JS and CSS features
- Blackberry browser - not tested, but unlikely
- Safari on old iOS versions - missing features
- WebOS browser
- Old Android Browser (before 4.4?) - not tested, likely missing JS features
## Main features
@@ -58,6 +63,10 @@ It **does not work with**:
- Full UTF-8 support, alternate character sets
- Standard mouse tracking modes
- You can dynamically set screen title, button labels...
- **Networking commands**
- Command for sending a message to another ESPTerm
- API endpoint (`/api/v1/msg`) for receiving messages sent e.g. from a script on PC, web browser or CURL
- Command for requesting remote servers and getting back response headers and/or body
- **Web Terminal Interface**
- Real-time screen update via WebSocket
- Mouse and keyboard input, works also on mobile
@@ -67,6 +76,15 @@ It **does not work with**:
- **User-friendly comprehensive WiFi configuration** (Demo: [WiFi][demo-wifi], [network][demo-network] config)
- Static IP, DHCP, channel selection, power
- SSID search utility for finding your existing network
- **Basic security features**
- Possibility to password-lock parts of the web interface
- Admin password for some sensitive operations (can be changed!)
- Configurable AP password & Hidden attribute
- **Advanced settings storage**
- Stored in Flash
- Seamlesly updated and usually backwards compatible in minor releases
- Settings can be saved as defaults and later easily restored (ideal e.g. for classroom use, saving
good tested settings before giving the module to students)
## Bugs? Ideas?
@@ -108,36 +126,31 @@ It can happen that some changes to the WiFi or network config make the module in
- To reset all settings to defaults, hold the button a couple seconds until the LED flashes rapidly, then release it.
- You can cancel this wipe/reset operation (when triggered by accident) by pressing Reset or disconnecting the power supply.
### Config files
### Config banks
ESPTerm has two config "files", one for defaults and one for the currently used settings. In the case of the terminal
config, there is also a third, temporary file for changes done via ESC commands.
When you get your settings *just right*, you can store them as defaults, which can then be at any time restored
by holding the BOOT (GPIO0) button. You can do this on the System Settings page. This asks for an "admin password",
which you can define when building the firmware in the `esphttpdconfig.mk` file.
The default password is `19738426`. This password can't presently be changed without re-flashing the firmware.
which can (and should!) be changed. This password can't be easily recovered when forgotten.
You can also restore everything (except the saved defaults) to "factory defaults", there is a button for this
on the System Settings page. Those are the initial values in the config files.
on the System Settings page. Those are the initial values you would get after a clean install.
## Research resources
Developing ESPTerm wasn't an easy task, because the information is scattered across many places and the existing
terminal emulators I originally used for reference (terminator, Konsole) are not implemented correctly in some details.
Developing the terminal emulator was complicated by the information being scattered across many places and the existing
implementations I used for reference often got some details wrong or didn't implement certain features at all. Xterm proved to be by far the most complete implementation.
A great tool for checking my implementation has proven to be [VTTTEST][vttest] and Xterm as a reference
implementation that is probably the most complete emulator available, although it's cumbersome to use and its age
really shows in the looks.
A great tool for checking my code has proven to be [VTTTEST][vttest]. ESPTerm passes most of the tests on the main page and some additional Xterm specific ones, like Mouse Tracking.
I've comnpiled a list of those I found most helpful here: [VT100 emulation resources][resources]
Here is a list of useful [VT100 emulation resources][resources] I've collected for reference.
## Development
ESPTerm's firmware is written in C and is based on SpriteTM's `libesphttpd` http server library forked to
[MightyPork/libesphttpd][httpdlib]. This fork includes various improvements
and changes required by the project.
[MightyPork/libesphttpd][httpdlib]. This fork includes various improvements and changes required by the project.
### Installation for development
-61
View File
@@ -1,61 +0,0 @@
# --------------- esphttpd config options ---------------
# If GZIP_COMPRESSION is set to "yes" then the static css, js, and html files will be compressed with gzip before added to the espfs image
# and will be served with gzip Content-Encoding header.
# This could speed up the downloading of these files, but might break compatibility with older web browsers not supporting gzip encoding
# because Accept-Encoding is simply ignored. Enable this option if you have large static files to serve (for e.g. JQuery, Twitter bootstrap)
# By default only js, css and html files are compressed.
# If you have text based static files with different extensions what you want to serve compressed then you will need to add the extension to the following places:
# - Add the extension to this Makefile at the webpages.espfs target to the find command
# - Add the extension to the gzippedFileTypes array in the user/httpd.c file
#
# Adding JPG or PNG files (and any other compressed formats) is not recommended, because GZIP compression does not works effectively on compressed files.
#Static gzipping is disabled by default.
GZIP_COMPRESSION = yes
# If COMPRESS_W_YUI is set to "yes" then the static css and js files will be compressed with yui-compressor
# This option works only when GZIP_COMPRESSION is set to "yes"
# http://yui.github.io/yuicompressor/
#Disabled by default.
COMPRESS_W_YUI = no
YUI-COMPRESSOR = /usr/bin/yui-compressor
#If USE_HEATSHRINK is set to "yes" then the espfs files will be compressed with Heatshrink and decompressed
#on the fly while reading the file. Because the decompression is done in the esp8266, it does not require
#any support in the browser.
USE_HEATSHRINK = yes
USE_OPENSDK = yes
# this ugly trick is needed to allow a relative path
SDK_BASE=$(dir $(lastword $(MAKEFILE_LIST)))/esp_iot_sdk_v1.5.2/
# combined / separate / ota
OUTPUT_TYPE = combined
# SPI flash size, in K
ESP_SPI_FLASH_SIZE_K = 1024
GLOBAL_CFLAGS = \
-DDEBUG_ROUTER=0 \
-DDEBUG_CAPTDNS=0 \
-DDEBUG_HTTP=0 \
-DDEBUG_ESPFS=0 \
-DDEBUG_PERSIST=1 \
-DDEBUG_UTFCACHE=0 \
-DDEBUG_CGI=0 \
-DDEBUG_WIFI=0 \
-DDEBUG_WS=0 \
-DDEBUG_ANSI=1 \
-DDEBUG_ANSI_NOIMPL=1 \
-DDEBUG_INPUT=0 \
-DDEBUG_HEAP=1 \
-DDEBUG_MALLOC=0 \
-DHTTPD_MAX_BACKLOG_SIZE=8192 \
-DHTTPD_MAX_HEAD_LEN=1024 \
-DHTTPD_MAX_POST_LEN=512 \
-DDEBUG_LOGBUF_SIZE=1024 \
-mforce-l32 \
-DUSE_OPTIMIZE_PRINTF=1
+3
View File
@@ -39,9 +39,12 @@ OUTPUT_TYPE = combined
ESP_SPI_FLASH_SIZE_K = 1024
GLOBAL_CFLAGS = \
-DASYNC_LOG=1 \
-DDEBUG_D2D=0 \
-DDEBUG_ROUTER=0 \
-DDEBUG_CAPTDNS=0 \
-DDEBUG_HTTP=0 \
-DDEBUG_HTTPC=0 \
-DDEBUG_ESPFS=0 \
-DDEBUG_PERSIST=1 \
-DDEBUG_UTFCACHE=0 \
+14
View File
@@ -0,0 +1,14 @@
//
// Created by MightyPork on 2017/10/03.
//
// helper for building release packages
//
// Run with `tcc -run`
//
#include "user/version.h"
#include <stdio.h>
void main() {
printf(FW_VERSION);
}
-1
View File
@@ -1 +0,0 @@
+21
View File
@@ -0,0 +1,21 @@
This is a release archive of ESPTerm,
the VT100 terminal emulator for ESP8266.
--------------------------------------------
Version: %VERS%
Locale : %LANG%
Built : %DATETIME%
--------------------------------------------
Source repository:
https://github.com/espterm/espterm-firmware
Report any bugs to our bug-tracker at
https://github.com/espterm/espterm-firmware/issues
or send them to out mailing list
espterm-dev@googlegroups.com
On-line demo is available at
https://espterm.github.io/term.html
[EOF]
+26
View File
@@ -0,0 +1,26 @@
#!/usr/bin/env bash
# The parameters ESPTOOL, ESPPORT and ESPBAUD can be customized
# - export your preferred values in .bashrc
echo -e "\e[32;1mFlashing ESPTerm %VERS% (%LANG%)\e[0m"
if [ -z ${ESPTOOL} ]; then
ESPTOOL='esptool'
which ${ESPTOOL} &>/dev/null
if [ $? -ne 0 ]; then
ESPTOOL='esptool.py'
which ${ESPTOOL} &>/dev/null
if [ $? -ne 0 ]; then
echo -e '\e[31;1mesptool not found!\e[0m'
exit 1
fi
fi
fi
[ -z ESPPORT ] && ESPPORT=/dev/ttyUSB0
[ -z ESPBAUD ] && ESPBAUD=460800
set -x
${ESPTOOL} --port ${ESPPORT} --baud ${ESPBAUD} \
write_flash 0x00000 '%FILE0%' 0x40000 '%FILE4%'
+3
View File
@@ -0,0 +1,3 @@
*
!.gitignore
!flash-tpl.sh
Executable
+69
View File
@@ -0,0 +1,69 @@
#!/usr/bin/env bash
if [ -z "$1" ]; then
vers=$(tcc -run get_version.c)
else
vers=$1
fi
git pull
echo -n -e "\e[1;36mBuilding packages for version $vers\e[0m"
cd front-end
git pull
cd ..
function buildlang() {
lang=$1
echo -e "\n\e[33;1m------ Building \"${lang}\" package ------\e[0m\n"
make clean
ESP_LANG=${lang} make web
ESP_LANG=${lang} make actual_all -B -j4
cd release
destdir="$vers-$lang"
file0=${vers}-0x00000-${lang}.bin
file4=${vers}-0x40000-${lang}.bin
[ -e ${destdir} ] && rm -r ${destdir}
mkdir ${destdir}
cp ../firmware/0x00000.bin ${destdir}/${file0}
cp ../firmware/0x40000.bin ${destdir}/${file4}
flashsh=${destdir}/flash.sh
cp ../rel-tpl/flash.sh ${flashsh}
sed -i s/%FILE0%/${file0}/ ${flashsh}
sed -i s/%FILE4%/${file4}/ ${flashsh}
sed -i s/%VERS%/${vers}/ ${flashsh}
sed -i s/%LANG%/${lang}/ ${flashsh}
chmod +x ${flashsh}
readmefil=${destdir}/README.txt
cp ../rel-tpl/README.txt ${readmefil}
sed -i s/%VERS%/${vers}/ ${readmefil}
sed -i s/%LANG%/${lang}/ ${readmefil}
dt=$(LC_TIME=en_US.UTF-8 date '+%c')
sed -i "s#%DATETIME%#${dt}#" ${readmefil}
unix2dos ${readmefil}
cd ${destdir}
sha256sum ${file0} ${file4} README.txt flash.sh > checksums.txt
cd ..
targetfile=espterm-${vers}-${lang}.zip
[[ -e ${targetfile}.zip ]] && rm ${targetfile}.zip
pwd
zip -9 ${targetfile} ${destdir}/*
cd ..
}
if [ -z "$ESP_LANG" ]; then
buildlang cs
buildlang en
buildlang de
else
buildlang ${ESP_LANG}
fi
+41 -35
View File
@@ -5,10 +5,11 @@
#include "ansi_parser_callbacks.h"
#include "ascii.h"
#include "apars_logging.h"
#include "screen.h"
/* Ragel constants block */
/* #line 12 "user/ansi_parser.c" */
/* #line 13 "user/ansi_parser.c" */
static const char _ansi_actions[] ESP_CONST_DATA = {
0, 1, 0, 1, 1, 1, 2, 1,
3, 1, 4, 1, 5, 1, 6, 1,
@@ -32,18 +33,15 @@ static const int ansi_en_charsetcmd_body = 10;
static const int ansi_en_main = 1;
/* #line 11 "user/ansi_parser.rl" */
/* #line 12 "user/ansi_parser.rl" */
// Max nr of CSI parameters
#define CSI_N_MAX 10
#define ANSI_STR_LEN 64
static volatile int cs = -1;
static volatile bool inside_string = false;
// public
volatile u32 ansi_parser_char_cnt = 0;
volatile bool ansi_parser_inhibit = 0;
void ICACHE_FLASH_ATTR
ansi_parser_reset(void) {
@@ -108,18 +106,25 @@ ansi_parser(char newchar)
static char string_buffer[ANSI_STR_LEN];
static int str_ni;
if (ansi_parser_inhibit) return;
// This is used to detect timeout delay (time since last rx char)
ansi_parser_char_cnt++;
if (termconf->ascii_debug) {
apars_handle_plainchar(newchar);
return;
}
// Init Ragel on the first run
if (cs == -1) {
/* #line 118 "user/ansi_parser.c" */
/* #line 123 "user/ansi_parser.c" */
{
cs = ansi_start;
}
/* #line 92 "user/ansi_parser.rl" */
/* #line 97 "user/ansi_parser.rl" */
#if DEBUG_ANSI
memset(history, 0, sizeof(history));
@@ -133,6 +138,13 @@ ansi_parser(char newchar)
history[HISTORY_LEN-1] = newchar;
#endif
// THose should work always, even inside a string
if (newchar == CAN || newchar == SUB) {
// Cancel the active sequence
cs = ansi_start;
return;
}
// Handle simple characters immediately (bypass parser)
if (newchar < ' ' && !inside_string) {
switch (newchar) {
@@ -174,12 +186,6 @@ ansi_parser(char newchar)
apars_handle_enq();
return;
// Cancel the active sequence
case CAN:
case SUB:
cs = ansi_start;
return;
default:
// Discard all other control codes
return;
@@ -199,7 +205,7 @@ ansi_parser(char newchar)
// The parser
/* #line 203 "user/ansi_parser.c" */
/* #line 209 "user/ansi_parser.c" */
{
const char *_acts;
unsigned int _nacts;
@@ -389,7 +395,7 @@ execFuncs:
while ( _nacts-- > 0 ) {
switch ( *_acts++ ) {
case 0:
/* #line 179 "user/ansi_parser.rl" */
/* #line 185 "user/ansi_parser.rl" */
{
ansi_warn("Parser error.");
apars_show_context();
@@ -398,7 +404,7 @@ execFuncs:
}
break;
case 1:
/* #line 188 "user/ansi_parser.rl" */
/* #line 194 "user/ansi_parser.rl" */
{
if ((*p) != 0) {
apars_handle_plainchar((*p));
@@ -406,7 +412,7 @@ execFuncs:
}
break;
case 2:
/* #line 196 "user/ansi_parser.rl" */
/* #line 202 "user/ansi_parser.rl" */
{
// Reset the CSI builder
leadchar = NUL;
@@ -423,13 +429,13 @@ execFuncs:
}
break;
case 3:
/* #line 211 "user/ansi_parser.rl" */
/* #line 217 "user/ansi_parser.rl" */
{
leadchar = (*p);
}
break;
case 4:
/* #line 215 "user/ansi_parser.rl" */
/* #line 221 "user/ansi_parser.rl" */
{
if (arg_cnt == 0) arg_cnt = 1;
// x10 + digit
@@ -439,7 +445,7 @@ execFuncs:
}
break;
case 5:
/* #line 223 "user/ansi_parser.rl" */
/* #line 229 "user/ansi_parser.rl" */
{
if (arg_cnt == 0) arg_cnt = 1; // handle case when first arg is empty
arg_cnt++;
@@ -447,20 +453,20 @@ execFuncs:
}
break;
case 6:
/* #line 229 "user/ansi_parser.rl" */
/* #line 235 "user/ansi_parser.rl" */
{
interchar = (*p);
}
break;
case 7:
/* #line 233 "user/ansi_parser.rl" */
/* #line 239 "user/ansi_parser.rl" */
{
apars_handle_csi(leadchar, arg, arg_cnt, interchar, (*p));
{cs = 1;goto _again;}
}
break;
case 8:
/* #line 245 "user/ansi_parser.rl" */
/* #line 251 "user/ansi_parser.rl" */
{
leadchar = (*p);
str_ni = 0;
@@ -470,13 +476,13 @@ execFuncs:
}
break;
case 9:
/* #line 253 "user/ansi_parser.rl" */
/* #line 259 "user/ansi_parser.rl" */
{
string_buffer[str_ni++] = (*p);
}
break;
case 10:
/* #line 257 "user/ansi_parser.rl" */
/* #line 263 "user/ansi_parser.rl" */
{
inside_string = false;
string_buffer[str_ni++] = '\0';
@@ -485,41 +491,41 @@ execFuncs:
}
break;
case 11:
/* #line 270 "user/ansi_parser.rl" */
/* #line 276 "user/ansi_parser.rl" */
{
apars_handle_hash_cmd((*p));
{cs = 1;goto _again;}
}
break;
case 12:
/* #line 275 "user/ansi_parser.rl" */
/* #line 281 "user/ansi_parser.rl" */
{
apars_handle_short_cmd((*p));
{cs = 1;goto _again;}
}
break;
case 13:
/* #line 280 "user/ansi_parser.rl" */
/* #line 286 "user/ansi_parser.rl" */
{
apars_handle_space_cmd((*p));
{cs = 1;goto _again;}
}
break;
case 14:
/* #line 287 "user/ansi_parser.rl" */
/* #line 293 "user/ansi_parser.rl" */
{
leadchar = (*p);
{cs = 10;goto _again;}
}
break;
case 15:
/* #line 292 "user/ansi_parser.rl" */
/* #line 298 "user/ansi_parser.rl" */
{
apars_handle_chs_designate(leadchar, (*p));
{cs = 1;goto _again;}
}
break;
/* #line 523 "user/ansi_parser.c" */
/* #line 529 "user/ansi_parser.c" */
}
}
goto _again;
@@ -537,7 +543,7 @@ _again:
while ( __nacts-- > 0 ) {
switch ( *__acts++ ) {
case 0:
/* #line 179 "user/ansi_parser.rl" */
/* #line 185 "user/ansi_parser.rl" */
{
ansi_warn("Parser error.");
apars_show_context();
@@ -547,7 +553,7 @@ _again:
goto _again;}
}
break;
/* #line 551 "user/ansi_parser.c" */
/* #line 557 "user/ansi_parser.c" */
}
}
}
@@ -555,6 +561,6 @@ goto _again;}
_out: {}
}
/* #line 315 "user/ansi_parser.rl" */
/* #line 321 "user/ansi_parser.rl" */
}
+5
View File
@@ -3,6 +3,11 @@
#include <stdlib.h>
#define CSI_N_MAX 12
#define ANSI_STR_LEN 256
extern volatile bool ansi_parser_inhibit; // discard all characters
void ansi_parser_reset(void);
extern volatile u32 ansi_parser_char_cnt;
+16 -10
View File
@@ -3,6 +3,7 @@
#include "ansi_parser_callbacks.h"
#include "ascii.h"
#include "apars_logging.h"
#include "screen.h"
/* Ragel constants block */
%%{
@@ -10,15 +11,12 @@
write data;
}%%
// Max nr of CSI parameters
#define CSI_N_MAX 10
#define ANSI_STR_LEN 64
static volatile int cs = -1;
static volatile bool inside_string = false;
// public
volatile u32 ansi_parser_char_cnt = 0;
volatile bool ansi_parser_inhibit = 0;
void ICACHE_FLASH_ATTR
ansi_parser_reset(void) {
@@ -83,9 +81,16 @@ ansi_parser(char newchar)
static char string_buffer[ANSI_STR_LEN];
static int str_ni;
if (ansi_parser_inhibit) return;
// This is used to detect timeout delay (time since last rx char)
ansi_parser_char_cnt++;
if (termconf->ascii_debug) {
apars_handle_plainchar(newchar);
return;
}
// Init Ragel on the first run
if (cs == -1) {
%% write init;
@@ -102,6 +107,13 @@ ansi_parser(char newchar)
history[HISTORY_LEN-1] = newchar;
#endif
// THose should work always, even inside a string
if (newchar == CAN || newchar == SUB) {
// Cancel the active sequence
cs = ansi_start;
return;
}
// Handle simple characters immediately (bypass parser)
if (newchar < ' ' && !inside_string) {
switch (newchar) {
@@ -143,12 +155,6 @@ ansi_parser(char newchar)
apars_handle_enq();
return;
// Cancel the active sequence
case CAN:
case SUB:
cs = ansi_start;
return;
default:
// Discard all other control codes
return;
+34 -1
View File
@@ -11,6 +11,14 @@
#include "version.h"
#include "uart_buffer.h"
#include "screen.h"
#include "wifimgr.h"
volatile bool enquiry_suppressed = false;
ETSTimer enqTimer;
void ICACHE_FLASH_ATTR enqTimerCb(void *unused)
{
enquiry_suppressed = false;
}
/**
* Send a response to UART0
@@ -19,6 +27,7 @@
void ICACHE_FLASH_ATTR
apars_respond(const char *str)
{
// Using the Tx buffer causes issues with large data (eg. from http requests)
UART_SendAsync(str, -1);
}
@@ -37,8 +46,32 @@ apars_handle_bel(void)
void ICACHE_FLASH_ATTR
apars_handle_enq(void)
{
if (enquiry_suppressed) return;
u8 mac[6];
wifi_get_macaddr(SOFTAP_IF, mac);
char buf100[100];
char *buf = buf100;
buf += sprintf(buf, "\x1bX");
buf += sprintf(buf, "ESPTerm "VERSION_STRING" ");
buf += sprintf(buf, "#"GIT_HASH_BACKEND"+"GIT_HASH_FRONTEND" ");
buf += sprintf(buf, "id=%02X%02X%02X ", mac[3], mac[4], mac[5]);
int x = getStaIpAsString(buf);
if (x) buf += x;
else buf--; // remove the trailing space
buf += sprintf(buf, "\x1b\\");
(void)buf;
// version encased in SOS and ST
apars_respond("\x1bXESPTerm " FIRMWARE_VERSION "\x1b\\");
apars_respond(buf100);
// Throttle enquiry - this is a single-character-invoked response,
// so it tends to happen randomly when throwing garbage at the ESP.
// We don't want to fill the output buffer with dozens of enquiry responses
enquiry_suppressed = true;
TIMER_START(&enqTimer, enqTimerCb, 500, 0);
}
void ICACHE_FLASH_ATTR
+4 -2
View File
@@ -709,6 +709,8 @@ do_csi_set_private_option(CSI_Data *opts)
mouse_tracking.mode,
mouse_tracking.encoding,
mouse_tracking.focus_tracking);
screen_notifyChange(TOPIC_CHANGE_SCREEN_OPTS);
}
else if (n == 12) {
screen_cursor_blink(yn);
@@ -757,11 +759,11 @@ do_csi_set_private_option(CSI_Data *opts)
}
else if (n == 800) { // ESPTerm: Toggle display of buttons
termconf_live.show_buttons = yn;
screen_notifyChange(CHANGE_CONTENT); // this info is included in the screen preamble
screen_notifyChange(TOPIC_CHANGE_SCREEN_OPTS); // this info is included in the screen preamble
}
else if (n == 801) { // ESPTerm: Toggle display of config links
termconf_live.show_config_links = yn;
screen_notifyChange(CHANGE_CONTENT); // this info is included in the screen preamble
screen_notifyChange(TOPIC_CHANGE_SCREEN_OPTS); // this info is included in the screen preamble
}
else {
ansi_noimpl("?OPTION %d", n);
+5 -3
View File
@@ -30,7 +30,7 @@
* @param buffer - the DCS body (after DCS and before ST)
*/
void ICACHE_FLASH_ATTR
apars_handle_dcs(const char *buffer)
apars_handle_dcs(char *buffer)
{
char buf[64]; // just about big enough for full-house SGR
size_t len = strlen(buffer);
@@ -47,7 +47,9 @@ apars_handle_dcs(const char *buffer)
}
else if (buffer[2] == 'r') {
// DECSTBM - Query scrolling region
sprintf(buf, "\033P1$r%d;%dr\033\\", 1, termconf_live.height); // 1-80 TODO real extent of scrolling region
int v0, v1;
screen_region_get(&v0, &v1);
sprintf(buf, "\033P1$r%d;%dr\033\\", v0+1, v1+1);
apars_respond(buf);
}
else if (buffer[2] == 's') {
@@ -64,7 +66,7 @@ apars_handle_dcs(const char *buffer)
}
else if (strneq(buffer+2, " q", 2)) {
// DECSCUSR - Query cursor style
sprintf(buf, "\033P1$r%d q\033\\", 1);
sprintf(buf, "\033P1$r%d q\033\\", termconf_live.cursor_shape);
/*
Ps = 0 -> blinking block.
Ps = 1 -> blinking block (default).
+1 -1
View File
@@ -5,6 +5,6 @@
#ifndef ESP_VT100_FIRMWARE_APARS_DCS_H
#define ESP_VT100_FIRMWARE_APARS_DCS_H
void apars_handle_dcs(const char *buffer);
void apars_handle_dcs(char *buffer);
#endif //ESP_VT100_FIRMWARE_APARS_DCS_H
+4
View File
@@ -49,6 +49,10 @@ apars_handle_osc(char *buffer)
buffer[0] = 'G';
notify_growl(buffer);
}
else if (n == 70) {
// ESPTerm: backdrop
screen_set_backdrop(buffer);
}
else if (n >= 81 && n <= 85) {
// ESPTerm: action button label
screen_set_button_text(n - 80, buffer);
+34
View File
@@ -0,0 +1,34 @@
//
// Created by MightyPork on 2017/08/20.
//
// Handle privacy messages
// PM Pt ST
// (PM = ESC ^)
//
// Those are used for device-to-device communication.
// They were not used for anything in the original VT100 and are not
// used by Xterm or any other common emulator, but they should be safely discarded.
//
#include <esp8266.h>
#include <httpclient.h>
#include "apars_pm.h"
#include "version.h"
#include "ansi_parser_callbacks.h"
#include "screen.h"
#include "apars_logging.h"
#include "cgi_d2d.h"
/**
* Helper function to parse incoming DCS (Device Control String)
* @param msg - the DCS body (after DCS and before ST)
*/
void ICACHE_FLASH_ATTR
apars_handle_pm(char *msg)
{
if (d2d_parse_command(msg)) return;
return;
fail:
ansi_warn("D2D message error: %s", msg);
}
+10
View File
@@ -0,0 +1,10 @@
//
// Created by MightyPork on 2017/08/20.
//
#ifndef ESP_VT100_FIRMWARE_APARS_PM_H
#define ESP_VT100_FIRMWARE_APARS_PM_H
void apars_handle_pm(char *msg);
#endif //ESP_VT100_FIRMWARE_APARS_PM_H
+7
View File
@@ -42,9 +42,11 @@
//
#include <esp8266.h>
#include <httpclient.h>
#include "apars_short.h"
#include "apars_logging.h"
#include "screen.h"
#include "ansi_parser_callbacks.h"
// ----- Character Set ---
@@ -103,6 +105,11 @@ void ICACHE_FLASH_ATTR apars_handle_hash_cmd(char c)
screen_fill_with_E();
break;
// development codes - do not use!
case '7':
http_get("http://wtfismyip.com/text", NULL, http_callback_example);
break;
default:
ansi_noimpl("ESC # %c", c);
}
+3 -1
View File
@@ -17,6 +17,7 @@
#include "apars_logging.h"
#include "ansi_parser_callbacks.h"
#include "screen.h"
#include "apars_pm.h"
// ----- Generic String cmd - disambiguation -----
@@ -24,7 +25,7 @@ void ICACHE_FLASH_ATTR
apars_handle_string_cmd(char leadchar, char *buffer)
{
switch (leadchar) {
case 'k': // ESC k TITLE ST (defined in GNU screen manpage)
case 'k': // ESC k TITLE ST (defined in GNU screen manpage, probably not standard)
screen_set_title(buffer);
break;
@@ -37,6 +38,7 @@ apars_handle_string_cmd(char leadchar, char *buffer)
break;
case '^': // PM - Privacy Message
apars_handle_pm(buffer);
break;
case '_': // APC - Application Program Command
+166 -26
View File
@@ -8,9 +8,13 @@
#include "apars_utf8.h"
#include "apars_logging.h"
#include "screen.h"
#include "uart_driver.h"
#include "ansi_parser_callbacks.h"
#include "ansi_parser.h"
#include "ascii.h"
static char utf_collect[4];
static int utf_i = 0;
static u8 bytes[4];
static int utf_len = 0;
static int utf_j = 0;
/**
@@ -20,11 +24,121 @@ static int utf_j = 0;
void ICACHE_FLASH_ATTR
apars_reset_utf8buffer(void)
{
utf_i = 0;
utf_len = 0;
utf_j = 0;
memset(utf_collect, 0, 4);
memset(bytes, 0, 4);
}
// Code Points First Byte Second Byte Third Byte Fourth Byte
// U+0000 - U+007F 00 - 7F
// U+0080 - U+07FF C2 - DF 80 - BF
// U+0800 - U+0FFF E0 *A0 - BF 80 - BF
// U+1000 - U+CFFF E1 - EC 80 - BF 80 - BF
// U+D000 - U+D7FF ED 80 - *9F 80 - BF
// U+E000 - U+FFFF EE - EF 80 - BF 80 - BF
// U+10000 - U+3FFFF F0 *90 - BF 80 - BF 80 - BF
// U+40000 - U+FFFFF F1 - F3 80 - BF 80 - BF 80 - BF
// U+100000 - U+10FFFF F4 80 - *8F 80 - BF 80 - BF
static void ICACHE_FLASH_ATTR screen_print_ascii(const char *str)
{
char gly[2];
gly[1] = 0;
for(int j = 0;str[j]!=0;j++) {
gly[0] = str[j];
screen_putchar(gly);
}
}
static void ICACHE_FLASH_ATTR hdump_spaces_eol(int needed)
{
if (needed == 0) needed = 5;
int x, y;
screen_cursor_get(&y, &x);
if (x > termconf_live.width - needed) {
screen_clear_in_line(CLEAR_FROM_CURSOR);
screen_putchar("\n");
screen_putchar("\r");
}
}
static void ICACHE_FLASH_ATTR hdump_good(const char *ch)
{
char buf[10];
hdump_spaces_eol(6);
screen_set_fg(7);
screen_set_bg(0);
if(ch[0]<32) {
screen_set_fg(7);
screen_set_bg(2);
switch (ch[0]) {
case NUL: screen_print_ascii("NUL"); break;
case SOH: screen_print_ascii("SOH"); break;
case STX: screen_print_ascii("STX"); break;
case ETX: screen_print_ascii("ETX"); break;
case EOT: screen_print_ascii("EOT"); break;
case ENQ: screen_print_ascii("ENQ"); break;
case ACK: screen_print_ascii("ACK"); break;
case BEL: screen_print_ascii("BEL"); break;
case BS: screen_print_ascii("BS"); break;
case TAB: screen_print_ascii("TAB"); break;
case LF: screen_print_ascii("LF"); break;
case VT: screen_print_ascii("VT"); break;
case FF: screen_print_ascii("FF"); break;
case CR: screen_print_ascii("CR"); break;
case SO: screen_print_ascii("SO"); break;
case SI: screen_print_ascii("SI"); break;
case DLE: screen_print_ascii("DLE"); break;
case DC1: screen_print_ascii("DC1"); break;
case DC2: screen_print_ascii("DC2"); break;
case DC3: screen_print_ascii("DC3"); break;
case DC4: screen_print_ascii("DC4"); break;
case NAK: screen_print_ascii("NAK"); break;
case SYN: screen_print_ascii("SYN"); break;
case ETB: screen_print_ascii("ETB"); break;
case CAN: screen_print_ascii("CAN"); break;
case EM: screen_print_ascii("EM"); break;
case SUB: screen_print_ascii("SUB"); break;
case ESC: screen_print_ascii("ESC"); break;
case FS: screen_print_ascii("FS"); break;
case GS: screen_print_ascii("GS"); break;
case RS: screen_print_ascii("RS"); break;
case US: screen_print_ascii("US"); break;
case SP: screen_print_ascii("SP"); break;
case DEL: screen_print_ascii("DEL"); break;
default:
sprintf(buf, "%02Xh", ch[0]);
screen_print_ascii(buf);
}
} else {
screen_putchar(ch);
}
screen_set_default_bg();
screen_set_default_fg();
screen_print_ascii(" ");
}
static void ICACHE_FLASH_ATTR hdump_bad(const char *ch, int len)
{
char buf[10];
hdump_spaces_eol(len*5);
screen_set_fg(7);
screen_set_bg(1);
for (int i=0;i<len;i++) {
sprintf(buf, "%02Xh", ch[i]);
screen_print_ascii(buf);
if(i<len-1) screen_print_ascii(" ");
}
screen_set_default_bg();
screen_set_default_fg();
screen_print_ascii(" ");
}
/**
* Handle a received plain character
* @param c - received character
@@ -32,53 +146,79 @@ apars_reset_utf8buffer(void)
void ICACHE_FLASH_ATTR
apars_handle_plainchar(char c)
{
u8 uc = (u8)c;
// collecting unicode glyphs...
if (c & 0x80) {
if (utf_i == 0) {
if (uc & 0x80) {
if (utf_len == 0) {
bytes[0] = uc;
utf_j = 1;
// start
if (c == 192 || c == 193 || c >= 245) {
// forbidden codes (would be an overlong sequence)
if (uc == 0xC0 || uc == 0xC1 || uc > 0xF4) {
// forbidden start codes
goto fail;
}
if ((c & 0xE0) == 0xC0) {
utf_i = 2;
if ((uc & 0xE0) == 0xC0) {
utf_len = 2;
}
else if ((c & 0xF0) == 0xE0) {
utf_i = 3;
else if ((uc & 0xF0) == 0xE0) {
utf_len = 3;
}
else if ((c & 0xF8) == 0xF0) {
utf_i = 4;
else if ((uc & 0xF8) == 0xF0) {
utf_len = 4;
}
else {
// chars over 127 that don't start unicode sequences
goto fail;
}
utf_collect[0] = c;
utf_j = 1;
}
else {
if ((c & 0xC0) != 0x80) {
if ((uc & 0xC0) != 0x80) {
bytes[utf_j++] = uc;
goto fail;
}
else {
utf_collect[utf_j++] = c;
if (utf_j >= utf_i) {
screen_putchar(utf_collect);
bytes[utf_j++] = uc;
if (utf_j >= utf_len) {
// check for bad sequences - overlong or some other problem
if (bytes[0] == 0xF4 && bytes[1] > 0x8F) goto fail;
if (bytes[0] == 0xF0 && bytes[1] < 0x90) goto fail;
if (bytes[0] == 0xED && bytes[1] > 0x9F) goto fail;
if (bytes[0] == 0xE0 && bytes[1] < 0xA0) goto fail;
// trap for surrogates - those break javascript
if (bytes[0] == 0xED && bytes[1] >= 0xA0 && bytes[1] <= 0xBF) goto fail;
if (termconf_live.ascii_debug) {
hdump_good((const char *) bytes);
} else {
screen_putchar((const char *) bytes);
}
apars_reset_utf8buffer();
}
}
}
}
else {
utf_collect[0] = c;
utf_collect[1] = 0; // just to make sure it's closed...
screen_putchar(utf_collect);
bytes[0] = uc;
bytes[1] = 0; // just to make sure it's closed...
if (termconf_live.ascii_debug) {
hdump_good((const char *) bytes);
} else {
screen_putchar((const char *) bytes);
}
apars_reset_utf8buffer();
}
return;
fail:
ansi_warn("Bad UTF-8: %0Xh", c);
fail:
if (termconf_live.ascii_debug) {
hdump_bad((const char *) bytes, utf_j);
} else {
screen_putchar("\xEF\xBF\xBD");
}
//ansi_warn("BAD UTF8!");
//apars_show_context();
apars_reset_utf8buffer();
}
+15
View File
@@ -0,0 +1,15 @@
//
// Created by MightyPork on 2017/10/01.
//
#ifndef ESPTERM_API_H
#define ESPTERM_API_H
// TODO use X-MACRO for access restrictions etc
#define API_D2D_MSG "/api/v1/msg"
#define API_REBOOT "/api/v1/reboot"
#define API_PING "/api/v1/ping"
#define API_CLEAR "/api/v1/clear"
#endif //ESPTERM_API_H
+324
View File
@@ -0,0 +1,324 @@
//
// Created by MightyPork on 2017/10/01.
//
#include <esp8266.h>
#include "cgi_d2d.h"
#include "version.h"
#include "ansi_parser_callbacks.h"
#include "api.h"
#include "uart_driver.h"
#include <httpclient.h>
#include <esp_utils.h>
#define D2D_TIMEOUT_MS 2000
#define D2D_HEADERS \
"User-Agent: ESPTerm "VERSION_STRING" like curl wget HTTPie\r\n" \
"Content-Type: text/plain; charset=utf-8\r\n" \
"Accept-Encoding: identity\r\n" \
"Accept-Charset: utf-8\r\n" \
"Accept: text/*, application/json\r\n" \
"Cache-Control: no-cache,private,max-age=0\r\n"
struct d2d_request_opts {
bool want_body;
bool want_head;
size_t max_result_len;
char *nonce;
};
volatile bool request_pending = false;
// NOTE! We bypass the async buffer here - used for user input and
// responses to queries {apars_respond()}. In rare situations this could
// lead to a race condition and mixing two different messages
static inline void ICACHE_FLASH_ATTR sendResponseToUART(const char *str)
{
UART_WriteString(UART0, str, UART_TIMEOUT_US);
}
static void ICACHE_FLASH_ATTR
requestNoopCb(int http_status,
char *response_headers,
char *response_body,
size_t body_size,
void *userArg)
{
request_pending = false;
if (userArg != NULL) free(userArg);
}
static void ICACHE_FLASH_ATTR
requestCb(int http_status,
char *response_headers,
char *response_body,
size_t body_size,
void *userArg)
{
if (userArg == NULL) {
request_pending = false;
return;
}
struct d2d_request_opts *opts = userArg;
// ensure positive - would be hard to parse
if (http_status < 0) http_status = -http_status;
char buff100[100];
int len = 0;
size_t headers_size = strlen(response_headers);
if (opts->want_head) len += headers_size;
if (opts->want_body) len += body_size + (opts->want_head*2);
if (opts->max_result_len > 0 && len > opts->max_result_len)
len = (int) opts->max_result_len;
d2d_info("Rx HTTP response, code %d, len %d, nonce \"%s\"", http_status, len, opts->nonce?opts->nonce:"");
char *bb = buff100;
bb += sprintf(bb, "\x1b^h;%d;", http_status);
const char *comma = "";
if (opts->want_head) {
bb += sprintf(bb, "%sH", comma);
comma = ",";
}
if (opts->want_body) {
bb += sprintf(bb, "%sB", comma);
comma = ",";
}
if (opts->nonce) {
bb += sprintf(bb, "%sN=%s", comma, opts->nonce);
comma = ",";
}
if (opts->want_head || opts->want_body) {
bb += sprintf(bb, "%sL=%d", comma, len);
//comma = ",";
}
// semicolon only if more data is to be sent
if (opts->want_head || opts->want_body) sprintf(bb, ";");
sendResponseToUART(buff100);
//d2d_dbg("Headers (part) %100s", response_headers);
//d2d_dbg("Body (part) %100s", response_body);
// head and payload separated by \r\n\r\n (one \r\n is at the end of head - maybe)
if (opts->want_head) {
// truncate
if (headers_size > len) {
response_headers[len] = 0;
opts->want_body = false; // soz, it wouldn't fit
}
sendResponseToUART(response_headers);
if(opts->want_body) sendResponseToUART("\r\n");
}
if(opts->want_body) {
// truncate
if (opts->want_head*(headers_size+2)+body_size > len) {
response_body[len - (opts->want_head*(headers_size+2))] = 0;
}
sendResponseToUART(response_body);
}
sendResponseToUART("\a");
free(opts->nonce);
free(opts);
request_pending = false;
}
bool ICACHE_FLASH_ATTR
d2d_parse_command(char *msg)
{
char buff40[40];
char *p;
#define FIND_NEXT(target, delim) do { \
p = strchr(msg, (delim)); \
if (p == NULL) return false; \
*p = '\0'; \
(target) = msg; \
msg = p + 1; \
} while(0) \
if (strstarts(msg, "M;")) {
if (request_pending) return false;
// Send a esp-esp message
msg += 2;
const char *ip;
FIND_NEXT(ip, ';');
const char *payload = msg;
d2d_info("D2D Tx,dest=%s,msg=%s", ip, payload);
sprintf(buff40, "http://%s" API_D2D_MSG, ip);
httpclient_args args;
httpclient_args_init(&args);
args.method = HTTPD_METHOD_POST;
args.body = payload;
args.headers = D2D_HEADERS;
args.timeout = D2D_TIMEOUT_MS;
args.url = buff40; // "escapes scope" warning - can ignore, strdup is used
request_pending = true;
http_request(&args, requestNoopCb);
return true;
}
else if (strstarts(msg, "H;")) {
if (request_pending) return false;
// Send a esp-esp message
msg += 2;
const char *method = NULL;
const char *params = NULL;
const char *nonce = NULL;
const char *url = NULL;
const char *payload = NULL;
httpd_method methodNum;
FIND_NEXT(method, ';');
if (streq(method, "GET")) methodNum = HTTPD_METHOD_GET;
else if (streq(method, "POST")) methodNum = HTTPD_METHOD_POST;
else if (streq(method, "OPTIONS")) methodNum = HTTPD_METHOD_OPTIONS;
else if (streq(method, "PUT")) methodNum = HTTPD_METHOD_PUT;
else if (streq(method, "DELETE")) methodNum = HTTPD_METHOD_DELETE;
else if (streq(method, "PATCH")) methodNum = HTTPD_METHOD_PATCH;
else if (streq(method, "HEAD")) methodNum = HTTPD_METHOD_HEAD;
else {
d2d_warn("BAD METHOD: %s", method);
return false;
}
FIND_NEXT(params, ';');
d2d_info("HTTP request");
d2d_dbg("Method %s", method);
size_t max_buf_len = HTTPCLIENT_DEF_MAX_LEN;
size_t max_result_len = 0; // 0 = no truncate
uint timeout = HTTPCLIENT_DEF_TIMEOUT_MS;
bool want_body = 0;
bool want_head = 0;
bool no_resp = 0;
do {
p = strchr(params, ',');
if (p != NULL) *p = '\0';
const char *param = params;
if (params[0] == 0) break; // no params
if(streq(param, "H")) want_head = 1; // Return head
else if(streq(param, "B")) want_body = 1; // Return body
else if(streq(param, "X")) no_resp = 1; // X - no response, no callback
else if(strstarts(param, "l=")) { // max buffer length
max_buf_len = (size_t) atoi(param + 2);
} else if(strstarts(param, "L=")) { // max length
max_result_len = (size_t) atoi(param + 2);
} else if(strstarts(param, "T=")) { // timeout
timeout = (uint) atoi(param + 2);
} else if(strstarts(param, "N=")) { // Nonce
nonce = param+2;
} else {
d2d_warn("BAD PARAM: %s", param);
return false;
}
d2d_dbg("- param %s", params);
if (p == NULL) break;
params = p + 1;
} while(1);
p = strchr(msg, '\n');
if (p != NULL) *p = '\0';
url = msg;
d2d_dbg("URL: %s", url);
if (p != NULL) {
payload = p + 1;
d2d_dbg("Payload: %s", payload);
} else {
payload = NULL;
}
httpclient_args args;
httpclient_args_init(&args);
args.method = methodNum;
args.body = payload;
args.headers = D2D_HEADERS;
args.timeout = timeout;
args.max_response_len = max_buf_len;
args.url = url;
if (!no_resp) {
struct d2d_request_opts *opts = malloc(sizeof(struct d2d_request_opts));
opts->want_body = want_body;
opts->want_head = want_head;
opts->max_result_len = max_result_len;
opts->nonce = esp_strdup(nonce);
args.userData = opts;
}
request_pending = true;
http_request(&args, no_resp ? requestNoopCb : requestCb);
d2d_dbg("Request sent.");
return true;
}
return false;
}
httpd_cgi_state ICACHE_FLASH_ATTR cgiD2DMessage(HttpdConnData *connData)
{
if (connData->conn==NULL) {
//Connection aborted. Clean up.
return HTTPD_CGI_DONE;
}
size_t len = 0;
if (connData->post && connData->post->buff)
len = strlen(connData->post->buff);
else if (connData->getArgs)
len = strlen(connData->getArgs);
else
len = 0;
u8 *ip = connData->remote_ip;
char buf[20];
sprintf(buf, "\x1b^m;"IPSTR";L=%d;", ip[0], ip[1], ip[2], ip[3], (int)len);
sendResponseToUART(buf);
if (connData->post && connData->post->buff)
sendResponseToUART(connData->post->buff);
else if (connData->getArgs)
sendResponseToUART(connData->getArgs);
sendResponseToUART("\a");
d2d_info("D2D Rx src="IPSTR",len=%d", ip[0], ip[1], ip[2], ip[3],len);
// Received a msg
httdResponseOptions(connData, 0);
httdSetTransferMode(connData, HTTPD_TRANSFER_CLOSE);
httpdStartResponse(connData, 200);
httpdHeader(connData, "Content-Type", "text/plain");
httpdEndHeaders(connData);
httpdSend(connData, "message received\r\n", -1);
return HTTPD_CGI_DONE;
}
+25
View File
@@ -0,0 +1,25 @@
//
// Created by MightyPork on 2017/10/01.
//
#ifndef ESPTERM_CGI_D2D_H
#define ESPTERM_CGI_D2D_H
#include <esp8266.h>
#include <httpd.h>
#if DEBUG_D2D
#define d2d_warn warn
#define d2d_dbg dbg
#define d2d_info info
#else
#define d2d_warn(fmt, ...)
#define d2d_dbg(fmt, ...)
#define d2d_info(fmt, ...)
#endif
bool d2d_parse_command(char *msg);
httpd_cgi_state cgiD2DMessage(HttpdConnData *connData);
#endif //ESPTERM_CGI_D2D_H
+4 -17
View File
@@ -25,24 +25,12 @@ httpd_cgi_state ICACHE_FLASH_ATTR tplScreen(HttpdConnData *connData, char *token
char buff[150];
if (streq(token, "labels_seq")) {
screenSerializeLabelsToBuffer(buff, 150);
tplSend(connData, buff, -1);
}
else if (streq(token, "theme")) {
sprintf(buff, "%d", termconf->theme);
tplSend(connData, buff, -1);
}
else if (streq(token, "want_all_fn")) {
if (streq(token, "want_all_fn")) {
sprintf(buff, "%d", termconf->want_all_fn);
tplSend(connData, buff, -1);
}
else if (streq(token, "default_fg")) {
sprintf(buff, "%d", termconf->default_fg);
tplSend(connData, buff, -1);
}
else if (streq(token, "default_bg")) {
sprintf(buff, "%d", termconf->default_bg);
else if (streq(token, "debugbar")) {
sprintf(buff, "%d", termconf->debugbar);
tplSend(connData, buff, -1);
}
@@ -56,7 +44,7 @@ tplAbout(HttpdConnData *connData, char *token, void **arg)
if (token == NULL) return HTTPD_CGI_DONE;
if (streq(token, "vers_fw")) {
tplSend(connData, FIRMWARE_VERSION, -1);
tplSend(connData, VERSION_STRING, -1);
}
else if (streq(token, "date")) {
tplSend(connData, __DATE__, -1);
@@ -68,7 +56,6 @@ tplAbout(HttpdConnData *connData, char *token, void **arg)
tplSend(connData, httpdGetVersion(), -1);
}
else if (streq(token, "vers_sdk")) {
//tplSend(connData, STR(ESP_SDK_VERSION), -1);
tplSend(connData, system_get_sdk_version(), -1);
}
else if (streq(token, "hash_backend")) {
+59 -71
View File
@@ -16,20 +16,22 @@
// Must be less than httpd sendbuf
#define SOCK_BUF_LEN 2000
volatile ScreenNotifyTopics pendingBroadcastTopics = 0;
// flags for screen update timeouts
volatile bool notify_available = true;
volatile bool notify_cooldown = false;
volatile bool notify_scheduled = false;
/** True if we sent XOFF to browser to stop uploading,
* and we have to tell it we're ready again */
volatile bool browser_wants_xon = false;
static ETSTimer notifyContentTim;
static ETSTimer notifyLabelsTim;
static ETSTimer updateNotifyTim;
static ETSTimer notifyCooldownTim;
static ETSTimer heartbeatTim;
volatile int active_clients = 0;
volatile int term_active_clients = 0;
// we're trying to do a kind of mutex here, without the actual primitives
// this might glitch, very rarely.
@@ -52,26 +54,22 @@ notifyCooldownTimCb(void *arg)
* @param arg
*/
static void ICACHE_FLASH_ATTR
notifyContentTimCb(void *arg)
updateNotify_do(Websock *ws, ScreenNotifyTopics topics)
{
Websock *ws = arg;
void *data = NULL;
int max_bl, total_bl;
char sock_buff[SOCK_BUF_LEN];
cgiWebsockMeasureBacklog(URL_WS_UPDATE, &max_bl, &total_bl);
if (!notify_available || notify_cooldown || (max_bl > 2048)) { // do not send if we have anything significant backlogged
// postpone a little
TIMER_START(&notifyContentTim, notifyContentTimCb, 4, 0);
inp_dbg("postpone notify content");
return;
}
notify_available = false;
for (int i = 0; i < 20; i++) {
httpd_cgi_state cont = screenSerializeToBuffer(sock_buff, SOCK_BUF_LEN, &data);
int flg = 0;
if (! ws) {
// broadcast
topics = pendingBroadcastTopics;
pendingBroadcastTopics = 0;
}
httpd_cgi_state cont = screenSerializeToBuffer(sock_buff, SOCK_BUF_LEN, topics, &data);
int flg = 0; //WEBSOCK_FLAG_BIN
if (cont == HTTPD_CGI_MORE) flg |= WEBSOCK_FLAG_MORE;
if (i > 0) flg |= WEBSOCK_FLAG_CONT;
if (ws) {
@@ -86,56 +84,45 @@ notifyContentTimCb(void *arg)
}
// cleanup
screenSerializeToBuffer(NULL, SOCK_BUF_LEN, &data);
screenSerializeToBuffer(NULL, 0, 0, &data);
notify_cooldown = true;
notify_available = true;
TIMER_START(&notifyCooldownTim, notifyCooldownTimCb, termconf->display_cooldown_ms, 0);
}
/**
* Tell browsers about the new text labels
* Tell browser we have new content
* @param arg
*/
static void ICACHE_FLASH_ATTR
notifyLabelsTimCb(void *arg)
updateNotifyCb(void *arg)
{
Websock *ws = arg;
char sock_buff[SOCK_BUF_LEN];
int max_bl, total_bl;
cgiWebsockMeasureBacklog(URL_WS_UPDATE, &max_bl, &total_bl);
if (!notify_available || notify_cooldown) {
inp_dbg("Notify broadcast +%02Xh?", pendingBroadcastTopics);
if (!notify_available || notify_cooldown || (max_bl > 2048)) { // do not send if we have anything significant backlogged
// postpone a little
TIMER_START(&notifyLabelsTim, notifyLabelsTimCb, 7, 0);
inp_dbg("postpone notify labels");
TIMER_START(&updateNotifyTim, updateNotifyCb, 4, 0);
inp_dbg("postpone notify; avail? %d coold? %d maxbl? %d", notify_available, notify_cooldown, max_bl);
return;
}
notify_available = false;
screenSerializeLabelsToBuffer(sock_buff, SOCK_BUF_LEN);
if (ws) {
cgiWebsocketSend(ws, sock_buff, (int) strlen(sock_buff), 0);
} else {
cgiWebsockBroadcast(URL_WS_UPDATE, sock_buff, (int) strlen(sock_buff), 0);
resetHeartbeatTimer();
}
updateNotify_do(arg, 0);
notify_scheduled = false;
notify_cooldown = true;
notify_available = true;
TIMER_START(&notifyCooldownTim, notifyCooldownTimCb, termconf->display_cooldown_ms, 0);
}
/** Beep */
void ICACHE_FLASH_ATTR
send_beep(void)
{
if (active_clients == 0) return;
// here's some potential for a race error with the other broadcast functions :C
cgiWebsockBroadcast(URL_WS_UPDATE, "B", 1, 0);
resetHeartbeatTimer();
if (term_active_clients == 0) return;
screen_notifyChange(TOPIC_BELL); // XXX has latency, maybe better to send directly
}
@@ -143,11 +130,11 @@ send_beep(void)
void ICACHE_FLASH_ATTR
notify_growl(char *msg)
{
if (active_clients == 0) return;
if (term_active_clients == 0) return;
// TODO via timer...
// here's some potential for a race error with the other broadcast functions :C
cgiWebsockBroadcast(URL_WS_UPDATE, msg, (int) strlen(msg), 0);
// here's some potential for a race error with the other broadcast functions
// - we assume app won't send notifications in the middle of updating content
cgiWebsockBroadcast(URL_WS_UPDATE, msg, (int) strlen(msg), WEBSOCK_FLAG_BIN);
resetHeartbeatTimer();
}
@@ -157,24 +144,20 @@ notify_growl(char *msg)
* This is a callback for the Screen module,
* called after each visible screen modification.
*/
void ICACHE_FLASH_ATTR screen_notifyChange(ScreenNotifyChangeTopic topic)
void ICACHE_FLASH_ATTR screen_notifyChange(ScreenNotifyTopics topics)
{
if (active_clients == 0) return;
if (term_active_clients == 0) return;
// this is probably not needed here - ensure timeout is not 0
if (termconf->display_tout_ms == 0)
termconf->display_tout_ms = SCR_DEF_DISPLAY_TOUT_MS;
inp_dbg("Notify +%02Xh", topics);
// NOTE: the timers are restarted if already running
pendingBroadcastTopics |= topics;
if (topic == CHANGE_LABELS) {
// separate timer from content change timer, to avoid losing that update
TIMER_START(&notifyLabelsTim, notifyLabelsTimCb, termconf->display_tout_ms+2, 0); // this delay is useful when both are fired at once on screen reset
}
else if (topic == CHANGE_CONTENT) {
// throttle delay
TIMER_START(&notifyContentTim, notifyContentTimCb, termconf->display_tout_ms, 0);
}
int time = termconf->display_tout_ms;
if (time == 0 && notify_scheduled) return; // do not reset the timer if already scheduled
notify_scheduled = true;
// NOTE: the timer is restarted if already running
TIMER_START(&updateNotifyTim, updateNotifyCb, time, 0); // note - this adds latency to beep
}
/**
@@ -277,7 +260,7 @@ static void ICACHE_FLASH_ATTR updateSockRx(Websock *ws, char *data, int len, int
// TODO base this on the actual buffer empty space, not rx chunk size
if ((UART_AsyncTxGetEmptySpace() < 256) && !browser_wants_xon) {
UART_WriteChar(UART1, '-', 100);
//UART_WriteChar(UART1, '-', 100);
cgiWebsockBroadcast(URL_WS_UPDATE, "-", 1, 0);
browser_wants_xon = true;
@@ -296,8 +279,7 @@ static void ICACHE_FLASH_ATTR updateSockRx(Websock *ws, char *data, int len, int
case 'i':
// requests initial load
inp_dbg("Client requests initial load");
notifyContentTimCb(ws); // delay??
notifyLabelsTimCb(ws);
updateNotify_do(ws, TOPIC_INITIAL|TOPIC_FLAG_NOCLEAN);
break;
case 'm':
@@ -322,13 +304,17 @@ static void ICACHE_FLASH_ATTR updateSockRx(Websock *ws, char *data, int len, int
/** Send a heartbeat msg */
static void ICACHE_FLASH_ATTR heartbeatTimCb(void *unused)
{
if (active_clients > 0) {
static u32 hbcnt=0;
if (term_active_clients > 0) {
if (notify_available) {
inp_dbg(".");
// Heartbeat packet - indicate we're still connected
// JS reloads the page if heartbeat is lost for a couple seconds
cgiWebsockBroadcast(URL_WS_UPDATE, ".", 1, 0);
char buf[10];
sprintf(buf, ".%d", hbcnt++);
cgiWebsockBroadcast(URL_WS_UPDATE, buf, (int) strlen(buf), 0);
// schedule next tick
TIMER_START(&heartbeatTim, heartbeatTimCb, HB_TIME, 0);
@@ -348,9 +334,10 @@ static void ICACHE_FLASH_ATTR resetHeartbeatTimer(void)
static void ICACHE_FLASH_ATTR closeSockCb(Websock *ws)
{
active_clients--;
if (active_clients <= 0) {
active_clients = 0;
term_active_clients--;
inp_dbg("Close socket CB, remain %d clients", term_active_clients);
if (term_active_clients <= 0) {
term_active_clients = 0;
if (mouse_tracking.focus_tracking) {
UART_SendAsync("\x1b[O", 3);
@@ -358,6 +345,7 @@ static void ICACHE_FLASH_ATTR closeSockCb(Websock *ws)
// stop the timer
os_timer_disarm(&heartbeatTim);
inp_dbg("Stop HB timer");
}
}
@@ -368,7 +356,7 @@ void ICACHE_FLASH_ATTR updateSockConnect(Websock *ws)
ws->recvCb = updateSockRx;
ws->closeCb = closeSockCb;
if (active_clients == 0) {
if (term_active_clients == 0) {
if (mouse_tracking.focus_tracking) {
UART_SendAsync("\x1b[I", 3);
}
@@ -376,14 +364,14 @@ void ICACHE_FLASH_ATTR updateSockConnect(Websock *ws)
resetHeartbeatTimer();
}
active_clients++;
term_active_clients++;
}
ETSTimer xonTim;
static void ICACHE_FLASH_ATTR notify_empty_txbuf_cb(void *unused)
{
UART_WriteChar(UART1, '+', 100);
//UART_WriteChar(UART1, '+', 100);
cgiWebsockBroadcast(URL_WS_UPDATE, "+", 1, 0);
resetHeartbeatTimer();
browser_wants_xon = false;
+2
View File
@@ -15,6 +15,8 @@ void send_beep(void);
/** open pop-up notification */
void notify_growl(char *msg);
extern volatile int term_active_clients;
// defined in the makefile
#if DEBUG_INPUT
#define inp_warn warn
+2 -2
View File
@@ -50,7 +50,7 @@ httpd_cgi_state ICACHE_FLASH_ATTR cgiResetDevice(HttpdConnData *connData)
os_timer_setfn(&tmr, tmrCb, NULL);
os_timer_arm(&tmr, 100, false);
httpdSend(connData, "system reset\n", -1);
httpdSend(connData, "system reset\r\n", -1);
return HTTPD_CGI_DONE;
}
@@ -66,7 +66,7 @@ httpd_cgi_state ICACHE_FLASH_ATTR cgiPing(HttpdConnData *connData)
httpdHeader(connData, "Content-Type", "text/plain");
httpdEndHeaders(connData);
httpdSend(connData, "pong\n", -1);
httpdSend(connData, "pong\r\n", -1);
return HTTPD_CGI_DONE;
}
+57 -19
View File
@@ -40,7 +40,7 @@ cgiTermCfgSetParams(HttpdConnData *connData)
char buff[50];
char redir_url_buf[100];
int32 n, w, h;
bool notify_screen_content = 0, notify_screen_labels = 0;
ScreenNotifyTopics topics = 0;
bool shall_clear_screen = false;
bool shall_init_uart = false;
@@ -94,7 +94,8 @@ cgiTermCfgSetParams(HttpdConnData *connData)
if (termconf->width != w || termconf->height != h) {
termconf->width = w;
termconf->height = h;
shall_clear_screen = true; // this causes a notify
shall_clear_screen = true;
topics |= TOPIC_CHANGE_SCREEN_OPTS | TOPIC_CHANGE_CONTENT_ALL;
}
} while (0);
}
@@ -112,6 +113,7 @@ cgiTermCfgSetParams(HttpdConnData *connData)
if (termconf->default_bg != n) {
termconf->default_bg = n; // this is current not sent through socket, no use to notify
topics |= TOPIC_CHANGE_SCREEN_OPTS;
}
}
@@ -128,6 +130,7 @@ cgiTermCfgSetParams(HttpdConnData *connData)
if (termconf->default_fg != n) {
termconf->default_fg = n; // this is current not sent through socket, no use to notify
topics |= TOPIC_CHANGE_SCREEN_OPTS;
}
}
@@ -145,7 +148,7 @@ cgiTermCfgSetParams(HttpdConnData *connData)
if (GET_ARG("display_tout_ms")) {
cgi_dbg("Display update idle timeout: %s ms", buff);
n = atoi(buff);
if (n > 0) {
if (n >= 0) {
termconf->display_tout_ms = n;
} else {
cgi_warn("Bad update timeout %s", buff);
@@ -168,40 +171,62 @@ cgiTermCfgSetParams(HttpdConnData *connData)
cgi_dbg("FN alt mode: %s", buff);
n = atoi(buff);
termconf->fn_alt_mode = (bool)n;
notify_screen_content = true;
topics |= TOPIC_CHANGE_SCREEN_OPTS;
}
if (GET_ARG("want_all_fn")) {
cgi_dbg("AllFN mode: %s", buff);
n = atoi(buff);
termconf->want_all_fn = (bool)n;
topics |= TOPIC_CHANGE_SCREEN_OPTS;
}
if (GET_ARG("crlf_mode")) {
cgi_dbg("CRLF mode: %s", buff);
n = atoi(buff);
termconf->crlf_mode = (bool)n;
notify_screen_content = true;
topics |= TOPIC_CHANGE_SCREEN_OPTS;
}
if (GET_ARG("show_buttons")) {
cgi_dbg("Show buttons: %s", buff);
n = atoi(buff);
termconf->show_buttons = (bool)n;
notify_screen_content = true;
topics |= TOPIC_CHANGE_SCREEN_OPTS;
}
if (GET_ARG("show_config_links")) {
cgi_dbg("Show config links: %s", buff);
n = atoi(buff);
termconf->show_config_links = (bool)n;
notify_screen_content = true;
topics |= TOPIC_CHANGE_SCREEN_OPTS;
}
if (GET_ARG("loopback")) {
cgi_dbg("Loopback: %s", buff);
n = atoi(buff);
termconf->loopback = (bool)n;
topics |= TOPIC_CHANGE_SCREEN_OPTS;
}
if (GET_ARG("debugbar")) {
cgi_dbg("Debugbar: %s", buff);
n = atoi(buff);
termconf->debugbar = (bool)n;
topics |= TOPIC_CHANGE_SCREEN_OPTS;
}
if (GET_ARG("allow_decopt_12")) {
cgi_dbg("DECOPT 12: %s", buff);
n = atoi(buff);
termconf->allow_decopt_12 = (bool)n;
}
if (GET_ARG("ascii_debug")) {
cgi_dbg("ascii_debug: %s", buff);
n = atoi(buff);
termconf->ascii_debug = (bool)n;
shall_clear_screen = true;
}
if (GET_ARG("theme")) {
@@ -213,6 +238,7 @@ cgiTermCfgSetParams(HttpdConnData *connData)
} else {
cgi_warn("Bad theme num: %s", buff);
redir_url += sprintf(redir_url, "theme,");
topics |= TOPIC_CHANGE_SCREEN_OPTS;
}
}
@@ -221,7 +247,7 @@ cgiTermCfgSetParams(HttpdConnData *connData)
n = atoi(buff);
if (n >= 0 && n <= 6 && n != 1) {
termconf->cursor_shape = (enum CursorShape) n;
notify_screen_content = true;
topics |= TOPIC_CHANGE_SCREEN_OPTS;
} else {
cgi_warn("Bad cursor_shape num: %s", buff);
redir_url += sprintf(redir_url, "cursor_shape,");
@@ -230,8 +256,14 @@ cgiTermCfgSetParams(HttpdConnData *connData)
if (GET_ARG("term_title")) {
cgi_dbg("Terminal title default text: \"%s\"", buff);
strncpy_safe(termconf->title, buff, 64); // ATTN those must match the values in
notify_screen_labels = true;
strncpy_safe(termconf->title, buff, TERM_TITLE_LEN); // ATTN those must match the values in
topics |= TOPIC_CHANGE_TITLE;
}
if (GET_ARG("backdrop")) {
cgi_dbg("Terminal backdrop url: \"%s\"", buff);
strncpy_safe(termconf->backdrop, buff, TERM_BACKDROP_LEN); // ATTN those must match the values in
topics |= TOPIC_CHANGE_BACKDROP;
}
for (int btn_i = 1; btn_i <= TERM_BTN_COUNT; btn_i++) {
@@ -239,7 +271,7 @@ cgiTermCfgSetParams(HttpdConnData *connData)
if (GET_ARG(buff)) {
cgi_dbg("Button%d default text: \"%s\"", btn_i, buff);
strncpy_safe(termconf->btn[btn_i-1], buff, TERM_BTN_LEN);
notify_screen_labels = true;
topics |= TOPIC_CHANGE_BUTTONS;
}
sprintf(buff, "bm%d", btn_i);
@@ -368,13 +400,7 @@ cgiTermCfgSetParams(HttpdConnData *connData)
serialInit();
}
if (notify_screen_content) {
screen_notifyChange(CHANGE_CONTENT);
}
if (notify_screen_labels) {
screen_notifyChange(CHANGE_LABELS);
}
if (topics) screen_notifyChange(topics);
httpdRedirect(connData, SET_REDIR_SUC "?msg=Settings%20saved%20and%20applied.");
} else {
@@ -396,7 +422,7 @@ cgiTermCfgSetParams(HttpdConnData *connData)
httpd_cgi_state ICACHE_FLASH_ATTR
tplTermCfg(HttpdConnData *connData, char *token, void **arg)
{
#define BUFLEN TERM_TITLE_LEN
#define BUFLEN 100 // large enough for backdrop
char buff[BUFLEN];
char buff2[10];
@@ -437,9 +463,18 @@ tplTermCfg(HttpdConnData *connData, char *token, void **arg)
else if (streq(token, "show_config_links")) {
sprintf(buff, "%d", (int)termconf->show_config_links);
}
else if (streq(token, "allow_decopt_12")) {
sprintf(buff, "%d", (int)termconf->allow_decopt_12);
}
else if (streq(token, "ascii_debug")) {
sprintf(buff, "%d", (int)termconf->ascii_debug);
}
else if (streq(token, "loopback")) {
sprintf(buff, "%d", (int)termconf->loopback);
}
else if (streq(token, "debugbar")) {
sprintf(buff, "%d", (int)termconf->debugbar);
}
else if (streq(token, "theme")) {
sprintf(buff, "%d", termconf->theme);
}
@@ -463,6 +498,9 @@ tplTermCfg(HttpdConnData *connData, char *token, void **arg)
else if (streq(token, "term_title")) {
strncpy_safe(buff, termconf->title, BUFLEN);
}
else if (streq(token, "backdrop")) {
strncpy_safe(buff, termconf->backdrop, BUFLEN);
}
else if (streq(token, "uart_baud")) {
sprintf(buff, "%d", sysconf->uart_baudrate);
}
+1 -16
View File
@@ -617,22 +617,7 @@ httpd_cgi_state ICACHE_FLASH_ATTR tplWlan(HttpdConnData *connData, char *token,
}
}
else if (streq(token, "sta_active_ip")) {
x = wifi_get_opmode();
connectStatus = wifi_station_get_connect_status();
if (x == SOFTAP_MODE || connectStatus != STATION_GOT_IP || wificonf->opmode == SOFTAP_MODE) {
strcpy(buff, "");
}
else {
struct ip_info info;
wifi_get_ip_info(STATION_IF, &info);
sprintf(buff, IPSTR, GOOD_IP2STR(info.ip.addr));
// sprintf(buff, "ip: "IPSTR", mask: "IPSTR", gw: "IPSTR,
// GOOD_IP2STR(info.ip.addr),
// GOOD_IP2STR(info.netmask.addr),
// GOOD_IP2STR(info.gw.addr));
}
getStaIpAsString(buff);
}
tplSend(connData, buff, -1);
+336 -127
View File
@@ -19,143 +19,352 @@
* Based on rxvt-unicode screen.C table.
*/
static const u16 codepage_0[] ESP_CONST_DATA =
{// Unicode ASCII SYM
{ // Unicode ASCII SYM
// %%BEGIN:0%%
0x2666, // 96 `
0x2592, // 97 a
0x2409, // 98 b HT
0x240c, // 99 c FF
0x240d, // 100 d CR
0x240a, // 101 e LF
0x00b0, // 102 f °
0x00b1, // 103 g ±
0x2424, // 104 h NL
0x240b, // 105 i VT
0x2518, // 106 j
0x2510, // 107 k
0x250c, // 108 l
0x2514, // 109 m
0x253c, // 110 n
0x23ba, // 111 o
0x23bb, // 112 p
0x2500, // 113 q
0x23bc, // 114 r
0x23bd, // 115 s
0x251c, // 116 t
0x2524, // 117 u
0x2534, // 118 v
0x252c, // 119 w
0x2502, // 120 x
0x2264, // 121 y
0x2265, // 122 z
0x03c0, // 123 { π
0x2260, // 124 |
0x20a4, // 125 } £
0x00b7, // 126 ~ ·
u'', // 0x2666 96 `
u'', // 0x2592 97 a
u'', // 0x2409 98 b
u'', // 0x240c 99 c FF
u'', // 0x240d 100 d CR
u'', // 0x240a 101 e LF
u'°', // 0x00b0 102 f
u'±', // 0x00b1 103 g
u'', // 0x2424 104 h NL
u'', // 0x240b 105 i VT
u'', // 0x2518 106 j
u'', // 0x2510 107 k
u'', // 0x250c 108 l
u'', // 0x2514 109 m
u'', // 0x253c 110 n
u'', // 0x23ba 111 o
u'', // 0x23bb 112 p
u'', // 0x2500 113 q
u'', // 0x23bc 114 r
u'', // 0x23bd 115 s
u'', // 0x251c 116 t
u'', // 0x2524 117 u
u'', // 0x2534 118 v
u'', // 0x252c 119 w
u'', // 0x2502 120 x
u'', // 0x2264 121 y
u'', // 0x2265 122 z
u'π', // 0x03c0 123 {
u'', // 0x2260 124 |
u'£', // 0x20a4 125 }
u'·', // 0x00b7 126 ~
// %%END:0%%
};
#define CODEPAGE_1_BEGIN 33
#define CODEPAGE_1_END 126
// DOS, thin and double lines, arrows, angles, diagonals, thick border
static const u16 codepage_1[] ESP_CONST_DATA =
{// Unicode ASCII SYM DOS
{// Unicode ASCII DOS
// %%BEGIN:1%%
0x263A, // 33 ! (1) - low ASCII symbols from DOS, moved to +32
0x263B, // 34 " (2)
0x2665, // 35 # (3)
0x2666, // 36 $ (4)
0x2663, // 37 % (5)
0x2660, // 38 & (6)
0x2022, // 39 ' (7) - inverse dot and circle left out, can be done with SGR
0x231B, // 40 ( ⌛ - hourglass (timer icon)
0x25CB, // 41 ) (9)
0x21AF, // 42 * ↯ - electricity (lightning monitor...)
0x266A, // 43 + (13)
0x266B, // 44 , (14)
0x263C, // 45 - (15)
0x2302, // 46 . (127)
0x2622, // 47 / ☢ - radioactivity (geiger counter...)
0x2591, // 48 0 (176) - this block is kept aligned and ordered from DOS, moved -128
0x2592, // 49 1 (177)
0x2593, // 50 2 (178)
0x2502, // 51 3 (179)
0x2524, // 52 4 (180)
0x2561, // 53 5 (181)
0x2562, // 54 6 (182)
0x2556, // 55 7 (183)
0x2555, // 56 8 (184)
0x2563, // 57 9 (185)
0x2551, // 58 : (186)
0x2557, // 59 ; (187)
0x255D, // 60 < (188)
0x255C, // 61 = (189)
0x255B, // 62 > (190)
0x2510, // 63 ? (191)
0x2514, // 64 @ (192)
0x2534, // 65 A (193)
0x252C, // 66 B (194)
0x251C, // 67 C (195)
0x2500, // 68 D (196)
0x253C, // 69 E (197)
0x255E, // 70 F (198)
0x255F, // 71 G (199)
0x255A, // 72 H (200)
0x2554, // 73 I (201)
0x2569, // 74 J (202)
0x2566, // 75 K (203)
0x2560, // 76 L (204)
0x2550, // 77 M (205)
0x256C, // 78 N (206)
0x2567, // 79 O (207)
0x2568, // 80 P (208)
0x2564, // 81 Q (209)
0x2565, // 82 R (210)
0x2559, // 83 S (211)
0x2558, // 84 T (212)
0x2552, // 85 U (213)
0x2553, // 86 V (214)
0x256B, // 87 W (215)
0x256A, // 88 X (216)
0x2518, // 89 Y (217)
0x250C, // 90 Z (218)
0x2588, // 91 [ (219)
0x2584, // 92 \ (220)
0x258C, // 93 ] (221)
0x2590, // 94 ^ (222)
0x2580, // 95 _ (223)
0x2195, // 96 ` (18) - moved from low DOS ASCII
0x2191, // 97 a (24)
0x2193, // 98 b (25)
0x2192, // 99 c (26)
0x2190, // 100 d (27)
0x2194, // 101 e (29)
0x25B2, // 102 f (30)
0x25BC, // 103 g (31)
0x25BA, // 104 h (16)
0x25C4, // 105 i (17)
0x25E2, // 106 j ◢ - added for slanted corners
0x25E3, // 107 k
0x25E4, // 108 l
0x25E5, // 109 m
0x256D, // 110 n ╭ - rounded corners
0x256E, // 111 o
0x256F, // 112 p
0x2570, // 113 q
0x0, // 114 r - free positions for future expansion
0x0, // 115 s
0x0, // 116 t
0x0, // 117 u
0x0, // 118 v
0x0, // 119 w
0x0, // 120 x
0x0, // 121 y
0x0, // 122 z
0x0, // 123 {
0x0, // 124 |
0x2714, // 125 } ✔ - checkboxes or checklist items
0x2718, // 126 ~
u'', // 0x263A, 33 ! (1) - low ASCII symbols from DOS, moved to +32
u'', // 0x263B, 34 " (2)
u'', // 0x2665, 35 # (3)
u'', // 0x2666, 36 $ (4)
u'', // 0x2663, 37 % (5)
u'', // 0x2660, 38 & (6)
u'', // 0x2022, 39 ' (7) - inverse dot and circle left out, can be done with SGR
u'', // 0x231B, 40 ( - hourglass (timer icon)
u'', // 0x25CB, 41 ) (9)
u'', // 0x21AF, 42 * - electricity (lightning monitor...)
u'', // 0x266A, 43 + (13)
u'', // 0x266B, 44 , (14)
u'', // 0x263C, 45 - (15)
u'', // 0x2302, 46 . (127)
u'', // 0x2622, 47 / - radioactivity (geiger counter...)
u'', // 0x2591, 48 0 (176) - this block is kept aligned and ordered from DOS, moved -128
u'', // 0x2592, 49 1 (177)
u'', // 0x2593, 50 2 (178)
u'', // 0x2502, 51 3 (179)
u'', // 0x2524, 52 4 (180)
u'', // 0x2561, 53 5 (181)
u'', // 0x2562, 54 6 (182)
u'', // 0x2556, 55 7 (183)
u'', // 0x2555, 56 8 (184)
u'', // 0x2563, 57 9 (185)
u'', // 0x2551, 58 : (186)
u'', // 0x2557, 59 ; (187)
u'', // 0x255D, 60 < (188)
u'', // 0x255C, 61 = (189)
u'', // 0x255B, 62 > (190)
u'', // 0x2510, 63 ? (191)
u'', // 0x2514, 64 @ (192)
u'', // 0x2534, 65 A (193)
u'', // 0x252C, 66 B (194)
u'', // 0x251C, 67 C (195)
u'', // 0x2500, 68 D (196)
u'', // 0x253C, 69 E (197)
u'', // 0x255E, 70 F (198)
u'', // 0x255F, 71 G (199)
u'', // 0x255A, 72 H (200)
u'', // 0x2554, 73 I (201)
u'', // 0x2569, 74 J (202)
u'', // 0x2566, 75 K (203)
u'', // 0x2560, 76 L (204)
u'', // 0x2550, 77 M (205)
u'', // 0x256C, 78 N (206)
u'', // 0x2567, 79 O (207)
u'', // 0x2568, 80 P (208)
u'', // 0x2564, 81 Q (209)
u'', // 0x2565, 82 R (210)
u'', // 0x2559, 83 S (211)
u'', // 0x2558, 84 T (212)
u'', // 0x2552, 85 U (213)
u'', // 0x2553, 86 V (214)
u'', // 0x256B, 87 W (215)
u'', // 0x256A, 88 X (216)
u'', // 0x2518, 89 Y (217)
u'', // 0x250C, 90 Z (218)
u'', // 0x2588, 91 [ (219)
u'', // 0x2584, 92 \ (220)
u'', // 0x258C, 93 ] (221)
u'', // 0x2590, 94 ^ (222)
u'', // 0x2580, 95 _ (223)
u'', // 0x2195, 96 ` (18) - moved from low DOS ASCII
u'', // 0x2191, 97 a (24)
u'', // 0x2193, 98 b (25)
u'', // 0x2192, 99 c (26)
u'', // 0x2190, 100 d (27)
u'', // 0x2194, 101 e (29)
u'', // 0x25B2, 102 f (30)
u'', // 0x25BC, 103 g (31)
u'', // 0x25BA, 104 h (16)
u'', // 0x25C4, 105 i (17)
u'', // 0x25E2, 106 j - added for slanted corners
u'', // 0x25E3, 107 k
u'', // 0x25E4, 108 l
u'', // 0x25E5, 109 m
u'', // 0x256D, 110 n - rounded corners
u'', // 0x256E, 111 o
u'', // 0x256F, 112 p
u'', // 0x2570, 113 q
u'', // 0x0, 114 r - right up diagonal
u'', // 0x0, 115 s - right down diagonal
u'', // 0x0, 116 t
u'', // 0x0, 117 u
u'', // 0x0, 118 v
u'', // 0x0, 119 w
u'', // 0x0, 120 x
0xE0B0, // powerline right triangle (filled), 121 y
0xE0B1, // powerline right triangle (hollow), 122 z
0xE0B2, // powerline left triangle (filled), 123 {
0xE0B3, // powerline left triangle (hollow), 124 | - reserved
u'', // 0x2714, 125 } - checkboxes or checklist items
u'', // 0x2718, 126 ~
// %%END:1%%
};
#define CODEPAGE_2_BEGIN 33
#define CODEPAGE_2_END 126
// blocks, thick and split lines, line butts
static const u16 codepage_2[] ESP_CONST_DATA =
{// Unicode ASCII DOS
// %%BEGIN:2%%
u'', // 0x2581, 33 ! - those are ordered this way to allow easy calculating of the right code (for graphs)
u'', // 0x2582, 34 "
u'', // 0x2583, 35 #
u'', // 0x2584, 36 $
u'', // 0x2585, 37 %
u'', // 0x2586, 38 &
u'', // 0x2587, 39 ' - 7-eighths
u'', // 0x2588, 40 ( - full block, shared by both sequences
u'', // 0x2589, 41 ) - those grow thinner, to re-use the full block
u'', // 0x258A, 42 *
u'', // 0x258B, 43 +
u'', // 0x258C, 44 ,
u'', // 0x258D, 45 -
u'', // 0x258E, 46 .
u'', // 0x258F, 47 /
u'', // 0x2594, 48 0 - complementary symbols
u'', // 0x2595, 49 1
u'', // 0x2590, 50 2
u'', // 0x2580, 51 3
u'', // 0x2598, 52 4 - top-left, top-right, bottom-right, bottom-left
u'', // 0x259D, 53 5
u'', // 0x2597, 54 6
u'', // 0x2596, 55 7
u'', // 0x259F, 56 8
u'', // 0x2599, 57 9
u'', // 0x259B, 58 :
u'', // 0x259C, 59 ;
u'', // 0x259E, 60 < - complementary diagonals
u'', // 0x259A, 61 =
u'', // 0x, 62 > - here are thick and thin lines and their joins. it's really quite arbitrary, based on the unicode order, excluding single lines
u'', // 0x, 63 ?
u'', // 0x, 64 @
u'', // 0x, 65 A
u'', // 0x, 66 B
u'', // 0x, 67 C
u'', // 0x, 68 D
u'', // 0x, 69 E
u'', // 0x, 70 F
u'', // 0x, 71 G
u'', // 0x, 72 H
u'', // 0x, 73 I
u'', // 0x, 74 J
u'', // 0x, 75 K
u'', // 0x, 76 L
u'', // 0x, 77 M
u'', // 0x, 78 N
u'', // 0x, 79 O
u'', // 0x, 80 P
u'', // 0x, 81 Q
u'', // 0x, 82 R
u'', // 0x, 83 S
u'', // 0x, 84 T
u'', // 0x, 85 U
u'', // 0x, 86 V
u'', // 0x, 87 W
u'', // 0x, 88 X
u'', // 0x, 89 Y
u'', // 0x, 90 Z
u'', // 0x, 91 [
u'', // 0x, 92 \ .
u'', // 0x, 93 ]
u'', // 0x, 94 ^
u'', // 0x, 95 _
u'', // 0x, 96 `
u'', // 0x, 97 a
u'', // 0x, 98 b
u'', // 0x, 99 c
u'', // 0x, 100 d
u'', // 0x, 101 e
u'', // 0x, 102 f
u'', // 0x, 103 g
u'', // 0x, 104 h
u'', // 0x, 105 i
u'', // 0x, 106 j
u'', // 0x, 107 k
u'', // 0x, 108 l
u'', // 0x, 109 m
u'', // 0x, 110 n
u'', // 0x, 111 o
u'', // 0x, 112 p
u'', // 0x, 113 q
u'', // 0x, 114 r
u'', // 0x, 115 s
u'', // 0x, 116 t
u'', // 0x, 117 u
u'', // 0x, 118 v
u'', // 0x, 119 w - butts
u'', // 0x, 120 x
u'', // 0x, 121 y
u'', // 0x, 122 z
u'', // 0x, 123 {
u'', // 0x, 124 |
u'', // 0x, 125 }
u'', // 0x, 126 ~
// %%END:2%%
};
#define CODEPAGE_3_BEGIN 33
#define CODEPAGE_3_END 48
// dashed lines, split straight lines
static const u16 codepage_3[] ESP_CONST_DATA =
{// Unicode ASCII DOS
// %%BEGIN:3%%
u'', // 0x, 33 !
u'', // 0x, 34 "
u'', // 0x, 35 #
u'', // 0x, 36 $
u'', // 0x, 37 %
u'', // 0x, 38 &
u'', // 0x, 39 '
u'', // 0x, 40 (
u'', // 0x, 41 )
u'', // 0x, 42 *
u'', // 0x, 43 +
u'', // 0x, 44 ,
u'', // 0x, 45 -
u'', // 0x, 46 .
u'', // 0x, 47 /
u'', // 0x, 48 0
// %%END:3%%
// u'\0', // 0x, 49 1
// u'\0', // 0x, 50 2
// u'\0', // 0x, 51 3
// u'\0', // 0x, 52 4
// u'\0', // 0x, 53 5
// u'\0', // 0x, 54 6
// u'\0', // 0x, 55 7
// u'\0', // 0x, 56 8
// u'\0', // 0x, 57 9
// u'\0', // 0x, 58 :
// u'\0', // 0x, 59 ;
// u'\0', // 0x, 60 <
// u'\0', // 0x, 61 =
// u'\0', // 0x, 62 >
// u'\0', // 0x, 63 ?
// u'\0', // 0x, 64 @
// u'\0', // 0x, 65 A
// u'\0', // 0x, 66 B
// u'\0', // 0x, 67 C
// u'\0', // 0x, 68 D
// u'\0', // 0x, 69 E
// u'\0', // 0x, 70 F
// u'\0', // 0x, 71 G
// u'\0', // 0x, 72 H
// u'\0', // 0x, 73 I
// u'\0', // 0x, 74 J
// u'\0', // 0x, 75 K
// u'\0', // 0x, 76 L
// u'\0', // 0x, 77 M
// u'\0', // 0x, 78 N
// u'\0', // 0x, 79 O
// u'\0', // 0x, 80 P
// u'\0', // 0x, 81 Q
// u'\0', // 0x, 82 R
// u'\0', // 0x, 83 S
// u'\0', // 0x, 84 T
// u'\0', // 0x, 85 U
// u'\0', // 0x, 86 V
// u'\0', // 0x, 87 W
// u'\0', // 0x, 88 X
// u'\0', // 0x, 89 Y
// u'\0', // 0x, 90 Z
// u'\0', // 0x, 91 [
// u'\0', // 0x, 92 \ .
// u'\0', // 0x, 93 ]
// u'\0', // 0x, 94 ^
// u'\0', // 0x, 95 _
// u'\0', // 0x, 96 `
// u'\0', // 0x, 97 a
// u'\0', // 0x, 98 b
// u'\0', // 0x, 99 c
// u'\0', // 0x, 100 d
// u'\0', // 0x, 101 e
// u'\0', // 0x, 102 f
// u'\0', // 0x, 103 g
// u'\0', // 0x, 104 h
// u'\0', // 0x, 105 i
// u'\0', // 0x, 106 j
// u'\0', // 0x, 107 k
// u'\0', // 0x, 108 l
// u'\0', // 0x, 109 m
// u'\0', // 0x, 110 n
// u'\0', // 0x, 111 o
// u'\0', // 0x, 112 p
// u'\0', // 0x, 113 q
// u'\0', // 0x, 114 r
// u'\0', // 0x, 115 s
// u'\0', // 0x, 116 t
// u'\0', // 0x, 117 u
// u'\0', // 0x, 118 v
// u'\0', // 0x, 119 w
// u'\0', // 0x, 120 x
// u'\0', // 0x, 121 y
// u'\0', // 0x, 122 z
// u'\0', // 0x, 123 {
// u'\0', // 0x, 124 |
// u'\0', // 0x, 125 }
// u'\0', // 0x, 126 ~
};
#endif //ESPTERM_CHARACTER_SETS_H_H
+15 -7
View File
@@ -14,6 +14,8 @@
#include "cgi_persist.h"
#include "syscfg.h"
#include "persist.h"
#include "api.h"
#include "cgi_d2d.h"
/**
* Password for WiFi config
@@ -45,7 +47,8 @@ httpd_cgi_state ICACHE_FLASH_ATTR cgiOptionalPwLock(HttpdConnData *connData)
break;
case PWLOCK_SETTINGS_NOTERM:
protect = strstarts(connData->url, "/cfg") && !strstarts(connData->url, "/cfg/term");
protect = strstarts(connData->url, "/cfg") &&
!strstarts(connData->url, "/cfg/term");
break;
case PWLOCK_SETTINGS_ALL:
@@ -53,7 +56,9 @@ httpd_cgi_state ICACHE_FLASH_ATTR cgiOptionalPwLock(HttpdConnData *connData)
break;
case PWLOCK_MENUS:
protect = strstarts(connData->url, "/cfg") || strstarts(connData->url, "/about") || strstarts(connData->url, "/help");
protect = strstarts(connData->url, "/cfg") ||
strstarts(connData->url, "/about") ||
strstarts(connData->url, "/help");
break;
default:
@@ -64,11 +69,11 @@ httpd_cgi_state ICACHE_FLASH_ATTR cgiOptionalPwLock(HttpdConnData *connData)
// pages outside the normal scope
if (sysconf->pwlock > PWLOCK_NONE) {
if (strstarts(connData->url, "/system/reset")) protect = true;
if (strstarts(connData->url, "/api/v1/reboot")) protect = true;
}
if (sysconf->pwlock > PWLOCK_SETTINGS_NOTERM) {
if (strstarts(connData->url, "/system/cls")) protect = true;
if (strstarts(connData->url, "/api/v1/clear")) protect = true;
}
if (sysconf->access_pw[0] == 0) {
@@ -103,9 +108,12 @@ const HttpdBuiltInUrl routes[] ESP_CONST_DATA = {
ROUTE_WS(URL_WS_UPDATE, updateSockConnect),
// --- System control ---
ROUTE_CGI("/system/reset/?", cgiResetDevice),
ROUTE_CGI("/system/ping/?", cgiPing),
ROUTE_CGI("/system/cls/?", cgiResetScreen),
// API endpoints
ROUTE_CGI(API_REBOOT"/?", cgiResetDevice),
ROUTE_CGI(API_PING"/?", cgiPing),
ROUTE_CGI(API_CLEAR"/?", cgiResetScreen),
ROUTE_CGI(API_D2D_MSG"/?", cgiD2DMessage),
ROUTE_REDIRECT("/cfg/?", "/cfg/wifi"),
-3
View File
@@ -6,7 +6,4 @@
extern const HttpdBuiltInUrl routes[];
/** Broadcast screen state to sockets */
void screen_notifyChange();
#endif //ROUTES_H
+558 -156
View File
File diff suppressed because it is too large Load Diff
+60 -27
View File
@@ -34,15 +34,11 @@
*
*/
// Size designed for the terminal config structure
// Must be constant to avoid corrupting user config after upgrade
#define TERMCONF_SIZE 300
#define TERMCONF_VERSION 0
#define TERM_BTN_LEN 10
#define TERM_BTN_MSG_LEN 10
#define TERM_TITLE_LEN 64
#define TERM_BTN_COUNT 5
#define TERM_BACKDROP_LEN 100
#define SCR_DEF_DISPLAY_TOUT_MS 12
#define SCR_DEF_DISPLAY_COOLDOWN_MS 35
@@ -70,10 +66,18 @@ enum CursorShape {
#define SCR_DEF_CURSOR_SHAPE CURSOR_BLOCK_BL
#define SCR_DEF_CRLF 0 // enter sends CRLF
#define SCR_DEF_ALLFN 0 // capture F5 etc
#define SCR_DEF_DEBUGBAR 0
#define SCR_DEF_DECOPT12 0
#define SCR_DEF_ASCIIDEBUG 0
// --- Persistent Settings ---
#define CURSOR_BLINKS(shape) ((shape)==CURSOR_BLOCK_BL||(shape)==CURSOR_UNDERLINE_BL||(shape)==CURSOR_BAR_BL)
// Size designed for the terminal config structure
// Must be constant to avoid corrupting user config after upgrade
#define TERMCONF_SIZE 400
#define TERMCONF_VERSION 4
typedef struct {
u32 width;
u32 height;
@@ -94,6 +98,10 @@ typedef struct {
enum CursorShape cursor_shape;
bool crlf_mode;
bool want_all_fn;
bool debugbar;
bool allow_decopt_12;
bool ascii_debug;
char backdrop[TERM_BACKDROP_LEN];
} TerminalConfigBundle;
// Live config
@@ -142,6 +150,8 @@ void screen_resize(int rows, int cols);
void screen_set_title(const char *title);
/** Set a button text */
void screen_set_button_text(int num, const char *text);
/** Change backdrop */
void screen_set_backdrop(const char *url);
// --- Encoding ---
@@ -150,11 +160,35 @@ typedef enum {
CS_A_UKASCII = 'A',
CS_0_DEC_SUPPLEMENTAL = '0',
CS_1_DOS_437 = '1',
CS_2_BLOCKS_LINES = '2',
CS_3_LINES_EXTRA = '3',
} CHARSET;
httpd_cgi_state screenSerializeToBuffer(char *buffer, size_t buf_len, void **data);
enum ScreenSerializeTopic {
TOPIC_CHANGE_SCREEN_OPTS = (1<<0),
TOPIC_CHANGE_CONTENT_ALL = (1<<1),
TOPIC_CHANGE_CONTENT_PART = (1<<2),
TOPIC_CHANGE_TITLE = (1<<3),
TOPIC_CHANGE_BUTTONS = (1<<4),
TOPIC_CHANGE_CURSOR = (1<<5),
TOPIC_INTERNAL = (1<<6), // debugging internal state
TOPIC_BELL = (1<<7), // beep
TOPIC_CHANGE_BACKDROP = (1<<8),
TOPIC_FLAG_NOCLEAN = (1<<15), // do not clean dirty extents
void screenSerializeLabelsToBuffer(char *buffer, size_t buf_len);
// combos
TOPIC_INITIAL =
TOPIC_CHANGE_SCREEN_OPTS |
TOPIC_CHANGE_CONTENT_ALL |
TOPIC_CHANGE_CURSOR |
TOPIC_CHANGE_TITLE |
TOPIC_CHANGE_BACKDROP |
TOPIC_CHANGE_BUTTONS,
};
typedef u16 ScreenNotifyTopics;
httpd_cgi_state screenSerializeToBuffer(char *buffer, size_t buf_len, ScreenNotifyTopics topics, void **data);
// --- Clearing ---
@@ -223,6 +257,8 @@ void screen_wrap_enable(bool enable);
void screen_reverse_wrap_enable(bool enable);
/** Set scrolling region */
void screen_set_scrolling_region(int from, int to);
/* Report scrolling region */
void screen_region_get(int *pv0, int *pv1);
/** Enable or disable origin remap to top left of scrolling region */
void screen_set_origin_mode(bool region_origin);
@@ -231,18 +267,19 @@ void screen_set_origin_mode(bool region_origin);
typedef uint8_t Color;
typedef uint16_t CellAttrs;
// TODO sort by the expected frequency of being set - so when we switch to utf-8 encoding for data fields, it uses fewer bytes
#define ATTR_BOLD (1<<0) //!< Bold font
#define ATTR_FAINT (1<<1) //!< Faint foreground color (reduced alpha)
#define ATTR_ITALIC (1<<2) //!< Italic font
#define ATTR_UNDERLINE (1<<3) //!< Underline decoration
#define ATTR_BLINK (1<<4) //!< Blinking
#define ATTR_FRAKTUR (1<<5) //!< Fraktur font (unicode substitution)
#define ATTR_STRIKE (1<<6) //!< Strike-through decoration
#define ATTR_OVERLINE (1<<7) //!< Over-line decoration
#define ATTR_FG (1<<8) //!< 1 if not using default background color (ignore cell bg) - color extension bit
#define ATTR_BG (1<<9) //!< 1 if not using default foreground color (ignore cell fg) - color extension bit
#define ATTR_INVERSE (1<<10) //!< Invert colors - this is useful so we can clear then with SGR manipulation commands
enum SgrAttrBits {
ATTR_FG = (1<<0), //!< 1 if not using default background color (ignore cell bg) - color extension bit
ATTR_BG = (1<<1), //!< 1 if not using default foreground color (ignore cell fg) - color extension bit
ATTR_BOLD = (1<<2), //!< Bold font
ATTR_UNDERLINE = (1<<3), //!< Underline decoration
ATTR_INVERSE = (1<<4), //!< Invert colors - this is useful so we can clear then with SGR manipulation commands
ATTR_BLINK = (1<<5), //!< Blinking
ATTR_ITALIC = (1<<6), //!< Italic font
ATTR_STRIKE = (1<<7), //!< Strike-through decoration
ATTR_OVERLINE = (1<<8), //!< Over-line decoration
ATTR_FAINT = (1<<9), //!< Faint foreground color (reduced alpha)
ATTR_FRAKTUR = (1<<10), //!< Fraktur font (unicode substitution)
};
/** Set cursor foreground color */
void screen_set_fg(Color color);
@@ -323,18 +360,14 @@ void screen_repeat_last_character(int count);
/** Report current SGR as num;num;... for DAC query */
void screen_report_sgr(char *buffer);
// --- Notify ---
typedef enum {
CHANGE_CONTENT = 0,
CHANGE_LABELS = 1,
} ScreenNotifyChangeTopic;
/**
* Called when the screen content or settings change
* and the front-end should redraw / update.
* @param topic - what kind of change this is (chooses what message to send)
*/
extern void screen_notifyChange(ScreenNotifyChangeTopic topic);
extern void screen_notifyChange(ScreenNotifyTopics topics);
#define seri_dbg(...)
#define seri_warn(...) warn(__VA_ARGS__)
#endif // SCREEN_H
+9 -5
View File
@@ -40,10 +40,10 @@ buf_pop(void *unused)
}
}
//LOCAL void my_putc(char c)
//{
// UART_WriteCharCRLF(UART1, (u8) c, 10);
//}
LOCAL void my_putc(char c)
{
UART_WriteCharCRLF(UART1, (u8) c, 10);
}
/**
* Init the serial ports
@@ -56,8 +56,11 @@ void ICACHE_FLASH_ATTR serialInitBase(void)
UART_SetStopBits(UART1, ONE_STOP_BIT);
UART_SetBaudrate(UART1, BIT_RATE_115200);
UART_SetPrintPort(UART1);
#if ASYNC_LOG
os_install_putc1(buf_putc);
//os_install_putc1(my_putc);
#else
os_install_putc1(my_putc);
#endif
UART_SetupAsyncReceiver();
// 1 ms timer
@@ -92,4 +95,5 @@ void ICACHE_FLASH_ATTR serialInit(void)
void ICACHE_FLASH_ATTR UART_HandleRxByte(char c)
{
ansi_parser(c);
system_soft_wdt_feed(); // so we survive long torrents
}
+46 -39
View File
@@ -8,8 +8,8 @@
#include <esp8266.h>
#include <uart_register.h>
#define UART_TX_BUFFER_SIZE 512 //Ring buffer length of tx buffer
#define UART_RX_BUFFER_SIZE 600 //Ring buffer length of rx buffer
//#define buf_dbg(format, ...) printf(format "\r\n", ##__VA_ARGS__)
#define buf_dbg(format, ...) (void)format
struct UartBuffer {
uint32 UartBuffSize;
@@ -22,12 +22,15 @@ struct UartBuffer {
static struct UartBuffer *pTxBuffer = NULL;
static struct UartBuffer *pRxBuffer = NULL;
static struct UartBuffer *UART_AsyncBufferInit(uint32 buf_size);
static u8 rxArray[UART_RX_BUFFER_SIZE];
static u8 txArray[UART_TX_BUFFER_SIZE];
static struct UartBuffer *UART_AsyncBufferInit(uint32 buf_size, u8 *buffer);
void ICACHE_FLASH_ATTR UART_AllocBuffers(void)
{
pTxBuffer = UART_AsyncBufferInit(UART_TX_BUFFER_SIZE);
pRxBuffer = UART_AsyncBufferInit(UART_RX_BUFFER_SIZE);
pTxBuffer = UART_AsyncBufferInit(UART_TX_BUFFER_SIZE, txArray);
pRxBuffer = UART_AsyncBufferInit(UART_RX_BUFFER_SIZE, rxArray);
}
/******************************************************************************
@@ -37,7 +40,7 @@ void ICACHE_FLASH_ATTR UART_AllocBuffers(void)
* Returns : NONE
*******************************************************************************/
static struct UartBuffer *ICACHE_FLASH_ATTR
UART_AsyncBufferInit(uint32 buf_size)
UART_AsyncBufferInit(uint32 buf_size, u8 *buffer)
{
uint32 heap_size = system_get_free_heap_size();
if (heap_size <= buf_size) {
@@ -47,7 +50,7 @@ UART_AsyncBufferInit(uint32 buf_size)
else {
struct UartBuffer *pBuff = (struct UartBuffer *) malloc(sizeof(struct UartBuffer));
pBuff->UartBuffSize = buf_size;
pBuff->pUartBuff = (uint8 *) malloc(pBuff->UartBuffSize);
pBuff->pUartBuff = buffer != NULL ? buffer : (uint8 *) malloc(pBuff->UartBuffSize);
pBuff->pInPos = pBuff->pUartBuff;
pBuff->pOutPos = pBuff->pUartBuff;
pBuff->Space = (uint16) pBuff->UartBuffSize;
@@ -55,6 +58,13 @@ UART_AsyncBufferInit(uint32 buf_size)
}
}
static void ICACHE_FLASH_ATTR
UART_AsyncBufferReset(struct UartBuffer *pBuff)
{
pBuff->pInPos = pBuff->pUartBuff;
pBuff->pOutPos = pBuff->pUartBuff;
pBuff->Space = (uint16) pBuff->UartBuffSize;
}
/**
* Copy data onto Buffer
@@ -67,23 +77,30 @@ UART_WriteToAsyncBuffer(struct UartBuffer *pCur, const char *pdata, uint16 data_
{
if (data_len == 0) return;
buf_dbg("WTAB %d, space %d", data_len, pCur->Space);
uint16 tail_len = (uint16) (pCur->pUartBuff + pCur->UartBuffSize - pCur->pInPos);
if (tail_len >= data_len) { //do not need to loop back the queue
buf_dbg("tail %d, no fold", tail_len);
memcpy(pCur->pInPos, pdata, data_len);
pCur->pInPos += (data_len);
pCur->pInPos = (pCur->pUartBuff + (pCur->pInPos - pCur->pUartBuff) % pCur->UartBuffSize);
pCur->Space -= data_len;
}
else {
buf_dbg("tail only %d, folding", tail_len);
memcpy(pCur->pInPos, pdata, tail_len);
buf_dbg("chunk 1, %d", tail_len);
pCur->pInPos += (tail_len);
pCur->pInPos = (pCur->pUartBuff + (pCur->pInPos - pCur->pUartBuff) % pCur->UartBuffSize);
pCur->Space -= tail_len;
buf_dbg("chunk 2, %d", data_len - tail_len);
memcpy(pCur->pInPos, pdata + tail_len, data_len - tail_len);
pCur->pInPos += (data_len - tail_len);
pCur->pInPos = (pCur->pUartBuff + (pCur->pInPos - pCur->pUartBuff) % pCur->UartBuffSize);
pCur->Space -= (data_len - tail_len);
}
buf_dbg("new space %d", pCur->Space);
}
/******************************************************************************
@@ -158,9 +175,8 @@ void UART_RxFifoCollect(void)
uint8 fifo_data;
fifo_len = (uint8) ((READ_PERI_REG(UART_STATUS(UART0)) >> UART_RXFIFO_CNT_S) & UART_RXFIFO_CNT);
if (fifo_len >= pRxBuffer->Space) {
// try to read at least the bit we can
fifo_len = (uint8) (pRxBuffer->Space - 1);
UART_WriteChar(UART1, '%', 1);
UART_WriteChar(UART1, '#', 10);
// discard contents of the FIFO - would loop forever
buf_idx = 0;
while (buf_idx < fifo_len) {
@@ -193,35 +209,30 @@ u16 ICACHE_FLASH_ATTR UART_AsyncTxGetEmptySpace(void)
return pTxBuffer->Space;
}
u16 ICACHE_FLASH_ATTR UART_AsyncTxCount(void)
{
return (u16) (pTxBuffer->UartBuffSize - pTxBuffer->Space);
}
/**
* Schedule data to be sent
* @param pdata
* @param data_len - can be -1 for strlen
*/
void ICACHE_FLASH_ATTR
UART_SendAsync(const char *pdata, int16_t data_len)
UART_SendAsync(const char *pdata, int data_len)
{
u16 real_len = (u16) data_len;
if (data_len <= 0) real_len = (u16) strlen(pdata);
size_t real_len = (data_len) <= 0 ? strlen(pdata) : (size_t) data_len;
// if (pTxBuffer == NULL) {
// printf("init tx buf\n\r");
// pTxBuffer = UART_AsyncBufferInit(UART_TX_BUFFER_SIZE);
// if (pTxBuffer != NULL) {
// UART_WriteToAsyncBuffer(pTxBuffer, pdata, real_len);
// }
// else {
// printf("tx alloc fail\r\n");
// }
// }
// else {
if (real_len <= pTxBuffer->Space) {
UART_WriteToAsyncBuffer(pTxBuffer, pdata, real_len);
}
else {
UART_WriteChar(UART1, '^', 1);
}
// }
buf_dbg("Send Async %d", real_len);
if (real_len <= pTxBuffer->Space) {
buf_dbg("accepted, space %d", pTxBuffer->Space);
UART_WriteToAsyncBuffer(pTxBuffer, pdata, (uint16) real_len);
}
else {
buf_dbg("FULL!");
UART_WriteChar(UART1, '=', 10);
}
// Here we enable TX empty interrupt that will take care of sending the content
SET_PERI_REG_MASK(UART_CONF1(UART0), (UART_TX_EMPTY_THRESH_VAL & UART_TXFIFO_EMPTY_THRHD) << UART_TXFIFO_EMPTY_THRHD_S);
@@ -257,8 +268,8 @@ void UART_DispatchFromTxBuffer(uint8 uart_no)
uint8 len_tmp;
uint16 data_len;
// if (pTxBuffer) {
data_len = (uint8) (pTxBuffer->UartBuffSize - pTxBuffer->Space);
data_len = (uint16) (pTxBuffer->UartBuffSize - pTxBuffer->Space);
buf_dbg("rem %d",data_len);
if (data_len > fifo_remain) {
len_tmp = fifo_remain;
UART_TxFifoEnq(pTxBuffer, len_tmp, uart_no);
@@ -268,8 +279,9 @@ void UART_DispatchFromTxBuffer(uint8 uart_no)
len_tmp = (uint8) data_len;
UART_TxFifoEnq(pTxBuffer, len_tmp, uart_no);
// we get one more IT after fifo ends even if we have 0 more bytes
// for notify
// We get one more IT after fifo ends even if we have 0 more bytes,
// for notify. Otherwise we would say we have space while the FIFO
// was still running
if (next_empty_it_only_for_notify) {
notify_empty_txbuf();
next_empty_it_only_for_notify = 0;
@@ -279,9 +291,4 @@ void UART_DispatchFromTxBuffer(uint8 uart_no)
SET_PERI_REG_MASK(UART_INT_ENA(UART0), UART_TXFIFO_EMPTY_INT_ENA);
}
}
// }
// else {
// error("pTxBuff null \n\r");
// }
}
+5 -1
View File
@@ -7,6 +7,9 @@
#include <esp8266.h>
#define UART_TX_BUFFER_SIZE 1000 //Ring buffer length of tx buffer
#define UART_RX_BUFFER_SIZE 600 //Ring buffer length of rx buffer
// the init func
void UART_AllocBuffers(void);
@@ -14,7 +17,7 @@ void UART_AllocBuffers(void);
uint16 UART_ReadAsync(char *pdata, uint16 data_len);
// write to tx buffer
void UART_SendAsync(const char *pdata, int16_t data_len);
void UART_SendAsync(const char *pdata, int data_len);
//move data from uart fifo to rx buffer
void UART_RxFifoCollect(void);
@@ -22,6 +25,7 @@ void UART_RxFifoCollect(void);
void UART_DispatchFromTxBuffer(uint8 uart_no);
u16 UART_AsyncRxCount(void);
u16 UART_AsyncTxCount(void);
u16 UART_AsyncTxGetEmptySpace(void);
+5 -4
View File
@@ -24,8 +24,8 @@ static void uart_recvTask(os_event_t *events);
static void uart_processTask(os_event_t *events);
// Those heavily affect the byte loss ratio
#define PROCESS_CHUNK_LEN 1
#define FIFO_FULL_THRES 32
#define PROCESS_CHUNK_LEN 10
#define RX_FIFO_FULL_THRES 40
#define uart_recvTaskPrio 1
#define uart_recvTaskQueueLen 25
@@ -52,6 +52,7 @@ void ICACHE_FLASH_ATTR UART_Init(void)
// U0RXD
PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD);
PIN_PULLUP_DIS(PERIPHS_IO_MUX_U0RXD_U);
// U1TXD (GPIO2)
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_U1TXD_BK);
@@ -78,8 +79,8 @@ void ICACHE_FLASH_ATTR UART_SetupAsyncReceiver(void)
ETS_UART_INTR_ATTACH((void *)uart0_rx_intr_handler, &(UartDev.rcv_buff)); // the buf will be used as an arg
// fifo threshold config (max: UART_RXFIFO_FULL_THRHD = 127)
uint32_t conf = ((FIFO_FULL_THRES & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S);
conf |= ((0x10 & UART_TXFIFO_EMPTY_THRHD) << UART_TXFIFO_EMPTY_THRHD_S);
uint32_t conf = ((RX_FIFO_FULL_THRES & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S);
conf |= ((0x05 & UART_TXFIFO_EMPTY_THRHD) << UART_TXFIFO_EMPTY_THRHD_S);
// timeout config
conf |= ((0x06 & UART_RX_TOUT_THRHD) << UART_RX_TOUT_THRHD_S); // timeout threshold
conf |= UART_RX_TOUT_EN; // enable timeout
+40 -15
View File
@@ -28,6 +28,9 @@
#include "ansi_parser_callbacks.h"
#include "wifimgr.h"
#include "persist.h"
#include "ansi_parser.h"
#include "ascii.h"
#include "uart_buffer.h"
#ifdef ESPFS_POS
CgiUploadFlashDef uploadParams={
@@ -49,6 +52,7 @@ CgiUploadFlashDef uploadParams={
#define INCLUDE_FLASH_FNS
#endif
#define HEAP_TIMER_MS 1000
/** Periodically show heap usage */
static void ICACHE_FLASH_ATTR prHeapTimerCb(void *arg)
{
@@ -58,18 +62,24 @@ static void ICACHE_FLASH_ATTR prHeapTimerCb(void *arg)
int heap = system_get_free_heap_size();
int diff = (heap-last);
int rxc = UART_AsyncRxCount();
int txc = UART_AsyncTxCount();
int rxp = ((rxc*10000) / UART_RX_BUFFER_SIZE)/100;
int txp = ((txc*10000) / UART_TX_BUFFER_SIZE)/100;
const char *cc = "+";
if (diff<0) cc = "";
if (diff == 0) {
if (cnt == 5) {
// only every 5 secs if no change
dbg("FH: %d", heap);
dbg("Rx/Tx: %d/%d%c, Hp: %d", rxp, txp, '%', heap);
cnt = 0;
}
} else {
// report change
dbg("FH: %d (%s%d)", heap, cc, diff);
dbg("Rx/Tx: %d/%d%c, Hp: %d (%s%d)", rxp, txp, '%', heap, cc, diff);
cnt = 0;
}
@@ -86,6 +96,7 @@ static ETSTimer prHeapTimer;
//Main routine. Initialize stdout, the I/O, filesystem and the webserver and we're done.
void ICACHE_FLASH_ATTR user_init(void)
{
ansi_parser_inhibit = true;
serialInitBase();
// Prevent WiFi starting and connecting by default
@@ -93,13 +104,22 @@ void ICACHE_FLASH_ATTR user_init(void)
wifi_station_set_auto_connect(false);
wifi_set_opmode(NULL_MODE); // saves to flash if changed - this might avoid the current spike on startup?
printf("\r\n");
banner("====== ESPTerm ======");
banner_info("Firmware (c) Ondrej Hruska, 2017");
banner_info(TERMINAL_GITHUB_REPO);
banner_info("");
banner_info("Version "FIRMWARE_VERSION", built " __DATE__ " at " __TIME__ " " __TIMEZONE__);
printf("\r\n");
u8 mac[6];
wifi_get_macaddr(SOFTAP_IF, mac);
banner_gap();
banner("================ ESPTerm ================");
banner_info();
banner_info("Project by Ondrej Hruska, 2017");
banner_info();
banner_info(TERMINAL_GITHUB_REPO_NOPROTO);
banner_info();
banner_info("Version "FW_VERSION" ("ESP_LANG"), code name "FW_CODENAME_QUOTED);
banner_info(" back-end #"GIT_HASH_BACKEND" front-end #"GIT_HASH_FRONTEND);
banner_info(" built "__DATE__" at "__TIME__" "__TIMEZONE__);
banner_info();
banner_info("Device ID: %02X%02X%02X", mac[3], mac[4], mac[5]);
banner_gap();
ioInit();
@@ -111,11 +131,6 @@ void ICACHE_FLASH_ATTR user_init(void)
espFsInit((void *) (webpages_espfs_start));
#endif
#if DEBUG_HEAP
// Heap use timer & blink
TIMER_START(&prHeapTimer, prHeapTimerCb, 1000, 1);
#endif
// do later (some functions do not work if called from user_init)
TIMER_START(&userStartTimer, user_start, 10, 0);
}
@@ -127,10 +142,20 @@ static void ICACHE_FLASH_ATTR user_start(void *unused)
captdnsInit();
httpdInit(routes, 80);
httpdSetName("ESPTerm " VERSION_STRING);
ansi_parser_inhibit = false;
// Print the CANCEL character to indicate the module has restarted
// Critically important for client application if any kind of screen persistence / content re-use is needed
UART_WriteChar(UART0, 24, UART_TIMEOUT_US); // 0x18 - 24 - CAN
UART_WriteChar(UART0, CAN, UART_TIMEOUT_US); // 0x18 - 24 - CAN
dbg("tsize=%d", sizeof(TerminalConfigBundle));
#if DEBUG_HEAP
// Heap use timer & blink
TIMER_START(&prHeapTimer, prHeapTimerCb, HEAP_TIMER_MS, 1);
#endif
}
// ---- unused funcs removed from sdk to save space ---
+6 -1
View File
@@ -160,8 +160,13 @@ unicode_cache_remove(UnicodeCacheRef ref)
* @return number of bytes on success, 0 on failure (also produces U+FFFD, which uses 3 bytes)
*/
int ICACHE_FLASH_ATTR
utf8_encode(char *out, uint32_t utf)
utf8_encode(char *out, uint32_t utf, bool surrogateFix)
{
// Skip the surrogate block (wtf, unicode???)
if (surrogateFix && utf >= 0xD800) {
utf += 0x800;
}
if (utf <= 0x7F) {
// Plain ASCII
out[0] = (char) utf;
+2 -1
View File
@@ -63,9 +63,10 @@ bool unicode_cache_remove(UnicodeCacheRef ref);
*
* @param out - output buffer (min 4 characters), will be 0-terminated if shorten than 4
* @param utf - code point 0-0x10FFFF
* @param surrogateFix - add 0x800 to 0xD800-0xDFFF to avoid invalid code points
* @return number of bytes on success, 0 on failure (also produces U+FFFD, which uses 3 bytes)
*/
int utf8_encode(char *out, uint32_t utf);
int utf8_encode(char *out, uint32_t utf, bool surrogateFix);
#if DEBUG_UTFCACHE
#define utfc_warn warn
+15 -3
View File
@@ -5,13 +5,25 @@
#ifndef ESP_VT100_FIRMWARE_VERSION_H
#define ESP_VT100_FIRMWARE_VERSION_H
#define STR_HELPER(x) #x
#define STR(x) STR_HELPER(x)
#define FW_V_MAJOR 2
#define FW_V_MINOR 0
#define FW_V_MINOR 2
#define FW_V_PATCH 0
#define FW_V_SUFFIX ""
#define FW_CODENAME "Bluet" // 2.2
#define FW_CODENAME_QUOTED "\""FW_CODENAME"\""
#define FW_VERSION STR(FW_V_MAJOR) "." STR(FW_V_MINOR) "." STR(FW_V_PATCH) FW_V_SUFFIX
#define VERSION_STRING FW_VERSION " " FW_CODENAME_QUOTED
#define FIRMWARE_VERSION STR(FW_V_MAJOR) "." STR(FW_V_MINOR) "." STR(FW_V_PATCH)
#define FIRMWARE_VERSION_NUM (FW_V_MAJOR*1000 + FW_V_MINOR*10 + FW_V_PATCH) // this is used in ID queries
#define TERMINAL_GITHUB_REPO "https://github.com/espterm/espterm-firmware"
#define TERMINAL_GITHUB_REPO_NOPROTO "github.com/espterm/espterm-firmware"
#define TERMINAL_GITHUB_REPO "https://"TERMINAL_GITHUB_REPO_NOPROTO
#define TERMINAL_GITHUB_REPO_FRONT "https://github.com/espterm/espterm-front-end"
#endif //ESP_VT100_FIRMWARE_VERSION_H
+16
View File
@@ -8,6 +8,22 @@
WiFiConfigBundle * const wificonf = &persist.current.wificonf;
WiFiConfChangeFlags wifi_change_flags;
int ICACHE_FLASH_ATTR getStaIpAsString(char *buffer)
{
WIFI_MODE x = wifi_get_opmode();
STATION_STATUS connectStatus = wifi_station_get_connect_status();
if (x == SOFTAP_MODE || connectStatus != STATION_GOT_IP || wificonf->opmode == SOFTAP_MODE) {
strcpy(buffer, "");
return 0;
}
else {
struct ip_info info;
wifi_get_ip_info(STATION_IF, &info);
return sprintf(buffer, IPSTR, GOOD_IP2STR(info.ip.addr));
}
}
/**
* Restore defaults in the WiFi config block.
* This is to be called if the WiFi config is corrupted on startup,
+2
View File
@@ -60,6 +60,8 @@ void wifimgr_restore_defaults(void);
void wifimgr_apply_settings(void);
int getStaIpAsString(char *buffer);
#if DEBUG_WIFI
#define wifi_warn warn
#define wifi_dbg dbg