169 lines
4.5 KiB
C++
169 lines
4.5 KiB
C++
#include <array>
|
|
#include <cstdint>
|
|
#include <stdio.h>
|
|
#include <algorithm>
|
|
|
|
#include "app_networking.hpp"
|
|
#include "app_serial.hpp"
|
|
#include "app_config.hpp"
|
|
#include "app_led.hpp"
|
|
|
|
#include "freertos/FreeRTOS.h"
|
|
#include "freertos/queue.h"
|
|
#include "freertos/timers.h"
|
|
#include "nvs_flash.h"
|
|
#include "driver/uart.h"
|
|
#include "esp_log.h"
|
|
|
|
namespace
|
|
{
|
|
|
|
static const char* LOG_TAG = "App";
|
|
|
|
TaskHandle_t s_main_task = nullptr;
|
|
|
|
TimerHandle_t s_timer = nullptr;
|
|
|
|
QueueSetHandle_t s_queue_set = nullptr;
|
|
QueueHandle_t s_esp_now_queue = nullptr;
|
|
QueueHandle_t s_uart_queue = nullptr;
|
|
|
|
void s_sendUartData(std::size_t len)
|
|
{
|
|
len = std::clamp<std::size_t>(len, 1, CONFIG_ESPTNL_BUFFER_SIZE);
|
|
ESP_LOGD(LOG_TAG, "Sending %u bytes via UART.", len);
|
|
|
|
std::array<std::uint8_t, CONFIG_ESPTNL_BUFFER_SIZE> tx_buffer;
|
|
uart_read_bytes(CONFIG_ESPTNL_UART, tx_buffer.data(), len, 0);
|
|
|
|
xTimerStop(s_timer, 0);
|
|
Led::flashTx();
|
|
|
|
Networking::sendData(tx_buffer, len);
|
|
}
|
|
|
|
std::size_t s_uartBytesWaiting()
|
|
{
|
|
std::size_t len = 0;
|
|
uart_get_buffered_data_len(CONFIG_ESPTNL_UART, &len);
|
|
return std::min<std::size_t>(len, CONFIG_ESPTNL_BUFFER_SIZE);
|
|
}
|
|
|
|
[[noreturn]] void s_mainTask(void*)
|
|
{
|
|
while (true)
|
|
{
|
|
QueueSetMemberHandle_t queue_select = xQueueSelectFromSet(s_queue_set, portMAX_DELAY);
|
|
|
|
ESP_LOGI(LOG_TAG, "Event: %s.", queue_select == s_esp_now_queue ? "ESP-NOW event" : "UART event");
|
|
|
|
if (queue_select == s_esp_now_queue)
|
|
{
|
|
Networking::EspNowEvent event;
|
|
xQueueReceive(s_esp_now_queue, &event, 0);
|
|
|
|
ESP_LOGD(LOG_TAG, "ESP-NOW event: %u, rx-length: %ull.", event.type, event.rx_length);
|
|
|
|
if (event.type == Networking::EspNowEvent::MSG_RECEIVED)
|
|
{
|
|
std::size_t uart_free = 0;
|
|
uart_get_tx_buffer_free_size(CONFIG_ESPTNL_UART, &uart_free);
|
|
|
|
if (uart_free >= event.rx_length)
|
|
{
|
|
ESP_LOGD(LOG_TAG, "ESP-NOW event: wrote %ull bytes to UART RX.", uart_free);
|
|
|
|
Led::flashRx();
|
|
|
|
const auto& esp_rx_buffer = Networking::getRxBuffer();
|
|
uart_write_bytes(CONFIG_ESPTNL_UART, esp_rx_buffer.data(), event.rx_length);
|
|
}
|
|
else
|
|
{
|
|
ESP_LOGW(LOG_TAG, "ESP-NOW event: dropped RX data due to full UART RX buffer.");
|
|
}
|
|
}
|
|
else if (event.type == Networking::EspNowEvent::MSG_SEND_COMPLETE)
|
|
{
|
|
ESP_LOGD(LOG_TAG, "ESP-NOW event: TX completed. Checking to send data.");
|
|
|
|
const std::size_t bytes_waiting = s_uartBytesWaiting();
|
|
if (s_uartBytesWaiting() >= CONFIG_ESPTNL_BUFFER_SIZE)
|
|
{
|
|
s_sendUartData(bytes_waiting);
|
|
}
|
|
}
|
|
}
|
|
else if (queue_select == s_uart_queue)
|
|
{
|
|
uart_event_t event;
|
|
xQueueReceive(s_uart_queue, &event, 0);
|
|
|
|
ESP_LOGD(LOG_TAG, "UART event: %d, size: %u", event.type, event.size);
|
|
|
|
if (event.type == UART_DATA)
|
|
{
|
|
const std::size_t recv_size = s_uartBytesWaiting();
|
|
if (recv_size >= CONFIG_ESPTNL_BUFFER_SIZE)
|
|
s_sendUartData(recv_size);
|
|
else
|
|
xTimerReset(s_timer, 0);
|
|
}
|
|
else if (event.type == UART_BUFFER_FULL)
|
|
{
|
|
const std::size_t recv_size = s_uartBytesWaiting();
|
|
s_sendUartData(recv_size);
|
|
}
|
|
else if (event.type == UART_FIFO_OVF)
|
|
{
|
|
ESP_LOGE(LOG_TAG, "UART FIFO overflow. Flushing.");
|
|
Serial::discardRxBuffer(CONFIG_ESPTNL_UART);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ESP_LOGW(LOG_TAG, "Unknown event type.");
|
|
}
|
|
}
|
|
}
|
|
|
|
void s_cbListenTimeout(TimerHandle_t)
|
|
{
|
|
ESP_LOGD(LOG_TAG, "s_cbListenTimeout invoked from timer.");
|
|
|
|
const std::size_t bytes_waiting = s_uartBytesWaiting();
|
|
if (bytes_waiting > 0)
|
|
s_sendUartData(bytes_waiting);
|
|
}
|
|
|
|
}// namespace
|
|
|
|
extern "C" void app_main(void)
|
|
{
|
|
ESP_ERROR_CHECK(nvs_flash_init());
|
|
|
|
esp_log_level_set("*", esp_log_level_t(CONFIG_LOG_DEFAULT_LEVEL));
|
|
esp_log_level_set(LOG_TAG, Config::appLogLevel());
|
|
esp_log_level_set(Networking::LOG_TAG, Config::appLogLevel());
|
|
|
|
ESP_LOGD(LOG_TAG, "Starting main.");
|
|
|
|
Networking::setupWifi();
|
|
s_esp_now_queue = Networking::setupEspNow();
|
|
s_uart_queue = Serial::setupSerial(CONFIG_ESPTNL_UART);
|
|
|
|
s_timer = xTimerCreate("autosend_timer", pdMS_TO_TICKS(100), false, nullptr, s_cbListenTimeout);
|
|
|
|
s_queue_set = xQueueCreateSet(4 + 4);
|
|
xQueueAddToSet(s_esp_now_queue, s_queue_set);
|
|
xQueueAddToSet(s_uart_queue, s_queue_set);
|
|
|
|
Led::setupLed(GPIO_NUM_8);
|
|
|
|
ESP_LOGI(LOG_TAG, "Setup completed. Sending hello.");
|
|
|
|
Networking::sendHello();
|
|
|
|
xTaskCreate(s_mainTask, "main_task", 2048, nullptr, 4, &s_main_task);
|
|
}
|