diff --git a/components/esp_netif/lwip/esp_netif_lwip_ppp.c b/components/esp_netif/lwip/esp_netif_lwip_ppp.c index 95f7201026..bea508da1d 100644 --- a/components/esp_netif/lwip/esp_netif_lwip_ppp.c +++ b/components/esp_netif/lwip/esp_netif_lwip_ppp.c @@ -246,7 +246,8 @@ esp_err_t esp_netif_ppp_set_auth(esp_netif_t *netif, esp_netif_auth_type_t autht struct lwip_ppp_ctx *obj = netif->lwip_ppp_ctx; pppapi_set_auth(obj->ppp, authtype, user, passwd); #else -#error "Unsupported AUTH Negotiation" + ESP_LOGE(TAG, "%s failed: No authorisation enabled in menuconfig", __func__); + return ESP_ERR_ESP_NETIF_IF_NOT_READY; #endif return ESP_OK; } diff --git a/components/lwip/port/esp32/include/lwipopts.h b/components/lwip/port/esp32/include/lwipopts.h index d6aa757f01..2b4a593f38 100644 --- a/components/lwip/port/esp32/include/lwipopts.h +++ b/components/lwip/port/esp32/include/lwipopts.h @@ -661,6 +661,8 @@ #if PPP_DEBUG_ON #define PPP_DEBUG LWIP_DBG_ON +#define PRINTPKT_SUPPORT 1 +#define PPP_PROTOCOLNAME 1 #else #define PPP_DEBUG LWIP_DBG_OFF #endif diff --git a/examples/protocols/pppos_client/components/modem/CMakeLists.txt b/examples/protocols/pppos_client/components/modem/CMakeLists.txt index 33cc955dea..543d22b2a4 100644 --- a/examples/protocols/pppos_client/components/modem/CMakeLists.txt +++ b/examples/protocols/pppos_client/components/modem/CMakeLists.txt @@ -7,4 +7,4 @@ set(srcs "src/esp_modem.c" idf_component_register(SRCS "${srcs}" INCLUDE_DIRS include - REQUIRES driver) \ No newline at end of file + REQUIRES driver) diff --git a/examples/protocols/pppos_client/components/modem/Kconfig b/examples/protocols/pppos_client/components/modem/Kconfig new file mode 100644 index 0000000000..932c1c091e --- /dev/null +++ b/examples/protocols/pppos_client/components/modem/Kconfig @@ -0,0 +1,9 @@ +menu "ESP-MODEM" + + config EXAMPLE_COMPONENT_MODEM_APN + string "Set Access Point Name (APN)" + default "CMNET" + help + Logical name which is used to select the GGSN or the external packet data network. + +endmenu diff --git a/examples/protocols/pppos_client/components/modem/include/esp_modem.h b/examples/protocols/pppos_client/components/modem/include/esp_modem.h index 689fe32b52..6b6185fc66 100644 --- a/examples/protocols/pppos_client/components/modem/include/esp_modem.h +++ b/examples/protocols/pppos_client/components/modem/include/esp_modem.h @@ -50,6 +50,17 @@ typedef struct { uart_parity_t parity; /*!< Parity type */ modem_flow_ctrl_t flow_control; /*!< Flow control type */ uint32_t baud_rate; /*!< Communication baud rate */ + int tx_io_num; /*!< TXD Pin Number */ + int rx_io_num; /*!< RXD Pin Number */ + int rts_io_num; /*!< RTS Pin Number */ + int cts_io_num; /*!< CTS Pin Number */ + int rx_buffer_size; /*!< UART RX Buffer Size */ + int tx_buffer_size; /*!< UART TX Buffer Size */ + int pattern_queue_size; /*!< UART Pattern Queue Size */ + int event_queue_size; /*!< UART Event Queue Size */ + uint32_t event_task_stack_size; /*!< UART Event Task Stack size */ + int event_task_priority; /*!< UART Event Task Priority */ + int line_buffer_size; /*!< Line buffer size for command mode */ } esp_modem_dte_config_t; /** @@ -69,7 +80,18 @@ typedef esp_err_t (*esp_modem_on_receive)(void *buffer, size_t len, void *contex .stop_bits = UART_STOP_BITS_1, \ .parity = UART_PARITY_DISABLE, \ .baud_rate = 115200, \ - .flow_control = MODEM_FLOW_CONTROL_NONE \ + .flow_control = MODEM_FLOW_CONTROL_NONE,\ + .tx_io_num = 25, \ + .rx_io_num = 26, \ + .rts_io_num = 27, \ + .cts_io_num = 23, \ + .rx_buffer_size = 1024, \ + .tx_buffer_size = 512, \ + .pattern_queue_size = 20, \ + .event_queue_size = 30, \ + .event_task_stack_size = 2048, \ + .event_task_priority = 5, \ + .line_buffer_size = 512 \ } /** diff --git a/examples/protocols/pppos_client/components/modem/src/esp_modem.c b/examples/protocols/pppos_client/components/modem/src/esp_modem.c index 2134e387cd..1af3eed2ec 100644 --- a/examples/protocols/pppos_client/components/modem/src/esp_modem.c +++ b/examples/protocols/pppos_client/components/modem/src/esp_modem.c @@ -21,7 +21,6 @@ #include "esp_log.h" #include "sdkconfig.h" -#define ESP_MODEM_LINE_BUFFER_SIZE (CONFIG_EXAMPLE_UART_RX_BUFFER_SIZE / 2) #define ESP_MODEM_EVENT_QUEUE_SIZE (16) #define MIN_PATTERN_INTERVAL (9) @@ -57,8 +56,10 @@ typedef struct { TaskHandle_t uart_event_task_hdl; /*!< UART event task handle */ SemaphoreHandle_t process_sem; /*!< Semaphore used for indicating processing status */ modem_dte_t parent; /*!< DTE interface that should extend */ - esp_modem_on_receive receive_cb; /*!< ptr to data reception */ - void *receive_cb_ctx; /*!< ptr to rx fn context data */ + esp_modem_on_receive receive_cb; /*!< ptr to data reception */ + void *receive_cb_ctx; /*!< ptr to rx fn context data */ + int line_buffer_size; /*!< line buffer size in commnad mode */ + int event_queue_size; /*!< UART event queue size */ } esp_modem_dte_t; @@ -108,12 +109,12 @@ static void esp_handle_uart_pattern(esp_modem_dte_t *esp_dte) int pos = uart_pattern_pop_pos(esp_dte->uart_port); int read_len = 0; if (pos != -1) { - if (pos < ESP_MODEM_LINE_BUFFER_SIZE - 1) { + if (pos < esp_dte->line_buffer_size - 1) { /* read one line(include '\n') */ read_len = pos + 1; } else { ESP_LOGW(MODEM_TAG, "ESP Modem Line buffer too small"); - read_len = ESP_MODEM_LINE_BUFFER_SIZE - 1; + read_len = esp_dte->line_buffer_size - 1; } read_len = uart_read_bytes(esp_dte->uart_port, esp_dte->buffer, read_len, pdMS_TO_TICKS(100)); if (read_len) { @@ -137,9 +138,16 @@ static void esp_handle_uart_pattern(esp_modem_dte_t *esp_dte) */ static void esp_handle_uart_data(esp_modem_dte_t *esp_dte) { + if (esp_dte->parent.dce->mode != MODEM_PPP_MODE) { + ESP_LOGE(MODEM_TAG, "Error: Got data event in PPP mode"); + /* pattern detection mode -> ignore date event on uart + * (should never happen, but if it does, we could still + * read the valid data once pattern detect event fired) */ + return; + } size_t length = 0; uart_get_buffered_data_len(esp_dte->uart_port, &length); - length = MIN(ESP_MODEM_LINE_BUFFER_SIZE, length); + length = MIN(esp_dte->line_buffer_size, length); length = uart_read_bytes(esp_dte->uart_port, esp_dte->buffer, length, portMAX_DELAY); /* pass the input data to configured callback */ if (length) { @@ -307,7 +315,7 @@ static esp_err_t esp_modem_dte_change_mode(modem_dte_t *dte, modem_mode_t new_mo uart_disable_rx_intr(esp_dte->uart_port); uart_flush(esp_dte->uart_port); uart_enable_pattern_det_baud_intr(esp_dte->uart_port, '\n', 1, MIN_PATTERN_INTERVAL, MIN_POST_IDLE, MIN_PRE_IDLE); - uart_pattern_queue_reset(esp_dte->uart_port, CONFIG_EXAMPLE_UART_PATTERN_QUEUE_SIZE); + uart_pattern_queue_reset(esp_dte->uart_port, esp_dte->event_queue_size); MODEM_CHECK(dce->set_working_mode(dce, new_mode) == ESP_OK, "set new working mode:%d failed", err, new_mode); break; default: @@ -361,7 +369,8 @@ modem_dte_t *esp_modem_dte_init(const esp_modem_dte_config_t *config) esp_modem_dte_t *esp_dte = calloc(1, sizeof(esp_modem_dte_t)); MODEM_CHECK(esp_dte, "calloc esp_dte failed", err_dte_mem); /* malloc memory to storing lines from modem dce */ - esp_dte->buffer = calloc(1, ESP_MODEM_LINE_BUFFER_SIZE); + esp_dte->line_buffer_size = config->line_buffer_size; + esp_dte->buffer = calloc(1, config->line_buffer_size); MODEM_CHECK(esp_dte->buffer, "calloc line memory failed", err_line_mem); /* Set attributes */ esp_dte->uart_port = config->port_num; @@ -380,20 +389,15 @@ modem_dte_t *esp_modem_dte_init(const esp_modem_dte_config_t *config) .data_bits = config->data_bits, .parity = config->parity, .stop_bits = config->stop_bits, - .source_clk = UART_SCLK_APB, + .source_clk = UART_SCLK_REF_TICK, .flow_ctrl = (config->flow_control == MODEM_FLOW_CONTROL_HW) ? UART_HW_FLOWCTRL_CTS_RTS : UART_HW_FLOWCTRL_DISABLE }; - /* Install UART driver and get event queue used inside driver */ - res = uart_driver_install(esp_dte->uart_port, CONFIG_EXAMPLE_UART_RX_BUFFER_SIZE, CONFIG_EXAMPLE_UART_TX_BUFFER_SIZE, - CONFIG_EXAMPLE_UART_EVENT_QUEUE_SIZE, &(esp_dte->event_queue), 0); - MODEM_CHECK(res == ESP_OK, "install uart driver failed", err_uart_config); - MODEM_CHECK(uart_param_config(esp_dte->uart_port, &uart_config) == ESP_OK, "config uart parameter failed", err_uart_config); if (config->flow_control == MODEM_FLOW_CONTROL_HW) { - res = uart_set_pin(esp_dte->uart_port, CONFIG_EXAMPLE_UART_MODEM_TX_PIN, CONFIG_EXAMPLE_UART_MODEM_RX_PIN, - CONFIG_EXAMPLE_UART_MODEM_RTS_PIN, CONFIG_EXAMPLE_UART_MODEM_CTS_PIN); + res = uart_set_pin(esp_dte->uart_port, config->tx_io_num, config->rx_io_num, + config->rts_io_num, config->cts_io_num); } else { - res = uart_set_pin(esp_dte->uart_port, CONFIG_EXAMPLE_UART_MODEM_TX_PIN, CONFIG_EXAMPLE_UART_MODEM_RX_PIN, + res = uart_set_pin(esp_dte->uart_port, config->tx_io_num, config->rx_io_num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); } MODEM_CHECK(res == ESP_OK, "config uart gpio failed", err_uart_config); @@ -404,10 +408,19 @@ modem_dte_t *esp_modem_dte_init(const esp_modem_dte_config_t *config) res = uart_set_sw_flow_ctrl(esp_dte->uart_port, true, 8, UART_FIFO_LEN - 8); } MODEM_CHECK(res == ESP_OK, "config uart flow control failed", err_uart_config); + /* Install UART driver and get event queue used inside driver */ + esp_dte->event_queue_size = config->event_queue_size; + res = uart_driver_install(esp_dte->uart_port, config->rx_buffer_size, config->tx_buffer_size, + config->event_queue_size, &(esp_dte->event_queue), 0); + MODEM_CHECK(res == ESP_OK, "install uart driver failed", err_uart_config); + /* Set pattern interrupt, used to detect the end of a line. */ res = uart_enable_pattern_det_baud_intr(esp_dte->uart_port, '\n', 1, MIN_PATTERN_INTERVAL, MIN_POST_IDLE, MIN_PRE_IDLE); /* Set pattern queue size */ - res |= uart_pattern_queue_reset(esp_dte->uart_port, CONFIG_EXAMPLE_UART_PATTERN_QUEUE_SIZE); + res |= uart_pattern_queue_reset(esp_dte->uart_port, config->pattern_queue_size); + /* Starting in command mode -> explicitly disable RX interrupt */ + uart_disable_rx_intr(esp_dte->uart_port); + MODEM_CHECK(res == ESP_OK, "config uart pattern failed", err_uart_pattern); /* Create Event loop */ esp_event_loop_args_t loop_args = { @@ -420,10 +433,10 @@ modem_dte_t *esp_modem_dte_init(const esp_modem_dte_config_t *config) MODEM_CHECK(esp_dte->process_sem, "create process semaphore failed", err_sem); /* Create UART Event task */ BaseType_t ret = xTaskCreate(uart_event_task_entry, //Task Entry - "uart_event", //Task Name - CONFIG_EXAMPLE_UART_EVENT_TASK_STACK_SIZE, //Task Stack Size(Bytes) + "uart_event", //Task Name + config->event_task_stack_size, //Task Stack Size(Bytes) esp_dte, //Task Parameter - CONFIG_EXAMPLE_UART_EVENT_TASK_PRIORITY, //Task Priority + config->event_task_priority, //Task Priority & (esp_dte->uart_event_task_hdl) //Task Handler ); MODEM_CHECK(ret == pdTRUE, "create uart event task failed", err_tsk_create); @@ -463,7 +476,7 @@ esp_err_t esp_modem_start_ppp(modem_dte_t *dte) MODEM_CHECK(dce, "DTE has not yet bind with DCE", err); esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent); /* Set PDP Context */ - MODEM_CHECK(dce->define_pdp_context(dce, 1, "IP", CONFIG_EXAMPLE_MODEM_APN) == ESP_OK, "set MODEM APN failed", err); + MODEM_CHECK(dce->define_pdp_context(dce, 1, "IP", CONFIG_EXAMPLE_COMPONENT_MODEM_APN) == ESP_OK, "set MODEM APN failed", err); /* Enter PPP mode */ MODEM_CHECK(dte->change_mode(dte, MODEM_PPP_MODE) == ESP_OK, "enter ppp mode failed", err); diff --git a/examples/protocols/pppos_client/components/modem/src/esp_modem_compat.c b/examples/protocols/pppos_client/components/modem/src/esp_modem_compat.c index 20497bc7b2..297acc248c 100644 --- a/examples/protocols/pppos_client/components/modem/src/esp_modem_compat.c +++ b/examples/protocols/pppos_client/components/modem/src/esp_modem_compat.c @@ -73,12 +73,12 @@ esp_err_t esp_modem_add_event_handler(modem_dte_t *dte, esp_event_handler_t hand esp_err_t esp_modem_setup_ppp(modem_dte_t *dte) { -#if CONFIG_LWIP_PPP_PAP_SUPPORT +#if CONFIG_LWIP_PPP_PAP_SUPPORT && defined(CONFIG_EXAMPLE_MODEM_PPP_AUTH_USERNAME) && defined(CONFIG_EXAMPLE_MODEM_PPP_AUTH_PASSWORD) esp_netif_auth_type_t auth_type = NETIF_PPP_AUTHTYPE_PAP; -#elif CONFIG_LWIP_PPP_CHAP_SUPPORT +#elif CONFIG_LWIP_PPP_CHAP_SUPPORT && defined(CONFIG_EXAMPLE_MODEM_PPP_AUTH_USERNAME) && defined(CONFIG_EXAMPLE_MODEM_PPP_AUTH_PASSWORD) esp_netif_auth_type_t auth_type = NETIF_PPP_AUTHTYPE_CHAP; -#else -#error "Unsupported AUTH Negotiation" +#elif defined(CONFIG_EXAMPLE_MODEM_PPP_AUTH_USERNAME) && defined(CONFIG_EXAMPLE_MODEM_PPP_AUTH_PASSWORD) +#error "Unsupported AUTH Negotiation while AUTH_USERNAME and PASSWORD defined" #endif // Init netif object esp_netif_config_t cfg = ESP_NETIF_DEFAULT_PPP(); @@ -88,7 +88,9 @@ esp_err_t esp_modem_setup_ppp(modem_dte_t *dte) // event loop has to be created when using this API -- create and ignore failure if already created esp_event_loop_create_default(); ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, ESP_EVENT_ANY_ID, &on_ip_event, NULL)); +#if defined(CONFIG_EXAMPLE_MODEM_PPP_AUTH_USERNAME) && defined(CONFIG_EXAMPLE_MODEM_PPP_AUTH_PASSWORD) esp_netif_ppp_set_auth(esp_netif, auth_type, CONFIG_EXAMPLE_MODEM_PPP_AUTH_USERNAME, CONFIG_EXAMPLE_MODEM_PPP_AUTH_PASSWORD); +#endif void *modem_netif_adapter = esp_modem_netif_setup(dte); esp_modem_netif_set_default_handlers(modem_netif_adapter, esp_netif); /* attach the modem to the network interface */ diff --git a/examples/protocols/pppos_client/main/Kconfig.projbuild b/examples/protocols/pppos_client/main/Kconfig.projbuild index 7d84465642..0618de0b82 100644 --- a/examples/protocols/pppos_client/main/Kconfig.projbuild +++ b/examples/protocols/pppos_client/main/Kconfig.projbuild @@ -16,24 +16,26 @@ menu "Example Configuration" Quectel BG96 is a series of LTE Cat M1/Cat NB1/EGPRS module. endchoice - config EXAMPLE_MODEM_APN - string "Set Access Point Name (APN)" - default "CMNET" - help - Logical name which is used to select the GGSN or the external packet 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 @@ -49,70 +51,70 @@ menu "Example Configuration" endif menu "UART Configuration" - config EXAMPLE_UART_MODEM_TX_PIN + config EXAMPLE_MODEM_UART_TX_PIN int "TXD Pin Number" default 25 range 0 31 help Pin number of UART TX. - config EXAMPLE_UART_MODEM_RX_PIN + config EXAMPLE_MODEM_UART_RX_PIN int "RXD Pin Number" default 26 range 0 31 help Pin number of UART RX. - config EXAMPLE_UART_MODEM_RTS_PIN + config EXAMPLE_MODEM_UART_RTS_PIN int "RTS Pin Number" default 27 range 0 31 help Pin number of UART RTS. - config EXAMPLE_UART_MODEM_CTS_PIN + config EXAMPLE_MODEM_UART_CTS_PIN int "CTS Pin Number" default 23 range 0 31 help Pin number of UART CTS. - config EXAMPLE_UART_EVENT_TASK_STACK_SIZE + 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_UART_EVENT_TASK_PRIORITY + 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_UART_EVENT_QUEUE_SIZE + 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_UART_PATTERN_QUEUE_SIZE + 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_UART_TX_BUFFER_SIZE + 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_UART_RX_BUFFER_SIZE + config EXAMPLE_MODEM_UART_RX_BUFFER_SIZE int "UART RX Buffer Size" range 256 2048 default 1024 diff --git a/examples/protocols/pppos_client/main/pppos_client_main.c b/examples/protocols/pppos_client/main/pppos_client_main.c index c4b5fd8ab0..9bf3b44949 100644 --- a/examples/protocols/pppos_client/main/pppos_client_main.c +++ b/examples/protocols/pppos_client/main/pppos_client_main.c @@ -217,7 +217,7 @@ void app_main(void) esp_netif_auth_type_t auth_type = NETIF_PPP_AUTHTYPE_PAP; #elif CONFIG_LWIP_PPP_CHAP_SUPPORT esp_netif_auth_type_t auth_type = NETIF_PPP_AUTHTYPE_CHAP; -#else +#elif !defined(CONFIG_EXAMPLE_MODEM_PPP_AUTH_NONE) #error "Unsupported AUTH Negotiation" #endif ESP_ERROR_CHECK(esp_netif_init()); @@ -234,6 +234,18 @@ void app_main(void) /* create dte object */ esp_modem_dte_config_t config = ESP_MODEM_DTE_DEFAULT_CONFIG(); + /* setup UART specific configuration based on kconfig options */ + config.tx_io_num = CONFIG_EXAMPLE_MODEM_UART_TX_PIN; + config.rx_io_num = CONFIG_EXAMPLE_MODEM_UART_RX_PIN; + config.rts_io_num = CONFIG_EXAMPLE_MODEM_UART_RTS_PIN; + config.cts_io_num = CONFIG_EXAMPLE_MODEM_UART_CTS_PIN; + config.rx_buffer_size = CONFIG_EXAMPLE_MODEM_UART_RX_BUFFER_SIZE; + config.tx_buffer_size = CONFIG_EXAMPLE_MODEM_UART_TX_BUFFER_SIZE; + config.pattern_queue_size = CONFIG_EXAMPLE_MODEM_UART_PATTERN_QUEUE_SIZE; + config.event_queue_size = CONFIG_EXAMPLE_MODEM_UART_EVENT_QUEUE_SIZE; + config.event_task_stack_size = CONFIG_EXAMPLE_MODEM_UART_EVENT_TASK_STACK_SIZE; + config.event_task_priority = CONFIG_EXAMPLE_MODEM_UART_EVENT_TASK_PRIORITY; + config.line_buffer_size = CONFIG_EXAMPLE_MODEM_UART_RX_BUFFER_SIZE/2; modem_dte_t *dte = esp_modem_dte_init(&config); /* Register event handler */ ESP_ERROR_CHECK(esp_modem_set_event_handler(dte, modem_event_handler, ESP_EVENT_ANY_ID, NULL)); @@ -261,7 +273,9 @@ void app_main(void) ESP_ERROR_CHECK(dce->get_battery_status(dce, &bcs, &bcl, &voltage)); ESP_LOGI(TAG, "Battery voltage: %d mV", voltage); /* setup PPPoS network parameters */ +#if !defined(CONFIG_EXAMPLE_MODEM_PPP_AUTH_NONE) && (defined(CONFIG_LWIP_PPP_PAP_SUPPORT) || defined(CONFIG_LWIP_PPP_CHAP_SUPPORT)) esp_netif_ppp_set_auth(esp_netif, auth_type, CONFIG_EXAMPLE_MODEM_PPP_AUTH_USERNAME, CONFIG_EXAMPLE_MODEM_PPP_AUTH_PASSWORD); +#endif void *modem_netif_adapter = esp_modem_netif_setup(dte); esp_modem_netif_set_default_handlers(modem_netif_adapter, esp_netif); /* attach the modem to the network interface */ diff --git a/tools/ci/config/target-test.yml b/tools/ci/config/target-test.yml index 9a151930c9..e4ac44828e 100644 --- a/tools/ci/config/target-test.yml +++ b/tools/ci/config/target-test.yml @@ -313,6 +313,12 @@ test_app_test_002: - ESP32 - Example_WIFI +test_app_test_003: + extends: .test_app_template + tags: + - ESP32 + - Example_PPP + example_test_011: extends: .example_debug_template tags: diff --git a/tools/test_apps/protocols/pppos/CMakeLists.txt b/tools/test_apps/protocols/pppos/CMakeLists.txt new file mode 100644 index 0000000000..12a8475a34 --- /dev/null +++ b/tools/test_apps/protocols/pppos/CMakeLists.txt @@ -0,0 +1,7 @@ +# 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) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/protocols/pppos_client/components) +project(pppos_client) diff --git a/tools/test_apps/protocols/pppos/README.md b/tools/test_apps/protocols/pppos/README.md new file mode 100644 index 0000000000..6aed00816e --- /dev/null +++ b/tools/test_apps/protocols/pppos/README.md @@ -0,0 +1,54 @@ +# PPP over Serial test + +Testing connection of PPP client (ESP) to PPP server (raspberry pi) + +## Pin Assignment + +| ESP | rpi | +| ------ | -------------- | +| GPIO25 | UART-RX | +| GPIO26 | UART-TX | +| GND | GND | + +## Test workflow + +* Starts PPP server on a linux host +* Starts PPPoS client on ESP board +* Connects with both IPv4 and IPv6 +* Test IPv6 connection + - Start server on ESP + - Have linux host to connect and exchange some data +* Test IPv4 connection + - Start server on linux host + - Connect with ESP to the server and exchange some data +* Pass/fail + +## Manual test + +### Server side + +``` +sudo pppd /dev/ttyAMA0 115200 CONFIG_TEST_APP_PPP_SERVER_IP:TEST_APP_PPP_CLIENT_IP modem local noauth debug nodetach dump nocrtscts +``` + +or with `+ipv6` to support ipv6 assignment + +### IPv6 test + +Connect to the ESP local link address and send data, e.g. + +``` +nc fe80::74d7:edc5:9907:5457 2222 +``` + +### IPv4 tst + +Server side expects to run tcp server on port 2222 + +``` +nc -l 2222 +``` + +## Test environment + +configuration `Example_PPP` see wikis/test-docs/example-test-env#example_ppp diff --git a/tools/test_apps/protocols/pppos/app_test.py b/tools/test_apps/protocols/pppos/app_test.py new file mode 100644 index 0000000000..9111868e05 --- /dev/null +++ b/tools/test_apps/protocols/pppos/app_test.py @@ -0,0 +1,107 @@ +from __future__ import print_function +from __future__ import unicode_literals +import re +import socket +import subprocess +import ttfw_idf +import time +from threading import Thread, Event + + +def run_server(server_stop, port, server_ip, client_ip): + print("Starting PPP server on port: {}".format(port)) + try: + arg_list = ['pppd', port, '115200', '{}:{}'.format(server_ip, client_ip), 'modem', 'local', 'noauth', 'debug', 'nocrtscts', 'nodetach', '+ipv6'] + p = subprocess.Popen(arg_list, stdout=subprocess.PIPE, bufsize=1) + while not server_stop.is_set(): + if p.poll() is not None: + raise ValueError('ENV_TEST_FAILURE: PPP terminated unexpectedly with {}'.format(p.poll())) + line = p.stdout.readline() + if line: + print("[PPPD:]{}".format(line.rstrip())) + time.sleep(0.1) + except Exception as e: + print(e) + raise ValueError('ENV_TEST_FAILURE: Error running PPP server') + finally: + p.terminate() + print("PPP server stopped") + + +@ttfw_idf.idf_custom_test(env_tag="Example_PPP", group="test-apps") +def test_examples_protocol_pppos_connect(env, extra_data): + """ + steps: + 1. starts PPP server + 2. get DUT as PPP client to connect to the server + 3. check TCP client-server connection between client-server + """ + + dut1 = env.get_dut("pppos_connect_test", "tools/test_apps/protocols/pppos", dut_class=ttfw_idf.ESP32DUT) + # Look for test case symbolic names + try: + server_ip = dut1.app.get_sdkconfig()["CONFIG_TEST_APP_PPP_SERVER_IP"].replace('"','') + client_ip = dut1.app.get_sdkconfig()["CONFIG_TEST_APP_PPP_CLIENT_IP"].replace('"','') + port_nr = dut1.app.get_sdkconfig()["CONFIG_TEST_APP_TCP_PORT"] + except Exception: + print('ENV_TEST_FAILURE: Some mandatory configuration not found in sdkconfig') + raise + + print("Starting the test on {}".format(dut1)) + dut1.start_app() + + # the PPP test env uses two ttyUSB's: one for ESP32 board, another one for ppp server + # use the other port for PPP server than the DUT/ESP + port = '/dev/ttyUSB0' if dut1.port == '/dev/ttyUSB1' else '/dev/ttyUSB1' + # Start the PPP server + server_stop = Event() + t = Thread(target=run_server, args=(server_stop, port, server_ip, client_ip)) + t.start() + try: + ip6_addr = dut1.expect(re.compile(r"Got IPv6 address ([0-9a-f\:]+)"), timeout=30)[0] + print("IPv6 address of ESP: {}".format(ip6_addr)) + + dut1.expect(re.compile(r"Socket listening")) + print("Starting the IPv6 test...") + # Connect to TCP server on ESP using IPv6 address + for res in socket.getaddrinfo(ip6_addr + "%ppp0", int(port_nr), socket.AF_INET6, + socket.SOCK_STREAM, socket.SOL_TCP): + af, socktype, proto, canonname, addr = res + sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) + sock.connect(addr) + sock.sendall("Espressif") + sock.close() + + dut1.expect(re.compile(r"IPv6 test passed")) + print("IPv6 test passed!") + + print("Starting the IPv4 test...") + # Start the TCP server and wait for the ESP to connect with IPv4 address + try: + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.bind(('', int(port_nr))) + sock.listen(1) + conn, addr = sock.accept() + except socket.error as msg: + print('Socket error: ' + str(msg[0]) + ': ' + msg[1]) + raise + timeout = time.time() + 60 + while time.time() < timeout: + data = conn.recv(128) + if not data: + break + data = data.decode() + print('Received data: ' + data) + if data.startswith('Espressif'): + conn.send(data.encode()) + break + conn.close() + dut1.expect(re.compile(r"IPv4 test passed")) + print("IPv4 test passed!") + finally: + server_stop.set() + t.join() + + +if __name__ == '__main__': + test_examples_protocol_pppos_connect() diff --git a/tools/test_apps/protocols/pppos/main/CMakeLists.txt b/tools/test_apps/protocols/pppos/main/CMakeLists.txt new file mode 100644 index 0000000000..ba4dee208c --- /dev/null +++ b/tools/test_apps/protocols/pppos/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "pppos_client_main.c" "null_dce.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/tools/test_apps/protocols/pppos/main/Kconfig.projbuild b/tools/test_apps/protocols/pppos/main/Kconfig.projbuild new file mode 100644 index 0000000000..b9b14c6339 --- /dev/null +++ b/tools/test_apps/protocols/pppos/main/Kconfig.projbuild @@ -0,0 +1,24 @@ +menu "Test App Configuration" + + config TEST_APP_PPP_SERVER_IP + string "IP address of PPP server" + default "10.0.0.1" + help + IP address of PPP server. Note: this is also the address + where the TCP server is started to test the connection + + config TEST_APP_PPP_CLIENT_IP + string "IP address of PPP client" + default "10.0.0.2" + help + IP address that PPP server assigns to PPP client. + + config TEST_APP_TCP_PORT + int "Port of test" + range 0 65535 + default 2222 + help + The remote port to which the client will connects to + once the PPP connection established + +endmenu diff --git a/tools/test_apps/protocols/pppos/main/null_dce.c b/tools/test_apps/protocols/pppos/main/null_dce.c new file mode 100644 index 0000000000..792ce0a12d --- /dev/null +++ b/tools/test_apps/protocols/pppos/main/null_dce.c @@ -0,0 +1,71 @@ +// Copyright 2020 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 +#include +#include "esp_log.h" +#include "esp_modem.h" + +/** + * @brief Dummy DCE to facilitate testing lwip ppp client with ppp server + * + */ +typedef struct { + modem_dce_t parent; /*!< DCE parent class */ +} null_modem_dce_t; + + +static esp_err_t null_dce_set_working_mode(modem_dce_t *dce, modem_mode_t mode) +{ + dce->mode = mode; + return ESP_OK; +} + +static esp_err_t null_dce_define_pdp_context(modem_dce_t *dce, uint32_t cid, const char *type, const char *apn) +{ + return ESP_OK; +} + +esp_err_t null_dce_dce_hang_up(modem_dce_t *dce) +{ + return ESP_OK; +} + +static esp_err_t null_dce_deinit(modem_dce_t *dce) +{ + null_modem_dce_t *bg96_dce = __containerof(dce, null_modem_dce_t, parent); + if (dce->dte) { + dce->dte->dce = NULL; + } + free(bg96_dce); + return ESP_OK; +} + +modem_dce_t *null_dce_init(modem_dte_t *dte) +{ + if (!dte) return NULL; + /* malloc memory for bg96_dce object */ + null_modem_dce_t *null_dce = calloc(1, sizeof(null_modem_dce_t)); + if (!null_dce) return NULL; + /* Bind DTE with DCE */ + null_dce->parent.dte = dte; + dte->dce = &(null_dce->parent); + /* Bind methods */ + null_dce->parent.handle_line = NULL; + null_dce->parent.define_pdp_context = null_dce_define_pdp_context; + null_dce->parent.set_working_mode = null_dce_set_working_mode; + null_dce->parent.deinit = null_dce_deinit; + null_dce->parent.hang_up = null_dce_dce_hang_up; + /* Sync between DTE and DCE */ + return &(null_dce->parent); +} diff --git a/tools/test_apps/protocols/pppos/main/null_dce.h b/tools/test_apps/protocols/pppos/main/null_dce.h new file mode 100644 index 0000000000..e09f26ceae --- /dev/null +++ b/tools/test_apps/protocols/pppos/main/null_dce.h @@ -0,0 +1,23 @@ +// Copyright 2020 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. +#pragma once + +/** + * @brief Dummy DCE to facilitate testing of lwip ppp client connecting to ppp server + * It creates a modem instance that supports no command interface + * + * @param dte Modem DTE object + * @return modem_dce_t* Modem DCE object + */ +modem_dce_t *null_dce_init(modem_dte_t *dte); diff --git a/tools/test_apps/protocols/pppos/main/pppos_client_main.c b/tools/test_apps/protocols/pppos/main/pppos_client_main.c new file mode 100644 index 0000000000..058257125d --- /dev/null +++ b/tools/test_apps/protocols/pppos/main/pppos_client_main.c @@ -0,0 +1,257 @@ +/* PPPoS 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 +#include "freertos/FreeRTOS.h" +#include "freertos/event_groups.h" +#include "esp_netif.h" +#include "esp_netif_ppp.h" +#include "esp_modem.h" +#include "esp_modem_netif.h" +#include "esp_log.h" +#include "lwip/err.h" +#include "lwip/sockets.h" +#include "null_dce.h" + +#define HOST_IP_ADDR CONFIG_TEST_APP_PPP_SERVER_IP +#define PORT CONFIG_TEST_APP_TCP_PORT + +static const char *TAG = "pppos_test_app"; +static EventGroupHandle_t event_group = NULL; +static const int CONNECT_BIT = BIT0; +static const int STOP_BIT = BIT1; +static const int TCP_SERVER_DONE = BIT3; +static const int TCP_SERVER_FAILED = BIT4; +static char addr_str[128]; +static char rx_buffer[128]; + + +static void modem_event_handler(void *event_handler_arg, esp_event_base_t event_base, int32_t event_id, void *event_data) +{ + switch (event_id) { + case ESP_MODEM_EVENT_PPP_START: + ESP_LOGI(TAG, "Modem PPP Started"); + break; + case ESP_MODEM_EVENT_PPP_STOP: + ESP_LOGI(TAG, "Modem PPP Stopped"); + xEventGroupSetBits(event_group, STOP_BIT); + break; + case ESP_MODEM_EVENT_UNKNOWN: + ESP_LOGW(TAG, "Unknow line received: %s", (char *)event_data); + break; + default: + break; + } +} + +static void on_ppp_changed(void *arg, esp_event_base_t event_base, + int32_t event_id, void *event_data) +{ + ESP_LOGI(TAG, "PPP state changed event %d", event_id); +} + + +static void on_ip_event(void *arg, esp_event_base_t event_base, + int32_t event_id, void *event_data) +{ + if (event_id == IP_EVENT_PPP_GOT_IP) { + ESP_LOGI(TAG, "GOT ip event!!!"); + + ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data; + + ESP_LOGI(TAG, "PPP client connected to PPP Server"); + ESP_LOGI(TAG, "IP : " IPSTR, IP2STR(&event->ip_info.ip)); + ESP_LOGI(TAG, "Netmask : " IPSTR, IP2STR(&event->ip_info.netmask)); + ESP_LOGI(TAG, "Gateway : " IPSTR, IP2STR(&event->ip_info.gw)); + xEventGroupSetBits(event_group, CONNECT_BIT); + + } else if (event_id == IP_EVENT_PPP_LOST_IP) { + ESP_LOGI(TAG, "Modem Disconnect from PPP Server"); + } else if (event_id == IP_EVENT_GOT_IP6) { + ESP_LOGI(TAG, "GOT IPv6 event!"); + + ip_event_got_ip6_t *event = (ip_event_got_ip6_t *)event_data; + ESP_LOGI(TAG, "Got IPv6 address " IPV6STR, IPV62STR(event->ip6_info.ip)); + } +} + +static esp_err_t test_tcp_client_ipv4(void) +{ + struct sockaddr_in dest_addr; + + int addr_family; + int ip_protocol; + const char *payload = "Espressif"; + + + dest_addr.sin_addr.s_addr = inet_addr(HOST_IP_ADDR); + dest_addr.sin_family = AF_INET; + dest_addr.sin_port = htons(PORT); + addr_family = AF_INET; + ip_protocol = IPPROTO_IP; + inet_ntoa_r(dest_addr.sin_addr, addr_str, sizeof(addr_str) - 1); + int sock = socket(addr_family, SOCK_STREAM, ip_protocol); + if (sock < 0) { + ESP_LOGE(TAG, "Unable to create socket: errno %d", errno); + goto fail; + } + ESP_LOGI(TAG, "Socket created, connecting to %s:%d", HOST_IP_ADDR, PORT); + + int err = connect(sock, (struct sockaddr *)&dest_addr, sizeof(dest_addr)); + if (err != 0) { + ESP_LOGE(TAG, "Socket unable to connect: errno %d", errno); + goto fail; + } + ESP_LOGI(TAG, "Successfully connected"); + err = send(sock, payload, strlen(payload), 0); + if (err < 0) { + ESP_LOGE(TAG, "Error occurred during sending: errno %d", errno); + goto fail; + } + int len = recv(sock, rx_buffer, sizeof(rx_buffer) - 1, 0); + if (len < 0) { + ESP_LOGE(TAG, "recv failed: errno %d", errno); + goto fail; + } + rx_buffer[len] = 0; // Null-terminate whatever we received and treat like a string + ESP_LOGI(TAG, "Received from socket:%s", rx_buffer); + return ESP_OK; + +fail: + ESP_LOGE(TAG, "Test TCP connection failed!"); + return ESP_FAIL; +} + +static void test_tcp_server_ipv6(void *pvParameters) +{ + int addr_family; + int ip_protocol; + + 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(PORT); + addr_family = AF_INET6; + ip_protocol = IPPROTO_IPV6; + inet6_ntoa_r(dest_addr.sin6_addr, addr_str, sizeof(addr_str) - 1); + + int listen_sock = socket(addr_family, SOCK_STREAM, ip_protocol); + if (listen_sock < 0) { + ESP_LOGE(TAG, "Unable to create socket: errno %d", errno); + vTaskDelete(NULL); + return; + } + ESP_LOGI(TAG, "Socket created"); + + int err = bind(listen_sock, (struct sockaddr *)&dest_addr, sizeof(dest_addr)); + if (err != 0) { + ESP_LOGE(TAG, "Socket unable to bind: errno %d", errno); + goto failed; + } + ESP_LOGI(TAG, "Socket bound, port %d", PORT); + + err = listen(listen_sock, 1); + if (err != 0) { + ESP_LOGE(TAG, "Error occurred during listen: errno %d", errno); + goto failed; + } + + while (1) { + ESP_LOGI(TAG, "Socket listening"); + + struct sockaddr_in6 source_addr; + size_t addr_len = sizeof(source_addr); + int sock = accept(listen_sock, (struct sockaddr *)&source_addr, &addr_len); + if (sock < 0) { + ESP_LOGE(TAG, "Unable to accept connection: errno %d", errno); + break; + } + + inet6_ntoa_r(source_addr.sin6_addr, addr_str, sizeof(addr_str) - 1); + ESP_LOGI(TAG, "Socket accepted ip address: %s", addr_str); + + int len = recv(sock, rx_buffer, sizeof(rx_buffer) - 1, 0); + if (len < 0) { + ESP_LOGE(TAG, "Error occurred during receiving: errno %d", errno); + } else if (len == 0) { + ESP_LOGW(TAG, "Connection closed"); + } else { + rx_buffer[len] = 0; // Null-terminate whatever is received and treat it like a string + ESP_LOGI(TAG, "Received %d bytes: %s", len, rx_buffer); + goto passed; + } + + shutdown(sock, 0); + close(sock); + } + +failed: + xEventGroupSetBits(event_group, TCP_SERVER_FAILED); +passed: + xEventGroupSetBits(event_group, TCP_SERVER_DONE); + close(listen_sock); + vTaskDelete(NULL); +} + +void app_main(void) +{ + ESP_ERROR_CHECK(esp_netif_init()); + ESP_ERROR_CHECK(esp_event_loop_create_default()); + ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, ESP_EVENT_ANY_ID, &on_ip_event, NULL)); + ESP_ERROR_CHECK(esp_event_handler_register(NETIF_PPP_STATUS, ESP_EVENT_ANY_ID, &on_ppp_changed, NULL)); + + event_group = xEventGroupCreate(); + + // Init netif object + esp_netif_config_t cfg = ESP_NETIF_DEFAULT_PPP(); + esp_netif_t *esp_netif = esp_netif_new(&cfg); + assert(esp_netif); + + /* create dte object */ + esp_modem_dte_config_t config = ESP_MODEM_DTE_DEFAULT_CONFIG(); + config.rx_io_num = 26; + config.tx_io_num = 25; + modem_dte_t *dte = esp_modem_dte_init(&config); + /* Register event handler */ + ESP_ERROR_CHECK(esp_modem_set_event_handler(dte, modem_event_handler, ESP_EVENT_ANY_ID, NULL)); + /* create dce object */ + modem_dce_t *dce = null_dce_init(dte); + + void *modem_netif_adapter = esp_modem_netif_setup(dte); + esp_modem_netif_set_default_handlers(modem_netif_adapter, esp_netif); + /* attach the modem to the network interface */ + esp_netif_attach(esp_netif, modem_netif_adapter); + /* Wait for IP address */ + xEventGroupWaitBits(event_group, CONNECT_BIT, pdTRUE, pdTRUE, portMAX_DELAY); + + ESP_LOGI(TAG, "start IPv6 test"); + xTaskCreate(test_tcp_server_ipv6, "tcp_server_ipv6", 4096, NULL, 5, NULL); + xEventGroupWaitBits(event_group, TCP_SERVER_DONE, pdTRUE, pdTRUE, portMAX_DELAY); + if (TCP_SERVER_FAILED & xEventGroupGetBits(event_group)) { + ESP_LOGE(TAG, "IPv6 test failed!"); + } else { + ESP_LOGI(TAG, "IPv6 test passed"); + } + + /* Wait until the TCP server starts on the host */ + vTaskDelay(1000 / portTICK_PERIOD_MS); + ESP_LOGI(TAG, "start IPv4 test"); + if (test_tcp_client_ipv4() == ESP_OK) { + ESP_LOGI(TAG, "IPv4 test passed"); + } else { + ESP_LOGE(TAG, "IPv6 test failed!"); + } + + ESP_ERROR_CHECK(esp_modem_stop_ppp(dte)); + /* Destroy the netif adapter withe events, which internally frees also the esp-netif instance */ + esp_modem_netif_clear_default_handlers(modem_netif_adapter); + esp_modem_netif_teardown(modem_netif_adapter); + xEventGroupWaitBits(event_group, STOP_BIT, pdTRUE, pdTRUE, portMAX_DELAY); + ESP_ERROR_CHECK(dce->deinit(dce)); + ESP_ERROR_CHECK(dte->deinit(dte)); +} diff --git a/tools/test_apps/protocols/pppos/sdkconfig.defaults b/tools/test_apps/protocols/pppos/sdkconfig.defaults new file mode 100644 index 0000000000..87d6f9d978 --- /dev/null +++ b/tools/test_apps/protocols/pppos/sdkconfig.defaults @@ -0,0 +1,6 @@ +# Override some defaults to enable PPP +CONFIG_LWIP_PPP_SUPPORT=y +CONFIG_LWIP_PPP_NOTIFY_PHASE_SUPPORT=y +CONFIG_LWIP_PPP_PAP_SUPPORT=y +CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=4096 +CONFIG_LWIP_PPP_ENABLE_IPV6=y