Pracovni prvni odevzdani - zatim nefunkcni!

This commit is contained in:
Pavel Brychta 2018-06-26 10:48:12 +02:00
parent 76eae4e788
commit 691ecffe39
20 changed files with 2150 additions and 34 deletions

43
.gitignore vendored
View File

@ -1,34 +1,9 @@
# ---> C++ .pioenvs
# Prerequisites .piolibdeps
*.d .clang_complete
.gcc-flags.json
# Compiled Object files .pioenvs
*.slo .piolibdeps
*.lo .vscode/.browse.c_cpp.db*
*.o .vscode/c_cpp_properties.json
*.obj .vscode/launch.json
# 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

55
.travis.yml Normal file
View File

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

7
.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,7 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"platformio.platformio-ide"
]
}

6
.vscode/settings.json vendored Normal file
View File

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

20
eagle.flash.4m2m.ld Normal file
View File

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

117
lib/led/led.cpp Normal file
View File

@ -0,0 +1,117 @@
// Obsluha LED signalizace
#include <Arduino.h>
#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<void *>(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<PGM_P>(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<LED *>(ptr);
LED *pled = ptr;
pled->rtLed();
}

72
lib/led/led.h Normal file
View File

@ -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 <Ticker.h>
#include <pgmspace.h>
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

41
lib/readme.txt Normal file
View File

@ -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 <Foo.h>
#include <Bar.h>
// 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

View File

@ -0,0 +1,36 @@
extern "C" {
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
}
#include <Arduino.h>
#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;
}

30
lib/uinterval/uinterval.h Normal file
View File

@ -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 <inttypes.h>
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

24
platformio.ini Normal file
View File

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

73
src/configuration.h Normal file
View File

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

425
src/nvt.cpp Normal file
View File

@ -0,0 +1,425 @@
#include "configuration.h"
#include "nvt.h"
#include "nvt_int.h"
#include <string.h>
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 <IAC>
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 <IAC><IAC> escapovany byte ze subnegotiation sekvence
else
terminalescape(dta); // byl to nejaky povel - doufame, ze to byl <SE>
break;
case NVT_IAC_FOUND:
_streamstate = NVT_IAC_HUNT;
if (NVT_IAC == dta)
terminalbyte(dta); // data do vystupu (->serial)
else // slo o <IAC><povel> - 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

107
src/nvt.h Normal file
View File

@ -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 <stdint.h>
#include <stdbool.h>
#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 <SB> a ukonceny <SE>
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

46
src/nvt_int.h Normal file
View File

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

132
src/obfuscator.h Normal file
View File

@ -0,0 +1,132 @@
#include <stdio.h>
#include <stdint.h>
//-------------------------------------------------------------//
// "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 <uint32_t Const> 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<vxCplRandom(__COUNTER__ + 1)>::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<vxCplHash(Str)>::Value ^ vxCplConstantify<vxCplRandom(1)>::Value)
// Compile-time generator for list of indexes (0, 1, 2, ...)
template <uint32_t...> struct vxCplIndexList {};
template <typename IndexList, uint32_t Right> struct vxCplAppend;
template <uint32_t... Left, uint32_t Right> struct vxCplAppend<vxCplIndexList<Left...>, Right> { typedef vxCplIndexList<Left..., Right> Result; };
template <uint32_t N> struct vxCplIndexes { typedef typename vxCplAppend<typename vxCplIndexes<N - 1>::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 <typename IndexList> struct vxCplEncryptedString;
template <uint32_t... Idx> struct vxCplEncryptedString<vxCplIndexList<Idx...> >
{
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<vxCplIndexes<sizeof(Str) - 1>::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<vxCplIndexes<sizeof(Str) - 1>::Result>(Str))
auto enc = vxENCRYPT2("secret");
printf("str: %s\n", enc.decrypt());
*/

394
src/vsp.ino Normal file
View File

@ -0,0 +1,394 @@
//#include <Arduino.h>
#include <cbuf.h>
#include "nvt.h"
#include <uinterval.h>
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();
}
}

212
src/web.ino Normal file
View File

@ -0,0 +1,212 @@
#include <Arduino.h>
// 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();
}

126
src/websocket.ino Normal file
View File

@ -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);
}

218
src/xpvsp.ino Normal file
View File

@ -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 <EEPROM.h>
#include <ESP8266WiFi.h>
#include <ESPAsyncTCP.h>
#include <ESPAsyncUDP.h>
#include <ESPAsyncWebServer.h>
#ifdef USE_EDITOR
#include <SPIFFSEditor.h>
#endif
#include <ArduinoOTA.h>
#include <ESP8266mDNS.h>
#include <Ticker.h>
#include <SPI.h>
#ifdef HTTP_UPDATE
#include <ESP8266HTTPUpdateServer.h>
#endif
#include <interval.h>
#include <ESP8266NetBIOS.h>
#include <WiFiConfig.h>
#if (LED_PIN != NO_PIN)
#include <led.h>
#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<vxCplIndexes<sizeof(Str) - 1>::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();
}