You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

210 lines
6.8 KiB

6 years ago
  1. #include <Arduino.h>
  2. /*
  3. WiFiTelnetToSerial - Example Transparent UART to Telnet Server for esp8266
  4. Copyright (c) 2015 Hristo Gochkov. All rights reserved.
  5. This file is part of the ESP8266WiFi library for Arduino environment.
  6. This library is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU Lesser General Public
  8. License as published by the Free Software Foundation; either
  9. version 2.1 of the License, or (at your option) any later version.
  10. This library is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. Lesser General Public License for more details.
  14. You should have received a copy of the GNU Lesser General Public
  15. License along with this library; if not, write to the Free Software
  16. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  17. */
  18. #include <ESP8266WiFi.h>
  19. #include <algorithm> // std::min
  20. #ifndef STASSID
  21. #define STASSID "ZyXEL5500bT5"
  22. #define STAPSK "eBusgxczl5"
  23. #endif
  24. /*
  25. SWAP_PINS:
  26. 0: use Serial1 for logging (legacy example)
  27. 1: configure Hardware Serial port on RX:GPIO13 TX:GPIO15
  28. and use SoftwareSerial for logging on
  29. standard Serial pins RX:GPIO3 and TX:GPIO1
  30. */
  31. #define SWAP_PINS 0
  32. /*
  33. SERIAL_LOOPBACK
  34. 0: normal serial operations
  35. 1: RX-TX are internally connected (loopback)
  36. */
  37. #define SERIAL_LOOPBACK 0
  38. #define BAUD_SERIAL 115200
  39. #define BAUD_LOGGER 115200
  40. #define RXBUFFERSIZE 1024
  41. ////////////////////////////////////////////////////////////
  42. #if SERIAL_LOOPBACK
  43. #undef BAUD_SERIAL
  44. #define BAUD_SERIAL 3000000
  45. #include <esp8266_peri.h>
  46. #endif
  47. #if SWAP_PINS
  48. #include <SoftwareSerial.h>
  49. SoftwareSerial* logger = nullptr;
  50. #else
  51. #define logger (&Serial1)
  52. #endif
  53. #define STACK_PROTECTOR 512 // bytes
  54. //how many clients should be able to telnet to this ESP8266
  55. #define MAX_SRV_CLIENTS 2
  56. const char* ssid = STASSID;
  57. const char* password = STAPSK;
  58. const int port = 23;
  59. WiFiServer server(port);
  60. WiFiClient serverClients[MAX_SRV_CLIENTS];
  61. void setup() {
  62. Serial.begin(BAUD_SERIAL);
  63. Serial.setRxBufferSize(RXBUFFERSIZE);
  64. #if SWAP_PINS
  65. Serial.swap();
  66. // Hardware serial is now on RX:GPIO13 TX:GPIO15
  67. // use SoftwareSerial on regular RX(3)/TX(1) for logging
  68. logger = new SoftwareSerial(3, 1);
  69. logger->begin(BAUD_LOGGER);
  70. logger->println("\n\nUsing SoftwareSerial for logging");
  71. #else
  72. logger->begin(BAUD_LOGGER);
  73. logger->println("\n\nUsing Serial1 for logging");
  74. #endif
  75. logger->println(ESP.getFullVersion());
  76. logger->printf("Serial baud: %d (8n1: %d KB/s)\n", BAUD_SERIAL, BAUD_SERIAL * 8 / 10 / 1024);
  77. logger->printf("Serial receive buffer size: %d bytes\n", RXBUFFERSIZE);
  78. #if SERIAL_LOOPBACK
  79. USC0(0) |= (1 << UCLBE); // incomplete HardwareSerial API
  80. logger->println("Serial Internal Loopback enabled");
  81. #endif
  82. WiFi.mode(WIFI_STA);
  83. WiFi.begin(ssid, password);
  84. logger->print("\nConnecting to ");
  85. logger->println(ssid);
  86. while (WiFi.status() != WL_CONNECTED) {
  87. logger->print('.');
  88. delay(500);
  89. }
  90. logger->println();
  91. logger->print("connected, address=");
  92. logger->println(WiFi.localIP());
  93. //start server
  94. server.begin();
  95. server.setNoDelay(true);
  96. logger->print("Ready! Use 'telnet ");
  97. logger->print(WiFi.localIP());
  98. logger->printf(" %d' to connect\n", port);
  99. }
  100. void loop() {
  101. //check if there are any new clients
  102. if (server.hasClient()) {
  103. //find free/disconnected spot
  104. int i;
  105. for (i = 0; i < MAX_SRV_CLIENTS; i++)
  106. if (!serverClients[i]) { // equivalent to !serverClients[i].connected()
  107. serverClients[i] = server.available();
  108. logger->print("New client: index ");
  109. logger->print(i);
  110. break;
  111. }
  112. //no free/disconnected spot so reject
  113. if (i == MAX_SRV_CLIENTS) {
  114. server.available().println("busy");
  115. // hints: server.available() is a WiFiClient with short-term scope
  116. // when out of scope, a WiFiClient will
  117. // - flush() - all data will be sent
  118. // - stop() - automatically too
  119. logger->printf("server is busy with %d active connections\n", MAX_SRV_CLIENTS);
  120. }
  121. }
  122. //check TCP clients for data
  123. #if 1
  124. // Incredibly, this code is faster than the bufferred one below - #4620 is needed
  125. // loopback/3000000baud average 348KB/s
  126. for (int i = 0; i < MAX_SRV_CLIENTS; i++)
  127. while (serverClients[i].available() && Serial.availableForWrite() > 0) {
  128. // working char by char is not very efficient
  129. Serial.write(serverClients[i].read());
  130. }
  131. #else
  132. // loopback/3000000baud average: 312KB/s
  133. for (int i = 0; i < MAX_SRV_CLIENTS; i++)
  134. while (serverClients[i].available() && Serial.availableForWrite() > 0) {
  135. size_t maxToSerial = std::min(serverClients[i].available(), Serial.availableForWrite());
  136. maxToSerial = std::min(maxToSerial, (size_t)STACK_PROTECTOR);
  137. uint8_t buf[maxToSerial];
  138. size_t tcp_got = serverClients[i].read(buf, maxToSerial);
  139. size_t serial_sent = Serial.write(buf, tcp_got);
  140. if (serial_sent != maxToSerial) {
  141. logger->printf("len mismatch: available:%zd tcp-read:%zd serial-write:%zd\n", maxToSerial, tcp_got, serial_sent);
  142. }
  143. }
  144. #endif
  145. // determine maximum output size "fair TCP use"
  146. // client.availableForWrite() returns 0 when !client.connected()
  147. size_t maxToTcp = 0;
  148. for (int i = 0; i < MAX_SRV_CLIENTS; i++)
  149. if (serverClients[i]) {
  150. size_t afw = serverClients[i].availableForWrite();
  151. if (afw) {
  152. if (!maxToTcp) {
  153. maxToTcp = afw;
  154. } else {
  155. maxToTcp = std::min(maxToTcp, afw);
  156. }
  157. } else {
  158. // warn but ignore congested clients
  159. logger->println("one client is congested");
  160. }
  161. }
  162. //check UART for data
  163. size_t len = std::min((size_t)Serial.available(), maxToTcp);
  164. len = std::min(len, (size_t)STACK_PROTECTOR);
  165. if (len) {
  166. uint8_t sbuf[len];
  167. size_t serial_got = Serial.readBytes(sbuf, len);
  168. // push UART data to all connected telnet clients
  169. for (int i = 0; i < MAX_SRV_CLIENTS; i++)
  170. // if client.availableForWrite() was 0 (congested)
  171. // and increased since then,
  172. // ensure write space is sufficient:
  173. if (serverClients[i].availableForWrite() >= serial_got) {
  174. size_t tcp_sent = serverClients[i].write(sbuf, serial_got);
  175. if (tcp_sent != len) {
  176. logger->printf("len mismatch: available:%zd serial-read:%zd tcp-write:%zd\n", len, serial_got, tcp_sent);
  177. }
  178. }
  179. }
  180. }