diff --git a/.gitignore b/.gitignore index e257658..839bc90 100644 --- a/.gitignore +++ b/.gitignore @@ -1,34 +1,9 @@ -# ---> C++ -# Prerequisites -*.d - -# Compiled Object files -*.slo -*.lo -*.o -*.obj - -# Precompiled Headers -*.gch -*.pch - -# Compiled Dynamic libraries -*.so -*.dylib -*.dll - -# Fortran module files -*.mod -*.smod - -# Compiled Static libraries -*.lai -*.la -*.a -*.lib - -# Executables -*.exe -*.out -*.app - +.pioenvs +.piolibdeps +.clang_complete +.gcc-flags.json +.pioenvs +.piolibdeps +.vscode/.browse.c_cpp.db* +.vscode/c_cpp_properties.json +.vscode/launch.json diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..52072ef --- /dev/null +++ b/.travis.yml @@ -0,0 +1,55 @@ +# Continuous Integration (CI) is the practice, in software +# engineering, of merging all developer working copies with a shared mainline +# several times a day < http://docs.platformio.org/page/ci/index.html > +# +# Documentation: +# +# * Travis CI Embedded Builds with PlatformIO +# < https://docs.travis-ci.com/user/integration/platformio/ > +# +# * PlatformIO integration with Travis CI +# < http://docs.platformio.org/page/ci/travis.html > +# +# * User Guide for `platformio ci` command +# < http://docs.platformio.org/page/userguide/cmd_ci.html > +# +# +# Please choice one of the following templates (proposed below) and uncomment +# it (remove "# " before each line) or use own configuration according to the +# Travis CI documentation (see above). +# + + +# +# Template #1: General project. Test it using existing `platformio.ini`. +# + +# language: python +# python: +# - "2.7" +# +# install: +# - pip install -U platformio +# +# script: +# - platformio run + + +# +# Template #2: The project is intended to by used as a library with examples +# + +# language: python +# python: +# - "2.7" +# +# env: +# - PLATFORMIO_CI_SRC=path/to/test/file.c +# - PLATFORMIO_CI_SRC=examples/file.ino +# - PLATFORMIO_CI_SRC=path/to/test/directory +# +# install: +# - pip install -U platformio +# +# script: +# - platformio ci --lib="." --board=ID_1 --board=ID_2 --board=ID_N diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..272828b --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,7 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 + // for the documentation about the extensions.json format + "recommendations": [ + "platformio.platformio-ide" + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..0f00390 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "terminal.integrated.env.windows": { + "PATH": "C:\\Users\\PBRY\\.platformio\\penv\\Scripts;C:\\Users\\PBRY\\.platformio\\penv;C:\\ProgramData\\Oracle\\Java\\javapath;C:\\Python27\\;C:\\Python27\\Scripts;C:\\Windows\\system32;C:\\Windows;C:\\Windows\\System32\\Wbem;c:\\python27;C:\\Program Files\\TortoiseSVN\\bin\\;%USERPROFILE%\\.dnx\\bin;C:\\Program Files\\Microsoft DNX\\Dnvm\\;C:\\Users\\PBRY\\AppData\\Local\\Programs\\Git\\cmd;C:\\Program Files\\Microsoft SQL Server\\110\\Tools\\Binn\\;C:\\Program Files\\Microsoft SQL Server\\130\\Tools\\Binn\\;C:\\Python27\\;C:\\Python27\\Scripts;C:\\Windows\\system32;C:\\Windows;C:\\Windows\\System32\\Wbem;c:\\python27;C:\\Program Files\\TortoiseSVN\\bin\\;C:\\Users\\PBRY\\.dnx\\bin;C:\\Program Files\\Microsoft DNX\\Dnvm\\;C:\\Users\\PBRY\\AppData\\Local\\Programs\\Git\\cmd;C:\\Program Files\\Microsoft SQL Server\\110\\Tools\\Binn\\;C:\\Users\\PBRY\\.dnx\\bin;C:\\Program Files (x86)\\Atmel\\sam-ba_2.12\\drv\\;C:\\Program Files (x86)\\Atmel\\sam-ba_2.12;C:\\Program Files\\Intel\\WiFi\\bin\\;C:\\Program Files\\Common Files\\Intel\\WirelessCommon\\;i:\\MyProjects\\Kicad\\BOM\";C:\\Users\\PBRY\\AppData\\Local\\Programs\\Fiddler;C:\\Users\\PBRY\\AppData\\Local\\atom\\bin;C:\\Program Files\\Microsoft VS Code\\bin;C:\\ProgramData\\Oracle\\Java\\javapath;C:\\Python27\\;C:\\Python27\\Scripts;C:\\Windows\\system32;C:\\Windows;C:\\Windows\\System32\\Wbem;c:\\python27;C:\\Program Files\\TortoiseSVN\\bin\\;%USERPROFILE%\\.dnx\\bin;C:\\Program Files\\Microsoft DNX\\Dnvm\\;C:\\Users\\PBRY\\AppData\\Local\\Programs\\Git\\cmd;C:\\Program Files\\Microsoft SQL Server\\110\\Tools\\Binn\\;C:\\Program Files\\Microsoft SQL Server\\130\\Tools\\Binn\\;C:\\Python27\\;C:\\Python27\\Scripts;C:\\Windows\\system32;C:\\Windows;C:\\Windows\\System32\\Wbem;c:\\python27;C:\\Program Files\\TortoiseSVN\\bin\\;C:\\Users\\PBRY\\.dnx\\bin;C:\\Program Files\\Microsoft DNX\\Dnvm\\;C:\\Users\\PBRY\\AppData\\Local\\Programs\\Git\\cmd;C:\\Program Files\\Microsoft SQL Server\\110\\Tools\\Binn\\;C:\\Users\\PBRY\\.dnx\\bin;C:\\Program Files (x86)\\Atmel\\sam-ba_2.12\\drv\\;C:\\Program Files (x86)\\Atmel\\sam-ba_2.12;C:\\Program Files\\Intel\\WiFi\\bin\\;C:\\Program Files\\Common Files\\Intel\\WirelessCommon\\;i:\\MyProjects\\Kicad\\BOM\";C:\\Users\\PBRY\\AppData\\Local\\Programs\\Fiddler;C:\\Users\\PBRY\\AppData\\Local\\atom\\bin;C:\\Program Files\\Microsoft VS Code\\bin", + "PLATFORMIO_CALLER": "vscode" + } +} \ No newline at end of file diff --git a/eagle.flash.4m2m.ld b/eagle.flash.4m2m.ld new file mode 100644 index 0000000..59c6e57 --- /dev/null +++ b/eagle.flash.4m2m.ld @@ -0,0 +1,20 @@ +/* Flash Split for 4M chips */ +/* sketch 1019KB */ +/* empty 1024KB */ +/* spiffs 2028KB */ +/* eeprom 20KB */ + +MEMORY +{ + dport0_0_seg : org = 0x3FF00000, len = 0x10 + dram0_0_seg : org = 0x3FFE8000, len = 0x14000 + iram1_0_seg : org = 0x40100000, len = 0x8000 + irom0_0_seg : org = 0x40201010, len = 0xfeff0 +} + +PROVIDE ( _SPIFFS_start = 0x40400000 ); +PROVIDE ( _SPIFFS_end = 0x405FB000 ); +PROVIDE ( _SPIFFS_page = 0x100 ); +PROVIDE ( _SPIFFS_block = 0x2000 ); + +INCLUDE "../ld/eagle.app.v6.common.ld" diff --git a/lib/led/led.cpp b/lib/led/led.cpp new file mode 100644 index 0000000..606c167 --- /dev/null +++ b/lib/led/led.cpp @@ -0,0 +1,117 @@ +// Obsluha LED signalizace +#include +#include "led.h" + +LED::LED(int pin, int ledon, int ledoff) +{ + _pin = pin; + _ledon = ledon; + _ledoff = ledoff; +} + +void LED::rtLed(void) +{ + + switch (_state) + { + case LS_RUN: + { + uint8_t instr; + + if (NULL != _signal) + instr = *_ptr; // instrukce + else if (NULL != _psignal) + instr = pgm_read_byte(_pptr); + else + instr = LEDS_STOP; + switch (instr & 0xc0) + { + case LEDS_ONFOR: + digitalWrite(_pin, _ledon); + _timer = 10ul * ((instr & 0x3F) + 1); + _state = LS_WAIT; + break; + + case LEDS_OFFFOR: + digitalWrite(_pin, _ledoff); + _timer = 10ul * ((instr & 0x3F) + 1); + _state = LS_WAIT; + break; + + case LEDS_STOP: + _state = LS_IDLE; + break; + + case LEDS_RESTART: + _ptr = _signal; + _pptr = _psignal; + break; + } + } + break; + + case LS_WAIT: + --_timer; + if (0 == _timer) + { + _state = LS_RUN; + ++_ptr; + ++_pptr; + } + break; + + default: + break; + } +} + +void LED::begin(void) +{ + + pinMode(_pin, OUTPUT); + digitalWrite(_pin, _ledoff); + _state - LS_IDLE; +// _handler.attach_ms(10, lh, static_cast(this)); + _handler.attach_ms(10, lh, this); +} + +void LED::set(const uint8_t *signal) +{ + + noInterrupts(); + _signal = signal; + _ptr = _signal; + _psignal = NULL; + _state = LS_RUN; + interrupts(); +} + +//void LED::set(const __FlashStringHelper *signal) +void LED::set(PGM_P signal) +{ + noInterrupts(); +// _psignal = reinterpret_cast(signal); + _psignal = signal; + _pptr = _psignal; + _signal = NULL; + _state = LS_RUN; + interrupts(); +} + +void LED::start() +{ + + noInterrupts(); + _ptr = _signal; + _pptr = _psignal; + _state = LS_RUN; + interrupts(); +} + +//void LED::lh(void *ptr) +void LED::lh(LED *ptr) +{ +// LED *pled = static_cast(ptr); + LED *pled = ptr; + pled->rtLed(); +} diff --git a/lib/led/led.h b/lib/led/led.h new file mode 100644 index 0000000..27f829a --- /dev/null +++ b/lib/led/led.h @@ -0,0 +1,72 @@ +/** + * @file led.h + * @author Pavel Brychta, http://www.xpablo.cz + * + * Copyright (c) 2015,16 Pavel Brychta. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#ifndef _led_h_ +#define _led_h_ + +#include +#include + +typedef struct +{ + +}ledsignal_t; + +enum +{ + LEDS_ONFOR = 0x00, // rozsviti LED na delku, ktera je uvedena v nizsich 6-ti bitech (+1) [100ms], 0 znamena, ze se rozsviti na 100ms + LEDS_OFFFOR = 0x40, + LEDS_STOP = 0x80, + LEDS_RESTART = 0xc0 +}; + +class LED +{ +// typedef void (LED::*runtime)(void); + + protected: + int _pin; // pin, na kterem je LED pripojena + Ticker _handler; // obsluha LED signalizace + const uint8_t *_signal; // ukazatel na vzor signalizace + PGM_P _psignal; + const uint8_t *_ptr; // ukazatel na aktualne zpracovavane misto v signalizaci + PGM_P _pptr; + uint32_t _timer; // casovani + int _ledon; + int _ledoff; + enum + { + LS_IDLE, // klid, cekame na zmenu (zavolani set, nebo start) + LS_RUN, // bezi automat + LS_WAIT, // cekame v automatu + }_state; // stav automatu + public: + LED(int pin, int ledon, int ledoff); + void begin(void); + void set(const uint8_t *signal); +// void set(const __FlashStringHelper *signal); + void set(PGM_P signal); + void start(); +// static void lh(void *ptr); + static void lh(LED *ptr); + void rtLed(void); // vykonna metoda +}; +#endif diff --git a/lib/readme.txt b/lib/readme.txt new file mode 100644 index 0000000..131f1bf --- /dev/null +++ b/lib/readme.txt @@ -0,0 +1,41 @@ + +This directory is intended for the project specific (private) libraries. +PlatformIO will compile them to static libraries and link to executable file. + +The source code of each library should be placed in separate directory, like +"lib/private_lib/[here are source files]". + +For example, see how can be organized `Foo` and `Bar` libraries: + +|--lib +| | +| |--Bar +| | |--docs +| | |--examples +| | |--src +| | |- Bar.c +| | |- Bar.h +| | |- library.json (optional, custom build options, etc) http://docs.platformio.org/page/librarymanager/config.html +| | +| |--Foo +| | |- Foo.c +| | |- Foo.h +| | +| |- readme.txt --> THIS FILE +| +|- platformio.ini +|--src + |- main.c + +Then in `src/main.c` you should use: + +#include +#include + +// rest H/C/CPP code + +PlatformIO will find your libraries automatically, configure preprocessor's +include paths and build them. + +More information about PlatformIO Library Dependency Finder +- http://docs.platformio.org/page/librarymanager/ldf.html diff --git a/lib/uinterval/uinterval.cpp b/lib/uinterval/uinterval.cpp new file mode 100644 index 0000000..43bb1d3 --- /dev/null +++ b/lib/uinterval/uinterval.cpp @@ -0,0 +1,36 @@ +extern "C" { + #include + #include + #include +} +#include +#include "uinterval.h" + +// Public Methods ////////////////////////////////////////////////////////////// +uint32_t uInterval::remains(void) +{ + + return _timeout - (micros() - _timefrom); +} + +uint32_t uInterval::elapsed(void) +{ + + return micros() - _timefrom; +} + +bool uInterval::expired(void) +{ + + if ((micros() - _timefrom) >= _timeout) + return true; + else + return false; +} + +void uInterval::set(uint32_t tmout) +{ + + _timefrom = micros(); + _timeout = tmout; +} diff --git a/lib/uinterval/uinterval.h b/lib/uinterval/uinterval.h new file mode 100644 index 0000000..637cac8 --- /dev/null +++ b/lib/uinterval/uinterval.h @@ -0,0 +1,30 @@ + +#ifndef uinterval_h +#define uinterval_h + +/* uInterval + * Copyright (C) 2014, 2016 Pavel Brychta http://www.xpablo.cz + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses + */ + +#include + +class uInterval +{ + protected: + uint32_t _timefrom; + uint32_t _timeout; + public: + bool expired(void); + void set(uint32_t tmout); + uint32_t elapsed(void); + uint32_t remains(void); +}; + +#endif +// EOF diff --git a/platformio.ini b/platformio.ini new file mode 100644 index 0000000..51cea04 --- /dev/null +++ b/platformio.ini @@ -0,0 +1,24 @@ +[env:esp12e] +; platform = https://github.com/platformio/platform-espressif8266.git#feature/stage +; platform = https://github.com/platformio/platform-espressif8266.git +platform = espressif8266 +; platform = espressif8266@1.6 - odladena na verzi @1.7 diky workaroundu +board = esp12e +framework = arduino +board_build.flash_mode = dio +upload_port = com25 +;upload_port = bwrpn5325.local +;upload_port = bwrt00.local +; upload_port = 192.168.1.197 +; upload_port = /dev/ttyUSB0 +upload_speed = 230400 +lib_deps = + http://git.xpablo.cz/pablo2048/Interval.git + http://git.xpablo.cz/pablo2048/WiFiConfig.git + https://github.com/me-no-dev/AsyncTCP.git + https://github.com/me-no-dev/ESPAsyncUDP.git + https://github.com/me-no-dev/ESPAsyncWebServer.git + http://git.xpablo.cz/pablo2048/Trace.git +build_flags = + -Wl,-Teagle.flash.4m2m.ld + -D PIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY diff --git a/src/configuration.h b/src/configuration.h new file mode 100644 index 0000000..f61d2d4 --- /dev/null +++ b/src/configuration.h @@ -0,0 +1,73 @@ +#ifndef _CONFIGURATION_H_ +#define _CONFIGURATION_H_ +#define NO_PIN -1 // indikator nepouziteho pinu + +#define VERSION "0.0.3" +#define SYSTEM_BUILD 3 + +#define __INOVERSION__ __FILE__ " Compiled @" __DATE__ " " __TIME__ + +#define DEBUG_BUILD // **** ladici varianta s Arduino OTA + +#define HTTP_UPDATE // **** moznost aktualizace firmware pres www server pomoci http://%s.local/update +#define HTTP_UPDATE_USERNAME "admin" // **** uzivatelske jmeno pro update firmware (zapoznamkovanim teto definice vypneme nutnost prihlasovani) +#define HTTP_UPDATE_PASSWORD "nimda" // **** uzivatelske heslo pro update firmware + +//#define USE_SPIFFS // **** podpora pro praci s SPIFFS souborovym systemem (webovy server dokaze servirovat stranky z SPIFFS) + +#define FORCE_CONFIG_BUTTON_PIN NO_PIN // **** I/O pin, pouzity pro vynuceni konfigurace + +#define LED_PIN 2//NO_PIN // pin, ke kteremu je pripojena LED dioda + +#define HTTP_PORT 80 // port, na kterem pobezi HTTP (www) server + +#ifdef DEBUG_BUILD + #define STRINGIFY(x) #x + #define TOSTRING(x) STRINGIFY(x) + #include + + #define TRACE(severity, ...) trace_print(severity, __VA_ARGS__) + #define TRACEFUNC(severity, ...) trace_printfunc(severity, __func__, __FILE__, TOSTRING(__LINE__), __VA_ARGS__) + #define TRACEDUMP(severity, prefix, address, size) trace_dump(severity, prefix, address, size) + #define TRACE_INIT trace_init() + #define TRACE_ADDWEB(srv) trace_addweb(srv) + #define TRACE_POLL trace_poll() +#else + #define TRACE(...) ((void)0) // from assert.h "NOP" - http://stackoverflow.com/questions/9187628/c-empty-function-macros + #define TRACEFUNC(...) ((void)0) + #define TRACEDUMP(...) ((void)0) + #define TRACE_INIT ((void)0) + #define TRACE_ADDWEB(a) ((void)0) + #define TRACE_POLL ((void)0) +#endif + +#define BUFFERSIZE 128 // velikost vyrovnavaciho bufferu + +#define VCP_PORT 5555 // cislo pouziteho portu + +#define NVT_TX_MAXSIZE 64 + +#define TX_TIMEOUT_MULTIPLIER 3 + +#define TX_TIMEOUT_DIVISOR 2 + +//#define RX_BUFFER_SIZE 4096 // velikost prijimaciho bufferu pro seriovy port v pripade, ze Core uz podporuje nastaveni velikosti (v soucasne dobe pouze github verze...) + +#define INITIAL_SERIAL_SPEED 9600 // pocatecni prenosova rychlost + +#define EEPROM_MAGIC 0xaabbccdc + +#ifdef USE_CRASHDUMP + #define SAVE_CRASH_SPACE_SIZE 0x0200 // space reserved to store crash data + #define SAVE_CRASH_EEPROM_OFFSET (EEPROM_CONFIG_ORIGIN + offsetof(eepromconfig_t, sc)) +#endif + +#define EEPROM_SIZE (sizeof(wificonfigarea_t) + sizeof(eepromconfig_t) + 10) // velikost EEPROM oblasti (POZOR!!! zbytecnym zvetsovanim se zaroven zmensuje velikost RAM kvuli zrcadlu!!!) + +#define EEPROM_WIFICONFIG_ORIGIN (EEPROM_SIZE - sizeof(wificonfigarea_t)) // pocatek oblasti, pouzivane WiFiConfig + +#define EEPROM_CONFIG_ORIGIN (0) + +#define CORS_DEBUG + +#endif diff --git a/src/nvt.cpp b/src/nvt.cpp new file mode 100644 index 0000000..abed4b4 --- /dev/null +++ b/src/nvt.cpp @@ -0,0 +1,425 @@ + +#include "configuration.h" + +#include "nvt.h" +#include "nvt_int.h" +#include + +static uint8_t DONOTIFYLINESTATE[] = {NVT_IAC, NVT_DO, COM_PORT_OPTION}; +static uint8_t NOTIFYMODEMSTATE[] = {NVT_IAC, NVT_SB, COM_PORT_OPTION, ASC_NOTIFY_MODEMSTATE, 16 + 64, NVT_IAC, NVT_SE}; + +static const char TXBFROVFL[] PROGMEM = "NVT: tx buffer overflow"; + +void nvt::puttotx(uint8_t c) +{ + + if (_txptr < sizeof(_nvttxbuff)) + { + _nvttxbuff[_txptr] = c; + ++_txptr; + } + else + TRACE(TRACE_ERROR, FPSTR(TXBFROVFL)); +} + +void nvt::puttotxesc(uint8_t c) +{ + + if ((_txptr + 1) < sizeof(_nvttxbuff)) + { + _nvttxbuff[_txptr] = c; + ++_txptr; + if (NVT_IAC == c) + { + _nvttxbuff[_txptr] = c; + ++_txptr; + } + } + else + TRACE(TRACE_ERROR, FPSTR(TXBFROVFL)); +} + +void nvt::outdata(uint8_t *ptr, size_t size) +{ + + if (_netchr) + { + while (size) + { + _netchr(*ptr); + ++ptr; + --size; + } + } +} + +int nvt::getnvtbyte(uint8_t *dta) +{ + + if (_getindex < _cmdindex) + { + *dta = _nvtcmd[_getindex]; + _getindex++; + return 0; + } + else + return -1; // neni dalsi byte +} + +// Zpracovani NVT povelu +void nvt::donvtcmd(void) +{ + uint8_t dta; + uint8_t cmd; + bool wontquit = true; + uint32_t parameter; + + _getindex = 0; + + if (0 == getnvtbyte(&dta)) +// while ((0 == getnvtbyte(&dta)) && wontquit) + { + switch (dta) + { + case COM_PORT_OPTION: + if (0 == getnvtbyte(&cmd)) + { + switch (cmd) + { + case CAS_SIGNATURE: + break; + + case CAS_SET_BAUDRATE: + if ((_cmdindex - _getindex) >= 4) + { + getnvtbyte(&dta); + parameter = dta << 24; + getnvtbyte(&dta); + parameter += dta << 16; + getnvtbyte(&dta); + parameter += dta << 8; + getnvtbyte(&dta); + parameter += dta; + if (0 != parameter) + { + _speed = parameter; + _setserial(_speed, -_databits, -_parity, -_stopbits); // aktualizujeme prenosovou rychlost + } + parameter = _speed; + } + break; + + case CAS_SET_DATASIZE: + if (0 == getnvtbyte(&dta)) + { + if (0 != dta) + { + _databits = dta; + _setserial(-_speed, _databits, -_parity, -_stopbits); + } + parameter = _databits; + } + break; + + case CAS_SET_PARITY: + if (0 == getnvtbyte(&dta)) + { + if (0 != dta) + { + _parity = dta; + _setserial(-_speed, -_databits, _parity, -_stopbits); + } + parameter = _parity; + } + break; + + case CAS_SET_STOPSIZE: + if (0 == getnvtbyte(&dta)) + { + if (0 != dta) + { + _stopbits = dta; + _setserial(-_speed, -_databits, -_parity, _stopbits); + } + parameter = _stopbits; + } + break; + + case CAS_SET_CONTROL: + if (0 == getnvtbyte(&dta)) + { + if (_setgetcontrol) + parameter = _setgetcontrol(dta); + else + parameter = 1; // No Flow Control available + TRACE(TRACE_INFO, F("Set/Get Control returns %i"), (int)parameter); + } + break; + + case CAS_SET_LINESTATE_MASK: + if (0 == getnvtbyte(&dta)) + { + _linestatemask = dta; + parameter = _linestatemask; + TRACE(TRACE_INFO, F("Line state mask set to %i"), (int)_linestatemask); + } + break; + + case CAS_SET_MODEMSTATE_MASK: + if (0 == getnvtbyte(&dta)) + { + _modemstatemask = dta; + parameter = _modemstatemask; + TRACE(TRACE_INFO, F("Modem state mask set to %i"), (int)_modemstatemask); + } + break; + + default: + TRACE(TRACE_ERROR, F("Unsupported CAS %i"), (int)dta); + wontquit = false; + break; + } +// odeslani odpovedi + if (wontquit) + { + _txptr = 0; + puttotx(NVT_IAC); + puttotx(NVT_SB); + puttotx(COM_PORT_OPTION); + puttotx(cmd + 100); // z dotazu udelame odpoved + if (CAS_SET_BAUDRATE == cmd) + { // nastaveni/dotaz na prenosovou rychlost vraci 4 byty + puttotxesc((parameter >> 24) & 0xff); + puttotxesc((parameter >> 16) & 0xff); + puttotxesc((parameter >> 8) & 0xff); + puttotxesc((parameter >> 0) & 0xff); + } + else + { + puttotxesc(parameter & 0xff); // ostatni povely vraci jeden byte + } + puttotx(NVT_IAC); + puttotx(NVT_SE); + outdata(_nvttxbuff, _txptr); + } + } + break; + + default: + TRACE(TRACE_ERROR, F("Unsupported cmd %i"), (int)dta); + break; + } + } +} + +// Standardni metoda pro prepousteni dat do vystupu +void nvt::terminalbyte(uint8_t dta) +{ + + if (_putchr) + _putchr(dta); +} + +// metoda reseni subnegotiation options +void nvt::subnegotiationbyte(uint8_t dta) +{ + + _nvtcmd[_cmdindex] = dta; + _cmdindex++; + if (MAX_NVT_CMD_SIZE == _cmdindex) + { // preteceni bufferu + _streamstate = NVT_IAC_HUNT; // rusime zpracovani povelu + TRACE(TRACE_ERROR, F("Internal buffer overflow")); + } +} + +// Standardni metoda reakce na NVT povel +void nvt::terminalescape(uint8_t dta) +{ + + switch (dta) + { + case NVT_NOP: + break; + + case NVT_AYT: + { + if (0 == strlen(_aytstring)) + outdata((uint8_t*)"Yes", 3); // genericka odpoved + else + outdata((uint8_t *)_aytstring, strlen(_aytstring)); // uzivatelska odpoved + } + break; + + case NVT_SB: // zacatek subnegotiation + _streamstate = NVT_SB_FOUND; // nasli jsme zacatek subnegotiation + _cmdindex = 0; // nastavime index na zacatek + break; + + case NVT_SE: // konec subnegotiation + _streamstate = NVT_IAC_HUNT; // rusime osetrovani subnegotiation + if (_cmdindex) + donvtcmd(); // zpracujeme NVT povel + break; + + case NVT_WILL: + case NVT_WONT: + case NVT_DO: + case NVT_DONT: + wwdd = dta; // ulozime si typ povelu WILL/WONT/DO/DONT + _streamstate = NVT_WILL_WONT_DO_DONT_PARAM; // priste budeme analyzovat parametr + break; + + default: + // Detekovan neznamy znak po + TRACE(TRACE_ERROR, F("Unknown NVT %i"), (int)dta); + break; + } +} + +void nvt::handlewwddp(uint8_t p) +{ + + TRACE(TRACE_INFO, F("DO/DONT/WILL/WONT")); + _txptr = 0; + puttotx(NVT_IAC); + switch (wwdd) + { + case NVT_WILL: + if (COM_PORT_OPTION == p) + puttotx(NVT_DO); + else + puttotx(NVT_DONT); + break; + + case NVT_WONT: + puttotx(NVT_DONT); + break; + + case NVT_DO: + if (COM_PORT_OPTION == p) + puttotx(NVT_WILL); + else + puttotx(NVT_WONT); + break; + + case NVT_DONT: + puttotx(NVT_WONT); + break; + } + puttotx(p); + outdata(_nvttxbuff, _txptr); +} + +void nvt::parsenvtstream(uint8_t dta) +{ + + switch (_streamstate) + { + case NVT_SB_FOUND: + if (NVT_IAC == dta) + _streamstate = NVT_IAC_SB_FOUND; + else + subnegotiationbyte(dta); // prijimame bezny byte z SB - SE povelu + break; + + case NVT_IAC_SB_FOUND: + _streamstate = NVT_SB_FOUND; + if (NVT_IAC == dta) + subnegotiationbyte(dta); // byl to obycejny escapovany byte ze subnegotiation sekvence + else + terminalescape(dta); // byl to nejaky povel - doufame, ze to byl + break; + + case NVT_IAC_FOUND: + _streamstate = NVT_IAC_HUNT; + if (NVT_IAC == dta) + terminalbyte(dta); // data do vystupu (->serial) + else // slo o - signalizujeme IAC + terminalescape(dta); + break; + + case NVT_WILL_WONT_DO_DONT_PARAM: + _streamstate = NVT_IAC_HUNT; + handlewwddp(dta); + break; + + default: + _streamstate = NVT_IAC_HUNT; + case NVT_IAC_HUNT: + if (NVT_IAC != dta) + terminalbyte(dta); // data do vystupu + else + _streamstate = NVT_IAC_FOUND; + break; + } +} + +void nvt::handlestream(uint8_t *ptr, int len) +{ + + while (len) + { + parsenvtstream(*ptr); + ++ptr; + --len; + } +} + +void nvt::createsendstream(uint8_t *ptr, int len) +{ + uint8_t dta; + + while (len) + { + dta = *ptr; + ++ptr; + --len; + if (_netchr) + { + _netchr(dta); + if (NVT_IAC == dta) + { // NVT_IAC je escapovany + _netchr(dta); + } + } + } +} + +void nvt::init(setserial_cb setserial, putchr_cb putchr, netchr_cb netchr) +{ + + _setserial = setserial; + _putchr = putchr; + _netchr = netchr; + _speed = NVT_INITIAL_SPEED; + _databits = NVT_INITIAL_DATA_BITS; + _parity = NVT_INITIAL_PARITY; + _stopbits = NVT_INITIAL_STOP_BITS; + _setserial(_speed, _databits, _parity, _stopbits); + _streamstate = NVT_IAC_HUNT; + _modemstatemask = 0; + _linestatemask = 0; +} + +void nvt::setAYTstring(const char *aytstring) +{ + + strcpy(_aytstring, aytstring); +} + +void nvt::newguy(void) +{ + +// outdata(DONOTIFYLINESTATE, sizeof(DONOTIFYLINESTATE)); // zajima nas zmena stavu ridicich signalu +// outdata(NOTIFYMODEMSTATE, sizeof(NOTIFYMODEMSTATE)); +} + +void nvt::setSetGetCtrl(setgetcontrol_cb sgc) +{ + + _setgetcontrol = sgc; +} + +// EOF + diff --git a/src/nvt.h b/src/nvt.h new file mode 100644 index 0000000..76d3b44 --- /dev/null +++ b/src/nvt.h @@ -0,0 +1,107 @@ +/** + * @file nvt.h + * @author Pavel Brychta, http://www.xpablo.cz + * + * Copyright (c) 2014,15,16 Pavel Brychta. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef _NVT_H_ +#define _NVT_H_ + +#include +#include + +#define NVT_PARITY_NONE 1 +#define NVT_PARITY_EVEN 3 +#define NVT_PARITY_ODD 2 + +#define NVT_STOP_BITS_1 1 +#define NVT_STOP_BITS_15 3 +#define NVT_STOP_BITS_2 2 + +#define NVT_INITIAL_SPEED 9600 +#define NVT_INITIAL_DATA_BITS 8 +#define NVT_INITIAL_PARITY NVT_PARITY_NONE +#define NVT_INITIAL_STOP_BITS NVT_STOP_BITS_1 + +#define MAX_NVT_CMD_SIZE 64 // maximalni velikost povelu +#define MAX_NVT_RESP_SIZE 64 // maximalni velikost jedne odpovedi na NVT povel +#ifndef NVT_MAX_AYT_LENGTH + #define NVT_MAX_AYT_LENGTH 64 +#endif + +typedef void (*putchr_cb)(uint8_t c); // callback pro vystup bytu - smer NVT stream->Seriovy port +typedef void (*netchr_cb)(uint8_t c); // callback pro vystup bytu - smer NVT stream->Network port +typedef void (*setserial_cb)(int32_t speed, int32_t databits, int32_t parity, int32_t stopbits); // nastaveni parametru seriove linky (cislo mensi nez 0 udava, ze parametr je stejny, jako z minuleho volani - kvuli optimalizaci nastavovani) +typedef uint8_t (*setgetcontrol_cb)(uint8_t newcontrol); // nastaveni/ziskani + +class nvt +{ + protected: + enum + { + NVT_IAC_HUNT = 0, // testujeme na IAC + NVT_IAC_FOUND, // minuly znak byl IAC + NVT_SB_FOUND, // nasli jsme SB - sledujeme povel + NVT_IAC_SB_FOUND, // detekovali jsme IAC behem SB + NVT_WILL_WONT_DO_DONT_PARAM, // parametr WILL/WONT/DO/DONT + } _streamstate; + + uint8_t _nvtcmd[MAX_NVT_CMD_SIZE]; // misto pro prikaz, uvozeny a ukonceny + int _cmdindex; // aktualni pozice v nvtcmd + int _getindex; // zpracovavaci ukazatel + int wwdd; // posledni detekovany WILL/WONT/DO/DONT + + uint32_t _speed; // aktualni prenosova rychlost + uint8_t _databits; // aktualni pocet datovych bitu + uint8_t _parity; // aktualni parita + uint8_t _stopbits; // pocet stop bitu + uint8_t _linestatemask; // aktivni maska odesilani zmen stavu + uint8_t _modemstatemask; // aktivni maska odesilani zmen stavu + + uint8_t _nvttxbuff[MAX_NVT_RESP_SIZE]; // buffer pro sestaveni odpovedi z NVT + int _txptr; // ukazatel v bufferu pro sestaveni odpovedi + + char _aytstring[NVT_MAX_AYT_LENGTH]; // misto pro AYT retezec + + putchr_cb _putchr; // metoda pro vystup bytu - smer NVT_Stream->Output (seriovy port) + netchr_cb _netchr; // metoda pro vystup bytu - smer sitovy port + setserial_cb _setserial; // nastaveni parametru seriove linky + setgetcontrol_cb _setgetcontrol; // nastaveni/ziskani + + void puttotx(uint8_t c); + void puttotxesc(uint8_t c); + void outdata(uint8_t *ptr, size_t size); // vystup proudu dat do _netchr + int getnvtbyte(uint8_t *dta); + void donvtcmd(void); + void terminalbyte(uint8_t dta); + void subnegotiationbyte(uint8_t dta); + void terminalescape(uint8_t dta); + void parsenvtstream(uint8_t dta); + void handlewwddp(uint8_t p); + + public: + void init(setserial_cb setserial, putchr_cb putchr, netchr_cb netchr); + void setAYTstring(const char *aytstring); + void handlestream(uint8_t *ptr, int len); + void createsendstream(uint8_t *ptr, int len); + void newguy(void); + void setSetGetCtrl(setgetcontrol_cb sgc); +}; + +#endif diff --git a/src/nvt_int.h b/src/nvt_int.h new file mode 100644 index 0000000..3ce6242 --- /dev/null +++ b/src/nvt_int.h @@ -0,0 +1,46 @@ +// Interni konstanty protokolu dle RFC + +#define NVT_IAC (0xff) // NVT command prefix + +#define NVT_SE (0xf0) // End of sub negotiation parameters +#define NVT_NOP (0xf1) // No operation +#define NVT_AYT (0xf6) // Are You There +#define NVT_SB (0xfa) // Indicates that what follows is sub negotiation of the indicated option. +#define NVT_WILL 251 +#define NVT_WONT 252 +#define NVT_DO 253 +#define NVT_DONT 254 + +#define COM_PORT_OPTION 44 + +#define CAS_SIGNATURE 0 +#define CAS_SET_BAUDRATE 1 +#define CAS_SET_DATASIZE 2 +#define CAS_SET_PARITY 3 +#define CAS_SET_STOPSIZE 4 +#define CAS_SET_CONTROL 5 +#define CAS_NOTIFY_LINESTATE 6 +#define CAS_NOTIFY_MODEMSTATE 7 +#define CAS_FLOWCONTROL_SUSPEND 8 +#define CAS_FLOWCONTROL_RESUME 9 +#define CAS_SET_LINESTATE_MASK 10 +#define CAS_SET_MODEMSTATE_MASK 11 +#define CAS_PURGE_DATA 12 +#define CAS_OPT_GPIO 50 +#define CAS_SET_GPIO 51 + +#define ASC_SIGNATURE 100 +#define ASC_SET_BAUDRATE 101 +#define ASC_SET_DATASIZE 102 +#define ASC_SET_PARITY 103 +#define ASC_SET_STOPSIZE 104 +#define ASC_SET_CONTROL 105 +#define ASC_NOTIFY_LINESTATE 106 +#define ASC_NOTIFY_MODEMSTATE 107 +#define ASC_FLOWCONTROL_SUSPEND 108 +#define ASC_FLOWCONTROL_RESUME 109 +#define ASC_SET_LINESTATE_MASK 110 +#define ASC_SET_MODEMSTATE_MASK 111 +#define ASC_PURGE_DATA 112 +#define ASC_OPT_GPIO 150 +#define ASC_SET_GPIO 151 diff --git a/src/obfuscator.h b/src/obfuscator.h new file mode 100644 index 0000000..f2ccb6c --- /dev/null +++ b/src/obfuscator.h @@ -0,0 +1,132 @@ +#include +#include + +//-------------------------------------------------------------// +// "Malware related compile-time hacks with C++11" by LeFF // +// You can use this code however you like, I just don't really // +// give a shit, but if you feel some respect for me, please // +// don't cut off this comment when copy-pasting... ;-) // +//-------------------------------------------------------------// + +// Usage examples: +void exampleRandom1() __attribute__((noinline)); +void exampleRandom2() __attribute__((noinline)); +void exampleHashing() __attribute__((noinline)); +void exampleEncryption() __attribute__((noinline)); + +#ifndef vxCPLSEED + // If you don't specify the seed for algorithms, the time when compilation + // started will be used, seed actually changes the results of algorithms... + #define vxCPLSEED ((__TIME__[7] - '0') * 1 + (__TIME__[6] - '0') * 10 + \ + (__TIME__[4] - '0') * 60 + (__TIME__[3] - '0') * 600 + \ + (__TIME__[1] - '0') * 3600 + (__TIME__[0] - '0') * 36000) +#endif + +// The constantify template is used to make sure that the result of constexpr +// function will be computed at compile-time instead of run-time +template struct vxCplConstantify { enum { Value = Const }; }; + +// Compile-time mod of a linear congruential pseudorandom number generator, +// the actual algorithm was taken from "Numerical Recipes" book +constexpr uint32_t vxCplRandom(uint32_t Id) +{ return (1013904223 + 1664525 * ((Id > 0) ? (vxCplRandom(Id - 1)) : (vxCPLSEED))) & 0xFFFFFFFF; } + +// Compile-time random macros, can be used to randomize execution +// path for separate builds, or compile-time trash code generation +#define vxRANDOM(Min, Max) (Min + (vxRAND() % (Max - Min + 1))) +#define vxRAND() (vxCplConstantify::Value) + +// Compile-time recursive mod of string hashing algorithm, +// the actual algorithm was taken from Qt library (this +// function isn't case sensitive due to vxCplTolower) +constexpr char vxCplTolower(char Ch) { return (Ch >= 'A' && Ch <= 'Z') ? (Ch - 'A' + 'a') : (Ch); } +constexpr uint32_t vxCplHashPart3(char Ch, uint32_t Hash) { return ((Hash << 4) + vxCplTolower(Ch)); } +constexpr uint32_t vxCplHashPart2(char Ch, uint32_t Hash) { return (vxCplHashPart3(Ch, Hash) ^ ((vxCplHashPart3(Ch, Hash) & 0xF0000000) >> 23)); } +constexpr uint32_t vxCplHashPart1(char Ch, uint32_t Hash) { return (vxCplHashPart2(Ch, Hash) & 0x0FFFFFFF); } +constexpr uint32_t vxCplHash(const char* Str) { return (*Str) ? (vxCplHashPart1(*Str, vxCplHash(Str + 1))) : (0); } + +// Compile-time hashing macro, hash values changes using the first pseudorandom number in sequence +#define vxHASH(Str) (uint32_t)(vxCplConstantify::Value ^ vxCplConstantify::Value) + +// Compile-time generator for list of indexes (0, 1, 2, ...) +template struct vxCplIndexList {}; +template struct vxCplAppend; +template struct vxCplAppend, Right> { typedef vxCplIndexList Result; }; +template struct vxCplIndexes { typedef typename vxCplAppend::Result, N - 1>::Result Result; }; +template <> struct vxCplIndexes<0> { typedef vxCplIndexList<> Result; }; + +// Compile-time string encryption of a single character +const char vxCplEncryptCharKey = vxRANDOM(0, 0xFF); +constexpr char vxCplEncryptChar(const char Ch, uint32_t Idx) { return Ch ^ (vxCplEncryptCharKey + Idx); } + +// Compile-time string encryption class +template struct vxCplEncryptedString; +template struct vxCplEncryptedString > +{ + char Value[sizeof...(Idx) + 1]; // Buffer for a string + + // Compile-time constructor + constexpr inline vxCplEncryptedString(const char* const Str) + : Value({ vxCplEncryptChar(Str[Idx], Idx)... }) {} + + // Run-time decryption + char* decrypt() + { + for(volatile uint32_t t = 0; t < sizeof...(Idx); t++) + { this->Value[t] = this->Value[t] ^ (vxCplEncryptCharKey + t); } + this->Value[sizeof...(Idx)] = '\0'; return this->Value; + } +}; + +// Compile-time string encryption macro +#define vxENCRYPT(Str) (vxCplEncryptedString::Result>(Str).decrypt()) + +/* +// A small random code path example +void exampleRandom1() +{ + switch(vxRANDOM(1, 4)) + { + case 1: { printf("exampleRandom1: Code path 1!\n"); break; } + case 2: { printf("exampleRandom1: Code path 2!\n"); break; } + case 3: { printf("exampleRandom1: Code path 3!\n"); break; } + case 4: { printf("exampleRandom1: Code path 4!\n"); break; } + default: { printf("Fucking poltergeist!\n"); } + } +} + +// A small random code generator example +void exampleRandom2() +{ + volatile uint32_t RndVal = vxRANDOM(0, 100); + if(vxRAND() % 2) { RndVal += vxRANDOM(0, 100); } + else { RndVal -= vxRANDOM(0, 200); } + printf("exampleRandom2: %d\n", RndVal); +} + +// A small string hasing example +void exampleHashing() +{ + printf("exampleHashing: 0x%08X\n", vxHASH("hello world!")); + printf("exampleHashing: 0x%08X\n", vxHASH("HELLO WORLD!")); +} + +void exampleEncryption() +{ + printf("exampleEncryption: %s\n", vxENCRYPT("Hello world!")); +} + +extern "C" void Main() +{ + exampleRandom1(); + exampleRandom2(); + exampleHashing(); + exampleEncryption(); +} + +// Example +#define vxENCRYPT2(Str) (vxCplEncryptedString::Result>(Str)) +auto enc = vxENCRYPT2("secret"); +printf("str: %s\n", enc.decrypt()); +*/ + diff --git a/src/vsp.ino b/src/vsp.ino new file mode 100644 index 0000000..759c901 --- /dev/null +++ b/src/vsp.ino @@ -0,0 +1,394 @@ +//#include + +#include +#include "nvt.h" +#include + +WiFiServer server(VCP_PORT); +WiFiClient client; +cbuf fromNet(3000); +cbuf toNet(3000); +uint8_t sbuf[128]; // vyrovnavaci buffer pro vycitani serioveho portu/sitoveho soketu + +nvt netterm; // network virtual terminal objekt + +uint8_t nvttx[1500]; // vyrovnavaci vystupni buffer +uInterval nvtt; // casovac pro rizeni odesilani bufferu +uint32_t baudtiming; // vypocitana delka cekani pri paketizaci + +int control = 1; // aktivni rezim rizeni vystupu atd... (implicitne je to No Flow Control) +int dtrstate; +int breakstate; +int rtsstate; + +int newguy = 0; + +// statistika +uint32_t serial_tx; // pocet odeslanych bytu na seriove rozhrani +uint32_t serial_rx; // pocet prijatych bytu ze serioveho rozhrani +uint32_t drop_tx; // pocet vynechanych bytu pri odesilani (preplneny buffer ze site) +uint32_t drop_rx; // pocet vynechanych bytu pri prijmu (preplneny buffer ze serioveho portu) + +/* Nastaveni parametru serioveho portu +*/ +void setserialport(int32_t speed, int32_t databits, int32_t parity, int32_t stopbits) // nastaveni parametru seriove linky ( cislo mensi nez 0 udava, ze parametr je steny, jako z minuleho volani - kvuli optimalizaci nastavovani) +{ + uint32_t spd; + int serialMode; + int totalbits; // celkovy pocet bitu ve slove pro vypocet timeoutu + + if (speed > 0) + TRACE(TRACE_INFO, F("New serial speed set to %i"), (int)speed); + spd = abs(speed); + +/* Nastaveni poctu datovych bitu + BITS: + Value Data Bit Size + 0 Request Current Data Bit Size + 1 Available for Future Use + 2 Available for Future Use + 3 Available for Future Use + 4 Available for Future Use + 5 5 + 6 6 + 7 7 + 8 8 + 9-127 Available for Future Use +*/ + switch (abs(databits)) + { + case 5: + serialMode |= UART_NB_BIT_5; + totalbits = 5 + 1; + break; + + case 6: + serialMode |= UART_NB_BIT_6; + totalbits = 6 + 1; + break; + + case 7: + serialMode |= UART_NB_BIT_7; + totalbits = 7 + 1; + break; + + default: + serialMode |= UART_NB_BIT_8; + totalbits = 8 + 1; + break; + } + if (databits > 0) + TRACE(TRACE_INFO, F("New databits set to %i"), (int)databits); + +/* Nastaveni typu parity + PARITY: + 1 NONE + 2 ODD + 3 EVEN + 4 MARK + 5 SPACE +*/ + switch (abs(parity)) + { + case 2: + serialMode |= UART_PARITY_ODD; + totalbits += 1; + if (parity > 0) + TRACE(TRACE_INFO, F("Parity set to ODD")); + break; + + case 3: + serialMode |= UART_PARITY_EVEN; + totalbits += 1; + if (parity > 0) + TRACE(TRACE_INFO, F("Parity set to EVEN")); + break; + + case 4: + case 5: + if (parity > 0) + TRACE(TRACE_ERROR, F("Unsupported parity type")); + default: + if (parity > 0) + TRACE(TRACE_INFO, F("Parity set to NONE")); + serialMode |= UART_PARITY_NONE; + totalbits += 0; + break; + } +/* Nastaveni poctu stop bitu + STOPBITS: + Value Stop Bit Size + 0 Request Current Number of Stop Bits + 1 1 + 2 2 + 3 1.5 + 4-127 Available for Future Use +*/ + switch (abs(stopbits)) + { + case 2: + serialMode |= UART_NB_STOP_BIT_2; + totalbits += 2; + if (stopbits > 0) + TRACE(TRACE_INFO, F("Stop bits set to 2")); + break; + + case 3: + serialMode |= UART_NB_STOP_BIT_15; + totalbits += 2; // 1,5 je jako dva... + if (stopbits > 0) + TRACE(TRACE_INFO, F("Stop bits set to 1.5")); + break; + + default: + serialMode |= UART_NB_STOP_BIT_1; + totalbits += 1; + if (stopbits > 0) + TRACE(TRACE_INFO, F("Stop bits set to 1")); + break; + } +// podle poctu bitu a prenosove rychlosti spocitame casovou konstantu pro paketovaci casovac + uint32_t work = (totalbits * 1000000ul * TX_TIMEOUT_MULTIPLIER) / (spd * TX_TIMEOUT_DIVISOR); + if (baudtiming != work) + TRACE(TRACE_DEBUG, "Interval set to %i us", (int)work); + baudtiming = work; +// skutecne zmenime nastaveni serioveho portu + Serial.flush(); + // delay(200); + Serial.end(); + delay(10); // 100 + Serial.begin(spd, (SerialConfig)serialMode); + Serial.setDebugOutput(false); + delay(10); // 100 + Serial.flush(); + serial_tx = 0; + serial_rx = 0; +} + +// Odeslani dat na seriovy port +void sputchar(uint8_t c) +{ + + if (fromNet.empty() && Serial.availableForWrite()) + { + Serial.write(c); + ++serial_tx; + } + else + { + if (!fromNet.full()) + { + fromNet.write(c); + } + else + ++drop_tx; + } +} + +// Ulozeni bytu do sitoveho vystupniho bufferu +void nputchar(uint8_t c) +{ + + if (!toNet.full()) + { + toNet.write(c); + nvtt.set(baudtiming); // timeout pro odeslani bloku dat + } + else + ++drop_rx; +} + +/* + This command is sent by the client to the access server to set + special com port options. The command can also be sent to query + the current option value. The value is one octet (byte). The + value is an index into the following value table: + + Value Control Commands + 0 Request Com Port Flow Control Setting + (outbound/both) + 1 Use No Flow Control (outbound/both) + 2 Use XON/XOFF Flow Control (outbound/both) + 3 Use HARDWARE Flow Control (outbound/both) + 4 Request BREAK State + 5 Set BREAK State ON + 6 Set BREAK State OFF + 7 Request DTR Signal State + 8 Set DTR Signal State ON + 9 Set DTR Signal State OFF + 10 Request RTS Signal State + 11 Set RTS Signal State ON + 12 Set RTS Signal State OFF + 13 Request Com Port Flow Control Setting (inbound) + 14 Use No Flow Control (inbound) + 15 Use XON/XOFF Flow Control (inbound) + 16 Use HARDWARE Flow Control (inbound) + 17 Use DCD Flow Control (outbound/both) + 18 Use DTR Flow Control (inbound) + 19 Use DSR Flow Control (outbound/both) + 20-127 Available for Future Use +*/ +uint8_t setgetcontrol(uint8_t _ctrl) +{ + uint8_t result; + + TRACE(TRACE_INFO, F("Set/Get control %i"), (int)_ctrl); + switch (_ctrl) + { + case 1: + case 2: + case 3: + case 13: + case 14: + case 15: + case 16: + case 17: + case 18: + case 19: + control = _ctrl; + result = control; + break; + + case 4: + result = breakstate; + break; + + case 5: + breakstate = 1; + result = breakstate; + break; + + case 6: + breakstate = 0; + result = breakstate; + break; + + case 7: + result = dtrstate; + break; + + case 8: + dtrstate = 1; + result = dtrstate; + break; + + case 9: + dtrstate = 0; + result = dtrstate; + break; + + case 10: + result = rtsstate; + break; + + case 11: + rtsstate = 1; + result = rtsstate; + break; + + case 12: + rtsstate = 0; + result = rtsstate; + break; + + default: + TRACE(TRACE_ERROR, F("Unsupported control %i"), (int)_ctrl); + case 0: + result = control; // ziskame aktualni stav + break; + } + + return result; +} + +// Inicializace virtualniho serioveho portu NVT +void vsp_init() +{ + + Serial.begin(INITIAL_SERIAL_SPEED); +#ifdef RX_BUFFER_SIZE + int rxsize = Serial.setRxBufferSize(RX_BUFFER_SIZE); + TRACE(TRACE_INFO, F("RX buffser size set to %i"), rxsize); +#endif + Serial.setDebugOutput(false); + + // Inicializace NVT parametru + netterm.init(setserialport, sputchar, nputchar); + netterm.setSetGetCtrl(setgetcontrol); + server.begin(); +} + +void vsp_loop() +{ + int len; + + // kontrola, zda se nepripojil kilent + if (server.hasClient()) + { + if (!client || !client.connected()) + { + if (client) + client.stop(); + client = server.available(); + client.setNoDelay(true); + ++newguy; + TRACE(TRACE_INFO, "TCP: New client"); + } + WiFiClient serverClient = server.available(); + serverClient.stop(); + } + + // testovani, zda ma UART nejaka data + if (int len = Serial.available()) + { + size_t will_copy = (len < sizeof(sbuf)) ? len : sizeof(sbuf); + Serial.readBytes(sbuf, will_copy); + netterm.createsendstream(sbuf, will_copy); + serial_rx += will_copy; + } + + // testovani, zda TCP klient neposlal nejaka data + if (client && client.connected()) + { + if (len = client.available()) + { + while ((len > 0) && ((fromNet.room() >= len) || (fromNet.room() >= sizeof(sbuf)))) + { + size_t will_copy = (len < sizeof(sbuf)) ? len : sizeof(sbuf); + client.readBytes(sbuf, will_copy); +// TRACE(TRACE_INFO, F("RX:%i"), will_copy); + netterm.handlestream(sbuf, will_copy); + len -= will_copy; + } + } + } + + // testovani, zda neposlat nejaka data do TCP klienta + if (!toNet.empty() && nvtt.expired()) + { + size_t read = toNet.read((char *)&nvttx[0], sizeof(nvttx)); + + if (client && client.connected()) + { + uint32_t t = micros(); + client.write((const uint8_t *)&nvttx[0], read); // data do TCP soketu +// TRACE(TRACE_INFO, F("TX: %i, took %i us"), read, (int)micros() - t); + } + } + + // testovani, zda neposlat nejaka data do serioveho rozhrani + if (!fromNet.empty() && (len = Serial.availableForWrite())) + { + size_t will_copy = (len < sizeof(sbuf)) ? len : sizeof(sbuf); + will_copy = fromNet.read((char *)sbuf, will_copy); + Serial.write(sbuf, will_copy); + serial_tx += will_copy; + } + + if (newguy) + { + newguy = 0; + netterm.newguy(); + } +} + diff --git a/src/web.ino b/src/web.ino new file mode 100644 index 0000000..6f45e75 --- /dev/null +++ b/src/web.ino @@ -0,0 +1,212 @@ +#include + +// Obsluha weboveho serveru +Ticker deferred; // zpozdene veci (konkretne restart ESP treba po aktualizaci) +const char TEXTPLAIN[] PROGMEM = "text/plain"; +const char TEXTJSON[] PROGMEM = "text/json"; +const char TEXTHTML[] PROGMEM = "text/html"; +const char CCLEAR[] PROGMEM = "Crash area cleared!"; + +const char RESTARTING[] PROGMEM = "Restarting..."; + +void handleReset(AsyncWebServerRequest *request) +{ + + deferred.once_ms(500, []() + { + ESP.restart(); + }); + + request->send_P(200, FPSTR(TEXTPLAIN), RESTARTING); +} + +void handleEEDump(AsyncWebServerRequest *request) +{ + AsyncWebServerResponse *response = request->beginChunkedResponse("application/octet-stream", [](uint8_t *buffer, size_t maxLen, size_t index) -> size_t { + size_t written = 0; + + while ((index < EEPROM_SIZE) && (written < maxLen)) + { + buffer[written] = EEPROM.read(index); + ++index; + ++written; + } + return written; + }); + request->send(response); +} + +#ifdef USE_CRASHDUMP +void handleCrash(AsyncWebServerRequest *request) +{ + String st; + + st.reserve(2000); + crashGet(st); + request->send(200, FPSTR(TEXTHTML), st); +} + +void handleCrashClear(AsyncWebServerRequest *request) +{ + String st; + + crashClear(); + request->send_P(200, FPSTR(TEXTPLAIN), CCLEAR); +} +#endif + +void handleNotFound(AsyncWebServerRequest *request) +{ + +#ifdef CORS_DEBUG + if (request->method() == HTTP_OPTIONS) + { + request->send(200); + } + else +#endif + String message; + + message.reserve(1024); + + message = F("Page Not Found\r\n\r\nURI:"); + message.concat(request->url()); + message.concat(F("\r\nMethod: ")); + message.concat((request->method() == HTTP_GET) ? F("GET") : F("POST")); + message.concat(F("\r\nParams: ")); + message.concat(request->params()); + message.concat(F("\r\n")); + + for (unsigned int i = 0; i < request->params(); i++ ) + { + AsyncWebParameter *p = request->getParam(i); + message.concat(F(" ")); + message.concat(p->name()); + message.concat(F(": ")); + message.concat(p->value()); + message.concat(F("\r\n")); + } + request->send(404, FPSTR(TEXTPLAIN), message); +} + +void www_onUpgrade(AsyncWebServerRequest *request) +{ + AsyncWebServerResponse *response = request->beginResponse(200, FPSTR(TEXTPLAIN), Update.hasError() ? F("FAIL") : F("OK")); + + response->addHeader(FPSTR("Connection"), FPSTR("close")); + if (!Update.hasError()) + { + deferred.once_ms(100, []() + { + ESP.restart(); + }); + } + request->send(response); +} + +void www_onUpgradeData(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) +{ + + if (!index) + { + TRACE(TRACE_DEBUG, F("[UPGRADE] Start: %s"), filename.c_str()); + Update.runAsync(true); + if (!Update.begin((ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000)) + { + TRACE(TRACE_ERROR, F("[UPGRADE] Error: %i"), Update.getError()); + } + } + if (!Update.hasError()) + { + if (Update.write(data, len) != len) + { + TRACE(TRACE_ERROR, F("[UPGRADE] Error: %i"), Update.getError()); + } + } + if (final) + { + if (Update.end(true)) + { + //TRACE(TRACE_DEBUG, F("[UPGRADE] Success: %u bytes"), index + len); + } + else + { + TRACE(TRACE_ERROR, F("[UPGRADE] Error: %i"), Update.getError()); + } + } + else + { +// DEBUG_MSG_P(PSTR("[UPGRADE] Progress: %u bytes\r"), index + len); + } +} + +void www_onScan(AsyncWebServerRequest *request) +{ + String json; + + json.reserve(1024); + json = F("["); + int n = WiFi.scanComplete(); + + if (n == -2) + { + WiFi.scanNetworks(true); + } else if (n) + { + for (int i = 0; i < n; ++i) + { + if (i) + json.concat(F(",")); + json.concat(("{\"rssi\":")); + json.concat(String(WiFi.RSSI(i))); + json.concat(F(",\"ssid\":\"")); + json.concat(WiFi.SSID(i)); + json.concat(F("\",\"bssid\":\"")); + json.concat(WiFi.BSSIDstr(i)); + json.concat(F("\",\"channel\":")); + json.concat(String(WiFi.channel(i))); + json.concat(F(",\"secure\":")); + json.concat(String(WiFi.encryptionType(i))); + json.concat(F(",\"hidden\":")); + json.concat(String(WiFi.isHidden(i)?F("true"):F("false"))); + json.concat(F("}")); + } + WiFi.scanDelete(); + if (WiFi.scanComplete() == -2) + { + WiFi.scanNetworks(true); + } + } + json.concat(F("]")); + request->send(200, FPSTR(TEXTJSON), json); +} + +void webserver_init(void) +{ + + www.rewrite("/", "/index.htm"); + init_websocket(); +#ifdef HTTP_UPDATE + httpUpdater.setup(&www); +#endif +// TRACE_ADDWEB(&www); // ladici stranka +#ifdef USE_CRASHDUMP + www.on("/crash", handleCrash); + www.on("/crashclear", handleCrashClear); +#endif + www.on("/rst", handleReset); + www.on("/eedump", handleEEDump); +#ifdef USE_EDITOR + www.addHandler(new SPIFFSEditor("admin", "nimda")); +#endif +#ifdef USE_PROFILING + www.on("/profile", handleProfiling) +#endif + www.serveStatic("/", SPIFFS, "/"); + www.onNotFound(handleNotFound); +#ifdef CORS_DEBUG + DefaultHeaders::Instance().addHeader("Access-Control-Allow-Origin", "*"); + DefaultHeaders::Instance().addHeader("Access-Control-Allow-Headers", "content-type"); +#endif + www.begin(); +} diff --git a/src/websocket.ino b/src/websocket.ino new file mode 100644 index 0000000..f815835 --- /dev/null +++ b/src/websocket.ino @@ -0,0 +1,126 @@ +// +AsyncWebSocket wsStatus("/wss"); + +int wsSConnected(void) +{ + + return wsStatus.count(); +} + +void wsSSend(String &txt) +{ + + wsStatus.textAll(txt); // odesleme informace do klienta +} + +// Osetreni komunikace pres webovy soket +void wseStatus(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len) +{ + + switch (type) + { + case WS_EVT_DISCONNECT: + break; + + case WS_EVT_CONNECT: + { // zalogovani pripojeni prohlizece + +// odesilame prvni informace do klienta + String inf; + + inf.reserve(512); + inf = F("{\"type\":\"hwinfo\""); + inf.concat(F(",\"version\":\"")); + inf.concat(F(VERSION)); + inf.concat(F("\"")); + inf.concat(F("}")); + + trace_forceupdate(); // vynutime take odeslani informaci ze stopare po pripojeni + client->text(inf); // odesleme informace do klienta + } + break; + + case WS_EVT_DATA: + { + int free = ESP.getFreeHeap(); + AwsFrameInfo *info = (AwsFrameInfo *)arg; + + if (WS_TEXT == info->opcode) + { + if (!strncmp_P((const char *)data, PSTR("status"), info->len)) + { + String inf; + + inf.reserve(512); + inf = F("{\"type\":\"status\",\"ram\":"); + int load = 0; + + if (upcounter > 0) + load = 100 - (100 * loopCounterLast / loopCounterMax); + inf.concat(free); + inf.concat(F(",\"load\":")); + inf.concat(load); + inf.concat(F(",\"lc\":")); + inf.concat(loopCounterLast); + inf.concat(F("}")); + client->text(inf); + } + + if (!strncmp_P((const char *)data, PSTR("wscan"), info->len)) + { // ziskani seznamu WiFi siti v dosahu + TRACE(TRACE_INFO, F("Request WiFi scan")); + String json; + + json.reserve(2048); + json = F("["); + int n = WiFi.scanComplete(); + + if (n == -2) + { + WiFi.scanNetworks(true); + } else if (n) + { + for (int i = 0; i < n; ++i) + { + if (i) + json.concat(F(",")); + json.concat(F("{")); + json.concat(F("\"rssi\":")); + json.concat(String(WiFi.RSSI(i))); + json.concat(F(",\"ssid\":\"")); + json.concat(WiFi.SSID(i)); + json.concat(F("\",\"bssid\":\"")); + json.concat(WiFi.BSSIDstr(i)); + json.concat(F("\",\"channel\":")); + json.concat(String(WiFi.channel(i))); + json.concat(F(",\"secure\":")); + json.concat(String(WiFi.encryptionType(i))); + json.concat(F(",\"hidden\":")); + json.concat(String(WiFi.isHidden(i)?F("true"):F("false"))); + json.concat(F("}")); + } + WiFi.scanDelete(); + if (WiFi.scanComplete() == -2) + { + WiFi.scanNetworks(true); + } + } + json.concat(F("]")); + client->text(json); + } + } + } + break; + + default: + break; + } +} + +void init_websocket(void) +{ + + wsStatus.onEvent(wseStatus); + www.addHandler(&wsStatus); + TRACE_ADDWEB(&wsStatus); +} diff --git a/src/xpvsp.ino b/src/xpvsp.ino new file mode 100644 index 0000000..f9232d2 --- /dev/null +++ b/src/xpvsp.ino @@ -0,0 +1,218 @@ +/** + * Transparentni seriovy port s podporou NVT pro ESP8266 + * + * @file xpvsp.ino + * @author Pavel Brychta, http://www.xpablo.cz + * + * Copyright (c) 2016-2018 Pavel Brychta. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "configuration.h" +#include +#include +#include +#include +#include +#ifdef USE_EDITOR + #include +#endif +#include +#include +#include +#include +#ifdef HTTP_UPDATE + #include +#endif +#include +#include +#include +#if (LED_PIN != NO_PIN) + #include +#endif +#ifdef USE_SPIFFS + #warning Pouzivame SPIFFS - nezapomen pripravit obsah flash! + #include "FS.h" +#endif +#include "obfuscator.h" + +// Definice obsazeni EEPROM +#define elementSize(type, element) sizeof(((type *)0)->element) +typedef struct +{ + wificonfigarea_t wc; // oblast, vyhrazena pro konfiguraci WiFi +// **** sem pokracuji dalsi polozky, ukladane do EEPROM + +} eepromdata_t; + +#if (LED_PIN != NO_PIN) + LED led(LED_PIN, LOW, HIGH); + const uint8_t LS_CONNECTING[] = {LEDS_ONFOR + 0, LEDS_OFFFOR + 8, LEDS_RESTART}; + const uint8_t LS_CONFIGAP[] = {LEDS_ONFOR + 0, LEDS_OFFFOR + 0, LEDS_ONFOR + 0, LEDS_OFFFOR + 6, LEDS_RESTART}; + const uint8_t LS_CONNECTED[] = {LEDS_ONFOR + 0, LEDS_OFFFOR + 0, LEDS_ONFOR + 0, LEDS_OFFFOR + 0, LEDS_ONFOR + 0, LEDS_OFFFOR + 6, LEDS_RESTART}; +#endif + +#ifdef HTTP_UPDATE + ESP8266HTTPUpdateServer httpUpdater; + #ifdef HTTP_UPDATE_USERNAME + #define vxENCRYPT2(Str) (vxCplEncryptedString::Result>(Str)) + auto _huuser = vxENCRYPT2(HTTP_UPDATE_USERNAME); + auto _hupass = vxENCRYPT2(HTTP_UPDATE_PASSWORD); + #endif +#endif + +int otaActive = 0; // priznak moznosti aktivovat OTA +AsyncWebServer www(HTTP_PORT); // webovy server +Interval timer30s; // tikani po 30-ti sekundach +uint32_t upcounter; // citac poctu ubehlych 30-ti sekund (pro mereni uptime) +// Profiling +uint32_t start = 0; +uint32_t elapsed = 0; +uint32_t loopCounter = 0; +uint32_t loopCounterLast = 0; +uint32_t loopCounterMax = 1; +// **** sem je mozne dopsat dalsi globalni promenne + +void wificfgcb(wificonfigstate_t state) +{ + + switch (state) + { + case WCS_CONNECTSTART: + // **** kod pro start signalizace, oznamujici zacatek pripojovani k WiFi siti (volano pouze jednou) +#if (LED_PIN != NO_PIN) + led.set(LS_CONNECTING); +#endif + + break; + + case WCS_CONNECTING: + // **** kod pro periodickou signalizaci probihajiciho pripojovani k WiFi siti (volano periodicky) + + break; + + case WCS_CONNECTED: + // **** kod pro start signalizace uspesneho pripojeni k WiFi siti (volano pouze jednou) +#if (LED_PIN != NO_PIN) + led.set(LS_CONNECTED); +#endif + + break; + + case WCS_CONFIGSTART: + // **** kod pro start signalizace, oznamujici spusteni konfiguracniho AP (volano pouze jednou) +#if (LED_PIN != NO_PIN) + led.set(LS_CONFIGAP); +#endif + + break; + + case WCS_CONFIGWAIT: + // **** kod pro periodickou signalizaci beziciho konfiguracniho AP (volano periodicky) + + break; + } +} + +void runEach30Seconds(void) +{ + + timer30s.set(30000); // nove nastaveni casovace + ++upcounter; // celkova delka behu + +// mereni pro vypocet zatizeni zarizeni + loopCounterLast = loopCounter; + loopCounter = 0; + if (loopCounterLast > loopCounterMax) + loopCounterMax = loopCounterLast; +} + +void ICACHE_FLASH_ATTR setup() +{ + int _fc; + + TRACE_INIT; // inicializace ladeni + EEPROM.begin(sizeof(eepromdata_t) + 10); // zahajujeme praci s EEPROM (10 bytu je jen rezerva) +#if (LED_PIN != NO_PIN) + led.begin(); // inicializace signalizace +#endif + +#if (FORCE_CONFIG_BUTTON_PIN != NO_PIN) + pinMode(FORCE_CONFIG_BUTTON_PIN, INPUT_PULLUP); + delay(20); // male zpozdeni, aby se ustalila hodnota na vstupu + _fc = digitalRead(FORCE_CONFIG_BUTTON_PIN); // pokud je na I/O pinu hodnota 0, tak vynutime nastavovaci AP +#else + _fc = 1; // nevstupujeme do konfigurace +#endif + { + WiFiConfig wifi; // konfigurace WiFi casti ESP modulu + + if (WCR_OK != wifi.begin(offsetof(eepromdata_t, wc), _fc, 60, wificfgcb)) // startujeme pripojeni + ESP.restart(); + } + if (ESP.getFlashChipRealSize() > 1000000) + otaActive = 1; // flash pameti je dost - povolime OTA + + if (strlen(WiFiDeviceName)) + { + NBNS.begin(WiFiDeviceName); + if (otaActive) + { + ArduinoOTA.setHostname(WiFiDeviceName); + ArduinoOTA.begin(); + TRACE(TRACE_INFO, F("OTA aktivovano")); + } + else + { + MDNS.begin(WiFiDeviceName); + MDNS.addService("http", "tcp", HTTP_PORT); + } + } +// montaz souboroveho systemu +#ifdef USE_SPIFFS + if (!SPIFFS.begin()) + TRACE(TRACE_ERROR, F("SPIFFS neni pripojeny!")); +#endif +// Start weboveho serveru - sem je mozno pridavat odkazy na dalsi stranky + +#ifdef HTTP_UPDATE + #ifndef HTTP_UPDATE_USERNAME + httpUpdater.setup(&www); + #else + httpUpdater.setup(&www, _huuser.decrypt(), _hupass.decrypt()); + #endif +#endif + + webserver_init(); // startujeme webovy server + vsp_init(); +// **** dalsi uzivatelska inicializace +} + +void loop() +{ + + if (otaActive) + { // pripadna obsluha OTA aktualizace FW + ArduinoOTA.handle(); + } + TRACE_POLL; + if (timer30s.expired()) + runEach30Seconds(); + ++loopCounter; +// **** dalsi uzivatelske metody + vsp_loop(); +}