Compare commits

..

11 Commits

Author SHA1 Message Date
ecc465daa3 Merge pull request #321 from gabsuren/mdns/release_1.2.0
bump(mdns): 1.1.0 -> 1.2.0
2023-07-04 12:24:13 +04:00
181b6e4013 bump(mdns): 1.1.0 -> 1.2.0
1.2.0
Features
- add an API for setting address to a delegated host (ddc3eb6)
- Add support for lwip build under linux (588465d)
- Allow for adding a delegated host with no address (c562461)
- Add APIs for looking up self hosted services and getting the self hostname (f0df12d)
Bug Fixes
- Refactor freertos linux compat layers (79a0e57)
- Fix delegated service PTR response (cab0e1d)
- Added unit tests to CI + minor fix to pass it (c974c14)
Updated
- docs: update documentation links (4de5298)
2023-07-04 11:56:33 +04:00
40e3875f76 Merge pull request #315 from zwx1995esp/feature/add_delegate_host_addr_set
feat(mdns): add an API for setting address to a delegated host
2023-07-04 10:54:35 +04:00
ddc3eb62d0 feat(mdns): add an API for setting address to a delegated host 2023-06-29 21:57:39 +08:00
3625889049 Merge pull request #286 from david-cermak/feat/example_multiple_netifs
feat(examples): Add multiple netif demo: eth+wifi+PPP
2023-06-28 17:49:32 +02:00
2bd6163ec8 ci(common): Introduce global warning list file 2023-06-28 16:49:37 +02:00
f1eb46580e feat(examples): Add build/host tests to examples 2023-06-28 12:59:48 +02:00
1c20328dcf feat(examples): Support simple PPP connect in multinet example 2023-06-28 12:59:44 +02:00
6de22f3893 Merge pull request #314 from david-cermak/fix/issue_template
Update issue template with correct docs links
2023-06-27 17:40:36 +02:00
e280b3b541 docs(common): Update issue template with correct docs links 2023-06-26 10:33:16 +02:00
00d7c40848 feat(examples): Add multiple netif demo: eth+wifi+PPP 2023-06-22 11:49:59 +02:00
32 changed files with 1184 additions and 14 deletions

View File

@ -8,7 +8,7 @@ body:
label: Answers checklist.
description: Before submitting a new issue, please follow the checklist and try to find the answer.
options:
- label: I have read the documentation for [esp-protocols components](https://espressif.github.io/esp-protocols/) and the issue is not addressed there.
- label: I have read the documentation for esp-protocols [components](https://github.com/espressif/esp-protocols#readme) and the issue is not addressed there.
required: true
- label: I have updated my esp-protocols branch (master or release) to the latest version and checked that the issue is present there.
required: true

View File

@ -1,7 +1,7 @@
blank_issues_enabled: false
contact_links:
- name: esp-protocols documentation
url: https://espressif.github.io/esp-protocols/
- name: esp-protocols documentation links
url: https://github.com/espressif/esp-protocols#readme
about: Documenation for esp-protocols components.
- name: ESP-IDF Programming Guide
url: https://docs.espressif.com/projects/esp-idf/en/latest/

View File

@ -7,7 +7,7 @@ body:
label: Answers checklist.
description: Before submitting a new issue, please follow the checklist and try to find the answer.
options:
- label: I have read the documentation for [esp-protocols components](https://espressif.github.io/esp-protocols/) and the issue is not addressed there.
- label: I have read the documentation for esp-protocols [components](https://github.com/espressif/esp-protocols#readme) and the issue is not addressed there.
required: true
- label: I have updated my esp-protocols branch (master or release) to the latest version and checked that the issue is present there.
required: true

View File

@ -0,0 +1,48 @@
name: "examples: build/host-tests"
on:
push:
branches:
- master
pull_request:
types: [opened, synchronize, reopened, labeled]
jobs:
build_all_examples:
if: contains(github.event.pull_request.labels.*.name, 'examples') || github.event_name == 'push'
name: Build examples
strategy:
matrix:
idf_ver: ["latest", "release-v5.1"]
runs-on: ubuntu-20.04
container: espressif/idf:${{ matrix.idf_ver }}
steps:
- name: Checkout esp-protocols
uses: actions/checkout@v3
- name: Build with IDF-${{ matrix.idf_ver }}
shell: bash
run: |
. ${IDF_PATH}/export.sh
python -m pip install idf-build-apps
# Build default configs for all targets
python ./ci/build_apps.py examples -m examples/.build-test-rules.yml -d -c
build_and_run_on_host:
if: contains(github.event.pull_request.labels.*.name, 'examples') || github.event_name == 'push'
name: Build and run examples on linux
strategy:
matrix:
idf_ver: ["latest"]
runs-on: ubuntu-20.04
container: espressif/idf:${{ matrix.idf_ver }}
steps:
- name: Checkout esp-protocols
uses: actions/checkout@v3
- name: Build with IDF-${{ matrix.idf_ver }}
shell: bash
run: |
. ${IDF_PATH}/export.sh
python -m pip install idf-build-apps
python ./ci/build_apps.py examples/mqtt -l -t linux
timeout 5 ./examples/mqtt/build_linux_default/esp_mqtt_demo.elf | tee test.log || true
grep 'MQTT_EVENT_DATA' test.log

View File

@ -26,20 +26,29 @@ if __name__ == '__main__':
parser.add_argument('-r', '--rules', nargs='*', default=['sdkconfig.ci=default', 'sdkconfig.ci.*=', '=default'], help='Rules how to treat configs')
parser.add_argument('-m', '--manifests', nargs='*', default=[], help='list of manifest files')
parser.add_argument('-d', '--delete', action='store_true', help='Delete build artifacts')
parser.add_argument('-c', '--recursive', action='store_true', help='Build recursively')
parser.add_argument('-l', '--linux', action='store_true', help='Include linux build (dont check warnings)')
args = parser.parse_args()
IDF_PATH = os.environ['IDF_PATH']
print(args.paths)
# Compose the ignore warning strings from the global list and from the environment
ignore_warning_file = os.path.join(os.path.dirname(os.path.realpath(__file__)),'ignore_build_warnings.txt')
ignore_warning = open(ignore_warning_file).read().rstrip('\n').split('\n')
if 'EXPECTED_WARNING' in os.environ:
ignore_warning += os.environ['EXPECTED_WARNING'].split('\n')
if args.linux:
SUPPORTED_TARGETS.append('linux')
ignore_warning = 'warning: ' # Ignore all common warnings on linux builds
setup_logging(2)
apps = find_apps(
args.paths,
recursive=False,
recursive=args.recursive,
target=args.target,
build_dir='build_@t_@w',
config_rules_str=args.rules,
build_log_path='build_log.txt',
size_json_path='size.json',
size_json_path='size.json' if not args.linux else None,
check_warnings=True,
preserve=not args.delete,
manifest_files=args.manifests,
@ -54,5 +63,5 @@ if __name__ == '__main__':
build_apps(apps,
dry_run=False,
keep_going=False,
ignore_warning_strs=os.environ['EXPECTED_WARNING']
if 'EXPECTED_WARNING' in os.environ else None))
ignore_warning_strs=ignore_warning)
)

View File

@ -0,0 +1 @@
DeprecationWarning: pkg_resources is deprecated as an API

View File

@ -3,6 +3,6 @@ commitizen:
bump_message: 'bump(mdns): $current_version -> $new_version'
pre_bump_hooks: python ../../ci/changelog.py mdns
tag_format: mdns-v$version
version: 1.1.0
version: 1.2.0
version_files:
- idf_component.yml

View File

@ -1,5 +1,24 @@
# Changelog
## [1.2.0](https://github.com/espressif/esp-protocols/commits/mdns-v1.2.0)
### Features
- add an API for setting address to a delegated host ([ddc3eb6](https://github.com/espressif/esp-protocols/commit/ddc3eb6))
- Add support for lwip build under linux ([588465d](https://github.com/espressif/esp-protocols/commit/588465d))
- Allow for adding a delegated host with no address ([c562461](https://github.com/espressif/esp-protocols/commit/c562461))
- Add APIs for looking up self hosted services and getting the self hostname ([f0df12d](https://github.com/espressif/esp-protocols/commit/f0df12d))
### Bug Fixes
- Refactor freertos linux compat layers ([79a0e57](https://github.com/espressif/esp-protocols/commit/79a0e57))
- Fix delegated service PTR response ([cab0e1d](https://github.com/espressif/esp-protocols/commit/cab0e1d))
- Added unit tests to CI + minor fix to pass it ([c974c14](https://github.com/espressif/esp-protocols/commit/c974c14))
### Updated
- docs: update documentation links ([4de5298](https://github.com/espressif/esp-protocols/commit/4de5298))
## [1.1.0](https://github.com/espressif/esp-protocols/commits/mdns-v1.1.0)
### Features

View File

@ -1,4 +1,4 @@
version: "1.1.0"
version: "1.2.0"
description: mDNS
url: https://github.com/espressif/esp-protocols/tree/master/components/mdns
dependencies:

View File

@ -158,6 +158,21 @@ esp_err_t mdns_hostname_get(char *hostname);
*/
esp_err_t mdns_delegate_hostname_add(const char *hostname, const mdns_ip_addr_t *address_list);
/**
* @brief Set the address to a delegated hostname
*
* @param hostname Hostname to set
* @param address_list The IP address list of the host
*
* @return
* - ESP_OK success
* - ESP_ERR_INVALID_STATE mDNS is not running
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_ERR_NO_MEM memory error
*
*/
esp_err_t mdns_delegate_hostname_set_address(const char *hostname, const mdns_ip_addr_t *address_list);
/**
* @brief Remove a delegated hostname
* All the services added to this host will also be removed.

View File

@ -2993,6 +2993,27 @@ static void free_address_list(mdns_ip_addr_t *address_list)
}
}
static bool _mdns_delegate_hostname_set_address(const char *hostname, mdns_ip_addr_t *address_list)
{
if (!_str_null_or_empty(_mdns_server->hostname) &&
strcasecmp(hostname, _mdns_server->hostname) == 0) {
return false;
}
mdns_host_item_t *host = _mdns_host_list;
while (host != NULL) {
if (strcasecmp(hostname, host->hostname) == 0) {
// free previous address list
free_address_list(host->address_list);
// set current address list to the host
host->address_list = address_list;
return true;
}
host = host->next;
}
return false;
}
static mdns_ip_addr_t *copy_address_list(const mdns_ip_addr_t *address_list)
{
mdns_ip_addr_t *head = NULL;
@ -4845,6 +4866,7 @@ static void _mdns_free_action(mdns_action_t *action)
case ACTION_RX_HANDLE:
_mdns_packet_free(action->data.rx_handle.packet);
break;
case ACTION_DELEGATE_HOSTNAME_SET_ADDR:
case ACTION_DELEGATE_HOSTNAME_ADD:
free((char *)action->data.delegate_hostname.hostname);
free_address_list(action->data.delegate_hostname.address_list);
@ -5065,6 +5087,13 @@ static void _mdns_execute_action(mdns_action_t *action)
free_address_list(action->data.delegate_hostname.address_list);
}
break;
case ACTION_DELEGATE_HOSTNAME_SET_ADDR:
if (!_mdns_delegate_hostname_set_address(action->data.delegate_hostname.hostname,
action->data.delegate_hostname.address_list)) {
free_address_list(action->data.delegate_hostname.address_list);
}
free((char *)action->data.delegate_hostname.hostname);
break;
case ACTION_DELEGATE_HOSTNAME_REMOVE:
_mdns_delegate_hostname_remove(action->data.delegate_hostname.hostname);
free((char *)action->data.delegate_hostname.hostname);
@ -5634,6 +5663,36 @@ esp_err_t mdns_delegate_hostname_remove(const char *hostname)
return ESP_OK;
}
esp_err_t mdns_delegate_hostname_set_address(const char *hostname, const mdns_ip_addr_t *address_list)
{
if (!_mdns_server) {
return ESP_ERR_INVALID_STATE;
}
if (_str_null_or_empty(hostname) || strlen(hostname) > (MDNS_NAME_BUF_LEN - 1)) {
return ESP_ERR_INVALID_ARG;
}
char *new_hostname = strndup(hostname, MDNS_NAME_BUF_LEN - 1);
if (!new_hostname) {
return ESP_ERR_NO_MEM;
}
mdns_action_t *action = (mdns_action_t *)malloc(sizeof(mdns_action_t));
if (!action) {
HOOK_MALLOC_FAILED;
free(new_hostname);
return ESP_ERR_NO_MEM;
}
action->type = ACTION_DELEGATE_HOSTNAME_SET_ADDR;
action->data.delegate_hostname.hostname = new_hostname;
action->data.delegate_hostname.address_list = copy_address_list(address_list);
if (xQueueSend(_mdns_server->action_queue, &action, (TickType_t)0) != pdPASS) {
free(new_hostname);
free(action);
return ESP_ERR_NO_MEM;
}
return ESP_OK;
}
bool mdns_hostname_exists(const char *hostname)
{
return _hostname_is_ours(hostname);

View File

@ -196,6 +196,7 @@ typedef enum {
ACTION_TASK_STOP,
ACTION_DELEGATE_HOSTNAME_ADD,
ACTION_DELEGATE_HOSTNAME_REMOVE,
ACTION_DELEGATE_HOSTNAME_SET_ADDR,
ACTION_MAX
} mdns_action_type_t;

View File

@ -0,0 +1,3 @@
examples/esp_netif/multiple_netifs:
disable:
- if: IDF_TARGET != "esp32"

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(multiple_netifs)

View File

@ -0,0 +1,25 @@
| Supported Targets | ESP32 |
| ----------------- | ----- |
# Multiple Interface example
## Overview
This example demonstrates working with multiple different interfaces with different priorities. It creates these interfaces and tries to connect:
* WiFi Station
* Ethernet using ESP32 internal ethernet driver
* PPPoS over cellular modem
## How to use example
* Set the priorities and the host name for the example to ICMP ping.
* The example will initialize all interfaces
* The example will start looping and checking connectivity to the host name
* It prints the default interface and ping output
* It tries to reconfigure DNS server if host name resolution fails
* It tries to manually change the default interface if connection fails
### Hardware Required
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).
You would also need a modem connected to the board using UART interface.

View File

@ -0,0 +1,13 @@
set(ppp_connect_srcs ppp_connect.c)
if(CONFIG_EXAMPLE_PPP_CONNECT_ESP_MODEM)
list(APPEND ppp_connect_srcs ppp_connect_esp_modem.c)
else()
list(APPEND ppp_connect_srcs ppp_connect_simple.c)
endif()
idf_component_register(SRCS multi_netif_main.c
check_connection.c
wifi_connect.c
ethernet_connect.c
${ppp_connect_srcs}
INCLUDE_DIRS ".")

View File

@ -0,0 +1,57 @@
menu "Example Configuration"
config ESP_WIFI_SSID
string "WiFi SSID"
default "myssid"
help
SSID (network name) for the example to connect to.
config ESP_WIFI_PASSWORD
string "WiFi Password"
default "mypassword"
help
WiFi password (WPA or WPA2) for the example to use.
config ESP_MAXIMUM_RETRY
int "Maximum retry"
default 0
help
Set the Maximum retry to avoid station reconnecting. Set to 0 to keep retrying indefinitely.
config EXAMPLE_MODEM_PPP_APN
string "Set MODEM APN"
default "default.apn"
help
Set APN (Access Point Name), a logical name to choose data network
config EXAMPLE_PPP_UART_TX_PIN
int "TXD Pin Number"
default 15
range 0 31
help
Pin number of UART TX.
config EXAMPLE_PPP_UART_RX_PIN
int "RXD Pin Number"
default 14
range 0 31
help
Pin number of UART RX.
choice EXAMPLE_PPP_CONNECT
prompt "Connect to PPP server"
default EXAMPLE_PPP_CONNECT_ESP_MODEM
help
Choose modem interface library.
We use esp_modem by default, but in some
simple cases (and a very constrained environment)
we could simply connect UART directly to lwIP.
To experiment with this option, choose EXAMPLE_PPP_CONNECT_SIMPLE
config EXAMPLE_PPP_CONNECT_ESP_MODEM
bool "Using esp_modem library"
config EXAMPLE_PPP_CONNECT_SIMPLE
bool "Using simple UART-PPP driver"
endchoice
endmenu

View File

@ -0,0 +1,113 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
/* Checks network connectivity by pinging configured host
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 "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "ping/ping_sock.h"
#include "lwip/netdb.h"
#include "esp_log.h"
#define SUCCESS (1)
#define FAIL (2)
static const char *TAG = "check_connection";
static void cmd_ping_on_ping_success(esp_ping_handle_t hdl, void *args)
{
uint8_t ttl;
uint16_t seqno;
uint32_t elapsed_time, recv_len;
ip_addr_t target_addr;
esp_ping_get_profile(hdl, ESP_PING_PROF_SEQNO, &seqno, sizeof(seqno));
esp_ping_get_profile(hdl, ESP_PING_PROF_TTL, &ttl, sizeof(ttl));
esp_ping_get_profile(hdl, ESP_PING_PROF_IPADDR, &target_addr, sizeof(target_addr));
esp_ping_get_profile(hdl, ESP_PING_PROF_SIZE, &recv_len, sizeof(recv_len));
esp_ping_get_profile(hdl, ESP_PING_PROF_TIMEGAP, &elapsed_time, sizeof(elapsed_time));
ESP_LOGI(TAG, "%" PRIu32 " bytes from %s icmp_seq=%d ttl=%d time=%" PRIu32 " ms",
recv_len, inet_ntoa(target_addr.u_addr.ip4), seqno, ttl, elapsed_time);
}
static void cmd_ping_on_ping_timeout(esp_ping_handle_t hdl, void *args)
{
uint16_t seqno;
ip_addr_t target_addr;
esp_ping_get_profile(hdl, ESP_PING_PROF_SEQNO, &seqno, sizeof(seqno));
esp_ping_get_profile(hdl, ESP_PING_PROF_IPADDR, &target_addr, sizeof(target_addr));
ESP_LOGE(TAG, "From %s icmp_seq=%d timeout", inet_ntoa(target_addr.u_addr.ip4), seqno);
}
static void cmd_ping_on_ping_end(esp_ping_handle_t hdl, void *args)
{
EventGroupHandle_t events = args;
ip_addr_t target_addr;
uint32_t transmitted;
uint32_t received;
uint32_t total_time_ms;
esp_ping_get_profile(hdl, ESP_PING_PROF_REQUEST, &transmitted, sizeof(transmitted));
esp_ping_get_profile(hdl, ESP_PING_PROF_REPLY, &received, sizeof(received));
esp_ping_get_profile(hdl, ESP_PING_PROF_IPADDR, &target_addr, sizeof(target_addr));
esp_ping_get_profile(hdl, ESP_PING_PROF_DURATION, &total_time_ms, sizeof(total_time_ms));
uint32_t loss = (uint32_t)((1 - ((float)received) / transmitted) * 100);
if (IP_IS_V4(&target_addr)) {
ESP_LOGI(TAG, "\n--- %s ping statistics ---", inet_ntoa(*ip_2_ip4(&target_addr)));
} else {
ESP_LOGI(TAG, "\n--- %s ping statistics ---\n", inet6_ntoa(*ip_2_ip6(&target_addr)));
}
ESP_LOGI(TAG, "%" PRIu32 " packets transmitted, %" PRIu32 " received, %" PRIu32 "%% packet loss, time %"PRIu32"ms\n",
transmitted, received, loss, total_time_ms);
xEventGroupSetBits(events, received == 0 ? FAIL : SUCCESS);
}
esp_err_t check_connectivity(const char *host)
{
EventGroupHandle_t events = xEventGroupCreate();
ip_addr_t target_addr;
struct addrinfo hint;
struct addrinfo *res = NULL;
memset(&hint, 0, sizeof(hint));
memset(&target_addr, 0, sizeof(target_addr));
/* convert domain name to IP address */
if (getaddrinfo(host, NULL, &hint, &res) != 0) {
ESP_LOGE(TAG, "ping: unknown host %s\n", host);
return ESP_ERR_NOT_FOUND;
}
if (res->ai_family == AF_INET) {
struct in_addr addr4 = ((struct sockaddr_in *) (res->ai_addr))->sin_addr;
inet_addr_to_ip4addr(ip_2_ip4(&target_addr), &addr4);
} else {
struct in6_addr addr6 = ((struct sockaddr_in6 *) (res->ai_addr))->sin6_addr;
inet6_addr_to_ip6addr(ip_2_ip6(&target_addr), &addr6);
}
freeaddrinfo(res);
esp_ping_config_t config = ESP_PING_DEFAULT_CONFIG();
config.target_addr = target_addr;
esp_ping_callbacks_t cbs = {
.on_ping_success = cmd_ping_on_ping_success,
.on_ping_timeout = cmd_ping_on_ping_timeout,
.on_ping_end = cmd_ping_on_ping_end,
.cb_args = events
};
esp_ping_handle_t ping;
esp_ping_new_session(&config, &cbs, &ping);
esp_ping_start(ping);
vTaskDelay(pdMS_TO_TICKS(config.count * config.interval_ms));
EventBits_t bits = xEventGroupWaitBits(events, FAIL | SUCCESS, pdFALSE, pdFALSE, portMAX_DELAY);
vEventGroupDelete(events);
esp_ping_delete_session(ping);
return bits == SUCCESS ? ESP_OK : ESP_FAIL;
}

View File

@ -0,0 +1,137 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
/* Ethernet Basic Initialization
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 "esp_netif.h"
#include "esp_eth.h"
#include "esp_event.h"
#include "esp_log.h"
#include "sdkconfig.h"
#include "iface_info.h"
static const char *TAG = "ethernet_connect";
struct eth_info_t {
iface_info_t parent;
esp_eth_handle_t eth_handle;
esp_eth_netif_glue_handle_t glue;
esp_eth_mac_t *mac;
esp_eth_phy_t *phy;
};
static void eth_event_handler(void *args, esp_event_base_t event_base,
int32_t event_id, void *event_data)
{
uint8_t mac_addr[6] = {0};
/* we can get the ethernet driver handle from event data */
esp_eth_handle_t eth_handle = *(esp_eth_handle_t *)event_data;
struct eth_info_t *eth_info = args;
switch (event_id) {
case ETHERNET_EVENT_CONNECTED:
esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, mac_addr);
ESP_LOGI(TAG, "Ethernet Link Up");
ESP_LOGI(TAG, "Ethernet HW Addr %02x:%02x:%02x:%02x:%02x:%02x",
mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
eth_info->parent.connected = true;
break;
case ETHERNET_EVENT_DISCONNECTED:
ESP_LOGI(TAG, "Ethernet Link Down");
eth_info->parent.connected = false;
break;
case ETHERNET_EVENT_START:
ESP_LOGI(TAG, "Ethernet Started");
break;
case ETHERNET_EVENT_STOP:
ESP_LOGI(TAG, "Ethernet Stopped");
break;
default:
break;
}
}
static void got_ip_event_handler(void *args, esp_event_base_t event_base,
int32_t event_id, void *event_data)
{
ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data;
const esp_netif_ip_info_t *ip_info = &event->ip_info;
struct eth_info_t *eth_info = args;
ESP_LOGI(TAG, "Ethernet Got IP Address");
ESP_LOGI(TAG, "~~~~~~~~~~~");
ESP_LOGI(TAG, "IP:" IPSTR, IP2STR(&ip_info->ip));
ESP_LOGI(TAG, "MASK:" IPSTR, IP2STR(&ip_info->netmask));
ESP_LOGI(TAG, "GW:" IPSTR, IP2STR(&ip_info->gw));
ESP_LOGI(TAG, "~~~~~~~~~~~");
for (int i = 0; i < 2; ++i) {
esp_netif_get_dns_info(eth_info->parent.netif, i, &eth_info->parent.dns[i]);
ESP_LOGI(TAG, "DNS %i:" IPSTR, i, IP2STR(&eth_info->parent.dns[i].ip.u_addr.ip4));
}
ESP_LOGI(TAG, "~~~~~~~~~~~");
}
static void eth_destroy(iface_info_t *info)
{
struct eth_info_t *eth_info = __containerof(info, struct eth_info_t, parent);
esp_eth_stop(eth_info->eth_handle);
esp_eth_del_netif_glue(eth_info->glue);
esp_eth_driver_uninstall(eth_info->eth_handle);
eth_info->phy->del(eth_info->phy);
eth_info->mac->del(eth_info->mac);
esp_netif_destroy(eth_info->parent.netif);
free(eth_info);
}
iface_info_t *eth_init(int prio)
{
struct eth_info_t *eth_info = malloc(sizeof(struct eth_info_t));
assert(eth_info);
eth_info->parent.destroy = eth_destroy;
eth_info->parent.name = "Ethernet";
// Init common MAC and PHY configs to default
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
// Use internal ESP32's ethernet
eth_esp32_emac_config_t esp32_emac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG();
eth_info->mac = esp_eth_mac_new_esp32(&esp32_emac_config, &mac_config);
eth_info->phy = esp_eth_phy_new_ip101(&phy_config);
// Init Ethernet driver to default and install it
esp_eth_config_t config = ETH_DEFAULT_CONFIG(eth_info->mac, eth_info->phy);
ESP_ERROR_CHECK(esp_eth_driver_install(&config, &eth_info->eth_handle));
// Create an instance of esp-netif for Ethernet
esp_netif_inherent_config_t base_netif_cfg = ESP_NETIF_INHERENT_DEFAULT_ETH();
base_netif_cfg.route_prio = prio;
esp_netif_config_t cfg = {
.base = &base_netif_cfg,
.stack = ESP_NETIF_NETSTACK_DEFAULT_ETH,
};
eth_info->parent.netif = esp_netif_new(&cfg);
eth_info->glue = esp_eth_new_netif_glue(eth_info->eth_handle);
// Attach Ethernet driver to TCP/IP stack
ESP_ERROR_CHECK(esp_netif_attach(eth_info->parent.netif, eth_info->glue ));
// Register user defined event handers
ESP_ERROR_CHECK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, &eth_event_handler, eth_info));
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &got_ip_event_handler, eth_info));
// Start Ethernet driver state machine
ESP_ERROR_CHECK(esp_eth_start(eth_info->eth_handle));
return &eth_info->parent;
}

View File

@ -0,0 +1,4 @@
dependencies:
espressif/esp_modem:
version: "^1.0.0"
override_path: "../../../../components/esp_modem"

View File

@ -0,0 +1,26 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
/* Common interface info
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.
*/
#pragma once
#include "esp_netif.h"
struct iface_info_t {
esp_netif_t *netif;
esp_netif_dns_info_t dns[2];
void (*destroy)(struct iface_info_t *);
const char *name;
bool connected;
};
typedef struct iface_info_t iface_info_t;

View File

@ -0,0 +1,129 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
/* Multiple Network Interface 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 <lwip/dns.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_netif.h"
#include "esp_event.h"
#include "esp_log.h"
#include "sdkconfig.h"
#include "nvs_flash.h"
#include "iface_info.h"
iface_info_t *eth_init(int prio);
iface_info_t *wifi_init(int prio);
iface_info_t *ppp_init(int prio);
esp_err_t check_connectivity(const char *host);
#define HOST "www.espressif.com"
#define ETH_PRIO 200
#define WIFI_PRIO 100
#define PPP_PRIO 50
static const char *TAG = "app_main";
static ssize_t get_default(iface_info_t *list[], size_t num)
{
esp_netif_t *default_netif = esp_netif_get_default_netif();
if (default_netif == NULL) {
ESP_LOGE(TAG, "default netif is NULL!");
return -1;
}
ESP_LOGI(TAG, "Default netif: %s", esp_netif_get_desc(default_netif));
for (int i = 0; i < num; ++i) {
if (list[i] && list[i]->netif == default_netif) {
ESP_LOGI(TAG, "Default interface: %s", list[i]->name);
return i;
}
}
// not found
return -2;
}
void app_main(void)
{
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
ESP_ERROR_CHECK(esp_netif_init());
// Create default event loop that running in background
ESP_ERROR_CHECK(esp_event_loop_create_default());
// all interfaces
iface_info_t *ifaces[] = {
eth_init(ETH_PRIO),
wifi_init(WIFI_PRIO),
ppp_init(PPP_PRIO),
};
size_t num_of_ifaces = sizeof(ifaces) / sizeof(ifaces[0]);
while (true) {
dns_clear_cache();
vTaskDelay(pdMS_TO_TICKS(2000));
ssize_t i = get_default(ifaces, num_of_ifaces);
if (i == -1) { // default netif is NULL, probably all interfaces are down -> retry
continue;
} else if (i < 0) {
break; // some other error, exit
}
esp_err_t connect_status = check_connectivity(HOST);
if (connect_status == ESP_OK) {
// connectivity ok
continue;
}
if (connect_status == ESP_ERR_NOT_FOUND) {
// set the default DNS info to global DNS server list
for (int j = 0; j < 2; ++j) {
esp_netif_dns_info_t dns_info;
esp_netif_get_dns_info(ifaces[i]->netif, j, &dns_info);
if (memcmp(&dns_info.ip, &ifaces[i]->dns[j].ip, sizeof(esp_ip_addr_t)) == 0) {
connect_status = ESP_FAIL;
} else {
esp_netif_set_dns_info(ifaces[i]->netif, j, &ifaces[i]->dns[j]);
ESP_LOGI(TAG, "Reconfigured DNS%i=" IPSTR, j, IP2STR(&ifaces[i]->dns[j].ip.u_addr.ip4));
}
}
}
if (connect_status == ESP_FAIL) {
ESP_LOGE(TAG, "No connection via the default netif!");
// try to switch interfaces manually
// WARNING: Once we set_default_netif() manually, we disable the automatic prio-routing
int next = (i + 1) % num_of_ifaces;
while (ifaces[i] != ifaces[next]) {
if (ifaces[next]->connected) {
ESP_LOGE(TAG, "Trying another interface: %s", ifaces[next]->name);
esp_netif_set_default_netif(ifaces[next]->netif);
break;
}
++next;
next = next % num_of_ifaces;
}
}
}
ESP_LOGI(TAG, "Stop and cleanup all interfaces");
for (int i = 0; i < num_of_ifaces; ++i) {
if (ifaces[i]) {
ifaces[i]->destroy(ifaces[i]);
}
}
}

View File

@ -0,0 +1,123 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
/* PPPoS Initialization
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "esp_netif.h"
#include "esp_netif_ppp.h"
#include "mqtt_client.h"
#include "esp_log.h"
#include "sdkconfig.h"
#include "iface_info.h"
#include "ppp_connect.h"
static const int CONNECT_BIT = BIT0;
static const char *TAG = "pppos_connect";
static EventGroupHandle_t event_group = NULL;
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 %" PRIu32, event_id);
if (event_id == NETIF_PPP_ERRORUSER) {
struct ppp_info_t *ppp_info = arg;
esp_netif_t *netif = event_data;
ESP_LOGI(TAG, "User interrupted event from netif:%p", netif);
ppp_info->parent.connected = false;
}
}
static void on_ip_event(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data)
{
ESP_LOGD(TAG, "IP event! %" PRIu32, event_id);
struct ppp_info_t *ppp_info = arg;
if (event_id == IP_EVENT_PPP_GOT_IP) {
ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data;
ESP_LOGI(TAG, "Modem Connect to PPP Server");
ESP_LOGI(TAG, "~~~~~~~~~~~~~~");
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));
for (int i = 0; i < 2; ++i) {
esp_netif_get_dns_info(ppp_info->parent.netif, i, &ppp_info->parent.dns[i]);
ESP_LOGI(TAG, "DNS %i:" IPSTR, i, IP2STR(&ppp_info->parent.dns[i].ip.u_addr.ip4));
}
ESP_LOGI(TAG, "~~~~~~~~~~~~~~");
xEventGroupSetBits(event_group, CONNECT_BIT);
ppp_info->parent.connected = true;
ESP_LOGI(TAG, "GOT ip event!!!");
} else if (event_id == IP_EVENT_PPP_LOST_IP) {
ESP_LOGI(TAG, "Modem Disconnect from PPP Server");
ppp_info->parent.connected = false;
} 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 void ppp_destroy(iface_info_t *info)
{
struct ppp_info_t *ppp_info = __containerof(info, struct ppp_info_t, parent);
esp_netif_action_disconnected(ppp_info->parent.netif, 0, 0, 0);
esp_netif_action_stop(ppp_info->parent.netif, 0, 0, 0);
ppp_destroy_context(ppp_info);
vEventGroupDelete(event_group);
ppp_info->stop_task = true;
free(info);
}
iface_info_t *init_ppp(int prio)
{
struct ppp_info_t *ppp_info = calloc(1, sizeof(struct ppp_info_t));
assert(ppp_info);
ppp_info->parent.destroy = ppp_destroy;
ppp_info->parent.name = "Modem";
event_group = xEventGroupCreate();
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, ESP_EVENT_ANY_ID, &on_ip_event, ppp_info));
ESP_ERROR_CHECK(esp_event_handler_register(NETIF_PPP_STATUS, ESP_EVENT_ANY_ID, &on_ppp_changed, ppp_info));
esp_netif_inherent_config_t base_netif_cfg = ESP_NETIF_INHERENT_DEFAULT_PPP();
base_netif_cfg.route_prio = prio;
esp_netif_config_t netif_ppp_config = { .base = &base_netif_cfg,
.driver = ppp_driver_cfg,
.stack = ESP_NETIF_NETSTACK_DEFAULT_PPP
};
ppp_info->parent.netif = esp_netif_new(&netif_ppp_config);
if (ppp_info->parent.netif == NULL) {
goto err;
}
if (xTaskCreate(ppp_task, "ppp_retry_task", 4096, ppp_info, 5, NULL) != pdTRUE) {
goto err;
}
ESP_LOGI(TAG, "Waiting for IP address");
xEventGroupWaitBits(event_group, CONNECT_BIT, pdFALSE, pdFALSE, pdMS_TO_TICKS(10000));
return &ppp_info->parent;
err:
ppp_destroy(&ppp_info->parent);
return NULL;
}

View File

@ -0,0 +1,18 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#pragma once
struct ppp_info_t {
iface_info_t parent;
void *context;
bool stop_task;
};
extern const esp_netif_driver_ifconfig_t *ppp_driver_cfg;
void ppp_task(void *args);
void ppp_destroy_context(struct ppp_info_t *ppp_info);

View File

@ -0,0 +1,109 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "esp_netif.h"
#include "esp_netif_ppp.h"
#include "mqtt_client.h"
#include "esp_modem_api.h"
#include "esp_log.h"
#include "sdkconfig.h"
#include "iface_info.h"
#include "ppp_connect.h"
static const char *TAG = "ppp_esp_modem";
const esp_netif_driver_ifconfig_t *ppp_driver_cfg = NULL;
void ppp_task(void *args)
{
struct ppp_info_t *ppp_info = args;
int backoff_time = 15000;
const int max_backoff = 60000;
esp_modem_dce_config_t dce_config = ESP_MODEM_DCE_DEFAULT_CONFIG(CONFIG_EXAMPLE_MODEM_PPP_APN);
esp_modem_dte_config_t dte_config = ESP_MODEM_DTE_DEFAULT_CONFIG();
dte_config.uart_config.tx_io_num = CONFIG_EXAMPLE_PPP_UART_TX_PIN;
dte_config.uart_config.rx_io_num = CONFIG_EXAMPLE_PPP_UART_RX_PIN;
esp_modem_dce_t *dce = esp_modem_new(&dte_config, &dce_config, ppp_info->parent.netif);
ppp_info->context = dce;
int rssi, ber;
esp_err_t ret = esp_modem_get_signal_quality(dce, &rssi, &ber);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "esp_modem_get_signal_quality failed with %d %s", ret, esp_err_to_name(ret));
goto failed;
}
ESP_LOGI(TAG, "Signal quality: rssi=%d, ber=%d", rssi, ber);
ret = esp_modem_set_mode(dce, ESP_MODEM_MODE_DATA);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "esp_modem_set_mode(ESP_MODEM_MODE_DATA) failed with %d", ret);
goto failed;
}
failed:
#define CONTINUE_LATER() backoff_time *= 2; \
if (backoff_time > max_backoff) { backoff_time = max_backoff; } \
continue;
// now let's keep retrying
while (!ppp_info->stop_task) {
vTaskDelay(pdMS_TO_TICKS(backoff_time));
if (ppp_info->parent.connected) {
backoff_time = 5000;
continue;
}
// try if the modem got stuck in data mode
ESP_LOGI(TAG, "Trying to Sync with modem");
ret = esp_modem_sync(dce);
if (ret != ESP_OK) {
ESP_LOGI(TAG, "Switching to command mode");
esp_modem_set_mode(dce, ESP_MODEM_MODE_COMMAND);
ESP_LOGI(TAG, "Retry sync 3 times");
for (int i = 0; i < 3; ++i) {
ret = esp_modem_sync(dce);
if (ret == ESP_OK) {
break;
}
vTaskDelay(pdMS_TO_TICKS(1000));
}
if (ret != ESP_OK) {
CONTINUE_LATER();
}
}
ESP_LOGI(TAG, "Manual hang-up before reconnecting");
ret = esp_modem_at(dce, "ATH", NULL, 2000);
if (ret != ESP_OK) {
CONTINUE_LATER();
}
ret = esp_modem_get_signal_quality(dce, &rssi, &ber);
if (ret != ESP_OK) {
CONTINUE_LATER();
}
ESP_LOGI(TAG, "Signal quality: rssi=%d, ber=%d", rssi, ber);
ret = esp_modem_set_mode(dce, ESP_MODEM_MODE_DATA);
if (ret != ESP_OK) {
CONTINUE_LATER();
}
}
#undef CONTINUE_LATER
vTaskDelete(NULL);
}
void ppp_destroy_context(struct ppp_info_t *ppp_info)
{
esp_modem_dce_t *dce = ppp_info->context;
esp_err_t err = esp_modem_set_mode(dce, ESP_MODEM_MODE_COMMAND);
if (err != ESP_OK) {
ESP_LOGE(TAG, "esp_modem_set_mode(ESP_MODEM_MODE_COMMAND) failed with %d", err);
return;
}
esp_modem_destroy(dce);
}

View File

@ -0,0 +1,122 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <string.h>
#include "esp_netif.h"
#include "esp_log.h"
#include "esp_event.h"
#include "sdkconfig.h"
#include "iface_info.h"
#include "ppp_connect.h"
#include "driver/uart.h"
static const char *TAG = "ppp_connect_simple";
static esp_err_t transmit(void *h, void *buffer, size_t len)
{
ESP_LOG_BUFFER_HEXDUMP("ppp_connect_tx", buffer, len, ESP_LOG_VERBOSE);
uart_write_bytes(UART_NUM_1, buffer, len);
return ESP_OK;
}
static esp_netif_driver_ifconfig_t driver_cfg = {
.handle = (void *)1, // singleton driver, just to != NULL
.transmit = transmit,
};
const esp_netif_driver_ifconfig_t *ppp_driver_cfg = &driver_cfg;
#define BUF_SIZE (1024)
#define CONNECTED "CONNECT 115200"
void ppp_task(void *args)
{
struct ppp_info_t *ppp_info = args;
uart_config_t uart_config = {
.baud_rate = 115200,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
.source_clk = UART_SCLK_DEFAULT,
};
QueueHandle_t event_queue;
ESP_ERROR_CHECK(uart_driver_install(UART_NUM_1, BUF_SIZE, 0, 16, &event_queue, 0));
ESP_ERROR_CHECK(uart_param_config(UART_NUM_1, &uart_config));
ESP_ERROR_CHECK(uart_set_pin(UART_NUM_1, CONFIG_EXAMPLE_PPP_UART_TX_PIN, CONFIG_EXAMPLE_PPP_UART_RX_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
ESP_ERROR_CHECK(uart_set_rx_timeout(UART_NUM_1, 1));
char *buffer = malloc(BUF_SIZE);
ppp_info->context = buffer;
const struct seq_t {
const char *cmd;
const char *expect;
bool allow_fail;
} init_sequence[] = {
{ .cmd = "AT\r\n", .expect = "OK" },
{ .cmd = "AT+CGDCONT=1,\"IP\",\"" CONFIG_EXAMPLE_MODEM_PPP_APN "\"\r\n", .expect = "OK" },
{ .cmd = "ATD*99##\r\n", .expect = "CONNECT", .allow_fail = true },
{ .cmd = "ATO\r\n", .expect = "CONNECT" },
};
int cmd_i = 0;
int retry = 0;
char *reply = buffer;
const int max_retries = 3;
uart_event_t event;
uart_write_bytes(UART_NUM_1, "+++", 3);
vTaskDelay(pdMS_TO_TICKS(1000));
while (retry < max_retries) {
ESP_LOGD(TAG, "Sending command: %s", init_sequence[cmd_i].cmd);
uart_write_bytes(UART_NUM_1, init_sequence[cmd_i].cmd, strlen(init_sequence[cmd_i].cmd));
xQueueReceive(event_queue, &event, pdMS_TO_TICKS(pdMS_TO_TICKS(1000)));
size_t len;
uart_get_buffered_data_len(UART_NUM_1, &len);
if (!len) {
continue;
}
len = uart_read_bytes(UART_NUM_1, reply, BUF_SIZE, 0);
ESP_LOGD(TAG, "Received: %.*s", len, reply);
if (strstr(reply, init_sequence[cmd_i].expect) || init_sequence[cmd_i].allow_fail) {
if (strstr(reply, CONNECTED)) { // are we connected already?
break;
}
cmd_i++;
continue;
}
++retry;
vTaskDelay(pdMS_TO_TICKS(retry * 1000));
}
if (retry >= max_retries) {
ESP_LOGE(TAG, "Failed to perform initial modem connection");
vTaskDelete(NULL);
}
ESP_LOGI(TAG, "Modem configured correctly, switching to PPP protocol");
esp_event_handler_register(IP_EVENT, IP_EVENT_PPP_GOT_IP, esp_netif_action_connected, ppp_info->parent.netif);
esp_netif_action_start(ppp_info->parent.netif, 0, 0, 0);
while (!ppp_info->stop_task) {
xQueueReceive(event_queue, &event, pdMS_TO_TICKS(pdMS_TO_TICKS(1000)));
if (event.type == UART_DATA) {
size_t len;
uart_get_buffered_data_len(UART_NUM_1, &len);
if (len) {
len = uart_read_bytes(UART_NUM_1, buffer, BUF_SIZE, 0);
ESP_LOG_BUFFER_HEXDUMP("ppp_uart_recv", buffer, len, ESP_LOG_VERBOSE);
esp_netif_receive(ppp_info->parent.netif, buffer, len, NULL);
}
} else {
ESP_LOGW(TAG, "Received UART event: %d", event.type);
}
}
}
void ppp_destroy_context(struct ppp_info_t *ppp_info)
{
char *buffer = ppp_info->context;
ppp_info->stop_task = true;
vTaskDelay(pdMS_TO_TICKS(1000));
free(buffer);
uart_driver_delete(UART_NUM_1);
}

View File

@ -0,0 +1,128 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
/* WiFi connection
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "iface_info.h"
#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT BIT1
static const char *TAG = "wifi_connect";
static int s_retry_num = 0;
static EventGroupHandle_t s_wifi_event_group;
static void event_handler(void *args, esp_event_base_t event_base,
int32_t event_id, void *event_data)
{
struct iface_info_t *wifi_info = args;
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
esp_wifi_connect();
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
wifi_info->connected = false;
if (s_retry_num < CONFIG_ESP_MAXIMUM_RETRY || CONFIG_ESP_MAXIMUM_RETRY == 0) {
esp_wifi_connect();
s_retry_num++;
ESP_LOGI(TAG, "retry to connect to the AP");
} else {
xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
}
ESP_LOGI(TAG, "connect to the AP fail");
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data;
const esp_netif_ip_info_t *ip_info = &event->ip_info;
ESP_LOGI(TAG, "WiFi station Got IP Address");
ESP_LOGI(TAG, "~~~~~~~~~~~");
ESP_LOGI(TAG, "IP:" IPSTR, IP2STR(&ip_info->ip));
ESP_LOGI(TAG, "MASK:" IPSTR, IP2STR(&ip_info->netmask));
ESP_LOGI(TAG, "GW:" IPSTR, IP2STR(&ip_info->gw));
ESP_LOGI(TAG, "~~~~~~~~~~~");
for (int i = 0; i < 2; ++i) {
esp_netif_get_dns_info(wifi_info->netif, i, &wifi_info->dns[i]);
ESP_LOGI(TAG, "DNS %i:" IPSTR, i, IP2STR(&wifi_info->dns[i].ip.u_addr.ip4));
}
ESP_LOGI(TAG, "~~~~~~~~~~~");
s_retry_num = 0;
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
wifi_info->connected = true;
}
}
static void wifi_destroy(iface_info_t *info)
{
esp_netif_action_disconnected(info->netif, 0, 0, 0);
esp_netif_action_stop(info->netif, 0, 0, 0);
esp_wifi_stop();
esp_wifi_deinit();
free(info);
}
iface_info_t *wifi_init(int prio)
{
struct iface_info_t *wifi_info = malloc(sizeof(iface_info_t));
assert(wifi_info);
wifi_info->destroy = wifi_destroy;
wifi_info->name = "WiFi station";
s_wifi_event_group = xEventGroupCreate();
esp_netif_inherent_config_t esp_netif_config = ESP_NETIF_INHERENT_DEFAULT_WIFI_STA();
esp_netif_config.route_prio = prio;
wifi_info->netif = esp_netif_create_wifi(WIFI_IF_STA, &esp_netif_config);
esp_wifi_set_default_wifi_sta_handlers();
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, event_handler, wifi_info));
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, event_handler, wifi_info));
wifi_config_t wifi_config = {
.sta = {
.ssid = CONFIG_ESP_WIFI_SSID,
.password = CONFIG_ESP_WIFI_PASSWORD,
},
};
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );
ESP_ERROR_CHECK(esp_wifi_start() );
ESP_LOGI(TAG, "wifi_init_sta finished.");
/* Waiting until either the connection or a failure (connection failed or a timeout) */
EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group, (WIFI_CONNECTED_BIT | WIFI_FAIL_BIT), pdFALSE, pdFALSE, pdMS_TO_TICKS(5000));
if (bits & WIFI_CONNECTED_BIT) {
ESP_LOGI(TAG, "connected to ap SSID:%s password:%s",
CONFIG_ESP_WIFI_SSID, CONFIG_ESP_WIFI_PASSWORD);
} else if (bits & WIFI_FAIL_BIT) {
ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s",
CONFIG_ESP_WIFI_SSID, CONFIG_ESP_WIFI_PASSWORD);
wifi_destroy(wifi_info);
wifi_info = NULL;
} else if (CONFIG_ESP_MAXIMUM_RETRY == 0) {
ESP_LOGI(TAG, "No connection at the moment, will keep retrying...");
} else {
ESP_LOGE(TAG, "Failed to connect withing specified timeout");
wifi_destroy(wifi_info);
wifi_info = NULL;
}
return wifi_info;
}

View File

@ -0,0 +1,2 @@
CONFIG_LWIP_PPP_SUPPORT=y
CONFIG_LWIP_PPP_NOTIFY_PHASE_SUPPORT=y

View File

@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.16)
# For ESP32 platform target
set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common)
if(${IDF_TARGET} STREQUAL "linux")
if("${IDF_TARGET}" STREQUAL "linux")
# For linux-target we have two options:
# - With lwIP (must be defined on command line, e.g. idf.py -DWITH_LWIP=1)
# access networking from linux `tap` interface (TAP networking mode)

View File

@ -1,2 +0,0 @@
CONFIG_IDF_TARGET="linux"
# CONFIG_ESP_EVENT_POST_FROM_ISR is not set

View File

@ -0,0 +1,3 @@
CONFIG_IDF_TARGET="esp32h2"
CONFIG_EXAMPLE_CONNECT_WIFI=n
CONFIG_EXAMPLE_CONNECT_ETHERNET=y

View File

@ -0,0 +1,2 @@
CONFIG_IDF_TARGET="linux"
# CONFIG_ESP_EVENT_POST_FROM_ISR is not set