feat(eppp): Added support for UART transport

This commit is contained in:
David Cermak
2023-12-21 14:28:28 +01:00
parent a7610395ef
commit ad27414a64
17 changed files with 706 additions and 4 deletions

View File

@ -1,3 +1,3 @@
idf_component_register(SRCS "eppp_link.c"
INCLUDE_DIRS "include"
PRIV_REQUIRES esp_netif esp_driver_spi esp_driver_gpio esp_timer)
PRIV_REQUIRES esp_netif esp_driver_spi esp_driver_gpio esp_timer driver)

View File

@ -8,6 +8,7 @@
#include "sdkconfig.h"
#include "esp_log.h"
#include "esp_netif.h"
#include "esp_check.h"
#include "esp_event.h"
#include "esp_netif_ppp.h"
#include "eppp_link_types.h"
@ -17,6 +18,8 @@
#include "driver/spi_slave.h"
#include "driver/gpio.h"
#include "esp_timer.h"
#elif CONFIG_EPPP_LINK_DEVICE_UART
#include "driver/uart.h"
#endif
static const int GOT_IPV4 = BIT0;
@ -44,7 +47,11 @@ enum eppp_type {
struct eppp_handle {
QueueHandle_t out_queue;
#if CONFIG_EPPP_LINK_DEVICE_SPI
QueueHandle_t ready_semaphore;
#elif CONFIG_EPPP_LINK_DEVICE_UART
QueueHandle_t uart_event_queue;
#endif
esp_netif_t *netif;
enum eppp_type role;
};
@ -57,7 +64,7 @@ struct packet {
static esp_err_t transmit(void *h, void *buffer, size_t len)
{
#if CONFIG_EXAMPLE_CONNECT_PPP_DEVICE_SPI
#if CONFIG_EPPP_LINK_DEVICE_SPI
#define MAX_PAYLOAD 1600
struct eppp_handle *handle = h;
struct packet buf = { };
@ -76,6 +83,8 @@ static esp_err_t transmit(void *h, void *buffer, size_t len)
ESP_LOGE(TAG, "Failed to queue packet to slave!");
}
} while (remaining > 0);
#elif CONFIG_EPPP_LINK_DEVICE_UART
uart_write_bytes(UART_NUM_1, buffer, len);
#endif
return ESP_OK;
}
@ -101,6 +110,7 @@ static esp_netif_t *netif_init(enum eppp_type role)
return NULL;
}
h->role = role;
#if CONFIG_EPPP_LINK_DEVICE_SPI
if (role == EPPP_CLIENT) {
h->ready_semaphore = xSemaphoreCreateBinary();
if (!h->ready_semaphore) {
@ -110,6 +120,7 @@ static esp_netif_t *netif_init(enum eppp_type role)
return NULL;
}
}
#endif
esp_netif_driver_ifconfig_t driver_cfg = {
.handle = h,
@ -119,7 +130,7 @@ static esp_netif_t *netif_init(enum eppp_type role)
esp_netif_inherent_config_t base_netif_cfg = ESP_NETIF_INHERENT_DEFAULT_PPP();
char if_key[] = "EPPP0"; // netif key needs to be unique
if_key[sizeof(if_key) - 1] += s_eppp_netif_count++;
if_key[sizeof(if_key) - 2 /* 2 = two chars before the terminator */ ] += s_eppp_netif_count++;
base_netif_cfg.if_key = if_key;
if (role == EPPP_CLIENT) {
base_netif_cfg.if_desc = "pppos_client";
@ -470,7 +481,56 @@ _Noreturn static void ppp_task(void *args)
}
}
}
#endif // CONFIG_EPPP_LINK_DEVICE_SPI
#elif CONFIG_EPPP_LINK_DEVICE_UART
#define BUF_SIZE (1024)
#define UART_TX_CLIENT_TO_SERVER 10
#define UART_TX_SERVER_TO_CLIENT 11
#define UART_BAUDRATE 4000000
#define UART_QUEUE_SIZE 16
static esp_err_t init_uart(struct eppp_handle *h)
{
uart_config_t uart_config = {};
uart_config.baud_rate = UART_BAUDRATE;
uart_config.data_bits = UART_DATA_8_BITS;
uart_config.parity = UART_PARITY_DISABLE;
uart_config.stop_bits = UART_STOP_BITS_1;
uart_config.flow_ctrl = UART_HW_FLOWCTRL_DISABLE;
uart_config.source_clk = UART_SCLK_DEFAULT;
ESP_RETURN_ON_ERROR(uart_driver_install(UART_NUM_1, BUF_SIZE, 0, UART_QUEUE_SIZE, &h->uart_event_queue, 0), TAG, "Failed to install UART");
ESP_RETURN_ON_ERROR(uart_param_config(UART_NUM_1, &uart_config), TAG, "Failed to set params");
int tx_io_num = h->role == EPPP_CLIENT ? UART_TX_CLIENT_TO_SERVER : UART_TX_SERVER_TO_CLIENT;
int rx_io_num = h->role == EPPP_CLIENT ? UART_TX_SERVER_TO_CLIENT : UART_TX_CLIENT_TO_SERVER;
ESP_RETURN_ON_ERROR(uart_set_pin(UART_NUM_1, tx_io_num, rx_io_num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE), TAG, "Failed to set UART pins");
ESP_RETURN_ON_ERROR(uart_set_rx_timeout(UART_NUM_1, 1), TAG, "Failed to set UART Rx timeout");
return ESP_OK;
}
_Noreturn static void ppp_task(void *args)
{
static uint8_t buffer[BUF_SIZE] = {};
esp_netif_t *netif = args;
struct eppp_handle *h = esp_netif_get_io_driver(netif);
uart_event_t event;
while (1) {
xQueueReceive(h->uart_event_queue, &event, pdMS_TO_TICKS(pdMS_TO_TICKS(100)));
if (event.type == UART_DATA) {
size_t len;
uart_get_buffered_data_len(UART_NUM_1, &len);
if (len) {
len = uart_read_bytes(UART_NUM_1, buffer, BUF_SIZE, 0);
ESP_LOG_BUFFER_HEXDUMP("ppp_uart_recv", buffer, len, ESP_LOG_VERBOSE);
esp_netif_receive(netif, buffer, len, NULL);
}
} else {
ESP_LOGW(TAG, "Received UART event: %d", event.type);
}
}
}
#endif // CONFIG_EPPP_LINK_DEVICE_SPI / UART
static esp_netif_t *default_setup(enum eppp_type role)
@ -498,6 +558,8 @@ static esp_netif_t *default_setup(enum eppp_type role)
} else {
init_slave(&s_spi_device, netif);
}
#elif CONFIG_EPPP_LINK_DEVICE_UART
init_uart(esp_netif_get_io_driver(netif));
#endif
netif_start(netif);

View File

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

View File

@ -0,0 +1,9 @@
# Client side demo of ESP-PPP-Link
This is a basic demo of using esp-mqtt library, but connects to the internet using a PPPoS client. To run this example, you would need a PPP server that provides connectivity to the MQTT broker used in this example (by default a public broker accessible on the internet).
If configured, this example could also run a ping session and an iperf console.
The PPP server could be a Linux computer with `pppd` service or an ESP32 acting like a connection gateway with PPPoS server (see the "slave" project).

View File

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

View File

@ -0,0 +1,43 @@
menu "Example Configuration"
config EXAMPLE_GLOBAL_DNS
hex "Set global DNS server"
range 0 0xFFFFFFFF
default 0x08080808
help
Global DNS server address.
config EXAMPLE_MQTT
bool "Run mqtt example"
default y
help
Run MQTT client after startup.
config EXAMPLE_BROKER_URL
string "Broker URL"
depends on EXAMPLE_MQTT
default "mqtt://mqtt.eclipseprojects.io"
help
URL of the broker to connect to.
config EXAMPLE_ICMP_PING
bool "Run ping example"
default y
help
Ping configured address after startup.
config EXAMPLE_PING_ADDR
hex "Ping IPv4 address"
depends on EXAMPLE_ICMP_PING
range 0 0xFFFFFFFF
default 0x08080808
help
Address to send ping requests.
config EXAMPLE_IPERF
bool "Run iperf"
default y
help
Init and run iperf console.
endmenu

View File

@ -0,0 +1,203 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include "esp_system.h"
#include "nvs_flash.h"
#include "esp_event.h"
#include "esp_netif.h"
#include "eppp_link.h"
#include "lwip/sockets.h"
#include "esp_log.h"
#include "mqtt_client.h"
#include "ping/ping_sock.h"
#include "esp_console.h"
void register_iperf(void);
static const char *TAG = "eppp_host_example";
#if CONFIG_EXAMPLE_MQTT
static void mqtt_event_handler(void *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=%" PRIi32 "", base, event_id);
esp_mqtt_event_handle_t event = 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");
if (event->error_handle->error_type == MQTT_ERROR_TYPE_TCP_TRANSPORT) {
ESP_LOGI(TAG, "Last errno string (%s)", strerror(event->error_handle->esp_transport_sock_errno));
}
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 = {
.broker.address.uri = CONFIG_EXAMPLE_BROKER_URL,
};
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_EVENT_ANY_ID, mqtt_event_handler, NULL);
esp_mqtt_client_start(client);
}
#endif // MQTT
#if CONFIG_EXAMPLE_ICMP_PING
static void test_on_ping_success(esp_ping_handle_t hdl, void *args)
{
uint8_t ttl;
uint16_t seqno;
uint32_t elapsed_time, recv_len;
ip_addr_t target_addr;
esp_ping_get_profile(hdl, ESP_PING_PROF_SEQNO, &seqno, sizeof(seqno));
esp_ping_get_profile(hdl, ESP_PING_PROF_TTL, &ttl, sizeof(ttl));
esp_ping_get_profile(hdl, ESP_PING_PROF_IPADDR, &target_addr, sizeof(target_addr));
esp_ping_get_profile(hdl, ESP_PING_PROF_SIZE, &recv_len, sizeof(recv_len));
esp_ping_get_profile(hdl, ESP_PING_PROF_TIMEGAP, &elapsed_time, sizeof(elapsed_time));
printf("%" PRId32 "bytes from %s icmp_seq=%d ttl=%d time=%" PRId32 " ms\n",
recv_len, inet_ntoa(target_addr.u_addr.ip4), seqno, ttl, elapsed_time);
}
static void test_on_ping_timeout(esp_ping_handle_t hdl, void *args)
{
uint16_t seqno;
ip_addr_t target_addr;
esp_ping_get_profile(hdl, ESP_PING_PROF_SEQNO, &seqno, sizeof(seqno));
esp_ping_get_profile(hdl, ESP_PING_PROF_IPADDR, &target_addr, sizeof(target_addr));
printf("From %s icmp_seq=%d timeout\n", inet_ntoa(target_addr.u_addr.ip4), seqno);
}
static void test_on_ping_end(esp_ping_handle_t hdl, void *args)
{
uint32_t transmitted;
uint32_t received;
uint32_t total_time_ms;
esp_ping_get_profile(hdl, ESP_PING_PROF_REQUEST, &transmitted, sizeof(transmitted));
esp_ping_get_profile(hdl, ESP_PING_PROF_REPLY, &received, sizeof(received));
esp_ping_get_profile(hdl, ESP_PING_PROF_DURATION, &total_time_ms, sizeof(total_time_ms));
printf("%" PRId32 " packets transmitted, %" PRId32 " received, time %" PRId32 "ms\n", transmitted, received, total_time_ms);
}
#endif // PING
void app_main(void)
{
ESP_LOGI(TAG, "[APP] Startup..");
ESP_LOGI(TAG, "[APP] Free memory: %" PRIu32 " bytes", esp_get_free_heap_size());
ESP_LOGI(TAG, "[APP] IDF version: %s", esp_get_idf_version());
ESP_ERROR_CHECK(nvs_flash_init());
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
/* Sets up the default EPPP-connection
*/
esp_netif_t *eppp_netif = eppp_connect();
if (eppp_netif == NULL) {
ESP_LOGE(TAG, "Failed to connect");
return ;
}
// Setup global DNS
esp_netif_dns_info_t dns;
dns.ip.u_addr.ip4.addr = esp_netif_htonl(CONFIG_EXAMPLE_GLOBAL_DNS);
dns.ip.type = ESP_IPADDR_TYPE_V4;
ESP_ERROR_CHECK(esp_netif_set_dns_info(eppp_netif, ESP_NETIF_DNS_MAIN, &dns));
#if CONFIG_EXAMPLE_IPERF
esp_console_repl_t *repl = NULL;
esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT();
esp_console_dev_uart_config_t uart_config = ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT();
repl_config.prompt = "iperf>";
// init console REPL environment
ESP_ERROR_CHECK(esp_console_new_repl_uart(&uart_config, &repl_config, &repl));
register_iperf();
printf("\n =======================================================\n");
printf(" | Steps to Test PPP Client Bandwidth |\n");
printf(" | |\n");
printf(" | 1. Enter 'help', check all supported commands |\n");
printf(" | 2. Start PPP server on host system |\n");
printf(" | - pppd /dev/ttyUSB1 115200 192.168.11.1:192.168.11.2 modem local noauth debug nocrtscts nodetach +ipv6\n");
printf(" | 3. Wait ESP32 to get IP from PPP server |\n");
printf(" | 4. Enter 'pppd info' (optional) |\n");
printf(" | 5. Server: 'iperf -u -s -i 3' |\n");
printf(" | 6. Client: 'iperf -u -c SERVER_IP -t 60 -i 3' |\n");
printf(" | |\n");
printf(" =======================================================\n\n");
// start console REPL
ESP_ERROR_CHECK(esp_console_start_repl(repl));
#endif
#if CONFIG_EXAMPLE_ICMP_PING
ip_addr_t target_addr = { .type = IPADDR_TYPE_V4, .u_addr.ip4.addr = esp_netif_htonl(CONFIG_EXAMPLE_PING_ADDR) };
esp_ping_config_t ping_config = ESP_PING_DEFAULT_CONFIG();
ping_config.timeout_ms = 2000;
ping_config.interval_ms = 20,
ping_config.target_addr = target_addr;
ping_config.count = 100; // ping in infinite mode
/* set callback functions */
esp_ping_callbacks_t cbs;
cbs.on_ping_success = test_on_ping_success;
cbs.on_ping_timeout = test_on_ping_timeout;
cbs.on_ping_end = test_on_ping_end;
esp_ping_handle_t ping;
esp_ping_new_session(&ping_config, &cbs, &ping);
/* start ping */
esp_ping_start(ping);
#endif // PING
#if CONFIG_EXAMPLE_MQTT
mqtt_app_start();
#endif
}

View File

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

View File

@ -0,0 +1,183 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "sys/socket.h" // for INADDR_ANY
#include "esp_netif.h"
#include "esp_log.h"
#include "esp_system.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_netif.h"
#include "esp_netif_ppp.h"
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "esp_console.h"
#include "esp_event.h"
#include "esp_bit_defs.h"
#include "argtable3/argtable3.h"
#include "iperf.h"
#include "sdkconfig.h"
/* "iperf" command */
static struct {
struct arg_str *ip;
struct arg_lit *server;
struct arg_lit *udp;
struct arg_lit *version;
struct arg_int *port;
struct arg_int *length;
struct arg_int *interval;
struct arg_int *time;
struct arg_int *bw_limit;
struct arg_lit *abort;
struct arg_end *end;
} iperf_args;
static int ppp_cmd_iperf(int argc, char **argv)
{
int nerrors = arg_parse(argc, argv, (void **)&iperf_args);
iperf_cfg_t cfg;
if (nerrors != 0) {
arg_print_errors(stderr, iperf_args.end, argv[0]);
return 0;
}
memset(&cfg, 0, sizeof(cfg));
// ethernet iperf only support IPV4 address
cfg.type = IPERF_IP_TYPE_IPV4;
/* iperf -a */
if (iperf_args.abort->count != 0) {
iperf_stop();
return 0;
}
if (((iperf_args.ip->count == 0) && (iperf_args.server->count == 0)) ||
((iperf_args.ip->count != 0) && (iperf_args.server->count != 0))) {
ESP_LOGE(__func__, "Wrong mode! ESP32 should run in client or server mode");
return 0;
}
/* iperf -s */
if (iperf_args.ip->count == 0) {
cfg.flag |= IPERF_FLAG_SERVER;
}
/* iperf -c SERVER_ADDRESS */
else {
cfg.destination_ip4 = esp_ip4addr_aton(iperf_args.ip->sval[0]);
cfg.flag |= IPERF_FLAG_CLIENT;
}
if (iperf_args.length->count == 0) {
cfg.len_send_buf = 0;
} else {
cfg.len_send_buf = iperf_args.length->ival[0];
}
cfg.source_ip4 = INADDR_ANY;
/* iperf -u */
if (iperf_args.udp->count == 0) {
cfg.flag |= IPERF_FLAG_TCP;
} else {
cfg.flag |= IPERF_FLAG_UDP;
}
/* iperf -p */
if (iperf_args.port->count == 0) {
cfg.sport = IPERF_DEFAULT_PORT;
cfg.dport = IPERF_DEFAULT_PORT;
} else {
if (cfg.flag & IPERF_FLAG_SERVER) {
cfg.sport = iperf_args.port->ival[0];
cfg.dport = IPERF_DEFAULT_PORT;
} else {
cfg.sport = IPERF_DEFAULT_PORT;
cfg.dport = iperf_args.port->ival[0];
}
}
/* iperf -i */
if (iperf_args.interval->count == 0) {
cfg.interval = IPERF_DEFAULT_INTERVAL;
} else {
cfg.interval = iperf_args.interval->ival[0];
if (cfg.interval <= 0) {
cfg.interval = IPERF_DEFAULT_INTERVAL;
}
}
/* iperf -t */
if (iperf_args.time->count == 0) {
cfg.time = IPERF_DEFAULT_TIME;
} else {
cfg.time = iperf_args.time->ival[0];
if (cfg.time <= cfg.interval) {
cfg.time = cfg.interval;
}
}
/* iperf -b */
if (iperf_args.bw_limit->count == 0) {
cfg.bw_lim = IPERF_DEFAULT_NO_BW_LIMIT;
} else {
cfg.bw_lim = iperf_args.bw_limit->ival[0];
if (cfg.bw_lim <= 0) {
cfg.bw_lim = IPERF_DEFAULT_NO_BW_LIMIT;
}
}
printf("mode=%s-%s sip=" IPSTR ":%" PRIu16 ", dip=%" PRIu32 ".%" PRIu32 ".%" PRIu32 ".%" PRIu32 ":%" PRIu16 ", interval=%" PRIu32 ", time=%" PRIu32 "\r\n",
cfg.flag & IPERF_FLAG_TCP ? "tcp" : "udp",
cfg.flag & IPERF_FLAG_SERVER ? "server" : "client",
(uint16_t) cfg.source_ip4 & 0xFF,
(uint16_t) (cfg.source_ip4 >> 8) & 0xFF,
(uint16_t) (cfg.source_ip4 >> 16) & 0xFF,
(uint16_t) (cfg.source_ip4 >> 24) & 0xFF,
cfg.sport,
cfg.destination_ip4 & 0xFF, (cfg.destination_ip4 >> 8) & 0xFF,
(cfg.destination_ip4 >> 16) & 0xFF, (cfg.destination_ip4 >> 24) & 0xFF, cfg.dport,
cfg.interval, cfg.time);
iperf_start(&cfg);
return 0;
}
void register_iperf(void)
{
iperf_args.ip = arg_str0("c", "client", "<ip>",
"run in client mode, connecting to <host>");
iperf_args.server = arg_lit0("s", "server", "run in server mode");
iperf_args.udp = arg_lit0("u", "udp", "use UDP rather than TCP");
iperf_args.version = arg_lit0("V", "ipv6_domain", "use IPV6 address rather than IPV4");
iperf_args.port = arg_int0("p", "port", "<port>",
"server port to listen on/connect to");
iperf_args.length = arg_int0("l", "len", "<length>", "set read/write buffer size");
iperf_args.interval = arg_int0("i", "interval", "<interval>",
"seconds between periodic bandwidth reports");
iperf_args.time = arg_int0("t", "time", "<time>", "time in seconds to transmit for (default 10 secs)");
iperf_args.bw_limit = arg_int0("b", "bandwidth", "<bandwidth>", "bandwidth to send at in Mbits/sec");
iperf_args.abort = arg_lit0("a", "abort", "abort running iperf");
iperf_args.end = arg_end(1);
const esp_console_cmd_t iperf_cmd = {
.command = "iperf",
.help = "iperf command",
.hint = NULL,
.func = &ppp_cmd_iperf,
.argtable = &iperf_args
};
ESP_ERROR_CHECK(esp_console_cmd_register(&iperf_cmd));
}

View File

@ -0,0 +1,8 @@
# This file was generated using idf.py save-defconfig. It can be edited manually.
# Espressif IoT Development Framework (ESP-IDF) 5.3.0 Project Minimal Configuration
#
CONFIG_UART_ISR_IN_IRAM=y
CONFIG_LWIP_PPP_SUPPORT=y
CONFIG_LWIP_PPP_VJ_HEADER_COMPRESSION=n
CONFIG_LWIP_PPP_DEBUG_ON=y
CONFIG_EPPP_LINK_DEVICE_SPI=y

View File

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

View File

@ -0,0 +1,7 @@
# Wi-Fi station to PPPoS server
This example demonstrate using NAPT to bring connectivity from WiFi station to PPPoS server.
This example expect a PPPoS client to connect to the server and use the connectivity.
The client could be a Linux computer with `pppd` service or another microcontroller with PPP client (or another ESP32 with not WiFi interface)

View File

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

View File

@ -0,0 +1,21 @@
menu "Example Configuration"
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.
config ESP_MAXIMUM_RETRY
int "Maximum retry"
default 5
help
Set the Maximum retry to avoid station reconnecting to the AP unlimited when the AP is really inexistent.
endmenu

View File

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

View File

@ -0,0 +1,132 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.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 "lwip/err.h"
#include "lwip/sys.h"
/* FreeRTOS event group to signal when we are connected*/
static EventGroupHandle_t s_wifi_event_group;
/* The event group allows multiple bits for each event, but we only care about two events:
* - we are connected to the AP with an IP
* - we failed to connect after the maximum amount of retries */
#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT BIT1
static const char *TAG = "sta2pppos";
static int s_retry_num = 0;
static void event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data)
{
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 < CONFIG_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);
}
}
void wifi_init_sta(void)
{
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 = CONFIG_ESP_WIFI_SSID,
.password = CONFIG_ESP_WIFI_PASSWORD,
},
};
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",
CONFIG_ESP_WIFI_SSID, CONFIG_ESP_WIFI_PASSWORD);
} else if (bits & WIFI_FAIL_BIT) {
ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s",
CONFIG_ESP_WIFI_SSID, CONFIG_ESP_WIFI_PASSWORD);
} else {
ESP_LOGE(TAG, "UNEXPECTED EVENT");
}
}
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_LOGI(TAG, "ESP_WIFI_MODE_STA");
wifi_init_sta();
esp_netif_t *eppp_netif = eppp_listen();
if (eppp_netif == NULL) {
ESP_LOGE(TAG, "Failed to setup connection");
return ;
}
ESP_ERROR_CHECK(esp_netif_napt_enable(eppp_netif));
}

View File

@ -0,0 +1,8 @@
CONFIG_UART_ISR_IN_IRAM=y
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
CONFIG_EPPP_LINK_DEVICE_SPI=y