diff --git a/rx_esp32/CMakeLists.txt b/rx_esp32/CMakeLists.txt index ac19fa6..45ac46b 100644 --- a/rx_esp32/CMakeLists.txt +++ b/rx_esp32/CMakeLists.txt @@ -1,6 +1,12 @@ cmake_minimum_required(VERSION 3.16.0) -set(COMPONENT_DIRS $ENV{IDF_PATH}/components $ENV{IDF_PATH}/../idf-extra-components/led_strip ./lib ./src) +set(COMPONENT_DIRS + $ENV{IDF_PATH}/components + $ENV{IDF_PATH}/../idf-extra-components/led_strip + $ENV{IDF_PATH}/../esp-protocols/components/esp_websocket_client + ./lib + ./src +) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(rx_esp32) diff --git a/rx_esp32/dependencies.lock b/rx_esp32/dependencies.lock index 80bd792..a2c18ec 100644 --- a/rx_esp32/dependencies.lock +++ b/rx_esp32/dependencies.lock @@ -4,6 +4,6 @@ dependencies: source: type: idf version: 5.2.2 -manifest_hash: 25da577a782e8f239c184378e32f45cca356a1cf3257d50b4f7446629da3faa1 +manifest_hash: 0646c148cf0e35f84678cd2cb46e9929051a1c6db31905f3a584cca01fd1e49a target: esp32c6 version: 1.0.0 diff --git a/rx_esp32/sdkconfig b/rx_esp32/sdkconfig index 296e553..0888c30 100644 --- a/rx_esp32/sdkconfig +++ b/rx_esp32/sdkconfig @@ -1835,6 +1835,12 @@ CONFIG_WIFI_PROV_AUTOSTOP_TIMEOUT=30 CONFIG_WIFI_PROV_STA_ALL_CHANNEL_SCAN=y # CONFIG_WIFI_PROV_STA_FAST_SCAN is not set # end of Wi-Fi Provisioning Manager + +# +# ESP WebSocket client +# +# CONFIG_ESP_WS_CLIENT_ENABLE_DYNAMIC_BUFFER is not set +# end of ESP WebSocket client # end of Component config # CONFIG_IDF_EXPERIMENTAL_FEATURES is not set diff --git a/rx_esp32/src/CMakeLists.txt b/rx_esp32/src/CMakeLists.txt index d6973b8..86fb914 100644 --- a/rx_esp32/src/CMakeLists.txt +++ b/rx_esp32/src/CMakeLists.txt @@ -11,6 +11,7 @@ idf_component_register( ./commands.c ./servos.c ./logger.c + ./ws.c INCLUDE_DIRS "./" PRIV_REQUIRES # project components @@ -18,5 +19,6 @@ idf_component_register( # idf extra components led_strip # idf base components + esp_websocket_client spi_flash driver nvs_flash esp_wifi ) diff --git a/rx_esp32/src/config.h b/rx_esp32/src/config.h index a7cd884..53a0e69 100644 --- a/rx_esp32/src/config.h +++ b/rx_esp32/src/config.h @@ -24,4 +24,9 @@ #define SERVOS_CH5 #define SERVOS_CH6 +#define WS_RX_BUFFER_LEN 512 +#define WS_URL "ws://10.0.0.2:80/ws" + +#define LOGGER_BUFFER_SIZE 65536 + #endif diff --git a/rx_esp32/src/logger.c b/rx_esp32/src/logger.c index 2648e15..840a91c 100644 --- a/rx_esp32/src/logger.c +++ b/rx_esp32/src/logger.c @@ -2,6 +2,7 @@ #include #include +#include "config.h" #include "logger.h" #ifndef LOGGER_BUFFER_SIZE diff --git a/rx_esp32/src/main.c b/rx_esp32/src/main.c index f0739e8..b7e7bcc 100644 --- a/rx_esp32/src/main.c +++ b/rx_esp32/src/main.c @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -16,22 +17,37 @@ #include "led.h" #include "servos.h" #include "logger.h" +#include "ws.h" bool volatile running = true; CMDList_t* cmdList; bool rxBuffer_overflow = false; -/* - * CLI char out function. used to print back to a CLI, but the lib - * is only used for reciving command and not having a full cli - */ +typedef enum { + STATE_WIFI_CONNECTING, + STATE_WIFI_WAIT_CONNECTION, + STATE_WS_CONNECTING, + STATE_WS_WAIT_CONNECTION, + STATE_IDEL, + STATE_DRIVING +} MainState_t; +MainState_t MainState = STATE_WIFI_CONNECTING; + +ws_client_t ws_client; + int charOut_uart(const char* c) { printf("%c", *c); return 0; } +int charOut_ws(const char* c) +{ + ws_putchar(ws_client, *c); + return 0; +} + void app_main() { // disable watchdog ESP_ERROR_CHECK(esp_task_wdt_deinit()); @@ -59,58 +75,89 @@ void app_main() { servo_init(); wifiInit(); - wifi_connect(); - - /* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum - * number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */ - EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group, - WIFI_CONNECTED_BIT | WIFI_FAIL_BIT, - pdFALSE, - pdFALSE, - portMAX_DELAY); - - /* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually - * happened. */ - if (bits & WIFI_CONNECTED_BIT) - { - led_setRGB(0, 20, 0); - LOG_I("main: connected to ap SSID '%s'", WIFI_SSID); - } - else if (bits & WIFI_FAIL_BIT) - { - led_setRGB(2, 0, 0); - LOG_E("main: Failed to connect to SSID '%s',", WIFI_SSID); - } - else - { - led_setRGB(2, 0, 0); - LOG_C("main: UNEXPECTED EVENT"); - return; - } - - // // setup UDP server - // int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - // if (sock < 0) - // { - // printf("FAITAL: main: failed to create UDP socket\n"); - // return; - // } running = true; - cmdList = getCMDList(); - // init cli + cmdList = getCMDList(); CLI_t cli_uart = CLI_init((CLI_charOutFn)&charOut_uart, cmdList); - uint8_t ch_uart = 0; - + uint8_t charIn = 0; + EventBits_t bits; + MainState_t lastMainState = MainState; + CLI_t cli_ws_client; + LOG_D("main: main loop starting in state %d", MainState); while (running) { - ch_uart = getchar(); - if (ch_uart != 255) + charIn = getchar(); + if (charIn != 255) { - CLI_charIn(&cli_uart, ch_uart); + CLI_charIn(&cli_uart, charIn); + } + + if (lastMainState != MainState) + { + LOG_D("main: MainState changed from %d to %d", lastMainState, MainState); + lastMainState = MainState; + } + + switch (MainState) + { + case STATE_WIFI_CONNECTING: + wifi_connect(); + MainState = STATE_WIFI_WAIT_CONNECTION; + break; + case STATE_WIFI_WAIT_CONNECTION: + bits = xEventGroupGetBits(s_wifi_event_group); + if ((bits & WIFI_CONNECTED_BIT) != 0) + { + led_setRGB(0, 20, 0); + MainState = STATE_WS_CONNECTING; + LOG_I("main: connected to ap SSID '%s'", WIFI_SSID); + } + else if ((bits & WIFI_FAIL_BIT) != 0) + { + led_setRGB(2, 0, 0); + MainState = STATE_WIFI_CONNECTING; + // wifi_reconnect(); + LOG_E("main: Failed to connect to SSID '%s'", WIFI_SSID); + } + else if (bits != 0) + { + led_setRGB(2, 0, 0); + // MainState = STATE_WIFI_CONNECTING; + LOG_C("main: UNEXPECTED EVENT (bits: 0x%04x)", bits); + } + break; + + + + case STATE_WS_CONNECTING: + ws_client = ws_connect(WS_URL); + cli_ws_client = CLI_init((CLI_charOutFn)&charOut_uart, cmdList); + MainState = STATE_WS_WAIT_CONNECTION; + break; + case STATE_WS_WAIT_CONNECTION: + if (ws_client->connected) + { + MainState = STATE_IDEL; + } + + + + case STATE_IDEL: + case STATE_DRIVING: + if (!ws_client->connected) + { + MainState = STATE_WS_WAIT_CONNECTION; + } + + charIn = ws_getchar(ws_client); + if (charIn != 255) + { + CLI_charIn(&cli_ws_client, charIn); + } + break; } } diff --git a/rx_esp32/src/utils.c b/rx_esp32/src/utils.c index 1f404c6..cf735d9 100644 --- a/rx_esp32/src/utils.c +++ b/rx_esp32/src/utils.c @@ -106,7 +106,7 @@ void printChipInfo() LOG_W("Get flash size failed"); return; } - + LOG_D("%" PRIu32 "MB %s flash", flash_size / (uint32_t)(1024 * 1024), (chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded" : "external" diff --git a/rx_esp32/src/ws.c b/rx_esp32/src/ws.c new file mode 100644 index 0000000..153a2e6 --- /dev/null +++ b/rx_esp32/src/ws.c @@ -0,0 +1,128 @@ +#include "ws.h" + +#include +#include + +#include + +#include "config.h" +#include "logger.h" + +static void ws_event_handler(void* handler_args, esp_event_base_t base, int32_t event_id, void* event_data) +{ + esp_websocket_event_data_t* data = (esp_websocket_event_data_t*)event_data; + ws_client_t client = (ws_client_t)handler_args; + switch (event_id) + { + case WEBSOCKET_EVENT_CONNECTED: + LOG_I("ws_event_handler: connected"); + client->connected = true; + break; + case WEBSOCKET_EVENT_DISCONNECTED: + LOG_W("ws_event_handler: disconnected"); + client->connected = false; + + if (data->error_handle.esp_ws_handshake_status_code != 0) + LOG_E("ws_event_handler: HTTP status code %d", data->error_handle.esp_ws_handshake_status_code); + if (data->error_handle.error_type == WEBSOCKET_ERROR_TYPE_TCP_TRANSPORT) { + if (data->error_handle.esp_tls_last_esp_err != 0) + LOG_E("ws_event_handler: reported from esp-tls", data->error_handle.esp_tls_last_esp_err); + if (data->error_handle.esp_tls_stack_err != 0) + LOG_E("ws_event_handler: reported from tls stack", data->error_handle.esp_tls_stack_err); + if (data->error_handle.esp_transport_sock_errno != 0) + LOG_E("ws_event_handler: captured as transport's socket errno", data->error_handle.esp_transport_sock_errno); + } + + esp_websocket_client_start(client->handle); + break; + + case WEBSOCKET_EVENT_DATA: + LOG_D("ws_event_handler: data recieved (opcode=%02x)", data->op_code); + if (data->op_code == 0x2) + { + LOG_D("ws_event_handler: binary data recieved"); + // ESP_LOG_BUFFER_HEX("Received binary data", data->data_ptr, data->data_len); + } + else if (data->op_code == 0x08 && data->data_len == 2) + { + LOG_W("ws_event_handler: recieved closed message (code: %d)", (((int16_t)(data->data_ptr[0]))<<8) + data->data_ptr[1]); + // ESP_LOGW(TAG, "Received closed message with code=%d", 256 * data->data_ptr[0] + data->data_ptr[1]); + } + else + { + LOG_D("ws_event_handler: data recieved (opcode: %d, size: %d): %.*s", data->op_code, data->data_len, data->data_len, (char*) data->data_ptr); + uint16_t sizeLeft = WS_RX_BUFFER_LEN + client->rxBuffer_rp - client->rxBuffer_wp; + if (sizeLeft > WS_RX_BUFFER_LEN) + { + sizeLeft -= WS_RX_BUFFER_LEN; + } + + if (data->data_len <= sizeLeft) + { + if (WS_RX_BUFFER_LEN - client->rxBuffer_wp <= data->data_len) + { + memcpy(&client->rxBuffer[client->rxBuffer_wp], data->data_ptr, data->data_len); + } + else + { + memcpy(&client->rxBuffer[client->rxBuffer_wp], data->data_ptr, sizeLeft); + memcpy(&client->rxBuffer[0], data->data_ptr + sizeLeft, data->data_len - sizeLeft); + } + client->rxBuffer_wp += data->data_len; + } + else + { + LOG_E("ws_event_handler: no space left in buffer. data ignored (free space: %u)", data->data_len, sizeLeft + client->rxBuffer_rp); + } + } + break; + case WEBSOCKET_EVENT_ERROR: + if (data->error_handle.esp_ws_handshake_status_code != 0) + LOG_E("ws_event_handler: HTTP status code %d", data->error_handle.esp_ws_handshake_status_code); + + if (data->error_handle.error_type == WEBSOCKET_ERROR_TYPE_TCP_TRANSPORT) { + if (data->error_handle.esp_tls_last_esp_err != 0) + LOG_E("ws_event_handler: reported from esp-tls %d", data->error_handle.esp_tls_last_esp_err); + if (data->error_handle.esp_tls_stack_err != 0) + LOG_E("ws_event_handler: reported from tls stack %d", data->error_handle.esp_tls_stack_err); + if (data->error_handle.esp_transport_sock_errno != 0) + LOG_E("ws_event_handler: captured as transport's socket errno %d", data->error_handle.esp_transport_sock_errno); + } + break; + } +} + +ws_client_t ws_connect(char *url) +{ + ws_client_t client = malloc(sizeof(ws_client_data_t)); + client->rxBuffer_rp = 0; + client->rxBuffer_wp = 0; + memset(&(client->rxBuffer[0]), 0, WS_RX_BUFFER_LEN); + + const esp_websocket_client_config_t ws_conf = { + .uri = url + }; + client->handle = esp_websocket_client_init(&ws_conf); + esp_websocket_register_events(client->handle, WEBSOCKET_EVENT_ANY, ws_event_handler, (void *)client); + + esp_websocket_client_start(client->handle); + + return client; +} + +int ws_getchar(ws_client_t client) +{ + int out = 255; + if (client->rxBuffer_rp != client->rxBuffer_wp) + { + out = client->rxBuffer[client->rxBuffer_rp]; + client->rxBuffer_rp++; + if (client->rxBuffer_rp >= WS_RX_BUFFER_LEN) + { + client->rxBuffer_rp = 0; + } + } + return out; +} + +void ws_putchar(ws_client_t client, char c); diff --git a/rx_esp32/src/ws.h b/rx_esp32/src/ws.h new file mode 100644 index 0000000..433bcff --- /dev/null +++ b/rx_esp32/src/ws.h @@ -0,0 +1,23 @@ +#ifndef WS_H +#define WS_H + +#include + +#include + +#include "config.h" + +typedef struct { + esp_websocket_client_handle_t handle; + int connected; + unsigned char rxBuffer[WS_RX_BUFFER_LEN]; + uint16_t rxBuffer_wp; + uint16_t rxBuffer_rp; +} ws_client_data_t; +typedef ws_client_data_t* ws_client_t; + +ws_client_t ws_connect(char *url); +int ws_getchar(ws_client_t client); +void ws_putchar(ws_client_t client, char c); + +#endif