#include #include #include #include "esp_log.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/queue.h" #include "websocket_server.h" #include "websocket.h" #include "websocket_if.h" #include "protocol.h" static QueueHandle_t client_queue; const static int client_queue_size = 10; int websocket_if_start(void) { int ws_res = ws_server_start(); if (ws_res == 0) { printf("Websocket error\n"); } xTaskCreate(&server_task,"server_task",8*1024,NULL,6,NULL); xTaskCreate(&server_handle_task,"server_handle_task",8*1024,NULL,9,NULL); return 1; } int websocket_if_stop(void) { return 1; } // Handles websocket events - Pass on to protocol handler using queue void websocket_callback(uint8_t num,WEBSOCKET_TYPE_t type,char* msg,uint64_t len) { const static char* TAG = "websocket_callback"; int value; switch(type) { case WEBSOCKET_CONNECT: ESP_LOGI(TAG,"client %i connected!",num); break; case WEBSOCKET_DISCONNECT_EXTERNAL: ESP_LOGI(TAG,"client %i sent a disconnect message",num); break; case WEBSOCKET_DISCONNECT_INTERNAL: ESP_LOGI(TAG,"client %i was disconnected",num); break; case WEBSOCKET_DISCONNECT_ERROR: ESP_LOGI(TAG,"client %i was disconnected due to an error",num); break; case WEBSOCKET_TEXT: if(len) { // if the message length was greater than zero switch(msg[0]) { case 'L': if(sscanf(msg,"L%i",&value)) { ESP_LOGI(TAG,"LED value: %i",value); ws_server_send_text_all_from_callback(msg,len); // broadcast it! } break; case 'M': ESP_LOGI(TAG, "got message length %i: %s", (int)len-1, &(msg[1])); break; default: ESP_LOGI(TAG, "got an unknown message with length %i", (int)len); break; } } break; case WEBSOCKET_BIN: { //ESP_LOGI(TAG,"client %i sent binary message of size %i:\n",num,(uint32_t)len); uint8_t (*protmsg)[] = malloc(len); memcpy(protmsg,msg,len); xQueueSendToBack(prot_queue,&protmsg,portMAX_DELAY); break; } case WEBSOCKET_PING: ESP_LOGI(TAG,"client %i pinged us with message of size %i:\n%s",num,(uint32_t)len,msg); break; case WEBSOCKET_PONG: ESP_LOGI(TAG,"client %i responded to the ping",num); break; } } // serves any clients void http_serve(struct netconn *conn) { const static char* TAG = "http_server"; struct netbuf* inbuf; static char* buf; static uint16_t buflen; static err_t err; netconn_set_recvtimeout(conn,2000); // allow a connection timeout of 1 second ESP_LOGI(TAG,"reading from client..."); err = netconn_recv(conn, &inbuf); ESP_LOGI(TAG,"read from client"); if(err==ERR_OK) { netbuf_data(inbuf, (void**)&buf, &buflen); if(buf) { if(strstr(buf,"GET / ") && strstr(buf,"Upgrade: websocket")) { ESP_LOGI(TAG,"Requesting websocket on /"); ws_server_add_client(conn,buf,buflen,"/",websocket_callback); netbuf_delete(inbuf); } else { ESP_LOGI(TAG,"Unknown request"); netconn_close(conn); netconn_delete(conn); netbuf_delete(inbuf); } } else { ESP_LOGI(TAG,"Unknown request (empty?...)"); netconn_close(conn); netconn_delete(conn); netbuf_delete(inbuf); } } else { // if err==ERR_OK ESP_LOGI(TAG,"error on read, closing connection"); netconn_close(conn); netconn_delete(conn); netbuf_delete(inbuf); } } // handles clients when they first connect. passes to a queue void server_task(void* pvParameters) { const static char* TAG = "server_task"; struct netconn *conn, *newconn; static err_t err; client_queue = xQueueCreate(client_queue_size,sizeof(struct netconn*)); conn = netconn_new(NETCONN_TCP); netconn_bind(conn,NULL,8088); netconn_listen(conn); ESP_LOGI(TAG,"server listening"); do { err = netconn_accept(conn, &newconn); ESP_LOGI(TAG,"new client"); if(err == ERR_OK) { xQueueSendToBack(client_queue,&newconn,portMAX_DELAY); //http_serve(newconn); } } while(err == ERR_OK); netconn_close(conn); netconn_delete(conn); ESP_LOGE(TAG,"task ending, rebooting board"); esp_restart(); } // receives clients from queue, handles them void server_handle_task(void* pvParameters) { const static char* TAG = "server_handle_task"; struct netconn* conn; ESP_LOGI(TAG,"task starting"); for(;;) { xQueueReceive(client_queue,&conn,portMAX_DELAY); if(!conn) continue; http_serve(conn); } vTaskDelete(NULL); }