Compare commits

...

50 Commits

Author SHA1 Message Date
96f4ebd994 Merge pull request #504 from gabsuren/mdns_1.2.4
bump(mdns): 1.2.3 -> 1.2.4
2024-02-08 16:39:33 +04:00
247ca41bb7 bump(mdns): 1.2.3 -> 1.2.4
1.2.4
Bug Fixes
- Correction on 6d2c475 MDNS_PREDEF_NETIF_ETH fix (fc59f87c4e)
- fix the logic of creating pcb for networking socket (5000a9a20a)
- fix compiling issue when disabling IPv4 (2646dcd23a)
- Fix compile error when MDNS_PREDEF_NETIF_ETH is defined, but ETH_ENABLED is not (#459) (6d2c475c20)
2024-02-06 11:51:38 +04:00
891384cc53 Merge pull request #414 from wqx6/fix/mdns_disable_ipv4
fix(mdns): fix compiling issue when disabling IPv4 (IDFGH-11453)
2024-02-06 11:45:45 +04:00
38ef603296 Merge pull request #500 from gabsuren/websocket_linux
fix(websocket): added dependency checks, sdkconfig.defaults and refined README.md
2024-02-05 14:05:00 +04:00
312982e4aa fix(websocket): added dependency checks, sdkconfig.defaults and refined README.md 2024-02-05 13:22:39 +04:00
d9d377133e Merge pull request #501 from gabsuren/update_examples
docs(common): Enhance documentation clarity in the examples directory
2024-02-05 13:16:47 +04:00
110536ebb2 docs(common): Enhance documentation clarity in the examples directory 2024-02-05 13:15:25 +04:00
5ba7cfab8e Merge pull request #496 from gabsuren/readme_websocket_linux
docs(websocket): Added README for websocket host example (IDF-9115)
2024-01-26 20:31:15 +04:00
2f7c58259d docs(websocket): Added README for websocket host example 2024-01-26 20:29:28 +04:00
f42c0adfc0 Merge pull request #494 from david-cermak/bump/modem_v1.1
bump(modem): 1.0.5 -> 1.1.0
2024-01-22 17:08:55 +01:00
2782277f3f bump(modem): 1.0.5 -> 1.1.0
1.1.0
Features
- Added support for at_raw() command (ae38110, #471)
- Added iperf test for PPP netifs (976e98d)
- Added test that performs OTA to exercise modem layers (f2223dd)
Bug Fixes
- Fixed OTA test to gracefully fail with no verification (1dc4299)
- Added C-API to configure APN (ce7dadd, #485)
- Fixed AT commands to copy strings to prevent overrides (741d166, #463)
- Fixed incorrect dial command format (0998f3d, #433)
- Fixed documentation and example on creating custom device (577de67, #452)
- Removed CI jobs for IDF v4.2 (d88cd61)
- Fixed OAT test to verify server cert and CN (edc3e72)
- Fixed set_pdp_context() command timeout (1d80cbc, #455)
Updated
- docs(modem): Added description of manual test procedure (68ce794)
2024-01-22 16:33:07 +01:00
3225f40c22 Merge pull request #491 from david-cermak/feat/modem_set_apn
fix(modem): Added C-API to configure APN
2024-01-22 16:05:51 +01:00
d63f831fff Merge pull request #466 from gabsuren/websocket_bump_1.2.2
bump(websocket): 1.2.1 -> 1.2.2
2024-01-19 19:27:37 +04:00
f62db5cfa2 Merge pull request #492 from euripedesrocha/mqttcxx_0_3_0
bump(mqtt_cxx): 0.2.0 -> 0.3.0
2024-01-19 08:42:52 -03:00
68ce794098 docs(modem): Added description of manual test procedure 2024-01-19 11:16:18 +01:00
60174f290e bump(mqtt_cxx): 0.2.0 -> 0.3.0
0.3.0
Bug Fixes
- Incorrect documentation link (aa4e9d57)
- reference protocol_examples_common from IDF (e6c0538d)
- specify override_path in example manifest files (fa005c63)
2024-01-19 09:43:07 +01:00
efa26b7062 Merge pull request #484 from david-cermak/fix/modem_docs_ota
fix(modem): Documented some tips on failing OTA
2024-01-18 17:43:03 +01:00
7b777948fc Merge pull request #487 from euripedesrocha/mqttcxx_link_fix
Incorrect documentation link
2024-01-18 05:10:23 -03:00
1dc4299eb0 fix(modem): Fixed OTA test to gracefully fail with no verification 2024-01-17 17:43:47 +01:00
ce7daddc77 fix(modem): Added C-API to configure APN
Closes https://github.com/espressif/esp-protocols/issues/485
2024-01-17 14:30:05 +01:00
09e68cc0c0 Merge pull request #490 from david-cermak/fix/mdns_eth
fix(mdns): Correction on 6d2c475 MDNS_PREDEF_NETIF_ETH fix
2024-01-17 12:53:14 +01:00
fc59f87c4e fix(mdns): Correction on 6d2c475 MDNS_PREDEF_NETIF_ETH fix 2024-01-17 11:51:17 +01:00
7a2b23909f Merge pull request #489 from espressif/revert-478-component/console_cmd_iperf
Revert "feat(console): Added component with iperf command"
2024-01-17 10:24:17 +01:00
d3bf773445 Revert "feat(console): Added component with iperf command" 2024-01-17 20:20:30 +11:00
1c29af9237 Merge pull request #472 from david-cermak/fix/modem_at_corrupt_response
fix(modem): Fixed AT commands to copy strings to prevent overrides
2024-01-17 09:48:24 +01:00
b53981a68c Merge pull request #479 from marekmaskarinec/master
fix(mdns): Fix compile error when MDNS_PREDEF_NETIF_ETH is defined, but ETH_ENABLED is not (IDFGH-11868)
2024-01-17 09:48:05 +01:00
5000a9a20a fix(mdns): fix the logic of creating pcb for networking socket 2024-01-17 10:48:40 +08:00
2646dcd23a fix(mdns): fix compiling issue when disabling IPv4 2024-01-17 10:48:40 +08:00
de8ec67a88 Merge pull request #478 from espressif-abhikroy/component/console_cmd_iperf
feat(console): Added component with iperf command
2024-01-17 00:53:56 +11:00
8dac30781c Merge pull request #488 from gabsuren/fix_docs
docs(common): Added package requirements.txt for esp-docs
2024-01-16 16:59:05 +04:00
ba3f06f942 docs(common): Added package requirements.txt for esp-docs 2024-01-16 16:57:58 +04:00
a10f0008fb bump(console): First version [1.0.0]
1.0.0
Features
- Added component with iperf command (93d14087)
2024-01-16 20:27:56 +11:00
741d166034 fix(modem): Fixed AT commands to copy strings to prevent overrides
Previously we used std::string_view, which pointed to the lower-layers
buffer which might have been reused for other asynchronous operations
before processing it, thus causing corruption of replies.

Closes https://github.com/espressif/esp-protocols/issues/463
2024-01-16 09:51:51 +01:00
93d140875f feat(console): Added component with iperf command 2024-01-16 19:18:01 +11:00
eb7699388c bump(websocket): 1.2.1 -> 1.2.2
1.2.2
Bug Fixes
- continuation after FIN in websocket client (#460) (774d1c75e6)
- Re-applie refs to common comps idf_component.yml (9fe44a4504)
2024-01-16 12:17:25 +04:00
585e4b30b2 Merge pull request #483 from espressif-abhikroy/ci/build_app_failure_fix
fix(common): Fixed scripts for build test failure
2024-01-16 09:07:14 +01:00
aa4e9d5795 fix(mqtt_cxx): Incorrect documentation link
- Link in the component README was incorrect.

Fixes #486
2024-01-16 08:41:55 +01:00
6d2c475c20 fix(mdns): Fix compile error when MDNS_PREDEF_NETIF_ETH is defined, but ETH_ENABLED is not (#459)
Signed-off-by: Marek Maškarinec <marek@mrms.cz>
2024-01-15 16:50:44 +01:00
47736a2556 fix(common): Fixed scripts for build test failure 2024-01-16 01:59:11 +11:00
adde6df6e8 fix(modem): Documented some tips on failing OTA
Closes https://github.com/espressif/esp-protocols/issues/482
2024-01-15 14:58:03 +01:00
1393764dc5 Merge pull request #477 from david-cermak/feat/modem_at_raw
feat(modem): Added support for at_raw() command
2024-01-15 12:31:18 +01:00
0998f3dd4f fix(modem): Fixed incorrect dial command format
ATD command is used to switch generic device to the data mode
by dialing GPRS_SRC. The generic version of the command was incorrect
`ATD*99##` (containing extra trailing # char, which is accepted by most
devices). Command has been fixed, but the extra #'s been kept for devices
that we cannot test (to be fixed in IDFGH-9470).

Closes https://github.com/espressif/esp-protocols/issues/433
2024-01-09 12:48:16 +01:00
577de67c0e fix(modem): Fixed documentation and example on creating custom device
Updates docs and examples per recent changes:
* Modem example does no longer demonstrate how to overwrite an AT method
* PPPoS client example now contains much simpler custom module
definition

Closes https://github.com/espressif/esp-protocols/issues/452
2024-01-09 10:26:39 +01:00
ae38110d84 feat(modem): Added support for at_raw() command
at_raw() sends raw string and supports custom pass/fail phrases for the
API to return OK/FAIL. It also returns raw, unprocessed string as
output.
This allows sending custom requests, such as:
* dce->at_raw("", resp, "RDY", "...", 20000) -- waiting for reset
* esp_modem_at_raw(dce, "+++", resp, "DISCONNECTED", "ERROR", 5000) --
exits PPP mode

Closes https://github.com/espressif/esp-protocols/issues/471
Partially addresses https://github.com/espressif/esp-protocols/issues/468
2024-01-09 08:20:10 +01:00
5ab699d6f4 Merge pull request #354 from david-cermak/feat/modem_iperf_test
feat(modem): Add iperf test of PPP netif
2024-01-08 16:48:02 +01:00
976e98d6ff feat(modem): Added iperf test for PPP netifs 2024-01-08 16:22:22 +01:00
18b2ae103a Merge pull request #476 from david-cermak/fix/ci_examples
fix(examples): Fixed esp_netif_next() warning with IDFv5.3
2024-01-08 12:48:30 +01:00
52a34c21d0 fix(examples): Fixed esp_netif_next() warning with IDFv5.3 2024-01-08 08:02:20 +01:00
9df86641f3 Merge pull request #475 from gabsuren/bump_mdns__v1.2.3
bump(mdns): 1.2.2 -> 1.2.3
2024-01-05 14:22:25 +04:00
75af01670e bump(mdns): 1.2.2 -> 1.2.3
1.2.3
Bug Fixes
- fixed CI issues for host and afl tests (4be5efc84e)
- fix copy delegated host addr (19fb36000c)
- enable CONFIG_ESP_WIFI_ENABLED if CONFIG_SOC_WIFI_SUPPORTED is also enabled (for ESP-IDF <= 5.1) (d20a718320)
- remove protocol_examples_common (1ee9dae6bf)
- move the example into a subdirectory (d28232b9f8)
- reference protocol_examples_common from IDF (c83b76ea8f)
2024-01-05 14:00:34 +04:00
62 changed files with 1294 additions and 257 deletions

View File

@ -15,7 +15,7 @@ jobs:
matrix:
idf_ver: ["latest", "release-v5.0"]
idf_target: ["esp32"]
test: [ { app: example, path: "components/console_cmd_ifconfig/examples" }]
test: [ { app: ifconfig-basic, path: "components/console_cmd_ifconfig/examples"}]
runs-on: ubuntu-20.04
container: espressif/idf:${{ matrix.idf_ver }}
steps:
@ -29,4 +29,4 @@ jobs:
run: |
${IDF_PATH}/install.sh --enable-pytest
. ${IDF_PATH}/export.sh
python $IDF_PATH/tools/ci/ci_build_apps.py . --target ${{ matrix.idf_target }} -vv --preserve-all --pytest-app
python ../../../ci/build_apps.py ./${{ matrix.test.app }} --target ${{ matrix.idf_target }} -vv --preserve-all --pytest-app

View File

@ -15,7 +15,7 @@ jobs:
matrix:
idf_ver: ["latest", "release-v5.0"]
idf_target: ["esp32"]
test: [ { app: example, path: "components/console_cmd_ping/examples" }]
test: [ { app: ping-basic, path: "components/console_cmd_ping/examples" }]
runs-on: ubuntu-20.04
container: espressif/idf:${{ matrix.idf_ver }}
steps:
@ -29,4 +29,4 @@ jobs:
run: |
${IDF_PATH}/install.sh --enable-pytest
. ${IDF_PATH}/export.sh
python $IDF_PATH/tools/ci/ci_build_apps.py . --target ${{ matrix.idf_target }} -vv --preserve-all --pytest-app
python ../../../ci/build_apps.py ./${{ matrix.test.app }} --target ${{ matrix.idf_target }} -vv --preserve-all --pytest-app

View File

@ -15,7 +15,7 @@ jobs:
matrix:
idf_ver: ["latest", "release-v5.0"]
idf_target: ["esp32"]
test: [ { app: example, path: "components/console_cmd_wifi/examples" }]
test: [ { app: wifi-basic, path: "components/console_cmd_wifi/examples" }]
runs-on: ubuntu-20.04
container: espressif/idf:${{ matrix.idf_ver }}
steps:
@ -29,4 +29,4 @@ jobs:
run: |
${IDF_PATH}/install.sh --enable-pytest
. ${IDF_PATH}/export.sh
python $IDF_PATH/tools/ci/ci_build_apps.py . --target ${{ matrix.idf_target }} -vv --preserve-all --pytest-app
python ../../../ci/build_apps.py ./${{ matrix.test.app }} --target ${{ matrix.idf_target }} -vv --preserve-all --pytest-app

View File

@ -15,7 +15,7 @@ jobs:
matrix:
idf_ver: ["latest", "release-v5.0"]
idf_target: ["esp32"]
test: [ { app: example, path: "components/console_simple_init/examples" }]
test: [ { app: console_basic, path: "components/console_simple_init/examples" }]
runs-on: ubuntu-20.04
container: espressif/idf:${{ matrix.idf_ver }}
steps:
@ -29,4 +29,4 @@ jobs:
run: |
${IDF_PATH}/install.sh --enable-pytest
. ${IDF_PATH}/export.sh
python $IDF_PATH/tools/ci/ci_build_apps.py . --target ${{ matrix.idf_target }} -vv --preserve-all --pytest-app
python ../../../ci/build_apps.py ./${{ matrix.test.app }} --target ${{ matrix.idf_target }} -vv --preserve-all --pytest-app

View File

@ -52,7 +52,7 @@ jobs:
strategy:
matrix:
idf_ver: ["release-v5.0", "release-v5.1", "latest"]
test: ["target", "target_ota"]
test: ["target", "target_ota", "target_iperf"]
runs-on: ubuntu-20.04
container: espressif/idf:${{ matrix.idf_ver }}

View File

@ -15,7 +15,7 @@ jobs:
matrix:
idf_ver: ["latest", "release-v5.0"]
idf_target: ["esp32"]
test: [ { app: example, path: "components/esp_mqtt_cxx/examples" }]
test: [ { app: mqtt-basic, path: "components/esp_mqtt_cxx/examples" }]
runs-on: ubuntu-20.04
container: espressif/idf:${{ matrix.idf_ver }}
steps:
@ -29,4 +29,4 @@ jobs:
run: |
${IDF_PATH}/install.sh --enable-pytest
. ${IDF_PATH}/export.sh
python $IDF_PATH/tools/ci/ci_build_apps.py . --target ${{ matrix.idf_target }} -vv --preserve-all --pytest-app
python ../../../ci/build_apps.py ./${{ matrix.test.app }} --target ${{ matrix.idf_target }} -vv --preserve-all --pytest-app

View File

@ -48,7 +48,7 @@ jobs:
run: |
sudo apt-get update
sudo apt-get -y install doxygen clang python3-pip
python -m pip install breathe recommonmark esp-docs==1.4.1
python -m pip install -r docs/requirements.txt
for comp in `ls components`; do
if [[ -d $GITHUB_WORKSPACE/docs/${comp} ]]; then
cd $GITHUB_WORKSPACE/docs/${comp}

View File

@ -10,6 +10,8 @@ import sys
from idf_build_apps import build_apps, find_apps, setup_logging
from idf_build_apps.constants import SUPPORTED_TARGETS
from packaging import version
from pkg_resources import get_distribution
if __name__ == '__main__':
parser = argparse.ArgumentParser(
@ -17,6 +19,12 @@ if __name__ == '__main__':
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
)
parser.add_argument('paths', nargs='+', help='Paths to the apps to build.')
parser.add_argument(
'-v',
'--verbose',
action='count',
help='Increase the LOGGER level of the script. Can be specified multiple times.',
)
parser.add_argument(
'-t',
'--target',
@ -28,6 +36,8 @@ if __name__ == '__main__':
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)')
parser.add_argument('--preserve-all', action='store_true', help='Preserve the binaries for all apps when specified.')
parser.add_argument('--pytest-apps', action='store_true', help='Only build apps required by pytest scripts.')
args = parser.parse_args()
IDF_PATH = os.environ['IDF_PATH']
@ -41,20 +51,36 @@ if __name__ == '__main__':
SUPPORTED_TARGETS.append('linux')
ignore_warning = 'warning: ' # Ignore all common warnings on linux builds
setup_logging(2)
apps = find_apps(
args.paths,
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' if not args.linux else None,
check_warnings=True,
preserve=not args.delete,
manifest_files=args.manifests,
default_build_targets=SUPPORTED_TARGETS,
manifest_rootpath='.',
)
if version.parse(get_distribution('idf_build_apps').version) >= version.parse('2.0.0'):
apps = find_apps(
args.paths,
recursive=args.recursive,
target=args.target,
build_dir='build_@t_@w',
config_rules_str=args.rules,
build_log_filename='build_log.txt',
size_json_filename='size.json' if not args.linux else None,
check_warnings=True,
preserve=not args.delete,
manifest_files=args.manifests,
default_build_targets=SUPPORTED_TARGETS,
manifest_rootpath='.',
)
else:
apps = find_apps(
args.paths,
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' if not args.linux else None,
check_warnings=True,
preserve=not args.delete,
manifest_files=args.manifests,
default_build_targets=SUPPORTED_TARGETS,
manifest_rootpath='.',
)
for app in apps:
print(app)

View File

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

View File

@ -1,5 +1,28 @@
# Changelog
## [1.1.0](https://github.com/espressif/esp-protocols/commits/modem-v1.1.0)
### Features
- Added support for at_raw() command ([ae38110](https://github.com/espressif/esp-protocols/commit/ae38110), [#471](https://github.com/espressif/esp-protocols/issues/471))
- Added iperf test for PPP netifs ([976e98d](https://github.com/espressif/esp-protocols/commit/976e98d))
- Added test that performs OTA to exercise modem layers ([f2223dd](https://github.com/espressif/esp-protocols/commit/f2223dd))
### Bug Fixes
- Fixed OTA test to gracefully fail with no verification ([1dc4299](https://github.com/espressif/esp-protocols/commit/1dc4299))
- Added C-API to configure APN ([ce7dadd](https://github.com/espressif/esp-protocols/commit/ce7dadd), [#485](https://github.com/espressif/esp-protocols/issues/485))
- Fixed AT commands to copy strings to prevent overrides ([741d166](https://github.com/espressif/esp-protocols/commit/741d166), [#463](https://github.com/espressif/esp-protocols/issues/463))
- Fixed incorrect dial command format ([0998f3d](https://github.com/espressif/esp-protocols/commit/0998f3d), [#433](https://github.com/espressif/esp-protocols/issues/433))
- Fixed documentation and example on creating custom device ([577de67](https://github.com/espressif/esp-protocols/commit/577de67), [#452](https://github.com/espressif/esp-protocols/issues/452))
- Removed CI jobs for IDF v4.2 ([d88cd61](https://github.com/espressif/esp-protocols/commit/d88cd61))
- Fixed OAT test to verify server cert and CN ([edc3e72](https://github.com/espressif/esp-protocols/commit/edc3e72))
- Fixed set_pdp_context() command timeout ([1d80cbc](https://github.com/espressif/esp-protocols/commit/1d80cbc), [#455](https://github.com/espressif/esp-protocols/issues/455))
### Updated
- docs(modem): Added description of manual test procedure ([68ce794](https://github.com/espressif/esp-protocols/commit/68ce794))
## [1.0.5](https://github.com/espressif/esp-protocols/commits/modem-v1.0.5)
### Major changes

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
@ -17,26 +17,20 @@
#include "cxx_include/esp_modem_dce_module.hpp"
/**
* @brief Definition of a custom modem which inherits from the GenericModule, uses all its methods
* and could override any of them. Here, for demonstration purposes only, we redefine just `get_module_name()`
* @brief Definition of a custom DCE uses GenericModule and all its methods
* but could override command processing. Here, for demonstration purposes only,
* we "inject" URC handler to the actual command processing.
* This is possible since we inherit from `CommandableIf` and redefine `command()` method.
* Then we're able to use declare all common methods from the command library
* to be processed using "our" `command()` method (with custom URC handler).
*/
class MyShinyModem: public esp_modem::GenericModule {
using GenericModule::GenericModule;
public:
esp_modem::command_result get_module_name(std::string &name) override
{
name = "Custom Shiny Module";
return esp_modem::command_result::OK;
}
};
namespace Shiny {
using namespace esp_modem;
class DCE : public esp_modem::DCE_T<MyShinyModem>, public CommandableIf {
class DCE : public esp_modem::DCE_T<GenericModule>, public CommandableIf {
public:
using DCE_T<MyShinyModem>::DCE_T;
using DCE_T<GenericModule>::DCE_T;
command_result
command(const std::string &cmd, got_line_cb got_line, uint32_t time_ms) override
@ -97,7 +91,7 @@ public:
std::shared_ptr<esp_modem::DTE> dte,
esp_netif_t *netif)
{
return build_generic_DCE<MyShinyModem, DCE, std::unique_ptr<DCE>>(config, std::move(dte), netif);
return build_generic_DCE<GenericModule, DCE, std::unique_ptr<DCE>>(config, std::move(dte), netif);
}
};

View File

@ -1,4 +1,4 @@
version: "1.0.5"
version: "1.1.0"
description: Library for communicating with cellular modems in command and data modes
url: https://github.com/espressif/esp-protocols/tree/master/components/esp_modem
issues: https://github.com/espressif/esp-protocols/issues

View File

@ -54,7 +54,7 @@ command_result power_down_sim76xx(CommandableIf *t);
command_result power_down_sim70xx(CommandableIf *t);
command_result set_network_bands_sim76xx(CommandableIf *t, const std::string &mode, const int *bands, int size);
command_result power_down_sim8xx(CommandableIf *t);
command_result set_data_mode_sim8xx(CommandableIf *t);
command_result set_data_mode_alt(CommandableIf *t);
command_result set_pdp_context(CommandableIf *t, PdpContext &pdp, uint32_t timeout_ms);
/**

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -25,18 +25,16 @@ command_result generic_command(CommandableIf *t, const std::string &command,
* @brief Utility command to send command and return reply (after DCE says OK)
* @param t Anything that is "command-able"
* @param command Command to issue
* @param output String to return
* @param timeout_ms
* @param output String to return (could be either std::string& or std::string_view&)
* @param timeout_ms Command timeout in ms
* @return Generic command return type (OK, FAIL, TIMEOUT)
*/
command_result generic_get_string(CommandableIf *t, const std::string &command, std::string &output, uint32_t timeout_ms = 500);
template <typename T> command_result generic_get_string(CommandableIf *t, const std::string &command, T &output, uint32_t timeout_ms = 500);
/**
* @brief Generic command that passes on "OK" and fails on "ERROR"
* @param t Anything that is "command-able"
* @param command Command to issue
* @param timeout
* @param timeout_ms Command timeout in ms
* @return Generic command return type (OK, FAIL, TIMEOUT)
*/

View File

@ -144,6 +144,8 @@ class SIM7070: public GenericModule {
using GenericModule::GenericModule;
public:
command_result power_down() override;
command_result set_data_mode() override;
};
/**
@ -162,7 +164,6 @@ class SIM800: public GenericModule {
using GenericModule::GenericModule;
public:
command_result power_down() override;
command_result set_data_mode() override;
};
/**

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -119,8 +119,27 @@ esp_err_t esp_modem_set_error_cb(esp_modem_dce_t *dce, esp_modem_terminal_error_
*/
esp_err_t esp_modem_set_mode(esp_modem_dce_t *dce, esp_modem_dce_mode_t mode);
/**
* @brief Convenient function to run arbitrary commands from C-API
*
* @param dce Modem DCE handle
* @param command Command to send
* @param got_line_cb Callback function which is called whenever we receive a line
* @param timeout_ms Command timeout
* @return ESP_OK on success, ESP_FAIL on failure
*/
esp_err_t esp_modem_command(esp_modem_dce_t *dce, const char *command, esp_err_t(*got_line_cb)(uint8_t *data, size_t len), uint32_t timeout_ms);
/**
* @brief Sets the APN and configures it into the modem's PDP context
*
* @param dce Modem DCE handle
* @param apn Access Point Name
* @return ESP_OK on success
*/
esp_err_t esp_modem_set_apn(esp_modem_dce_t *dce, const char *apn);
/**
* @}
*/

View File

@ -44,6 +44,18 @@ ESP_MODEM_DECLARE_DCE_COMMAND(store_profile, command_result, 0) \
*/\
ESP_MODEM_DECLARE_DCE_COMMAND(set_pin, command_result, 1, STRING_IN(p1, pin)) \
\
/**
* @brief Execute the supplied AT command in raw mode (doesn't append '\r' to command, returns everything)
* @param[in] cmd String command that's send to DTE
* @param[out] out Raw output from DTE
* @param[in] pass Pattern in response for the API to return OK
* @param[in] fail Pattern in response for the API to return FAIL
* @param[in] cmd String command that's send to DTE
* @param[in] timeout AT command timeout in milliseconds
* @return OK, FAIL or TIMEOUT
*/\
ESP_MODEM_DECLARE_DCE_COMMAND(at_raw, command_result, 5, STRING_IN(p1, cmd), STRING_OUT(p2, out), STRING_IN(p3, pass), STRING_IN(p4, fail), INT_IN(p5, timeout)) \
\
/**
* @brief Execute the supplied AT command
* @param[in] cmd AT command

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -17,7 +17,7 @@
#include "esp_private/c_api_wrapper.hpp"
#ifndef ESP_MODEM_C_API_STR_MAX
#define ESP_MODEM_C_API_STR_MAX 64
#define ESP_MODEM_C_API_STR_MAX 128
#endif
#ifndef HAVE_STRLCPY
@ -206,6 +206,20 @@ extern "C" esp_err_t esp_modem_get_imsi(esp_modem_dce_t *dce_wrap, char *p_imsi)
return ret;
}
extern "C" esp_err_t esp_modem_at_raw(esp_modem_dce_t *dce_wrap, const char *cmd, char *p_out, const char *pass, const char *fail, int timeout)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
std::string out;
auto ret = command_response_to_esp_err(dce_wrap->dce->at_raw(cmd, out, pass, fail, timeout));
if ((p_out != NULL) && (!out.empty())) {
strlcpy(p_out, out.c_str(), ESP_MODEM_C_API_STR_MAX);
}
return ret;
}
extern "C" esp_err_t esp_modem_set_flow_control(esp_modem_dce_t *dce_wrap, int dce_flow, int dte_flow)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
@ -434,3 +448,10 @@ extern "C" esp_err_t esp_modem_set_baud(esp_modem_dce_t *dce_wrap, int baud)
{
return command_response_to_esp_err(dce_wrap->dce->set_baud(baud));
}
extern "C" esp_err_t esp_modem_set_apn(esp_modem_dce_t *dce_wrap, const char *apn)
{
auto new_pdp = std::unique_ptr<PdpContext>(new PdpContext(apn));
dce_wrap->dce->get_module()->configure_pdp_context(std::move(new_pdp));
return ESP_OK;
}

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -51,7 +51,35 @@ command_result generic_command(CommandableIf *t, const std::string &command,
return generic_command(t, command, pass, fail, timeout_ms);
}
static command_result generic_get_string(CommandableIf *t, const std::string &command, std::string_view &output, uint32_t timeout_ms = 500)
/*
* Purpose of this namespace is to provide different means of assigning the result to a string-like parameter.
* By default we assign strings, which comes with an allocation. Alternatively we could take `std::span`
* with user's buffer and directly copy the result, thus avoiding allocations (this is not used as of now)
*/
namespace str_copy {
bool set(std::string &dest, std::string_view &src)
{
dest = src;
return true;
}
/* This is an example of using std::span output in generic_get_string()
bool set(std::span<char> &dest, std::string_view &src)
{
if (dest.size() >= src.size()) {
std::copy(src.begin(), src.end(), dest.data());
dest = dest.subspan(0, src.size());
return true;
}
ESP_LOGE(TAG, "Cannot set result of size %d (to span of size %d)", dest.size(), src.size());
return false;
}
*/
} // str_copy
template <typename T> command_result generic_get_string(CommandableIf *t, const std::string &command, T &output, uint32_t timeout_ms)
{
ESP_LOGV(TAG, "%s", __func__ );
return t->command(command, [&](uint8_t *data, size_t len) {
@ -70,7 +98,9 @@ static command_result generic_get_string(CommandableIf *t, const std::string &co
} else if (token.find("ERROR") != std::string::npos) {
return command_result::FAIL;
} else if (token.size() > 2) {
output = token;
if (!str_copy::set(output, token)) {
return command_result::FAIL;
}
}
response = response.substr(pos + 1);
}
@ -78,18 +108,6 @@ static command_result generic_get_string(CommandableIf *t, const std::string &co
}, timeout_ms);
}
command_result generic_get_string(CommandableIf *t, const std::string &command, std::string &output, uint32_t timeout_ms)
{
ESP_LOGV(TAG, "%s", __func__ );
std::string_view out;
auto ret = generic_get_string(t, command, out, timeout_ms);
if (ret == command_result::OK) {
output = out;
}
return ret;
}
command_result generic_command_common(CommandableIf *t, const std::string &command, uint32_t timeout_ms)
{
ESP_LOGV(TAG, "%s", __func__ );
@ -153,7 +171,7 @@ command_result hang_up(CommandableIf *t)
command_result get_battery_status(CommandableIf *t, int &voltage, int &bcs, int &bcl)
{
ESP_LOGV(TAG, "%s", __func__ );
std::string_view out;
std::string out;
auto ret = generic_get_string(t, "AT+CBC\r", out);
if (ret != command_result::OK) {
return ret;
@ -189,7 +207,7 @@ command_result get_battery_status(CommandableIf *t, int &voltage, int &bcs, int
command_result get_battery_status_sim7xxx(CommandableIf *t, int &voltage, int &bcs, int &bcl)
{
ESP_LOGV(TAG, "%s", __func__ );
std::string_view out;
std::string out;
auto ret = generic_get_string(t, "AT+CBC\r", out);
if (ret != command_result::OK) {
return ret;
@ -224,7 +242,7 @@ command_result set_flow_control(CommandableIf *t, int dce_flow, int dte_flow)
command_result get_operator_name(CommandableIf *t, std::string &operator_name, int &act)
{
ESP_LOGV(TAG, "%s", __func__ );
std::string_view out;
std::string out;
auto ret = generic_get_string(t, "AT+COPS?\r", out, 75000);
if (ret != command_result::OK) {
return ret;
@ -277,13 +295,13 @@ command_result set_pdp_context(CommandableIf *t, PdpContext &pdp)
command_result set_data_mode(CommandableIf *t)
{
ESP_LOGV(TAG, "%s", __func__ );
return generic_command(t, "ATD*99##\r", "CONNECT", "ERROR", 5000);
return generic_command(t, "ATD*99#\r", "CONNECT", "ERROR", 5000);
}
command_result set_data_mode_sim8xx(CommandableIf *t)
command_result set_data_mode_alt(CommandableIf *t)
{
ESP_LOGV(TAG, "%s", __func__ );
return generic_command(t, "ATD*99#\r", "CONNECT", "ERROR", 5000);
return generic_command(t, "ATD*99##\r", "CONNECT", "ERROR", 5000);
}
command_result resume_data_mode(CommandableIf *t)
@ -361,7 +379,7 @@ command_result set_cmux(CommandableIf *t)
command_result read_pin(CommandableIf *t, bool &pin_ok)
{
ESP_LOGV(TAG, "%s", __func__ );
std::string_view out;
std::string out;
auto ret = generic_get_string(t, "AT+CPIN?\r", out);
if (ret != command_result::OK) {
return ret;
@ -394,10 +412,26 @@ command_result at(CommandableIf *t, const std::string &cmd, std::string &out, in
return generic_get_string(t, at_command, out, timeout);
}
command_result at_raw(CommandableIf *t, const std::string &cmd, std::string &out, const std::string &pass, const std::string &fail, int timeout = 500)
{
ESP_LOGV(TAG, "%s", __func__ );
return t->command(cmd, [&](uint8_t *data, size_t len) {
out.assign(reinterpret_cast<char *>(data), len);
if (out.find(pass) != std::string::npos) {
return command_result::OK;
} else if (out.find(fail) != std::string::npos) {
return command_result::FAIL;
}
return command_result::TIMEOUT;
}, timeout);
}
command_result get_signal_quality(CommandableIf *t, int &rssi, int &ber)
{
ESP_LOGV(TAG, "%s", __func__ );
std::string_view out;
std::string out;
auto ret = generic_get_string(t, "AT+CSQ\r", out);
if (ret != command_result::OK) {
return ret;
@ -435,7 +469,7 @@ command_result set_network_attachment_state(CommandableIf *t, int state)
command_result get_network_attachment_state(CommandableIf *t, int &state)
{
ESP_LOGV(TAG, "%s", __func__ );
std::string_view out;
std::string out;
auto ret = generic_get_string(t, "AT+CGATT?\r", out);
if (ret != command_result::OK) {
return ret;
@ -462,7 +496,7 @@ command_result set_radio_state(CommandableIf *t, int state)
command_result get_radio_state(CommandableIf *t, int &state)
{
ESP_LOGV(TAG, "%s", __func__ );
std::string_view out;
std::string out;
auto ret = generic_get_string(t, "AT+CFUN?\r", out);
if (ret != command_result::OK) {
return ret;
@ -527,7 +561,7 @@ command_result set_network_bands_sim76xx(CommandableIf *t, const std::string &mo
command_result get_network_system_mode(CommandableIf *t, int &mode)
{
ESP_LOGV(TAG, "%s", __func__ );
std::string_view out;
std::string out;
auto ret = generic_get_string(t, "AT+CNSMOD?\r", out);
if (ret != command_result::OK) {
return ret;
@ -555,7 +589,7 @@ command_result set_gnss_power_mode(CommandableIf *t, int mode)
command_result get_gnss_power_mode(CommandableIf *t, int &mode)
{
ESP_LOGV(TAG, "%s", __func__ );
std::string_view out;
std::string out;
auto ret = generic_get_string(t, "AT+CGNSPWR?\r", out);
if (ret != command_result::OK) {
return ret;

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -67,6 +67,11 @@ command_result SIM7070::power_down()
return dce_commands::power_down_sim70xx(dte.get());
}
command_result SIM7070::set_data_mode()
{
return dce_commands::set_data_mode_alt(dte.get());
}
command_result SIM7000::power_down()
{
return dce_commands::power_down_sim70xx(dte.get());
@ -77,11 +82,6 @@ command_result SIM800::power_down()
return dce_commands::power_down_sim8xx(dte.get());
}
command_result SIM800::set_data_mode()
{
return dce_commands::set_data_mode_sim8xx(dte.get());
}
command_result BG96::set_pdp_context(esp_modem::PdpContext &pdp)
{
return dce_commands::set_pdp_context(dte.get(), pdp, 300);

View File

@ -0,0 +1,47 @@
# ESP-Modem Testing
This folder contains automated and manual tests for esp-modem component. Beside these tests, some jobs are executed in CI to exercise standard examples (please refer to the CI definition and CI related sdkconfigs in examples).
List of test projects:
* `host_test` -- esp_modem is build on host (linux), modem's terminal in mocked using Loobpack class which creates simple responders to AT and CMUX mode. This test is executed in CI.
* `target` -- test executed on target with no modem device, just a pppd running on the test runner. This test is executed in CI.
* `target_ota` -- Manual test which perform OTA over PPP.
* `target_iperf` -- Manual test to measure data throughput via PPP.
## Manual testing
Prior to every `esp_modem` release, these manual tests must be executed and pass
(IDF-9074 to move the manual tests to CI)
### `target_ota`
Make sure that the UART ISR is not in IRAM, so the error messages are expected in the log, but the ESP32 should recover and continue with downloading the image.
Perform the test for these devices
* SIM7600 (CMUX mode)
* BG96 (CMUX mode)
* SIM7000 (PPP mode)
* A7672 (CMUX mode -- the only device with 2 byte CMUX payload), so the test is expected to fail more often if (`CONFIG_ESP_MODEM_CMUX_DEFRAGMENT_PAYLOAD=y` && `CONFIG_ESP_MODEM_USE_INFLATABLE_BUFFER_IF_NEEDED=n` && dte_buffer < device max payload)
* NetworkDCE -- no modem device, pppd (PPP mode)
Perform the test with these configurations:
* CONFIG_TEST_USE_VFS_TERM (y/n)
* CONFIG_ESP_HTTP_CLIENT_ENABLE_CUSTOM_TRANSPORT (y/n)
* CONFIG_ESP_MODEM_CMUX_DEFRAGMENT_PAYLOAD (y/n)
* CONFIG_ESP_MODEM_USE_INFLATABLE_BUFFER_IF_NEEDED (y/n)
**Criteria for passing the test**
The test should complete the download with maximum 1 retry (50% of OTA failure)
In case of CMUX mode, we're trying to exit CMUX at the end of the test. This step might also fail for some devices, as the CMUX-exit is not supported on certain devices (when the final error message appears that the device failed to exit CMUX, we just verify the new image by reseting the ESP32)
### `target_iperf`
Run these 4 `iperf` configurations (either manually or using `pytest`):
* tcp_tx_throughput
* tcp_rx_throughput
* udp_tx_throughput
* udp_rx_throughput
And verify in all four cases the value is about 0.70 Mbps

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
@ -36,7 +36,7 @@ int LoopbackTerm::write(uint8_t *data, size_t len)
} else if (command == "ATO\r") {
response = "ERROR\r\n";
} else if (command.find("ATD") != std::string::npos) {
response = "CONNECT\r\n";
response = "CONNECT\n";
} else if (command.find("AT+CSQ\r") != std::string::npos) {
response = "+CSQ: 123,456\n\r\nOK\r\n";
} else if (command.find("AT+CGMM\r") != std::string::npos) {
@ -74,6 +74,9 @@ int LoopbackTerm::write(uint8_t *data, size_t len)
}
if (len > 2 && data[0] == 0xf9) { // Simple CMUX responder
// turn the request into a reply -> implements CMUX loopback
// Note: This simple CMUX responder only updates CMUX headers and replaces payload.
// It means that all responses (that we test) must be shorter or equal to the requests
// For example ATD (dial command): sizeof("ATD*99#") >= sizeof("CONNECT");
if (data[2] == 0x3f || data[2] == 0x53) { // SABM command
data[2] = 0x73;
} else if (data[2] == 0xef) { // Generic request

View File

@ -0,0 +1,10 @@
# The following five lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/system/console/advanced/components
$ENV{IDF_PATH}/examples/common_components/iperf
"../..")
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(pppd_test)

View File

@ -0,0 +1,48 @@
# Target test for measuring TCP/UDP network performance
## Overview
The aim of this test is to run `iperf` application to measure network throughput of the esp_modem library.
### Configure PPP server
This test uses a network DCE device, which only needs a PPP server. To run the PPP server, use this command:
```
sudo pppd /dev/ttyUSB1 115200 192.168.11.1:192.168.11.2 ms-dns 8.8.8.8 modem local noauth debug nocrtscts nodetach +ipv6
```
### Running using pytest
For checking the performance, you only need to execute the pytest, which will measure the network throughput automatically and report the resultant values. For running the pytest, you need to:
* install IDF pytest packages by running: `./install.sh --enable-pytest`
* add IDF internal packages to python path: `export PYTHONPATH=${DIF_PATH}/tools/ci/python_packages/`
* run the pytest as **superuser**
It's useful to note that when running the test multiple times, you can use `pytest --skip-autoflash y` so the pytest wouldn't have to always reprogram the DUT.
### Performance summary
Here's an example of the resultant summary logged by the pytest
```
2023-11-29 18:28:25 INFO [Performance][tcp_tx_throughput]: 0.75 Mbps
2023-11-29 18:28:25 INFO [Performance][tcp_rx_throughput]: 0.70 Mbps
2023-11-29 18:28:25 INFO [Performance][udp_tx_throughput]: 0.73 Mbps
2023-11-29 18:28:25 INFO [Performance][udp_rx_throughput]: 0.70 Mbps
```
### Running the iperf manually
Execute `idf.py flash monitor` in one terminal and after connecting to the PPP server (after getting an IP address), you can use standard `iperf` commands.
In another terminal, you need to execute the iperf counterpart.
For example running for checking UDP performance, and running server on ESP32, please run:
* iperf -u -s -i 3 (in ESP32 terminal)
* iperf -u -c SERVER_IP -t 60 -i 3 (on the host side)
Note that command `pppd info` will print actual IP addresses:
```
iperf> pppd info
ppp:
IP: 192.168.11.2
MASK: 255.255.255.255
GW: 192.168.11.3
```

View File

@ -0,0 +1,3 @@
idf_component_register(SRCS "NetworkDCE.cpp"
"cmd_pppclient.c"
"pppd_iperf_main.c")

View File

@ -0,0 +1,96 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include "cxx_include/esp_modem_dte.hpp"
#include "esp_modem_config.h"
#include "cxx_include/esp_modem_api.hpp"
#include "cxx_include/esp_modem_dce_factory.hpp"
#include <memory>
#include <utility>
using namespace esp_modem;
using namespace esp_modem::dce_factory;
class NetModule;
typedef DCE_T<NetModule> NetDCE;
/**
* @brief Custom factory which can build and create a DCE using a custom module
*/
class NetDCE_Factory: public Factory {
public:
template <typename T, typename ...Args>
static DCE_T<T> *create(const config *cfg, Args &&... args)
{
return build_generic_DCE<T>(cfg, std::forward<Args>(args)...);
}
};
/**
* @brief This is a null-module, doesn't define any AT commands, just passes everything to pppd
*/
class NetModule: public ModuleIf {
public:
explicit NetModule(std::shared_ptr<DTE> dte, const esp_modem_dce_config *cfg):
dte(std::move(dte)) {}
bool setup_data_mode() override
{
return true;
}
bool set_mode(modem_mode mode) override
{
return true;
}
static esp_err_t init(esp_netif_t *netif)
{
// configure
esp_modem_dte_config_t dte_config = ESP_MODEM_DTE_DEFAULT_CONFIG();
dte_config.uart_config.baud_rate = 921600; // check also 460800
esp_modem_dce_config dce_config = ESP_MODEM_DCE_DEFAULT_CONFIG("");
// create DTE and minimal network DCE
auto uart_dte = create_uart_dte(&dte_config);
dce = NetDCE_Factory::create<NetModule>(&dce_config, uart_dte, netif);
return dce == nullptr ? ESP_FAIL : ESP_OK;
}
static void deinit()
{
delete dce;
}
static void start()
{
dce->set_data();
}
static void stop()
{
dce->exit_data();
}
private:
static NetDCE *dce;
std::shared_ptr<DTE> dte;
};
NetDCE *NetModule::dce = nullptr;
extern "C" esp_err_t modem_init_network(esp_netif_t *netif)
{
return NetModule::init(netif);
}
extern "C" esp_err_t modem_start_network()
{
NetModule::start();
return ESP_OK;
}
extern "C" void modem_stop_network()
{
NetModule::stop();
}

View File

@ -0,0 +1,289 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "sys/socket.h" // for INADDR_ANY
#include "esp_netif.h"
#include "esp_log.h"
#include "esp_system.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_netif.h"
#include "esp_netif_ppp.h"
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "esp_console.h"
#include "esp_event.h"
#include "esp_bit_defs.h"
#include "argtable3/argtable3.h"
#include "iperf.h"
#include "sdkconfig.h"
#include "network_dce.h"
static const char *TAG = "pppd_test";
static EventGroupHandle_t event_group = NULL;
static esp_netif_t *s_ppp_netif;
static const int GOTIP_BIT = BIT0;
static void on_modem_event(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data)
{
if (event_base == IP_EVENT) {
ESP_LOGD(TAG, "IP event! %" PRIu32, event_id);
if (event_id == IP_EVENT_PPP_GOT_IP) {
esp_netif_dns_info_t dns_info;
ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data;
esp_netif_t *netif = event->esp_netif;
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));
esp_netif_get_dns_info(netif, ESP_NETIF_DNS_MAIN, &dns_info);
ESP_LOGI(TAG, "Name Server1: " IPSTR, IP2STR(&dns_info.ip.u_addr.ip4));
esp_netif_get_dns_info(netif, ESP_NETIF_DNS_BACKUP, &dns_info);
ESP_LOGI(TAG, "Name Server2: " IPSTR, IP2STR(&dns_info.ip.u_addr.ip4));
ESP_LOGI(TAG, "~~~~~~~~~~~~~~");
ESP_LOGI(TAG, "GOT ip event!!!");
xEventGroupSetBits(event_group, GOTIP_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 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 %" PRId32, event_id);
if (event_id == NETIF_PPP_ERRORUSER) {
/* User interrupted event from esp-netif */
esp_netif_t *netif = (esp_netif_t *)event_data;
ESP_LOGI(TAG, "User interrupted event from netif:%p", netif);
xEventGroupSetBits(event_group, 2);
}
}
/* "pppd" command */
static struct {
struct arg_str *control;
struct arg_end *end;
} pppd_control_args;
static int pppd_cmd_control(int argc, char **argv)
{
int nerrors = arg_parse(argc, argv, (void **)&pppd_control_args);
if (nerrors != 0) {
arg_print_errors(stderr, pppd_control_args.end, argv[0]);
return 1;
}
if (!strncmp(pppd_control_args.control->sval[0], "info", 4)) {
esp_netif_ip_info_t ip;
printf("%s:\n", esp_netif_get_desc(s_ppp_netif));
esp_netif_get_ip_info(s_ppp_netif, &ip);
printf(" IP: " IPSTR "\r\n", IP2STR(&ip.ip));
printf(" MASK: " IPSTR "\r\n", IP2STR(&ip.netmask));
printf(" GW: " IPSTR "\r\n", IP2STR(&ip.gw));
}
return 0;
}
/* "iperf" command */
static struct {
struct arg_str *ip;
struct arg_lit *server;
struct arg_lit *udp;
struct arg_lit *version;
struct arg_int *port;
struct arg_int *length;
struct arg_int *interval;
struct arg_int *time;
struct arg_int *bw_limit;
struct arg_lit *abort;
struct arg_end *end;
} iperf_args;
static int ppp_cmd_iperf(int argc, char **argv)
{
int nerrors = arg_parse(argc, argv, (void **)&iperf_args);
iperf_cfg_t cfg;
if (nerrors != 0) {
arg_print_errors(stderr, iperf_args.end, argv[0]);
return 0;
}
memset(&cfg, 0, sizeof(cfg));
// ethernet iperf only support IPV4 address
cfg.type = IPERF_IP_TYPE_IPV4;
/* iperf -a */
if (iperf_args.abort->count != 0) {
iperf_stop();
return 0;
}
if (((iperf_args.ip->count == 0) && (iperf_args.server->count == 0)) ||
((iperf_args.ip->count != 0) && (iperf_args.server->count != 0))) {
ESP_LOGE(__func__, "Wrong mode! ESP32 should run in client or server mode");
return 0;
}
/* iperf -s */
if (iperf_args.ip->count == 0) {
cfg.flag |= IPERF_FLAG_SERVER;
}
/* iperf -c SERVER_ADDRESS */
else {
cfg.destination_ip4 = esp_ip4addr_aton(iperf_args.ip->sval[0]);
cfg.flag |= IPERF_FLAG_CLIENT;
}
if (iperf_args.length->count == 0) {
cfg.len_send_buf = 0;
} else {
cfg.len_send_buf = iperf_args.length->ival[0];
}
/* wait for ip, could blocked here */
xEventGroupWaitBits(event_group, GOTIP_BIT, pdFALSE, pdTRUE, portMAX_DELAY);
cfg.source_ip4 = INADDR_ANY;
/* iperf -u */
if (iperf_args.udp->count == 0) {
cfg.flag |= IPERF_FLAG_TCP;
} else {
cfg.flag |= IPERF_FLAG_UDP;
}
/* iperf -p */
if (iperf_args.port->count == 0) {
cfg.sport = IPERF_DEFAULT_PORT;
cfg.dport = IPERF_DEFAULT_PORT;
} else {
if (cfg.flag & IPERF_FLAG_SERVER) {
cfg.sport = iperf_args.port->ival[0];
cfg.dport = IPERF_DEFAULT_PORT;
} else {
cfg.sport = IPERF_DEFAULT_PORT;
cfg.dport = iperf_args.port->ival[0];
}
}
/* iperf -i */
if (iperf_args.interval->count == 0) {
cfg.interval = IPERF_DEFAULT_INTERVAL;
} else {
cfg.interval = iperf_args.interval->ival[0];
if (cfg.interval <= 0) {
cfg.interval = IPERF_DEFAULT_INTERVAL;
}
}
/* iperf -t */
if (iperf_args.time->count == 0) {
cfg.time = IPERF_DEFAULT_TIME;
} else {
cfg.time = iperf_args.time->ival[0];
if (cfg.time <= cfg.interval) {
cfg.time = cfg.interval;
}
}
/* iperf -b */
if (iperf_args.bw_limit->count == 0) {
cfg.bw_lim = IPERF_DEFAULT_NO_BW_LIMIT;
} else {
cfg.bw_lim = iperf_args.bw_limit->ival[0];
if (cfg.bw_lim <= 0) {
cfg.bw_lim = IPERF_DEFAULT_NO_BW_LIMIT;
}
}
printf("mode=%s-%s sip=" IPSTR ":%" PRIu16 ", dip=%" PRIu32 ".%" PRIu32 ".%" PRIu32 ".%" PRIu32 ":%" PRIu16 ", interval=%" PRIu32 ", time=%" PRIu32 "\r\n",
cfg.flag & IPERF_FLAG_TCP ? "tcp" : "udp",
cfg.flag & IPERF_FLAG_SERVER ? "server" : "client",
(uint16_t) cfg.source_ip4 & 0xFF,
(uint16_t) (cfg.source_ip4 >> 8) & 0xFF,
(uint16_t) (cfg.source_ip4 >> 16) & 0xFF,
(uint16_t) (cfg.source_ip4 >> 24) & 0xFF,
cfg.sport,
cfg.destination_ip4 & 0xFF, (cfg.destination_ip4 >> 8) & 0xFF,
(cfg.destination_ip4 >> 16) & 0xFF, (cfg.destination_ip4 >> 24) & 0xFF, cfg.dport,
cfg.interval, cfg.time);
iperf_start(&cfg);
return 0;
}
void register_pppd(void)
{
event_group = xEventGroupCreate();
ESP_ERROR_CHECK(esp_event_loop_create_default());
ESP_ERROR_CHECK(esp_netif_init());
esp_netif_config_t ppp_netif_config = ESP_NETIF_DEFAULT_PPP();
s_ppp_netif = esp_netif_new(&ppp_netif_config);
assert(s_ppp_netif);
esp_netif_ppp_config_t ppp_config = { true, true };
esp_netif_ppp_set_params(s_ppp_netif, &ppp_config);
ESP_ERROR_CHECK(modem_init_network(s_ppp_netif));
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, ESP_EVENT_ANY_ID, on_modem_event, NULL));
ESP_ERROR_CHECK(esp_event_handler_register(NETIF_PPP_STATUS, ESP_EVENT_ANY_ID, on_ppp_changed, NULL));
modem_start_network();
pppd_control_args.control = arg_str1(NULL, NULL, "<info>", "Get info of pppd");
pppd_control_args.end = arg_end(1);
const esp_console_cmd_t cmd = {
.command = "pppd",
.help = "PPP interface IO control",
.hint = NULL,
.func = pppd_cmd_control,
.argtable = &pppd_control_args
};
ESP_ERROR_CHECK(esp_console_cmd_register(&cmd));
iperf_args.ip = arg_str0("c", "client", "<ip>",
"run in client mode, connecting to <host>");
iperf_args.server = arg_lit0("s", "server", "run in server mode");
iperf_args.udp = arg_lit0("u", "udp", "use UDP rather than TCP");
iperf_args.version = arg_lit0("V", "ipv6_domain", "use IPV6 address rather than IPV4");
iperf_args.port = arg_int0("p", "port", "<port>",
"server port to listen on/connect to");
iperf_args.length = arg_int0("l", "len", "<length>", "set read/write buffer size");
iperf_args.interval = arg_int0("i", "interval", "<interval>",
"seconds between periodic bandwidth reports");
iperf_args.time = arg_int0("t", "time", "<time>", "time in seconds to transmit for (default 10 secs)");
iperf_args.bw_limit = arg_int0("b", "bandwidth", "<bandwidth>", "bandwidth to send at in Mbits/sec");
iperf_args.abort = arg_lit0("a", "abort", "abort running iperf");
iperf_args.end = arg_end(1);
const esp_console_cmd_t iperf_cmd = {
.command = "iperf",
.help = "iperf command",
.hint = NULL,
.func = &ppp_cmd_iperf,
.argtable = &iperf_args
};
ESP_ERROR_CHECK(esp_console_cmd_register(&iperf_cmd));
}

View File

@ -0,0 +1,26 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#pragma once
#include "esp_err.h"
#include "esp_netif.h"
/**
* @brief Initialize PPP network (with a generic PPP server)
* @param netif PPP netif
* @return ESP_OK on success
*/
esp_err_t modem_init_network(esp_netif_t *netif);
/**
* @brief Start PPP network
*/
void modem_start_network();
/**
* @brief Stop PPP network
*/
void modem_stop_network();

View File

@ -0,0 +1,43 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <stdio.h>
#include <string.h>
#include "sdkconfig.h"
#include "esp_log.h"
#include "esp_console.h"
#include "cmd_system.h"
void register_pppd(void);
void app_main(void)
{
esp_console_repl_t *repl = NULL;
esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT();
esp_console_dev_uart_config_t uart_config = ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT();
repl_config.prompt = "iperf>";
// init console REPL environment
ESP_ERROR_CHECK(esp_console_new_repl_uart(&uart_config, &repl_config, &repl));
/* Register commands */
register_system_common();
register_pppd();
printf("\n =======================================================\n");
printf(" | Steps to Test PPP Client Bandwidth |\n");
printf(" | |\n");
printf(" | 1. Enter 'help', check all supported commands |\n");
printf(" | 2. Start PPP server on host system |\n");
printf(" | - pppd /dev/ttyUSB1 115200 192.168.11.1:192.168.11.2 modem local noauth debug nocrtscts nodetach +ipv6\n");
printf(" | 3. Wait ESP32 to get IP from PPP server |\n");
printf(" | 4. Enter 'pppd info' (optional) |\n");
printf(" | 5. Server: 'iperf -u -s -i 3' |\n");
printf(" | 6. Client: 'iperf -u -c SERVER_IP -t 60 -i 3' |\n");
printf(" | |\n");
printf(" =======================================================\n\n");
// start console REPL
ESP_ERROR_CHECK(esp_console_start_repl(repl));
}

View File

@ -0,0 +1,112 @@
# SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Unlicense OR CC0-1.0
"""
Test case for iperf example.
This test case might have problem running on Windows:
- use `sudo killall iperf` to force kill iperf, didn't implement windows version
"""
from __future__ import division, unicode_literals
import logging
import os
import subprocess
import pytest
from common_test_methods import get_host_ip4_by_dest_ip
from idf_iperf_test_util import IperfUtility
from pytest_embedded import Dut
try:
from typing import Any, Callable, Tuple
except ImportError:
# Only used for type annotations
pass
NO_BANDWIDTH_LIMIT = -1 # iperf send bandwidth is not limited
class IperfTestUtilityEth(IperfUtility.IperfTestUtility):
""" iperf test implementation """
def __init__(self, dut: str, config_name: str, pc_nic_ip: str, pc_iperf_log_file: str, test_result:Any=None) -> None:
IperfUtility.IperfTestUtility.__init__(self, dut, config_name, 'None', 'None', pc_nic_ip, pc_iperf_log_file, test_result)
def setup(self) -> Tuple[str,int]:
"""
setup iperf test:
1. kill current iperf process
2. reboot DUT (currently iperf is not very robust, need to reboot DUT)
"""
try:
subprocess.check_output('sudo killall iperf 2>&1 > /dev/null', shell=True)
except subprocess.CalledProcessError:
pass
self.dut.write('restart')
dut_ip = self.dut.expect(r'pppd_test: IP : (\d+\.\d+\.\d+\.\d+)').group(1)
self.dut.expect("Type 'help' to get the list of commands.")
self.dut.expect('iperf>')
rssi = 0
return dut_ip, rssi
@pytest.fixture
def log_performance(record_property: Callable[[str, object], None]) -> Callable[[str, str], None]:
"""
log performance item with pre-defined format to the console
and record it under the ``properties`` tag in the junit report if available.
"""
def real_func(item: str, value: str) -> None:
"""
:param item: performance item name
:param value: performance value
"""
logging.info('[Performance][%s]: %s', item, value)
return real_func
def test_esp_pppd_iperf(
dut: Dut,
log_performance: Callable[[str, object], None],
# check_performance: Callable[[str, float, str], None],
) -> None:
"""
steps: |
1. test TCP tx rx and UDP tx rx throughput
2. compare with the pre-defined pass standard
"""
# 1. preparing
pc_iperf_log_file = os.path.join(dut.logdir, 'pc_iperf_log.md')
# 2. wait for DUT
dut_ip = dut.expect(r'pppd_test: IP : (\d+\.\d+\.\d+\.\d+)').group(1)
pc_nic_ip = get_host_ip4_by_dest_ip(dut_ip)
test_result = {
'tcp_tx': IperfUtility.TestResult('tcp', 'tx', 'ppp_client'),
'tcp_rx': IperfUtility.TestResult('tcp', 'rx', 'ppp_client'),
'udp_tx': IperfUtility.TestResult('udp', 'tx', 'ppp_client'),
'udp_rx': IperfUtility.TestResult('udp', 'rx', 'ppp_client'),
}
test_utility = IperfTestUtilityEth(dut, 'ppp', pc_nic_ip, pc_iperf_log_file, test_result)
# 3. run test for TCP Tx, Rx and UDP Tx, Rx
test_utility.run_test('tcp', 'tx', 0, 5)
test_utility.run_test('tcp', 'rx', 0, 5)
test_utility.run_test('udp', 'tx', 0, 5)
test_utility.run_test('udp', 'rx', 0, 5)
# 4. print out performance details
for throughput_type in test_result:
print('{}_throughput'.format(throughput_type))
print(test_result[throughput_type])
print('---------------------------')
# 5. log performance summary
for throughput_type in test_result:
log_performance('{}_throughput'.format(throughput_type),
'{:.02f} Mbps'.format(test_result[throughput_type].get_best_throughput()))

View File

@ -0,0 +1,3 @@
CONFIG_COMPILER_CXX_EXCEPTIONS=y
CONFIG_LWIP_PPP_SUPPORT=y
CONFIG_ESP_MAIN_TASK_STACK_SIZE=4096

View File

@ -35,6 +35,10 @@ bool manual_ota::begin()
esp_transport_handle_t tcp = esp_transport_tcp_init();
ssl_ = esp_transport_batch_tls_init(tcp, max_buffer_size_);
http_.config_.transport = ssl_;
if (http_.config_.cert_pem == nullptr || common_name_ == nullptr) {
ESP_LOGE(TAG, "TLS with no verification is not supported");
return fail();
}
if (!esp_transport_batch_set_ca_cert(ssl_, http_.config_.cert_pem, 0)) {
return fail();
}

View File

@ -40,7 +40,7 @@ public:
/**
* @brief Set common name of the server to verify
*/
const char *common_name_;
const char *common_name_{};
/**
* @brief Wrapper around the http client -- Please set the http config
*/

View File

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

View File

@ -1,5 +1,13 @@
# Changelog
## [0.3.0](https://github.com/espressif/esp-protocols/commits/mqtt_cxx-v0.3.0)
### Bug Fixes
- Incorrect documentation link ([aa4e9d57](https://github.com/espressif/esp-protocols/commit/aa4e9d57))
- reference protocol_examples_common from IDF ([e6c0538d](https://github.com/espressif/esp-protocols/commit/e6c0538d))
- specify override_path in example manifest files ([fa005c63](https://github.com/espressif/esp-protocols/commit/fa005c63))
## [0.2.0](https://github.com/espressif/esp-protocols/commits/mqtt_cxx-v0.2.0)
### Features

View File

@ -10,4 +10,4 @@ Get started with [examples](https://github.com/espressif/esp-protocols/tree/mast
## Documentation
* View the full [html documentation](https://docs.espressif.com/projects/esp-protocols/docs/latest/esp_mqtt_cxx/index.html)
* View the full [html documentation](https://docs.espressif.com/projects/esp-protocols/esp_mqtt_cxx/docs/latest/index.html)

View File

@ -1,4 +1,4 @@
version: "0.2.0"
version: "0.3.0"
description: C++ APIs for ESP-MQTT library
url: https://github.com/espressif/esp-protocols/tree/master/components/esp_mqtt_cxx
issues: https://github.com/espressif/esp-protocols/issues

View File

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

View File

@ -1,5 +1,12 @@
# Changelog
## [1.2.2](https://github.com/espressif/esp-protocols/commits/websocket-v1.2.2)
### Bug Fixes
- continuation after FIN in websocket client (#460) ([774d1c75e6](https://github.com/espressif/esp-protocols/commit/774d1c75e6))
- Re-applie refs to common comps idf_component.yml ([9fe44a4504](https://github.com/espressif/esp-protocols/commit/9fe44a4504))
## [1.2.1](https://github.com/espressif/esp-protocols/commits/websocket-v1.2.1)
### Bug Fixes

View File

@ -0,0 +1,35 @@
# ESP Websocket Client - Host Example
This example demonstrates the ESP websocket client using the `linux` target. It allows for compilation and execution of the example directly within a Linux environment.
## Compilation and Execution
To compile and execute this example on Linux need to set target `linux`
```
idf.py --preview set-target linux
idf.py build
./websocket.elf
```
## Example Output
```
I (164532) websocket: [APP] Startup..
I (164532) websocket: [APP] Free memory: 4294967295 bytes
I (164532) websocket: [APP] IDF version: v5.3-dev-1353-gb3f7e2c8a4
I (164538) websocket: Connecting to ws://echo.websocket.events...
W (164538) websocket_client: `reconnect_timeout_ms` is not set, or it is less than or equal to zero, using default time out 10000 (milliseconds)
W (164538) websocket_client: `network_timeout_ms` is not set, or it is less than or equal to zero, using default time out 10000 (milliseconds)
I (165103) websocket: WEBSOCKET_EVENT_CONNECTED
I (165539) websocket: Sending hello 0000
I (165627) websocket: WEBSOCKET_EVENT_DATA
I (165627) websocket: Received opcode=1
W (165627) websocket: Received=hello 0000
W (165627) websocket: Total payload length=10, data_len=10, current payload offset=0
I (166539) websocket: Sending fragmented message
```
## Coverage Reporting
For generating a coverage report, it's necessary to enable `CONFIG_GCOV_ENABLED=y` option. Set the following configuration in your project's SDK configuration file (`sdkconfig.ci.coverage`, `sdkconfig.ci.linux` or via `menuconfig`):

View File

@ -1,3 +1,4 @@
dependencies:
idf: ">5.2"
protocol_examples_common:
path: ${IDF_PATH}/examples/common_components/protocol_examples_common

View File

@ -4,5 +4,3 @@ CONFIG_IDF_TARGET_LINUX=y
CONFIG_ESP_EVENT_POST_FROM_ISR=n
CONFIG_ESP_EVENT_POST_FROM_IRAM_ISR=n
CONFIG_WEBSOCKET_URI="ws://echo.websocket.events"
CONFIG_WEBSOCKET_URI_FROM_STRING=y
CONFIG_WEBSOCKET_URI_FROM_STDIN=n

View File

@ -3,6 +3,3 @@ CONFIG_IDF_TARGET_LINUX=y
CONFIG_ESP_EVENT_POST_FROM_ISR=n
CONFIG_ESP_EVENT_POST_FROM_IRAM_ISR=n
CONFIG_WEBSOCKET_URI="ws://echo.websocket.events"
CONFIG_WEBSOCKET_URI_FROM_STRING=y
CONFIG_WEBSOCKET_URI_FROM_STDIN=n
CONFIG_EXAMPLE_CONNECT_WIFI=n

View File

@ -0,0 +1,5 @@
CONFIG_IDF_TARGET="linux"
CONFIG_IDF_TARGET_LINUX=y
CONFIG_ESP_EVENT_POST_FROM_ISR=n
CONFIG_ESP_EVENT_POST_FROM_IRAM_ISR=n
CONFIG_WEBSOCKET_URI="ws://echo.websocket.events"

View File

@ -1,4 +1,4 @@
version: "1.2.1"
version: "1.2.2"
description: WebSocket protocol client for ESP-IDF
url: https://github.com/espressif/esp-protocols/tree/master/components/esp_websocket_client
dependencies:

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.2.2
version: 1.2.4
version_files:
- idf_component.yml

View File

@ -1,5 +1,25 @@
# Changelog
## [1.2.4](https://github.com/espressif/esp-protocols/commits/mdns-v1.2.4)
### Bug Fixes
- Correction on 6d2c475 MDNS_PREDEF_NETIF_ETH fix ([fc59f87c4e](https://github.com/espressif/esp-protocols/commit/fc59f87c4e))
- fix the logic of creating pcb for networking socket ([5000a9a20a](https://github.com/espressif/esp-protocols/commit/5000a9a20a))
- fix compiling issue when disabling IPv4 ([2646dcd23a](https://github.com/espressif/esp-protocols/commit/2646dcd23a))
- Fix compile error when MDNS_PREDEF_NETIF_ETH is defined, but ETH_ENABLED is not (#459) ([6d2c475c20](https://github.com/espressif/esp-protocols/commit/6d2c475c20))
## [1.2.3](https://github.com/espressif/esp-protocols/commits/mdns-v1.2.3)
### Bug Fixes
- fixed CI issues for host and afl tests ([4be5efc84e](https://github.com/espressif/esp-protocols/commit/4be5efc84e))
- fix copy delegated host addr ([19fb36000c](https://github.com/espressif/esp-protocols/commit/19fb36000c))
- enable CONFIG_ESP_WIFI_ENABLED if CONFIG_SOC_WIFI_SUPPORTED is also enabled (for ESP-IDF <= 5.1) ([d20a718320](https://github.com/espressif/esp-protocols/commit/d20a718320))
- remove protocol_examples_common ([1ee9dae6bf](https://github.com/espressif/esp-protocols/commit/1ee9dae6bf))
- move the example into a subdirectory ([d28232b9f8](https://github.com/espressif/esp-protocols/commit/d28232b9f8))
- reference protocol_examples_common from IDF ([c83b76ea8f](https://github.com/espressif/esp-protocols/commit/c83b76ea8f))
## [1.2.2](https://github.com/espressif/esp-protocols/commits/mdns-v1.2.2)
### Bug Fixes

View File

@ -21,6 +21,12 @@
#include "driver/gpio.h"
#include "netdb.h"
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 1, 0)
/* CONFIG_LWIP_IPV4 was introduced in IDF v5.1, set CONFIG_LWIP_IPV4 to 1 by default for IDF v5.0 */
#ifndef CONFIG_LWIP_IPV4
#define CONFIG_LWIP_IPV4 1
#endif // CONFIG_LWIP_IPV4
#endif // ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 1, 0)
#define EXAMPLE_MDNS_INSTANCE CONFIG_MDNS_INSTANCE
#define EXAMPLE_BUTTON_GPIO CONFIG_MDNS_BUTTON_GPIO
@ -227,7 +233,7 @@ static void query_mdns_hosts_async(const char *host_name)
vTaskDelay(50 / portTICK_PERIOD_MS);
}
}
#ifdef CONFIG_LWIP_IPV4
static void query_mdns_host(const char *host_name)
{
ESP_LOGI(TAG, "Query A: %s.local", host_name);
@ -247,6 +253,7 @@ static void query_mdns_host(const char *host_name)
ESP_LOGI(TAG, "Query A: %s.local resolved to: " IPSTR, host_name, IP2STR(&addr));
}
#endif // CONFIG_LWIP_IPV4
static void initialise_button(void)
{
@ -265,7 +272,9 @@ static void check_button(void)
bool new_level = gpio_get_level(EXAMPLE_BUTTON_GPIO);
if (!new_level && old_level) {
query_mdns_hosts_async("esp32-mdns");
#ifdef CONFIG_LWIP_IPV4
query_mdns_host("esp32");
#endif
query_mdns_service("_arduino", "_tcp");
query_mdns_service("_http", "_tcp");
query_mdns_service("_printer", "_tcp");
@ -286,7 +295,9 @@ static void mdns_example_task(void *pvParameters)
{
#if CONFIG_MDNS_RESOLVE_TEST_SERVICES == 1
/* Send initial queries that are started by CI tester */
#ifdef CONFIG_LWIP_IPV4
query_mdns_host("tinytester");
#endif
query_mdns_host_with_gethostbyname("tinytester-lwip.local");
query_mdns_host_with_getaddrinfo("tinytester-lwip.local");
#endif
@ -362,7 +373,16 @@ static void query_mdns_host_with_gethostbyname(char *host)
if (res) {
unsigned int i = 0;
while (res->h_addr_list[i] != NULL) {
ESP_LOGI(TAG, "gethostbyname: %s resolved to: %s", host, inet_ntoa(*(struct in_addr *) (res->h_addr_list[i])));
ESP_LOGI(TAG, "gethostbyname: %s resolved to: %s", host,
#if defined(CONFIG_LWIP_IPV6) && defined(CONFIG_LWIP_IPV4)
res->h_addrtype == AF_INET ? inet_ntoa(*(struct in_addr *) (res->h_addr_list[i])) :
inet6_ntoa(*(struct in6_addr *) (res->h_addr_list[i]))
#elif defined(CONFIG_LWIP_IPV6)
inet6_ntoa(*(struct in6_addr *) (res->h_addr_list[i]))
#else
inet_ntoa(*(struct in_addr *) (res->h_addr_list[i]))
#endif
);
i++;
}
}
@ -384,10 +404,12 @@ static void query_mdns_host_with_getaddrinfo(char *host)
if (!getaddrinfo(host, NULL, &hints, &res)) {
while (res) {
char *resolved_addr;
#if CONFIG_LWIP_IPV6
#if defined(CONFIG_LWIP_IPV6) && defined(CONFIG_LWIP_IPV4)
resolved_addr = res->ai_family == AF_INET ?
inet_ntoa(((struct sockaddr_in *) res->ai_addr)->sin_addr) :
inet_ntoa(((struct sockaddr_in6 *) res->ai_addr)->sin6_addr);
inet6_ntoa(((struct sockaddr_in6 *) res->ai_addr)->sin6_addr);
#elif defined(CONFIG_LWIP_IPV6)
resolved_addr = inet6_ntoa(((struct sockaddr_in6 *) res->ai_addr)->sin6_addr);
#else
resolved_addr = inet_ntoa(((struct sockaddr_in *) res->ai_addr)->sin_addr);
#endif // CONFIG_LWIP_IPV6

View File

@ -87,26 +87,30 @@ def mdns_server(esp_host, events):
continue
data, addr = sock.recvfrom(1024)
dns = dpkt.dns.DNS(data)
if len(dns.qd) > 0 and dns.qd[0].type == dpkt.dns.DNS_A:
if dns.qd[0].name == TESTER_NAME:
print('Received query: {} '.format(dns.__repr__()))
sock.sendto(get_dns_answer_to_mdns(TESTER_NAME),
(MCAST_GRP, UDP_PORT))
elif dns.qd[0].name == TESTER_NAME_LWIP:
print('Received query: {} '.format(dns.__repr__()))
sock.sendto(
get_dns_answer_to_mdns_lwip(TESTER_NAME_LWIP, dns.id),
addr)
if len(dns.an) > 0 and dns.an[0].type == dpkt.dns.DNS_A:
print('Received answer from {}'.format(dns.an[0].name))
if dns.an[0].name == esp_host + u'.local':
print('Received answer to esp32-mdns query: {}'.format(
dns.__repr__()))
events['esp_answered'].set()
if dns.an[0].name == esp_host + u'-delegated.local':
print('Received answer to esp32-mdns-delegate query: {}'.
format(dns.__repr__()))
events['esp_delegated_answered'].set()
if len(dns.qd) > 0:
for dns_query in dns.qd:
if dns_query.type == dpkt.dns.DNS_A:
if dns_query.name == TESTER_NAME:
print('Received query: {} '.format(dns.__repr__()))
sock.sendto(get_dns_answer_to_mdns(TESTER_NAME),
(MCAST_GRP, UDP_PORT))
elif dns_query.name == TESTER_NAME_LWIP:
print('Received query: {} '.format(dns.__repr__()))
sock.sendto(
get_dns_answer_to_mdns_lwip(TESTER_NAME_LWIP, dns.id),
addr)
if len(dns.an) > 0:
for dns_answer in dns.an:
if dns_answer.type == dpkt.dns.DNS_A:
print('Received answer from {}'.format(dns_answer.name))
if dns_answer.name == esp_host + u'.local':
print('Received answer to esp32-mdns query: {}'.format(
dns.__repr__()))
events['esp_answered'].set()
if dns_answer.name == esp_host + u'-delegated.local':
print('Received answer to esp32-mdns-delegate query: {}'.format(
dns.__repr__()))
events['esp_delegated_answered'].set()
except socket.timeout:
break
except dpkt.UnpackError:
@ -133,62 +137,66 @@ def test_examples_protocol_mdns(dut):
}
mdns_responder = Thread(target=mdns_server,
args=(str(specific_host), mdns_server_events))
ipv4 = dut.expect(r'IPv4 address: (\d+\.\d+\.\d+\.\d+)[^\d]',
timeout=30)[1].decode()
ip_addresses = [ipv4]
ip_addresses = []
if dut.app.sdkconfig.get('LWIP_IPV4') is True:
ipv4 = dut.expect(r'IPv4 address: (\d+\.\d+\.\d+\.\d+)[^\d]',
timeout=30)[1].decode()
ip_addresses.append(ipv4)
if dut.app.sdkconfig.get('LWIP_IPV6') is True:
ipv6_r = r':'.join((r'[0-9a-fA-F]{4}', ) * 8)
ipv6 = dut.expect(ipv6_r, timeout=30)[0].decode()
ip_addresses.append(ipv6)
print('Connected with IP addresses: {}'.format(','.join(ip_addresses)))
try:
# 3. check the mdns name is accessible.
# TODO: Add test for example disabling IPV4
mdns_responder.start()
if not mdns_server_events['esp_answered'].wait(timeout=30):
raise ValueError(
'Test has failed: did not receive mdns answer within timeout')
if not mdns_server_events['esp_delegated_answered'].wait(timeout=30):
raise ValueError(
'Test has failed: did not receive mdns answer for delegated host within timeout'
if dut.app.sdkconfig.get('LWIP_IPV4') is True:
# 3. check the mdns name is accessible.
if not mdns_server_events['esp_answered'].wait(timeout=30):
raise ValueError(
'Test has failed: did not receive mdns answer within timeout')
if not mdns_server_events['esp_delegated_answered'].wait(timeout=30):
raise ValueError(
'Test has failed: did not receive mdns answer for delegated host within timeout'
)
# 4. check DUT output if mdns advertized host is resolved
dut.expect(
re.compile(
b'mdns-test: Query A: tinytester.local resolved to: 127.0.0.1')
)
# 4. check DUT output if mdns advertized host is resolved
dut.expect(
re.compile(
b'mdns-test: Query A: tinytester.local resolved to: 127.0.0.1')
)
dut.expect(
re.compile(
b'mdns-test: gethostbyname: tinytester-lwip.local resolved to: 127.0.0.1'
))
dut.expect(
re.compile(
b'mdns-test: getaddrinfo: tinytester-lwip.local resolved to: 127.0.0.1'
))
# 5. check the DUT answers to `dig` command
dig_output = subprocess.check_output([
'dig', '+short', '-p', '5353', '@224.0.0.251',
'{}.local'.format(specific_host)
])
print('Resolving {} using "dig" succeeded with:\n{}'.format(
specific_host, dig_output))
if not ipv4.encode('utf-8') in dig_output:
raise ValueError(
'Test has failed: Incorrectly resolved DUT hostname using dig'
"Output should've contained DUT's IP address:{}".format(ipv4))
# 6. check the DUT reverse lookup
if dut.app.sdkconfig.get('MDNS_RESPOND_REVERSE_QUERIES') is True:
for ip_address in ip_addresses:
dig_output = subprocess.check_output([
'dig', '+short', '-p', '5353', '@224.0.0.251', '-x',
'{}'.format(ip_address)
])
print('Reverse lookup for {} using "dig" succeeded with:\n{}'.
format(ip_address, dig_output))
if specific_host not in dig_output.decode():
raise ValueError(
'Test has failed: Incorrectly resolved DUT IP address using dig'
"Output should've contained DUT's name:{}".format(
specific_host))
dut.expect(
re.compile(
b'mdns-test: gethostbyname: tinytester-lwip.local resolved to: 127.0.0.1'
))
dut.expect(
re.compile(
b'mdns-test: getaddrinfo: tinytester-lwip.local resolved to: 127.0.0.1'
))
# 5. check the DUT answers to `dig` command
dig_output = subprocess.check_output([
'dig', '+short', '-p', '5353', '@224.0.0.251',
'{}.local'.format(specific_host)
])
print('Resolving {} using "dig" succeeded with:\n{}'.format(
specific_host, dig_output))
if not ipv4.encode('utf-8') in dig_output:
raise ValueError(
'Test has failed: Incorrectly resolved DUT hostname using dig'
"Output should've contained DUT's IP address:{}".format(ipv4))
# 6. check the DUT reverse lookup
if dut.app.sdkconfig.get('MDNS_RESPOND_REVERSE_QUERIES') is True:
for ip_address in ip_addresses:
dig_output = subprocess.check_output([
'dig', '+short', '-p', '5353', '@224.0.0.251', '-x',
'{}'.format(ip_address)
])
print('Reverse lookup for {} using "dig" succeeded with:\n{}'.
format(ip_address, dig_output))
if specific_host not in dig_output.decode():
raise ValueError(
'Test has failed: Incorrectly resolved DUT IP address using dig'
"Output should've contained DUT's name:{}".format(
specific_host))
finally:
mdns_server_events['stop'].set()

View File

@ -0,0 +1,15 @@
CONFIG_IDF_TARGET="esp32"
CONFIG_MDNS_RESOLVE_TEST_SERVICES=y
CONFIG_MDNS_ADD_MAC_TO_HOSTNAME=y
CONFIG_MDNS_PUBLISH_DELEGATE_HOST=y
CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES=y
CONFIG_LWIP_IPV4=n
CONFIG_EXAMPLE_CONNECT_ETHERNET=y
CONFIG_EXAMPLE_CONNECT_WIFI=n
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
CONFIG_EXAMPLE_ETH_PHY_IP101=y
CONFIG_EXAMPLE_ETH_MDC_GPIO=23
CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5
CONFIG_EXAMPLE_ETH_PHY_ADDR=1
CONFIG_MDNS_BUTTON_GPIO=32

View File

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

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -132,7 +132,7 @@ static inline esp_netif_t *esp_netif_from_preset_if(mdns_predef_if_t predef_if)
return esp_netif_get_handle_from_ifkey("WIFI_STA_DEF");
case MDNS_IF_AP:
return esp_netif_get_handle_from_ifkey("WIFI_AP_DEF");
#if CONFIG_ETH_ENABLED
#if CONFIG_ETH_ENABLED && CONFIG_MDNS_PREDEF_NETIF_ETH
case MDNS_IF_ETH:
return esp_netif_get_handle_from_ifkey("ETH_DEF");
#endif
@ -184,6 +184,11 @@ static inline void _mdns_clean_netif_ptr(mdns_if_t tcpip_if)
static mdns_if_t _mdns_get_if_from_esp_netif(esp_netif_t *esp_netif)
{
for (int i = 0; i < MDNS_MAX_INTERFACES; ++i) {
// The predefined netifs in the static array are NULL when firstly calling this function
// if IPv4 is disabled. Set these netifs here.
if (s_esp_netifs[i].netif == NULL && s_esp_netifs[i].predefined) {
s_esp_netifs[i].netif = esp_netif_from_preset_if(s_esp_netifs[i].predef_if);
}
if (esp_netif == s_esp_netifs[i].netif) {
return i;
}
@ -1059,6 +1064,7 @@ static uint16_t _mdns_append_srv_record(uint8_t *packet, uint16_t *index, mdns_s
return record_length;
}
#ifdef CONFIG_LWIP_IPV4
/**
* @brief appends A record to a packet, incrementing the index
*
@ -1108,8 +1114,9 @@ static uint16_t _mdns_append_a_record(uint8_t *packet, uint16_t *index, const ch
record_length += 4;
return record_length;
}
#endif /* CONFIG_LWIP_IPV4 */
#if CONFIG_LWIP_IPV6
#ifdef CONFIG_LWIP_IPV6
/**
* @brief appends AAAA record to a packet, incrementing the index
*
@ -1232,7 +1239,7 @@ static bool _mdns_if_is_dup(mdns_if_t tcpip_if)
return false;
}
#if CONFIG_LWIP_IPV6
#ifdef CONFIG_LWIP_IPV6
/**
* @brief Check if IPv6 address is NULL
*/
@ -1247,7 +1254,7 @@ static bool _ipv6_address_is_zero(esp_ip6_addr_t ip6)
}
return true;
}
#endif
#endif /* CONFIG_LWIP_IPV6 */
static uint8_t _mdns_append_host_answer(uint8_t *packet, uint16_t *index, mdns_host_item_t *host,
uint8_t address_type, bool flush, bool bye)
@ -1257,17 +1264,19 @@ static uint8_t _mdns_append_host_answer(uint8_t *packet, uint16_t *index, mdns_h
while (addr != NULL) {
if (addr->addr.type == address_type) {
#ifdef CONFIG_LWIP_IPV4
if (address_type == ESP_IPADDR_TYPE_V4 &&
_mdns_append_a_record(packet, index, host->hostname, addr->addr.u_addr.ip4.addr, flush, bye) <= 0) {
break;
}
#if CONFIG_LWIP_IPV6
#endif /* CONFIG_LWIP_IPV4 */
#ifdef CONFIG_LWIP_IPV6
if (address_type == ESP_IPADDR_TYPE_V6 &&
_mdns_append_aaaa_record(packet, index, host->hostname, (uint8_t *)addr->addr.u_addr.ip6.addr, flush,
bye) <= 0) {
break;
}
#endif // CONFIG_LWIP_IPV6
#endif /* CONFIG_LWIP_IPV6 */
num_records++;
}
addr = addr->next;
@ -1360,7 +1369,9 @@ static uint8_t _mdns_append_answer(uint8_t *packet, uint16_t *index, mdns_out_an
return _mdns_append_txt_record(packet, index, answer->service, answer->flush, answer->bye) > 0;
} else if (answer->type == MDNS_TYPE_SDPTR) {
return _mdns_append_sdptr_record(packet, index, answer->service, answer->flush, answer->bye) > 0;
} else if (answer->type == MDNS_TYPE_A) {
}
#ifdef CONFIG_LWIP_IPV4
else if (answer->type == MDNS_TYPE_A) {
if (answer->host == &_mdns_self_host) {
esp_netif_ip_info_t if_ip_info;
if (!mdns_is_netif_ready(tcpip_if, MDNS_IP_PROTOCOL_V4) && _mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V4].state != PCB_DUP) {
@ -1387,7 +1398,8 @@ static uint8_t _mdns_append_answer(uint8_t *packet, uint16_t *index, mdns_out_an
return _mdns_append_host_answer(packet, index, answer->host, ESP_IPADDR_TYPE_V4, answer->flush, answer->bye);
}
}
#if CONFIG_LWIP_IPV6
#endif /* CONFIG_LWIP_IPV4 */
#ifdef CONFIG_LWIP_IPV6
else if (answer->type == MDNS_TYPE_AAAA) {
if (answer->host == &_mdns_self_host) {
struct esp_ip6_addr if_ip6s[NETIF_IPV6_MAX_NUMS];
@ -1425,7 +1437,7 @@ static uint8_t _mdns_append_answer(uint8_t *packet, uint16_t *index, mdns_out_an
answer->bye);
}
}
#endif
#endif /* CONFIG_LWIP_IPV6 */
return 0;
}
@ -1713,12 +1725,14 @@ static mdns_tx_packet_t *_mdns_alloc_packet_default(mdns_if_t tcpip_if, mdns_ip_
packet->tcpip_if = tcpip_if;
packet->ip_protocol = ip_protocol;
packet->port = MDNS_SERVICE_PORT;
#ifdef CONFIG_LWIP_IPV4
if (ip_protocol == MDNS_IP_PROTOCOL_V4) {
esp_ip_addr_t addr = ESP_IP4ADDR_INIT(224, 0, 0, 251);
memcpy(&packet->dst, &addr, sizeof(esp_ip_addr_t));
}
#if CONFIG_LWIP_IPV6
else {
#endif
#ifdef CONFIG_LWIP_IPV6
if (ip_protocol == MDNS_IP_PROTOCOL_V6) {
esp_ip_addr_t addr = ESP_IP6ADDR_INIT(0x000002ff, 0, 0, 0xfb000000);
memcpy(&packet->dst, &addr, sizeof(esp_ip_addr_t));
}
@ -2877,6 +2891,7 @@ static void _mdns_dup_interface(mdns_if_t tcpip_if)
}
}
#ifdef CONFIG_LWIP_IPV4
/**
* @brief Detect IPv4 address collision
*/
@ -2890,7 +2905,6 @@ static int _mdns_check_a_collision(esp_ip4_addr_t *ip, mdns_if_t tcpip_if)
if (esp_netif_get_ip_info(_mdns_get_esp_netif(tcpip_if), &if_ip_info)) {
return 1;//they win
}
int ret = memcmp((uint8_t *)&if_ip_info.ip.addr, (uint8_t *)&ip->addr, sizeof(esp_ip4_addr_t));
if (ret > 0) {
return -1;//we win
@ -2911,8 +2925,9 @@ static int _mdns_check_a_collision(esp_ip4_addr_t *ip, mdns_if_t tcpip_if)
}
return 0;//same
}
#endif /* CONFIG_LWIP_IPV4 */
#if CONFIG_LWIP_IPV6
#ifdef CONFIG_LWIP_IPV6
/**
* @brief Detect IPv6 address collision
*/
@ -2946,7 +2961,7 @@ static int _mdns_check_aaaa_collision(esp_ip6_addr_t *ip, mdns_if_t tcpip_if)
}
return 0;//same
}
#endif
#endif /* CONFIG_LWIP_IPV6 */
static bool _hostname_is_ours(const char *hostname)
{
@ -3509,22 +3524,25 @@ void mdns_parse_packet(mdns_rx_packet_t *packet)
#ifndef CONFIG_MDNS_SKIP_SUPPRESSING_OWN_QUERIES
// Check if the packet wasn't sent by us
#ifdef CONFIG_LWIP_IPV4
if (packet->ip_protocol == MDNS_IP_PROTOCOL_V4) {
esp_netif_ip_info_t if_ip_info;
if (esp_netif_get_ip_info(_mdns_get_esp_netif(packet->tcpip_if), &if_ip_info) == ESP_OK &&
memcmp(&if_ip_info.ip.addr, &packet->src.u_addr.ip4.addr, sizeof(esp_ip4_addr_t)) == 0) {
return;
}
#if CONFIG_LWIP_IPV6
} else {
}
#endif /* CONFIG_LWIP_IPV4 */
#ifdef CONFIG_LWIP_IPV6
if (packet->ip_protocol == MDNS_IP_PROTOCOL_V6) {
struct esp_ip6_addr if_ip6;
if (esp_netif_get_ip6_linklocal(_mdns_get_esp_netif(packet->tcpip_if), &if_ip6) == ESP_OK &&
memcmp(&if_ip6, &packet->src.u_addr.ip6, sizeof(esp_ip6_addr_t)) == 0) {
return;
}
#endif
}
#endif
#endif /* CONFIG_LWIP_IPV6 */
#endif // CONFIG_MDNS_SKIP_SUPPRESSING_OWN_QUERIES
// Check for the minimum size of mdns packet
if (len <= MDNS_HEAD_ADDITIONAL_OFFSET) {
@ -3887,7 +3905,7 @@ void mdns_parse_packet(mdns_rx_packet_t *packet)
}
}
#if CONFIG_LWIP_IPV6
#ifdef CONFIG_LWIP_IPV6
else if (type == MDNS_TYPE_AAAA) {//ipv6
esp_ip_addr_t ip6;
ip6.type = ESP_IPADDR_TYPE_V6;
@ -3940,7 +3958,8 @@ void mdns_parse_packet(mdns_rx_packet_t *packet)
}
}
#endif
#endif /* CONFIG_LWIP_IPV6 */
#ifdef CONFIG_LWIP_IPV4
else if (type == MDNS_TYPE_A) {
esp_ip_addr_t ip;
ip.type = ESP_IPADDR_TYPE_V4;
@ -3993,6 +4012,7 @@ void mdns_parse_packet(mdns_rx_packet_t *packet)
}
}
#endif /* CONFIG_LWIP_IPV4 */
}
//end while
if (parsed_packet->authoritative) {
@ -4094,6 +4114,7 @@ static void perform_event_action(mdns_if_t mdns_if, mdns_event_actions_t action)
}
#ifdef CONFIG_MDNS_RESPOND_REVERSE_QUERIES
#ifdef CONFIG_LWIP_IPV4
if (action & MDNS_EVENT_IP4_REVERSE_LOOKUP) {
esp_netif_ip_info_t if_ip_info;
if (esp_netif_get_ip_info(_mdns_get_esp_netif(mdns_if), &if_ip_info) == ESP_OK) {
@ -4107,7 +4128,7 @@ static void perform_event_action(mdns_if_t mdns_if, mdns_event_actions_t action)
}
}
}
#endif /* CONFIG_LWIP_IPV4 */
#ifdef CONFIG_LWIP_IPV6
if (action & MDNS_EVENT_IP6_REVERSE_LOOKUP) {
esp_ip6_addr_t addr6;
@ -4189,7 +4210,7 @@ void mdns_preset_if_handle_system_event(void *arg, esp_event_base_t event_base,
}
} else
#endif
#if CONFIG_ETH_ENABLED
#if CONFIG_ETH_ENABLED && CONFIG_MDNS_PREDEF_NETIF_ETH
if (event_base == ETH_EVENT) {
switch (event_id) {
case ETHERNET_EVENT_CONNECTED:
@ -4214,7 +4235,7 @@ void mdns_preset_if_handle_system_event(void *arg, esp_event_base_t event_base,
post_mdns_enable_pcb(MDNS_IF_STA, MDNS_IP_PROTOCOL_V4);
post_mdns_announce_pcb(MDNS_IF_STA, MDNS_IP_PROTOCOL_V6);
break;
#if CONFIG_ETH_ENABLED
#if CONFIG_ETH_ENABLED && CONFIG_MDNS_PREDEF_NETIF_ETH
case IP_EVENT_ETH_GOT_IP:
post_mdns_enable_pcb(MDNS_IF_ETH, MDNS_IP_PROTOCOL_V4);
break;
@ -5483,22 +5504,25 @@ esp_err_t mdns_init(void)
#endif
uint8_t i;
#if CONFIG_LWIP_IPV6
#ifdef CONFIG_LWIP_IPV6
esp_ip6_addr_t tmp_addr6;
#endif
#ifdef CONFIG_LWIP_IPV4
esp_netif_ip_info_t if_ip_info;
#endif
for (i = 0; i < MDNS_MAX_INTERFACES; i++) {
#if CONFIG_LWIP_IPV6
#ifdef CONFIG_LWIP_IPV6
if (!esp_netif_get_ip6_linklocal(_mdns_get_esp_netif(i), &tmp_addr6) && !_ipv6_address_is_zero(tmp_addr6)) {
_mdns_enable_pcb(i, MDNS_IP_PROTOCOL_V6);
}
#endif
#ifdef CONFIG_LWIP_IPV4
if (!esp_netif_get_ip_info(_mdns_get_esp_netif(i), &if_ip_info) && if_ip_info.ip.addr) {
_mdns_enable_pcb(i, MDNS_IP_PROTOCOL_V4);
}
#endif
}
if (_mdns_service_task_start()) {
//service start failed!
err = ESP_FAIL;
@ -6468,6 +6492,7 @@ esp_err_t mdns_lookup_selfhosted_service(const char *instance, const char *servi
return ESP_OK;
}
#ifdef CONFIG_LWIP_IPV4
esp_err_t mdns_query_a(const char *name, uint32_t timeout, esp_ip4_addr_t *addr)
{
mdns_result_t *result = NULL;
@ -6504,8 +6529,9 @@ esp_err_t mdns_query_a(const char *name, uint32_t timeout, esp_ip4_addr_t *addr)
mdns_query_results_free(result);
return ESP_ERR_NOT_FOUND;
}
#endif /* CONFIG_LWIP_IPV4 */
#if CONFIG_LWIP_IPV6
#ifdef CONFIG_LWIP_IPV6
esp_err_t mdns_query_aaaa(const char *name, uint32_t timeout, esp_ip6_addr_t *addr)
{
mdns_result_t *result = NULL;
@ -6542,7 +6568,7 @@ esp_err_t mdns_query_aaaa(const char *name, uint32_t timeout, esp_ip6_addr_t *ad
mdns_query_results_free(result);
return ESP_ERR_NOT_FOUND;
}
#endif
#endif /* CONFIG_LWIP_IPV6 */
#ifdef MDNS_ENABLE_DEBUG

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -8,6 +8,7 @@
#include "esp_console.h"
#include "argtable3/argtable3.h"
#include "mdns.h"
#include "mdns_private.h"
static const char *ip_protocol_str[] = {"V4", "V6", "MAX"};
@ -50,6 +51,7 @@ static struct {
struct arg_end *end;
} mdns_query_a_args;
#ifdef CONFIG_LWIP_IPV4
static int cmd_mdns_query_a(int argc, char **argv)
{
int nerrors = arg_parse(argc, argv, (void **) &mdns_query_a_args);
@ -106,8 +108,9 @@ static void register_mdns_query_a(void)
ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_init) );
}
#endif /* CONFIG_LWIP_IPV4 */
#if CONFIG_LWIP_IPV6
#ifdef CONFIG_LWIP_IPV6
static int cmd_mdns_query_aaaa(int argc, char **argv)
{
int nerrors = arg_parse(argc, argv, (void **) &mdns_query_a_args);
@ -164,7 +167,7 @@ static void register_mdns_query_aaaa(void)
ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_init) );
}
#endif
#endif /* CONFIG_LWIP_IPV6 */
static struct {
struct arg_str *instance;
@ -1042,8 +1045,10 @@ void mdns_console_register(void)
register_mdns_service_txt_remove();
register_mdns_service_remove_all();
#ifdef CONFIG_LWIP_IPV4
register_mdns_query_a();
#if CONFIG_LWIP_IPV6
#endif
#ifdef CONFIG_LWIP_IPV6
register_mdns_query_aaaa();
#endif
register_mdns_query_txt();

View File

@ -96,6 +96,7 @@ static esp_err_t _udp_join_group(mdns_if_t if_inx, mdns_ip_protocol_t ip_protoco
netif = esp_netif_get_netif_impl(tcpip_if);
assert(netif);
#if LWIP_IPV4
if (ip_protocol == MDNS_IP_PROTOCOL_V4) {
ip4_addr_t multicast_addr;
IP4_ADDR(&multicast_addr, 224, 0, 0, 251);
@ -110,21 +111,22 @@ static esp_err_t _udp_join_group(mdns_if_t if_inx, mdns_ip_protocol_t ip_protoco
}
}
}
#if CONFIG_LWIP_IPV6
else {
#endif // LWIP_IPV4
#if LWIP_IPV6
if (ip_protocol == MDNS_IP_PROTOCOL_V6) {
ip_addr_t multicast_addr = IPADDR6_INIT(0x000002ff, 0, 0, 0xfb000000);
if (join) {
if (mld6_joingroup_netif(netif, &(multicast_addr.u_addr.ip6))) {
if (mld6_joingroup_netif(netif, ip_2_ip6(&multicast_addr))) {
return ESP_ERR_INVALID_STATE;
}
} else {
if (mld6_leavegroup_netif(netif, &(multicast_addr.u_addr.ip6))) {
if (mld6_leavegroup_netif(netif, ip_2_ip6(&multicast_addr))) {
return ESP_ERR_INVALID_STATE;
}
}
}
#endif
#endif // LWIP_IPV6
return ESP_OK;
}
@ -152,29 +154,34 @@ static void _udp_recv(void *arg, struct udp_pcb *upcb, struct pbuf *pb, const ip
packet->tcpip_if = MDNS_MAX_INTERFACES;
packet->pb = this_pb;
packet->src_port = rport;
#if CONFIG_LWIP_IPV6
#if LWIP_IPV4 && LWIP_IPV6
packet->src.type = raddr->type;
memcpy(&packet->src.u_addr, &raddr->u_addr, sizeof(raddr->u_addr));
#else
#elif LWIP_IPV4
packet->src.type = IPADDR_TYPE_V4;
memcpy(&packet->src.u_addr.ip4, &raddr->addr, sizeof(ip_addr_t));
packet->src.u_addr.ip4.addr = raddr->addr;
#elif LWIP_IPV6
packet->src.type = IPADDR_TYPE_V6;
memcpy(&packet->src.u_addr.ip6, raddr, sizeof(ip_addr_t));
#endif
packet->dest.type = packet->src.type;
#if LWIP_IPV4
if (packet->src.type == IPADDR_TYPE_V4) {
packet->ip_protocol = MDNS_IP_PROTOCOL_V4;
struct ip_hdr *iphdr = (struct ip_hdr *)(((uint8_t *)(packet->pb->payload)) - UDP_HLEN - IP_HLEN);
packet->dest.u_addr.ip4.addr = iphdr->dest.addr;
packet->multicast = ip4_addr_ismulticast(&(packet->dest.u_addr.ip4));
}
#if CONFIG_LWIP_IPV6
else {
#endif // LWIP_IPV4
#if LWIP_IPV6
if (packet->src.type == IPADDR_TYPE_V6) {
packet->ip_protocol = MDNS_IP_PROTOCOL_V6;
struct ip6_hdr *ip6hdr = (struct ip6_hdr *)(((uint8_t *)(packet->pb->payload)) - UDP_HLEN - IP6_HLEN);
memcpy(&packet->dest.u_addr.ip6.addr, (uint8_t *)ip6hdr->dest.addr, 16);
packet->multicast = ip6_addr_ismulticast(&(packet->dest.u_addr.ip6));
}
#endif
#endif // LWIP_IPV6
//lwip does not return the proper pcb if you have more than one for the same multicast address (but different interfaces)
struct netif *netif = NULL;
@ -182,15 +189,14 @@ static void _udp_recv(void *arg, struct udp_pcb *upcb, struct pbuf *pb, const ip
for (i = 0; i < MDNS_MAX_INTERFACES; i++) {
netif = esp_netif_get_netif_impl(_mdns_get_esp_netif(i));
if (s_interfaces[i].proto && netif && netif == ip_current_input_netif ()) {
#if LWIP_IPV4
if (packet->src.type == IPADDR_TYPE_V4) {
#if CONFIG_LWIP_IPV6
if ((packet->src.u_addr.ip4.addr & netif->netmask.u_addr.ip4.addr) != (netif->ip_addr.u_addr.ip4.addr & netif->netmask.u_addr.ip4.addr)) {
#else
if ((packet->src.u_addr.ip4.addr & netif->netmask.addr) != (netif->ip_addr.addr & netif->netmask.addr)) {
#endif //packet source is not in the same subnet
if ((packet->src.u_addr.ip4.addr & ip_2_ip4(&netif->netmask)->addr) != (ip_2_ip4(&netif->ip_addr)->addr & ip_2_ip4(&netif->netmask)->addr)) {
//packet source is not in the same subnet
break;
}
}
#endif // LWIP_IPV4
packet->tcpip_if = i;
found = true;
break;
@ -347,12 +353,17 @@ size_t _mdns_udp_pcb_write(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol, c
memcpy((uint8_t *)pbt->payload, data, len);
ip_addr_t ip_add_copy;
#if CONFIG_LWIP_IPV6
#if LWIP_IPV6 && LWIP_IPV4
ip_add_copy.type = ip->type;
memcpy(&(ip_add_copy.u_addr), &(ip->u_addr), sizeof(ip_add_copy.u_addr));
#else
memcpy(&(ip_add_copy.addr), &(ip->u_addr), sizeof(ip_add_copy.addr));
#endif // CONFIG_LWIP_IPV6
#elif LWIP_IPV4
ip_add_copy.addr = ip->u_addr.ip4.addr;
#elif LWIP_IPV6
#if LWIP_IPV6_SCOPES
ip_add_copy.zone = ip->u_addr.ip6.zone;
#endif // LWIP_IPV6_SCOPES
memcpy(ip_add_copy.addr, ip->u_addr.ip6.addr, sizeof(ip_add_copy.addr));
#endif
mdns_api_call_t msg = {
.tcpip_if = tcpip_if,

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -138,11 +138,13 @@ static inline char *get_string_address(struct sockaddr_storage *source_addr)
static char address_str[40]; // 40=(8*4+7+term) is the max size of ascii IPv6 addr "XXXX:XX...XX:XXXX"
char *res = NULL;
// Convert ip address to string
#ifdef CONFIG_LWIP_IPV4
if (source_addr->ss_family == PF_INET) {
res = inet_ntoa_r(((struct sockaddr_in *)source_addr)->sin_addr, address_str, sizeof(address_str));
}
#endif
#ifdef CONFIG_LWIP_IPV6
else if (source_addr->ss_family == PF_INET6) {
if (source_addr->ss_family == PF_INET6) {
res = inet6_ntoa_r(((struct sockaddr_in6 *)source_addr)->sin6_addr, address_str, sizeof(address_str));
}
#endif
@ -157,6 +159,7 @@ static inline size_t espaddr_to_inet(const esp_ip_addr_t *addr, const uint16_t p
{
size_t ss_addr_len = 0;
memset(in_addr, 0, sizeof(struct sockaddr_storage));
#ifdef CONFIG_LWIP_IPV4
if (ip_protocol == MDNS_IP_PROTOCOL_V4 && addr->type == ESP_IPADDR_TYPE_V4) {
in_addr->ss_family = PF_INET;
#if !defined(CONFIG_IDF_TARGET_LINUX)
@ -167,8 +170,9 @@ static inline size_t espaddr_to_inet(const esp_ip_addr_t *addr, const uint16_t p
in_addr_ip4->sin_port = port;
in_addr_ip4->sin_addr.s_addr = addr->u_addr.ip4.addr;
}
#if CONFIG_LWIP_IPV6
else if (ip_protocol == MDNS_IP_PROTOCOL_V6 && addr->type == ESP_IPADDR_TYPE_V6) {
#endif // CONFIG_LWIP_IPV4
#ifdef CONFIG_LWIP_IPV6
if (ip_protocol == MDNS_IP_PROTOCOL_V6 && addr->type == ESP_IPADDR_TYPE_V6) {
memset(in_addr, 0, sizeof(struct sockaddr_storage));
in_addr->ss_family = PF_INET6;
#if !defined(CONFIG_IDF_TARGET_LINUX)
@ -212,6 +216,7 @@ size_t _mdns_udp_pcb_write(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol, c
static inline void inet_to_espaddr(const struct sockaddr_storage *in_addr, esp_ip_addr_t *addr, uint16_t *port)
{
#ifdef CONFIG_LWIP_IPV4
if (in_addr->ss_family == PF_INET) {
struct sockaddr_in *in_addr_ip4 = (struct sockaddr_in *)in_addr;
memset(addr, 0, sizeof(esp_ip_addr_t));
@ -219,8 +224,9 @@ static inline void inet_to_espaddr(const struct sockaddr_storage *in_addr, esp_i
addr->u_addr.ip4.addr = in_addr_ip4->sin_addr.s_addr;
addr->type = ESP_IPADDR_TYPE_V4;
}
#if CONFIG_LWIP_IPV6
else if (in_addr->ss_family == PF_INET6) {
#endif /* CONFIG_LWIP_IPV4 */
#ifdef CONFIG_LWIP_IPV6
if (in_addr->ss_family == PF_INET6) {
struct sockaddr_in6 *in_addr_ip6 = (struct sockaddr_in6 *)in_addr;
memset(addr, 0, sizeof(esp_ip_addr_t));
*port = in_addr_ip6->sin6_port;
@ -346,17 +352,9 @@ static bool create_pcb(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol)
}
int sock = s_interfaces[tcpip_if].sock;
esp_netif_t *netif = _mdns_get_esp_netif(tcpip_if);
if (sock >= 0) {
mdns_ip_protocol_t other_ip_proto = ip_protocol == MDNS_IP_PROTOCOL_V4 ? MDNS_IP_PROTOCOL_V6 : MDNS_IP_PROTOCOL_V4;
int err = join_mdns_multicast_group(sock, netif, other_ip_proto);
if (err < 0) {
ESP_LOGE(TAG, "Failed to add ipv6 multicast group for protocol %d", ip_protocol);
return false;
}
s_interfaces[tcpip_if].proto |= (other_ip_proto == MDNS_IP_PROTOCOL_V4 ? PROTO_IPV4 : PROTO_IPV6);
return true;
if (sock < 0) {
sock = create_socket(netif);
}
sock = create_socket(netif);
if (sock < 0) {
ESP_LOGE(TAG, "Failed to create the socket!");
return false;
@ -383,7 +381,7 @@ esp_err_t _mdns_pcb_init(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol)
static int create_socket(esp_netif_t *netif)
{
#if CONFIG_LWIP_IPV6
#ifdef CONFIG_LWIP_IPV6
int sock = socket(PF_INET6, SOCK_DGRAM, 0);
#else
int sock = socket(PF_INET, SOCK_DGRAM, 0);
@ -398,7 +396,7 @@ static int create_socket(esp_netif_t *netif)
ESP_LOGE(TAG, "Failed setsockopt() to set SO_REUSEADDR. errno=%d: %s\n", errno, strerror(errno));
}
// Bind the socket to any address
#if CONFIG_LWIP_IPV6
#ifdef CONFIG_LWIP_IPV6
struct sockaddr_in6 saddr = { INADDR_ANY };
saddr.sin6_family = AF_INET6;
saddr.sin6_port = htons(5353);
@ -434,7 +432,7 @@ err:
return -1;
}
#if CONFIG_LWIP_IPV6
#ifdef CONFIG_LWIP_IPV6
static int socket_add_ipv6_multicast_group(int sock, esp_netif_t *netif)
{
int ifindex = esp_netif_get_netif_impl_index(netif);
@ -457,6 +455,7 @@ static int socket_add_ipv6_multicast_group(int sock, esp_netif_t *netif)
}
#endif // CONFIG_LWIP_IPV6
#ifdef CONFIG_LWIP_IPV4
static int socket_add_ipv4_multicast_group(int sock, esp_netif_t *netif)
{
struct ip_mreq imreq = { 0 };
@ -481,13 +480,16 @@ static int socket_add_ipv4_multicast_group(int sock, esp_netif_t *netif)
err:
return err;
}
#endif // CONFIG_LWIP_IPV4
static int join_mdns_multicast_group(int sock, esp_netif_t *netif, mdns_ip_protocol_t ip_protocol)
{
#ifdef CONFIG_LWIP_IPV4
if (ip_protocol == MDNS_IP_PROTOCOL_V4) {
return socket_add_ipv4_multicast_group(sock, netif);
}
#if CONFIG_LWIP_IPV6
#endif // CONFIG_LWIP_IPV4
#ifdef CONFIG_LWIP_IPV6
if (ip_protocol == MDNS_IP_PROTOCOL_V6) {
return socket_add_ipv6_multicast_group(sock, netif);
}

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -39,6 +39,14 @@
#define NETIF_IPV6_MAX_NUMS 3
#endif
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 1, 0)
/* CONFIG_LWIP_IPV4 was introduced in IDF v5.1 */
/* For IDF v5.0, set CONFIG_LWIP_IPV4 to 1 by default */
#ifndef CONFIG_LWIP_IPV4
#define CONFIG_LWIP_IPV4 1
#endif // CONFIG_LWIP_IPV4
#endif // ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 1, 0)
/** Number of configured interfaces */
#if MDNS_MAX_PREDEF_INTERFACES > CONFIG_MDNS_MAX_INTERFACES
#warning Number of configured interfaces is less then number of predefined interfaces. Please update CONFIG_MDNS_MAX_INTERFACES.

View File

@ -6,4 +6,10 @@ menu "LWIP-MOCK-CONFIG"
help
Enable/disable IPv6
config LWIP_IPV4
bool "Enable IPv4"
default y
help
Enable/disable IPv4
endmenu

View File

@ -120,6 +120,7 @@ Switching between manual modes
The diagram below depicts allowed transitions between manual CMUX modes
::
+------------------------------------
| |
+----------+ +-------------+ +------------+ +----------+
@ -187,8 +188,18 @@ Is defined using standard configuration structures for ``DTE`` and
Known issues
------------
There are certain issues, especially in using CMUX mode which you can
experience with some devices:
There are certain typical issues you might experience when working with esp_modem. This section elaborates on these problems and offers workarounds.
When using UART terminal, you might find running OTA over https quite unstable, exhibiting frequent UART buffer overflows.
The reason for that is that ESP32's UART is interrupt driven, so while performing computational extensive tasks with TLS session,
we need to timely interrupt to process incoming data. Here'are few suggestions to mitigate the impact:
* Move UART ISR to IRAM
* Increase internal UART rx buffer size
* Increase UART terminal task priority
* Use UART flow control
If none of the above helps, you can check the test ``target_ota``, which performs OTA in two steps -- first read the data, then pass the data to mbedTLS. See the test ``README.md`` for more details.
Potential issues when using CMUX mode and these devices:
1) Some modems (e.g. A76xx serries) use 2 bytes CMUX payload, which
might cause buffer overflow when trying to defragment the payload.

View File

@ -26,15 +26,17 @@ Create custom module
Creating a custom module is necessary if the application needs to use a specific device that is not supported
and their commands differ from any of the supported devices. In this case it is recommended to define a new class
representing this specific device and derive from the :cpp:class:`esp_modem::GenericModule`. In order to instantiate
the appropriate DCE of this module, application could use :ref:`the DCE factory<dce_factory>`, and build the DCE with
the specific module, using :cpp:func:`esp_modem::dce_factory::Factory::build`.
representing this specific device and derive from the :cpp:class:`esp_modem::GenericModule` (or any other available
module, that's close to your custom device). Then you can create the DCE using :ref:`the DCE factory<dce_factory>`
public method :cpp:func:`esp_modem::dce_factory::Factory::create_unique_dce_from`.
Please refer to the implementation of the existing modules.
Please note that the ``modem_console`` example defines a trivial custom modem DCE which overrides one command,
Please note that the ``pppos_client`` example defines a trivial custom DCE which overrides one command, and adds a new command
for demonstration purposes only.
It is also possible to create a specific DCE class that would conform to the generic ``DCE`` API and use all generic commands,
work with commands differently. This might be useful to add some custom preprocessing of commands or replies.
Please check the ``modem_console`` example with ``CONFIG_EXAMPLE_MODEM_DEVICE_SHINY=y`` configuration which demonstrates
overriding default ``command()`` method to implement URC processing in user space.
Create new communication interface
----------------------------------

8
docs/requirements.txt Normal file
View File

@ -0,0 +1,8 @@
sphinxcontrib-applehelp==1.0.4
sphinxcontrib_devhelp==1.0.2
sphinxcontrib-htmlhelp==2.0.1
sphinxcontrib-serializinghtml==1.1.5
sphinxcontrib-qthelp==1.0.3
breathe==4.35
recommonmark==0.7.1
esp-docs==1.7.1

22
examples/README.md Normal file
View File

@ -0,0 +1,22 @@
# Examples
## Overview
This directory showcases a variety of examples, illustrating the use of different interfaces and functionalities. Navigate through these examples to understand how to implement and integrate various components and features in your projects.
## Detailed Examples
1. **Multiple Network Interfaces Example**: Demonstrates the integration and management of multiple network interfaces.
Location: [multiple_netifs](esp_netif/multiple_netifs)
2. **SLIP Device Client**: Provides a detailed example of a SLIP (Serial Line Internet Protocol) device client implementation.
Location: [slip_custom_netif](esp_netif/slip_custom_netif/)
3. **MQTT Demo on Linux**: A comprehensive demonstration of an MQTT (Message Queuing Telemetry Transport) application designed to run on a Linux environment.
Location: [mqtt](mqtt)
## Additional Resources and Examples
For an extensive collection of additional examples, especially those related to specific components, please visit the upper layer directory and navigate to the respective component's example directory.
**Important**: To explore more, check the path: `components/*component_name/examples`

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -109,7 +109,11 @@ static esp_netif_t *get_netif_with_esp_index(int index)
{
esp_netif_t *netif = NULL;
int counter = 0;
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 0)
while ((netif = esp_netif_next_unsafe(netif)) != NULL) {
#else
while ((netif = esp_netif_next(netif)) != NULL) {
#endif
if (counter == index) {
return netif;
}
@ -124,7 +128,11 @@ static int get_esp_netif_index(esp_netif_t *esp_netif)
{
esp_netif_t *netif = NULL;
int counter = 0;
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 0)
while ((netif = esp_netif_next_unsafe(netif)) != NULL) {
#else
while ((netif = esp_netif_next(netif)) != NULL) {
#endif
if (esp_netif == netif) {
return counter;
}