#include <WiFi.h>
#define OLED_SDA GPIO_NUM_4
#define OLED_SCL GPIO_NUM_15
#define OLED_ADDR 0x3C
#define OLED_RESET GPIO_UNUSED
char const * AUTOEXEC = "info\r";
enum class State { Prompt, PromptInput, UnknownCommand, Help,
Info, Wifi, TelnetInit, Telnet, Scan, Ping, Reset };
State state = State::Prompt;
WiFiClient client;
char const * currentScript = nullptr;
bool error = false;
int clientWaitForChar()
{
while (!client.available())
;
return client.read();
}
int termWaitForChar()
{
;
}
void exe_info()
{
Terminal.
write(
"FabGL Terminal\r\n");
Terminal.printf(
"Terminal Size: %dx%d\r\n", Terminal.
getColumns(), Terminal.
getRows());
Terminal.
write(
"Keyboard Error!!\r\n");
Terminal.printf("Free Mem: %d\r\n", heap_caps_get_free_size(0));
if (WiFi.status() == WL_CONNECTED) {
Terminal.printf("WiFi SSID: %s\r\n", WiFi.SSID().c_str());
Terminal.printf("IP: %s\r\n", WiFi.localIP().toString().c_str());
}
Terminal.
write(
"Type 'help' for info\r\n");
error = false;
state = State::Prompt;
}
void exe_help()
{
Terminal.
write(
"info\r\n");
Terminal.
write(
" Shows system info.\r\n\r\n");
termWaitForChar();
Terminal.
write(
"scan\r\n");
Terminal.
write(
" Scan for WiFi networks.\r\n\r\n");
termWaitForChar();
Terminal.
write(
"wifi SSID PASSWORD\r\n");
Terminal.
write(
" Connect to SSID using PASSWORD.\r\n\r\n");
termWaitForChar();
Terminal.
write(
"telnet HOST [PORT]\r\n");
Terminal.
write(
" Open telnet session with HOST (IP or host name) using PORT.\r\n\r\n");
termWaitForChar();
Terminal.
write(
"reboot\r\n");
Terminal.
write(
" Restart the system.\r\n\r\n");
error = false;
state = State::Prompt;
}
void decode_command()
{
auto inputLine = LineEditor.get();
if (*inputLine == 0)
state = State::Prompt;
else if (strncmp(inputLine, "help", 4) == 0)
state = State::Help;
else if (strncmp(inputLine, "info", 4) == 0)
state = State::Info;
else if (strncmp(inputLine, "wifi", 4) == 0)
state = State::Wifi;
else if (strncmp(inputLine, "telnet", 6) == 0)
state = State::TelnetInit;
else if (strncmp(inputLine, "scan", 4) == 0)
state = State::Scan;
else if (strncmp(inputLine, "ping", 4) == 0)
state = State::Ping;
else if (strncmp(inputLine, "reboot", 4) == 0)
state = State::Reset;
else
state = State::UnknownCommand;
}
void exe_prompt()
{
if (currentScript) {
if (*currentScript == 0 || error) {
currentScript = nullptr;
state = State::Prompt;
} else {
int linelen = strchr(currentScript, '\r') - currentScript;
LineEditor.setText(currentScript, linelen);
currentScript += linelen + 1;
decode_command();
}
} else {
state = State::PromptInput;
}
}
void exe_promptInput()
{
LineEditor.setText("");
LineEditor.edit();
decode_command();
}
void exe_scan()
{
static char const * ENC2STR[] = { "Open", "WEP", "WPA-PSK", "WPA2-PSK", "WPA/WPA2-PSK", "WPA-ENTERPRISE" };
Terminal.
write(
"Scanning...\r\n");
int networksCount = WiFi.scanNetworks();
Terminal.printf("%d network(s)\r\n", networksCount);
if (networksCount) {
for (int i = 0; i < networksCount; ++i)
Terminal.printf("#%d %s %ddBm ch%d %s\r\n", i + 1, WiFi.SSID(i).c_str(), WiFi.RSSI(i), WiFi.channel(i), ENC2STR[WiFi.encryptionType(i)]);
}
WiFi.scanDelete();
error = false;
state = State::Prompt;
}
void exe_wifi()
{
static const int MAX_SSID_SIZE = 32;
static const int MAX_PSW_SIZE = 32;
char ssid[MAX_SSID_SIZE + 1];
char psw[MAX_PSW_SIZE + 1] = {0};
error = true;
auto inputLine = LineEditor.get();
if (sscanf(inputLine, "wifi %32s %32s", ssid, psw) >= 1) {
Terminal.
write(
"Connecting WiFi...");
WiFi.disconnect(true, true);
for (int i = 0; i < 2; ++i) {
WiFi.begin(ssid, psw);
if (WiFi.waitForConnectResult() == WL_CONNECTED)
break;
WiFi.disconnect(true, true);
}
if (WiFi.status() == WL_CONNECTED) {
Terminal.printf("SSID: %s\r\nIP: %s\r\n", WiFi.SSID().c_str(), WiFi.localIP().toString().c_str());
error = false;
} else {
Terminal.
write(
"failed!\r\n");
}
}
state = State::Prompt;
}
void exe_telnetInit()
{
static const int MAX_HOST_SIZE = 32;
char host[MAX_HOST_SIZE + 1];
int port;
error = true;
auto inputLine = LineEditor.get();
int pCount = sscanf(inputLine, "telnet %32s %d", host, &port);
if (pCount > 0) {
if (pCount == 1)
port = 23;
Terminal.printf("Trying %s...\r\n", host);
if (client.connect(host, port)) {
Terminal.printf("Connected to %s\r\n", host);
error = false;
state = State::Telnet;
} else {
Terminal.
write(
"Unable to connect to remote host\r\n");
state = State::Prompt;
}
} else {
Terminal.
write(
"Mistake\r\n");
state = State::Prompt;
}
}
void exe_telnet()
{
for (int i = 0; client.available() && i < 1024; ++i) {
int c = client.read();
if (c == 0xFF) {
uint8_t cmd = clientWaitForChar();
uint8_t opt = clientWaitForChar();
if (cmd == 0xFD && opt == 0x1F) {
client.write("\xFF\xFB\x1F", 3);
client.write("\xFF\xFA\x1F" "\x00\x50\x00\x19" "\xFF\xF0", 9);
} else if (cmd == 0xFD && opt == 0x18) {
client.write("\xFF\xFB\x18", 3);
} else if (cmd == 0xFA && opt == 0x18) {
c = clientWaitForChar();
c = clientWaitForChar();
c = clientWaitForChar();
client.write("\xFF\xFA\x18\x00" "wsvt25" "\xFF\xF0", 12);
} else {
uint8_t pck[3] = {0xFF, 0, opt};
if (cmd == 0xFD)
pck[1] = 0xFC;
else if (cmd == 0xFB)
pck[1] = 0xFD;
client.write(pck, 3);
}
} else {
}
}
client.write( Terminal.
read() );
}
if (!client.connected()) {
client.stop();
state = State::Prompt;
}
}
void exe_ping()
{
char host[64];
auto inputLine = LineEditor.get();
int pcount = sscanf(inputLine, "ping %s", host);
if (pcount > 0) {
int sent = 0, recv = 0;
while (true) {
break;
if (t >= 0) {
Terminal.printf(
"%s %d %dms\r\n", icmp.
hostIP().toString().c_str(), icmp.
receivedSeq(), (
int)((
double)t/1000.0));
delay(1000);
++recv;
} else if (t == -2) {
Terminal.printf("Cannot resolve %s: Unknown host\r\n", host);
break;
} else {
Terminal.printf("Timeout s=%d\r\n", icmp.receivedSeq());
}
++sent;
}
if (sent > 0) {
Terminal.printf("--- %s ping statistics ---\r\n", host);
Terminal.printf("%d packets transmitted, %d packets received, %.1f%% packet loss\r\n", sent, recv, (double)(sent - recv) / sent * 100.0);
}
}
state = State::Prompt;
}
void setup()
{
PS2Controller.
begin(PS2Preset::KeyboardPort0);
I2C.begin(OLED_SDA, OLED_SCL);
DisplayController.
begin(&I2C, OLED_ADDR, OLED_RESET);
Terminal.
begin(&DisplayController);
currentScript = AUTOEXEC;
}
void loop()
{
switch (state) {
case State::Prompt:
exe_prompt();
break;
case State::PromptInput:
exe_promptInput();
break;
case State::Help:
exe_help();
break;
case State::Info:
exe_info();
break;
case State::Wifi:
exe_wifi();
break;
case State::TelnetInit:
exe_telnetInit();
break;
case State::Telnet:
exe_telnet();
break;
case State::Scan:
exe_scan();
break;
case State::Ping:
exe_ping();
break;
case State::Reset:
ESP.restart();
break;
case State::UnknownCommand:
Terminal.
write(
"\r\nMistake\r\n");
state = State::Prompt;
break;
default:
Terminal.
write(
"\r\nNot Implemeted\r\n");
state = State::Prompt;
break;
}
}
This file contains ICMP (ping) class.
I2C class allows multiple tasks to communicate with I2C devices, serializing read/write jobs.
bool isKeyboardAvailable()
Checks if keyboard has been detected and correctly initialized.
LineEditor is a single-line / multiple-rows editor which uses the Terminal object as input and output...
static Keyboard * keyboard()
Returns the instance of Keyboard object automatically created by PS2Controller.
static void begin(gpio_num_t port0_clkGPIO, gpio_num_t port0_datGPIO, gpio_num_t port1_clkGPIO=GPIO_UNUSED, gpio_num_t port1_datGPIO=GPIO_UNUSED)
Initializes PS2 device controller.
The PS2 device controller class.
void setResolution(char const *modeline, int viewPortWidth=-1, int viewPortHeight=-1, bool doubleBuffered=false)
Sets SSD1306 resolution and viewport size.
void begin(I2C *i2c, int address=0x3C, gpio_num_t resetGPIO=GPIO_UNUSED)
Initializes SSD1306 assigning I2C bus, reset pin and address.
Display driver for SSD1306 based OLED display, with I2C connection.
void connectLocally()
Permits using of terminal locally.
int getRows()
Returns the number of lines.
void clear(bool moveCursor=true)
Clears the screen.
int available()
Gets the number of codes available in the keyboard queue.
int getColumns()
Returns the number of columns.
void loadFont(FontInfo const *font)
Sets the font to use.
size_t write(const uint8_t *buffer, size_t size)
Sends specified number of codes to the display.
int read()
Reads codes from keyboard.
void enableCursor(bool value)
Enables or disables cursor.
void setBackgroundColor(Color color, bool setAsDefault=true)
Sets the background color.
bool begin(BaseDisplayController *displayController, int maxColumns=-1, int maxRows=-1, Keyboard *keyboard=nullptr)
Initializes the terminal.
void flush(bool waitVSync)
Waits for all codes sent to the display has been processed.
void setForegroundColor(Color color, bool setAsDefault=true)
Sets the foreground color.
An ANSI-VT100 compatible display terminal.
This file is the all in one include file. Application can just include this file to use FabGL library...