From 68e336ff52ead559a3139d99a54b3413cbf3cde9 Mon Sep 17 00:00:00 2001 From: Lennart Hennigs Date: Thu, 3 Mar 2022 20:18:24 +0100 Subject: [PATCH] added line mode, as described in #17 --- CHANGELOG.md | 1 + README.md | 1 + .../TelnetServerLineMode.ino | 151 ++++++++++++++++++ keywords.txt | 4 +- src/ESPTelnet.cpp | 41 ++++- src/ESPTelnet.h | 8 +- 6 files changed, 195 insertions(+), 11 deletions(-) create mode 100644 examples/TelnetServerLineMode/TelnetServerLineMode.ino diff --git a/CHANGELOG.md b/CHANGELOG.md index 1affd93..b23628c 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Changelog ## Unreleased (but available on Github) +- Added a line mode toggle as suggested in [#17](https://github.com/LennartHennigs/ESPTelnet/pull/17) - Changed `String` arguments to `const String &` and `WiFiClient` argument to `WiFiClient &` to avoid copies as requested in pull request [#16](https://github.com/LennartHennigs/ESPTelnet/pull/16) - You can now define a custom port via the `begin(uint16_t port)` function as requested in [#18](https://github.com/LennartHennigs/ESPTelnet/issues/18) - Added a `clientDisconnect()` function as requested in [#18](https://github.com/LennartHennigs/ESPTelnet/issues/18) diff --git a/README.md b/README.md index a0461c9..450a75b 100755 --- a/README.md +++ b/README.md @@ -39,6 +39,7 @@ __Output and Input__ - Via `print()` and `println()` you can output text on the telnet server. - To receive and parse input from the telnet client you can add a handler via `onInputReceived()`. +- By default, the library waits for a newline character from the client, and sends data to the callback handler one line at a time. This behaviour can be deactivated by calling `setlineMode(false)`. __Using it to Debug Code__ - A common use case is to use it for debuging remote devices, where you might not have access to Serial. Thus I added a few macros to make debugging easier: diff --git a/examples/TelnetServerLineMode/TelnetServerLineMode.ino b/examples/TelnetServerLineMode/TelnetServerLineMode.ino new file mode 100644 index 0000000..f0d61a9 --- /dev/null +++ b/examples/TelnetServerLineMode/TelnetServerLineMode.ino @@ -0,0 +1,151 @@ +/* ------------------------------------------------- */ + +#include "ESPTelnet.h" + +/* ------------------------------------------------- */ + +#define SERIAL_SPEED 9600 +#define WIFI_SSID "MY SSID" +#define WIFI_PASSWORD "MY PASS" + +/* ------------------------------------------------- */ + + +ESPTelnet telnet; +IPAddress ip; +uint16_t port = 23; + +/* ------------------------------------------------- */ + +void setupSerial(long speed, String msg = "") { + Serial.begin(speed); + while (!Serial) { + } + delay(200); + Serial.println(); + Serial.println(); + if (msg != "") Serial.println(msg); +} + +/* ------------------------------------------------- */ + +bool isConnected() { + return (WiFi.status() == WL_CONNECTED); +} + +/* ------------------------------------------------- */ + +bool connectToWiFi(const char* ssid, const char* password, int max_tries = 20, int pause = 500) { + int i = 0; + WiFi.mode(WIFI_STA); + #if defined(ARDUINO_ARCH_ESP8266) + WiFi.forceSleepWake(); + delay(200); + #endif + WiFi.begin(ssid, password); + do { + delay(pause); + Serial.print("."); + } while (!isConnected() || i++ < max_tries); + WiFi.setAutoReconnect(true); + WiFi.persistent(true); + return isConnected(); +} + +/* ------------------------------------------------- */ + +void errorMsg(String error, bool restart = true) { + Serial.println(error); + if (restart) { + Serial.println("Rebooting now..."); + delay(2000); + ESP.restart(); + delay(2000); + } +} + +/* ------------------------------------------------- */ + +void setupTelnet() { + // passing on functions for various telnet events + telnet.onConnect(onTelnetConnect); + telnet.onConnectionAttempt(onTelnetConnectionAttempt); + telnet.onReconnect(onTelnetReconnect); + telnet.onDisconnect(onTelnetDisconnect); + + // passing a lambda function + telnet.onInputReceived([](String str) { + Serial.print(str); + }); + + telnet.setLineMode(false); + Serial.print("- Telnet Line Mode: "); Serial.println(telnet.isLineModeSet() ? "YES" : "NO"); + + Serial.print("- Telnet: "); + if (telnet.begin(port)) { + Serial.println("running"); + } else { + Serial.println("error."); + errorMsg("Will reboot..."); + } +} + +/* ------------------------------------------------- */ + +// (optional) callback functions for telnet events +void onTelnetConnect(String ip) { + Serial.print("- Telnet: "); + Serial.print(ip); + Serial.println(" connected"); + telnet.println("\nWelcome " + telnet.getIP()); + telnet.println("(Use ^] + q to disconnect.)"); +} + +void onTelnetDisconnect(String ip) { + Serial.print("- Telnet: "); + Serial.print(ip); + Serial.println(" disconnected"); +} + +void onTelnetReconnect(String ip) { + Serial.print("- Telnet: "); + Serial.print(ip); + Serial.println(" reconnected"); +} + +void onTelnetConnectionAttempt(String ip) { + Serial.print("- Telnet: "); + Serial.print(ip); + Serial.println(" tried to connected"); +} + +/* ------------------------------------------------- */ + +void setup() { + setupSerial(SERIAL_SPEED, "Telnet Test"); + + Serial.print("- Wifi: "); + connectToWiFi(WIFI_SSID, WIFI_PASSWORD); + + if (isConnected()) { + ip = WiFi.localIP(); + Serial.println(); + Serial.print("- Telnet: "); Serial.print(ip); Serial.print(" "); Serial.println(port); + setupTelnet(); + } else { + Serial.println(); + errorMsg("Error connecting to WiFi"); + } +} + +/* ------------------------------------------------- */ + +void loop() { + telnet.loop(); + + // send serial input to telnet as output + if (Serial.available()) { + telnet.print(Serial.read()); + } +} +//* ------------------------------------------------- */ \ No newline at end of file diff --git a/keywords.txt b/keywords.txt index f98c8e4..585919f 100755 --- a/keywords.txt +++ b/keywords.txt @@ -13,4 +13,6 @@ onReconnect KEYWORD2 onDisconnect KEYWORD2 onInputReceived KEYWORD2 emptyClientStream KEYWORD2 -isClientConnected KEYWORD2 \ No newline at end of file +isClientConnected KEYWORD2 +isLineModeSet KEYWORD2 +setLineMode KEYWORD2 \ No newline at end of file diff --git a/src/ESPTelnet.cpp b/src/ESPTelnet.cpp index fc95d74..9732a57 100755 --- a/src/ESPTelnet.cpp +++ b/src/ESPTelnet.cpp @@ -111,18 +111,31 @@ void ESPTelnet::loop() { // gather input if (client && isConnected && client.available()) { char c = client.read(); - if (c != '\n') { - if (c >= 32 && c < 127) { - input += c; + // collect string + if (_lineMode) { + if (c != '\n') { + if (c >= 32 && c < 127) { + input += c; + } + // EOL -> send input + } else { + if (on_input != NULL) on_input(input); + input = ""; } - // EOL -> send input + // send indvidual characters } else { - if (on_input != NULL) on_input(input); - input = ""; + if (on_input != NULL) { + if (input.length()) { + on_input(input + c); + input = ""; + } else { + on_input(String(c)); + } } + } } - yield(); - } + yield(); +} /* ------------------------------------------------- */ @@ -166,6 +179,18 @@ String ESPTelnet::getIP() const { /* ------------------------------------------------- */ +bool ESPTelnet::isLineModeSet() { + return _lineMode; +} + +/* ------------------------------------------------- */ + +void ESPTelnet::setLineMode(bool value) { + _lineMode = value; +} + +/* ------------------------------------------------- */ + String ESPTelnet::getLastAttemptIP() const { return attemptIp; } diff --git a/src/ESPTelnet.h b/src/ESPTelnet.h index 02c5aff..26de304 100755 --- a/src/ESPTelnet.h +++ b/src/ESPTelnet.h @@ -34,6 +34,9 @@ class ESPTelnet { void println(const char c); void println(); + bool isLineModeSet(); + void setLineMode(bool value); + String getIP() const; String getLastAttemptIP() const; @@ -42,7 +45,7 @@ class ESPTelnet { void onReconnect(CallbackFunction f); void onDisconnect(CallbackFunction f); void onInputReceived(CallbackFunction f); - + void disconnectClient(); protected: @@ -53,7 +56,8 @@ class ESPTelnet { String attemptIp; String input = ""; uint16_t server_port = 23; - + bool _lineMode = true; + bool isClientConnected(WiFiClient &client); void emptyClientStream();