Compare commits

..

25 Commits

Author SHA1 Message Date
9b48b0a5e0 update(esp_modem): Bump component version 2022-09-30 17:37:11 +02:00
25ac2d98c6 feat(esp_modem): Make some CMUX params compile-time configurable
* bool flag to defragment CMUX payload (useful for devices that send longer messages)
* int flag to force a delay between creating virtual terminals (useful for chatty devices that send some requests)
2022-09-30 17:36:38 +02:00
ce175df376 fix(esp_modem): CMUX to ignore MSC frames
Otherwise it gets confused with DISC frame and causes trouble when entering
CMUX mode (if device sends MSC requests)

Closes https://github.com/espressif/esp-protocols/issues/140
2022-09-30 17:36:38 +02:00
9d9d0db1ee Merge pull request #145 from david-cermak/bugfix/modem_console_flow_ctrl_config
fix(esp_modem): Console example to use configurable flow-ctrl
2022-09-30 16:56:22 +02:00
b704aaa33b Merge pull request #113 from david-cermak/feature/add_slip_example
Add protocols SLIP example
2022-09-30 16:39:30 +02:00
7a21db23ad fix(examples): Update SLIP example with error checks 2022-09-30 16:04:46 +02:00
fcd6f0bb14 feat(examples): Move the slip example to esp-netif folder
And update the slip_modem_get_ipv6_address() to return the address by
copy instead of reference (to employ return value optimizaiton where
possible)
2022-09-30 14:46:13 +02:00
52d7458b99 esp_netif: Migrate SLIP interface to user-space
* Original commit: espressif/esp-idf@83b8556f10
2022-09-30 14:46:13 +02:00
56cb58ced7 build system: re-add -Wno-format as private flag for some example components
* Original commit: espressif/esp-idf@e596c84d49
2022-09-30 14:46:13 +02:00
77a7538a02 docs: changes docs supported targets tables
* Original commit: espressif/esp-idf@c0568611dd
2022-09-30 14:46:13 +02:00
c8d0a13f0e ci: partially enable example build for esp32c2
* Original commit: espressif/esp-idf@f7be540222
2022-09-30 14:46:13 +02:00
582f5b5ff6 tools: Increase the minimal supported CMake version to 3.16
This updates the minimal supported version of CMake to 3.16, which in turn enables us to use more CMake features and have a cleaner build system.
This is the version that provides most new features and also the one we use in our latest docker image for CI.


* Original commit: espressif/esp-idf@facab8c5a7
2022-09-30 14:46:13 +02:00
06dd536d52 G0: target component (components/esp32*) doesn't depend on driver anymore
* Original commit: espressif/esp-idf@2571aaf3c9
2022-09-30 14:46:13 +02:00
e66b19c414 freertos: Remove legacy data types
This commit removes the usage of all legacy FreeRTOS data types that
are exposed via configENABLE_BACKWARD_COMPATIBILITY. Legacy types can
still be used by enabling CONFIG_FREERTOS_ENABLE_BACKWARD_COMPATIBILITY.


* Original commit: espressif/esp-idf@57fd78f5ba
2022-09-30 14:46:13 +02:00
0ad6cad8b2 Build & config: Remove leftover files from the unsupported "make" build system
* Original commit: espressif/esp-idf@766aa57084
2022-09-30 14:46:13 +02:00
ffa13e4b90 bugfix for ipv6_address_value_issue
Closes https://github.com/espressif/esp-idf/issues/5663


* Original commit: espressif/esp-idf@74236f0b29
2022-09-30 14:46:13 +02:00
0fc1fc6b23 Whitespace: Automated whitespace fixes (large commit)
Apply the pre-commit hook whitespace fixes to all files in the repo.

(Line endings, blank lines at end of file, trailing whitespace)


* Original commit: espressif/esp-idf@66fb5a29bb
2022-09-30 14:46:13 +02:00
f1d1d79daf esp-netif: Fix SLIP interface to start with correct IPv6 addr
Merges https://github.com/espressif/esp-idf/pull/4985


* Original commit: espressif/esp-idf@5dae28069f
2022-09-30 14:46:13 +02:00
36d0d32b35 esp-netif: removing SLIP related events as the slip-modem set state synchronously
* Original commit: espressif/esp-idf@bb9a7356ac
2022-09-30 14:46:13 +02:00
3bf488eb86 esp-netif: SLIP interface refactor to isolate interface from drivers
* Original commit: espressif/esp-idf@1a41545c3e
2022-09-30 14:46:13 +02:00
061885ad23 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
2022-09-30 14:46:13 +02:00
ab70791625 Merge pull request #147 from tore-espressif/feature/esp_modem/c_error
esp_modem: Allow C API extensions (IDFGH-8368)
2022-09-30 14:25:21 +02:00
62cb235aa9 esp_modem: Allow error handler register in C
C++ API offers interface to register error callback.
C API isn't flexible enough, so we offer conversion function between C++ and C enums.
2022-09-30 11:55:09 +02:00
07a347f907 fix(esp_modem): Fix CRLF endlines in examples 2022-09-20 08:20:05 +02:00
d9c9681094 fix(esp_modem): Console example to use configurable flow-ctrl 2022-09-20 08:18:53 +02:00
20 changed files with 1314 additions and 193 deletions

View File

@ -0,0 +1,28 @@
menu "esp-modem"
config ESP_MODEM_CMUX_DEFRAGMENT_PAYLOAD
bool "Defragment CMUX messages internally"
default y
help
If enabled (default), the esp-modem automatically defragments CMUX messages
to only pass the completed CMUX message to higher layers.
This is useful for messages in command mode (if they're received fragmented).
It's not a problem for messages in data mode as the upper layer (PPP protocol)
defines message boundaries.
Keep the default to true for most cases (as most devices use simply 1 byte CMUX
length, as the internal Rx buffer of size >= 256 bytes won't overflow)
Set to false if your devices uses 2 byte CMUX payload (e.g. A7672S).
The operation would work without an issue in data mode, but some replies
in command mode might come fragmented in rare cases so might need to retry
AT commands.
config ESP_MODEM_CMUX_DELAY_AFTER_DLCI_SETUP
int "Delay in ms to wait before creating another virtual terminal"
default 0
help
Some devices might need a pause before sending SABM command that creates
virtual terminal. This delay applies only to establishing a CMUX mode.
The typical reason for failing SABM request without a delay is that
some devices (SIM800) send MSC requests just after opening a new DLCI.
endmenu

View File

@ -69,10 +69,24 @@ after creating multiple virtual terminals, designating some of them solely to da
### DTE's
Currently we support only UART, but modern modules support other communication interfaces, such as USB, SPI.
Currently, we support only UART (and USB as a preview feature), but modern modules support other communication interfaces, such as USB, SPI.
### Other devices
Adding a new device is a must-have requirement for the esp-modem component. Different modules support different commands,
or some commands might have a different implementation. Adding a new device means to provide a new implementation
as a class derived from `GenericModule`, where we could add new commands or modify the existing ones.
## Configuration
Modem abstraction is configurable both compile-time and run-time.
### Component Kconfig
Compile-time configuration is provided using menuconfig. Please check the description for the CMUX mode configuration options.
### Runtime configuration
Is defined using standard configuration structures for `DTE` and `DCE` objects separately. Please find documentation of
* :cpp:class:`esp_modem_dte_config_t`
* :cpp:class:`esp_modem_dce_config_t`

View File

@ -1,176 +1,190 @@
menu "Example Configuration"
choice EXAMPLE_SERIAL_CONFIG
prompt "Type of serial connection to the modem"
default EXAMPLE_SERIAL_CONFIG_UART
config EXAMPLE_SERIAL_CONFIG_UART
bool "UART"
help
Connect to modem via UART.
config EXAMPLE_SERIAL_CONFIG_USB
bool "USB"
depends on IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
help
Connect to modem via USB (CDC-ACM class). For IDF version >= 4.4.
endchoice
choice EXAMPLE_MODEM_DEVICE
prompt "Choose supported modem device (DCE)"
default EXAMPLE_MODEM_DEVICE_BG96
help
Select modem device connected to the ESP DTE.
config EXAMPLE_MODEM_DEVICE_SHINY
bool "SHINY"
help
SHINY is a GSM/GPRS module.
It supports SHINY.
config EXAMPLE_MODEM_DEVICE_SIM800
bool "SIM800"
help
SIMCom SIM800L is a GSM/GPRS module.
It supports Quad-band 850/900/1800/1900MHz.
config EXAMPLE_MODEM_DEVICE_BG96
bool "BG96"
help
Quectel BG96 is a series of LTE Cat M1/Cat NB1/EGPRS module.
config EXAMPLE_MODEM_DEVICE_SIM7000
bool "SIM7000"
help
SIM7000 is a Multi-Band LTE-FDD and GSM/GPRS/EDGE module.
config EXAMPLE_MODEM_DEVICE_SIM7070
bool "SIM7070"
help
SIM7070 is Multi-Band CAT M and NB IoT module.
config EXAMPLE_MODEM_DEVICE_SIM7600
bool "SIM7600"
help
SIM7600 is a Multi-Band LTE-TDD/LTE-FDD/HSPA+ and GSM/GPRS/EDGE module.
endchoice
config EXAMPLE_MODEM_PPP_APN
string "Set MODEM APN"
default "internet"
help
Set APN (Access Point Name), a logical name to choose data network
config EXAMPLE_MODEM_PPP_AUTH_USERNAME
string "Set username for authentication"
default "espressif"
depends on !EXAMPLE_MODEM_PPP_AUTH_NONE
help
Set username for PPP Authentication.
config EXAMPLE_MODEM_PPP_AUTH_PASSWORD
string "Set password for authentication"
default "esp32"
depends on !EXAMPLE_MODEM_PPP_AUTH_NONE
help
Set password for PPP Authentication.
config EXAMPLE_MODEM_PPP_AUTH_NONE
bool "Skip PPP authentication"
default n
help
Set to true for the PPP client to skip authentication
config EXAMPLE_SEND_MSG
bool "Short message (SMS)"
default n
help
Select this, the modem will send a short message before power off.
if EXAMPLE_SEND_MSG
config EXAMPLE_SEND_MSG_PEER_PHONE_NUMBER
string "Peer Phone Number (with area code)"
default "+8610086"
help
Enter the peer phone number that you want to send message to.
endif
config EXAMPLE_NEED_SIM_PIN
bool "SIM PIN needed"
default n
help
Enable to set SIM PIN before starting the example
config EXAMPLE_SIM_PIN
string "Set SIM PIN"
default "1234"
depends on EXAMPLE_NEED_SIM_PIN
help
Pin to unlock the SIM
menu "UART Configuration"
config EXAMPLE_MODEM_UART_TX_PIN
int "TXD Pin Number"
default 25
range 0 31
help
Pin number of UART TX.
config EXAMPLE_MODEM_UART_RX_PIN
int "RXD Pin Number"
default 26
range 0 31
help
Pin number of UART RX.
config EXAMPLE_MODEM_UART_RTS_PIN
int "RTS Pin Number"
default 27
range 0 31
help
Pin number of UART RTS.
config EXAMPLE_MODEM_UART_CTS_PIN
int "CTS Pin Number"
default 23
range 0 31
help
Pin number of UART CTS.
config EXAMPLE_MODEM_UART_EVENT_TASK_STACK_SIZE
int "UART Event Task Stack Size"
range 2000 6000
default 2048
help
Stack size of UART event task.
config EXAMPLE_MODEM_UART_EVENT_TASK_PRIORITY
int "UART Event Task Priority"
range 3 22
default 5
help
Priority of UART event task.
config EXAMPLE_MODEM_UART_EVENT_QUEUE_SIZE
int "UART Event Queue Size"
range 10 40
default 30
help
Length of UART event queue.
config EXAMPLE_MODEM_UART_PATTERN_QUEUE_SIZE
int "UART Pattern Queue Size"
range 10 40
default 20
help
Length of UART pattern queue.
config EXAMPLE_MODEM_UART_TX_BUFFER_SIZE
int "UART TX Buffer Size"
range 256 2048
default 512
help
Buffer size of UART TX buffer.
config EXAMPLE_MODEM_UART_RX_BUFFER_SIZE
int "UART RX Buffer Size"
range 256 2048
default 1024
help
Buffer size of UART RX buffer.
endmenu
endmenu
menu "Example Configuration"
choice EXAMPLE_SERIAL_CONFIG
prompt "Type of serial connection to the modem"
default EXAMPLE_SERIAL_CONFIG_UART
config EXAMPLE_SERIAL_CONFIG_UART
bool "UART"
help
Connect to modem via UART.
config EXAMPLE_SERIAL_CONFIG_USB
bool "USB"
depends on IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
help
Connect to modem via USB (CDC-ACM class). For IDF version >= 4.4.
endchoice
choice EXAMPLE_MODEM_DEVICE
prompt "Choose supported modem device (DCE)"
default EXAMPLE_MODEM_DEVICE_BG96
help
Select modem device connected to the ESP DTE.
config EXAMPLE_MODEM_DEVICE_SHINY
bool "SHINY"
help
SHINY is a GSM/GPRS module.
It supports SHINY.
config EXAMPLE_MODEM_DEVICE_SIM800
bool "SIM800"
help
SIMCom SIM800L is a GSM/GPRS module.
It supports Quad-band 850/900/1800/1900MHz.
config EXAMPLE_MODEM_DEVICE_BG96
bool "BG96"
help
Quectel BG96 is a series of LTE Cat M1/Cat NB1/EGPRS module.
config EXAMPLE_MODEM_DEVICE_SIM7000
bool "SIM7000"
help
SIM7000 is a Multi-Band LTE-FDD and GSM/GPRS/EDGE module.
config EXAMPLE_MODEM_DEVICE_SIM7070
bool "SIM7070"
help
SIM7070 is Multi-Band CAT M and NB IoT module.
config EXAMPLE_MODEM_DEVICE_SIM7600
bool "SIM7600"
help
SIM7600 is a Multi-Band LTE-TDD/LTE-FDD/HSPA+ and GSM/GPRS/EDGE module.
endchoice
config EXAMPLE_MODEM_PPP_APN
string "Set MODEM APN"
default "internet"
help
Set APN (Access Point Name), a logical name to choose data network
config EXAMPLE_MODEM_PPP_AUTH_USERNAME
string "Set username for authentication"
default "espressif"
depends on !EXAMPLE_MODEM_PPP_AUTH_NONE
help
Set username for PPP Authentication.
config EXAMPLE_MODEM_PPP_AUTH_PASSWORD
string "Set password for authentication"
default "esp32"
depends on !EXAMPLE_MODEM_PPP_AUTH_NONE
help
Set password for PPP Authentication.
config EXAMPLE_MODEM_PPP_AUTH_NONE
bool "Skip PPP authentication"
default n
help
Set to true for the PPP client to skip authentication
config EXAMPLE_SEND_MSG
bool "Short message (SMS)"
default n
help
Select this, the modem will send a short message before power off.
if EXAMPLE_SEND_MSG
config EXAMPLE_SEND_MSG_PEER_PHONE_NUMBER
string "Peer Phone Number (with area code)"
default "+8610086"
help
Enter the peer phone number that you want to send message to.
endif
config EXAMPLE_NEED_SIM_PIN
bool "SIM PIN needed"
default n
help
Enable to set SIM PIN before starting the example
config EXAMPLE_SIM_PIN
string "Set SIM PIN"
default "1234"
depends on EXAMPLE_NEED_SIM_PIN
help
Pin to unlock the SIM
choice EXAMPLE_FLOW_CONTROL
bool "Set preferred modem control flow"
default EXAMPLE_FLOW_CONTROL_NONE
help
Set the modem's preferred control flow
config EXAMPLE_FLOW_CONTROL_NONE
bool "No control flow"
config EXAMPLE_FLOW_CONTROL_SW
bool "SW control flow"
config EXAMPLE_FLOW_CONTROL_HW
bool "HW control flow"
endchoice
menu "UART Configuration"
config EXAMPLE_MODEM_UART_TX_PIN
int "TXD Pin Number"
default 25
range 0 31
help
Pin number of UART TX.
config EXAMPLE_MODEM_UART_RX_PIN
int "RXD Pin Number"
default 26
range 0 31
help
Pin number of UART RX.
config EXAMPLE_MODEM_UART_RTS_PIN
int "RTS Pin Number"
default 27
range 0 31
help
Pin number of UART RTS.
config EXAMPLE_MODEM_UART_CTS_PIN
int "CTS Pin Number"
default 23
range 0 31
help
Pin number of UART CTS.
config EXAMPLE_MODEM_UART_EVENT_TASK_STACK_SIZE
int "UART Event Task Stack Size"
range 2000 6000
default 2048
help
Stack size of UART event task.
config EXAMPLE_MODEM_UART_EVENT_TASK_PRIORITY
int "UART Event Task Priority"
range 3 22
default 5
help
Priority of UART event task.
config EXAMPLE_MODEM_UART_EVENT_QUEUE_SIZE
int "UART Event Queue Size"
range 10 40
default 30
help
Length of UART event queue.
config EXAMPLE_MODEM_UART_PATTERN_QUEUE_SIZE
int "UART Pattern Queue Size"
range 10 40
default 20
help
Length of UART pattern queue.
config EXAMPLE_MODEM_UART_TX_BUFFER_SIZE
int "UART TX Buffer Size"
range 256 2048
default 512
help
Buffer size of UART TX buffer.
config EXAMPLE_MODEM_UART_RX_BUFFER_SIZE
int "UART RX Buffer Size"
range 256 2048
default 1024
help
Buffer size of UART RX buffer.
endmenu
endmenu

View File

@ -26,6 +26,14 @@
#include "console_helper.hpp"
#include "my_module_dce.hpp"
#if defined(CONFIG_EXAMPLE_FLOW_CONTROL_NONE)
#define EXAMPLE_FLOW_CONTROL ESP_MODEM_FLOW_CONTROL_NONE
#elif defined(CONFIG_EXAMPLE_FLOW_CONTROL_SW)
#define EXAMPLE_FLOW_CONTROL ESP_MODEM_FLOW_CONTROL_SW
#elif defined(CONFIG_EXAMPLE_FLOW_CONTROL_HW)
#define EXAMPLE_FLOW_CONTROL ESP_MODEM_FLOW_CONTROL_HW
#endif
#define CHECK_ERR(cmd, success_action) do { \
auto err = cmd; \
if (err == command_result::OK) { \
@ -69,7 +77,7 @@ extern "C" void app_main(void)
dte_config.uart_config.rx_io_num = CONFIG_EXAMPLE_MODEM_UART_RX_PIN;
dte_config.uart_config.rts_io_num = CONFIG_EXAMPLE_MODEM_UART_RTS_PIN;
dte_config.uart_config.cts_io_num = CONFIG_EXAMPLE_MODEM_UART_CTS_PIN;
dte_config.uart_config.flow_control = ESP_MODEM_FLOW_CONTROL_HW;
dte_config.uart_config.flow_control = EXAMPLE_FLOW_CONTROL;
dte_config.uart_config.rx_buffer_size = CONFIG_EXAMPLE_MODEM_UART_RX_BUFFER_SIZE;
dte_config.uart_config.tx_buffer_size = CONFIG_EXAMPLE_MODEM_UART_TX_BUFFER_SIZE;
dte_config.uart_config.event_queue_size = CONFIG_EXAMPLE_MODEM_UART_EVENT_QUEUE_SIZE;

View File

@ -1,4 +1,4 @@
version: "0.1.23"
version: "0.1.24"
description: esp modem
url: https://github.com/espressif/esp-protocols/tree/master/components/esp_modem
dependencies:

View File

@ -60,6 +60,23 @@ typedef enum esp_modem_dce_device
ESP_MODEM_DCE_SIM800,
} esp_modem_dce_device_t;
/**
* @brief Terminal errors
*/
typedef enum esp_modem_terminal_error
{
ESP_MODEM_TERMINAL_BUFFER_OVERFLOW,
ESP_MODEM_TERMINAL_CHECKSUM_ERROR,
ESP_MODEM_TERMINAL_UNEXPECTED_CONTROL_FLOW,
ESP_MODEM_TERMINAL_DEVICE_GONE,
ESP_MODEM_TERMINAL_UNKNOWN_ERROR,
} esp_modem_terminal_error_t;
/**
* @brief Terminal error callback
*/
typedef void (*esp_modem_terminal_error_cbt)(esp_modem_terminal_error_t);
/**
* @brief Create a generic DCE handle for new modem API
*
@ -90,6 +107,15 @@ esp_modem_dce_t *esp_modem_new_dev(esp_modem_dce_device_t module, const esp_mode
*/
void esp_modem_destroy(esp_modem_dce_t * dce);
/**
* @brief Set DTE's error callback
*
* @param dce Modem DCE handle
* @param[in] err_cb Error callback
* @return ESP_OK on success, ESP_FAIL on failure
*/
esp_err_t esp_modem_set_error_cb(esp_modem_dce_t * dce, esp_modem_terminal_error_cbt err_cb);
/**
* @brief Set operation mode for this DCE
* @param dce Modem DCE handle

View File

@ -12,6 +12,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @file c_api_wrapper.hpp
* @brief Collection of C API wrappers
*
* This file is located in include/esp_private because it is not intended for users,
* but rather for esp_modem C extension developers.
*
* The C extension API must provide a 'factory function' that returns initialized pointer to esp_modem_dce_wrap.
* Helper functions provided below, can be used for conversion between C++ enum classes and standard C enums.
*/
#pragma once
#include "cxx_include/esp_modem_dce_factory.hpp"
@ -23,6 +34,8 @@ struct esp_modem_dce_wrap { // need to mimic the polymorphic dispatch as CPP use
enum class modem_wrap_dte_type { UART, VFS, USB } dte_type;
dce_factory::ModemType modem_type;
DCE *dce;
std::shared_ptr<DTE> dte;
esp_modem_dce_wrap() : dce(nullptr), dte(nullptr) {}
};
inline dce_factory::ModemType convert_modem_enum(esp_modem_dce_device_t module)
@ -43,3 +56,32 @@ inline dce_factory::ModemType convert_modem_enum(esp_modem_dce_device_t module)
return esp_modem::dce_factory::ModemType::GenericModule;
}
}
inline esp_modem_terminal_error_t convert_terminal_error_enum(terminal_error err)
{
switch (err) {
case terminal_error::BUFFER_OVERFLOW:
return ESP_MODEM_TERMINAL_BUFFER_OVERFLOW;
case terminal_error::CHECKSUM_ERROR:
return ESP_MODEM_TERMINAL_CHECKSUM_ERROR;
case terminal_error::UNEXPECTED_CONTROL_FLOW:
return ESP_MODEM_TERMINAL_UNEXPECTED_CONTROL_FLOW;
case terminal_error::DEVICE_GONE:
return ESP_MODEM_TERMINAL_DEVICE_GONE;
default:
return ESP_MODEM_TERMINAL_UNKNOWN_ERROR;
}
}
inline esp_err_t command_response_to_esp_err(command_result res)
{
switch (res) {
case command_result::OK:
return ESP_OK;
case command_result::FAIL:
return ESP_FAIL;
case command_result::TIMEOUT:
return ESP_ERR_TIMEOUT;
}
return ESP_ERR_INVALID_ARG;
}

View File

@ -36,19 +36,6 @@ size_t strlcpy(char *dest, const char *src, size_t len);
// C API definitions
using namespace esp_modem;
static inline esp_err_t command_response_to_esp_err(command_result res)
{
switch (res) {
case command_result::OK:
return ESP_OK;
case command_result::FAIL:
return ESP_FAIL;
case command_result::TIMEOUT:
return ESP_ERR_TIMEOUT;
}
return ESP_ERR_INVALID_ARG;
}
extern "C" esp_modem_dce_t *esp_modem_new_dev(esp_modem_dce_device_t module, const esp_modem_dte_config_t *dte_config, const esp_modem_dce_config_t *dce_config, esp_netif_t *netif)
{
auto dce_wrap = new (std::nothrow) esp_modem_dce_wrap;
@ -60,6 +47,7 @@ extern "C" esp_modem_dce_t *esp_modem_new_dev(esp_modem_dce_device_t module, con
delete dce_wrap;
return nullptr;
}
dce_wrap->dte = dte;
dce_factory::Factory f(convert_modem_enum(module));
dce_wrap->dce = f.build(dce_config, std::move(dte), netif);
if (dce_wrap->dce == nullptr) {
@ -84,6 +72,22 @@ extern "C" void esp_modem_destroy(esp_modem_dce_t *dce_wrap)
}
}
extern "C" esp_err_t esp_modem_set_error_cb(esp_modem_dce_t * dce_wrap, esp_modem_terminal_error_cbt err_cb)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr || dce_wrap->dte == nullptr) {
return ESP_ERR_INVALID_ARG;
}
if (err_cb) {
dce_wrap->dte->set_error_cb([err_cb](terminal_error err) {
err_cb(convert_terminal_error_enum(err));
});
} else {
dce_wrap->dte->set_error_cb(nullptr);
}
return ESP_OK;
}
extern "C" esp_err_t esp_modem_sync(esp_modem_dce_t *dce_wrap)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {

View File

@ -17,15 +17,18 @@
#include <cxx_include/esp_modem_cmux.hpp>
#include "cxx_include/esp_modem_dte.hpp"
#include "esp_log.h"
#include "sdkconfig.h"
using namespace esp_modem;
#ifdef CONFIG_ESP_MODEM_CMUX_DEFRAGMENT_PAYLOAD
/**
* @brief Define this to defragment partially received data of CMUX payload
* This is useful if upper layers expect the entire payload available
* for parsing.
*/
#define DEFRAGMENT_CMUX_PAYLOAD
#endif
#define EA 0x01 /* Extension bit */
#define CR 0x02 /* Command / Response */
@ -143,6 +146,10 @@ void CMux::data_available(uint8_t *data, size_t len)
#endif
}
} else if ((type&FT_UIH) == FT_UIH && dlci == 0) { // notify the internal DISC command
if (len > 0 && (data[0] & 0xE1) == 0xE1) {
// Not a DISC, ignore (MSC frame)
return;
}
Scoped<Lock> l(lock);
sabm_ack = dlci;
}
@ -286,7 +293,7 @@ bool CMux::on_cmux_data(uint8_t *data, size_t actual_len)
actual_len = term->read(data, data_to_read);
#else
data = buffer.get();
actual_len = term->read(data, buffer_size);
actual_len = term->read(data, buffer.size);
#endif
}
ESP_LOG_BUFFER_HEXDUMP("CMUX Received", data, actual_len, ESP_LOG_VERBOSE);
@ -385,6 +392,9 @@ bool CMux::init()
return false;
}
}
if (i > 1) { // wait for each virtual terminal to settle MSC (no need for control term, DLCI=0)
usleep(CONFIG_ESP_MODEM_CMUX_DELAY_AFTER_DLCI_SETUP * 1'000);
}
}
return true;
}

View File

@ -0,0 +1,6 @@
# 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.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(slip_client)

View File

@ -0,0 +1,88 @@
| Supported Targets | ESP32 | ESP32-C3 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- |
# 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 ESP platform board to be used to bridge between low-power networks and IP (Wifi / Ethernet).
This example also demonstrates creating custom network interfaces, including UART drivers and lwIP netif layers, and attaching them to the standard `esp_netif` component, so the generic system interfaces can still use the common approach of listing all interfaces, updating states, posting events and handling routing priorities. Please refer to the implementation of [slip_modem](components/slip_modem) component for more details.
## 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 (e.g. linux device with slip module loaded)
#### Setup a test SLIP device
It is possible to configure any device with linux and a serial interface
(e.g. raspberry PI or a PC with USB to serial bridge) to enable SLIP interface.
To test this example with such device, please follow these steps:
- Configure IPv4 mode in the example configuration menu
- Setup SLIP interface
```
slattach -v -L -s 115200 -p slip /dev/ttyAMA0
```
where the `/dev/ttyAMA0` is the device's serial port
- Configure IP addresses
```
ifconfig sl0 10.0.0.1 dstaddr 10.0.0.2
```
where the `10.0.0.2` is IPv4 address of the ESP platform board
- Send and receive back UDP packets, as the example implements UDP echo server
```
nc -u 10.0.0.2 5678
```
#### Pin Assignment
**Note:** The following pin assignments are used by default which can be changed in menuconfig.
| ESP32 | Gateway |
| ------ | -------------- |
| GPIO25 | RX |
| GPIO26 | 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
- Choose port number and IP protocol for socket udp server
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,8 @@
# SLIP Modem Component
idf_component_register(
SRCS "library/slip_modem.c" "library/slip_modem_netif.c"
INCLUDE_DIRS "include"
REQUIRES esp_netif driver
)
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")

View File

@ -0,0 +1,95 @@
/*
* SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include "esp_netif.h"
#include "driver/uart.h"
/** @brief Configuration of SLIP network interface
*
*/
#define ESP_NETIF_INHERENT_DEFAULT_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 = "SLP_DEF", \
.if_desc = "slip", \
.route_prio = 16, \
.bridge_info = NULL \
};
extern esp_netif_netstack_config_t *netstack_default_slip;
typedef struct slip_modem* slip_modem_handle;
// Filter callbacks for handling application specific slip messages
typedef bool slip_rx_filter_cb_t(slip_modem_handle slip, 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 */
esp_ip6_addr_t *ipv6_addr;
} 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
*/
slip_modem_handle slip_modem_create(esp_netif_t *slip_netif, const slip_modem_config_t *modem_config);
/** @brief Destroy a slip modem
*
* @param[in] slip modem handle for destruction
*
* @return
* - ESP_OK on success
*/
esp_err_t slip_modem_destroy(slip_modem_handle slip);
/**
* @brief Getter for the internally configured IPv6 address
*
* @param[in] slip modem handle
*
* @returns
* - ipv6 address
*/
esp_ip6_addr_t slip_modem_get_ipv6_address(slip_modem_handle slip);
/**
* @brief Data path API that forward the supplied data to the attached network interface
*
* @param[in] slip modem object
* @param[in] buffer pointer to the outgoing data
* @param[in] len length of the data
*
*/
void slip_modem_raw_write(slip_modem_handle slip, void *buffer, size_t len);

View File

@ -0,0 +1,256 @@
/*
* SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include "slip_modem.h"
#include "esp_netif.h"
#include "slip_modem_netif.h"
#include "esp_event.h"
#include "esp_log.h"
#define SLIP_RX_TASK_PRIORITY 10
#define SLIP_RX_TASK_STACK_SIZE (4 * 1024)
static const char *TAG = "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 slip_modem {
// ESP base netif driver
esp_netif_driver_base_t base;
// 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;
// Running flag
bool running;
// esp_netif related: SLIP interface IP6 address
esp_ip6_addr_t addr;
};
static void slip_modem_uart_rx_task(void *arg);
static esp_err_t slip_modem_post_attach(esp_netif_t *esp_netif, void *args);
// Create a new slip modem
slip_modem_handle slip_modem_create(esp_netif_t *slip_netif, const slip_modem_config_t *modem_config)
{
if (slip_netif == NULL || modem_config == NULL) {
ESP_LOGE(TAG, "invalid parameters");
return NULL;
}
ESP_LOGI(TAG, "%s: Creating slip modem (netif: %p)", __func__, slip_netif);
ESP_LOGD(TAG, "%s (netif: %p)", __func__, slip_netif);
slip_modem_handle slip_modem = calloc(1, sizeof(struct slip_modem));
if (!slip_modem) {
ESP_LOGE(TAG, "create netif glue failed");
return NULL;
}
// Attach driver and post_attach callbacks
slip_modem->base.post_attach = slip_modem_post_attach;
slip_modem->base.netif = slip_netif;
// Attach config
slip_modem->buffer_len = modem_config->rx_buffer_len;
slip_modem->rx_filter = modem_config->rx_filter;
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;
slip_modem->addr = *modem_config->ipv6_addr;
// Return the new modem
return slip_modem;
}
// Internal handler called on driver start
static esp_err_t esp_slip_driver_start(slip_modem_handle 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;
}
// 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(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_action_start(slip_modem->base.netif, 0, 0, 0);
ESP_ERROR_CHECK(slip_modem_netif_start(slip_modem->base.netif, &slip_modem->addr));
return ESP_OK;
}
esp_err_t slip_modem_destroy(slip_modem_handle slip)
{
if (slip != NULL) {
// Stop slip driver
esp_netif_action_stop(slip->base.netif, 0, 0, 0);
ESP_ERROR_CHECK(slip_modem_netif_stop(slip->base.netif));
// Stop uart rx task
vTaskDelete(slip->uart.uart_rx_task);
// Delete driver
uart_driver_delete(slip->uart.uart_dev);
// Free slip interface
free(slip);
}
return ESP_OK;
}
// Modem transmit for glue logic
static esp_err_t 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);
slip_modem_handle slip_modem = (slip_modem_handle)slip_driver;
int32_t res = uart_write_bytes(slip_modem->uart.uart_dev, (char *)buffer, len);
if (res < 0) {
// Handle errors
ESP_LOGE(TAG, "%s: uart_write_bytes error %i", __func__, res);
return ESP_FAIL;
}
return ESP_OK;
}
// Post-attach handler for netif
static esp_err_t slip_modem_post_attach(esp_netif_t *esp_netif, void *args)
{
slip_modem_handle slip_modem = (slip_modem_handle) 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 = slip_modem_transmit,
.handle = slip_modem,
};
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;
}
static void slip_modem_uart_rx_task(void *arg)
{
if (arg == NULL) {
ESP_LOGE(TAG, "Starting a task with invalid parameters, deleting");
vTaskDelete(NULL);
}
slip_modem_handle slip_modem = (slip_modem_handle) arg;
ESP_LOGD(TAG, "Start SLIP modem RX task (slip_modem %p filter: %p)", slip_modem, 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_PERIOD_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, slip_modem->buffer, len)) {
continue;
}
// Pass received bytes in to slip interface
ESP_LOGI(TAG, "esp_netif %p", slip_modem->base.netif);
esp_netif_receive(slip_modem->base.netif, slip_modem->buffer, len, NULL);
}
// Yield to allow other tasks to progress
vTaskDelay(1 * portTICK_PERIOD_MS);
}
}
/**
* @brief Gets the internally configured ipv6 address
*/
esp_ip6_addr_t slip_modem_get_ipv6_address(slip_modem_handle slip)
{
return slip->addr;
}
void slip_modem_raw_write(slip_modem_handle slip, void *buffer, size_t len)
{
slip_modem_netif_raw_write(slip->base.netif, buffer, len);
}

View File

@ -0,0 +1,195 @@
/*
* SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include "esp_netif.h"
#include "esp_log.h"
#include "esp_netif_net_stack.h"
#include "lwip/esp_netif_net_stack.h"
#include "lwip/dns.h"
#include "lwip/ip6_addr.h"
#include "lwip/netif.h"
#include "netif/slipif.h"
#include "lwip/sio.h"
static const char *TAG = "slip-modem-netif";
/**
* @brief Stops the SLIP interface
*/
esp_err_t slip_modem_netif_stop(esp_netif_t *esp_netif)
{
struct netif *netif = esp_netif_get_netif_impl(esp_netif);
ESP_LOGI(TAG, "%s: Stopped SLIP connection: lwip netif:%p", __func__, netif);
// Stop interface
netif_set_link_down(netif);
return ESP_OK;
}
/**
* @brief Starts the SLIP interface
*/
esp_err_t slip_modem_netif_start(esp_netif_t *esp_netif, esp_ip6_addr_t *addr)
{
struct netif *netif = esp_netif_get_netif_impl(esp_netif);
ESP_LOGI(TAG, "%s: Starting SLIP interface: lwip netif:%p", __func__, netif);
// Set the netif up
netif_set_up(netif);
netif_set_link_up(netif);
#if CONFIG_LWIP_IPV6
int8_t addr_index = 0;
netif_ip6_addr_set(netif, addr_index, (ip6_addr_t *)addr);
netif_ip6_addr_set_state(netif, addr_index, IP6_ADDR_VALID);
#endif
return ESP_OK;
}
/**
* @brief Write incoming serial data to the SLIP interface
*/
void esp_netif_lwip_slip_input(void *h, void *buffer, unsigned int len, void *eb)
{
struct netif *netif = h;
ESP_LOGD(TAG, "%s", __func__);
ESP_LOG_BUFFER_HEXDUMP(TAG, buffer, len, ESP_LOG_DEBUG);
// Update slip netif with data
const int max_batch = 255;
int sent = 0;
while(sent < len) {
int batch = (len - sent) > max_batch ? max_batch : (len - sent);
slipif_received_bytes(netif, buffer+sent, batch);
sent += batch;
}
// Process incoming bytes
for (int i = 0; i < len; i++) {
slipif_process_rxqueue(netif);
}
}
/**
* @brief Write raw data out the SLIP interface
*/
void slip_modem_netif_raw_write(esp_netif_t *netif, void *buffer, size_t len)
{
struct netif *lwip_netif = esp_netif_get_netif_impl(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
#if CONFIG_LWIP_IPV6
lwip_netif->output_ip6(lwip_netif, &p, NULL);
#else
lwip_netif->output(lwip_netif, &p, NULL);
#endif
}
/** @brief Get esp-netif object corresponding to registration index
*/
static esp_netif_t * get_netif_with_esp_index(int index)
{
esp_netif_t *netif = NULL;
int counter = 0;
while ((netif = esp_netif_next(netif)) != NULL) {
if (counter == index) {
return netif;
}
counter++;
}
return NULL;
}
/** @brief Return list registration index of the supplied netif ptr
*/
static int get_esp_netif_index(esp_netif_t * esp_netif)
{
esp_netif_t *netif = NULL;
int counter = 0;
while ((netif = esp_netif_next(netif)) != NULL) {
if (esp_netif == netif) {
return counter;
}
counter++;
}
return -1;
}
static err_t esp_slipif_init(struct netif *netif)
{
if (netif == NULL) {
return ERR_IF;
}
esp_netif_t *esp_netif = netif->state;
int esp_index = get_esp_netif_index(esp_netif);
if (esp_index < 0) {
return ERR_IF;
}
// Store netif index in net interface for SIO open command to abstract the dev
netif->state = (void *)esp_index;
return slipif_init(netif);
}
const struct esp_netif_netstack_config s_netif_config_slip = {
.lwip = {
.init_fn = esp_slipif_init,
.input_fn = esp_netif_lwip_slip_input,
}
};
const esp_netif_netstack_config_t *netstack_default_slip = &s_netif_config_slip;
/***
* @brief Open a serial device for communication
*/
sio_fd_t sio_open(uint8_t devnum)
{
ESP_LOGD(TAG, "Opening device: %d\r\n", devnum);
esp_netif_t *esp_netif = get_netif_with_esp_index(devnum);
if (!esp_netif) {
ESP_LOGE(TAG, "didn't find esp-netif with index=%d\n", devnum);
return NULL;
}
// Return SIO handle
return esp_netif;
}
/***
* @brief Send a single character to the serial device (blocking)
*/
void sio_send(uint8_t c, sio_fd_t fd)
{
esp_netif_t *esp_netif = fd;
ESP_LOGD(TAG, "%s", __func__);
ESP_LOG_BUFFER_HEX_LEVEL(TAG, &c, 1, ESP_LOG_DEBUG);
esp_err_t ret = esp_netif_transmit(esp_netif, &c, 1);
if (ret != ESP_OK) {
// Handle errors
ESP_LOGD(TAG, "%s: uart_write_bytes error %i", __func__, ret);
}
}

View File

@ -0,0 +1,42 @@
/*
* SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
/**
* @brief Stop the esp slip netif
*
* @param[in] esp_netif handle to slip esp-netif instance
*
* @return
* - ESP_OK on success
*/
esp_err_t slip_modem_netif_stop(esp_netif_t *esp_netif);
/**
* @brief Start the esp slip netif
*
* @param[in] esp_netif handle to slip esp-netif instance
* @param[in] addr IPv6 address associated with this SLIP interface
*
* @return
* - ESP_OK on success
*/
esp_err_t slip_modem_netif_start(esp_netif_t *esp_netif, esp_ip6_addr_t *addr);
/**
* @brief Data path API to write raw packet ous the SLIP interface
*
* This API is typically used when implementing user defined methods
*
* @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 slip_modem_netif_raw_write(esp_netif_t *netif, void *buffer, size_t len);

View File

@ -0,0 +1,8 @@
# Slip client example
idf_component_register(
SRCS "slip_client_main.c"
INCLUDE_DIRS "."
REQUIRES esp_netif slip_modem driver
)
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")

View File

@ -0,0 +1,38 @@
menu "Example Configuration"
menu "UART Configuration"
config EXAMPLE_UART_TX_PIN
int "TXD Pin Number"
default 25
range 0 36
help
Pin number of UART TX.
config EXAMPLE_UART_RX_PIN
int "RXD Pin Number"
default 26
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
endmenu
config EXAMPLE_UDP_PORT
int "Port for UDP echo server"
default 5678
help
Port for UDP echo server in example
config EXAMPLE_IPV4
bool "Test with IPv4 address"
default n
help
Test interface using IPv4
endmenu

View File

@ -0,0 +1,237 @@
/* 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 <sys/socket.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_log.h"
#include "esp_event.h"
#include "esp_netif.h"
#include "slip_modem.h"
static const char *TAG = "slip-example";
#define STACK_SIZE (10 * 1024)
#define PRIORITY 10
static void udp_rx_tx_task(void *arg)
{
char addr_str[128];
uint8_t rx_buff[1024];
int sock = (int)arg;
struct sockaddr_storage 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
if (source_addr.ss_family == PF_INET) {
inet_ntoa_r(((struct sockaddr_in *)&source_addr)->sin_addr.s_addr, addr_str, sizeof(addr_str) - 1);
} else if (source_addr.ss_family == PF_INET6) {
inet6_ntoa_r(((struct sockaddr_in6 *)&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);
}
static esp_err_t udp_rx_tx_start(void)
{
// Setup bind address
struct sockaddr_in6 dest_addr;
#if CONFIG_EXAMPLE_IPV4
sa_family_t family = AF_INET;
int ip_protocol = IPPROTO_IP;
struct sockaddr_in *dest_addr_ip4 = (struct sockaddr_in *)&dest_addr;
dest_addr_ip4->sin_addr.s_addr = htonl(INADDR_ANY);
dest_addr_ip4->sin_family = AF_INET;
dest_addr_ip4->sin_port = htons(CONFIG_EXAMPLE_UDP_PORT);
ip_protocol = IPPROTO_IP;
#else
sa_family_t family = AF_INET6;
int ip_protocol = IPPROTO_IPV6;
bzero(&dest_addr.sin6_addr.un, sizeof(dest_addr.sin6_addr.un));
dest_addr.sin6_family = family;
dest_addr.sin6_port = htons(CONFIG_EXAMPLE_UDP_PORT);
#endif
// Create socket
int sock = socket(family, SOCK_DGRAM, ip_protocol);
if (sock < 0) {
ESP_LOGE(TAG, "Unable to create socket: errno %d", errno);
return ESP_FAIL;
}
// Disable IPv4 and reuse address
int opt = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
#if !CONFIG_EXAMPLE_IPV4
setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt));
#endif
// 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 ESP_FAIL;
}
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, (void *)sock, PRIORITY, NULL);
return ESP_OK;
}
// Write a prefix to the contiki slip device
static void slip_set_prefix(slip_modem_handle slip)
{
uint8_t buff[10] = {0};
const esp_ip6_addr_t addr = slip_modem_get_ipv6_address(slip);
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
slip_modem_raw_write(slip, buff, 2 + 8);
}
// slip_rx_filter filters incoming commands from the slip interface
// this implementation is designed for use with contiki slip devices
static bool slip_rx_filter(slip_modem_handle slip, uint8_t *data, uint32_t len)
{
if (data[1] == '?') {
switch (data[2]) {
case 'P':
ESP_LOGI(TAG, "Prefix request");
slip_set_prefix(slip);
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;
}
#if CONFIG_EXAMPLE_IPV4
static const esp_netif_ip_info_t s_slip_ip4 = {
.ip = { .addr = ESP_IP4TOADDR( 10, 0, 0, 2) },
};
#endif
// Initialise the SLIP interface
esp_netif_t *slip_if_init(void)
{
ESP_LOGI(TAG, "Initialising SLIP interface");
esp_netif_inherent_config_t base_cfg = ESP_NETIF_INHERENT_DEFAULT_SLIP()
#if CONFIG_EXAMPLE_IPV4
base_cfg.ip_info = &s_slip_ip4;
#endif
esp_netif_config_t cfg = { .base = &base_cfg,
.driver = NULL,
.stack = netstack_default_slip };
esp_netif_t *slip_netif = esp_netif_new(&cfg);
esp_ip6_addr_t local_addr; /* Local IP6 address */
IP6_ADDR(&local_addr,
lwip_htonl(0xfd0000),
lwip_htonl(0x00000000),
lwip_htonl(0x00000000),
lwip_htonl(0x00000001)
);
ESP_LOGI(TAG, "Initialising SLIP modem");
slip_modem_config_t modem_cfg = {
.uart_dev = UART_NUM_1,
.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,
.ipv6_addr = &local_addr
};
void *slip_modem = slip_modem_create(slip_netif, &modem_cfg);
assert(slip_modem);
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
esp_netif_init();
esp_log_level_set("*", ESP_LOG_DEBUG);
// Create event loop
ESP_ERROR_CHECK(esp_event_loop_create_default());
// Setup slip interface
esp_netif_t* esp_netif = slip_if_init();
assert(esp_netif);
// Start the UDP user application
udp_rx_tx_start();
}

View File

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