Compare commits

..

2 Commits

Author SHA1 Message Date
Erki
6765df9cf2 Initial working app 2023-06-03 15:21:03 +03:00
Erki
de7c271a95 Editor related setup 2023-06-03 15:20:55 +03:00
16 changed files with 328 additions and 63 deletions

67
.clang-format Normal file
View File

@ -0,0 +1,67 @@
# Generated from CLion C/C++ Code Style settings
BasedOnStyle: LLVM
AccessModifierOffset: -2
AlignAfterOpenBracket: Align
#AlignConsecutiveAssignments: false
AlignOperands: true
AllowAllArgumentsOnNextLine: false
AllowAllConstructorInitializersOnNextLine: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: Always
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Always
AllowShortLambdasOnASingleLine: All
AllowShortLoopsOnASingleLine: true
AlwaysBreakAfterReturnType: None
AlwaysBreakTemplateDeclarations: Yes
BreakBeforeBraces: Custom
BraceWrapping:
AfterCaseLabel: true
AfterClass: true
AfterControlStatement: Always
AfterEnum: true
AfterFunction: true
AfterNamespace: true
AfterUnion: true
AfterStruct: true
BeforeCatch: true
BeforeElse: true
IndentBraces: false
SplitEmptyFunction: false
SplitEmptyRecord: true
BreakBeforeBinaryOperators: None
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeColon
BreakInheritanceList: BeforeComma
ColumnLimit: 0
CompactNamespaces: false
ContinuationIndentWidth: 8
IndentCaseLabels: true
IndentPPDirectives: None
IndentWidth: 2
KeepEmptyLinesAtTheStartOfBlocks: true
MaxEmptyLinesToKeep: 2
NamespaceIndentation: None
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PointerAlignment: Left
ReflowComments: false
SpaceAfterCStyleCast: true
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 0
SpacesInAngles: false
SpacesInCStyleCastParentheses: false
SpacesInContainerLiterals: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
TabWidth: 2
UseTab: Never

2
.gitignore vendored
View File

@ -3,3 +3,5 @@ sdkconfig
sdkconfig.old sdkconfig.old
.vscode/ .vscode/
cmake-build-*/

8
.idea/.gitignore generated vendored Normal file
View File

@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

1
.idea/.name generated Normal file
View File

@ -0,0 +1 @@
esp-tunnel

5
.idea/codeStyles/codeStyleConfig.xml generated Normal file
View File

@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
</state>
</component>

2
.idea/esp-tunnel.git.iml generated Normal file
View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<module classpath="CMake" type="CPP_MODULE" version="4" />

4
.idea/misc.xml generated Normal file
View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
</project>

8
.idea/modules.xml generated Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/esp-tunnel.git.iml" filepath="$PROJECT_DIR$/.idea/esp-tunnel.git.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml generated Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

View File

@ -5,4 +5,4 @@
cmake_minimum_required(VERSION 3.16) cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake) include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(espnow-testies) project(esp-tunnel)

View File

@ -1,3 +1,4 @@
idf_component_register(SRCS "esp_tunnel.cpp" idf_component_register(SRCS "esp_tunnel.cpp"
"app_networking.cpp" "app_networking.cpp"
"app_serial.cpp"
INCLUDE_DIRS ".") INCLUDE_DIRS ".")

View File

@ -1,16 +1,59 @@
#include "app_networking.hpp" #include "app_networking.hpp"
#include <algorithm>
#include <cstring>
#include <variant>
#include "esp_event.h" #include "esp_event.h"
#include "esp_mac.h"
#include "esp_netif.h" #include "esp_netif.h"
#include "esp_wifi.h"
#include "esp_now.h" #include "esp_now.h"
#include "esp_wifi.h"
namespace namespace
{ {
using namespace Networking;
static_assert(std::is_standard_layout_v<EspNowEvent> && std::is_trivial_v<EspNowEvent>,
"EspNowEvent is not compatible with a FreeRTOS queue.");
QueueHandle_t s_esp_now_queue = nullptr;
std::array<std::uint8_t, 128> s_rx_buffer;
std::variant<MacAddress, std::monostate> 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<std::size_t>(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() void setupWifi()
@ -20,17 +63,47 @@ void setupWifi()
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg) ); ESP_ERROR_CHECK(esp_wifi_init(&cfg));
ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM)); 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_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_start()); ESP_ERROR_CHECK(esp_wifi_start());
ESP_ERROR_CHECK(esp_wifi_set_channel(1, WIFI_SECOND_CHAN_NONE)); ESP_ERROR_CHECK(esp_wifi_set_channel(1, WIFI_SECOND_CHAN_NONE));
} }
void setupEspNow() QueueHandle_t setupEspNow()
{ {
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_init());
// ESP_ERROR_CHECK(esp_now_set_pmk(nullptr)); // 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;
} }
bool isTxInFlight()
{
return s_tx_inflight;
} }
const std::array<std::uint8_t, 128>& getRxBuffer()
{
return s_rx_buffer;
}
void sendData(const std::array<std::uint8_t, 128>& buffer, const std::size_t length)
{
if (const MacAddress* peer_mac = std::get_if<MacAddress>(&s_peer);
!s_tx_inflight && peer_mac != nullptr)
{
esp_now_send(peer_mac->data(), buffer.data(), length);
s_tx_inflight = true;
}
}
}// namespace App

View File

@ -1,9 +1,32 @@
#pragma once #pragma once
namespace App #include <cstdint>
#include <array>
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
namespace Networking
{ {
void setupWifi(); struct EspNowEvent
void setupEspNow(); {
enum : std::uint8_t
{
MSG_RECEIVED,
MSG_SEND_COMPLETE
} type;
} std::size_t rx_length;
};
using MacAddress = std::array<std::uint8_t, 6>;
void setupWifi();
[[nodiscard]] QueueHandle_t setupEspNow();
void sendData(const std::array<std::uint8_t, 128>& buffer, const std::size_t length);
bool isTxInFlight();
const std::array<std::uint8_t, 128>& getRxBuffer();
}// namespace App

37
main/app_serial.cpp Normal file
View File

@ -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;
}
}

15
main/app_serial.hpp Normal file
View File

@ -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();
}

View File

@ -1,11 +1,14 @@
#include <cstdint>
#include <stdio.h> #include <stdio.h>
#include <array>
#include "app_networking.hpp" #include "app_networking.hpp"
#include "app_serial.hpp"
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/queue.h" #include "freertos/queue.h"
#include "nvs_flash.h" #include "nvs_flash.h"
#include "esp_now.h" #include "driver/uart.h"
namespace namespace
{ {
@ -16,65 +19,75 @@ QueueSetHandle_t s_queue_set = nullptr;
QueueHandle_t s_esp_now_queue = nullptr; QueueHandle_t s_esp_now_queue = nullptr;
QueueHandle_t s_uart_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<std::uint8_t, 128> 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*)
{ {
}
void s_mainTask(void*)
{
bool radio_tx_busy = false;
bool uart_tx_busy = false;
while (true) while (true)
{ {
const std::uint32_t notification = ulTaskNotifyTake(pdTRUE, portMAX_DELAY); QueueSetMemberHandle_t queue_select = xQueueSelectFromSet(s_queue_set, portMAX_DELAY);
if (notification & (1 << 0)) if (queue_select == s_esp_now_queue)
{ {
// Radio RX complete. Networking::EspNowEvent event;
// Send to uart. xQueueReceive(queue_select, &event, 0);
uart_tx_busy = true;
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)
{
const auto& esp_rx_buffer = Networking::getRxBuffer();
uart_write_bytes(UART_NUM_0, esp_rx_buffer.data(), event.rx_length);
} }
else
if (notification & (1 << 1))
{ {
// UART RX ISR fired. Send to radio. // log data drop
// 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.
} }
else if (event.type == Networking::EspNowEvent::MSG_SEND_COMPLETE && Networking::isTxInFlight())
if (notification & (1 << 3))
{ {
uart_tx_busy = false; // check if we have an UART_RX buffer, send if possible.
// uart TX complete. UART_TX_DONE_INT 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) extern "C" void app_main(void)
{ {
ESP_ERROR_CHECK(nvs_flash_init()); ESP_ERROR_CHECK(nvs_flash_init());
App::setupWifi(); Networking::setupWifi();
App::setupEspNow(); s_esp_now_queue = Networking::setupEspNow();
s_uart_queue = Serial::setupSerial();
ESP_ERROR_CHECK(esp_now_register_send_cb(s_cbMessageSendComplete)); s_queue_set = xQueueCreateSet(4 + 4);
ESP_ERROR_CHECK(esp_now_register_recv_cb(s_cbMessageReceiveComplete)); 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);
} }