Compare commits

...

29 Commits

Author SHA1 Message Date
e011188377 Merge pull request #566 from david-cermak/feat/eppp_force_lwip_opts
[eppp]: Force the `PPP` LWIP opts which are OFF by default
2024-05-07 19:48:18 +02:00
1fb1ea9300 bump(eppp): 0.0.1 -> 0.1.0
0.1.0
Features
- Added CI job to build examples and tests (7eefcf0)
Bug Fixes
- Fixed to select PPP LWIP opts which are OFF by default (16be2f9)
- Example to use iperf component from the registry (bd6b66d)
- Fixed defalt config designated init issue in C++ (8bd4712)
2024-05-07 10:32:55 +02:00
16be2f963b fix(eppp): Fixed to select PPP LWIP opts which are OFF by default 2024-05-07 10:30:43 +02:00
d786f0db88 Merge pull request #555 from gabsuren/websocket_keep_alirve
feat(websocket): adding support for `keep_alive_enable` when using WSS transport (IDFGH-11457)
2024-05-03 14:49:42 +04:00
f6f6ded001 Merge pull request #560 from david-cermak/fix/ci_build_v5.3
Fix CI build per IDFv5.3
2024-05-03 12:44:25 +02:00
5df46437f2 fix(console): Ignore eth_init hidden config warning 2024-04-26 11:57:06 +02:00
bd6b66d9d1 fix(eppp): Example to use iperf component from the registry 2024-04-26 11:32:46 +02:00
d0c17ef0d5 fix(modem): Fix CI build per IDFv5.3 2024-04-26 11:25:30 +02:00
06d013b20b Merge pull request #557 from euripedesrocha/fix_lastwill
Adds missing configuration fields
2024-04-26 02:50:23 -03:00
f032a9f023 Merge pull request #538 from david-cermak/feat/wifi_remote_example
[wifi remote]: Add example without `esp_hosted`
2024-04-25 16:03:15 +02:00
d16387859f bump(wifi_remote): 0.1.12 -> 0.2.0
0.2.0
Features
- Add support for simple eppp based RPC (fd168d8)
Bug Fixes
- Make services restartable, code cleanup (6c82ce2)
- Add examples to CI (d2b7c55)
2024-04-25 15:13:49 +02:00
6c82ce2915 fix(wifi_remote): Make services restartable, code cleanup 2024-04-25 15:11:17 +02:00
d2b7c55b89 fix(wifi_remote): Add examples to CI 2024-04-25 15:11:17 +02:00
fd168d86fc feat(wifi_remote): Add support for simple eppp based RPC 2024-04-25 15:11:09 +02:00
d4c6d5ed5d fix(mqtt_cxx): Adds missing configuration fields
Some aspects of the underlying mqtt client were not set.

Fix #554
2024-04-22 12:30:20 +02:00
c728eae5ea feat(websocket): adding support for keep_alive_enable when using WSS transport 2024-04-22 10:57:36 +04:00
bd6e120509 Merge pull request #509 from david-cermak/feat/mbedtls_cxx_component
fix(tls_cxx): Publish mbedtls-cxx component
2024-04-11 18:32:08 +02:00
13793a8236 bump(tls_cxx): First version [0.1.0]
0.1.0
Features
- Publish mbedtls component (0140455f)
2024-04-11 16:52:51 +02:00
0140455ff7 feat(tls_cxx): Publish mbedtls component
Adds examples and tests.
Also supports DTLS now.
2024-04-11 16:49:54 +02:00
c4d9cc6beb Merge pull request #540 from david-cermak/fix/modem_uart_missed_event
fix(modem): Fixed UART task to check for buffered data periodically
2024-04-11 14:44:51 +02:00
887dbcd73b Merge pull request #549 from gabsuren/mdns_1.3.0
bump(mdns): 1.2.5 -> 1.3.0
2024-04-10 14:36:36 +04:00
b3ba71ff4d bump(mdns): 1.2.5 -> 1.3.0
1.3.0
Features
- add a new mdns query mode `browse` (af330b6)
- Make including mdns_console KConfigurable (27adbfe)
Bug Fixes
- Schedule all queued Tx packets from timer task (d4e693e)
- add lock for some common apis (21c84bf)
- fix mdns answer append while host is invalid (7be16bc)
2024-04-10 11:24:25 +04:00
fbdb2483f5 Merge pull request #522 from zwx1995esp/feature/mdns_add_browse_suport
mdns add browse support (IDFGH-12512)
2024-04-10 09:48:55 +04:00
zwx
af330b6396 feat(mdns): add a new mdns query mode browse 2024-04-10 11:23:24 +08:00
0b94d9ec47 Merge pull request #543 from david-cermak/feat/wifi_remote_publish
fix(wifi_remote): Publish missing esp_wifi_remote and add to README
2024-04-04 10:46:45 +02:00
f26f2f88c2 Merge pull request #537 from david-cermak/fix/eppp_cxx_init
fix(eppp): Fixed default config designated init issue in C++
2024-04-02 14:50:41 +02:00
08d06a4b7d fix(wifi_remote): Publish missing esp_wifi_remote and add to README 2024-04-02 14:42:31 +02:00
4bdd90cc88 fix(modem): Fixed UART task to check for buffered data periodically
Closes https://github.com/espressif/esp-protocols/issues/536
2024-03-26 14:44:59 +01:00
8bd4712677 fix(eppp): Fixed defalt config designated init issue in C++ 2024-03-25 12:48:41 +01:00
109 changed files with 3366 additions and 178 deletions

View File

@ -13,9 +13,13 @@ jobs:
name: Build
strategy:
matrix:
idf_ver: ["latest", "release-v5.0"]
idf_ver: ["latest", "release-v5.1", "release-v5.0"]
idf_target: ["esp32"]
test: [ { app: ifconfig-basic, path: "components/console_cmd_ifconfig/examples"}]
include:
- idf_ver: "latest"
warning: "the choice symbol ETHERNET_PHY_LAN867X"
runs-on: ubuntu-22.04
container: espressif/idf:${{ matrix.idf_ver }}
steps:
@ -24,6 +28,8 @@ jobs:
with:
submodules: recursive
- name: Build ${{ matrix.test.app }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
env:
EXPECTED_WARNING: ${{ matrix.warning }}
shell: bash
working-directory: ${{matrix.test.path}}
run: |

View File

@ -98,5 +98,7 @@ jobs:
components/console_cmd_ping;
components/console_cmd_ifconfig;
components/console_cmd_wifi;
components/esp_wifi_remote;
components/mbedtls_cxx;
namespace: "espressif"
api_token: ${{ secrets.IDF_COMPONENT_API_TOKEN }}

30
.github/workflows/tls_cxx__build.yml vendored Normal file
View File

@ -0,0 +1,30 @@
name: "mbedtls-cxx: build-tests"
on:
push:
branches:
- master
pull_request:
types: [opened, synchronize, reopened, labeled]
jobs:
build_tls_cxx:
if: contains(github.event.pull_request.labels.*.name, 'tls_cxx') || github.event_name == 'push'
name: Build
strategy:
matrix:
idf_ver: ["latest", "release-v5.2", "release-v5.1"]
test: [ { app: client, path: "examples/tls_client" }, { app: udp, path: "examples/udp_mutual_auth" }, { app: test, path: "tests/uart_mutual_auth" } ]
runs-on: ubuntu-20.04
container: espressif/idf:${{ matrix.idf_ver }}
steps:
- name: Checkout esp-protocols
uses: actions/checkout@v3
with:
submodules: recursive
- name: Build ${{ matrix.test.app }} with IDF-${{ matrix.idf_ver }}
shell: bash
run: |
${IDF_PATH}/install.sh --enable-pytest
. ${IDF_PATH}/export.sh
python ./ci/build_apps.py ./components/mbedtls_cxx/${{ matrix.test.path }} -vv --preserve-all

View File

@ -29,7 +29,7 @@ jobs:
build_wifi_remote:
if: contains(github.event.pull_request.labels.*.name, 'wifi_remote') || github.event_name == 'push'
name: Build WiFi Remote
name: Build WiFi Remote Test
strategy:
matrix:
idf_ver: ["latest"]
@ -49,3 +49,29 @@ jobs:
${IDF_PATH}/install.sh --enable-pytest
. ${IDF_PATH}/export.sh
python ./ci/build_apps.py ./components/esp_wifi_remote/${{matrix.test.path}} -vv --preserve-all
build_wifi_remote_example:
if: contains(github.event.pull_request.labels.*.name, 'wifi_remote') || github.event_name == 'push'
name: Build WiFi Remote Example
strategy:
matrix:
idf_ver: ["latest"]
example: [ { app: host, path: "examples/mqtt" }, { app: slave, path: "examples/server" }]
include:
- idf_ver: "latest"
example: { app: slave, path: "examples/server" }
warning: "Warning: The smallest app partition is nearly full"
runs-on: ubuntu-20.04
container: espressif/idf:${{ matrix.idf_ver }}
steps:
- name: Checkout esp-protocols
uses: actions/checkout@v3
- name: Build ${{ matrix.example.app }} with IDF-${{ matrix.idf_ver }}
env:
EXPECTED_WARNING: ${{ matrix.warning }}
shell: bash
run: |
${IDF_PATH}/install.sh --enable-pytest
. ${IDF_PATH}/export.sh
python ./ci/build_apps.py ./components/esp_wifi_remote/${{matrix.example.path}} -vv --preserve-all

View File

@ -61,8 +61,8 @@ repos:
- repo: local
hooks:
- id: commit message scopes
name: "commit message must be scoped with: mdns, modem, websocket, asio, mqtt_cxx, console, common, eppp, wifi_remote"
entry: '\A(?!(feat|fix|ci|bump|test|docs)\((mdns|modem|common|console|websocket|asio|mqtt_cxx|examples|eppp|wifi_remote)\)\:)'
name: "commit message must be scoped with: mdns, modem, websocket, asio, mqtt_cxx, console, common, eppp, wifi_remote, tls_cxx"
entry: '\A(?!(feat|fix|ci|bump|test|docs)\((mdns|modem|common|console|websocket|asio|mqtt_cxx|examples|eppp|wifi_remote|tls_cxx)\)\:)'
language: pygrep
args: [--multiline]
stages: [commit-msg]

View File

@ -53,3 +53,11 @@ Please refer to instructions in [ESP-IDF](https://github.com/espressif/esp-idf)
### ESP PPP Link (eppp)
* Brief introduction [README](components/eppp_link/README.md)
### esp_wifi_remote
* Brief introduction [README](components/esp_wifi_remote/README.md)
### mbedtls_cxx
* Brief introduction [README](components/mbedtls_cxx/README.md)

View File

@ -3,6 +3,6 @@ commitizen:
bump_message: 'bump(eppp): $current_version -> $new_version'
pre_bump_hooks: python ../../ci/changelog.py eppp_link
tag_format: eppp-v$version
version: 0.0.1
version: 0.1.0
version_files:
- idf_component.yml

View File

@ -1,5 +1,17 @@
# Changelog
## [0.1.0](https://github.com/espressif/esp-protocols/commits/eppp-v0.1.0)
### Features
- Added CI job to build examples and tests ([7eefcf0](https://github.com/espressif/esp-protocols/commit/7eefcf0))
### Bug Fixes
- Fixed to select PPP LWIP opts which are OFF by default ([16be2f9](https://github.com/espressif/esp-protocols/commit/16be2f9))
- Example to use iperf component from the registry ([bd6b66d](https://github.com/espressif/esp-protocols/commit/bd6b66d))
- Fixed defalt config designated init issue in C++ ([8bd4712](https://github.com/espressif/esp-protocols/commit/8bd4712))
## [0.0.1](https://github.com/espressif/esp-protocols/commits/eppp-v0.0.1)
### Features

View File

@ -1,5 +1,11 @@
menu "eppp_link"
config EPPP_LINK_USES_LWIP
bool
default "y"
select LWIP_PPP_SUPPORT
select LWIP_PPP_SERVER_SUPPORT
choice EPPP_LINK_DEVICE
prompt "Choose PPP device"
default EPPP_LINK_DEVICE_UART

View File

@ -1,7 +1,6 @@
# The following four lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/iperf)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)

View File

@ -1,4 +1,5 @@
dependencies:
espressif/iperf-cmd: "^0.1.1"
espressif/eppp_link:
version: "*"
override_path: "../../.."

View File

@ -1,4 +1,4 @@
version: 0.0.1
version: 0.1.0
url: https://github.com/espressif/esp-protocols/tree/master/components/eppp_link
description: The component provides a general purpose PPP connectivity, typically used as WiFi-PPP router
dependencies:

View File

@ -35,8 +35,8 @@
.priority = 8, \
}, \
. ppp = { \
.our_ip4_addr.addr = our_ip, \
.their_ip4_addr.addr = their_ip, \
.our_ip4_addr = { .addr = our_ip }, \
.their_ip4_addr = { .addr = their_ip }, \
} \
}

View File

@ -1,6 +1,6 @@
components/esp_modem/examples/ap_to_pppos:
disable:
- if: IDF_TARGET in ["esp32h2"]
- if: IDF_TARGET in ["esp32h2", "esp32p4"]
components/esp_modem/examples/modem_console:
disable:

View File

@ -1,4 +1,4 @@
idf_component_register(SRCS mbedtls_wrap.cpp
tls_transport.cpp
idf_component_register(SRCS tls_transport.cpp
INCLUDE_DIRS include
REQUIRES tcp_transport)
REQUIRES tcp_transport
PRIV_REQUIRES mbedtls_cxx)

View File

@ -11,6 +11,8 @@
static const char *TAG = "tls_transport";
using namespace idf::mbedtls_cxx;
class TlsTransport: public Tls {
public:
explicit TlsTransport(esp_transport_handle_t parent) : Tls(), transport_(parent) {}

View File

@ -2,3 +2,6 @@ dependencies:
espressif/esp_modem:
version: "^1.0.1"
override_path: "../../../"
espressif/mbedtls_cxx:
version: "*"
override_path: "../../../../mbedtls_cxx"

View File

@ -160,6 +160,11 @@ void UartTerminal::task()
ESP_LOGW(TAG, "unknown uart event type: %d", event.type);
break;
}
} else {
uart_get_buffered_data_len(uart.port, &len);
if (len && on_read) {
on_read(nullptr, len);
}
}
}
}

View File

@ -2,9 +2,5 @@
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/system/console/advanced/components
$ENV{IDF_PATH}/examples/common_components/iperf
"../..")
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(pppd_test)

View File

@ -0,0 +1,6 @@
## IDF Component Manager Manifest File
dependencies:
espressif/esp_modem:
version: "^1.1.0"
override_path: "../../.."
espressif/iperf-cmd: "^0.1.1"

View File

@ -8,7 +8,6 @@
#include "sdkconfig.h"
#include "esp_log.h"
#include "esp_console.h"
#include "cmd_system.h"
void register_pppd(void);
@ -22,7 +21,6 @@ void app_main(void)
ESP_ERROR_CHECK(esp_console_new_repl_uart(&uart_config, &repl_config, &repl));
/* Register commands */
register_system_common();
register_pppd();
printf("\n =======================================================\n");

View File

@ -2,7 +2,7 @@
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.8)
set(EXTRA_COMPONENT_DIRS "../.." "../../examples/modem_tcp_client/components")
set(EXTRA_COMPONENT_DIRS "../.." "../../../mbedtls_cxx")
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(ota_test)

View File

@ -1,3 +1,3 @@
idf_component_register(SRCS manual_ota.cpp transport_batch_tls.cpp
INCLUDE_DIRS "."
PRIV_REQUIRES extra_tcp_transports esp_http_client app_update)
PRIV_REQUIRES mbedtls_cxx esp_http_client app_update)

View File

@ -10,6 +10,8 @@
#define TAG "batch-tls"
using namespace idf::mbedtls_cxx;
class TlsTransport: public Tls {
public:
explicit TlsTransport(esp_transport_handle_t parent):

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -7,12 +7,12 @@
#include <string>
#include <algorithm>
#include <stdexcept>
#include <variant>
#include "mqtt_client.h"
#include "esp_log.h"
#include "esp_mqtt.hpp"
#include "esp_mqtt_client_config.hpp"
namespace {
@ -133,6 +133,22 @@ esp_mqtt_client_config_t make_config(BrokerConfiguration const &broker, ClientCr
esp_mqtt_client_config_t mqtt_client_cfg{};
config_broker(mqtt_client_cfg, broker);
config_client_credentials(mqtt_client_cfg, credentials);
mqtt_client_cfg.session.keepalive = config.session.keepalive;
mqtt_client_cfg.session.last_will.msg = config.session.last_will.lwt_msg;
mqtt_client_cfg.session.last_will.topic = config.session.last_will.lwt_topic;
mqtt_client_cfg.session.last_will.msg_len = config.session.last_will.lwt_msg_len;
mqtt_client_cfg.session.last_will.qos = config.session.last_will.lwt_qos;
mqtt_client_cfg.session.last_will.retain = config.session.last_will.lwt_retain;
mqtt_client_cfg.session.protocol_ver = config.session.protocol_ver;
mqtt_client_cfg.session.disable_keepalive = config.session.disable_keepalive;
mqtt_client_cfg.network.reconnect_timeout_ms = config.connection.reconnect_timeout_ms;
mqtt_client_cfg.network.timeout_ms = config.connection.network_timeout_ms;
mqtt_client_cfg.network.disable_auto_reconnect = config.connection.disable_auto_reconnect;
mqtt_client_cfg.network.refresh_connection_after_ms = config.connection.refresh_connection_after_ms;
mqtt_client_cfg.task.priority = config.task.task_prio;
mqtt_client_cfg.task.stack_size = config.task.task_stack;
mqtt_client_cfg.buffer.size = config.buffer_size;
mqtt_client_cfg.buffer.out_size = config.out_buffer_size;
return mqtt_client_cfg;
}
}
@ -150,7 +166,6 @@ Client::Client(esp_mqtt_client_config_t const &config) : handler(esp_mqtt_clien
CHECK_THROW_SPECIFIC(esp_mqtt_client_start(handler.get()), mqtt::MQTTException);
}
void Client::mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) noexcept
{
ESP_LOGD(TAG, "Event dispatched from event loop base=%s, event_id=%" PRIu32, base, event_id);

View File

@ -497,6 +497,9 @@ static esp_err_t esp_websocket_client_create_transport(esp_websocket_client_hand
esp_transport_set_default_port(ssl, WEBSOCKET_SSL_DEFAULT_PORT);
esp_transport_list_add(client->transport_list, ssl, "_ssl"); // need to save to transport list, for cleanup
if (client->keep_alive_cfg.keep_alive_enable) {
esp_transport_ssl_set_keep_alive(ssl, &client->keep_alive_cfg);
}
if (client->config->use_global_ca_store == true) {
esp_transport_ssl_enable_global_ca_store(ssl);
} else if (client->config->cert) {

View File

@ -3,6 +3,6 @@ commitizen:
bump_message: 'bump(wifi_remote): $current_version -> $new_version'
pre_bump_hooks: python ../../ci/changelog.py esp_wifi_remote
tag_format: wifi_remote-v$version
version: 0.1.12
version: 0.2.0
version_files:
- idf_component.yml

View File

@ -1,5 +1,16 @@
# Changelog
## [0.2.0](https://github.com/espressif/esp-protocols/commits/wifi_remote-v0.2.0)
### Features
- Add support for simple eppp based RPC ([fd168d8](https://github.com/espressif/esp-protocols/commit/fd168d8))
### Bug Fixes
- Make services restartable, code cleanup ([6c82ce2](https://github.com/espressif/esp-protocols/commit/6c82ce2))
- Add examples to CI ([d2b7c55](https://github.com/espressif/esp-protocols/commit/d2b7c55))
## [0.1.12](https://github.com/espressif/esp-protocols/commits/wifi_remote-v0.1.12)
### Features

View File

@ -1,15 +1,20 @@
if(NOT CONFIG_ESP_WIFI_ENABLED)
set(src_wifi_is_remote esp_wifi_remote.c esp_wifi_with_remote.c)
set(src_wifi_is_remote esp_wifi_remote.c esp_wifi_with_remote.c esp_wifi_remote_net.c)
endif()
if(CONFIG_ESP_WIFI_REMOTE_LIBRARY_EPPP)
set(src_wifi_remote_eppp eppp/wifi_remote_rpc_client.cpp eppp/wifi_remote_rpc_server.cpp eppp/eppp_init.c)
else()
set(src_wifi_remote_weak esp_wifi_remote_weak.c)
endif()
idf_component_register(INCLUDE_DIRS include
SRCS ${src_wifi_is_remote}
esp_wifi_remote_net.c
esp_wifi_remote_weak.c
SRCS ${src_wifi_remote_weak}
${src_wifi_remote_eppp}
${src_wifi_is_remote}
PRIV_INCLUDE_DIRS eppp
REQUIRES esp_event esp_netif
PRIV_REQUIRES esp_wifi)
idf_component_optional_requires(PRIVATE esp_hosted)
PRIV_REQUIRES esp_wifi esp-tls)
idf_component_get_property(wifi esp_wifi COMPONENT_LIB)
target_link_libraries(${wifi} PUBLIC ${COMPONENT_LIB})

View File

@ -5,6 +5,7 @@ menu "Wi-Fi Remote"
default y
orsource "./Kconfig.soc_wifi_caps.in"
orsource "./Kconfig.rpc.in"
config ESP_WIFI_STATIC_RX_BUFFER_NUM
int "Max number of WiFi static RX buffers"
@ -191,7 +192,7 @@ menu "Wi-Fi Remote"
Set the size of WiFi Block Ack RX window. Generally a bigger value means higher throughput and better
compatibility but more memory. Most of time we should NOT change the default value unless special
reason, e.g. test the maximum UDP RX throughput with iperf etc. For iperf test in shieldbox, the
recommended value is 9~12. If PSRAM is used and WiFi memory is prefered to allocat in PSRAM first,
recommended value is 9~12. If PSRAM is used and WiFi memory is preferred to allocate in PSRAM first,
the default and minimum value should be 16 to achieve better throughput and compatibility with both
stations and APs.
@ -228,14 +229,14 @@ menu "Wi-Fi Remote"
help
ESP-MESH utilizes beacon frames to detect and resolve root node conflicts (see documentation). However
the default length of a beacon frame can simultaneously hold only five root node identifier structures,
meaning that a root node conflict of up to five nodes can be detected at one time. In the occurence of
meaning that a root node conflict of up to five nodes can be detected at one time. In the occurrence of
more root nodes conflict involving more than five root nodes, the conflict resolution process will
detect five of the root nodes, resolve the conflict, and re-detect more root nodes. This process will
repeat until all root node conflicts are resolved. However this process can generally take a very long
time.
To counter this situation, the beacon frame length can be increased such that more root nodes can be
detected simultaneously. Each additional root node will require 36 bytes and should be added ontop of
detected simultaneously. Each additional root node will require 36 bytes and should be added on top of
the default beacon frame length of
752 bytes. For example, if you want to detect 10 root nodes simultaneously, you need to set the beacon
frame length as
@ -487,9 +488,9 @@ menu "Wi-Fi Remote"
help
Select this option to use MbedTLS TLS client for WPA2 enterprise connection.
Please note that from MbedTLS-3.0 onwards, MbedTLS does not support SSL-3.0
TLS-v1.0, TLS-v1.1 versions. Incase your server is using one of these version,
TLS-v1.0, TLS-v1.1 versions. In case your server is using one of these version,
it is advisable to update your server.
Please disable this option for compatibilty with older TLS versions.
Please disable this option for compatibility with older TLS versions.
config ESP_WIFI_EAP_TLS1_3
bool "Enable EAP-TLS v1.3 Support for WiFi Enterprise connection"
@ -556,6 +557,26 @@ menu "Wi-Fi Remote"
help
Select this option to enable WiFi Multiband operation certification support.
config ESP_WIFI_ENABLE_ROAMING_APP
bool "Advanced support for Wi-Fi Roaming (Experimental)"
depends on IDF_EXPERIMENTAL_FEATURES
default n
select ESP_WIFI_SCAN_CACHE
help
Enable Espressif's roaming app to allow for efficient Wi-Fi roaming.
This includes configurable periodic environment scans, maintaining a cache of the
best APs, handling low rssi events etc.
Risk Warning
Please note that this feature is still experimental and enabling this potentially can
lead to unpredictable scanning, connection and roaming attempts.
We are still working on tuning and optimising this feature to ensure reliable and stable use.
menu "Configure roaming App"
depends on ESP_WIFI_ENABLE_ROAMING_APP
rsource "wifi_apps/roaming_app/src/Kconfig.roaming"
endmenu
config ESP_WIFI_DPP_SUPPORT
bool "Enable DPP support"
default n
@ -597,7 +618,7 @@ menu "Wi-Fi Remote"
default n
help
Select this option to enable validate each WPS attribute
rigorously. Disabling this add the workaorunds with various APs.
rigorously. Disabling this add the workarounds with various APs.
Enabling this may cause inter operability issues with some APs.
config ESP_WIFI_WPS_PASSPHRASE
@ -605,9 +626,9 @@ menu "Wi-Fi Remote"
default n
help
Select this option to get passphrase during WPS configuration.
This option fakes the virtual display capabilites to get the
This option fakes the virtual display capabilities to get the
configuration in passphrase mode.
Not recommanded to be used since WPS credentials should not
Not recommended to be used since WPS credentials should not
be shared to other devices, making it in readable format increases
that risk, also passphrase requires pbkdf2 to convert in psk.

View File

@ -0,0 +1,57 @@
choice ESP_WIFI_REMOTE_LIBRARY
prompt "Choose WiFi-remote implementation"
default ESP_WIFI_REMOTE_LIBRARY_EPPP
help
Select type of WiFi Remote implementation
ESP-HOSTED is the default and most versatile option.
It's also possible to use EPPP, which uses PPPoS link between micros and NAPT, so it's slower
and less universal.
config ESP_WIFI_REMOTE_LIBRARY_HOSTED
bool "ESP-HOSTED"
config ESP_WIFI_REMOTE_LIBRARY_EPPP
bool "EPPP"
endchoice
if ESP_WIFI_REMOTE_LIBRARY_EPPP
config ESP_WIFI_REMOTE_EPPP_UART_TX_PIN
int "TXD Pin Number"
default 10
range 0 31
help
Pin number of UART TX.
config ESP_WIFI_REMOTE_EPPP_UART_RX_PIN
int "RXD Pin Number"
default 11
range 0 31
help
Pin number of UART RX.
config ESP_WIFI_REMOTE_EPPP_SERVER_CA
string "Servers CA certificate"
default "--- Please copy content of the CA certificate ---"
config ESP_WIFI_REMOTE_EPPP_CLIENT_CRT
string "Client certificate"
default "--- Please copy content of the Client certificate ---"
config ESP_WIFI_REMOTE_EPPP_CLIENT_KEY
string "Client key"
default "--- Please copy content of the Client key ---"
config ESP_WIFI_REMOTE_EPPP_CLIENT_CA
string "Clients CA certificate"
default "--- Please copy content of the CA certificate ---"
config ESP_WIFI_REMOTE_EPPP_SERVER_CRT
string "Server certificate"
default "--- Please copy content of the Client certificate ---"
config ESP_WIFI_REMOTE_EPPP_SERVER_KEY
string "Server key"
default "--- Please copy content of the Client key ---"
endif

View File

@ -227,3 +227,11 @@ endif # ESP32C6
if SLAVE_IDF_TARGET_ESP32H2
endif # ESP32H2
if SLAVE_IDF_TARGET_ESP32P4
config SLAVE_SOC_WIFI_LIGHT_SLEEP_CLK_WIDTH
int
default 12
endif # ESP32P4

View File

@ -0,0 +1,20 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_log.h"
#include "esp_wifi.h"
#include "eppp_link.h"
__attribute__((weak)) esp_netif_t *wifi_remote_eppp_init(eppp_type_t role)
{
uint32_t our_ip = role == EPPP_SERVER ? EPPP_DEFAULT_SERVER_IP() : EPPP_DEFAULT_CLIENT_IP();
uint32_t their_ip = role == EPPP_SERVER ? EPPP_DEFAULT_CLIENT_IP() : EPPP_DEFAULT_SERVER_IP();
eppp_config_t config = EPPP_DEFAULT_CONFIG(our_ip, their_ip);
// We currently support only UART transport
config.transport = EPPP_TRANSPORT_UART;
config.uart.tx_io = CONFIG_ESP_WIFI_REMOTE_EPPP_UART_TX_PIN;
config.uart.rx_io = CONFIG_ESP_WIFI_REMOTE_EPPP_UART_RX_PIN;
return eppp_open(role, &config, portMAX_DELAY);
}

View File

@ -0,0 +1,297 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <netdb.h>
#include <memory>
#include <cinttypes>
#include "esp_log.h"
#include "esp_tls.h"
#include "esp_wifi.h"
#include "esp_check.h"
#include "wifi_remote_rpc_impl.hpp"
#include "eppp_link.h"
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "wifi_remote_rpc_params.h"
extern "C" esp_netif_t *wifi_remote_eppp_init(eppp_type_t role);
namespace eppp_rpc {
namespace client {
const char *TAG = "rpc_client";
const unsigned char ca_crt[] = "-----BEGIN CERTIFICATE-----\n" CONFIG_ESP_WIFI_REMOTE_EPPP_SERVER_CA "\n-----END CERTIFICATE-----";
const unsigned char crt[] = "-----BEGIN CERTIFICATE-----\n" CONFIG_ESP_WIFI_REMOTE_EPPP_CLIENT_CRT "\n-----END CERTIFICATE-----";
const unsigned char key[] = "-----BEGIN RSA PRIVATE KEY-----\n" CONFIG_ESP_WIFI_REMOTE_EPPP_CLIENT_KEY "\n-----END RSA PRIVATE KEY-----";
// TODO: Add option to supply keys and certs via a global symbol (file)
}
using namespace client;
class Sync {
friend class RpcInstance;
public:
void lock()
{
xSemaphoreTake(mutex, portMAX_DELAY);
}
void unlock()
{
xSemaphoreGive(mutex);
}
esp_err_t init()
{
mutex = xSemaphoreCreateMutex();
events = xEventGroupCreate();
return mutex == nullptr || events == nullptr ? ESP_ERR_NO_MEM : ESP_OK;
}
esp_err_t wait_for(EventBits_t bits, uint32_t timeout = portMAX_DELAY)
{
return (xEventGroupWaitBits(events, bits, pdTRUE, pdTRUE, timeout) & bits) == bits ? ESP_OK : ESP_FAIL;
}
esp_err_t notify(EventBits_t bits)
{
xEventGroupSetBits(events, bits);
return ESP_OK;
}
~Sync()
{
if (mutex) {
vSemaphoreDelete(mutex);
}
if (events) {
vEventGroupDelete(events);
}
}
private:
SemaphoreHandle_t mutex{nullptr};
EventGroupHandle_t events{nullptr};
const int request = 1;
const int resp_header = 2;
const int resp_payload = 4;
const int restart = 8;
};
class RpcInstance {
friend class Sync;
public:
template<typename T>
esp_err_t send(api_id id, T *t)
{
pending_resp = id;
ESP_RETURN_ON_ERROR(sync.notify(sync.request), TAG, "failed to notify req");
ESP_RETURN_ON_ERROR(rpc.send<T>(id, t), TAG, "Failed to send request");
return ESP_OK;
}
// overload of the templated method (used for functions with no arguments)
esp_err_t send(api_id id)
{
pending_resp = id;
ESP_RETURN_ON_ERROR(sync.notify(sync.request), TAG, "failed to notify req");
ESP_RETURN_ON_ERROR(rpc.send(id), TAG, "Failed to send request");
return ESP_OK;
}
template<typename T>
T get_resp(api_id id)
{
sync.wait_for(sync.resp_header);
auto ret = rpc.template get_payload<T>(id, pending_header);
sync.notify(sync.resp_payload);
return ret;
}
esp_err_t init()
{
ESP_RETURN_ON_FALSE(netif = wifi_remote_eppp_init(EPPP_CLIENT), ESP_FAIL, TAG, "Failed to connect to EPPP server");
ESP_RETURN_ON_ERROR(esp_event_handler_register(IP_EVENT, IP_EVENT_PPP_GOT_IP, got_ip, this), TAG, "Failed to register event");
ESP_RETURN_ON_ERROR(sync.init(), TAG, "Failed to init sync primitives");
ESP_RETURN_ON_ERROR(rpc.init(), TAG, "Failed to init RPC engine");
return xTaskCreate(task, "client", 8192, this, 5, nullptr) == pdTRUE ? ESP_OK : ESP_FAIL;
}
RpcEngine rpc{eppp_rpc::role::CLIENT};
Sync sync;
private:
api_id pending_resp{api_id::UNDEF};
RpcHeader pending_header{};
esp_err_t process_ip_event(RpcHeader &header)
{
auto event = rpc.get_payload<esp_wifi_remote_eppp_ip_event>(api_id::IP_EVENT, header);
// Now bypass network layers with EPPP interface
ESP_RETURN_ON_ERROR(esp_netif_set_dns_info(netif, ESP_NETIF_DNS_MAIN, &event.dns), TAG, "Failed to set DNS info");
ESP_RETURN_ON_ERROR(esp_netif_set_default_netif(netif), TAG, "Failed to set default netif to EPPP");
ip_event_got_ip_t evt = {
.esp_netif = netif,
.ip_info = {},
.ip_changed = true,
};
esp_netif_get_ip_info(netif, &evt.ip_info);
ESP_RETURN_ON_ERROR(esp_event_post(IP_EVENT, IP_EVENT_STA_GOT_IP, &evt, sizeof(evt), 0), TAG, "Failed to post IP event");
ESP_LOGI(TAG, "Main DNS:" IPSTR, IP2STR(&event.dns.ip.u_addr.ip4));
ESP_LOGI(TAG, "EPPP IP:" IPSTR, IP2STR(&event.ppp_ip.ip));
ESP_LOGI(TAG, "WIFI IP:" IPSTR, IP2STR(&event.wifi_ip.ip));
ESP_LOGI(TAG, "WIFI GW:" IPSTR, IP2STR(&event.wifi_ip.gw));
ESP_LOGI(TAG, "WIFI mask:" IPSTR, IP2STR(&event.wifi_ip.netmask));
return ESP_OK;
}
esp_err_t process_wifi_event(RpcHeader &header)
{
auto event_id = rpc.get_payload<int32_t>(api_id::WIFI_EVENT, header);
ESP_RETURN_ON_ERROR(esp_event_post(WIFI_EVENT, event_id, nullptr, 0, 0), TAG, "Failed to post WiFi event");
return ESP_OK;
}
esp_err_t perform()
{
auto header = rpc.get_header();
if (api_id(header.id) == api_id::ERROR) { // network error
return ESP_FAIL;
}
if (api_id(header.id) == api_id::UNDEF) { // network timeout
return ESP_OK;
}
if (api_id(header.id) == api_id::IP_EVENT) {
return process_ip_event(header);
}
if (api_id(header.id) == api_id::WIFI_EVENT) {
return process_wifi_event(header);
}
if (sync.wait_for(sync.request, 0) == ESP_OK && api_id(header.id) == pending_resp) {
pending_header = header;
pending_resp = api_id::UNDEF;
sync.notify(sync.resp_header);
sync.wait_for(sync.resp_payload);
return ESP_OK;
}
ESP_LOGE(TAG, "Unexpected header %" PRIi32, static_cast<uint32_t>(header.id));
return ESP_FAIL;
}
static void task(void *ctx)
{
auto instance = static_cast<RpcInstance *>(ctx);
do {
while (instance->perform() == ESP_OK) {}
} while (instance->restart() == ESP_OK);
vTaskDelete(nullptr);
}
esp_err_t restart()
{
rpc.deinit();
ESP_RETURN_ON_ERROR(sync.wait_for(sync.restart, pdMS_TO_TICKS(10000)), TAG, "Didn't receive EPPP address in time");
return rpc.init();
}
static void got_ip(void *ctx, esp_event_base_t base, int32_t id, void *data)
{
auto instance = static_cast<RpcInstance *>(ctx);
instance->sync.notify(instance->sync.restart);
}
esp_netif_t *netif{nullptr};
};
namespace client {
constinit RpcInstance instance;
} // namespace client
RpcInstance *RpcEngine::init_client()
{
char host[4 * 4 + 1] = {}; // IPv4: 4 x (3 numbers + '.') + \0
esp_ip4_addr_t ip = { .addr = EPPP_DEFAULT_SERVER_IP() };
if (esp_ip4addr_ntoa(&ip, host, sizeof(host)) == nullptr) {
return nullptr;
}
esp_tls_cfg_t cfg = {};
cfg.cacert_buf = client::ca_crt;
cfg.cacert_bytes = sizeof(client::ca_crt);
cfg.clientcert_buf = client::crt;
cfg.clientcert_bytes = sizeof(client::crt);
cfg.clientkey_buf = client::key;
cfg.clientkey_bytes = sizeof(client::key);
cfg.common_name = "espressif.local";
ESP_RETURN_ON_FALSE(tls_ = esp_tls_init(), nullptr, TAG, "Failed to create ESP-TLS instance");
int retries = 0;
while (esp_tls_conn_new_sync(host, strlen(host), rpc_port, &cfg, tls_) <= 0) {
esp_tls_conn_destroy(tls_);
tls_ = nullptr;
ESP_RETURN_ON_FALSE(retries++ < 3, nullptr, TAG, "Failed to open connection to %s", host);
ESP_LOGW(TAG, "Connection to RPC server failed! Will retry in %d second(s)", retries);
vTaskDelay(pdMS_TO_TICKS(1000 * retries));
ESP_RETURN_ON_FALSE(tls_ = esp_tls_init(), nullptr, TAG, "Failed to create ESP-TLS instance");
}
return &client::instance;
}
} // namespace eppp_rpc
//
// esp_wifi_remote API implementation
//
using namespace eppp_rpc;
using namespace client;
extern "C" esp_err_t esp_wifi_remote_init(const wifi_init_config_t *config)
{
// Here we initialize this client's RPC
ESP_RETURN_ON_ERROR(instance.init(), TAG, "Failed to initialize eppp-rpc");
std::lock_guard<Sync> lock(instance.sync);
ESP_RETURN_ON_ERROR(instance.send(api_id::INIT, config), TAG, "Failed to send request");
return instance.get_resp<esp_err_t>(api_id::INIT);
}
extern "C" esp_err_t esp_wifi_remote_set_config(wifi_interface_t interface, wifi_config_t *conf)
{
esp_wifi_remote_config params = { .interface = interface, .conf = {} };
memcpy(&params.conf, conf, sizeof(wifi_config_t));
std::lock_guard<Sync> lock(instance.sync);
ESP_RETURN_ON_ERROR(instance.send(api_id::SET_CONFIG, &params), TAG, "Failed to send request");
return instance.get_resp<esp_err_t>(api_id::SET_CONFIG);
}
extern "C" esp_err_t esp_wifi_remote_start(void)
{
std::lock_guard<Sync> lock(instance.sync);
ESP_RETURN_ON_ERROR(instance.send(api_id::START), TAG, "Failed to send request");
return instance.get_resp<esp_err_t>(api_id::START);
}
extern "C" esp_err_t esp_wifi_remote_stop(void)
{
std::lock_guard<Sync> lock(instance.sync);
ESP_RETURN_ON_ERROR(instance.send(api_id::STOP), TAG, "Failed to send request");
return instance.get_resp<esp_err_t>(api_id::STOP);
}
extern "C" esp_err_t esp_wifi_remote_connect(void)
{
std::lock_guard<Sync> lock(instance.sync);
ESP_RETURN_ON_ERROR(instance.send(api_id::CONNECT), TAG, "Failed to send request");
return instance.get_resp<esp_err_t>(api_id::CONNECT);
}
extern "C" esp_err_t esp_wifi_remote_get_mac(wifi_interface_t ifx, uint8_t mac[6])
{
std::lock_guard<Sync> lock(instance.sync);
ESP_RETURN_ON_ERROR(instance.send(api_id::GET_MAC, &ifx), TAG, "Failed to send request");
auto ret = instance.get_resp<esp_wifi_remote_mac_t>(api_id::GET_MAC);
ESP_LOG_BUFFER_HEXDUMP("MAC", ret.mac, 6, ESP_LOG_DEBUG);
memcpy(mac, ret.mac, 6);
return ret.err;
}
extern "C" esp_err_t esp_wifi_remote_set_mode(wifi_mode_t mode)
{
std::lock_guard<Sync> lock(instance.sync);
ESP_RETURN_ON_ERROR(instance.send(api_id::SET_MODE, &mode), TAG, "Failed to send request");
return instance.get_resp<esp_err_t>(api_id::SET_MODE);
}

View File

@ -0,0 +1,167 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <cstring>
#include <cerrno>
namespace eppp_rpc {
static constexpr int rpc_port = 3333;
/**
* @brief Currently supported RPC commands/events
*/
enum class api_id : uint32_t {
ERROR,
UNDEF,
INIT,
SET_MODE,
SET_CONFIG,
START,
STOP,
CONNECT,
GET_MAC,
WIFI_EVENT,
IP_EVENT,
};
enum class role {
SERVER,
CLIENT,
};
struct RpcHeader {
api_id id;
uint32_t size;
} __attribute((__packed__));
/**
* @brief Structure holding the outgoing or incoming parameter
*/
template<typename T>
struct RpcData {
RpcHeader head;
T value_{};
explicit RpcData(api_id id) : head{id, sizeof(T)} {}
uint8_t *value()
{
return (uint8_t *) &value_;
}
uint8_t *marshall(T *t, size_t &size)
{
size = head.size + sizeof(RpcHeader);
memcpy(value(), t, sizeof(T));
return (uint8_t *) this;
}
} __attribute((__packed__));
/**
* @brief Singleton holding the static data for either the client or server side
*/
class RpcInstance;
/**
* @brief Engine that implements a simple RPC mechanism
*/
class RpcEngine {
public:
constexpr explicit RpcEngine(role r) : tls_(nullptr), role_(r) {}
esp_err_t init()
{
if (tls_ != nullptr) {
return ESP_OK;
}
if (role_ == role::CLIENT) {
instance = init_client();
}
if (role_ == role::SERVER) {
instance = init_server();
}
return instance == nullptr ? ESP_FAIL : ESP_OK;
}
void deinit()
{
if (tls_ == nullptr) {
return;
}
if (role_ == role::CLIENT) {
esp_tls_conn_destroy(tls_);
} else if (role_ == role::SERVER) {
esp_tls_server_session_delete(tls_);
}
tls_ = nullptr;
}
template<typename T>
esp_err_t send(api_id id, T *t)
{
RpcData<T> req(id);
size_t size;
auto buf = req.marshall(t, size);
ESP_LOGD("rpc", "Sending API id:%d", (int) id);
ESP_LOG_BUFFER_HEXDUMP("rpc", buf, size, ESP_LOG_VERBOSE);
int len = esp_tls_conn_write(tls_, buf, size);
if (len <= 0) {
ESP_LOGE("rpc", "Failed to write data to the connection");
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t send(api_id id) // overload for (void)
{
RpcHeader head = {.id = id, .size = 0};
int len = esp_tls_conn_write(tls_, &head, sizeof(head));
if (len <= 0) {
ESP_LOGE("rpc", "Failed to write data to the connection");
return ESP_FAIL;
}
return ESP_OK;
}
RpcHeader get_header()
{
RpcHeader header{};
int len = esp_tls_conn_read(tls_, (char *) &header, sizeof(header));
if (len <= 0) {
if (len < 0 && errno != EAGAIN) {
ESP_LOGE("rpc", "Failed to read header data from the connection %d %s", errno, strerror(errno));
return {.id = api_id::ERROR, .size = 0};
}
return {.id = api_id::UNDEF, .size = 0};
}
return header;
}
template<typename T>
T get_payload(api_id id, RpcHeader &head)
{
RpcData<T> resp(id);
if (head.id != id || head.size != resp.head.size) {
ESP_LOGE("rpc", "unexpected header %d %d or sizes %" PRIu32 " %" PRIu32, (int)head.id, (int)id, head.size, resp.head.size);
return {};
}
int len = esp_tls_conn_read(tls_, (char *) resp.value(), resp.head.size);
if (len <= 0) {
ESP_LOGE("rpc", "Failed to read data from the connection");
return {};
}
return resp.value_;
}
private:
RpcInstance *init_server();
RpcInstance *init_client();
esp_tls_t *tls_;
role role_;
RpcInstance *instance{nullptr};
};
};

View File

@ -0,0 +1,23 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
struct esp_wifi_remote_config {
wifi_interface_t interface;
wifi_config_t conf;
};
struct esp_wifi_remote_mac_t {
esp_err_t err;
uint8_t mac[6];
};
struct esp_wifi_remote_eppp_ip_event {
uint32_t id;
esp_netif_ip_info_t wifi_ip;
esp_netif_ip_info_t ppp_ip;
esp_netif_dns_info_t dns;
};

View File

@ -0,0 +1,210 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <netdb.h>
#include <memory>
#include <cerrno>
#include <sys/socket.h>
#include "esp_log.h"
#include "esp_check.h"
#include "esp_tls.h"
#include "esp_wifi.h"
#include "wifi_remote_rpc_impl.hpp"
#include "eppp_link.h"
#include "wifi_remote_rpc_params.h"
#include "lwip/apps/snmp.h"
extern "C" esp_netif_t *wifi_remote_eppp_init(eppp_type_t role);
namespace eppp_rpc {
namespace server {
const char *TAG = "rpc_server";
const unsigned char ca_crt[] = "-----BEGIN CERTIFICATE-----\n" CONFIG_ESP_WIFI_REMOTE_EPPP_CLIENT_CA "\n-----END CERTIFICATE-----";
const unsigned char crt[] = "-----BEGIN CERTIFICATE-----\n" CONFIG_ESP_WIFI_REMOTE_EPPP_SERVER_CRT "\n-----END CERTIFICATE-----";
const unsigned char key[] = "-----BEGIN RSA PRIVATE KEY-----\n" CONFIG_ESP_WIFI_REMOTE_EPPP_SERVER_KEY "\n-----END RSA PRIVATE KEY-----";
// TODO: Add option to supply keys and certs via a global symbol (file)
}
using namespace server;
class RpcInstance {
public:
RpcEngine rpc{role::SERVER};
int sock{-1};
esp_err_t init()
{
ESP_RETURN_ON_FALSE(netif = wifi_remote_eppp_init(EPPP_SERVER), ESP_FAIL, TAG, "Failed to init EPPP connection");
ESP_RETURN_ON_ERROR(start_server(), TAG, "Failed to start RPC server");
ESP_RETURN_ON_ERROR(rpc.init(), TAG, "Failed to init RPC engine");
ESP_RETURN_ON_ERROR(esp_netif_napt_enable(netif), TAG, "Failed to enable NAPT");
ESP_RETURN_ON_ERROR(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, handler, this), TAG, "Failed to register event");
ESP_RETURN_ON_ERROR(esp_event_handler_register(IP_EVENT, ESP_EVENT_ANY_ID, handler, this), TAG, "Failed to register event");
return xTaskCreate(task, "server", 8192, this, 5, nullptr) == pdTRUE ? ESP_OK : ESP_FAIL;
}
private:
esp_netif_t *netif{nullptr};
static void task(void *ctx)
{
auto instance = static_cast<RpcInstance *>(ctx);
while (instance->perform() == ESP_OK) {}
esp_restart();
}
esp_err_t start_server()
{
struct sockaddr_in dest_addr = {};
int ret;
int opt = 1;
dest_addr.sin_addr.s_addr = htonl(INADDR_ANY);
dest_addr.sin_family = AF_INET;
dest_addr.sin_port = htons(rpc_port);
int listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
ESP_RETURN_ON_FALSE(listen_sock >= 0, ESP_FAIL, TAG, "Failed to create listening socket");
setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
ret = bind(listen_sock, (struct sockaddr *) &dest_addr, sizeof(dest_addr));
ESP_RETURN_ON_FALSE(ret == 0, ESP_FAIL, TAG, "Failed to bind the listening socket");
ret = listen(listen_sock, 1);
ESP_RETURN_ON_FALSE(ret == 0, ESP_FAIL, TAG, "Failed to start listening");
struct sockaddr_storage source_addr {};
socklen_t addr_len = sizeof(source_addr);
sock = accept(listen_sock, (struct sockaddr *) &source_addr, &addr_len);
ESP_RETURN_ON_FALSE(sock >= 0, ESP_FAIL, TAG, "Failed to accept connections: errno %d", errno);
ESP_LOGI(TAG, "Socket accepted on: %s", inet_ntoa(((struct sockaddr_in *) &source_addr)->sin_addr));
return ESP_OK;
}
esp_err_t wifi_event(int32_t id)
{
ESP_LOGI(TAG, "Received WIFI event %" PRIi32, id);
ESP_RETURN_ON_ERROR(rpc.send(api_id::WIFI_EVENT, &id), TAG, "Failed to marshall WiFi event");
return ESP_OK;
}
esp_err_t ip_event(int32_t id, ip_event_got_ip_t *ip_data)
{
ESP_LOGI(TAG, "Received IP event %" PRIi32, id);
esp_wifi_remote_eppp_ip_event ip_event{};
ip_event.id = id;
if (ip_data->esp_netif) {
// marshall additional data, only if netif available
ESP_RETURN_ON_ERROR(esp_netif_get_dns_info(ip_data->esp_netif, ESP_NETIF_DNS_MAIN, &ip_event.dns), TAG, "Failed to get DNS info");
ESP_LOGI(TAG, "Main DNS:" IPSTR, IP2STR(&ip_event.dns.ip.u_addr.ip4));
memcpy(&ip_event.wifi_ip, &ip_data->ip_info, sizeof(ip_event.wifi_ip));
ESP_RETURN_ON_ERROR(esp_netif_get_ip_info(netif, &ip_event.ppp_ip), TAG, "Failed to get IP info");
ESP_LOGI(TAG, "IP address:" IPSTR, IP2STR(&ip_data->ip_info.ip));
}
ESP_RETURN_ON_ERROR(rpc.send(api_id::IP_EVENT, &ip_event), TAG, "Failed to marshal IP event");
return ESP_OK;
}
static void handler(void *ctx, esp_event_base_t base, int32_t id, void *data)
{
auto instance = static_cast<RpcInstance *>(ctx);
if (base == WIFI_EVENT) {
instance->wifi_event(id);
} else if (base == IP_EVENT) {
auto *ip_data = (ip_event_got_ip_t *)data;
instance->ip_event(id, ip_data);
}
}
esp_err_t perform()
{
auto header = rpc.get_header();
ESP_LOGI(TAG, "Received header id %d", (int) header.id);
switch (header.id) {
case api_id::SET_MODE: {
auto req = rpc.get_payload<wifi_mode_t>(api_id::SET_MODE, header);
auto ret = esp_wifi_set_mode(req);
if (rpc.send(api_id::SET_MODE, &ret) != ESP_OK) {
return ESP_FAIL;
}
break;
}
case api_id::INIT: {
auto req = rpc.get_payload<wifi_init_config_t>(api_id::INIT, header);
req.osi_funcs = &g_wifi_osi_funcs;
req.wpa_crypto_funcs = g_wifi_default_wpa_crypto_funcs;
auto ret = esp_wifi_init(&req);
if (rpc.send(api_id::INIT, &ret) != ESP_OK) {
return ESP_FAIL;
}
break;
}
case api_id::SET_CONFIG: {
auto req = rpc.get_payload<esp_wifi_remote_config>(api_id::SET_CONFIG, header);
auto ret = esp_wifi_set_config(req.interface, &req.conf);
if (rpc.send(api_id::SET_CONFIG, &ret) != ESP_OK) {
return ESP_FAIL;
}
break;
}
case api_id::START: {
if (header.size != 0) {
return ESP_FAIL;
}
auto ret = esp_wifi_start();
if (rpc.send(api_id::START, &ret) != ESP_OK) {
return ESP_FAIL;
}
break;
}
case api_id::CONNECT: {
if (header.size != 0) {
return ESP_FAIL;
}
auto ret = esp_wifi_connect();
if (rpc.send(api_id::CONNECT, &ret) != ESP_OK) {
return ESP_FAIL;
}
break;
}
case api_id::GET_MAC: {
auto req = rpc.get_payload<wifi_interface_t>(api_id::GET_MAC, header);
esp_wifi_remote_mac_t resp = {};
resp.err = esp_wifi_get_mac(req, resp.mac);
if (rpc.send(api_id::GET_MAC, &resp) != ESP_OK) {
return ESP_FAIL;
}
break;
}
default:
return ESP_FAIL;
}
return ESP_OK;
}
};
namespace server {
constinit RpcInstance instance;
}
RpcInstance *RpcEngine::init_server()
{
esp_tls_cfg_server_t cfg = {};
cfg.cacert_buf = server::ca_crt;
cfg.cacert_bytes = sizeof(server::ca_crt);
cfg.servercert_buf = server::crt;
cfg.servercert_bytes = sizeof(server::crt);
cfg.serverkey_buf = server::key;
cfg.serverkey_bytes = sizeof(server::key);
ESP_RETURN_ON_FALSE(tls_ = esp_tls_init(), nullptr, TAG, "Failed to create ESP-TLS instance");
ESP_RETURN_ON_FALSE(esp_tls_server_session_create(&cfg, server::instance.sock, tls_) == ESP_OK, nullptr, TAG, "Failed to create TLS session");
return &server::instance;
}
} // namespace eppp_rpc
using namespace eppp_rpc;
extern "C" esp_err_t server_init(void)
{
return server::instance.init();
}

View File

@ -271,26 +271,6 @@ WEAK esp_err_t esp_wifi_remote_set_csi(_Bool en)
LOG_UNSUPPORTED_AND_RETURN(ESP_ERR_NOT_SUPPORTED);
}
WEAK esp_err_t esp_wifi_remote_set_ant_gpio(const wifi_ant_gpio_config_t *config)
{
LOG_UNSUPPORTED_AND_RETURN(ESP_ERR_NOT_SUPPORTED);
}
WEAK esp_err_t esp_wifi_remote_get_ant_gpio(wifi_ant_gpio_config_t *config)
{
LOG_UNSUPPORTED_AND_RETURN(ESP_ERR_NOT_SUPPORTED);
}
WEAK esp_err_t esp_wifi_remote_set_ant(const wifi_ant_config_t *config)
{
LOG_UNSUPPORTED_AND_RETURN(ESP_ERR_NOT_SUPPORTED);
}
WEAK esp_err_t esp_wifi_remote_get_ant(wifi_ant_config_t *config)
{
LOG_UNSUPPORTED_AND_RETURN(ESP_ERR_NOT_SUPPORTED);
}
WEAK int64_t esp_wifi_remote_get_tsf_time(wifi_interface_t interface)
{
LOG_UNSUPPORTED_AND_RETURN(-1);

View File

@ -267,26 +267,6 @@ esp_err_t esp_wifi_set_csi(_Bool en)
return esp_wifi_remote_set_csi(en);
}
esp_err_t esp_wifi_set_ant_gpio(const wifi_ant_gpio_config_t *config)
{
return esp_wifi_remote_set_ant_gpio(config);
}
esp_err_t esp_wifi_get_ant_gpio(wifi_ant_gpio_config_t *config)
{
return esp_wifi_remote_get_ant_gpio(config);
}
esp_err_t esp_wifi_set_ant(const wifi_ant_config_t *config)
{
return esp_wifi_remote_set_ant(config);
}
esp_err_t esp_wifi_get_ant(wifi_ant_config_t *config)
{
return esp_wifi_remote_get_ant(config);
}
int64_t esp_wifi_get_tsf_time(wifi_interface_t interface)
{
return esp_wifi_remote_get_tsf_time(interface);

View File

@ -0,0 +1,5 @@
# This project serves as a demo to enable using esp-mqtt on ESP platform targets as well as on linux
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(esp_mqtt_demo)

View File

@ -0,0 +1,31 @@
# MQTT application running on WiFi station
This is a simple mqtt demo, that connects to WiFi AP first. This application has a dependency to `esp_wifi_remote`, so that if it's build and executed on a chipset without WiFI capabilities it redirects all wifi calls the remote target.
## Overview
When running this example on a target that doesn't natively support WiFi, please make sure that the remote target (slave application) is connected to your chipset via the configured transport interface.
Connection to the slave device also depends on RPC library used. It is recommended to use [`esp_hosted`](https://github.com/espressif/esp-hosted). Alternatively you can use [`eppp_link`](https://components.espressif.com/components/espressif/eppp_link).
Please note, that `esp_hosted` as a component is currently WIP, so the `wifi_remote` defaults to `eppp`, for now.
## HW connection
We currently support only `UART` transport, so the connection is very simple. You only need to connect Rx, Tx and GND with the remote target.
You need to configure these fields according to your connection:
* CONFIG_ESP_WIFI_REMOTE_EPPP_UART_TX_PIN
* CONFIG_ESP_WIFI_REMOTE_EPPP_UART_RX_PIN
## SW configuration
The RPC mechanism between the host and the slave micro uses TLS with mutual authentication, so you would have to configure certificates and keys for both parties. This application -- host target -- is considered RPC client, so it needs client's certificate and key, as well as the CA certificate to validate the server (slave application).
If self-signed certificates are acceptable, you can use [generate_test_certs](../test_certs/generate_test_certs.sh) script to generate both the CA and the keys itself and convert them to the PEM format that's accepted by the EPPP RPC engine.
You will have to configure these options:
* CONFIG_ESP_WIFI_REMOTE_EPPP_SERVER_CA
* CONFIG_ESP_WIFI_REMOTE_EPPP_CLIENT_CRT
* CONFIG_ESP_WIFI_REMOTE_EPPP_CLIENT_KEY
## Setting up slave device
You need to set up the connection and configuration in a similar way on the slave part (connection pins + certificates and keys). Please refer to the [slave_application](../server/README.md) README for more information.

View File

@ -0,0 +1,4 @@
idf_component_register(SRCS "app_main.c"
INCLUDE_DIRS ".")
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")

View File

@ -0,0 +1,21 @@
menu "Example Configuration"
config BROKER_URL
string "Broker URL"
default "mqtt://mqtt.eclipseprojects.io"
help
URL of the broker to connect to
config ESP_WIFI_SSID
string "WiFi SSID"
default "myssid"
help
SSID (network name) for the example to connect to.
config ESP_WIFI_PASSWORD
string "WiFi Password"
default "mypassword"
help
WiFi password (WPA or WPA2) for the example to use.
endmenu

View File

@ -0,0 +1,204 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include "esp_system.h"
#include "nvs_flash.h"
#include "esp_event.h"
#include "esp_netif.h"
#include "esp_netif.h"
#include "esp_system.h"
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_log.h"
#include "mqtt_client.h"
static const char *TAG = "esp_mqtt_demo";
static EventGroupHandle_t s_wifi_event_group;
static int s_retry_num = 0;
#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT BIT1
#define EXAMPLE_ESP_WIFI_SSID CONFIG_ESP_WIFI_SSID
#define EXAMPLE_ESP_WIFI_PASS CONFIG_ESP_WIFI_PASSWORD
#define EXAMPLE_ESP_MAXIMUM_RETRY 5
static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
{
ESP_LOGD(TAG, "Event dispatched from event loop base=%s, event_id=%d", base, event_id);
esp_mqtt_event_handle_t event = (esp_mqtt_event_handle_t)event_data;
esp_mqtt_client_handle_t client = event->client;
int msg_id;
switch ((esp_mqtt_event_id_t)event_id) {
case MQTT_EVENT_CONNECTED:
ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
msg_id = esp_mqtt_client_publish(client, "/topic/qos1", "data_3", 0, 1, 0);
ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);
msg_id = esp_mqtt_client_subscribe(client, "/topic/qos0", 0);
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
msg_id = esp_mqtt_client_subscribe(client, "/topic/qos1", 1);
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
msg_id = esp_mqtt_client_unsubscribe(client, "/topic/qos1");
ESP_LOGI(TAG, "sent unsubscribe successful, msg_id=%d", msg_id);
break;
case MQTT_EVENT_DISCONNECTED:
ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
break;
case MQTT_EVENT_SUBSCRIBED:
ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id);
msg_id = esp_mqtt_client_publish(client, "/topic/qos0", "data", 0, 0, 0);
ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);
break;
case MQTT_EVENT_UNSUBSCRIBED:
ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);
break;
case MQTT_EVENT_PUBLISHED:
ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
break;
case MQTT_EVENT_DATA:
ESP_LOGI(TAG, "MQTT_EVENT_DATA");
printf("TOPIC=%.*s\r\n", event->topic_len, event->topic);
printf("DATA=%.*s\r\n", event->data_len, event->data);
break;
case MQTT_EVENT_ERROR:
ESP_LOGI(TAG, "MQTT_EVENT_ERROR");
break;
default:
ESP_LOGI(TAG, "Other event id:%d", event->event_id);
break;
}
}
static void mqtt_app_start(void)
{
esp_mqtt_client_config_t mqtt_cfg = {};
mqtt_cfg.broker.address.uri = CONFIG_BROKER_URL;
mqtt_cfg.credentials.client_id = "idf_on_linux_client";
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);
/* The last argument may be used to pass data to the event handler, in this example mqtt_event_handler */
esp_mqtt_client_register_event(client, (esp_mqtt_event_id_t)ESP_EVENT_ANY_ID, mqtt_event_handler, NULL);
esp_mqtt_client_start(client);
}
static void event_handler(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data)
{
ESP_LOGI(TAG, "EVENT type %s id %d", event_base, (int)event_id);
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
esp_wifi_connect();
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
if (s_retry_num < EXAMPLE_ESP_MAXIMUM_RETRY) {
esp_wifi_connect();
s_retry_num++;
ESP_LOGI(TAG, "retry to connect to the AP");
} else {
xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
}
ESP_LOGI(TAG, "connect to the AP fail");
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data;
ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
s_retry_num = 0;
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
}
}
static void wifi_init_sta()
{
s_wifi_event_group = xEventGroupCreate();
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
esp_netif_create_default_wifi_sta();
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
esp_event_handler_instance_t instance_any_id;
esp_event_handler_instance_t instance_got_ip;
ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
ESP_EVENT_ANY_ID,
&event_handler,
NULL,
&instance_any_id));
ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
IP_EVENT_STA_GOT_IP,
&event_handler,
NULL,
&instance_got_ip));
wifi_config_t wifi_config = {
.sta = {
.ssid = EXAMPLE_ESP_WIFI_SSID,
.password = EXAMPLE_ESP_WIFI_PASS,
},
};
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );
ESP_ERROR_CHECK(esp_wifi_start() );
ESP_LOGI(TAG, "wifi_init_sta finished.");
/* 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) {
ESP_LOGI(TAG, "connected to ap SSID:%s password:%s",
EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
} else if (bits & WIFI_FAIL_BIT) {
ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s",
EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
} else {
ESP_LOGE(TAG, "UNEXPECTED EVENT");
}
}
void app_main(void)
{
ESP_LOGI(TAG, "[APP] Startup..");
ESP_LOGI(TAG, "[APP] Free memory: %d bytes", esp_get_free_heap_size());
ESP_LOGI(TAG, "[APP] IDF version: %s", esp_get_idf_version());
esp_log_level_set("*", ESP_LOG_INFO);
esp_log_level_set("mqtt_client", ESP_LOG_VERBOSE);
esp_log_level_set("esp_mqtt_demo", ESP_LOG_VERBOSE);
esp_log_level_set("transport_base", ESP_LOG_VERBOSE);
esp_log_level_set("esp-tls", ESP_LOG_VERBOSE);
esp_log_level_set("transport", ESP_LOG_VERBOSE);
esp_log_level_set("outbox", ESP_LOG_VERBOSE);
//Initialize NVS
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
ESP_LOGI(TAG, "ESP_WIFI_MODE_STA");
wifi_init_sta();
mqtt_app_start();
}

View File

@ -0,0 +1,5 @@
dependencies:
espressif/eppp_link: "^0.0.1"
esp_wifi_remote:
version: "*"
override_path: ../../..

View File

@ -0,0 +1,5 @@
CONFIG_ESP_WIFI_REMOTE_EPPP_UART_TX_PIN=17
CONFIG_ESP_WIFI_REMOTE_EPPP_UART_RX_PIN=16
CONFIG_ESP_WIFI_REMOTE_EPPP_SERVER_CA="MIIDIzCCAgugAwIBAgIULOncUeRLKxgrihIh1kHGGlPV7ecwDQYJKoZIhvcNAQELBQAwITELMAkGA1UEBhMCQ1oxEjAQBgNVBAMMCUVzcHJlc3NpZjAeFw0yNDA0MDMwOTE0MjNaFw0zNDA0MDEwOTE0MjNaMCExCzAJBgNVBAYTAkNaMRIwEAYDVQQDDAlFc3ByZXNzaWYwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCbayaZAuzQWrwRj3oiFP9AZK0ECaDvVlJec4M6yokded1pqNY+bNmA7VsHSQkf3d1rO1G5GwEXoMPli15m7rJodq9iYp1J2LhLhpKDNapm19reyH9A4rAfjSyk/WyvT+3Y5sNHVFdE2t1EetOyzy90CfOHT9JfWG9PiV6b1W65CqgjJVCHMWioppVAGQCoN+mDBf1VhD4am6onei+ijHdALJDfp74mSIOJGulm/IR7504s+yy7068PQ05V/wHkmd9O1Iww5fnJdRh2KvTFZVOB5u9y54MTJb0sGZj+JfxIbcFiIWAykLFVWBk5PO6yj8fNMmk/Ogb2K4wo7AZnJ3qBAgMBAAGjUzBRMB0GA1UdDgQWBBT3j77hJHm/hI34fEn3tocHqB4INzAfBgNVHSMEGDAWgBT3j77hJHm/hI34fEn3tocHqB4INzAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBstXfBIRvqZp4OBQ2kCJig/CErcfdB4qQOS2LzQmpIOUQ4d/zvZOQD2WIw/x2Rd1/hto/+f57pOZNHsi8vfX2Z7kPOlD9ZG1wTznl1v8wOMP01AFJuVtmJQV0C4lVupb2/Mmu42xqP9pr/uL5pJ2rFb8ujl2xakhSvYVdMONtZL0mh9+hdnUb7Fj7KI3qWxzc7+uXGjCzh6LkOmcMBOB6+0V6xW2NVpUUPtuXytK0t2oyWpDvwFIrl0J6qBNRlH1ON1iz33HOo73IjprMNx3hIo5y/N8+TTxY6KEegbP67hSnJJhQ7tezoOu4OE0xmJp0XmGPMNewYARqL2UvHnZyf"
CONFIG_ESP_WIFI_REMOTE_EPPP_CLIENT_CRT="MIICwjCCAaoCFAWE4aJdYWbMJAaBTMxVpoXMrhzvMA0GCSqGSIb3DQEBCwUAMCExCzAJBgNVBAYTAkNaMRIwEAYDVQQDDAlFc3ByZXNzaWYwHhcNMjQwNDAzMDkxNjE4WhcNMzQwNDAxMDkxNjE4WjAaMRgwFgYDVQQDDA9lc3ByZXNzaWYubG9jYWwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDcjdBQ3sHbfuWRo2LlqZF37Dfuymz5/fq+szcOLUUWCccxku9qNNEdZAcZHMsINurezpHXa6ZNKGqmbmqZPVrEKzMUIolpnQmcerRt/yKqxCZ/kgsJE3IZyqi1T+xDwaBEhgdB6+wxyrL0/uBlLCbEdZAA7MPcauIKz8ykfIwo7Ht/vcHNxGaFFu+DcNoJI/Pw6hERlC9DHuUftK0/Lap1K2o+6kFQKqhVrvNQmaiqnz3Dr9psPO90AvbRqeODmfpi7rtU4MKOprQhUrMS9s9d5yVdJILp74pt6nzu3EnFiixRD5XD9PtK5NvP1sgDAgbWgTttwM9X7N6mzEe/gVUZAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAJVsbAamDRuZ1J2ogHLo/UmjmcmIATmqO7Ebaoid7+FYme/2NFzofOFtJNaCumdhwxSyf7ER6m2DUO6bDseblqNCTyRDNNXzTHEFQiYh2PThKSDdH0fbEf4IpcbOCnpSEpIg9C/ywEhq/wzYiOlxPhNWxBKHLhEkM7aWBerAhInCRRXymfus2HUf6aTWZ0wigMoUVKwOu16Zh04D2d6qb314cEMgKvANPiTTdgEae7Ot+rP1s2Zp75zUbWuz4uWd4wJDOHWR25mkD3ZELfbrpmEymbOTQ26zOpIUiPNfYZ1t9KwEjkKN+jBTXKu7QhB/u+g5yBHjRL++LEli4YGGGiA="
CONFIG_ESP_WIFI_REMOTE_EPPP_CLIENT_KEY="MIIEpQIBAAKCAQEA3I3QUN7B237lkaNi5amRd+w37sps+f36vrM3Di1FFgnHMZLvajTRHWQHGRzLCDbq3s6R12umTShqpm5qmT1axCszFCKJaZ0JnHq0bf8iqsQmf5ILCRNyGcqotU/sQ8GgRIYHQevsMcqy9P7gZSwmxHWQAOzD3GriCs/MpHyMKOx7f73BzcRmhRbvg3DaCSPz8OoREZQvQx7lH7StPy2qdStqPupBUCqoVa7zUJmoqp89w6/abDzvdAL20anjg5n6Yu67VODCjqa0IVKzEvbPXeclXSSC6e+Kbep87txJxYosUQ+Vw/T7SuTbz9bIAwIG1oE7bcDPV+zepsxHv4FVGQIDAQABAoIBAQDPzzc224yg+iHoZaArcOhFrGbPMiAYNLxrroTzcKglqbTr+txmn7lhDfy6Jq0O4l/O66fy59Vb4fcLNgJuvKanK2UHVbtPrc1+iQc0lS7e4866aKrJNG9P6emoXNPqy6fsqLRx4o88IxcXTIe2DDHC7lpu5KdvKa4uLblOSqPtcZTHXPD9olVe8ZYF5CttMUTc4SkF4HSkY2jb0j+6kASN4eQ2CqEt+IW4IxI5NiEzrlzZSOdyqIOeyGUZz+QcfILOProWZHYzH3jOHQe4PJSXO57f2dojY1GqRcjnr3guQMpw1s7wmDYO1QekiBYwRERNzjEY7VhgDq8T0rwJPHP5AoGBAPO13QpJVSj1NfQ/H0AgZlsJIIlIwIC2YwuwjA7b36A3JOFolkHjtq4eNntThNRQbTL9OficbxJSHXQcOsQeo7dvwEhJjuVwEajL4/6cjc9b4oyGJxLlTKTshUPmeKPfGWUjRZKGbVWbT3m4BXqGiv4laCZ0LDHiCt4DvEzQ1Bo3AoGBAOetBClbcbUJhxkAme5HHI9A5VcqyOi2CrRh+HjKd/2IJlDA+Vmbl2iEB+9cMRGRubazbrk1yAzgtW29GX8kngr8yxDtIM8M7lPR2NhXx7XbmCKwKosZ7l6hHNdnD12TFyLCjuuJlUA37sWXw8r33623mLFQlNVjnL0onUa1XSMvAoGACw47+cR73YDKMstOQp11pzmRxUiMmworEhOvNtlYmq8FuEgDUPfgiKOMOyn9w5fmbEK6h4GpND6PYX4KWG0/ZgnmwiC8H8Jmuq6NKDa35Ck57MAFM8E9Kdok7YCeBmkPgNwJwuzgNtr1zwK/FODXm1HdGKl6e8TSU2H9/8oVZR8CgYEAoHSWI0awNCCLLufZtMwPna/mpz58s6ARPel0u8QO4st/LgLZMBSxArQfAsqpOW/iXgVcNG5pRXIEdiK4G/TyeM2onup9BKoCDo+SThRNv0h9z9iPPpQRIf0YCp/YZojPR0XU0pERi86xUqzP8C1I//neiUA0NK6vCdutQiGuhgUCgYEAp89EFcM1WvtPRJE+md8N8BUef5MJ+JJ0nb+BW1kkLY50Q1MVmsVXdUowYupWLBgEfMn8fy8Q+xD9EeiISTF9MtT1X4iQSI/pzKW5LLd0OJYnqPMWzyggASzSNWdYBIGNkqsQGmGCtF9+i6V4acfTTbMD9LiB7u5/enQa8N0Qg+s="

View File

@ -0,0 +1,3 @@
CONFIG_LWIP_PPP_SUPPORT=y
CONFIG_LWIP_PPP_SERVER_SUPPORT=y
CONFIG_LWIP_PPP_VJ_HEADER_COMPRESSION=n

View File

@ -0,0 +1,6 @@
# The following five lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(pppos_slave)

View File

@ -0,0 +1,21 @@
# WiFi remote EPPP RPC server
This is a standalone application serving as the slave device for `esp_wifi_remote` users (with `eppp` RPC).
## Overview
You need to configure and connect a slave device to the `esp_wifi_remote` host and run this application. Please fallow carefully these guidelines on HW connection and configuration of the slave device, based on the host device.
## HW connection
We currently support only `UART` transport you just need to connect Rx, Tx and GND and configure these fields accordingly:
* CONFIG_ESP_WIFI_REMOTE_EPPP_UART_TX_PIN
* CONFIG_ESP_WIFI_REMOTE_EPPP_UART_RX_PIN
## SW configuration
You will have to install server side certificates and keys, as well as the CA which should verify the client side.
Please configure these options:
* CONFIG_ESP_WIFI_REMOTE_EPPP_CLIENT_CA
* CONFIG_ESP_WIFI_REMOTE_EPPP_SERVER_CRT
* CONFIG_ESP_WIFI_REMOTE_EPPP_SERVER_KEY

View File

@ -0,0 +1,2 @@
idf_component_register(SRCS "station_example_main.c"
INCLUDE_DIRS ".")

View File

@ -0,0 +1,5 @@
dependencies:
espressif/eppp_link: "^0.0.1"
esp_wifi_remote:
version: "*"
override_path: ../../..

View File

@ -0,0 +1,36 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <string.h>
#include <esp_private/wifi.h>
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "eppp_link.h"
#include "esp_wifi_remote.h"
esp_err_t server_init(void);
void app_main(void)
{
//Initialize NVS
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
esp_netif_create_default_wifi_sta();
server_init();
}

View File

@ -0,0 +1,6 @@
CONFIG_IDF_TARGET="esp32c6"
CONFIG_ESP_WIFI_REMOTE_EPPP_UART_TX_PIN=22
CONFIG_ESP_WIFI_REMOTE_EPPP_UART_RX_PIN=23
CONFIG_ESP_WIFI_REMOTE_EPPP_CLIENT_CA="MIIDIzCCAgugAwIBAgIUTWOEAhITHAm2ixn5i2XlSeL01mowDQYJKoZIhvcNAQELBQAwITELMAkGA1UEBhMCQ1oxEjAQBgNVBAMMCUVzcHJlc3NpZjAeFw0yNDA0MTAxNTEzNTdaFw0yNTA0MTAxNTEzNTdaMCExCzAJBgNVBAYTAkNaMRIwEAYDVQQDDAlFc3ByZXNzaWYwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCSewupiSiyZNfLdVW0/smQB0yJ0Ua0KNU423ZZ7HMSrBPhfHtnQQ6SJqTdfqGCl1lvSsJZN9aT4iaEtyAm6N9trmSbSWVlkn0D8MQuBHwHCT7jRsLnyRYURRPUs11TkQdqvxtsIFqFVFB/8nJqy4IuU6JFTobCbUappQMdHKCyidXJUVHZ5y+KK2kEYFiv26rHlry+D0O/VO5/xl97uFIzP0JVdnGNu5sy9uoRYp+ua0moD3tx12tYe83XIuHKbKHMpIayjPIoaZzhCwomZMh0NETEQ5t7RXYneRGZvXXyIb/O8jPCmbfSqJ6umhPhf757xBXHaC0iG/xlND0dnRIvAgMBAAGjUzBRMB0GA1UdDgQWBBTgqejeFi/5UAgNhNv4aH7UniqmQjAfBgNVHSMEGDAWgBTgqejeFi/5UAgNhNv4aH7UniqmQjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCQnqIue6KLXkjOXGtO5Bl4TkZpYAPkQuGiM6RgaBhdt3P5J1mF4T6aav8qGXSHShy1E3XkMR5OC3hkhG+FKBVKSaQLsRipuo+CeHp5RfOCNEzNI0RZwKJI92RcdWlhOA+pOTruXSoYuZvj0xnaePEghTrr7PLdgirpzIffLjvgh8BcQAz5QzP0U1XHkAVzbQjUBChiEiXVAlKChk7kKB/wEzwX3cvYKlTc89RB6I3+a+KhYJt3LIAOIDeyVp+Bhmb1JSo3H7zMpJAksG2RMnZCwlHeR6cMbb/OtJYeUKpNUxj0SaeNyHo3y8Q21G8TXcc9suU6sYJi780ArulC3cbQ"
CONFIG_ESP_WIFI_REMOTE_EPPP_SERVER_CRT="MIICvzCCAacCFCanehvaDq0bhjZA/3W/h4b0p1VHMA0GCSqGSIb3DQEBCwUAMCExCzAJBgNVBAYTAkNaMRIwEAYDVQQDDAlFc3ByZXNzaWYwHhcNMjQwNDEwMTUxMzU3WhcNMjUwNDEwMTUxMzU3WjAXMRUwEwYDVQQDDAwxOTIuMTY4LjExLjEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsyR1FqBhBT3mr9AH/6iYoo1VCHbzB+V/StfCokv6LnMm6t7yiu1GgzqVk1aiHrUJGor5tBfpXywLnfVjFByZSBhhEkI26xQVdK5pZUsU1hMCJ6CWd105CD+0e5tTbGzF0PNH2KzFdg2YUqOSWBsfmgSNtnp3az8XmZN5i4958Sxe1kMN3f6EQwvkxZHGVgXCrUsdsHAEyV5NVfYq7P2nBxz3HJSGkTScFd+PRp3nfVFbBbCQDmqwoPZ7E/gUXjoLIFf7zjIMzCXTsZd/dKgXWWEFHq8SPWmLtAEvPCProT5QUaZ3gJSHup9Wmh+ok9W8wrwMj1sHlfiZWo3tatFmvAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAAeWiWyTTyNbZRHq8X9qbr7oG6SYWOqDR3lPfs8wB8B+1Hez/JCrI/8quNqVAjhoTtebtp/2mcEseQDj5BOx8NBCDAmUOwB+ZKPzUoGiALy5XFGqUXzTv9tBMotC6dAMTIbT2Ql1mPJgtg2+Qv7vg6hsk4rlPMoICqN3lW6zXo2GOuJ56Tj5NkvVxv6MOVN2e3p67c92rRBysAxP6MaV8S9s2+VvnENuxpU5cq8sfzaxFkTn4UD9PoQSYGPNL9kv7Y/h7H5wlKiFY24KowPTHjulaH/DC9Fk4F1gNWjnkFcOgepzhiw/ibLrivMptUFtplFFbxGuwY5PaA26yhliBv8="
CONFIG_ESP_WIFI_REMOTE_EPPP_SERVER_KEY="MIIEowIBAAKCAQEArMkdRagYQU95q/QB/+omKKNVQh28wflf0rXwqJL+i5zJure8ortRoM6lZNWoh61CRqK+bQX6V8sC531YxQcmUgYYRJCNusUFXSuaWVLFNYTAieglnddOQg/tHubU2xsxdDzR9isxXYNmFKjklgbH5oEjbZ6d2s/F5mTeYuPefEsXtZDDd3+hEML5MWRxlYFwq1LHbBwBMleTVX2Kuz9pwcc9xyUhpE0nBXfj0ad531RWwWwkA5qsKD2exP4FF46CyBX+84yDMwl07GXf3SoF1lhBR6vEj1pi7QBLzwj66E+UFGmd4CUh7qfVpofqJPVvMK8DI9bB5X4mVqN7WrRZrwIDAQABAoIBAHDh833OlAoXIiZ1A9lt4AAstUa8ptUTVscSlmeLoUEU7bZO0659MpccanG2JKR/TQ1YxY/0l9lDiGI0Qgp24VI1KSWiSvX6Qcbc9bnlmXGdiSyPvgOg5j/Cp+fIZse+vFB0a7eoAFhXwBk/PhfF1lOBiuPS/M43b9NVkvSIapJIaS4pvmkBvKSzHEvSArDHcr+1vFuFssZyHTnXmVgB4WiYPX4ACE8S18cnjXIQDfx8zpBbF/itnqeHDC5echnto63UDB7qHZa+DVvakhEtv50rzAuhq3/uspBClucuQUhlAAimd4OeKuwB1UC0K9AamDZRCnsf0O/Bo8/W4SWYAgECgYEA5LpRmcQ9ghW8V6bzwYvK8XGWyeNy94qOpZysFeOjxqe2sUTHVY2Ty1s44RbDd/bm0n3xcxMtLof/6Oz4TX+JseskQWBQlRiwuqc46CcHHjUQ8qokfWtASwWYgb6AzLa4B/D+H91wP/AzRfYNdRB9xhSCr7AOk9Vo5KmEPRLN/VMCgYEAwWM3oDaCkMicoMgngz/9dZ2/1yohfYdrupC0pGPhtBFNKghP+9S+e6cwWKzwQJbbRjGgt1OA3e4UEuTHJjp1tw+BRkNQ/1FI0psJGwmOtveAE7yiHf7Tw7mNDk+j32vpAPWnL7I3222Kv4G8xi2vSbn3IaI2sl7M0RHLJc/JCrUCgYBh4dI16aMg3khhglLiSv6oYKHU9/8lLChreyaxn19hDjjCl9puJE5RQlKPEPzJg+G3xqnjQxucxBqiBXclQyUb/LLhP2R8ybonxpQ11S3YoYEFOAaxnYpAEL75Fxtrf+41h85YuJzm39YxZGDR7iLE99YNdVxnq3ZeFKVAtaFtfQKBgEalPRvc7eOANZ+SnsSWqru9regnLubRgqw70pG/HyONsnepY7amaBN55vJt8rJVqbLBzGlMKuZn45NnWc0ATCJcmqgVTVCH3Cd7lV74Jdd3IKWVIk/82FVGwl25AC9NF2hPVQzaeQdCxA3jkhd/dupi8gGqZXrRoNa7PlAI0POFAoGBAJDlvddpEYcKhT3pncXIorVfYR67TlXVcKZHvL9XljwgDuf1j52ZhAs8UuoWW+NSgOdWVxocAshrLbu5fjSIN92oDAq6YVeXvxis6e8l79xd6A5iFH9Po+dEuQSaOR8XgW56n39oVR2hfaFwqijawIEzDNlYpiXAD3qNyW5e0MKA"

View File

@ -0,0 +1,6 @@
CONFIG_LWIP_IP_FORWARD=y
CONFIG_LWIP_IPV4_NAPT=y
CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=4096
CONFIG_LWIP_PPP_SUPPORT=y
CONFIG_LWIP_PPP_SERVER_SUPPORT=y
CONFIG_LWIP_PPP_VJ_HEADER_COMPRESSION=n

View File

@ -0,0 +1,41 @@
#!/usr/bin/env bash
if [ -z "$1" ]; then
echo "Usage $0 <SERVER_CN> [CLIENT_CN]"
exit 1;
fi
SERVER_CN=$1
CLIENT_CN="${2-client_cn}"
echo "Server's CN: $SERVER_CN"
echo "Client's CN: $CLIENT_CN"
## First create our own CA
openssl genrsa -out ca.key 2048
openssl req -new -x509 -subj "/C=CZ/CN=Espressif" -days 365 -key ca.key -out ca.crt
# Server side
openssl genrsa -out srv.key 2048
openssl req -out srv.csr -key srv.key -subj "/CN=$SERVER_CN" -new -sha256
openssl x509 -req -in srv.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out srv.crt -days 365 -sha256
# Client side
openssl genrsa -out client.key 2048
openssl req -out client.csr -key client.key -subj "/CN=$CLIENT_CN" -new -sha256
openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt -days 365 -sha256
## Generate config options
# Client side:
CA_CRT=`cat ca.crt | sed '/---/d' | tr -d '\n'`
echo "CONFIG_ESP_WIFI_REMOTE_EPPP_SERVER_CA=\"$CA_CRT\""
CLIENT_CRT=`cat client.crt | sed '/---/d' | tr -d '\n'`
echo "CONFIG_ESP_WIFI_REMOTE_EPPP_CLIENT_CRT=\"$CLIENT_CRT\""
CLIENT_KEY=`cat client.key | sed '/---/d' | tr -d '\n'`
echo "CONFIG_ESP_WIFI_REMOTE_EPPP_CLIENT_KEY=\"$CLIENT_KEY\""
## Server side (here it uses the same CA)
echo "CONFIG_ESP_WIFI_REMOTE_EPPP_CLIENT_CA=\"$CA_CRT\""
SERVER_CRT=`cat srv.crt | sed '/---/d' | tr -d '\n'`
echo "CONFIG_ESP_WIFI_REMOTE_EPPP_SERVER_CRT=\"$SERVER_CRT\""
SERVER_KEY=`cat srv.key | sed '/---/d' | tr -d '\n'`
echo "CONFIG_ESP_WIFI_REMOTE_EPPP_SERVER_KEY=\"$SERVER_KEY\""

View File

@ -1,8 +1,10 @@
version: 0.1.12
version: 0.2.0
url: https://github.com/espressif/esp-protocols/tree/master/components/esp_wifi_remote
description: Utility wrapper for esp_wifi functionality on remote targets
dependencies:
espressif/eppp_link:
version: '0.0.1'
idf:
version: '5.3'
version: '>=5.3'
# espressif/esp_hosted:
# version: '*'

View File

@ -57,10 +57,6 @@ esp_err_t esp_wifi_remote_80211_tx(wifi_interface_t ifx, const void *buffer, int
esp_err_t esp_wifi_remote_set_csi_rx_cb(wifi_csi_cb_t cb, void *ctx);
esp_err_t esp_wifi_remote_set_csi_config(const wifi_csi_config_t *config);
esp_err_t esp_wifi_remote_set_csi(_Bool en);
esp_err_t esp_wifi_remote_set_ant_gpio(const wifi_ant_gpio_config_t *config);
esp_err_t esp_wifi_remote_get_ant_gpio(wifi_ant_gpio_config_t *config);
esp_err_t esp_wifi_remote_set_ant(const wifi_ant_config_t *config);
esp_err_t esp_wifi_remote_get_ant(wifi_ant_config_t *config);
int64_t esp_wifi_remote_get_tsf_time(wifi_interface_t interface);
esp_err_t esp_wifi_remote_set_inactive_time(wifi_interface_t ifx, uint16_t sec);
esp_err_t esp_wifi_remote_get_inactive_time(wifi_interface_t ifx, uint16_t *sec);

View File

@ -15,6 +15,7 @@ Param = namedtuple('Param', ['ptr', 'array', 'qual', 'type', 'name'])
AUTO_GENERATED = 'This file is auto-generated'
COPYRIGHT_HEADER = open('copyright_header.h', 'r').read()
NAMESPACE = re.compile(r'^esp_wifi')
DEPRECATED_API = ['esp_wifi_set_ant_gpio', 'esp_wifi_get_ant', 'esp_wifi_get_ant_gpio', 'esp_wifi_set_ant']
class FunctionVisitor(c_ast.NodeVisitor):
@ -51,6 +52,8 @@ class FunctionVisitor(c_ast.NodeVisitor):
if isinstance(node.type, c_ast.TypeDecl):
func_name = node.type.declname
if func_name.startswith('esp_wifi') and func_name in self.content:
if func_name in DEPRECATED_API:
return
ret = node.type.type.names[0]
args = []
for param in node.args.params:
@ -309,6 +312,7 @@ def generate_kconfig(idf_path, component_path):
f.write(' bool\n')
f.write(' default y\n\n')
f.write(' orsource "./Kconfig.soc_wifi_caps.in"\n')
f.write(' orsource "./Kconfig.rpc.in"\n')
for line1 in lines:
line = line1.strip()
if re.match(r'^if\s+[A-Z_0-9]+\s*$', line):
@ -322,7 +326,7 @@ def generate_kconfig(idf_path, component_path):
line1 = re.compile(config).sub('SLAVE_' + config, line1)
f.write(line1)
if line.startswith('if ESP_WIFI_ENABLED'):
if re.match(r'^if\s+\(?ESP_WIFI_ENABLED', line):
copy = nested_if
f.write('endmenu # Wi-Fi Remote\n')
return [remote_kconfig]

View File

@ -17,5 +17,7 @@ menu "ESP Hosted Mock"
bool "esp32c6"
config SLAVE_IDF_TARGET_ESP32H2
bool "esp32h2"
config SLAVE_IDF_TARGET_ESP32P4
bool "esp32p4"
endchoice
endmenu

View File

@ -267,26 +267,6 @@ esp_err_t esp_wifi_remote_set_csi(_Bool en)
return ESP_OK;
}
esp_err_t esp_wifi_remote_set_ant_gpio(const wifi_ant_gpio_config_t *config)
{
return ESP_OK;
}
esp_err_t esp_wifi_remote_get_ant_gpio(wifi_ant_gpio_config_t *config)
{
return ESP_OK;
}
esp_err_t esp_wifi_remote_set_ant(const wifi_ant_config_t *config)
{
return ESP_OK;
}
esp_err_t esp_wifi_remote_get_ant(wifi_ant_config_t *config)
{
return ESP_OK;
}
int64_t esp_wifi_remote_get_tsf_time(wifi_interface_t interface)
{
return 0;

View File

@ -57,10 +57,6 @@ esp_err_t esp_wifi_remote_80211_tx(wifi_interface_t ifx, const void *buffer, int
esp_err_t esp_wifi_remote_set_csi_rx_cb(wifi_csi_cb_t cb, void *ctx);
esp_err_t esp_wifi_remote_set_csi_config(const wifi_csi_config_t *config);
esp_err_t esp_wifi_remote_set_csi(_Bool en);
esp_err_t esp_wifi_remote_set_ant_gpio(const wifi_ant_gpio_config_t *config);
esp_err_t esp_wifi_remote_get_ant_gpio(wifi_ant_gpio_config_t *config);
esp_err_t esp_wifi_remote_set_ant(const wifi_ant_config_t *config);
esp_err_t esp_wifi_remote_get_ant(wifi_ant_config_t *config);
int64_t esp_wifi_remote_get_tsf_time(wifi_interface_t interface);
esp_err_t esp_wifi_remote_set_inactive_time(wifi_interface_t ifx, uint16_t sec);
esp_err_t esp_wifi_remote_get_inactive_time(wifi_interface_t ifx, uint16_t *sec);

View File

@ -280,26 +280,6 @@ void run_all_wifi_apis(void)
esp_wifi_set_csi(en);
}
{
const wifi_ant_gpio_config_t *config = NULL;
esp_wifi_set_ant_gpio(config);
}
{
wifi_ant_gpio_config_t *config = NULL;
esp_wifi_get_ant_gpio(config);
}
{
const wifi_ant_config_t *config = NULL;
esp_wifi_set_ant(config);
}
{
wifi_ant_config_t *config = NULL;
esp_wifi_get_ant(config);
}
{
wifi_interface_t interface = 0;
esp_wifi_get_tsf_time(interface);

View File

@ -280,26 +280,6 @@ void run_all_wifi_remote_apis(void)
esp_wifi_remote_set_csi(en);
}
{
const wifi_ant_gpio_config_t *config = NULL;
esp_wifi_remote_set_ant_gpio(config);
}
{
wifi_ant_gpio_config_t *config = NULL;
esp_wifi_remote_get_ant_gpio(config);
}
{
const wifi_ant_config_t *config = NULL;
esp_wifi_remote_set_ant(config);
}
{
wifi_ant_config_t *config = NULL;
esp_wifi_remote_get_ant(config);
}
{
wifi_interface_t interface = 0;
esp_wifi_remote_get_tsf_time(interface);

View File

@ -2,7 +2,7 @@
dependencies:
## Required IDF version
idf:
version: "5.3"
version: '>=5.3'
espressif/esp_wifi_remote:
version: "*"
override_path: ../../..

View File

@ -0,0 +1,2 @@
CONFIG_LWIP_PPP_SUPPORT=y
CONFIG_LWIP_PPP_SERVER_SUPPORT=y

View File

@ -0,0 +1,8 @@
---
commitizen:
bump_message: 'bump(tls_cxx): $current_version -> $new_version'
pre_bump_hooks: python ../../ci/changelog.py mbedtls_cxx
tag_format: tls_cxx-v$version
version: 0.1.0
version_files:
- idf_component.yml

View File

@ -0,0 +1,7 @@
# Changelog
## [0.1.0](https://github.com/espressif/esp-protocols/commits/tls_cxx-v0.1.0)
### Features
- Publish mbedtls component ([0140455f](https://github.com/espressif/esp-protocols/commit/0140455f))

View File

@ -0,0 +1,3 @@
idf_component_register(SRCS mbedtls_wrap.cpp
INCLUDE_DIRS include
REQUIRES tcp_transport)

View File

@ -0,0 +1,3 @@
# mbedtls_cxx
This is a simplified C++ wrapper of mbedTLS for performing TLS and DTLS handshake a communication. This component allows for overriding low level IO functions (`send()` and `recv()`) and thus supporting TLS over various physical channels.

View File

@ -0,0 +1,8 @@
idf_component_register(
EMBED_TXTFILES srv.crt
EMBED_TXTFILES srv.key
EMBED_TXTFILES ca.crt
EMBED_TXTFILES client.crt
EMBED_TXTFILES client.key
INCLUDE_DIRS "."
REQUIRES mbedtls_cxx)

View File

@ -0,0 +1,4 @@
# Test Certificates and Keys
This is a utility component, that uses test certificates for server and client side in examples and tests.
These are self-signed certificates and generated only for test and demonstration purposes.

View File

@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDIzCCAgugAwIBAgIULOncUeRLKxgrihIh1kHGGlPV7ecwDQYJKoZIhvcNAQEL
BQAwITELMAkGA1UEBhMCQ1oxEjAQBgNVBAMMCUVzcHJlc3NpZjAeFw0yNDA0MDMw
OTE0MjNaFw0zNDA0MDEwOTE0MjNaMCExCzAJBgNVBAYTAkNaMRIwEAYDVQQDDAlF
c3ByZXNzaWYwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCbayaZAuzQ
WrwRj3oiFP9AZK0ECaDvVlJec4M6yokded1pqNY+bNmA7VsHSQkf3d1rO1G5GwEX
oMPli15m7rJodq9iYp1J2LhLhpKDNapm19reyH9A4rAfjSyk/WyvT+3Y5sNHVFdE
2t1EetOyzy90CfOHT9JfWG9PiV6b1W65CqgjJVCHMWioppVAGQCoN+mDBf1VhD4a
m6onei+ijHdALJDfp74mSIOJGulm/IR7504s+yy7068PQ05V/wHkmd9O1Iww5fnJ
dRh2KvTFZVOB5u9y54MTJb0sGZj+JfxIbcFiIWAykLFVWBk5PO6yj8fNMmk/Ogb2
K4wo7AZnJ3qBAgMBAAGjUzBRMB0GA1UdDgQWBBT3j77hJHm/hI34fEn3tocHqB4I
NzAfBgNVHSMEGDAWgBT3j77hJHm/hI34fEn3tocHqB4INzAPBgNVHRMBAf8EBTAD
AQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBstXfBIRvqZp4OBQ2kCJig/CErcfdB4qQO
S2LzQmpIOUQ4d/zvZOQD2WIw/x2Rd1/hto/+f57pOZNHsi8vfX2Z7kPOlD9ZG1wT
znl1v8wOMP01AFJuVtmJQV0C4lVupb2/Mmu42xqP9pr/uL5pJ2rFb8ujl2xakhSv
YVdMONtZL0mh9+hdnUb7Fj7KI3qWxzc7+uXGjCzh6LkOmcMBOB6+0V6xW2NVpUUP
tuXytK0t2oyWpDvwFIrl0J6qBNRlH1ON1iz33HOo73IjprMNx3hIo5y/N8+TTxY6
KEegbP67hSnJJhQ7tezoOu4OE0xmJp0XmGPMNewYARqL2UvHnZyf
-----END CERTIFICATE-----

View File

@ -0,0 +1,17 @@
-----BEGIN CERTIFICATE-----
MIICwjCCAaoCFAWE4aJdYWbMJAaBTMxVpoXMrhzvMA0GCSqGSIb3DQEBCwUAMCEx
CzAJBgNVBAYTAkNaMRIwEAYDVQQDDAlFc3ByZXNzaWYwHhcNMjQwNDAzMDkxNjE4
WhcNMzQwNDAxMDkxNjE4WjAaMRgwFgYDVQQDDA9lc3ByZXNzaWYubG9jYWwwggEi
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDcjdBQ3sHbfuWRo2LlqZF37Dfu
ymz5/fq+szcOLUUWCccxku9qNNEdZAcZHMsINurezpHXa6ZNKGqmbmqZPVrEKzMU
IolpnQmcerRt/yKqxCZ/kgsJE3IZyqi1T+xDwaBEhgdB6+wxyrL0/uBlLCbEdZAA
7MPcauIKz8ykfIwo7Ht/vcHNxGaFFu+DcNoJI/Pw6hERlC9DHuUftK0/Lap1K2o+
6kFQKqhVrvNQmaiqnz3Dr9psPO90AvbRqeODmfpi7rtU4MKOprQhUrMS9s9d5yVd
JILp74pt6nzu3EnFiixRD5XD9PtK5NvP1sgDAgbWgTttwM9X7N6mzEe/gVUZAgMB
AAEwDQYJKoZIhvcNAQELBQADggEBAJVsbAamDRuZ1J2ogHLo/UmjmcmIATmqO7Eb
aoid7+FYme/2NFzofOFtJNaCumdhwxSyf7ER6m2DUO6bDseblqNCTyRDNNXzTHEF
QiYh2PThKSDdH0fbEf4IpcbOCnpSEpIg9C/ywEhq/wzYiOlxPhNWxBKHLhEkM7aW
BerAhInCRRXymfus2HUf6aTWZ0wigMoUVKwOu16Zh04D2d6qb314cEMgKvANPiTT
dgEae7Ot+rP1s2Zp75zUbWuz4uWd4wJDOHWR25mkD3ZELfbrpmEymbOTQ26zOpIU
iPNfYZ1t9KwEjkKN+jBTXKu7QhB/u+g5yBHjRL++LEli4YGGGiA=
-----END CERTIFICATE-----

View File

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEA3I3QUN7B237lkaNi5amRd+w37sps+f36vrM3Di1FFgnHMZLv
ajTRHWQHGRzLCDbq3s6R12umTShqpm5qmT1axCszFCKJaZ0JnHq0bf8iqsQmf5IL
CRNyGcqotU/sQ8GgRIYHQevsMcqy9P7gZSwmxHWQAOzD3GriCs/MpHyMKOx7f73B
zcRmhRbvg3DaCSPz8OoREZQvQx7lH7StPy2qdStqPupBUCqoVa7zUJmoqp89w6/a
bDzvdAL20anjg5n6Yu67VODCjqa0IVKzEvbPXeclXSSC6e+Kbep87txJxYosUQ+V
w/T7SuTbz9bIAwIG1oE7bcDPV+zepsxHv4FVGQIDAQABAoIBAQDPzzc224yg+iHo
ZaArcOhFrGbPMiAYNLxrroTzcKglqbTr+txmn7lhDfy6Jq0O4l/O66fy59Vb4fcL
NgJuvKanK2UHVbtPrc1+iQc0lS7e4866aKrJNG9P6emoXNPqy6fsqLRx4o88IxcX
TIe2DDHC7lpu5KdvKa4uLblOSqPtcZTHXPD9olVe8ZYF5CttMUTc4SkF4HSkY2jb
0j+6kASN4eQ2CqEt+IW4IxI5NiEzrlzZSOdyqIOeyGUZz+QcfILOProWZHYzH3jO
HQe4PJSXO57f2dojY1GqRcjnr3guQMpw1s7wmDYO1QekiBYwRERNzjEY7VhgDq8T
0rwJPHP5AoGBAPO13QpJVSj1NfQ/H0AgZlsJIIlIwIC2YwuwjA7b36A3JOFolkHj
tq4eNntThNRQbTL9OficbxJSHXQcOsQeo7dvwEhJjuVwEajL4/6cjc9b4oyGJxLl
TKTshUPmeKPfGWUjRZKGbVWbT3m4BXqGiv4laCZ0LDHiCt4DvEzQ1Bo3AoGBAOet
BClbcbUJhxkAme5HHI9A5VcqyOi2CrRh+HjKd/2IJlDA+Vmbl2iEB+9cMRGRubaz
brk1yAzgtW29GX8kngr8yxDtIM8M7lPR2NhXx7XbmCKwKosZ7l6hHNdnD12TFyLC
juuJlUA37sWXw8r33623mLFQlNVjnL0onUa1XSMvAoGACw47+cR73YDKMstOQp11
pzmRxUiMmworEhOvNtlYmq8FuEgDUPfgiKOMOyn9w5fmbEK6h4GpND6PYX4KWG0/
ZgnmwiC8H8Jmuq6NKDa35Ck57MAFM8E9Kdok7YCeBmkPgNwJwuzgNtr1zwK/FODX
m1HdGKl6e8TSU2H9/8oVZR8CgYEAoHSWI0awNCCLLufZtMwPna/mpz58s6ARPel0
u8QO4st/LgLZMBSxArQfAsqpOW/iXgVcNG5pRXIEdiK4G/TyeM2onup9BKoCDo+S
ThRNv0h9z9iPPpQRIf0YCp/YZojPR0XU0pERi86xUqzP8C1I//neiUA0NK6vCdut
QiGuhgUCgYEAp89EFcM1WvtPRJE+md8N8BUef5MJ+JJ0nb+BW1kkLY50Q1MVmsVX
dUowYupWLBgEfMn8fy8Q+xD9EeiISTF9MtT1X4iQSI/pzKW5LLd0OJYnqPMWzygg
ASzSNWdYBIGNkqsQGmGCtF9+i6V4acfTTbMD9LiB7u5/enQa8N0Qg+s=
-----END RSA PRIVATE KEY-----

View File

@ -0,0 +1,4 @@
dependencies:
espressif/mbedtls_cxx:
version: "*"
override_path: "../.."

View File

@ -0,0 +1,17 @@
-----BEGIN CERTIFICATE-----
MIICwjCCAaoCFAWE4aJdYWbMJAaBTMxVpoXMrhzuMA0GCSqGSIb3DQEBCwUAMCEx
CzAJBgNVBAYTAkNaMRIwEAYDVQQDDAlFc3ByZXNzaWYwHhcNMjQwNDAzMDkxNTI3
WhcNMzQwNDAxMDkxNTI3WjAaMRgwFgYDVQQDDA9lc3ByZXNzaWYubG9jYWwwggEi
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDChMP2z+M0MSy4dNO64tuJoI37
lWBBFEmaRj7AkEQQ2opD36qJvgv17AU/S997vQvpmL3GLC0uIKNFvdUp0p7Zw4m0
UuPDU8NZTCUqjGJVV2advYzsCCRz3dlosX8z5JpN9GmxLsPjoy+jJskVU/ZCiUnv
Tipk86VZq9K2gHVGaghVk0qbo8QEorjPLk0w8KfYpSNjMV8XL3wMIWeUQ7ZzlRIg
fhFVv7QO7hCGq/h1lGeyMjszmajCmALp8DyzFggL0I6HKpqBGh7WD99Tndhl3qkL
3VFiNuNALKn+ZDW7xYseCLf2w3zxMYzNwsdgFCcOlYJ4cznx/OFFKPTybXc3AgMB
AAEwDQYJKoZIhvcNAQELBQADggEBAFD31VncaNRvs4T8fc9g8GtiHS4/f0fDzwQY
CFufm+I/J1V0NFQZtfhJEnjXu3c8CAlZx8texiJplZwMXhEsd2Qs2JkQ0i9/vlAs
ClhqR9+lPmCDISK2cQZL5gUwGE8JpGev3ty8LNxVEgTTxlSSM7IdVtVJVRpWSxCj
4zSIiozt0w4XwU240W+pDGEptnSh0CtXl8fPTQa3Zr3eepk4Io0z14+lDecYExhi
acgqAaEKLety0+EfApsR0IK/QWGnDECQMCZiduLOJhPhssE3Ybxr0bRcUOuS1ltY
63h/eVuaOxgcp+YMkIDaSuW/LBcl1p84ZQ3B+hrUTN5TztggCtU=
-----END CERTIFICATE-----

View File

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEAwoTD9s/jNDEsuHTTuuLbiaCN+5VgQRRJmkY+wJBEENqKQ9+q
ib4L9ewFP0vfe70L6Zi9xiwtLiCjRb3VKdKe2cOJtFLjw1PDWUwlKoxiVVdmnb2M
7Agkc93ZaLF/M+SaTfRpsS7D46MvoybJFVP2QolJ704qZPOlWavStoB1RmoIVZNK
m6PEBKK4zy5NMPCn2KUjYzFfFy98DCFnlEO2c5USIH4RVb+0Du4Qhqv4dZRnsjI7
M5mowpgC6fA8sxYIC9COhyqagRoe1g/fU53YZd6pC91RYjbjQCyp/mQ1u8WLHgi3
9sN88TGMzcLHYBQnDpWCeHM58fzhRSj08m13NwIDAQABAoIBAQCNJAqRDrzcRQYe
/V4YT71eOmprbzK9ZfwV/fxQex14YSpMH4G9mnFRSqVwDRymy0BWiibBIZLS0onF
8/008IekmNZVSoPLWf73z2F0YxKCu/1QXZZgOXRBwmqbJZeXzrsL71m1X6pxhRnu
txjW6epY0wcbpcrrH0MOMredBs6RfOBi55wpuXNPjEP1YchBNXem0OR/ai5I3hGG
5ifStVvMv/+2N1vwTTelz28YvXcKqQXpMFhbVxfkIPw5JVnNvcDAWuC5oOj+jWeX
p5lhBzFqtnRuNjiC81qSbv/R5zDLMtceewwRew9/yu4su0VUsn8frSqTqsUPtpqf
Wa7BQgjBAoGBAOgSLCF/BZmeiJwNlVw1Mk/uHrDgGqDzZzGbKUX1CTtIoWOqT/JA
yr4NFpMQq8imS/XAvZJ8HyvBlT+YScmews+4TTRr/4QoAo00q99c24g2k3y4gZ/r
ddD5LFwkyr/JUwGQbSyx4Vf9CnVhHbnibm8jnI033hq9f9oOBr5tSOlXAoGBANaT
WPQIzansIu7f9inVNGzVsZEzmSoKU9P/81HsVblfhySXA3elqIK4WKJzJlyyRWk/
bE5tSVdk04mMWpNBgWmz6rVvFRZMDRjlJVoumqJ6F5wKK/yGTshwWTixiR+gX3/q
PtJVWGcv8y8tlfZmuxjeJyQzz6GA/T/yU2717tUhAoGBAK5u2lTjEOaCztPdMeL4
6TRDGzZ/fAR2b55NrhwzLhktYoFzRlwkbz+ivtETuss6k+XIVbWBLjzJaNFAOlYd
yvgu43j/pDNFj4VrjbR6K1ibDQi19liptwi4AavQy8SUIpwOXsE1gteMDwxjTuCl
XbST49wRnhQjU7Im0NLZefBJAoGBALQcvOci2JeQegYvAi89IqNUgJdUS3Wpc5IZ
X0Hd8lsG36aMCEIPULJhUS0TIRlgHrlonl36iDyOiq4DnSfMLXfvqM0g7/9mWPwT
pFXdlrlZaKX3N9LhXhILlCjthR+B+4egtZjSQMFk02k/h4hr1RLbrtlJkDiN0IYz
v2r9jrthAoGANtSFvvDTpUi79RaXkUYID8OqXIdqujViaDeWGI+wVgE88b8JF8ac
XcMcHz1J6meebPsjmkcNLLrD3jWo7NyiKT1j2xeYg6c0JEEMGNG/pmmu7b0a/P+i
jcofvRHBh/yYZwodabhoSHHtWOI2d+w1L2ECx/iezQM0uMfaXCsZ6ak=
-----END RSA PRIVATE KEY-----

View File

@ -0,0 +1,51 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "mbedtls_wrap.hpp"
namespace test_certs {
using pem_format = const unsigned char;
extern pem_format cacert_start[] asm("_binary_ca_crt_start");
extern pem_format cacert_end[] asm("_binary_ca_crt_end");
extern pem_format clientcert_start[] asm("_binary_client_crt_start");
extern pem_format clientcert_end[] asm("_binary_client_crt_end");
extern pem_format clientkey_start[] asm("_binary_client_key_start");
extern pem_format clientkey_end[] asm("_binary_client_key_end");
extern pem_format servercert_start[] asm("_binary_srv_crt_start");
extern pem_format servercert_end[] asm("_binary_srv_crt_end");
extern pem_format serverkey_start[] asm("_binary_srv_key_start");
extern pem_format serverkey_end[] asm("_binary_srv_key_end");
enum class type {
cacert,
servercert,
serverkey,
clientcert,
clientkey
};
#define IF_BUF_TYPE(buf_type) \
if (t == type::buf_type) { \
return idf::mbedtls_cxx::const_buf{buf_type ## _start, buf_type ## _end - buf_type ## _start}; \
}
static inline idf::mbedtls_cxx::const_buf get_buf(type t)
{
IF_BUF_TYPE(cacert);
IF_BUF_TYPE(servercert);
IF_BUF_TYPE(serverkey);
IF_BUF_TYPE(clientcert);
IF_BUF_TYPE(clientkey);
return idf::mbedtls_cxx::const_buf{};
}
static inline const char *get_server_cn()
{
return "espressif.local";
}
}

View File

@ -0,0 +1,11 @@
# For more information about build system see
# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html
# The following five lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
if("${IDF_TARGET}" STREQUAL "linux")
list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/mocks/freertos/")
endif()
project(tls_client)

View File

@ -0,0 +1,4 @@
# TCP client example
This is a simple example uses `mbedtls_cxx` to connect to a remote echo server.
The example needs a connection to internet (or a network where the TLS echo-server is available), it could be run on linux target as well as on ESP32.

View File

@ -0,0 +1,2 @@
idf_component_register(SRCS "tls_client.cpp"
INCLUDE_DIRS ".")

View File

@ -0,0 +1,7 @@
dependencies:
idf: ">=5.0"
espressif/mbedtls_cxx:
version: "*"
override_path: "../../.."
protocol_examples_common:
path: ${IDF_PATH}/examples/common_components/protocol_examples_common

View File

@ -0,0 +1,152 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include "esp_log.h"
#include "mbedtls_wrap.hpp"
using namespace idf::mbedtls_cxx;
namespace {
constexpr auto *TAG = "simple_tls_client";
}
class TlsSocketClient: public Tls {
public:
TlsSocketClient() = default;
~TlsSocketClient() override
{
if (sock >= 0) {
::close(sock);
}
}
int send(const unsigned char *buf, size_t len) override
{
return ::send(sock, buf, len, 0);
}
int recv(unsigned char *buf, size_t len) override
{
return ::recv(sock, buf, len, 0);
}
bool connect(const char *host, int port)
{
addr_info addr(host, AF_INET, SOCK_STREAM);
if (!addr) {
ESP_LOGE(TAG, "Failed to resolve host");
return false;
}
sock = addr.get_sock();
if (sock < 0) {
ESP_LOGE(TAG, "Failed to create socket");
return false;
}
if (::connect(sock, addr.get_addr(port), sizeof(struct sockaddr)) < 0) {
ESP_LOGE(TAG, "Failed to connect %d", errno);
return false;
}
if (!init(is_server{false}, do_verify{false})) {
return false;
}
return handshake() == 0;
}
private:
int sock{-1};
/**
* RAII wrapper of the address_info
*/
struct addr_info {
struct addrinfo *ai {
nullptr
};
~addr_info()
{
freeaddrinfo(ai);
}
explicit addr_info(const char *host, int family, int type)
{
struct addrinfo hints {};
hints.ai_family = family;
hints.ai_socktype = type;
if (getaddrinfo(host, nullptr, &hints, &ai) < 0) {
freeaddrinfo(ai);
ai = nullptr;
}
}
explicit operator bool() const
{
return ai != nullptr;
}
struct sockaddr *get_addr(uint16_t port) const {
auto *p = (struct sockaddr_in *)ai->ai_addr;
p->sin_port = htons(port);
return (struct sockaddr *)p;
}
int get_sock() const
{
return socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
}
};
};
namespace {
void tls_client()
{
const unsigned char message[] = "Hello\n";
unsigned char reply[128];
TlsSocketClient client;
if (!client.connect("tcpbin.com", 4243)) {
ESP_LOGE(TAG, "Failed to connect! %d", errno);
return;
}
if (client.write(message, sizeof(message)) < 0) {
ESP_LOGE(TAG, "Failed to write!");
return;
}
int len = client.read(reply, sizeof(reply));
if (len < 0) {
ESP_LOGE(TAG, "Failed to read!");
return;
}
ESP_LOGI(TAG, "Successfully received: %.*s", len, reply);
}
} // namespace
#if CONFIG_IDF_TARGET_LINUX
/**
* Linux target: We're already connected, just run the client
*/
int main()
{
tls_client();
return 0;
}
#else
/**
* ESP32 chipsets: Need to initialize system components
* and connect to network
*/
#include "nvs_flash.h"
#include "esp_event.h"
#include "protocol_examples_common.h"
#include "esp_netif.h"
extern "C" void app_main()
{
ESP_ERROR_CHECK(nvs_flash_init());
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
ESP_ERROR_CHECK(example_connect());
tls_client();
}
#endif

View File

@ -0,0 +1 @@
CONFIG_ESP_MAIN_TASK_STACK_SIZE=8192

View File

@ -0,0 +1,11 @@
# For more information about build system see
# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html
# The following five lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
if("${IDF_TARGET}" STREQUAL "linux")
list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/mocks/freertos/")
endif()
project(udp_mutual)

View File

@ -0,0 +1,4 @@
# UDP Mutual authentication example
This example uses `mbedtls_cxx` to perform a DTLS handshake and exchange a message between server and client.
The example uses UDP sockets on `'localhost'` interface, so no actual connection is needed, it could be run on linux target as well as on ESP32.

View File

@ -0,0 +1,2 @@
idf_component_register(SRCS "udp_mutual.cpp"
INCLUDE_DIRS ".")

View File

@ -0,0 +1,8 @@
dependencies:
idf: ">=5.0"
espressif/mbedtls_cxx:
version: "*"
override_path: "../../.."
test_certs:
version: "*"
path: "../../test_certs"

View File

@ -0,0 +1,229 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <thread>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include "esp_log.h"
#include "mbedtls_wrap.hpp"
#include "test_certs.hpp"
namespace {
constexpr auto *TAG = "udp_example";
}
using namespace idf::mbedtls_cxx;
using namespace test_certs;
class SecureLink: public Tls {
public:
explicit SecureLink() : Tls(), addr("localhost", 3333, AF_INET, SOCK_DGRAM) {}
~SecureLink() override
{
if (sock >= 0) {
::close(sock);
}
}
int send(const unsigned char *buf, size_t len) override
{
return sendto(sock, buf, len, 0, addr, ai_size);
}
int recv(unsigned char *buf, size_t len) override
{
socklen_t socklen = sizeof(sockaddr);
return recvfrom(sock, buf, len, 0, addr, &socklen);
}
int recv_timeout(unsigned char *buf, size_t len, int timeout) override
{
struct timeval tv {
timeout / 1000, (timeout % 1000 ) * 1000
};
fd_set read_fds;
FD_ZERO( &read_fds );
FD_SET( sock, &read_fds );
int ret = select(sock + 1, &read_fds, nullptr, nullptr, timeout == 0 ? nullptr : &tv);
if (ret == 0) {
return MBEDTLS_ERR_SSL_TIMEOUT;
}
if (ret < 0) {
if (errno == EINTR) {
return MBEDTLS_ERR_SSL_WANT_READ;
}
return ret;
}
return recv(buf, len);
}
bool open(bool server_not_client)
{
if (!addr) {
ESP_LOGE(TAG, "Failed to resolve endpoint");
return false;
}
sock = addr.get_sock();
if (sock < 0) {
ESP_LOGE(TAG, "Failed to create socket");
return false;
}
TlsConfig config{};
config.is_dtls = true;
config.timeout = 10000;
if (server_not_client) {
int err = bind(sock, addr, ai_size);
if (err < 0) {
ESP_LOGE(TAG, "Socket unable to bind: errno %d", errno);
return false;
}
const unsigned char client_id[] = "localhost";
config.client_id = std::make_pair(client_id, sizeof(client_id));
}
if (!init(is_server{server_not_client}, do_verify{true}, &config)) {
return false;
}
return handshake() == 0;
}
private:
int sock{-1};
/**
* RAII wrapper of the address_info
*/
struct addr_info {
struct addrinfo *ai = nullptr;
explicit addr_info(const char *host, int port, int family, int type)
{
struct addrinfo hints {};
hints.ai_family = family;
hints.ai_socktype = type;
if (getaddrinfo(host, nullptr, &hints, &ai) < 0) {
freeaddrinfo(ai);
ai = nullptr;
}
auto *p = (struct sockaddr_in *)ai->ai_addr;
p->sin_port = htons(port);
}
~addr_info()
{
freeaddrinfo(ai);
}
explicit operator bool() const
{
return ai != nullptr;
}
operator sockaddr *() const
{
auto *p = (struct sockaddr_in *)ai->ai_addr;
return (struct sockaddr *)p;
}
int get_sock() const
{
return socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
}
} addr;
const int ai_size{sizeof(struct sockaddr_in)};
};
namespace {
void tls_client()
{
const unsigned char message[] = "Hello\n";
unsigned char reply[128];
SecureLink client;
client.set_hostname(get_server_cn());
if (!client.set_own_cert(get_buf(type::clientcert), get_buf(type::clientkey))) {
ESP_LOGE(TAG, "Failed to set own cert");
return;
}
if (!client.set_ca_cert(get_buf(type::cacert))) {
ESP_LOGE(TAG, "Failed to set peer's cert");
return;
}
if (!client.open(false)) {
ESP_LOGE(TAG, "Failed to CONNECT! %d", errno);
return;
}
ESP_LOGI(TAG, "client opened...");
if (client.write(message, sizeof(message)) < 0) {
ESP_LOGE(TAG, "Failed to write!");
return;
}
int len = client.read(reply, sizeof(reply));
if (len < 0) {
ESP_LOGE(TAG, "Failed to read!");
return;
}
ESP_LOGI(TAG, "Successfully received: %.*s", len, reply);
}
void tls_server()
{
unsigned char message[128];
SecureLink server;
if (!server.set_own_cert(get_buf(type::servercert), get_buf(type::serverkey))) {
ESP_LOGE(TAG, "Failed to set own cert");
return;
}
if (!server.set_ca_cert(get_buf(type::cacert))) {
ESP_LOGE(TAG, "Failed to set peer's cert");
return;
}
ESP_LOGI(TAG, "opening...");
if (!server.open(true)) {
ESP_LOGE(TAG, "Failed to OPEN! %d", errno);
return;
}
int len = server.read(message, sizeof(message));
if (len < 0) {
ESP_LOGE(TAG, "Failed to read!");
return;
}
ESP_LOGI(TAG, "Received from client: %.*s", len, message);
if (server.write(message, len) < 0) {
ESP_LOGE(TAG, "Failed to write!");
return;
}
ESP_LOGI(TAG, "Written back");
}
void udp_auth()
{
std::thread t2(tls_server);
std::thread t1(tls_client);
t1.join();
t2.join();
}
} // namespace
#if CONFIG_IDF_TARGET_LINUX
/**
* Linux target: We're already connected, just run the client
*/
int main()
{
udp_auth();
return 0;
}
#else
/**
* ESP32 chipsets: Need to initialize system components
* and connect to network
*/
#include "esp_event.h"
#include "esp_netif.h"
extern "C" void app_main()
{
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
udp_auth();
}
#endif

View File

@ -0,0 +1,2 @@
CONFIG_MBEDTLS_SSL_PROTO_DTLS=y
CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT=8192

View File

@ -0,0 +1,7 @@
version: 0.1.0
url: https://github.com/espressif/esp-protocols/tree/master/components/mbedtls_cxx
description: C++ wrapper of mbedtls to perform (D)TLS connection
license: Apache-2.0
dependencies:
idf:
version: '>=5.0'

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -7,34 +7,78 @@
#include <utility>
#include <memory>
#include <span>
#include <mbedtls/timing.h>
#include <mbedtls/ssl_cookie.h>
#include "mbedtls/ssl.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/error.h"
using const_buf = std::span<const unsigned char>;
namespace idf::mbedtls_cxx {
using const_buf = std::pair<const unsigned char *, std::size_t>;
using buf = std::pair<unsigned char *, std::size_t>;
struct TlsConfig {
bool is_dtls;
uint32_t timeout;
const_buf client_id;
};
/**
* @brief Application wrapper of (D)TLS for authentication and creating encrypted communication channels
*/
class Tls {
public:
enum class is_server : bool {};
enum class do_verify : bool {};
/**
* High level configs for this class are per below: (server/client, with/out verification, TLS/DTLS)
*/
enum class is_server : bool {
};
enum class do_verify : bool {
};
enum class is_dtls : bool {
};
Tls();
virtual ~Tls();
bool init(is_server server, do_verify verify);
bool init(is_server server, do_verify verify, TlsConfig *config = nullptr);
bool init_dtls_cookies();
bool set_client_id();
bool deinit();
int handshake();
int write(const unsigned char *buf, size_t len);
int read(unsigned char *buf, size_t len);
[[nodiscard]] bool set_own_cert(const_buf crt, const_buf key);
[[nodiscard]] bool set_ca_cert(const_buf crt);
bool set_hostname(const char *name);
virtual int send(const unsigned char *buf, size_t len) = 0;
virtual int recv(unsigned char *buf, size_t len) = 0;
virtual int recv_timeout(unsigned char *buf, size_t len, int timeout)
{
return recv(buf, len);
}
size_t get_available_bytes();
protected:
/**
* mbedTLS internal structures (available after inheritance)
*/
mbedtls_ssl_context ssl_{};
mbedtls_x509_crt public_cert_{};
mbedtls_pk_context pk_key_{};
@ -42,35 +86,56 @@ protected:
mbedtls_ssl_config conf_{};
mbedtls_ctr_drbg_context ctr_drbg_{};
mbedtls_entropy_context entropy_{};
mbedtls_timing_delay_context timer_{};
mbedtls_ssl_cookie_ctx cookie_{};
const_buf client_id_{};
virtual void delay() {}
bool is_server_{false};
bool is_dtls_{false};
bool set_session();
bool get_session();
void reset_session();
bool is_session_loaded();
private:
static void print_error(const char *function, int error_code);
static int bio_write(void *ctx, const unsigned char *buf, size_t len);
static int bio_read(void *ctx, unsigned char *buf, size_t len);
int mbedtls_pk_parse_key( mbedtls_pk_context *ctx,
const unsigned char *key, size_t keylen,
const unsigned char *pwd, size_t pwdlen);
static int bio_read_tout(void *ctx, unsigned char *buf, size_t len, uint32_t timeout);
int mbedtls_pk_parse_key(mbedtls_pk_context *ctx,
const unsigned char *key, size_t keylen,
const unsigned char *pwd, size_t pwdlen);
struct unique_session {
unique_session()
{
::mbedtls_ssl_session_init(&s);
}
~unique_session()
{
::mbedtls_ssl_session_free(&s);
}
mbedtls_ssl_session *ptr()
{
return &s;
}
mbedtls_ssl_session s;
};
std::unique_ptr<unique_session> session_;
};
}

View File

@ -1,23 +1,34 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <mbedtls/timing.h>
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/ssl.h"
#include "mbedtls_wrap.hpp"
bool Tls::init(is_server server, do_verify verify)
using namespace idf::mbedtls_cxx;
bool Tls::init(is_server server, do_verify verify, TlsConfig *config)
{
const char pers[] = "mbedtls_wrapper";
is_server_ = server == is_server{true};
is_dtls_ = config ? config->is_dtls : false;
uint32_t timeout = config ? config->timeout : 0;
mbedtls_entropy_init(&entropy_);
mbedtls_ctr_drbg_seed(&ctr_drbg_, mbedtls_entropy_func, &entropy_, (const unsigned char *)pers, sizeof(pers));
int ret = mbedtls_ssl_config_defaults(&conf_, server == is_server{true} ? MBEDTLS_SSL_IS_SERVER : MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT);
int endpoint = server == is_server{true} ? MBEDTLS_SSL_IS_SERVER : MBEDTLS_SSL_IS_CLIENT;
int transport = is_dtls_ ? MBEDTLS_SSL_TRANSPORT_DATAGRAM : MBEDTLS_SSL_TRANSPORT_STREAM;
int ret = mbedtls_ssl_config_defaults(&conf_, endpoint, transport, MBEDTLS_SSL_PRESET_DEFAULT);
if (ret) {
print_error("mbedtls_ssl_config_defaults", ret);
return false;
}
mbedtls_ssl_conf_rng(&conf_, mbedtls_ctr_drbg_random, &ctr_drbg_);
if (timeout) {
mbedtls_ssl_conf_read_timeout(&conf_, timeout);
}
mbedtls_ssl_conf_authmode(&conf_, verify == do_verify{true} ? MBEDTLS_SSL_VERIFY_REQUIRED : MBEDTLS_SSL_VERIFY_NONE);
ret = mbedtls_ssl_conf_own_cert(&conf_, &public_cert_, &pk_key_);
if (ret) {
@ -27,11 +38,34 @@ bool Tls::init(is_server server, do_verify verify)
if (verify == do_verify{true}) {
mbedtls_ssl_conf_ca_chain(&conf_, &ca_cert_, nullptr);
}
#if CONFIG_MBEDTLS_SSL_PROTO_DTLS
if (is_server_ && is_dtls_) {
if (!init_dtls_cookies()) {
return false;
}
}
#endif // MBEDTLS_SSL_PROTO_DTLS
ret = mbedtls_ssl_setup(&ssl_, &conf_);
if (ret) {
print_error("mbedtls_ssl_setup", ret);
return false;
}
if (timeout) {
mbedtls_ssl_set_timer_cb(&ssl_, &timer_, mbedtls_timing_set_delay, mbedtls_timing_get_delay);
}
#if CONFIG_MBEDTLS_SSL_PROTO_DTLS
if (is_server_ && is_dtls_ && config && config->client_id != const_buf {}) {
client_id_ = config->client_id;
if (!set_client_id()) {
return false;
}
}
#endif // MBEDTLS_SSL_PROTO_DTLS
return true;
}
@ -57,10 +91,19 @@ void Tls::print_error(const char *function, int error_code)
int Tls::handshake()
{
int ret = 0;
mbedtls_ssl_set_bio(&ssl_, this, bio_write, bio_read, nullptr);
mbedtls_ssl_set_bio(&ssl_, this, bio_write, bio_read, is_dtls_ ? bio_read_tout : nullptr);
while ( ( ret = mbedtls_ssl_handshake( &ssl_ ) ) != 0 ) {
if ( ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE ) {
#if CONFIG_MBEDTLS_SSL_PROTO_DTLS
if (is_server_ && is_dtls_ && ret == MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED) {
// hello verification requested -> restart the session with this client_id
if (!set_client_id()) {
return -1;
}
continue;
}
#endif // MBEDTLS_SSL_PROTO_DTLS
print_error( "mbedtls_ssl_handshake returned", ret );
return -1;
}
@ -81,6 +124,12 @@ int Tls::bio_read(void *ctx, unsigned char *buf, size_t len)
return s->recv(buf, len);
}
int Tls::bio_read_tout(void *ctx, unsigned char *buf, size_t len, uint32_t timeout)
{
auto s = static_cast<Tls *>(ctx);
return s->recv_timeout(buf, len, timeout);
}
int Tls::write(const unsigned char *buf, size_t len)
{
return mbedtls_ssl_write( &ssl_, buf, len );
@ -93,12 +142,12 @@ int Tls::read(unsigned char *buf, size_t len)
bool Tls::set_own_cert(const_buf crt, const_buf key)
{
int ret = mbedtls_x509_crt_parse(&public_cert_, crt.data(), crt.size());
int ret = mbedtls_x509_crt_parse(&public_cert_, crt.first, crt.second);
if (ret < 0) {
print_error("mbedtls_x509_crt_parse", ret);
return false;
}
ret = mbedtls_pk_parse_key(&pk_key_, key.data(), key.size(), nullptr, 0);
ret = mbedtls_pk_parse_key(&pk_key_, key.first, key.second, nullptr, 0);
if (ret < 0) {
print_error("mbedtls_pk_parse_keyfile", ret);
return false;
@ -108,7 +157,7 @@ bool Tls::set_own_cert(const_buf crt, const_buf key)
bool Tls::set_ca_cert(const_buf crt)
{
int ret = mbedtls_x509_crt_parse(&ca_cert_, crt.data(), crt.size());
int ret = mbedtls_x509_crt_parse(&ca_cert_, crt.first, crt.second);
if (ret < 0) {
print_error("mbedtls_x509_crt_parse", ret);
return false;
@ -188,3 +237,32 @@ bool Tls::is_session_loaded()
{
return session_ != nullptr;
}
#if CONFIG_MBEDTLS_SSL_PROTO_DTLS
bool Tls::init_dtls_cookies()
{
int ret = mbedtls_ssl_cookie_setup(&cookie_, mbedtls_ctr_drbg_random, &ctr_drbg_);
if (ret != 0) {
print_error("mbedtls_ssl_cookie_setup() failed", ret);
return false;
}
mbedtls_ssl_conf_dtls_cookies(&conf_, mbedtls_ssl_cookie_write, mbedtls_ssl_cookie_check, &cookie_);
return true;
}
bool Tls::set_client_id()
{
int ret;
if (client_id_ == const_buf{}) {
printf("client_id is not set");
return false;
}
mbedtls_ssl_session_reset(&ssl_);
if ((ret = mbedtls_ssl_set_client_transport_id(&ssl_, client_id_.first, client_id_.second)) != 0) {
print_error("mbedtls_ssl_set_client_transport_id()", ret);
return false;
}
return true;
}
#endif

View File

@ -0,0 +1,8 @@
# For more information about build system see
# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html
# The following five lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(uart_mutual)

View File

@ -0,0 +1,17 @@
# UART mutual authentication test
This test creates a (D)TLS server and a client on one device and checks if they can perform a TLS handshake and exchange a message.
The test uses UART as the physical layer of communication channel and, since it runs on a single ESP32, it expects two UART ports interconnected as per below:
```
+------------------------+
| ESP32 |
| |
| UART-1 UART-2 |
+---25---26------4---5---+
| | | |
| +-------+ |
+----------------+
```
The test runs in two configurations: TLS and DTLS.

View File

@ -0,0 +1,2 @@
idf_component_register(SRCS "uart_mutual.cpp"
INCLUDE_DIRS ".")

View File

@ -0,0 +1,19 @@
menu "Test Configuration"
choice TEST_CONNECTION_METHOD
prompt "Choose connection method"
default TEST_TLS
help
Select type of connection. Either TLS or DTLS
config TEST_TLS
bool "TLS"
help
Use TLS method.
config TEST_DTLS
bool "DTLS"
help
Use DTLS method.
endchoice # TEST_CONNECTION_METHOD
endmenu

View File

@ -0,0 +1,8 @@
dependencies:
idf: ">=5.0"
espressif/mbedtls_cxx:
version: "*"
override_path: "../../.."
test_certs:
version: "*"
path: "../../../examples/test_certs"

View File

@ -0,0 +1,282 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <thread>
#include <sys/socket.h>
#include <unistd.h>
#include <esp_check.h>
#include "esp_log.h"
#include "mbedtls_wrap.hpp"
#include "driver/uart.h"
#include "esp_event.h"
#include "esp_netif.h"
#include "test_certs.hpp"
namespace {
constexpr auto *TAG = "uart_mutual_tls";
/**
* Using DTLS the below is set to true.
* In that case, we need to receive the entire datagram, not a fragment
* This defines a very simple datagram protocol over UART:
* | HEADER (2bytes) | PAYLOAD ... |
* | dgram_len | dgram_payload |
*
* If `use_dgrams` is set to false, we perform TLS on UART stream.
* The UART driver is already a stream-like API (using ringbufer), so we simple read and write to UART
*/
#if CONFIG_TEST_TLS
const bool use_dgrams = false;
#elif CONFIG_TEST_DTLS
const bool use_dgrams = true;
#endif
}
using namespace idf::mbedtls_cxx;
using namespace test_certs;
class SecureLink: public Tls {
public:
explicit SecureLink(uart_port_t port, int tx, int rx) : Tls(), uart(port, tx, rx) {}
~SecureLink() = default;
int send(const unsigned char *buf, size_t len) override
{
if (use_dgrams) {
// sends a separate dgram header
uint16_t header = len;
uart_write_bytes(uart.port_, &header, 2);
}
return uart_write_bytes(uart.port_, buf, len);
}
int recv(unsigned char *buf, size_t len) override
{
// stream read
return uart.recv(buf, len, 0);
}
int recv_timeout(unsigned char *buf, size_t len, int timeout) override
{
// dgram read
return uart.recv_dgram(buf, len, timeout);
}
bool listen() // open as server
{
return open(true);
}
bool connect() // open as client
{
return open(false);
}
private:
bool open(bool server_not_client)
{
if (uart.init() != ESP_OK) {
return false;
}
while (!uart.debounce(server_not_client)) {
printf("debouncing...\n");
usleep(10000);
}
TlsConfig config{};
config.is_dtls = use_dgrams;
config.timeout = 10000;
if (server_not_client) {
const unsigned char client_id[] = "Client1";
config.client_id = std::make_pair(client_id, sizeof(client_id));
}
if (!init(is_server{server_not_client}, do_verify{true}, &config)) {
return false;
}
return handshake() == 0;
}
/**
* RAII wrapper of UART
*/
struct uart_info {
uart_port_t port_;
QueueHandle_t queue_{};
int tx_, rx_;
// used for datagrams
bool header_{true};
int in_payload_{0};
int payload_len_{0};
uint8_t payload_[1600] {};
explicit uart_info(uart_port_t port, int tx, int rx): port_(port), tx_(tx), rx_(rx)
{
}
esp_err_t init()
{
uart_config_t uart_config = {};
uart_config.baud_rate = 115200;
uart_config.data_bits = UART_DATA_8_BITS;
uart_config.parity = UART_PARITY_DISABLE;
uart_config.stop_bits = UART_STOP_BITS_1;
uart_config.flow_ctrl = UART_HW_FLOWCTRL_DISABLE;
uart_config.source_clk = UART_SCLK_DEFAULT;
ESP_RETURN_ON_ERROR(uart_driver_install(port_, 1024, 0, 1, &queue_, 0), TAG, "Failed to install UART");
ESP_RETURN_ON_ERROR(uart_param_config(port_, &uart_config), TAG, "Failed to set params");
ESP_RETURN_ON_ERROR(uart_set_pin(port_, tx_, rx_, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE), TAG, "Failed to set UART pins");
ESP_RETURN_ON_ERROR(uart_set_rx_timeout(port_, 10), TAG, "Failed to set UART Rx timeout");
return ESP_OK;
}
~uart_info()
{
uart_driver_delete(port_);
}
bool debounce(bool server)
{
uint8_t data = 0;
if (server) {
while (uart_read_bytes(port_, &data, 1, 0) != 0) {
if (data == 0x55) {
uart_write_bytes(port_, &data, 1);
return true;
}
}
return false;
}
data = 0x55;
uart_write_bytes(port_, &data, 1);
data = 0;
uart_read_bytes(port_, &data, 1, pdMS_TO_TICKS(1000));
if (data != 0x55) {
uart_flush_input(port_);
return false;
}
return true;
}
int recv(unsigned char *buf, size_t size, int timeout) // this is for stream transport
{
int len = uart_read_bytes(port_, buf, size, pdMS_TO_TICKS(timeout));
if (len == 0) {
return MBEDTLS_ERR_SSL_WANT_READ;
}
return len;
}
int recv_dgram(unsigned char *buf, size_t size, int timeout) // this is for datagrams
{
uart_event_t event = {};
size_t length;
uart_get_buffered_data_len(port_, &length);
if (length == 0) {
xQueueReceive(queue_, &event, pdMS_TO_TICKS(timeout));
}
uart_get_buffered_data_len(port_, &length);
if (length == 0) {
return MBEDTLS_ERR_SSL_WANT_READ;
}
if (header_) {
if (length >= 2) {
uart_read_bytes(port_, &payload_len_, 2, 0);
header_ = false;
length -= 2;
}
}
if (!header_ && length > 0) {
int to_read = payload_len_ - in_payload_;
int l = uart_read_bytes(port_, &payload_[in_payload_], to_read, 0);
in_payload_ += l;
if (payload_len_ == in_payload_) {
header_ = true;
memcpy(buf, payload_, payload_len_);
in_payload_ = 0;
return payload_len_;
}
}
return MBEDTLS_ERR_SSL_WANT_READ;
}
} uart;
};
namespace {
void tls_client()
{
const unsigned char message[] = "Hello\n";
unsigned char reply[128];
SecureLink client(UART_NUM_2, 4, 5);
client.set_hostname(get_server_cn());
if (!client.set_own_cert(get_buf(type::clientcert), get_buf(type::clientkey))) {
ESP_LOGE(TAG, "Failed to set own cert");
return;
}
if (!client.set_ca_cert(get_buf(type::cacert))) {
ESP_LOGE(TAG, "Failed to set peer's cert");
return;
}
if (!client.connect()) {
ESP_LOGE(TAG, "Failed to CONNECT! %d", errno);
return;
}
ESP_LOGI(TAG, "client opened...");
if (client.write(message, sizeof(message)) < 0) {
ESP_LOGE(TAG, "Failed to write!");
return;
}
int len;
while ((len = client.read(reply, sizeof(reply))) == MBEDTLS_ERR_SSL_WANT_READ) {
vTaskDelay(pdMS_TO_TICKS(500));
}
if (len < 0) {
ESP_LOGE(TAG, "Failed to read!");
return;
}
ESP_LOGI(TAG, "Successfully received: %.*s", len, reply);
}
void tls_server()
{
unsigned char message[128];
SecureLink server(UART_NUM_1, 25, 26);
if (!server.set_own_cert(get_buf(type::servercert), get_buf(type::serverkey))) {
ESP_LOGE(TAG, "Failed to set own cert");
return;
}
if (!server.set_ca_cert(get_buf(type::cacert))) {
ESP_LOGE(TAG, "Failed to set peer's cert");
return;
}
ESP_LOGI(TAG, "openning...");
if (!server.listen()) {
ESP_LOGE(TAG, "Failed to OPEN! %d", errno);
return;
}
int len;
while ((len = server.read(message, sizeof(message))) == MBEDTLS_ERR_SSL_WANT_READ) {
vTaskDelay(pdMS_TO_TICKS(500));
}
if (len < 0) {
ESP_LOGE(TAG, "Failed to read! %x", -len);
return;
}
ESP_LOGI(TAG, "Received from client: %.*s", len, message);
if (server.write(message, len) < 0) {
ESP_LOGE(TAG, "Failed to write!");
return;
}
ESP_LOGI(TAG, "Written back");
vTaskDelay(pdMS_TO_TICKS(500));
}
} // namespace
extern "C" void app_main()
{
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
std::thread t2(tls_server);
std::thread t1(tls_client);
t1.join();
t2.join();
}

Some files were not shown because too many files have changed in this diff Show More