#include <WiFi.h>
char const * AUTOEXEC = "info\r"
"keyb us\r"
"scan\r";
enum class State { Prompt,
PromptInput,
UnknownCommand,
Help,
Wifi,
TelnetInit,
Telnet,
Scan,
Ping,
Reset,
Keyb
};
State state = State::Prompt;
WiFiClient client;
char const * currentScript = nullptr;
bool error = false;
void exe_info()
{
Terminal.
write(
"\e[97m* * FabGL - Network VT/ANSI Terminal\r\n");
Terminal.
write(
"\e[94m* * 2019-2022 by Fabrizio Di Vittorio - www.fabgl.com\e[92m\r\n\n");
Terminal.printf(
"\e[92mTerminal Size :\e[93m %d x %d\r\n", Terminal.
getColumns(), Terminal.
getRows());
Terminal.printf("\e[92mFree DMA Memory :\e[93m %d\r\n", heap_caps_get_free_size(MALLOC_CAP_DMA));
Terminal.printf("\e[92mFree 32 bit Memory :\e[93m %d\r\n", heap_caps_get_free_size(MALLOC_CAP_32BIT));
if (WiFi.status() == WL_CONNECTED) {
Terminal.printf("\e[92mWiFi SSID :\e[93m %s\r\n", WiFi.SSID().c_str());
Terminal.printf("\e[92mCurrent IP :\e[93m %s\r\n", WiFi.localIP().toString().c_str());
}
Terminal.
write(
"\n\e[92mType \e[93mhelp\e[92m to print all available commands.\r\n");
error = false;
state = State::Prompt;
}
void exe_help()
{
Terminal.
write(
"\e[93mhelp\e[92m\r\n");
Terminal.
write(
"\e[97m Shows this help.\r\n");
Terminal.
write(
"\e[93minfo\r\n");
Terminal.
write(
"\e[97m Shows system info.\r\n");
Terminal.
write(
"\e[93mscan\r\n");
Terminal.
write(
"\e[97m Scan for WiFi networks.\r\n");
Terminal.
write(
"\e[93mwifi [SSID PASSWORD]\r\n");
Terminal.
write(
"\e[97m Connect to SSID using PASSWORD.\r\n");
Terminal.
write(
"\e[97m Example:\r\n");
Terminal.
write(
"\e[97m wifi MyWifi MyPassword\r\n");
Terminal.
write(
"\e[93mtelnet HOST [PORT]\r\n");
Terminal.
write(
"\e[97m Open telnet session with HOST (IP or host name) using PORT.\r\n");
Terminal.
write(
"\e[97m Example:\r\n");
Terminal.
write(
"\e[97m telnet towel.blinkenlights.nl\e[92m\r\n");
Terminal.
write(
"\e[93mping HOST\r\n");
Terminal.
write(
"\e[97m Ping a HOST (IP or host name).\r\n");
Terminal.
write(
"\e[97m Example:\r\n");
Terminal.
write(
"\e[97m ping 8.8.8.8\e[92m\r\n");
Terminal.
write(
"\e[93mreboot\r\n");
Terminal.
write(
"\e[97m Restart the system.\e[92m\r\n");
Terminal.
write(
"\e[93mkeyb LAYOUT\r\n");
Terminal.
write(
"\e[97m Set keyboard layout. LAYOUT can be 'us', 'uk', 'de', 'it', 'es', 'fr', 'be', 'no'\r\n");
Terminal.
write(
"\e[97m Example:\r\n");
Terminal.
write(
"\e[97m keyb de\e[92m\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", 6) == 0)
state = State::Reset;
else if (strncmp(inputLine, "keyb", 4) == 0)
state = State::Keyb;
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...");
int networksCount = WiFi.scanNetworks();
Terminal.printf("%d network(s) found\r\n", networksCount);
if (networksCount) {
Terminal.
write (
"\e[90m #\e[4GSSID\e[45GRSSI\e[55GCh\e[60GEncryption\e[92m\r\n");
for (int i = 0; i < networksCount; ++i)
Terminal.printf("\e[93m %d\e[4G%s\e[93m\e[45G%d dBm\e[55G%d\e[60G%s\e[92m\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("connected to %s, IP is %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;
}
}
int clientWaitForChar()
{
while (!client.available())
;
return client.read();
}
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(
"%d bytes from %s: icmp_seq=%d ttl=%d time=%.3f ms\r\n", icmp.
receivedBytes(), icmp.
hostIP().toString().c_str(), icmp.
receivedSeq(), icmp.
receivedTTL(), (
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("Request timeout for icmp_seq %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 exe_keyb()
{
char layout[3];
auto inputLine = LineEditor.get();
if (sscanf(inputLine, "keyb %2s", layout) == 1) {
if (strcasecmp(layout, "US") == 0)
else if (strcasecmp(layout, "UK") == 0)
else if (strcasecmp(layout, "DE") == 0)
else if (strcasecmp(layout, "IT") == 0)
else if (strcasecmp(layout, "ES") == 0)
else if (strcasecmp(layout, "FR") == 0)
else if (strcasecmp(layout, "BE") == 0)
else if (strcasecmp(layout, "NO") == 0)
else {
Terminal.printf("Error! Invalid keyboard layout.\r\n");
state = State::Prompt;
return;
}
}
Terminal.printf(
"\r\nKeyboard layout is : \e[93m%s\e[92m\r\n\r\n", Terminal.
keyboard()->
getLayout()->
desc);
} else {
Terminal.printf("No keyboard present\r\n");
}
state = State::Prompt;
}
void setup()
{
PS2Controller.
begin(PS2Preset::KeyboardPort0);
DisplayController.
begin();
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::Keyb:
exe_keyb();
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.
int getViewPortHeight()
Determines vertical size of the viewport.
int getViewPortWidth()
Determines horizontal size of the viewport.
void setLayout(KeyboardLayout const *layout)
Sets keyboard layout.
KeyboardLayout const * getLayout()
Gets current keyboard layout.
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 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.
size_t write(const uint8_t *buffer, size_t size)
Sends specified number of codes to the display.
Keyboard * keyboard()
Gets associated keyboard object.
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.
void begin(gpio_num_t redGPIO, gpio_num_t greenGPIO, gpio_num_t blueGPIO, gpio_num_t HSyncGPIO, gpio_num_t VSyncGPIO)
This is the 8 colors (5 GPIOs) initializer.
void setResolution(char const *modeline=nullptr, int viewPortWidth=-1, int viewPortHeight=-1, bool doubleBuffered=false)
Sets fixed resolution.
Represents the VGA text-only controller.
This file is the all in one include file. Application can just include this file to use FabGL library...