mirror of
https://github.com/espressif/esp-protocols.git
synced 2025-07-29 10:17:30 +02:00
feat(wifi_remote): Add support for simple eppp based RPC
This commit is contained in:
23
components/esp_wifi_remote/eppp/eppp_init.c
Normal file
23
components/esp_wifi_remote/eppp/eppp_init.c
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
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);
|
||||
#if CONFIG_ESP_WIFI_REMOTE_EPPP_TRANSPORT_UART
|
||||
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;
|
||||
#else
|
||||
#error ESP_WIFI_REMOTE supports only UART transport
|
||||
#endif
|
||||
return eppp_open(role, &config, portMAX_DELAY);
|
||||
}
|
277
components/esp_wifi_remote/eppp/wifi_remote_rpc_client.cpp
Normal file
277
components/esp_wifi_remote/eppp/wifi_remote_rpc_client.cpp
Normal file
@ -0,0 +1,277 @@
|
||||
/*
|
||||
* 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-----";
|
||||
|
||||
}
|
||||
|
||||
using namespace client;
|
||||
|
||||
struct Sync {
|
||||
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 ? 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);
|
||||
}
|
||||
}
|
||||
SemaphoreHandle_t mutex{nullptr};
|
||||
EventGroupHandle_t events{nullptr};
|
||||
const int request = 1;
|
||||
const int resp_header = 2;
|
||||
const int resp_payload = 4;
|
||||
|
||||
};
|
||||
|
||||
class RpcInstance {
|
||||
public:
|
||||
template<typename T>
|
||||
esp_err_t send(api_id id, T *t)
|
||||
{
|
||||
ESP_RETURN_ON_ERROR(sync.notify(sync.request), TAG, "failed to notify req");
|
||||
pending_resp = id;
|
||||
ESP_RETURN_ON_ERROR(rpc.send<T>(id, t), TAG, "Failed to send request");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
// specialization for (void)
|
||||
esp_err_t send(api_id id)
|
||||
{
|
||||
ESP_RETURN_ON_ERROR(sync.notify(sync.request), TAG, "failed to notify req");
|
||||
pending_resp = id;
|
||||
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(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);
|
||||
while (instance->perform() == ESP_OK) {}
|
||||
vTaskDelete(nullptr);
|
||||
}
|
||||
esp_netif_t *netif{nullptr};
|
||||
};
|
||||
|
||||
|
||||
namespace client {
|
||||
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";
|
||||
|
||||
tls_ = esp_tls_init();
|
||||
if (!tls_) {
|
||||
ESP_LOGE(TAG, "Failed to allocate esp_tls handle!");
|
||||
goto exit;
|
||||
}
|
||||
if (esp_tls_conn_new_sync(host, strlen(host), rpc_port, &cfg, tls_) <= 0) {
|
||||
ESP_LOGE(TAG, "Failed to open a new connection %s", host);
|
||||
goto exit;
|
||||
}
|
||||
return &client::instance;
|
||||
exit:
|
||||
esp_tls_conn_destroy(tls_);
|
||||
tls_ = nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
} // 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(¶ms.conf, conf, sizeof(wifi_config_t));
|
||||
std::lock_guard<Sync> lock(instance.sync);
|
||||
ESP_RETURN_ON_ERROR(instance.send(api_id::SET_CONFIG, ¶ms), 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);
|
||||
}
|
142
components/esp_wifi_remote/eppp/wifi_remote_rpc_impl.hpp
Normal file
142
components/esp_wifi_remote/eppp/wifi_remote_rpc_impl.hpp
Normal file
@ -0,0 +1,142 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
#include <cstring>
|
||||
#include <cerrno>
|
||||
|
||||
namespace eppp_rpc {
|
||||
|
||||
const int rpc_port = 3333;
|
||||
|
||||
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__));
|
||||
|
||||
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__));
|
||||
|
||||
class RpcInstance;
|
||||
|
||||
class RpcEngine {
|
||||
public:
|
||||
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;
|
||||
}
|
||||
|
||||
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) // specialization 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};
|
||||
};
|
||||
|
||||
};
|
23
components/esp_wifi_remote/eppp/wifi_remote_rpc_params.h
Normal file
23
components/esp_wifi_remote/eppp/wifi_remote_rpc_params.h
Normal 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;
|
||||
};
|
209
components/esp_wifi_remote/eppp/wifi_remote_rpc_server.cpp
Normal file
209
components/esp_wifi_remote/eppp/wifi_remote_rpc_server.cpp
Normal file
@ -0,0 +1,209 @@
|
||||
/*
|
||||
* 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-----";
|
||||
|
||||
}
|
||||
|
||||
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) {}
|
||||
vTaskDelete(nullptr);
|
||||
}
|
||||
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 {
|
||||
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();
|
||||
}
|
Reference in New Issue
Block a user