Skip to content

Commit 3625889

Browse files
authored
Merge pull request #286 from david-cermak/feat/example_multiple_netifs
feat(examples): Add multiple netif demo: eth+wifi+PPP
2 parents 6de22f3 + 2bd6163 commit 3625889

23 files changed

+1084
-8
lines changed
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
name: "examples: build/host-tests"
2+
3+
on:
4+
push:
5+
branches:
6+
- master
7+
pull_request:
8+
types: [opened, synchronize, reopened, labeled]
9+
10+
jobs:
11+
build_all_examples:
12+
if: contains(github.event.pull_request.labels.*.name, 'examples') || github.event_name == 'push'
13+
name: Build examples
14+
strategy:
15+
matrix:
16+
idf_ver: ["latest", "release-v5.1"]
17+
runs-on: ubuntu-20.04
18+
container: espressif/idf:${{ matrix.idf_ver }}
19+
steps:
20+
- name: Checkout esp-protocols
21+
uses: actions/checkout@v3
22+
- name: Build with IDF-${{ matrix.idf_ver }}
23+
shell: bash
24+
run: |
25+
. ${IDF_PATH}/export.sh
26+
python -m pip install idf-build-apps
27+
# Build default configs for all targets
28+
python ./ci/build_apps.py examples -m examples/.build-test-rules.yml -d -c
29+
30+
build_and_run_on_host:
31+
if: contains(github.event.pull_request.labels.*.name, 'examples') || github.event_name == 'push'
32+
name: Build and run examples on linux
33+
strategy:
34+
matrix:
35+
idf_ver: ["latest"]
36+
runs-on: ubuntu-20.04
37+
container: espressif/idf:${{ matrix.idf_ver }}
38+
steps:
39+
- name: Checkout esp-protocols
40+
uses: actions/checkout@v3
41+
- name: Build with IDF-${{ matrix.idf_ver }}
42+
shell: bash
43+
run: |
44+
. ${IDF_PATH}/export.sh
45+
python -m pip install idf-build-apps
46+
python ./ci/build_apps.py examples/mqtt -l -t linux
47+
timeout 5 ./examples/mqtt/build_linux_default/esp_mqtt_demo.elf | tee test.log || true
48+
grep 'MQTT_EVENT_DATA' test.log

ci/build_apps.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,20 +26,29 @@
2626
parser.add_argument('-r', '--rules', nargs='*', default=['sdkconfig.ci=default', 'sdkconfig.ci.*=', '=default'], help='Rules how to treat configs')
2727
parser.add_argument('-m', '--manifests', nargs='*', default=[], help='list of manifest files')
2828
parser.add_argument('-d', '--delete', action='store_true', help='Delete build artifacts')
29+
parser.add_argument('-c', '--recursive', action='store_true', help='Build recursively')
30+
parser.add_argument('-l', '--linux', action='store_true', help='Include linux build (dont check warnings)')
2931
args = parser.parse_args()
3032

3133
IDF_PATH = os.environ['IDF_PATH']
3234

33-
print(args.paths)
35+
# Compose the ignore warning strings from the global list and from the environment
36+
ignore_warning_file = os.path.join(os.path.dirname(os.path.realpath(__file__)),'ignore_build_warnings.txt')
37+
ignore_warning = open(ignore_warning_file).read().rstrip('\n').split('\n')
38+
if 'EXPECTED_WARNING' in os.environ:
39+
ignore_warning += os.environ['EXPECTED_WARNING'].split('\n')
40+
if args.linux:
41+
SUPPORTED_TARGETS.append('linux')
42+
ignore_warning = 'warning: ' # Ignore all common warnings on linux builds
3443
setup_logging(2)
3544
apps = find_apps(
3645
args.paths,
37-
recursive=False,
46+
recursive=args.recursive,
3847
target=args.target,
3948
build_dir='build_@t_@w',
4049
config_rules_str=args.rules,
4150
build_log_path='build_log.txt',
42-
size_json_path='size.json',
51+
size_json_path='size.json' if not args.linux else None,
4352
check_warnings=True,
4453
preserve=not args.delete,
4554
manifest_files=args.manifests,
@@ -54,5 +63,5 @@
5463
build_apps(apps,
5564
dry_run=False,
5665
keep_going=False,
57-
ignore_warning_strs=os.environ['EXPECTED_WARNING']
58-
if 'EXPECTED_WARNING' in os.environ else None))
66+
ignore_warning_strs=ignore_warning)
67+
)

ci/ignore_build_warnings.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
DeprecationWarning: pkg_resources is deprecated as an API

examples/.build-test-rules.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
examples/esp_netif/multiple_netifs:
2+
disable:
3+
- if: IDF_TARGET != "esp32"
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# The following lines of boilerplate have to be in your project's CMakeLists
2+
# in this exact order for cmake to work correctly
3+
cmake_minimum_required(VERSION 3.16)
4+
5+
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
6+
project(multiple_netifs)
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
| Supported Targets | ESP32 |
2+
| ----------------- | ----- |
3+
4+
# Multiple Interface example
5+
6+
## Overview
7+
8+
This example demonstrates working with multiple different interfaces with different priorities. It creates these interfaces and tries to connect:
9+
* WiFi Station
10+
* Ethernet using ESP32 internal ethernet driver
11+
* PPPoS over cellular modem
12+
13+
## How to use example
14+
15+
* Set the priorities and the host name for the example to ICMP ping.
16+
* The example will initialize all interfaces
17+
* The example will start looping and checking connectivity to the host name
18+
* It prints the default interface and ping output
19+
* It tries to reconfigure DNS server if host name resolution fails
20+
* It tries to manually change the default interface if connection fails
21+
22+
### Hardware Required
23+
24+
To run this example, it's recommended that you have an official ESP32 Ethernet development board - [ESP32-Ethernet-Kit](https://docs.espressif.com/projects/esp-idf/en/latest/hw-reference/get-started-ethernet-kit.html).
25+
You would also need a modem connected to the board using UART interface.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
set(ppp_connect_srcs ppp_connect.c)
2+
if(CONFIG_EXAMPLE_PPP_CONNECT_ESP_MODEM)
3+
list(APPEND ppp_connect_srcs ppp_connect_esp_modem.c)
4+
else()
5+
list(APPEND ppp_connect_srcs ppp_connect_simple.c)
6+
endif()
7+
8+
idf_component_register(SRCS multi_netif_main.c
9+
check_connection.c
10+
wifi_connect.c
11+
ethernet_connect.c
12+
${ppp_connect_srcs}
13+
INCLUDE_DIRS ".")
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
menu "Example Configuration"
2+
3+
config ESP_WIFI_SSID
4+
string "WiFi SSID"
5+
default "myssid"
6+
help
7+
SSID (network name) for the example to connect to.
8+
9+
config ESP_WIFI_PASSWORD
10+
string "WiFi Password"
11+
default "mypassword"
12+
help
13+
WiFi password (WPA or WPA2) for the example to use.
14+
15+
config ESP_MAXIMUM_RETRY
16+
int "Maximum retry"
17+
default 0
18+
help
19+
Set the Maximum retry to avoid station reconnecting. Set to 0 to keep retrying indefinitely.
20+
21+
config EXAMPLE_MODEM_PPP_APN
22+
string "Set MODEM APN"
23+
default "default.apn"
24+
help
25+
Set APN (Access Point Name), a logical name to choose data network
26+
27+
config EXAMPLE_PPP_UART_TX_PIN
28+
int "TXD Pin Number"
29+
default 15
30+
range 0 31
31+
help
32+
Pin number of UART TX.
33+
34+
config EXAMPLE_PPP_UART_RX_PIN
35+
int "RXD Pin Number"
36+
default 14
37+
range 0 31
38+
help
39+
Pin number of UART RX.
40+
41+
choice EXAMPLE_PPP_CONNECT
42+
prompt "Connect to PPP server"
43+
default EXAMPLE_PPP_CONNECT_ESP_MODEM
44+
help
45+
Choose modem interface library.
46+
We use esp_modem by default, but in some
47+
simple cases (and a very constrained environment)
48+
we could simply connect UART directly to lwIP.
49+
To experiment with this option, choose EXAMPLE_PPP_CONNECT_SIMPLE
50+
51+
config EXAMPLE_PPP_CONNECT_ESP_MODEM
52+
bool "Using esp_modem library"
53+
config EXAMPLE_PPP_CONNECT_SIMPLE
54+
bool "Using simple UART-PPP driver"
55+
endchoice
56+
57+
endmenu
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
3+
*
4+
* SPDX-License-Identifier: Unlicense OR CC0-1.0
5+
*/
6+
/* Checks network connectivity by pinging configured host
7+
8+
This example code is in the Public Domain (or CC0 licensed, at your option.)
9+
10+
Unless required by applicable law or agreed to in writing, this
11+
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12+
CONDITIONS OF ANY KIND, either express or implied.
13+
*/
14+
#include "freertos/FreeRTOS.h"
15+
#include "freertos/event_groups.h"
16+
#include "ping/ping_sock.h"
17+
#include "lwip/netdb.h"
18+
#include "esp_log.h"
19+
20+
#define SUCCESS (1)
21+
#define FAIL (2)
22+
23+
static const char *TAG = "check_connection";
24+
25+
static void cmd_ping_on_ping_success(esp_ping_handle_t hdl, void *args)
26+
{
27+
uint8_t ttl;
28+
uint16_t seqno;
29+
uint32_t elapsed_time, recv_len;
30+
ip_addr_t target_addr;
31+
esp_ping_get_profile(hdl, ESP_PING_PROF_SEQNO, &seqno, sizeof(seqno));
32+
esp_ping_get_profile(hdl, ESP_PING_PROF_TTL, &ttl, sizeof(ttl));
33+
esp_ping_get_profile(hdl, ESP_PING_PROF_IPADDR, &target_addr, sizeof(target_addr));
34+
esp_ping_get_profile(hdl, ESP_PING_PROF_SIZE, &recv_len, sizeof(recv_len));
35+
esp_ping_get_profile(hdl, ESP_PING_PROF_TIMEGAP, &elapsed_time, sizeof(elapsed_time));
36+
ESP_LOGI(TAG, "%" PRIu32 " bytes from %s icmp_seq=%d ttl=%d time=%" PRIu32 " ms",
37+
recv_len, inet_ntoa(target_addr.u_addr.ip4), seqno, ttl, elapsed_time);
38+
}
39+
40+
static void cmd_ping_on_ping_timeout(esp_ping_handle_t hdl, void *args)
41+
{
42+
uint16_t seqno;
43+
ip_addr_t target_addr;
44+
esp_ping_get_profile(hdl, ESP_PING_PROF_SEQNO, &seqno, sizeof(seqno));
45+
esp_ping_get_profile(hdl, ESP_PING_PROF_IPADDR, &target_addr, sizeof(target_addr));
46+
ESP_LOGE(TAG, "From %s icmp_seq=%d timeout", inet_ntoa(target_addr.u_addr.ip4), seqno);
47+
}
48+
49+
static void cmd_ping_on_ping_end(esp_ping_handle_t hdl, void *args)
50+
{
51+
EventGroupHandle_t events = args;
52+
ip_addr_t target_addr;
53+
uint32_t transmitted;
54+
uint32_t received;
55+
uint32_t total_time_ms;
56+
esp_ping_get_profile(hdl, ESP_PING_PROF_REQUEST, &transmitted, sizeof(transmitted));
57+
esp_ping_get_profile(hdl, ESP_PING_PROF_REPLY, &received, sizeof(received));
58+
esp_ping_get_profile(hdl, ESP_PING_PROF_IPADDR, &target_addr, sizeof(target_addr));
59+
esp_ping_get_profile(hdl, ESP_PING_PROF_DURATION, &total_time_ms, sizeof(total_time_ms));
60+
uint32_t loss = (uint32_t)((1 - ((float)received) / transmitted) * 100);
61+
if (IP_IS_V4(&target_addr)) {
62+
ESP_LOGI(TAG, "\n--- %s ping statistics ---", inet_ntoa(*ip_2_ip4(&target_addr)));
63+
} else {
64+
ESP_LOGI(TAG, "\n--- %s ping statistics ---\n", inet6_ntoa(*ip_2_ip6(&target_addr)));
65+
}
66+
ESP_LOGI(TAG, "%" PRIu32 " packets transmitted, %" PRIu32 " received, %" PRIu32 "%% packet loss, time %"PRIu32"ms\n",
67+
transmitted, received, loss, total_time_ms);
68+
xEventGroupSetBits(events, received == 0 ? FAIL : SUCCESS);
69+
}
70+
71+
esp_err_t check_connectivity(const char *host)
72+
{
73+
EventGroupHandle_t events = xEventGroupCreate();
74+
75+
ip_addr_t target_addr;
76+
struct addrinfo hint;
77+
struct addrinfo *res = NULL;
78+
memset(&hint, 0, sizeof(hint));
79+
memset(&target_addr, 0, sizeof(target_addr));
80+
/* convert domain name to IP address */
81+
if (getaddrinfo(host, NULL, &hint, &res) != 0) {
82+
ESP_LOGE(TAG, "ping: unknown host %s\n", host);
83+
return ESP_ERR_NOT_FOUND;
84+
}
85+
if (res->ai_family == AF_INET) {
86+
struct in_addr addr4 = ((struct sockaddr_in *) (res->ai_addr))->sin_addr;
87+
inet_addr_to_ip4addr(ip_2_ip4(&target_addr), &addr4);
88+
} else {
89+
struct in6_addr addr6 = ((struct sockaddr_in6 *) (res->ai_addr))->sin6_addr;
90+
inet6_addr_to_ip6addr(ip_2_ip6(&target_addr), &addr6);
91+
}
92+
freeaddrinfo(res);
93+
94+
esp_ping_config_t config = ESP_PING_DEFAULT_CONFIG();
95+
config.target_addr = target_addr;
96+
97+
esp_ping_callbacks_t cbs = {
98+
.on_ping_success = cmd_ping_on_ping_success,
99+
.on_ping_timeout = cmd_ping_on_ping_timeout,
100+
.on_ping_end = cmd_ping_on_ping_end,
101+
.cb_args = events
102+
};
103+
esp_ping_handle_t ping;
104+
esp_ping_new_session(&config, &cbs, &ping);
105+
esp_ping_start(ping);
106+
vTaskDelay(pdMS_TO_TICKS(config.count * config.interval_ms));
107+
EventBits_t bits = xEventGroupWaitBits(events, FAIL | SUCCESS, pdFALSE, pdFALSE, portMAX_DELAY);
108+
109+
vEventGroupDelete(events);
110+
esp_ping_delete_session(ping);
111+
112+
return bits == SUCCESS ? ESP_OK : ESP_FAIL;
113+
}

0 commit comments

Comments
 (0)