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.

189 lines
5.9 KiB

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