1
0

WebSerial.h 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. /*
  2. __ __ _ ____ _ _
  3. \ \ / /__| |__/ ___| ___ _ __(_) __ _| |
  4. \ \ /\ / / _ \ '_ \___ \ / _ \ '__| |/ _` | |
  5. \ V V / __/ |_) |__) | __/ | | | (_| | |
  6. \_/\_/ \___|_.__/____/ \___|_| |_|\__,_|_|
  7. A remote terminal for wireless microcontrollers!
  8. Checkout Pro version at: https://webserial.pro
  9. -----
  10. Author: Ayush Sharma (ayush@softt.io)
  11. License: AGPL-3.0 (https://www.gnu.org/licenses/agpl-3.0.html)
  12. */
  13. #ifndef WebSerial_h
  14. #define WebSerial_h
  15. #include "Arduino.h"
  16. #include "stdlib_noniso.h"
  17. #include <functional>
  18. #if defined(ESP8266)
  19. #define HARDWARE "ESP8266"
  20. #include "ESP8266WiFi.h"
  21. #include "ESPAsyncTCP.h"
  22. #include "ESPAsyncWebServer.h"
  23. #elif defined(ESP32)
  24. #define HARDWARE "ESP32"
  25. #include "WiFi.h"
  26. #include "AsyncTCP.h"
  27. #include "ESPAsyncWebServer.h"
  28. #endif
  29. #ifndef WSL_MAX_WS_CLIENTS
  30. #define WSL_MAX_WS_CLIENTS DEFAULT_MAX_WS_CLIENTS
  31. #endif
  32. // High performance mode:
  33. // - Low memory footprint (no stack allocation, no global buffer by default)
  34. // - Low latency (messages sent immediately to the WebSocket queue)
  35. // - High throughput (up to 20 messages per second, no locking mechanism)
  36. // Activation with: -D WSL_HIGH_PERFORMANCE
  37. // Also recommended to tweak AsyncTCP and ESPAsyncWebServer settings, for example:
  38. // -D CONFIG_ASYNC_TCP_QUEUE_SIZE=128 // AsyncTCP queue size
  39. // -D CONFIG_ASYNC_TCP_RUNNING_CORE=1 // core for the async_task
  40. // -D WS_MAX_QUEUED_MESSAGES=128 // WS message queue size
  41. #ifndef WSL_HIGH_PERF
  42. // Global buffer ( buffers all packets )
  43. #ifndef WSL_BUFFER_SIZE
  44. #define WSL_BUFFER_SIZE 2048
  45. #endif
  46. #ifndef WSL_PRINT_BUFFER_SIZE
  47. #define WSL_PRINT_BUFFER_SIZE 1024
  48. #endif
  49. #ifndef WSL_MAX_ROW_PACKET_PAYLOAD_SIZE
  50. #define WSL_MAX_ROW_PACKET_PAYLOAD_SIZE 512
  51. #endif
  52. #ifndef WSL_PRINT_FLUSH_TIME_US
  53. #define WSL_PRINT_FLUSH_TIME_US 100
  54. #endif
  55. #ifndef WSL_GLOBAL_FLUSH_TIME_MS
  56. #define WSL_GLOBAL_FLUSH_TIME_MS 100
  57. #endif
  58. #ifndef WSL_CLEANUP_TIME_MS
  59. #define WSL_CLEANUP_TIME_MS 5000
  60. #endif
  61. #if WSL_BUFFER_SIZE < 512
  62. #error "WSL_BUFFER_SIZE must be >= 512 bytes"
  63. #endif
  64. #if WSL_BUFFER_SIZE < WSL_PRINT_BUFFER_SIZE
  65. #error "WSL_BUFFER_SIZE must be >= WSL_PRINT_BUFFER_SIZE"
  66. #endif
  67. #if WSL_PRINT_FLUSH_TIME_US < 1
  68. #error "WSL_PRINT_FLUSH_TIME_US must be greater than 1us"
  69. #endif
  70. #if WSL_GLOBAL_FLUSH_TIME_MS < 50
  71. #error "WSL_GLOBAL_FLUSH_TIME_MS must be greater than 50ms"
  72. #endif
  73. #endif // WSL_HIGH_PERFORMANCE
  74. typedef std::function<void(uint8_t *data, size_t len)> WSLMessageHandler;
  75. typedef std::function<void(const String& msg)> WSLStringMessageHandler;
  76. class WebSerialClass : public Print {
  77. public:
  78. void begin(AsyncWebServer *server, const char* url = "/webserial");
  79. inline void setAuthentication(const char* username, const char* password) { setAuthentication(String(username), String(password)); }
  80. void setAuthentication(const String& username, const String& password);
  81. void onMessage(WSLMessageHandler recv);
  82. void onMessage(WSLStringMessageHandler recv);
  83. size_t write(uint8_t) override;
  84. size_t write(const uint8_t* buffer, size_t size) override;
  85. // Only valid if WSL_HIGH_PERF is not activated (which is the default)
  86. // Housekeeping for WebSerial internals.
  87. // Calling this loop has no effect if WSL_HIGH_PERF is activated
  88. void loop();
  89. // Only valid if WSL_HIGH_PERF is activated
  90. // A buffer (shared across cores) can be initialised with an initial capacity to be able to use any Print functions event those that are not buffered and would
  91. // create a performance impact for WS calls. The goal of this buffer is to be used with lines ending with '\n', like log messages.
  92. // The buffer size will eventually grow until a '\n' is found, then the message will be sent to the WS clients and a new buffer will be created.
  93. // Set initialCapacity to 0 to disable buffering.
  94. // Must be called before begin(): calling it after will erase the buffer and its content will be lost.
  95. // The buffer is not enabled by default.
  96. void setBuffer(size_t initialCapacity);
  97. #ifdef WSL_HIGH_PERF
  98. #ifdef ASYNCWEBSERVER_FORK_mathieucarbou
  99. // Expose the internal WebSocket makeBuffer to even improve memory consumption on client-side
  100. // 1. make a AsyncWebSocketMessageBuffer
  101. // 2. put the data inside
  102. // 3. send the buffer
  103. // This method avoids a buffer copy when creating the WebSocket message
  104. AsyncWebSocketMessageBuffer* makeBuffer(size_t size = 0) {
  105. if (!_ws)
  106. return nullptr;
  107. return _ws->makeBuffer(size);
  108. }
  109. void send(AsyncWebSocketMessageBuffer* buffer) {
  110. if (!_ws || !buffer)
  111. return;
  112. _ws->cleanupClients(WSL_MAX_WS_CLIENTS);
  113. if (_ws->count())
  114. _ws->textAll(buffer);
  115. }
  116. #endif
  117. #endif
  118. private:
  119. // Server
  120. AsyncWebServer *_server;
  121. AsyncWebSocket *_ws;
  122. WSLMessageHandler _recv = nullptr;
  123. WSLStringMessageHandler _recvString = nullptr;
  124. bool _authenticate = false;
  125. String _username;
  126. String _password;
  127. #ifdef WSL_HIGH_PERF
  128. size_t _initialBufferCapacity = 0;
  129. String _buffer;
  130. void _send(const uint8_t* buffer, size_t size);
  131. #else
  132. unsigned long _last_cleanup_time = 0;
  133. // Global Buffer
  134. size_t _buffer_offset = 0;
  135. uint8_t _buffer[WSL_BUFFER_SIZE];
  136. // Print buffer
  137. size_t _print_buffer_offset = 0;
  138. uint8_t _print_buffer[WSL_PRINT_BUFFER_SIZE];
  139. unsigned long _last_print_buffer_write_time = 0;
  140. unsigned long _last_print_buffer_flush_time = 0;
  141. // Print
  142. bool _has_enough_space(size_t size);
  143. size_t _start_row();
  144. size_t _write_row(uint8_t *data, size_t len);
  145. size_t _end_row();
  146. void _flush_print_buffer();
  147. void _flush_global_buffer();
  148. #endif
  149. static size_t _write_row_packet(uint8_t* dest, const uint8_t *payload, size_t payload_size);
  150. };
  151. extern WebSerialClass WebSerial;
  152. #endif