esp-netif: Added esp_netif slip support, slip_modem component and example

Merges https://github.com/espressif/esp-idf/pull/4985
This commit is contained in:
ryan
2020-05-21 17:55:56 +12:00
committed by David Cermak
parent 95b33895b8
commit 266be00254
26 changed files with 1471 additions and 16 deletions

View File

@@ -3,6 +3,8 @@ idf_component_register(SRCS "esp_netif_handlers.c"
"esp_netif_defaults.c"
"lwip/esp_netif_lwip.c"
"lwip/esp_netif_lwip_ppp.c"
"lwip/esp_netif_lwip_slip.c"
"lwip/esp_netif_lwip_slip_sio.c"
"loopback/esp_netif_loopback.c"
"lwip/esp_netif_lwip_defaults.c"
"lwip/esp_netif_sta_list.c"

View File

@@ -37,6 +37,8 @@ const esp_netif_inherent_config_t _g_esp_netif_inherent_eth_config = ESP_NETIF_I
const esp_netif_inherent_config_t _g_esp_netif_inherent_ppp_config = ESP_NETIF_INHERENT_DEFAULT_PPP();
const esp_netif_inherent_config_t _g_esp_netif_inherent_slip_config = ESP_NETIF_INHERENT_DEFAULT_SLIP();
const esp_netif_ip_info_t _g_esp_netif_soft_ap_ip = {
.ip = { .addr = ESP_IP4TOADDR( 192, 168, 4, 1) },
.gw = { .addr = ESP_IP4TOADDR( 192, 168, 4, 1) },

View File

@@ -70,7 +70,19 @@ extern "C" {
.lost_ip_event = IP_EVENT_PPP_LOST_IP, \
.if_key = "PPP_DEF", \
.if_desc = "ppp", \
.route_prio = 128 \
.route_prio = 20 \
};
#define ESP_NETIF_INHERENT_DEFAULT_SLIP() \
{ \
.flags = ESP_NETIF_FLAG_IS_SLIP, \
ESP_COMPILER_DESIGNATED_INIT_AGGREGATE_TYPE_EMPTY(mac) \
ESP_COMPILER_DESIGNATED_INIT_AGGREGATE_TYPE_EMPTY(ip_info) \
.get_ip_event = 0, \
.lost_ip_event = 0, \
.if_key = "SLIP_DEF", \
.if_desc = "slip", \
.route_prio = 20 \
};
/**
@@ -112,6 +124,18 @@ extern "C" {
.driver = NULL, \
.stack = ESP_NETIF_NETSTACK_DEFAULT_PPP, \
}
/**
* @brief Default configuration reference of SLIP client
*/
#define ESP_NETIF_DEFAULT_SLIP() \
{ \
.base = ESP_NETIF_BASE_DEFAULT_SLIP, \
.driver = NULL, \
.stack = ESP_NETIF_NETSTACK_DEFAULT_SLIP, \
}
/**
* @brief Default base config (esp-netif inherent) of WIFI STA
*/
@@ -132,11 +156,18 @@ extern "C" {
*/
#define ESP_NETIF_BASE_DEFAULT_PPP &_g_esp_netif_inherent_ppp_config
/**
* @brief Default base config (esp-netif inherent) of slip interface
*/
#define ESP_NETIF_BASE_DEFAULT_SLIP &_g_esp_netif_inherent_slip_config
#define ESP_NETIF_NETSTACK_DEFAULT_ETH _g_esp_netif_netstack_default_eth
#define ESP_NETIF_NETSTACK_DEFAULT_WIFI_STA _g_esp_netif_netstack_default_wifi_sta
#define ESP_NETIF_NETSTACK_DEFAULT_WIFI_AP _g_esp_netif_netstack_default_wifi_ap
#define ESP_NETIF_NETSTACK_DEFAULT_PPP _g_esp_netif_netstack_default_ppp
#define ESP_NETIF_NETSTACK_DEFAULT_SLIP _g_esp_netif_netstack_default_slip
//
// Include default network stacks configs
@@ -148,6 +179,7 @@ extern const esp_netif_netstack_config_t *_g_esp_netif_netstack_default_eth;
extern const esp_netif_netstack_config_t *_g_esp_netif_netstack_default_wifi_sta;
extern const esp_netif_netstack_config_t *_g_esp_netif_netstack_default_wifi_ap;
extern const esp_netif_netstack_config_t *_g_esp_netif_netstack_default_ppp;
extern const esp_netif_netstack_config_t *_g_esp_netif_netstack_default_slip;
//
// Include default common configs inherent to esp-netif
@@ -158,6 +190,7 @@ extern const esp_netif_inherent_config_t _g_esp_netif_inherent_sta_config;
extern const esp_netif_inherent_config_t _g_esp_netif_inherent_ap_config;
extern const esp_netif_inherent_config_t _g_esp_netif_inherent_eth_config;
extern const esp_netif_inherent_config_t _g_esp_netif_inherent_ppp_config;
extern const esp_netif_inherent_config_t _g_esp_netif_inherent_slip_config;
extern const esp_netif_ip_info_t _g_esp_netif_soft_ap_ip;

View File

@@ -0,0 +1,123 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#ifndef _ESP_NETIF_SLIP_H_
#define _ESP_NETIF_SLIP_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "driver/uart.h"
/** @brief SLIP event base */
ESP_EVENT_DECLARE_BASE(SLIP_EVENT);
typedef enum esp_netif_slip_event {
SLIP_EVENT_START = 1,
SLIP_EVENT_STOP = 2,
} esp_netif_slip_event_e;
/** @brief Forward declaration of lwip_slip_ctx for external use */
typedef struct lwip_slip_ctx lwip_slip_ctx_t;
/** @brief Configuration structure for SLIP network interface
*
*/
typedef struct esp_netif_slip_config {
ip6_addr_t addr; /* Local IP6 address */
uart_port_t uart_dev; /* UART device for reading and writing SLIP information, this must be initialised externally */
} esp_netif_slip_config_t;
/** @brief Sets common parameters for the supplied esp-netif.
*
* @param[in] esp_netif handle to slip esp-netif instance
* @param[in] config Pointer to SLIP netif configuration structure
*
* @return ESP_OK on success, ESP_ERR_ESP_NETIF_INVALID_PARAMS if netif null or not SLIP
*/
esp_err_t esp_netif_slip_set_params(esp_netif_t *netif, const esp_netif_slip_config_t *config);
/**
* @brief Data path API to input incoming packets to SLIP
*
* @param[in] esp_netif handle to slip esp-netif instance
* @param[in] buffer pointer to the incoming data
* @param[in] len length of the data
*
* @return
* - ESP_OK on success
*/
void esp_netif_lwip_slip_raw_input(esp_netif_t *netif, void *buffer, size_t len);
/**
* @brief Data path API to write raw packet ous the SLIP interface
*
* @param[in] esp_netif handle to slip esp-netif instance
* @param[in] buffer pointer to the outgoing data
* @param[in] len length of the data
*
* @return
* - ESP_OK on success
*/
void esp_netif_lwip_slip_raw_output(esp_netif_t *netif, void *buffer, size_t len);
/**
* @brief Fetch IP6 address attached to the SLIP interface
*
* @param[in] esp_netif handle to slip esp-netif instance
* @param[in] address index (unused)
*
* @return
* - pointer to the internal ip6 address object
*/
const ip6_addr_t *esp_slip_get_ip6(esp_netif_t *slip_netif);
/**
* @brief Fetch lwip_slip_ctx_t for esp_netif_t object
*
* This is required to support the wiring of esp_netif objects outside
* of this component.
*
* @return
* - lwip slip context
*/
lwip_slip_ctx_t *esp_netif_lwip_slip_get_ctx(esp_netif_t *slip_netif);
/**
* @brief Start the esp slip netif
*
* @param[in] esp_netif handle to slip esp-netif instance
*
* @return
* - ESP_OK on success
*/
esp_err_t esp_netif_start_slip(lwip_slip_ctx_t *slip_ctx);
/**
* @brief Stop the esp slip netif
*
* @param[in] esp_netif handle to slip esp-netif instance
*
* @return
* - ESP_OK on success
*/
esp_err_t esp_netif_stop_slip(lwip_slip_ctx_t *slip_ctx);
#endif

View File

@@ -138,7 +138,8 @@ typedef enum esp_netif_flags {
ESP_NETIF_FLAG_AUTOUP = 1 << 2,
ESP_NETIF_FLAG_GARP = 1 << 3,
ESP_NETIF_FLAG_EVENT_IP_MODIFIED = 1 << 4,
ESP_NETIF_FLAG_IS_PPP = 1 << 5
ESP_NETIF_FLAG_IS_PPP = 1 << 5,
ESP_NETIF_FLAG_IS_SLIP = 1 << 6,
} esp_netif_flags_t;
typedef enum esp_netif_ip_event_type {
@@ -163,7 +164,9 @@ typedef struct esp_netif_inherent_config {
const char * if_key; /*!< string identifier of the interface */
const char * if_desc; /*!< textual description of the interface */
int route_prio; /*!< numeric priority of this interface to become a default
routing if (if other netifs are up) */
routing if (if other netifs are up).
A higher value of route_prio indicates
a higher priority */
} esp_netif_inherent_config_t;
typedef struct esp_netif_config esp_netif_config_t;

View File

@@ -34,6 +34,7 @@
#endif
#include "esp_netif_lwip_ppp.h"
#include "esp_netif_lwip_slip.h"
#include "dhcpserver/dhcpserver.h"
#include "dhcpserver/dhcpserver_options.h"
@@ -149,6 +150,8 @@ static void esp_netif_set_default_netif(esp_netif_t *esp_netif)
{
if (esp_netif->is_ppp_netif) {
esp_netif_ppp_set_default_netif(esp_netif->netif_handle);
} else if (esp_netif->is_slip_netif) {
esp_netif_slip_set_default_netif(esp_netif->netif_handle);
} else {
netif_set_default(esp_netif->netif_handle);
}
@@ -346,6 +349,17 @@ static esp_err_t esp_netif_init_configuration(esp_netif_t *esp_netif, const esp_
esp_netif->is_ppp_netif = true;
// Make the netif handle (used for tcpip input function) the ppp_netif
esp_netif->netif_handle = esp_netif->lwip_ppp_ctx;
} else if (cfg->base->flags & ESP_NETIF_FLAG_IS_SLIP) {
esp_netif->lwip_slip_ctx = esp_netif_new_slip(esp_netif, esp_netif_stack_config);
if (esp_netif->lwip_slip_ctx == NULL) {
return ESP_ERR_ESP_NETIF_INIT_FAILED;
}
esp_netif->lwip_input_fn = esp_netif_stack_config->lwip_slip.input_fn;
esp_netif->is_slip_netif = true;
// Make the netif handle (used for tcpip input function) the slip_netif
esp_netif->netif_handle = esp_netif->lwip_slip_ctx;
} else {
if (esp_netif_stack_config-> lwip.init_fn) {
esp_netif->lwip_init_fn = esp_netif_stack_config->lwip.init_fn;
@@ -488,6 +502,8 @@ void esp_netif_destroy(esp_netif_t *esp_netif)
esp_netif_lwip_remove(esp_netif);
if (esp_netif->is_ppp_netif) {
esp_netif_destroy_ppp(esp_netif->netif_handle);
} else if (esp_netif->is_slip_netif) {
esp_netif_destroy_slip(esp_netif->netif_handle);
}
free(esp_netif->lwip_netif);
free(esp_netif->hostname);
@@ -539,7 +555,7 @@ esp_err_t esp_netif_set_mac(esp_netif_t *esp_netif, uint8_t mac[])
if (esp_netif == NULL || esp_netif->lwip_netif == NULL) {
return ESP_ERR_ESP_NETIF_IF_NOT_READY;
}
if (esp_netif->is_ppp_netif) {
if (esp_netif->is_ppp_netif || esp_netif->is_slip_netif) {
return ESP_ERR_NOT_SUPPORTED;
}
memcpy(esp_netif->mac, mac, NETIF_MAX_HWADDR_LEN);
@@ -552,7 +568,7 @@ esp_err_t esp_netif_get_mac(esp_netif_t *esp_netif, uint8_t mac[])
if (esp_netif == NULL || esp_netif->lwip_netif == NULL) {
return ESP_ERR_ESP_NETIF_IF_NOT_READY;
}
if (esp_netif->is_ppp_netif) {
if (esp_netif->is_ppp_netif || esp_netif->is_slip_netif) {
return ESP_ERR_NOT_SUPPORTED;
}
if (esp_netif_is_netif_up(esp_netif)) {
@@ -675,6 +691,13 @@ esp_err_t esp_netif_start(esp_netif_t *esp_netif)
esp_netif_update_default_netif(esp_netif, ESP_NETIF_STARTED);
}
return ret;
} else if (esp_netif->is_slip_netif) {
// No need to start SLIP interface in lwip thread
esp_err_t ret = esp_netif_start_slip(esp_netif->lwip_slip_ctx);
if (ret == ESP_OK) {
esp_netif_update_default_netif(esp_netif, ESP_NETIF_STARTED);
}
return ret;
}
return esp_netif_lwip_ipc_call(esp_netif_start_api, esp_netif, NULL);
}
@@ -724,6 +747,13 @@ esp_err_t esp_netif_stop(esp_netif_t *esp_netif)
esp_netif_update_default_netif(esp_netif, ESP_NETIF_STOPPED);;
}
return ret;
} else if (esp_netif->is_slip_netif) {
// No need to stop PPP interface in lwip thread
esp_err_t ret = esp_netif_stop_slip(esp_netif->lwip_slip_ctx);
if (ret == ESP_OK) {
esp_netif_update_default_netif(esp_netif, ESP_NETIF_STOPPED);;
}
return ret;
}
return esp_netif_lwip_ipc_call(esp_netif_stop_api, esp_netif, NULL);
}
@@ -957,7 +987,7 @@ esp_err_t esp_netif_dhcpc_start(esp_netif_t *esp_netif) _RUN_IN_LWIP_TASK_IF_SUP
esp_err_t esp_netif_dhcps_get_status(esp_netif_t *esp_netif, esp_netif_dhcp_status_t *status)
{
if (!esp_netif || (esp_netif->flags & ESP_NETIF_DHCP_CLIENT) || esp_netif->is_ppp_netif) {
if (!esp_netif || (esp_netif->flags & ESP_NETIF_DHCP_CLIENT) || esp_netif->is_ppp_netif || esp_netif->is_slip_netif) {
return ESP_ERR_INVALID_ARG;
}
@@ -967,7 +997,7 @@ esp_err_t esp_netif_dhcps_get_status(esp_netif_t *esp_netif, esp_netif_dhcp_stat
esp_err_t esp_netif_dhcpc_get_status(esp_netif_t *esp_netif, esp_netif_dhcp_status_t *status)
{
if (!esp_netif || (esp_netif->flags & ESP_NETIF_DHCP_SERVER) || esp_netif->is_ppp_netif) {
if (!esp_netif || (esp_netif->flags & ESP_NETIF_DHCP_SERVER) || esp_netif->is_ppp_netif || esp_netif->is_slip_netif) {
return ESP_ERR_INVALID_ARG;
}
@@ -1080,7 +1110,7 @@ esp_err_t esp_netif_get_hostname(esp_netif_t *esp_netif, const char **hostname)
{
ESP_LOGD(TAG, "%s esp_netif:%p", __func__, esp_netif);
if (!esp_netif || esp_netif->is_ppp_netif) {
if (!esp_netif || esp_netif->is_ppp_netif || esp_netif->is_slip_netif) {
return ESP_ERR_INVALID_ARG;
}
@@ -1339,7 +1369,7 @@ static esp_err_t esp_netif_set_dns_info_api(esp_netif_api_msg_t *msg)
esp_err_t esp_netif_set_dns_info(esp_netif_t *esp_netif, esp_netif_dns_type_t type, esp_netif_dns_info_t *dns)
{
if (esp_netif->is_ppp_netif) {
if (esp_netif->is_ppp_netif || esp_netif->is_slip_netif) {
return ESP_ERR_NOT_SUPPORTED;
}
esp_netif_dns_param_t dns_param = {
@@ -1379,7 +1409,7 @@ static esp_err_t esp_netif_get_dns_info_api(esp_netif_api_msg_t *msg)
esp_err_t esp_netif_get_dns_info(esp_netif_t *esp_netif, esp_netif_dns_type_t type, esp_netif_dns_info_t *dns)
{
if (esp_netif->is_ppp_netif) {
if (esp_netif->is_ppp_netif || esp_netif->is_slip_netif) {
const ip_addr_t *dns_ip = dns_getserver(type);
if (dns_ip == IP_ADDR_ANY) {
return ESP_ERR_ESP_NETIF_DNS_NOT_CONFIGURED;
@@ -1464,7 +1494,7 @@ esp_err_t esp_netif_get_ip6_linklocal(esp_netif_t *esp_netif, esp_ip6_addr_t *if
{
ESP_LOGV(TAG, "%s esp-netif:%p", __func__, esp_netif);
if (esp_netif == NULL || if_ip6 == NULL || esp_netif->is_ppp_netif) {
if (esp_netif == NULL || if_ip6 == NULL || esp_netif->is_ppp_netif || esp_netif->is_slip_netif) {
return ESP_ERR_ESP_NETIF_INVALID_PARAMS;
}
struct netif *p_netif = esp_netif->lwip_netif;

View File

@@ -54,7 +54,16 @@ static const struct esp_netif_netstack_config s_netif_config_ppp = {
}
};
static const struct esp_netif_netstack_config s_netif_config_slip = {
.lwip_slip = {
.slip_config = {
.uart_dev = UART_NUM_1,
}
}
};
const esp_netif_netstack_config_t *_g_esp_netif_netstack_default_eth = &s_eth_netif_config;
const esp_netif_netstack_config_t *_g_esp_netif_netstack_default_wifi_sta = &s_wifi_netif_config_sta;
const esp_netif_netstack_config_t *_g_esp_netif_netstack_default_wifi_ap = &s_wifi_netif_config_ap;
const esp_netif_netstack_config_t *_g_esp_netif_netstack_default_ppp = &s_netif_config_ppp;
const esp_netif_netstack_config_t *_g_esp_netif_netstack_default_ppp = &s_netif_config_ppp;
const esp_netif_netstack_config_t *_g_esp_netif_netstack_default_slip = &s_netif_config_slip;

View File

@@ -16,6 +16,7 @@
#include "esp_netif.h"
#include "esp_netif_ppp.h"
#include "esp_netif_slip.h"
#include "lwip/netif.h"
struct esp_netif_netstack_lwip_vanilla_config {
@@ -28,11 +29,17 @@ struct esp_netif_netstack_lwip_ppp_config {
esp_netif_ppp_config_t ppp_events;
};
struct esp_netif_netstack_lwip_slip_config {
void (*input_fn)(void *netif, void *buffer, size_t len, void *eb);
esp_netif_slip_config_t slip_config;
};
// LWIP netif specific network stack configuration
struct esp_netif_netstack_config {
union {
struct esp_netif_netstack_lwip_vanilla_config lwip;
struct esp_netif_netstack_lwip_ppp_config lwip_ppp;
struct esp_netif_netstack_lwip_slip_config lwip_slip;
};
};
@@ -58,8 +65,9 @@ typedef struct esp_netif_ip_lost_timer_s {
bool timer_running;
} esp_netif_ip_lost_timer_t;
// Forward declare the ppp context
// Forward declare the ppp and slip context
typedef struct lwip_ppp_ctx lwip_ppp_ctx_t;
typedef struct lwip_slip_ctx lwip_slip_ctx_t;
/**
* @brief Main esp-netif container with interface related information
@@ -73,10 +81,13 @@ struct esp_netif_obj {
// lwip netif related
struct netif *lwip_netif;
lwip_ppp_ctx_t *lwip_ppp_ctx;
lwip_slip_ctx_t *lwip_slip_ctx;
err_t (*lwip_init_fn)(struct netif*);
void (*lwip_input_fn)(void *input_netif_handle, void *buffer, size_t len, void *eb);
void * netif_handle; // netif impl context (either vanilla lwip-netif or ppp_pcb)
bool is_ppp_netif;
bool is_slip_netif;
// io driver related
void* driver_handle;

View File

@@ -252,9 +252,9 @@ esp_err_t esp_netif_ppp_set_auth(esp_netif_t *netif, esp_netif_auth_type_t autht
return ESP_OK;
}
void esp_netif_ppp_set_default_netif(lwip_ppp_ctx_t* ppp_ctx)
void esp_netif_slip_set_default_netif(lwip_ppp_ctx_t* slip_ctx)
{
ppp_set_default(ppp_ctx->ppp);
netif_set_default(slip_ctx->netif)
}
lwip_ppp_ctx_t* esp_netif_new_ppp(esp_netif_t *esp_netif, const esp_netif_netstack_config_t *esp_netif_stack_config)

View File

@@ -0,0 +1,245 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "lwip/dns.h"
#include "esp_netif.h"
#include "esp_log.h"
#include "esp_netif_net_stack.h"
#include "esp_event.h"
#include "esp_netif_slip.h"
#include "esp_netif_lwip_internal.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 "netif/slipif.h"
#include <string.h>
ESP_EVENT_DEFINE_BASE(SLIP_EVENT);
static const char *TAG = "esp-netif_lwip-slip";
/**
* @brief LWIP SLIP context object
*/
typedef struct lwip_slip_ctx {
//! ESP netif object
esp_netif_t *esp_netif;
//! SLIP interface IP6 address
ip6_addr_t addr;
//! UART device for underling SIO
uart_port_t uart_dev;
} lwip_slip_ctx_t;
/**
* @brief Create a new lwip slip interface
*/
lwip_slip_ctx_t *esp_netif_new_slip(esp_netif_t *esp_netif, const esp_netif_netstack_config_t *esp_netif_stack_config)
{
ESP_LOGD(TAG, "%s", __func__);
// Fetch netif and create context
struct netif *netif_impl = esp_netif->lwip_netif;
lwip_slip_ctx_t *slip_ctx = calloc(1, sizeof(lwip_slip_ctx_t));
if (slip_ctx == NULL) {
ESP_LOGE(TAG, "%s: cannot allocate lwip_slip_ctx_t", __func__);
return NULL;
}
ESP_LOGD(TAG, "%s: Initialising SLIP (esp_netif %p, lwip_netif %p, device: %d)", __func__, esp_netif, netif_impl, slip_ctx->uart_dev);
// Load config
const esp_netif_slip_config_t *slip_config = &esp_netif_stack_config->lwip_slip.slip_config;
// Attache network interface and uart device
slip_ctx->uart_dev = slip_config->uart_dev;
slip_ctx->esp_netif = esp_netif;
ESP_LOGI(TAG, "%s: Created SLIP interface (netif %p, slip_ctx: %p)", __func__, esp_netif, slip_ctx);
return slip_ctx;
}
/**
* @brief Creates new SLIP related structure
*/
esp_err_t esp_netif_start_slip(lwip_slip_ctx_t *slip_ctx)
{
ESP_LOGI(TAG, "%s: Starting SLIP connection (slip_ctx: %p, addr: %s)", __func__, slip_ctx, ip6addr_ntoa(&slip_ctx->addr));
struct netif *netif_impl = slip_ctx->esp_netif->lwip_netif;
// Store serial port number in net interface for SIO open command
netif_impl->state = (void *)slip_ctx->uart_dev;
// Attach interface
netif_add_noaddr(slip_ctx->esp_netif->lwip_netif, (void *)slip_ctx->uart_dev, &slipif_init, &ip_input);
// Bind address
int8_t addr_index = 0;
// Note that addr_set is used here as the address is statically configured
// rather than negotiated over the link
netif_ip6_addr_set(slip_ctx->esp_netif->lwip_netif, addr_index, &slip_ctx->addr);
netif_ip6_addr_set_state(slip_ctx->esp_netif->lwip_netif, addr_index, IP6_ADDR_VALID);
// Setup interface
netif_set_link_up(slip_ctx->esp_netif->lwip_netif);
netif_set_up(slip_ctx->esp_netif->lwip_netif);
return ESP_OK;
}
/**
* @brief Stops the SLIP interface
*/
esp_err_t esp_netif_stop_slip(lwip_slip_ctx_t *slip_ctx)
{
ESP_LOGI(TAG, "%s: Stopped SLIP connection: %p", __func__, slip_ctx);
// Stop interface
netif_set_link_down(slip_ctx->esp_netif->lwip_netif);
return ESP_OK;
}
/**
* @brief Sets paramaters for the supplied netif
*/
esp_err_t esp_netif_slip_set_params(esp_netif_t *netif, const esp_netif_slip_config_t *slip_config)
{
lwip_slip_ctx_t *slip_ctx = netif->lwip_slip_ctx;
ESP_LOGD(TAG, "%s (slip_ctx: %p)", __func__, slip_ctx);
if (netif_is_link_up(slip_ctx->esp_netif->lwip_netif)) {
ESP_LOGE(TAG, "Cannot set parameters while SLIP interface is running");
return ESP_ERR_INVALID_STATE;
}
memcpy(&slip_ctx->addr, &slip_config->addr, sizeof(ip6_addr_t));
slip_ctx->uart_dev = slip_config->uart_dev;
return ESP_OK;
}
/**
* @brief Write incoming serial data to the SLIP interface
*/
void esp_netif_lwip_slip_input(void *ctx, void *buffer, size_t len, void *eb)
{
lwip_slip_ctx_t *slip_ctx = (lwip_slip_ctx_t *)ctx;
ESP_LOGD(TAG, "%s", __func__);
ESP_LOG_BUFFER_HEXDUMP(TAG, buffer, len, ESP_LOG_DEBUG);
// Update slip netif with data
slipif_received_bytes(slip_ctx->esp_netif->lwip_netif, buffer, len);
// Process incoming bytes
for (int i = 0; i < len; i++) {
slipif_process_rxqueue(slip_ctx->esp_netif->lwip_netif);
}
}
/**
* @brief Write raw data out the SLIP interface
*/
void esp_netif_lwip_slip_output(lwip_slip_ctx_t *slip_ctx, void *buffer, size_t len)
{
struct netif *lwip_netif = slip_ctx->esp_netif->lwip_netif;
ESP_LOGD(TAG, "%s", __func__);
ESP_LOG_BUFFER_HEXDUMP(TAG, buffer, len, ESP_LOG_DEBUG);
struct pbuf p = {
.next = NULL,
.payload = buffer,
.tot_len = len,
.len = len,
};
// Call slip if output function to feed data out slip interface
lwip_netif->output_ip6(lwip_netif, &p, NULL);
}
/**
* @brief Write raw data out the SLIP interface
*/
void esp_netif_lwip_slip_raw_output(esp_netif_t *slip_netif, void *buffer, size_t len)
{
struct netif *lwip_netif = slip_netif->lwip_netif;
ESP_LOGD(TAG, "%s", __func__);
struct pbuf p = {
.next = NULL,
.payload = buffer,
.tot_len = len,
.len = len,
};
// Call slip if output function to feed data out slip interface
lwip_netif->output_ip6(lwip_netif, &p, NULL);
}
/**
* @brief Fetch pointer to internal slip_lwip_context
*
* This is required to support the wiring of esp_netif objects outside
* of this component.
*
* @return
* - lwip slip context
*/
lwip_slip_ctx_t *esp_netif_lwip_slip_get_ctx(esp_netif_t *slip_netif)
{
return slip_netif->lwip_slip_ctx;
}
/**
* @brief Destroys the SLIP context object
*/
void esp_netif_destroy_slip(lwip_slip_ctx_t *slip_ctx)
{
ESP_LOGD(TAG, "%s", __func__);
// Free base object
free(slip_ctx);
}
void esp_netif_slip_set_default_netif(lwip_slip_ctx_t *slip_ctx)
{
netif_set_default(slip_ctx->esp_netif->lwip_netif);
}
const ip6_addr_t *esp_slip_get_ip6(esp_netif_t *slip_netif)
{
return &slip_netif->lwip_slip_ctx->addr;
}

View File

@@ -0,0 +1,71 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _ESP_NETIF_LWIP_SLIP_H_
#define _ESP_NETIF_LWIP_SLIP_H_
typedef struct lwip_slip_ctx lwip_slip_ctx_t;
/**
* @brief Creates new SLIP related structure
*
* @param[in] esp_netif pointer esp-netif instance
* @param[in] stack_config TCP/IP stack configuration structure
*
* @return
* - pointer to slip-netif object on success
* - NULL otherwise
*/
lwip_slip_ctx_t *esp_netif_new_slip(esp_netif_t *esp_netif, const esp_netif_netstack_config_t *esp_netif_stack_config);
/**
* @brief Creates new SLIP related structure
*
* @param[in] slip pointer to internal slip context instance
*
* @return
* - ESP_OK on success
*/
esp_err_t esp_netif_start_slip(lwip_slip_ctx_t *slip);
/**
* @brief Destroys the slip netif object
*
* @param[in] slip pointer to internal slip context instance
*/
void esp_netif_destroy_slip(lwip_slip_ctx_t *slip);
/**
* @brief Stops the SLIP interface
*
* @param[in] slip pointer to internal slip context instance
*
* @return
* - ESP_OK on success
*/
esp_err_t esp_netif_stop_slip(lwip_slip_ctx_t *slip);
/**
* @brief Sets default netif for routing priority config
*
* @note: This function must be called from lwip thread
*
*/
void esp_netif_slip_set_default_netif(lwip_slip_ctx_t *slip_ctx);
#endif // _ESP_NETIF_LWIP_SLIP_H_

View File

@@ -0,0 +1,163 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <string.h>
#include "esp_log.h"
#include "driver/uart.h"
#include "lwip/opt.h"
#include "lwip/sio.h"
static const char *TAG = "esp-netif_lwip-slip_sio";
/***
* @brief slip IO (SIO) uart driver
*/
typedef struct lwip_slip_sio {
uart_port_t uart_dev;
bool blocking;
} lwip_slip_sio_t;
/***
* @brief Open a serial device for communication
*/
sio_fd_t sio_open(uint8_t devnum)
{
ESP_LOGD(TAG, "Opening device: %d\r\n", devnum);
// Create SIO object
lwip_slip_sio_t *slip_sio = malloc(sizeof(lwip_slip_sio_t));
// Store device num etc.
slip_sio->uart_dev = devnum;
slip_sio->blocking = false;
// Return SIO handle
return slip_sio;
}
/***
* @brief Send a single character to the serial device (blocking)
*/
void sio_send(uint8_t c, sio_fd_t fd)
{
lwip_slip_sio_t *slip_sio = ( lwip_slip_sio_t *) fd;
ESP_LOGD(TAG, "%s", __func__);
ESP_LOG_BUFFER_HEX_LEVEL(TAG, &c, 1, ESP_LOG_DEBUG);
int res = uart_write_bytes(slip_sio->uart_dev, (const char *)&c, 1);
if (res < 0) {
// Handle errors
ESP_LOGD(TAG, "%s: uart_write_bytes error %i", __func__, res);
}
}
/***
* @brief Write to the serial port (blocking)
*/
uint32_t sio_write(sio_fd_t fd, uint8_t *data, uint32_t len)
{
lwip_slip_sio_t *slip_sio = ( lwip_slip_sio_t *) fd;
ESP_LOGD(TAG, "%s", __func__);
ESP_LOG_BUFFER_HEX_LEVEL(TAG, data, len, ESP_LOG_DEBUG);
int32_t res = uart_write_bytes(slip_sio->uart_dev, (char *)data, len);
if (res < 0) {
// Handle errors
ESP_LOGD(TAG, "%s: uart_write_bytes error %i", __func__, res);
return 0;
}
return (uint32_t) res;
}
/***
* @brief Receive a single character from the serial device (blocking)
*/
uint8_t sio_recv(sio_fd_t fd)
{
lwip_slip_sio_t *slip_sio = ( lwip_slip_sio_t *) fd;
uint8_t b;
slip_sio->blocking = true;
while (slip_sio->blocking == true) {
int res = uart_read_bytes(slip_sio->uart_dev, &b, 1, portTICK_RATE_MS * 1);
if (res < 0) {
// Handle errors
ESP_LOGD(TAG, "%s: uart_read_bytes error %i", __func__, res);
return 0;
} else if (res == 1) {
break;
}
}
return b;
}
/***
* @brief Read from the serial port (blocking, abort with `sio_read_abort`)
*/
uint32_t sio_read(sio_fd_t fd, uint8_t *data, uint32_t len)
{
lwip_slip_sio_t *slip_sio = ( lwip_slip_sio_t *) fd;
int res = 0;
slip_sio->blocking = true;
while (slip_sio->blocking == true) {
res = uart_read_bytes(slip_sio->uart_dev, data, len, portTICK_RATE_MS * 1);
if (res < 0) {
// Handle errors
ESP_LOGD(TAG, "%s: uart_read_bytes error %i", __func__, res);
return 0;
} else if (res > 0) {
break;
}
}
return (uint32_t) res;
}
/***
* @brief Read from the serial port (non-blocking)
*/
uint32_t sio_tryread(sio_fd_t fd, uint8_t *data, uint32_t len)
{
lwip_slip_sio_t *slip_sio = ( lwip_slip_sio_t *) fd;
int res = uart_read_bytes(slip_sio->uart_dev, data, len, portTICK_RATE_MS * 1);
if (res < 0) {
ESP_LOGD(TAG, "%s: uart_read_bytes error %i", __func__, res);
return 0;
}
return (uint32_t)res;
}
/***
* @brief Abort a pending sio_read call
*/
void sio_read_abort(sio_fd_t fd)
{
lwip_slip_sio_t *slip_sio = ( lwip_slip_sio_t *) fd;
slip_sio->blocking = false;
}

View File

@@ -647,6 +647,28 @@ menu "LWIP"
help
Enable PPP debug log output
menuconfig LWIP_SLIP_SUPPORT
bool "Enable SLIP support (new/experimental)"
default n
help
Enable SLIP stack. Now only SLIP over serial is possible.
SLIP over serial support is experimental and unsupported.
config LWIP_SLIP_RX_FROM_ISR
bool "Enable LWIP SLIP interrupt mode"
depends on LWIP_SLIP_SUPPORT
default y
help
Enable interrupt functions in SLIP netif/slipif.h
config LWIP_SLIP_DEBUG_ON
bool "Enable SLIP debug log output"
depends on LWIP_SLIP_SUPPORT
default n
help
Enable SLIP debug log output
menu "ICMP"
config LWIP_MULTICAST_PING

View File

@@ -474,6 +474,27 @@
------------------------------------
*/
#ifdef CONFIG_LWIP_SLIP_SUPPORT
/**
* Enable SLIP receive from ISR functions
*/
#define SLIP_RX_FROM_ISR CONFIG_LWIP_SLIP_RX_FROM_ISR
/**
* PPP_DEBUG: Enable debugging for PPP.
*/
#define SLIP_DEBUG_ON CONFIG_LWIP_SLIP_DEBUG_ON
#if SLIP_DEBUG_ON
#define SLIP_DEBUG LWIP_DBG_ON
#else
#define SLIP_DEBUG LWIP_DBG_OFF
#endif
#endif
/*
------------------------------------
---------- Thread options ----------

View File

@@ -1,2 +1,3 @@
idf_component_register(SRCS "pppos_client_main.c"
INCLUDE_DIRS ".")
INCLUDE_DIRS ".")

View File

@@ -0,0 +1,8 @@
# SLIP Modem Component
idf_component_register(
SRCS "library/slip_modem.c"
INCLUDE_DIRS "include"
REQUIRES lwip esp_netif
)

View File

@@ -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);

View File

@@ -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);
}
}

View 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)

View 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

View 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.)

View File

@@ -0,0 +1,7 @@
# Slip client example
idf_component_register(
SRCS "slip_client_main.c"
INCLUDE_DIRS "."
REQUIRES esp_netif slip_modem
)

View 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

View File

@@ -0,0 +1,4 @@
#
# "main" pseudo-component makefile.
#
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)

View 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);
}
}

View File

@@ -0,0 +1,3 @@
# Override some defaults to enable SLIP
CONFIG_LWIP_SLIP_SUPPORT=y