From 6765df9cf2395c505e366dc1fb666e2e40088a26 Mon Sep 17 00:00:00 2001 From: Erki Date: Sat, 3 Jun 2023 15:21:03 +0300 Subject: [PATCH] Initial working app --- CMakeLists.txt | 2 +- main/CMakeLists.txt | 1 + main/app_networking.cpp | 105 ++++++++++++++++++++++++++++++++++------ main/app_networking.hpp | 31 ++++++++++-- main/app_serial.cpp | 37 ++++++++++++++ main/app_serial.hpp | 15 ++++++ main/esp_tunnel.cpp | 97 +++++++++++++++++++++---------------- 7 files changed, 225 insertions(+), 63 deletions(-) create mode 100644 main/app_serial.cpp create mode 100644 main/app_serial.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index f085990..ea7fa6d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,4 +5,4 @@ cmake_minimum_required(VERSION 3.16) include($ENV{IDF_PATH}/tools/cmake/project.cmake) -project(espnow-testies) +project(esp-tunnel) diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 4b3427b..3f9ede8 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -1,3 +1,4 @@ idf_component_register(SRCS "esp_tunnel.cpp" "app_networking.cpp" + "app_serial.cpp" INCLUDE_DIRS ".") diff --git a/main/app_networking.cpp b/main/app_networking.cpp index 44a9fd0..50f0cb6 100644 --- a/main/app_networking.cpp +++ b/main/app_networking.cpp @@ -1,36 +1,109 @@ #include "app_networking.hpp" +#include +#include +#include + #include "esp_event.h" +#include "esp_mac.h" #include "esp_netif.h" -#include "esp_wifi.h" #include "esp_now.h" +#include "esp_wifi.h" namespace { +using namespace Networking; + +static_assert(std::is_standard_layout_v && std::is_trivial_v, + "EspNowEvent is not compatible with a FreeRTOS queue."); + +QueueHandle_t s_esp_now_queue = nullptr; +std::array s_rx_buffer; +std::variant s_peer; +bool s_tx_inflight = false; + +bool s_isBroadcastAddress(const std::uint8_t* mac) +{ + constexpr MacAddress broadcast_mac{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + return std::memcmp(mac, broadcast_mac.begin(), ESP_NOW_ETH_ALEN) == 0; } -namespace App +bool s_isBroadcastAddress(const esp_now_recv_info_t* sender) +{ + return s_isBroadcastAddress(sender->src_addr); +} + +void s_cbEspNowSendComplete(const std::uint8_t* peer_mac, esp_now_send_status_t status) +{ + s_tx_inflight = false; + + EspNowEvent event = { EspNowEvent::MSG_SEND_COMPLETE, 0 }; + xQueueSend(s_esp_now_queue, &event, 0); +} + +void s_cbEspNowReceiveComplete(const esp_now_recv_info_t* recv_info, const std::uint8_t* data, int len) +{ + const std::size_t rx_len = std::min(len, s_rx_buffer.size()); + std::copy_n(data, rx_len, s_rx_buffer.begin()); + + EspNowEvent event = { EspNowEvent::MSG_RECEIVED, rx_len }; + xQueueSend(s_esp_now_queue, &event, 0); +} + +} + +namespace Networking { void setupWifi() { - ESP_ERROR_CHECK(esp_netif_init()); - ESP_ERROR_CHECK(esp_event_loop_create_default()); - - wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); - - ESP_ERROR_CHECK(esp_wifi_init(&cfg) ); - ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM)); - ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); - ESP_ERROR_CHECK(esp_wifi_start()); - ESP_ERROR_CHECK(esp_wifi_set_channel(1, WIFI_SECOND_CHAN_NONE)); + ESP_ERROR_CHECK(esp_netif_init()); + ESP_ERROR_CHECK(esp_event_loop_create_default()); + + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + + ESP_ERROR_CHECK(esp_wifi_init(&cfg)); + ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM)); + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); + ESP_ERROR_CHECK(esp_wifi_start()); + ESP_ERROR_CHECK(esp_wifi_set_channel(1, WIFI_SECOND_CHAN_NONE)); } -void setupEspNow() +QueueHandle_t setupEspNow() { - ESP_ERROR_CHECK(esp_now_init()); -// ESP_ERROR_CHECK(esp_now_set_pmk(nullptr)); + s_esp_now_queue = xQueueCreate(4, sizeof(EspNowEvent)); + ESP_ERROR_CHECK(s_esp_now_queue != nullptr); + + ESP_ERROR_CHECK(esp_now_init()); + // ESP_ERROR_CHECK(esp_now_set_pmk(nullptr)); + + ESP_ERROR_CHECK(esp_now_register_send_cb(s_cbEspNowSendComplete)); + ESP_ERROR_CHECK(esp_now_register_recv_cb(s_cbEspNowReceiveComplete)); + + s_peer = MacAddress{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + + return s_esp_now_queue; } -} \ No newline at end of file +bool isTxInFlight() +{ + return s_tx_inflight; +} + +const std::array& getRxBuffer() +{ + return s_rx_buffer; +} + +void sendData(const std::array& buffer, const std::size_t length) +{ + if (const MacAddress* peer_mac = std::get_if(&s_peer); + !s_tx_inflight && peer_mac != nullptr) + { + esp_now_send(peer_mac->data(), buffer.data(), length); + s_tx_inflight = true; + } +} + +}// namespace App \ No newline at end of file diff --git a/main/app_networking.hpp b/main/app_networking.hpp index 4a68b03..44d9051 100644 --- a/main/app_networking.hpp +++ b/main/app_networking.hpp @@ -1,9 +1,32 @@ #pragma once -namespace App +#include +#include + +#include "freertos/FreeRTOS.h" +#include "freertos/queue.h" + +namespace Networking { -void setupWifi(); -void setupEspNow(); +struct EspNowEvent +{ + enum : std::uint8_t + { + MSG_RECEIVED, + MSG_SEND_COMPLETE + } type; -} + std::size_t rx_length; +}; + +using MacAddress = std::array; + +void setupWifi(); +[[nodiscard]] QueueHandle_t setupEspNow(); + +void sendData(const std::array& buffer, const std::size_t length); +bool isTxInFlight(); +const std::array& getRxBuffer(); + +}// namespace App diff --git a/main/app_serial.cpp b/main/app_serial.cpp new file mode 100644 index 0000000..7a5a64e --- /dev/null +++ b/main/app_serial.cpp @@ -0,0 +1,37 @@ +// +// Created by erki on 6/3/23. +// + +#include "app_serial.hpp" + +#include "driver/uart.h" + +namespace +{ + +QueueHandle_t s_uart_queue = nullptr; + +} + +namespace Serial +{ + +QueueHandle_t setupSerial() +{ + uart_config_t config = { + .baud_rate = 115200, + .data_bits = UART_DATA_8_BITS, + .parity = UART_PARITY_DISABLE, + .stop_bits = UART_STOP_BITS_1, + .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, + .source_clk = UART_SCLK_DEFAULT, + }; + + ESP_ERROR_CHECK(uart_driver_install(UART_NUM_0, 128, 128 * 2, 4, &s_uart_queue, 0)); + ESP_ERROR_CHECK(uart_param_config(UART_NUM_0, &config)); + ESP_ERROR_CHECK(uart_set_pin(UART_NUM_0, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE)); + + return s_uart_queue; +} + +} diff --git a/main/app_serial.hpp b/main/app_serial.hpp new file mode 100644 index 0000000..29fed6b --- /dev/null +++ b/main/app_serial.hpp @@ -0,0 +1,15 @@ +// +// Created by erki on 6/3/23. +// + +#pragma once + +#include "freertos/FreeRTOS.h" +#include "freertos/queue.h" + +namespace Serial +{ + +[[nodiscard]] QueueHandle_t setupSerial(); + +} diff --git a/main/esp_tunnel.cpp b/main/esp_tunnel.cpp index 31d6015..3095c4f 100644 --- a/main/esp_tunnel.cpp +++ b/main/esp_tunnel.cpp @@ -1,11 +1,14 @@ +#include #include +#include #include "app_networking.hpp" +#include "app_serial.hpp" #include "freertos/FreeRTOS.h" #include "freertos/queue.h" #include "nvs_flash.h" -#include "esp_now.h" +#include "driver/uart.h" namespace { @@ -16,65 +19,75 @@ QueueSetHandle_t s_queue_set = nullptr; QueueHandle_t s_esp_now_queue = nullptr; QueueHandle_t s_uart_queue = nullptr; -void s_cbEspNowSendComplete(const std::uint8_t* peer_mac, esp_now_send_status_t status) +void s_sendUartData() { - + std::size_t uart_rx_size = 0; + uart_get_buffered_data_len(UART_NUM_0, &uart_rx_size); + if (uart_rx_size > 128 / 2) + { + std::array tx_buffer; + uart_read_bytes(UART_NUM_0, tx_buffer.data(), uart_rx_size, 0); + Networking::sendData(tx_buffer, uart_rx_size); + } } -void s_cbEspNowReceiveComplete(const esp_now_recv_info_t* recv_info, const std::uint8_t* data, int len) +[[noreturn]] void s_mainTask(void*) { + while (true) + { + QueueSetMemberHandle_t queue_select = xQueueSelectFromSet(s_queue_set, portMAX_DELAY); -} - -void s_mainTask(void*) -{ - bool radio_tx_busy = false; - bool uart_tx_busy = false; - - while (true) + if (queue_select == s_esp_now_queue) { - const std::uint32_t notification = ulTaskNotifyTake(pdTRUE, portMAX_DELAY); + Networking::EspNowEvent event; + xQueueReceive(queue_select, &event, 0); - if (notification & (1 << 0)) + if (event.type == Networking::EspNowEvent::MSG_RECEIVED) + { + std::size_t uart_free = 0; + uart_get_tx_buffer_free_size(UART_NUM_0, &uart_free); + if (uart_free >= event.rx_length) { - // Radio RX complete. - // Send to uart. - uart_tx_busy = true; + const auto& esp_rx_buffer = Networking::getRxBuffer(); + uart_write_bytes(UART_NUM_0, esp_rx_buffer.data(), event.rx_length); } - - if (notification & (1 << 1)) + else { - // UART RX ISR fired. Send to radio. - // UART RX FIFO is 128 bytes for C3. UART_RXFIFO_FULL_INT, set by UART_RXFIFO_THRHD. - - radio_tx_busy = true; - } - - if (notification & (1 << 2)) - { - radio_tx_busy = false; - // radio TX complete. - } - - if (notification & (1 << 3)) - { - uart_tx_busy = false; - // uart TX complete. UART_TX_DONE_INT + // log data drop } + } + else if (event.type == Networking::EspNowEvent::MSG_SEND_COMPLETE && Networking::isTxInFlight()) + { + // check if we have an UART_RX buffer, send if possible. + s_sendUartData(); + } } + else if (queue_select == s_uart_queue) + { + uart_event_t event; + xQueueReceive(s_uart_queue, &event, 0); + + if (event.type == UART_DATA) + { + s_sendUartData(); + } + } + } } -} +}// namespace extern "C" void app_main(void) { - ESP_ERROR_CHECK(nvs_flash_init()); + ESP_ERROR_CHECK(nvs_flash_init()); - App::setupWifi(); - App::setupEspNow(); + Networking::setupWifi(); + s_esp_now_queue = Networking::setupEspNow(); + s_uart_queue = Serial::setupSerial(); - ESP_ERROR_CHECK(esp_now_register_send_cb(s_cbMessageSendComplete)); - ESP_ERROR_CHECK(esp_now_register_recv_cb(s_cbMessageReceiveComplete)); + s_queue_set = xQueueCreateSet(4 + 4); + xQueueAddToSet(s_esp_now_queue, s_queue_set); + xQueueAddToSet(s_uart_queue, s_queue_set); - xTaskCreate(s_mainTask, "main_task", 2048, nullptr, 4, &s_main_task); + xTaskCreate(s_mainTask, "main_task", 2048, nullptr, 4, &s_main_task); }