websocket.cpp 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. #include "esp_log.h"
  2. #include <esp_http_server.h>
  3. #include "../../include/defines.h"
  4. #include "ClassLogFile.h"
  5. #include "freertos/ringbuf.h"
  6. #include "psram.h"
  7. #include "websocket.h"
  8. #define MAX_MESSAGE_LENGTH 100
  9. static const char *TAG = "WEBSOCKET";
  10. static httpd_handle_t server = NULL;
  11. static httpd_handle_t websocket_handle = NULL;
  12. /*
  13. * Structure holding server handle and message
  14. * in order to use out of request send */
  15. struct async_resp_arg {
  16. httpd_handle_t hd;
  17. char message[MAX_MESSAGE_LENGTH];
  18. };
  19. /*
  20. * async send function, which we put into the httpd work queue
  21. */
  22. static void websocket_send_pending_message(void *arg) {
  23. esp_err_t ret;
  24. struct async_resp_arg *resp_arg = (struct async_resp_arg *)arg;
  25. LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Sending Websocket message: '" + std::string(resp_arg->message) + "'");
  26. httpd_ws_frame_t ws_pkt;
  27. memset(&ws_pkt, 0, sizeof(httpd_ws_frame_t));
  28. ws_pkt.payload = (uint8_t *)resp_arg->message;
  29. ws_pkt.len = strlen(resp_arg->message);
  30. ws_pkt.type = HTTPD_WS_TYPE_TEXT;
  31. static size_t max_clients = CONFIG_LWIP_MAX_LISTENING_TCP;
  32. size_t fds = max_clients;
  33. int client_fds[max_clients];
  34. ret = httpd_get_client_list(server, &fds, client_fds);
  35. if (ret != ESP_OK) {
  36. LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to get Websocket client ist: " + std::to_string(ret) + "!");
  37. free_psram_heap("websocket msg", resp_arg);
  38. return;
  39. }
  40. /* Send it to all websocket clients */
  41. for (int i = 0; i < fds; i++) {
  42. int client_info = httpd_ws_get_fd_info(server, client_fds[i]);
  43. if (client_info == HTTPD_WS_CLIENT_WEBSOCKET) {
  44. httpd_ws_send_frame_async(websocket_handle, client_fds[i], &ws_pkt);
  45. }
  46. }
  47. free_psram_heap("websocket msg", resp_arg);
  48. }
  49. esp_err_t schedule_websocket_message(std::string message) {
  50. // return 0;
  51. esp_err_t ret;
  52. if (websocket_handle == NULL) { // No websocket connecten open
  53. return ESP_OK;
  54. }
  55. LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Scheduled websocket message: '" + message + "'");
  56. struct async_resp_arg *resp_arg = (struct async_resp_arg *)malloc_psram_heap("websocket msg",
  57. sizeof(struct async_resp_arg), MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
  58. if (resp_arg == NULL) {
  59. LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to malloc memory for scheduled websocket message!");
  60. return ESP_ERR_NO_MEM;
  61. }
  62. strncpy(resp_arg->message, message.c_str(), MAX_MESSAGE_LENGTH);
  63. ret = httpd_queue_work(websocket_handle, websocket_send_pending_message, resp_arg);
  64. if (ret != ESP_OK) {
  65. LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Websocket Scheduling failed: " + std::to_string(ret) + "!");
  66. free_psram_heap("websocket msg", resp_arg);
  67. }
  68. return ret;
  69. }
  70. static esp_err_t ws_handler(httpd_req_t *req) {
  71. if (req->method == HTTP_GET) {
  72. LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Handshake done, the new websocket connection was opened");
  73. websocket_handle = req->handle;
  74. }
  75. return ESP_OK;
  76. }
  77. static const httpd_uri_t ws_uri = {
  78. .uri = "/ws",
  79. .method = HTTP_GET,
  80. .handler = ws_handler,
  81. .user_ctx = NULL,
  82. .is_websocket = true
  83. };
  84. esp_err_t start_websocket_server(httpd_handle_t _server) {
  85. esp_err_t ret;
  86. LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Init Websocket Server");
  87. server = _server;
  88. // Registering the ws handler
  89. LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Registering URI handler");
  90. ret = httpd_register_uri_handler(server, &ws_uri);
  91. if (ret != ESP_OK) {
  92. LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Registering Websocket URI handler failed: " + std::to_string(ret));
  93. }
  94. return ret;
  95. }