Skip to content

[eppp-link]: Support for channels #814

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions components/eppp_link/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,21 @@ menu "eppp_link"
default "06:00:00:00:00:02"
depends on EPPP_LINK_DEVICE_ETH

config EPPP_LINK_CHANNELS_SUPPORT
bool "Enable channel support (multiple logical channels)"
default n
depends on !EPPP_LINK_DEVICE_ETH
help
Enable support for multiple logical channels in the EPPP link layer.
When enabled, you can configure the number of channels used for communication.

config EPPP_LINK_NR_OF_CHANNELS
int "Number of logical channels"
depends on EPPP_LINK_CHANNELS_SUPPORT && !EPPP_LINK_DEVICE_ETH
range 1 8
default 2
help
Set the number of logical channels for EPPP link communication.
Each channel can be used for independent data streams.

endmenu
11 changes: 11 additions & 0 deletions components/eppp_link/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ Use `idf.py menuconfig` to select the transport layer:

Use PPP netif for UART; Keep the default (TUN) for others

### Channel support (multiple logical channels)

* `CONFIG_EPPP_LINK_CHANNELS_SUPPORT` -- Enable support for multiple logical channels (default: disabled)
* `CONFIG_EPPP_LINK_NR_OF_CHANNELS` -- Number of logical channels (default: 2, range: 1-8, only visible if channel support is enabled)

When channel support is enabled, the EPPP link can multiplex multiple logical data streams over the same transport. The number of channels is configurable. Channel support is not available for Ethernet transport.

To use channels in your application, use the `eppp_add_channels()` API and provide your own channel transmit/receive callbacks. These APIs and related types are only available when channel support is enabled in Kconfig.

## API

Expand All @@ -57,6 +65,9 @@ Use PPP netif for UART; Keep the default (TUN) for others
* `eppp_netif_start()` -- Starts the network, could be called after startup or whenever a connection is lost
* `eppp_netif_stop()` -- Stops the network
* `eppp_perform()` -- Perform one iteration of the PPP task (need to be called regularly in task-less configuration)
#ifdef CONFIG_EPPP_LINK_CHANNELS_SUPPORT
* `eppp_add_channels()` -- Register channel transmit/receive callbacks (only available if channel support is enabled)
#endif

## Throughput

Expand Down
21 changes: 21 additions & 0 deletions components/eppp_link/eppp_link.c
Original file line number Diff line number Diff line change
Expand Up @@ -367,3 +367,24 @@ void eppp_close(esp_netif_t *netif)
eppp_deinit(netif);
remove_handlers();
}

#ifdef CONFIG_EPPP_LINK_CHANNELS_SUPPORT
esp_err_t eppp_add_channels(esp_netif_t *netif, eppp_channel_fn_t *tx, const eppp_channel_fn_t rx, void* context)
{
ESP_RETURN_ON_FALSE(netif != NULL && tx != NULL && rx != NULL, ESP_ERR_INVALID_ARG, TAG, "Invalid arguments");
struct eppp_handle *h = esp_netif_get_io_driver(netif);
ESP_RETURN_ON_FALSE(h != NULL && h->channel_tx != NULL, ESP_ERR_INVALID_STATE, TAG, "Transport not initialized");
*tx = h->channel_tx;
h->channel_rx = rx;
h->context = context;
return ESP_OK;
}

void* eppp_get_context(esp_netif_t *netif)
{
ESP_RETURN_ON_FALSE(netif != NULL, NULL, TAG, "Invalid netif");
struct eppp_handle *h = esp_netif_get_io_driver(netif);
ESP_RETURN_ON_FALSE(h != NULL, NULL, TAG, "EPPP Not initialized");
return h->context;
}
#endif
4 changes: 4 additions & 0 deletions components/eppp_link/eppp_sdio.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "eppp_link.h"
#include "eppp_transport.h"
#include "eppp_transport_sdio.h"
#include "eppp_sdio.h"

#define TAG "eppp_sdio"

Expand Down Expand Up @@ -67,6 +68,9 @@ eppp_transport_handle_t eppp_sdio_init(struct eppp_config_sdio_s *config)
ESP_RETURN_ON_FALSE(config, NULL, TAG, "Config cannot be null");
struct eppp_sdio *h = calloc(1, sizeof(struct eppp_sdio));
ESP_RETURN_ON_FALSE(h, NULL, TAG, "Failed to allocate eppp_handle");
#ifdef CONFIG_EPPP_LINK_CHANNELS_SUPPORT
h->parent.channel_tx = eppp_sdio_transmit_channel;
#endif
h->parent.base.post_attach = post_attach;
h->is_host = config->is_host;
esp_err_t (*init_fn)(struct eppp_config_sdio_s * eppp_config) = h->is_host ? eppp_sdio_host_init : eppp_sdio_slave_init;
Expand Down
12 changes: 11 additions & 1 deletion components/eppp_link/eppp_sdio.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
Expand All @@ -8,12 +8,22 @@
#define MAX_SDIO_PAYLOAD 1500
#define SDIO_ALIGN(size) (((size) + 3U) & ~(3U))
#define SDIO_PAYLOAD SDIO_ALIGN(MAX_SDIO_PAYLOAD)
#define SDIO_PACKET_SIZE SDIO_ALIGN(MAX_SDIO_PAYLOAD + 4)
#define PPP_SOF 0x7E


// Interrupts and registers
#define SLAVE_INTR 0
#define SLAVE_REG_REQ 0

// Requests from host to slave
#define REQ_RESET 1
#define REQ_INIT 2

struct header {
uint8_t magic;
uint8_t channel;
uint16_t size;
} __attribute__((packed));

esp_err_t eppp_sdio_transmit_channel(esp_netif_t *netif, int channel, void *buffer, size_t len);
63 changes: 50 additions & 13 deletions components/eppp_link/eppp_sdio_host.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
Expand All @@ -15,6 +15,7 @@
#include "sdmmc_cmd.h"
#include "esp_check.h"
#include "eppp_link.h"
#include "eppp_transport.h"

#if CONFIG_EPPP_LINK_DEVICE_SDIO_HOST

Expand All @@ -28,22 +29,23 @@ static SemaphoreHandle_t s_essl_mutex = NULL;
static essl_handle_t s_essl = NULL;
static sdmmc_card_t *s_card = NULL;

static DRAM_DMA_ALIGNED_ATTR uint8_t send_buffer[SDIO_PAYLOAD];
static DMA_ATTR uint8_t rcv_buffer[SDIO_PAYLOAD];
static DRAM_DMA_ALIGNED_ATTR uint8_t send_buffer[SDIO_PACKET_SIZE];
static DMA_ATTR uint8_t rcv_buffer[SDIO_PACKET_SIZE];

esp_err_t eppp_sdio_host_tx(void *h, void *buffer, size_t len)
static esp_err_t eppp_sdio_host_tx_generic(int channel, void *buffer, size_t len)
{
if (s_essl == NULL || s_essl_mutex == NULL) {
// silently skip the Tx if the SDIO not fully initialized
return ESP_OK;
}

memcpy(send_buffer, buffer, len);
size_t send_len = SDIO_ALIGN(len);
if (send_len > len) {
// pad with SOF's
memset(&send_buffer[len], PPP_SOF, send_len - len);
}

struct header *head = (void *)send_buffer;
head->magic = PPP_SOF;
head->channel = channel;
head->size = len;
memcpy(send_buffer + sizeof(struct header), buffer, len);
size_t send_len = SDIO_ALIGN(len + sizeof(struct header));
xSemaphoreTake(s_essl_mutex, portMAX_DELAY);
esp_err_t ret = essl_send_packet(s_essl, send_buffer, send_len, PACKET_TIMEOUT_MS);
if (ret != ESP_OK) {
Expand All @@ -56,6 +58,19 @@ esp_err_t eppp_sdio_host_tx(void *h, void *buffer, size_t len)
return ret;
}

esp_err_t eppp_sdio_host_tx(void *h, void *buffer, size_t len)
{
return eppp_sdio_host_tx_generic(0, buffer, len);
}

#ifdef CONFIG_EPPP_LINK_CHANNELS_SUPPORT
esp_err_t eppp_sdio_transmit_channel(esp_netif_t *netif, int channel, void *buffer, size_t len)
{
return eppp_sdio_host_tx_generic(channel, buffer, len);
}
#endif


static esp_err_t request_slave_reset(void)
{
esp_err_t ret = ESP_OK;
Expand Down Expand Up @@ -145,15 +160,37 @@ esp_err_t eppp_sdio_host_rx(esp_netif_t *netif)
if (intr & ESSL_SDIO_DEF_ESP32.new_packet_intr_mask) {
esp_err_t ret;
do {
size_t size_read = SDIO_PAYLOAD;
ret = essl_get_packet(s_essl, rcv_buffer, SDIO_PAYLOAD, &size_read, PACKET_TIMEOUT_MS);
size_t size_read = SDIO_PACKET_SIZE;
ret = essl_get_packet(s_essl, rcv_buffer, SDIO_PACKET_SIZE, &size_read, PACKET_TIMEOUT_MS);
if (ret == ESP_ERR_NOT_FOUND) {
ESP_LOGE(TAG, "interrupt but no data can be read");
break;
} else if (ret == ESP_OK) {
ESP_LOGD(TAG, "receive data, size: %d", size_read);
struct header *head = (void *)rcv_buffer;
if (head->magic != PPP_SOF) {
ESP_LOGE(TAG, "invalid magic %x", head->magic);
break;
}
if (head->channel > NR_OF_CHANNELS) {
ESP_LOGE(TAG, "invalid channel %x", head->channel);
break;
}
if (head->size > SDIO_PAYLOAD || head->size > size_read) {
ESP_LOGE(TAG, "invalid size %x", head->size);
break;
}
ESP_LOG_BUFFER_HEXDUMP(TAG, rcv_buffer, size_read, ESP_LOG_VERBOSE);
esp_netif_receive(netif, rcv_buffer, size_read, NULL);
if (head->channel == 0) {
esp_netif_receive(netif, rcv_buffer + sizeof(struct header), head->size, NULL);
} else {
#if defined(CONFIG_EPPP_LINK_CHANNELS_SUPPORT)
struct eppp_handle *h = esp_netif_get_io_driver(netif);
if (h->channel_rx) {
h->channel_rx(netif, head->channel, rcv_buffer + sizeof(struct header), head->size);
}
#endif
}
break;
} else {
ESP_LOGE(TAG, "rx packet error: %08X", ret);
Expand Down
53 changes: 43 additions & 10 deletions components/eppp_link/eppp_sdio_slave.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@
#include "esp_netif.h"
#include "driver/sdio_slave.h"
#include "eppp_link.h"
#include "eppp_transport.h"
#include "eppp_sdio.h"
#include "esp_check.h"

#if CONFIG_EPPP_LINK_DEVICE_SDIO_SLAVE
#define BUFFER_NUM 4
#define BUFFER_SIZE SDIO_PAYLOAD
Expand All @@ -21,19 +21,18 @@ static DMA_ATTR uint8_t sdio_slave_rx_buffer[BUFFER_NUM][BUFFER_SIZE];
static DMA_ATTR uint8_t sdio_slave_tx_buffer[SDIO_PAYLOAD];
static int s_slave_request = 0;

esp_err_t eppp_sdio_slave_tx(void *h, void *buffer, size_t len)
static esp_err_t eppp_sdio_host_tx_generic(int channel, void *buffer, size_t len)
{
if (s_slave_request != REQ_INIT) {
// silently skip the Tx if the SDIO not fully initialized
return ESP_OK;
}
memcpy(sdio_slave_tx_buffer, buffer, len);
size_t send_len = SDIO_ALIGN(len);
if (send_len > len) {
// pad with SOF's if the size is not 4 bytes aligned
memset(&sdio_slave_tx_buffer[len], PPP_SOF, send_len - len);
}

struct header *head = (void *)sdio_slave_tx_buffer;
head->magic = PPP_SOF;
head->channel = channel;
head->size = len;
memcpy(sdio_slave_tx_buffer + sizeof(struct header), buffer, len);
size_t send_len = SDIO_ALIGN(len + sizeof(struct header));
ESP_LOG_BUFFER_HEXDUMP(TAG, sdio_slave_tx_buffer, send_len, ESP_LOG_VERBOSE);
esp_err_t ret = sdio_slave_transmit(sdio_slave_tx_buffer, send_len);
if (ret != ESP_OK) {
Expand All @@ -44,6 +43,18 @@ esp_err_t eppp_sdio_slave_tx(void *h, void *buffer, size_t len)
return ESP_OK;
}

esp_err_t eppp_sdio_slave_tx(void *h, void *buffer, size_t len)
{
return eppp_sdio_host_tx_generic(0, buffer, len);
}

#ifdef CONFIG_EPPP_LINK_CHANNELS_SUPPORT
esp_err_t eppp_sdio_transmit_channel(esp_netif_t *netif, int channel, void *buffer, size_t len)
{
return eppp_sdio_host_tx_generic(channel, buffer, len);
}
#endif

static esp_err_t slave_reset(void)
{
esp_err_t ret = ESP_OK;
Expand Down Expand Up @@ -82,7 +93,29 @@ esp_err_t eppp_sdio_slave_rx(esp_netif_t *netif)
if (ret == ESP_ERR_NOT_FINISHED || ret == ESP_OK) {
again:
ptr = sdio_slave_recv_get_buf(handle, &length);
esp_netif_receive(netif, ptr, length, NULL);
struct header *head = (void *)ptr;
if (head->magic != PPP_SOF) {
ESP_LOGE(TAG, "invalid magic %x", head->magic);
return ESP_FAIL;
}
if (head->channel > NR_OF_CHANNELS) {
ESP_LOGE(TAG, "invalid channel %x", head->channel);
return ESP_FAIL;
}
if (head->size > SDIO_PAYLOAD || head->size > length) {
ESP_LOGE(TAG, "invalid size %x", head->size);
return ESP_FAIL;
}
if (head->channel == 0) {
esp_netif_receive(netif, ptr + sizeof(struct header), head->size, NULL);
} else {
#if defined(CONFIG_EPPP_LINK_CHANNELS_SUPPORT)
struct eppp_handle *h = esp_netif_get_io_driver(netif);
if (h->channel_rx) {
h->channel_rx(netif, head->channel, ptr + sizeof(struct header), head->size);
}
#endif
}
if (sdio_slave_recv_load_buf(handle) != ESP_OK) {
ESP_LOGE(TAG, "Failed to recycle packet buffer");
return ESP_FAIL;
Expand Down
Loading