mirror of
https://github.com/espressif/esp-protocols.git
synced 2025-07-21 06:22:21 +02:00
esp-netif: Added esp_netif slip support, slip_modem component and example
Merges https://github.com/espressif/esp-idf/pull/4985 * Original commit: espressif/esp-idf@266be00254
This commit is contained in:
@ -0,0 +1,8 @@
|
|||||||
|
# SLIP Modem Component
|
||||||
|
|
||||||
|
idf_component_register(
|
||||||
|
SRCS "library/slip_modem.c"
|
||||||
|
INCLUDE_DIRS "include"
|
||||||
|
REQUIRES lwip esp_netif
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,55 @@
|
|||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "esp_netif.h"
|
||||||
|
#include "esp_netif_slip.h"
|
||||||
|
|
||||||
|
#include "driver/uart.h"
|
||||||
|
|
||||||
|
// Forward declare modem object
|
||||||
|
typedef struct esp_slip_modem esp_slip_modem_t;
|
||||||
|
|
||||||
|
// Filter callbacks for handling application specific slip messages
|
||||||
|
typedef bool slip_rx_filter_cb_t(void *ctx, uint8_t *data, uint32_t len);
|
||||||
|
|
||||||
|
|
||||||
|
/** @brief Configuration structure for SLIP modem interface
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
uart_port_t uart_dev; /* UART device for reading and writing SLIP information, this must be initialised externally */
|
||||||
|
|
||||||
|
int uart_tx_pin; /* UART TX pin number */
|
||||||
|
int uart_rx_pin; /* UART TX pin number */
|
||||||
|
|
||||||
|
uint32_t uart_baud; /* UART baud rate */
|
||||||
|
|
||||||
|
uint32_t rx_buffer_len; /* Length of buffer for RX messages */
|
||||||
|
|
||||||
|
slip_rx_filter_cb_t *rx_filter; /* Filter for parsing out non-SLIP messages from incoming SLIP stream */
|
||||||
|
void *rx_filter_ctx; /* Context to be passed to SLIP filter function */
|
||||||
|
|
||||||
|
} esp_slip_modem_config_t;
|
||||||
|
|
||||||
|
|
||||||
|
/** @brief Create a slip modem
|
||||||
|
*
|
||||||
|
* @param[in] slip configured esp netif
|
||||||
|
* @param[in] configuration for the slip modem
|
||||||
|
*
|
||||||
|
* @returns
|
||||||
|
* - slip modem driver glue object
|
||||||
|
*/
|
||||||
|
void *esp_slip_modem_create(esp_netif_t *slip_netif, esp_slip_modem_config_t *modem_config);
|
||||||
|
|
||||||
|
/** @brief Destroy a slip modem
|
||||||
|
*
|
||||||
|
* @param[in] slip modem object for destruction
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_OK on success
|
||||||
|
*/
|
||||||
|
esp_err_t esp_slip_modem_destroy(esp_slip_modem_t *slip_modem);
|
@ -0,0 +1,303 @@
|
|||||||
|
|
||||||
|
|
||||||
|
#include "slip_modem.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include "esp_netif.h"
|
||||||
|
#include "esp_netif_slip.h"
|
||||||
|
#include "esp_event.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include "lwip/opt.h"
|
||||||
|
#include "lwip/sio.h"
|
||||||
|
#include "lwip/ip.h"
|
||||||
|
#include "lwip/ip6.h"
|
||||||
|
#include "lwip/ip6_addr.h"
|
||||||
|
#include "lwip/netif.h"
|
||||||
|
|
||||||
|
#include "esp_netif_slip.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define SLIP_RX_TASK_PRIORITY 10
|
||||||
|
#define SLIP_RX_TASK_STACK_SIZE (4 * 1024)
|
||||||
|
|
||||||
|
|
||||||
|
static const char *TAG = "esp-slip_modem";
|
||||||
|
|
||||||
|
|
||||||
|
// UART container object
|
||||||
|
typedef struct {
|
||||||
|
// UART device number for SIO use
|
||||||
|
uart_port_t uart_dev;
|
||||||
|
|
||||||
|
// UART baud rate for configuration
|
||||||
|
uint32_t uart_baud;
|
||||||
|
|
||||||
|
// UART TX pin for configuration
|
||||||
|
int uart_tx_pin;
|
||||||
|
|
||||||
|
// UART RX pin for configuration
|
||||||
|
int uart_rx_pin;
|
||||||
|
|
||||||
|
// QueueHandle for uart driver
|
||||||
|
QueueHandle_t uart_queue;
|
||||||
|
|
||||||
|
// TaskHandle for receive task
|
||||||
|
TaskHandle_t uart_rx_task;
|
||||||
|
} esp_slip_uart_t;
|
||||||
|
|
||||||
|
|
||||||
|
// Modem object, implements glue logic for slip_driver and esp_netif
|
||||||
|
struct esp_slip_modem {
|
||||||
|
// ESP base netif driver
|
||||||
|
esp_netif_driver_base_t base;
|
||||||
|
|
||||||
|
// LWIP slip context
|
||||||
|
lwip_slip_ctx_t *slip_driver;
|
||||||
|
|
||||||
|
// Uart for use with slip
|
||||||
|
esp_slip_uart_t uart;
|
||||||
|
|
||||||
|
// Buffer for incoming messages
|
||||||
|
uint8_t *buffer;
|
||||||
|
uint32_t buffer_len;
|
||||||
|
|
||||||
|
// Filter callbacks for application-specific slip message handling
|
||||||
|
slip_rx_filter_cb_t *rx_filter;
|
||||||
|
void *rx_filter_ctx;
|
||||||
|
|
||||||
|
// Running flag
|
||||||
|
bool running;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Forward function definitions
|
||||||
|
static void esp_slip_modem_uart_rx_task(void *arg);
|
||||||
|
static esp_err_t esp_slip_modem_post_attach(esp_netif_t *esp_netif, void *args);
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: netif internal functions required for driver operation
|
||||||
|
esp_err_t esp_netif_start_slip(lwip_slip_ctx_t *slip_ctx);
|
||||||
|
esp_err_t esp_netif_stop_slip(lwip_slip_ctx_t *slip_ctx);
|
||||||
|
|
||||||
|
void esp_netif_lwip_slip_output(lwip_slip_ctx_t *slip_ctx, void *buffer, size_t len);
|
||||||
|
void esp_netif_lwip_slip_input(void *ctx, void *buffer, size_t len, void *eb);
|
||||||
|
|
||||||
|
|
||||||
|
// Create a new slip netif
|
||||||
|
void *esp_slip_modem_create(esp_netif_t *slip_netif, esp_slip_modem_config_t *modem_config)
|
||||||
|
{
|
||||||
|
ESP_LOGI(TAG, "%s: Creating slip modem (netif: %p)", __func__, slip_netif);
|
||||||
|
|
||||||
|
// Fetch lwip slip ctx object
|
||||||
|
// TODO: is the the best / a reasonable approach?
|
||||||
|
lwip_slip_ctx_t *slip_ctx = esp_netif_lwip_slip_get_ctx(slip_netif);
|
||||||
|
|
||||||
|
ESP_LOGD(TAG, "%s (netif: %p)", __func__, slip_netif);
|
||||||
|
|
||||||
|
esp_slip_modem_t *slip_modem = calloc(1, sizeof(esp_slip_modem_t));
|
||||||
|
if (!slip_modem) {
|
||||||
|
ESP_LOGE(TAG, "create netif glue failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attach driver and post_attach callbacks
|
||||||
|
slip_modem->slip_driver = slip_ctx;
|
||||||
|
slip_modem->base.post_attach = esp_slip_modem_post_attach;
|
||||||
|
|
||||||
|
// Attach config
|
||||||
|
slip_modem->buffer_len = modem_config->rx_buffer_len;
|
||||||
|
|
||||||
|
slip_modem->rx_filter = modem_config->rx_filter;
|
||||||
|
slip_modem->rx_filter_ctx = modem_config->rx_filter_ctx;
|
||||||
|
|
||||||
|
slip_modem->uart.uart_dev = modem_config->uart_dev;
|
||||||
|
slip_modem->uart.uart_baud = modem_config->uart_baud;
|
||||||
|
slip_modem->uart.uart_rx_pin = modem_config->uart_rx_pin;
|
||||||
|
slip_modem->uart.uart_tx_pin = modem_config->uart_tx_pin;
|
||||||
|
|
||||||
|
// Return new modem, with a cast to the first item
|
||||||
|
return &slip_modem->base;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Internal handler called on driver start
|
||||||
|
static esp_err_t esp_slip_driver_start(esp_slip_modem_t *slip_modem)
|
||||||
|
{
|
||||||
|
ESP_LOGD(TAG, "%s: Starting SLIP modem (modem %p)", __func__, slip_modem);
|
||||||
|
|
||||||
|
// Allocate RX buffer if one does not exist
|
||||||
|
if (slip_modem->buffer == NULL) {
|
||||||
|
slip_modem->buffer = malloc(slip_modem->buffer_len);
|
||||||
|
}
|
||||||
|
if (slip_modem->buffer == NULL) {
|
||||||
|
ESP_LOGE(TAG, "error allocating rx buffer");
|
||||||
|
return ESP_ERR_NO_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then, initialise UART
|
||||||
|
|
||||||
|
// Build configuration
|
||||||
|
uart_config_t uart_config = {
|
||||||
|
.baud_rate = slip_modem->uart.uart_baud,
|
||||||
|
.data_bits = UART_DATA_8_BITS,
|
||||||
|
.parity = UART_PARITY_DISABLE,
|
||||||
|
.stop_bits = UART_STOP_BITS_1,
|
||||||
|
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Initialise uart
|
||||||
|
ESP_ERROR_CHECK(uart_param_config(slip_modem->uart.uart_dev, &uart_config));
|
||||||
|
|
||||||
|
// Set UART pins
|
||||||
|
ESP_ERROR_CHECK(uart_set_pin(slip_modem->uart.uart_dev, slip_modem->uart.uart_tx_pin, slip_modem->uart.uart_rx_pin, 0, 0));
|
||||||
|
|
||||||
|
// Install UART driver
|
||||||
|
ESP_ERROR_CHECK(uart_driver_install(slip_modem->uart.uart_dev, slip_modem->buffer_len, slip_modem->buffer_len, 10, &slip_modem->uart.uart_queue, 0));
|
||||||
|
|
||||||
|
// Start slip RX task
|
||||||
|
slip_modem->running = true;
|
||||||
|
xTaskCreate(esp_slip_modem_uart_rx_task, "slip_modem_uart_rx_task", SLIP_RX_TASK_STACK_SIZE, slip_modem, SLIP_RX_TASK_PRIORITY, &slip_modem->uart.uart_rx_task);
|
||||||
|
|
||||||
|
// Finally, initialise slip network interface
|
||||||
|
esp_netif_start_slip(slip_modem->slip_driver);
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
esp_err_t esp_slip_modem_destroy(esp_slip_modem_t *slip_modem)
|
||||||
|
{
|
||||||
|
// Stop slip driver
|
||||||
|
esp_netif_stop_slip(slip_modem->slip_driver);
|
||||||
|
|
||||||
|
// Stop uart rx task
|
||||||
|
vTaskDelete(slip_modem->uart.uart_rx_task);
|
||||||
|
|
||||||
|
// Delete driver
|
||||||
|
uart_driver_delete(slip_modem->uart.uart_dev);
|
||||||
|
|
||||||
|
// Free slip interface
|
||||||
|
free(slip_modem);
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modem transmit for glue logic
|
||||||
|
esp_err_t esp_slip_modem_transmit(void *slip_driver, void *buffer, size_t len)
|
||||||
|
{
|
||||||
|
ESP_LOGD(TAG, "%s", __func__);
|
||||||
|
ESP_LOG_BUFFER_HEXDUMP(TAG, buffer, len, ESP_LOG_DEBUG);
|
||||||
|
|
||||||
|
lwip_slip_ctx_t *slip_ctx = (lwip_slip_ctx_t *) slip_driver;
|
||||||
|
|
||||||
|
esp_netif_lwip_slip_output(slip_ctx, buffer, len);
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modem receive for glue logic
|
||||||
|
void esp_slip_modem_receive(esp_netif_t *esp_netif, void *buffer, size_t len)
|
||||||
|
{
|
||||||
|
ESP_LOGD(TAG, "%s", __func__);
|
||||||
|
ESP_LOG_BUFFER_HEXDUMP(TAG, buffer, len, ESP_LOG_DEBUG);
|
||||||
|
|
||||||
|
esp_netif_receive(esp_netif, buffer, len, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Post-attach handler for netif
|
||||||
|
static esp_err_t esp_slip_modem_post_attach(esp_netif_t *esp_netif, void *args)
|
||||||
|
{
|
||||||
|
esp_slip_modem_t *slip_modem = (esp_slip_modem_t *) args;
|
||||||
|
|
||||||
|
ESP_LOGD(TAG, "%s (netif: %p args: %p)", __func__, esp_netif, args);
|
||||||
|
|
||||||
|
const esp_netif_driver_ifconfig_t driver_ifconfig = {
|
||||||
|
.driver_free_rx_buffer = NULL,
|
||||||
|
.transmit = esp_slip_modem_transmit,
|
||||||
|
.handle = slip_modem->slip_driver,
|
||||||
|
};
|
||||||
|
|
||||||
|
slip_modem->base.netif = esp_netif;
|
||||||
|
ESP_ERROR_CHECK(esp_netif_set_driver_config(esp_netif, &driver_ifconfig));
|
||||||
|
|
||||||
|
esp_slip_driver_start(slip_modem);
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_slip_modem_set_default_handlers(esp_netif_t *esp_netif)
|
||||||
|
{
|
||||||
|
esp_err_t ret;
|
||||||
|
|
||||||
|
if (esp_netif == NULL) {
|
||||||
|
ESP_LOGE(TAG, "esp-netif handle can't be null");
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = esp_event_handler_register(SLIP_EVENT, SLIP_EVENT_START, esp_netif_action_start, esp_netif);
|
||||||
|
if (ret != ESP_OK) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = esp_event_handler_register(SLIP_EVENT, SLIP_EVENT_STOP, esp_netif_action_stop, esp_netif);
|
||||||
|
if (ret != ESP_OK) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
fail:
|
||||||
|
esp_eth_clear_default_handlers(esp_netif);
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_slip_modem_clear_default_handlers(void *esp_netif)
|
||||||
|
{
|
||||||
|
if (!esp_netif) {
|
||||||
|
ESP_LOGE(TAG, "esp-netif handle can't be null");
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
esp_event_handler_unregister(SLIP_EVENT, SLIP_EVENT_START, esp_netif_action_start);
|
||||||
|
esp_event_handler_unregister(SLIP_EVENT, SLIP_EVENT_STOP, esp_netif_action_stop);
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void esp_slip_modem_uart_rx_task(void *arg)
|
||||||
|
{
|
||||||
|
esp_slip_modem_t *slip_modem = (esp_slip_modem_t *) arg;
|
||||||
|
|
||||||
|
ESP_LOGD(TAG, "Start SLIP modem RX task (slip_modem %p slip_ctx %p filter: %p)", slip_modem, slip_modem->slip_driver, slip_modem->rx_filter);
|
||||||
|
ESP_LOGD(TAG, "Uart: %d, buffer: %p (%d bytes)", slip_modem->uart.uart_dev, slip_modem->buffer, slip_modem->buffer_len);
|
||||||
|
|
||||||
|
|
||||||
|
while (slip_modem->running == true) {
|
||||||
|
// Read data from the UART
|
||||||
|
int len = uart_read_bytes(slip_modem->uart.uart_dev, slip_modem->buffer, slip_modem->buffer_len, 1 / portTICK_RATE_MS);
|
||||||
|
|
||||||
|
if (len > 0) {
|
||||||
|
|
||||||
|
// Log slip RX data
|
||||||
|
ESP_LOGD(TAG, "rx %d bytes", len);
|
||||||
|
ESP_LOG_BUFFER_HEX_LEVEL(TAG, slip_modem->buffer, len, ESP_LOG_DEBUG);
|
||||||
|
|
||||||
|
// Ensure null termination
|
||||||
|
slip_modem->buffer[len] = '\0';
|
||||||
|
|
||||||
|
// Filter if provided
|
||||||
|
if ((slip_modem->rx_filter != NULL) && slip_modem->rx_filter(slip_modem->rx_filter_ctx, slip_modem->buffer, len)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pass received bytes in to slip interface
|
||||||
|
esp_netif_lwip_slip_input(slip_modem->slip_driver, slip_modem->buffer, len, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Yeild to allow other tasks to progress
|
||||||
|
vTaskDelay(1 * portTICK_PERIOD_MS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
12
examples/protocols/slip/slip_udp/CMakeLists.txt
Normal file
12
examples/protocols/slip/slip_udp/CMakeLists.txt
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# The following 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.5)
|
||||||
|
|
||||||
|
set(EXTRA_COMPONENT_DIRS
|
||||||
|
../components/slip_modem/
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||||
|
project(slip_client)
|
||||||
|
|
9
examples/protocols/slip/slip_udp/Makefile
Normal file
9
examples/protocols/slip/slip_udp/Makefile
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#
|
||||||
|
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||||
|
# project subdirectory.
|
||||||
|
#
|
||||||
|
|
||||||
|
PROJECT_NAME := slip_client
|
||||||
|
|
||||||
|
include $(IDF_PATH)/make/project.mk
|
||||||
|
|
57
examples/protocols/slip/slip_udp/README.md
Normal file
57
examples/protocols/slip/slip_udp/README.md
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
# SLIP device client
|
||||||
|
|
||||||
|
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
This provides SLIP support for connection to Contiki gateway devices, allowing the ESP32 to be used to bridge between low-power networks and IP (Wifi / Ethernet).
|
||||||
|
|
||||||
|
## How to use example
|
||||||
|
|
||||||
|
### Hardware Required
|
||||||
|
|
||||||
|
To run this example, you need an ESP32 dev board (e.g. ESP32-WROVER Kit) or ESP32 core board (e.g. ESP32-DevKitC).
|
||||||
|
For test purpose, you also need a SLIP capable gateway device, such as anything running [Contiki](https://github.com/contiki-os/contiki) gateway firmware.
|
||||||
|
You can also try other modules as long as they implement the SLIP protocol.
|
||||||
|
|
||||||
|
#### Pin Assignment
|
||||||
|
|
||||||
|
**Note:** The following pin assignments are used by default which can be changed in menuconfig.
|
||||||
|
|
||||||
|
| ESP32 | Gateway |
|
||||||
|
| ------ | -------------- |
|
||||||
|
| GPIO4 | RX |
|
||||||
|
| GPIO36 | TX |
|
||||||
|
| GND | GND |
|
||||||
|
| 3v3 | VCC |
|
||||||
|
|
||||||
|
### Configure the project
|
||||||
|
|
||||||
|
Open the project configuration menu (`idf.py menuconfig`). Then go into `Example Configuration` menu.
|
||||||
|
|
||||||
|
- Choose the RX and TX pins
|
||||||
|
|
||||||
|
For use in external projects `SLIP support` must be enabled under the `components/lwip` menu.
|
||||||
|
|
||||||
|
|
||||||
|
### Build and Flash
|
||||||
|
|
||||||
|
Run `idf.py -p PORT flash monitor` to build and flash the project..
|
||||||
|
|
||||||
|
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||||
|
|
||||||
|
See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
1. Invalid slip packets
|
||||||
|
|
||||||
|
Many slip devices use additional messages for things like ipv6 prefix configuration (or sending log messages over the SLIP serial port). This is supported in the driver through the use of an `rx_filter` function that is called on receipt of all packets and can be used to filter packets prior to passing them to the stack.
|
||||||
|
|
||||||
|
2. No packets received
|
||||||
|
|
||||||
|
The first layer to check is the serial port, you can enable debugging of the SLIP component by setting the global log level to `DEBUG`, or changing the slip component log levbel with `esp_log_level_set("esp-netif_lwip-slip", ESP_LOG_DEBUG);`
|
||||||
|
|
||||||
|
(For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you as soon as possible.)
|
7
examples/protocols/slip/slip_udp/main/CMakeLists.txt
Normal file
7
examples/protocols/slip/slip_udp/main/CMakeLists.txt
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# Slip client example
|
||||||
|
|
||||||
|
idf_component_register(
|
||||||
|
SRCS "slip_client_main.c"
|
||||||
|
INCLUDE_DIRS "."
|
||||||
|
REQUIRES esp_netif slip_modem
|
||||||
|
)
|
32
examples/protocols/slip/slip_udp/main/Kconfig.projbuild
Normal file
32
examples/protocols/slip/slip_udp/main/Kconfig.projbuild
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
menu "Example Configuration"
|
||||||
|
|
||||||
|
menu "UART Configuration"
|
||||||
|
config EXAMPLE_UART_TX_PIN
|
||||||
|
int "TXD Pin Number"
|
||||||
|
default 4
|
||||||
|
range 0 36
|
||||||
|
help
|
||||||
|
Pin number of UART TX.
|
||||||
|
|
||||||
|
config EXAMPLE_UART_RX_PIN
|
||||||
|
int "RXD Pin Number"
|
||||||
|
default 36
|
||||||
|
range 0 36
|
||||||
|
help
|
||||||
|
Pin number of UART RX.
|
||||||
|
|
||||||
|
config EXAMPLE_UART_BAUD
|
||||||
|
int "UART baud rate"
|
||||||
|
default 115200
|
||||||
|
help
|
||||||
|
Baud rate for UART communication
|
||||||
|
|
||||||
|
config EXAMPLE_UDP_PORT
|
||||||
|
int "Port for UDP echo server"
|
||||||
|
default 5678
|
||||||
|
help
|
||||||
|
Port for UDP echo server in example
|
||||||
|
|
||||||
|
endmenu
|
||||||
|
|
||||||
|
endmenu
|
4
examples/protocols/slip/slip_udp/main/component.mk
Normal file
4
examples/protocols/slip/slip_udp/main/component.mk
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
#
|
||||||
|
# "main" pseudo-component makefile.
|
||||||
|
#
|
||||||
|
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
229
examples/protocols/slip/slip_udp/main/slip_client_main.c
Normal file
229
examples/protocols/slip/slip_udp/main/slip_client_main.c
Normal file
@ -0,0 +1,229 @@
|
|||||||
|
/* SLIP Client Example
|
||||||
|
|
||||||
|
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, this
|
||||||
|
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
*/
|
||||||
|
#include <string.h>
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
#include "freertos/event_groups.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include "esp_system.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "esp_event.h"
|
||||||
|
#include "esp_netif.h"
|
||||||
|
#include "esp_netif_slip.h"
|
||||||
|
|
||||||
|
#include "lwip/sockets.h"
|
||||||
|
#include "lwip/dns.h"
|
||||||
|
#include "lwip/netdb.h"
|
||||||
|
|
||||||
|
#include "slip_modem.h"
|
||||||
|
|
||||||
|
static const char *TAG = "SLIP_EXAMPLE";
|
||||||
|
|
||||||
|
#define STACK_SIZE (10 * 1024)
|
||||||
|
#define PRIORITY 10
|
||||||
|
|
||||||
|
TaskHandle_t udp_rx_tx_handle;
|
||||||
|
|
||||||
|
static void udp_rx_tx_task(void *arg)
|
||||||
|
{
|
||||||
|
char addr_str[128];
|
||||||
|
uint8_t rx_buff[1024];
|
||||||
|
|
||||||
|
int sock = *(int *)arg;
|
||||||
|
|
||||||
|
struct sockaddr_in6 source_addr;
|
||||||
|
socklen_t socklen = sizeof(source_addr);
|
||||||
|
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "Starting node manager UDP task");
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
// Receive data
|
||||||
|
int len = recvfrom(sock, rx_buff, sizeof(rx_buff) - 1, 0, (struct sockaddr *)&source_addr, &socklen);
|
||||||
|
if (len < 0) {
|
||||||
|
ESP_LOGE(TAG, "recvfrom failed: errno %d", errno);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse out address to string
|
||||||
|
inet6_ntoa_r(source_addr.sin6_addr, addr_str, sizeof(addr_str) - 1);
|
||||||
|
|
||||||
|
// Force null termination of received data and print
|
||||||
|
rx_buff[len] = 0;
|
||||||
|
ESP_LOGI(TAG, "Received '%s' from '%s'", rx_buff, addr_str);
|
||||||
|
|
||||||
|
// Send data back
|
||||||
|
int err = sendto(sock, rx_buff, len, 0, (struct sockaddr *)&source_addr, socklen);
|
||||||
|
if (err < 0) {
|
||||||
|
ESP_LOGE(TAG, "sendto failed: errno %d", errno);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vTaskDelete(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t udp_rx_tx_init()
|
||||||
|
{
|
||||||
|
// Setup bind address
|
||||||
|
struct sockaddr_in6 dest_addr;
|
||||||
|
bzero(&dest_addr.sin6_addr.un, sizeof(dest_addr.sin6_addr.un));
|
||||||
|
dest_addr.sin6_family = AF_INET6;
|
||||||
|
dest_addr.sin6_port = htons(CONFIG_EXAMPLE_UDP_PORT);
|
||||||
|
|
||||||
|
// Create socket
|
||||||
|
int sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_IPV6);
|
||||||
|
if (sock < 0) {
|
||||||
|
ESP_LOGE(TAG, "Unable to create socket: errno %d", errno);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disable IPv4 and reuse address
|
||||||
|
int opt = 1;
|
||||||
|
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
|
||||||
|
setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt));
|
||||||
|
|
||||||
|
// Bind socket
|
||||||
|
int err = bind(sock, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
|
||||||
|
if (err < 0) {
|
||||||
|
ESP_LOGE(TAG, "Socket unable to bind: errno %d", errno);
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
ESP_LOGI(TAG, "Socket bound, port %d", CONFIG_EXAMPLE_UDP_PORT);
|
||||||
|
|
||||||
|
|
||||||
|
// Start UDP rx thread
|
||||||
|
xTaskCreate(udp_rx_tx_task, "udp_rx_tx", STACK_SIZE, &sock, PRIORITY, &udp_rx_tx_handle);
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write a prefix to the contiki slip device
|
||||||
|
static void slip_set_prefix(esp_netif_t *slip_netif)
|
||||||
|
{
|
||||||
|
uint8_t buff[10] = {0};
|
||||||
|
|
||||||
|
// Fetch the slip interface IP
|
||||||
|
const ip6_addr_t *addr = esp_slip_get_ip6(slip_netif);
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "%s: prefix set (%08x:%08x)", __func__,
|
||||||
|
lwip_ntohl(addr->addr[0]), lwip_ntohl(addr->addr[1]));
|
||||||
|
|
||||||
|
// Build slip set message
|
||||||
|
buff[0] = '!';
|
||||||
|
buff[1] = 'P';
|
||||||
|
for (int i = 0; i < 2; i++) {
|
||||||
|
for (int j = 0; j < 4; j++) {
|
||||||
|
buff[2 + i * 4 + j] = addr->addr[i] >> (j * 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write raw data out the slip interface
|
||||||
|
esp_netif_lwip_slip_raw_output(slip_netif, buff, 2 + 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
// slip_rx_filter filters incomming commands from the slip interface
|
||||||
|
// this implementation is designed for use with contiki slip devices
|
||||||
|
bool slip_rx_filter(void *ctx, uint8_t *data, uint32_t len)
|
||||||
|
{
|
||||||
|
|
||||||
|
esp_netif_t *slip_netif = (esp_netif_t *)ctx;
|
||||||
|
|
||||||
|
if (data[1] == '?') {
|
||||||
|
switch (data[2]) {
|
||||||
|
case 'P':
|
||||||
|
ESP_LOGI(TAG, "Prefix request");
|
||||||
|
slip_set_prefix(slip_netif);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
ESP_LOGI(TAG, "Unhandled request '%c'", data[2]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} else if (data[1] == '!') {
|
||||||
|
switch (data[2]) {
|
||||||
|
default:
|
||||||
|
ESP_LOGI(TAG, "Unhandled command '%c'", data[2]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialise the SLIP interface
|
||||||
|
esp_netif_t *slip_if_init()
|
||||||
|
{
|
||||||
|
ESP_LOGI(TAG, "Initialising SLIP interface");
|
||||||
|
|
||||||
|
esp_netif_config_t cfg = ESP_NETIF_DEFAULT_SLIP();
|
||||||
|
esp_netif_t *slip_netif = esp_netif_new(&cfg);
|
||||||
|
|
||||||
|
esp_netif_slip_config_t slip_config = {
|
||||||
|
.uart_dev = UART_NUM_2,
|
||||||
|
};
|
||||||
|
|
||||||
|
IP6_ADDR(&slip_config.addr,
|
||||||
|
lwip_htonl(0xfd000000),
|
||||||
|
lwip_htonl(0x00000000),
|
||||||
|
lwip_htonl(0x00000000),
|
||||||
|
lwip_htonl(0x000000001)
|
||||||
|
);
|
||||||
|
|
||||||
|
esp_netif_slip_set_params(slip_netif, &slip_config);
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "Initialising SLIP modem");
|
||||||
|
|
||||||
|
esp_slip_modem_config_t modem_cfg = {
|
||||||
|
.uart_dev = UART_NUM_2,
|
||||||
|
|
||||||
|
.uart_tx_pin = CONFIG_EXAMPLE_UART_TX_PIN,
|
||||||
|
.uart_rx_pin = CONFIG_EXAMPLE_UART_RX_PIN,
|
||||||
|
.uart_baud = CONFIG_EXAMPLE_UART_BAUD,
|
||||||
|
|
||||||
|
.rx_buffer_len = 1024,
|
||||||
|
|
||||||
|
.rx_filter = slip_rx_filter,
|
||||||
|
.rx_filter_ctx = slip_netif,
|
||||||
|
};
|
||||||
|
|
||||||
|
void *slip_modem = esp_slip_modem_create(slip_netif, &modem_cfg);
|
||||||
|
ESP_ERROR_CHECK(esp_netif_attach(slip_netif, slip_modem));
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "SLIP init complete");
|
||||||
|
|
||||||
|
return slip_netif;
|
||||||
|
}
|
||||||
|
|
||||||
|
void app_main(void)
|
||||||
|
{
|
||||||
|
// Setup networking
|
||||||
|
tcpip_adapter_init();
|
||||||
|
|
||||||
|
esp_log_level_set("*", ESP_LOG_DEBUG);
|
||||||
|
|
||||||
|
// Create event loop
|
||||||
|
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||||
|
|
||||||
|
// Setup slip interface
|
||||||
|
slip_if_init();
|
||||||
|
|
||||||
|
// Setup UDP loopback service
|
||||||
|
udp_rx_tx_init();
|
||||||
|
|
||||||
|
// Run
|
||||||
|
while (1) {
|
||||||
|
vTaskDelay(portTICK_PERIOD_MS * 10);
|
||||||
|
}
|
||||||
|
}
|
3
examples/protocols/slip/slip_udp/sdkconfig.defaults
Normal file
3
examples/protocols/slip/slip_udp/sdkconfig.defaults
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# Override some defaults to enable SLIP
|
||||||
|
CONFIG_LWIP_SLIP_SUPPORT=y
|
||||||
|
|
Reference in New Issue
Block a user