diff --git a/.github/workflows/wifi_remote__build.yml b/.github/workflows/wifi_remote__build.yml index 0309273db..e2d096e01 100644 --- a/.github/workflows/wifi_remote__build.yml +++ b/.github/workflows/wifi_remote__build.yml @@ -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 diff --git a/components/esp_wifi_remote/.cz.yaml b/components/esp_wifi_remote/.cz.yaml index 8bc23f2aa..4cbf53c2b 100644 --- a/components/esp_wifi_remote/.cz.yaml +++ b/components/esp_wifi_remote/.cz.yaml @@ -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 diff --git a/components/esp_wifi_remote/CHANGELOG.md b/components/esp_wifi_remote/CHANGELOG.md index 414e56c2e..2d49bd147 100644 --- a/components/esp_wifi_remote/CHANGELOG.md +++ b/components/esp_wifi_remote/CHANGELOG.md @@ -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 diff --git a/components/esp_wifi_remote/CMakeLists.txt b/components/esp_wifi_remote/CMakeLists.txt index 577a37e00..e8460c874 100644 --- a/components/esp_wifi_remote/CMakeLists.txt +++ b/components/esp_wifi_remote/CMakeLists.txt @@ -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}) diff --git a/components/esp_wifi_remote/Kconfig b/components/esp_wifi_remote/Kconfig index c59c60db7..918e11bfa 100644 --- a/components/esp_wifi_remote/Kconfig +++ b/components/esp_wifi_remote/Kconfig @@ -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. diff --git a/components/esp_wifi_remote/Kconfig.rpc.in b/components/esp_wifi_remote/Kconfig.rpc.in new file mode 100644 index 000000000..d63530ab7 --- /dev/null +++ b/components/esp_wifi_remote/Kconfig.rpc.in @@ -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 diff --git a/components/esp_wifi_remote/Kconfig.soc_wifi_caps.in b/components/esp_wifi_remote/Kconfig.soc_wifi_caps.in index a0aee080a..1ec5de2b2 100644 --- a/components/esp_wifi_remote/Kconfig.soc_wifi_caps.in +++ b/components/esp_wifi_remote/Kconfig.soc_wifi_caps.in @@ -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 diff --git a/components/esp_wifi_remote/eppp/eppp_init.c b/components/esp_wifi_remote/eppp/eppp_init.c new file mode 100644 index 000000000..9c22eb2f3 --- /dev/null +++ b/components/esp_wifi_remote/eppp/eppp_init.c @@ -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); +} diff --git a/components/esp_wifi_remote/eppp/wifi_remote_rpc_client.cpp b/components/esp_wifi_remote/eppp/wifi_remote_rpc_client.cpp new file mode 100644 index 000000000..c287cc167 --- /dev/null +++ b/components/esp_wifi_remote/eppp/wifi_remote_rpc_client.cpp @@ -0,0 +1,297 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#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 + 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(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 + T get_resp(api_id id) + { + sync.wait_for(sync.resp_header); + auto ret = rpc.template get_payload(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(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(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(header.id)); + return ESP_FAIL; + + } + static void task(void *ctx) + { + auto instance = static_cast(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(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 lock(instance.sync); + ESP_RETURN_ON_ERROR(instance.send(api_id::INIT, config), TAG, "Failed to send request"); + return instance.get_resp(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(¶ms.conf, conf, sizeof(wifi_config_t)); + std::lock_guard lock(instance.sync); + ESP_RETURN_ON_ERROR(instance.send(api_id::SET_CONFIG, ¶ms), TAG, "Failed to send request"); + return instance.get_resp(api_id::SET_CONFIG); +} + +extern "C" esp_err_t esp_wifi_remote_start(void) +{ + std::lock_guard lock(instance.sync); + ESP_RETURN_ON_ERROR(instance.send(api_id::START), TAG, "Failed to send request"); + return instance.get_resp(api_id::START); +} + +extern "C" esp_err_t esp_wifi_remote_stop(void) +{ + std::lock_guard lock(instance.sync); + ESP_RETURN_ON_ERROR(instance.send(api_id::STOP), TAG, "Failed to send request"); + return instance.get_resp(api_id::STOP); +} + +extern "C" esp_err_t esp_wifi_remote_connect(void) +{ + std::lock_guard lock(instance.sync); + ESP_RETURN_ON_ERROR(instance.send(api_id::CONNECT), TAG, "Failed to send request"); + return instance.get_resp(api_id::CONNECT); +} + +extern "C" esp_err_t esp_wifi_remote_get_mac(wifi_interface_t ifx, uint8_t mac[6]) +{ + std::lock_guard lock(instance.sync); + ESP_RETURN_ON_ERROR(instance.send(api_id::GET_MAC, &ifx), TAG, "Failed to send request"); + auto ret = instance.get_resp(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 lock(instance.sync); + ESP_RETURN_ON_ERROR(instance.send(api_id::SET_MODE, &mode), TAG, "Failed to send request"); + return instance.get_resp(api_id::SET_MODE); +} diff --git a/components/esp_wifi_remote/eppp/wifi_remote_rpc_impl.hpp b/components/esp_wifi_remote/eppp/wifi_remote_rpc_impl.hpp new file mode 100644 index 000000000..30a0104db --- /dev/null +++ b/components/esp_wifi_remote/eppp/wifi_remote_rpc_impl.hpp @@ -0,0 +1,167 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once +#include +#include + +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 +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 + esp_err_t send(api_id id, T *t) + { + RpcData 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 + T get_payload(api_id id, RpcHeader &head) + { + RpcData 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}; +}; + +}; diff --git a/components/esp_wifi_remote/eppp/wifi_remote_rpc_params.h b/components/esp_wifi_remote/eppp/wifi_remote_rpc_params.h new file mode 100644 index 000000000..402308fab --- /dev/null +++ b/components/esp_wifi_remote/eppp/wifi_remote_rpc_params.h @@ -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; +}; diff --git a/components/esp_wifi_remote/eppp/wifi_remote_rpc_server.cpp b/components/esp_wifi_remote/eppp/wifi_remote_rpc_server.cpp new file mode 100644 index 000000000..0a8645d95 --- /dev/null +++ b/components/esp_wifi_remote/eppp/wifi_remote_rpc_server.cpp @@ -0,0 +1,210 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include +#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(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(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(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(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(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(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(); +} diff --git a/components/esp_wifi_remote/esp_wifi_remote_weak.c b/components/esp_wifi_remote/esp_wifi_remote_weak.c index 3bee295c0..e78732119 100644 --- a/components/esp_wifi_remote/esp_wifi_remote_weak.c +++ b/components/esp_wifi_remote/esp_wifi_remote_weak.c @@ -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); diff --git a/components/esp_wifi_remote/esp_wifi_with_remote.c b/components/esp_wifi_remote/esp_wifi_with_remote.c index 66b202fc9..c78aaf966 100644 --- a/components/esp_wifi_remote/esp_wifi_with_remote.c +++ b/components/esp_wifi_remote/esp_wifi_with_remote.c @@ -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); diff --git a/components/esp_wifi_remote/examples/mqtt/CMakeLists.txt b/components/esp_wifi_remote/examples/mqtt/CMakeLists.txt new file mode 100644 index 000000000..500c42d77 --- /dev/null +++ b/components/esp_wifi_remote/examples/mqtt/CMakeLists.txt @@ -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) diff --git a/components/esp_wifi_remote/examples/mqtt/README.md b/components/esp_wifi_remote/examples/mqtt/README.md new file mode 100644 index 000000000..0c81f4e21 --- /dev/null +++ b/components/esp_wifi_remote/examples/mqtt/README.md @@ -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. diff --git a/components/esp_wifi_remote/examples/mqtt/main/CMakeLists.txt b/components/esp_wifi_remote/examples/mqtt/main/CMakeLists.txt new file mode 100644 index 000000000..d6e9824b8 --- /dev/null +++ b/components/esp_wifi_remote/examples/mqtt/main/CMakeLists.txt @@ -0,0 +1,4 @@ +idf_component_register(SRCS "app_main.c" + INCLUDE_DIRS ".") + +target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format") diff --git a/components/esp_wifi_remote/examples/mqtt/main/Kconfig.projbuild b/components/esp_wifi_remote/examples/mqtt/main/Kconfig.projbuild new file mode 100644 index 000000000..7ad4dc25e --- /dev/null +++ b/components/esp_wifi_remote/examples/mqtt/main/Kconfig.projbuild @@ -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 diff --git a/components/esp_wifi_remote/examples/mqtt/main/app_main.c b/components/esp_wifi_remote/examples/mqtt/main/app_main.c new file mode 100644 index 000000000..07b60abdf --- /dev/null +++ b/components/esp_wifi_remote/examples/mqtt/main/app_main.c @@ -0,0 +1,204 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ +#include +#include +#include +#include +#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(); +} diff --git a/components/esp_wifi_remote/examples/mqtt/main/idf_component.yml b/components/esp_wifi_remote/examples/mqtt/main/idf_component.yml new file mode 100644 index 000000000..22d411780 --- /dev/null +++ b/components/esp_wifi_remote/examples/mqtt/main/idf_component.yml @@ -0,0 +1,5 @@ +dependencies: + espressif/eppp_link: "^0.0.1" + esp_wifi_remote: + version: "*" + override_path: ../../.. diff --git a/components/esp_wifi_remote/examples/mqtt/sdkconfig.ci.p4 b/components/esp_wifi_remote/examples/mqtt/sdkconfig.ci.p4 new file mode 100644 index 000000000..8ca2fb7ae --- /dev/null +++ b/components/esp_wifi_remote/examples/mqtt/sdkconfig.ci.p4 @@ -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=" diff --git a/components/esp_wifi_remote/examples/mqtt/sdkconfig.defaults b/components/esp_wifi_remote/examples/mqtt/sdkconfig.defaults new file mode 100644 index 000000000..2e93e03bb --- /dev/null +++ b/components/esp_wifi_remote/examples/mqtt/sdkconfig.defaults @@ -0,0 +1,3 @@ +CONFIG_LWIP_PPP_SUPPORT=y +CONFIG_LWIP_PPP_SERVER_SUPPORT=y +CONFIG_LWIP_PPP_VJ_HEADER_COMPRESSION=n diff --git a/components/esp_wifi_remote/examples/server/CMakeLists.txt b/components/esp_wifi_remote/examples/server/CMakeLists.txt new file mode 100644 index 000000000..144b9e1a2 --- /dev/null +++ b/components/esp_wifi_remote/examples/server/CMakeLists.txt @@ -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) diff --git a/components/esp_wifi_remote/examples/server/README.md b/components/esp_wifi_remote/examples/server/README.md new file mode 100644 index 000000000..f6e63d99b --- /dev/null +++ b/components/esp_wifi_remote/examples/server/README.md @@ -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 diff --git a/components/esp_wifi_remote/examples/server/main/CMakeLists.txt b/components/esp_wifi_remote/examples/server/main/CMakeLists.txt new file mode 100644 index 000000000..2ba044442 --- /dev/null +++ b/components/esp_wifi_remote/examples/server/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "station_example_main.c" + INCLUDE_DIRS ".") diff --git a/components/esp_wifi_remote/examples/server/main/idf_component.yml b/components/esp_wifi_remote/examples/server/main/idf_component.yml new file mode 100644 index 000000000..22d411780 --- /dev/null +++ b/components/esp_wifi_remote/examples/server/main/idf_component.yml @@ -0,0 +1,5 @@ +dependencies: + espressif/eppp_link: "^0.0.1" + esp_wifi_remote: + version: "*" + override_path: ../../.. diff --git a/components/esp_wifi_remote/examples/server/main/station_example_main.c b/components/esp_wifi_remote/examples/server/main/station_example_main.c new file mode 100644 index 000000000..93516d3ca --- /dev/null +++ b/components/esp_wifi_remote/examples/server/main/station_example_main.c @@ -0,0 +1,36 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ + +#include +#include +#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(); +} diff --git a/components/esp_wifi_remote/examples/server/sdkconfig.ci.c6 b/components/esp_wifi_remote/examples/server/sdkconfig.ci.c6 new file mode 100644 index 000000000..58f71a366 --- /dev/null +++ b/components/esp_wifi_remote/examples/server/sdkconfig.ci.c6 @@ -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" diff --git a/components/esp_wifi_remote/examples/server/sdkconfig.defaults b/components/esp_wifi_remote/examples/server/sdkconfig.defaults new file mode 100644 index 000000000..f2afde685 --- /dev/null +++ b/components/esp_wifi_remote/examples/server/sdkconfig.defaults @@ -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 diff --git a/components/esp_wifi_remote/examples/test_certs/generate_test_certs.sh b/components/esp_wifi_remote/examples/test_certs/generate_test_certs.sh new file mode 100755 index 000000000..e67249016 --- /dev/null +++ b/components/esp_wifi_remote/examples/test_certs/generate_test_certs.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash + +if [ -z "$1" ]; then + echo "Usage $0 [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\"" diff --git a/components/esp_wifi_remote/idf_component.yml b/components/esp_wifi_remote/idf_component.yml index 8ef35fc4a..8073e5b5e 100644 --- a/components/esp_wifi_remote/idf_component.yml +++ b/components/esp_wifi_remote/idf_component.yml @@ -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: '*' diff --git a/components/esp_wifi_remote/include/esp_wifi_remote_api.h b/components/esp_wifi_remote/include/esp_wifi_remote_api.h index 420aa5e7e..2ddcd7ee2 100644 --- a/components/esp_wifi_remote/include/esp_wifi_remote_api.h +++ b/components/esp_wifi_remote/include/esp_wifi_remote_api.h @@ -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); diff --git a/components/esp_wifi_remote/scripts/generate_and_check.py b/components/esp_wifi_remote/scripts/generate_and_check.py index c8df5b31a..37ac30762 100644 --- a/components/esp_wifi_remote/scripts/generate_and_check.py +++ b/components/esp_wifi_remote/scripts/generate_and_check.py @@ -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] diff --git a/components/esp_wifi_remote/test/smoke_test/components/esp_hosted/Kconfig b/components/esp_wifi_remote/test/smoke_test/components/esp_hosted/Kconfig index 48b4ed62e..e3e075afd 100644 --- a/components/esp_wifi_remote/test/smoke_test/components/esp_hosted/Kconfig +++ b/components/esp_wifi_remote/test/smoke_test/components/esp_hosted/Kconfig @@ -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 diff --git a/components/esp_wifi_remote/test/smoke_test/components/esp_hosted/esp_hosted_mock.c b/components/esp_wifi_remote/test/smoke_test/components/esp_hosted/esp_hosted_mock.c index 6ae190a66..117d4a0da 100644 --- a/components/esp_wifi_remote/test/smoke_test/components/esp_hosted/esp_hosted_mock.c +++ b/components/esp_wifi_remote/test/smoke_test/components/esp_hosted/esp_hosted_mock.c @@ -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; diff --git a/components/esp_wifi_remote/test/smoke_test/components/esp_hosted/include/esp_hosted_mock.h b/components/esp_wifi_remote/test/smoke_test/components/esp_hosted/include/esp_hosted_mock.h index 420aa5e7e..2ddcd7ee2 100644 --- a/components/esp_wifi_remote/test/smoke_test/components/esp_hosted/include/esp_hosted_mock.h +++ b/components/esp_wifi_remote/test/smoke_test/components/esp_hosted/include/esp_hosted_mock.h @@ -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); diff --git a/components/esp_wifi_remote/test/smoke_test/main/all_wifi_calls.c b/components/esp_wifi_remote/test/smoke_test/main/all_wifi_calls.c index 196c4df3e..78ce3f592 100644 --- a/components/esp_wifi_remote/test/smoke_test/main/all_wifi_calls.c +++ b/components/esp_wifi_remote/test/smoke_test/main/all_wifi_calls.c @@ -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); diff --git a/components/esp_wifi_remote/test/smoke_test/main/all_wifi_remote_calls.c b/components/esp_wifi_remote/test/smoke_test/main/all_wifi_remote_calls.c index 9b49393da..fd2bea18f 100644 --- a/components/esp_wifi_remote/test/smoke_test/main/all_wifi_remote_calls.c +++ b/components/esp_wifi_remote/test/smoke_test/main/all_wifi_remote_calls.c @@ -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); diff --git a/components/esp_wifi_remote/test/smoke_test/main/idf_component.yml b/components/esp_wifi_remote/test/smoke_test/main/idf_component.yml index ecffade56..cb6183a90 100644 --- a/components/esp_wifi_remote/test/smoke_test/main/idf_component.yml +++ b/components/esp_wifi_remote/test/smoke_test/main/idf_component.yml @@ -2,7 +2,7 @@ dependencies: ## Required IDF version idf: - version: "5.3" + version: '>=5.3' espressif/esp_wifi_remote: version: "*" override_path: ../../.. diff --git a/components/esp_wifi_remote/test/smoke_test/sdkconfig.defaults b/components/esp_wifi_remote/test/smoke_test/sdkconfig.defaults new file mode 100644 index 000000000..1f717cf36 --- /dev/null +++ b/components/esp_wifi_remote/test/smoke_test/sdkconfig.defaults @@ -0,0 +1,2 @@ +CONFIG_LWIP_PPP_SUPPORT=y +CONFIG_LWIP_PPP_SERVER_SUPPORT=y diff --git a/components/esp_wifi_remote/wifi_apps/roaming_app/src/Kconfig.roaming b/components/esp_wifi_remote/wifi_apps/roaming_app/src/Kconfig.roaming new file mode 100644 index 000000000..e69de29bb