mirror of
https://github.com/espressif/esp-protocols.git
synced 2025-07-27 09:17:29 +02:00
Compare commits
50 Commits
console_cm
...
mdns-v1.2.
Author | SHA1 | Date | |
---|---|---|---|
96f4ebd994 | |||
247ca41bb7 | |||
891384cc53 | |||
38ef603296 | |||
312982e4aa | |||
d9d377133e | |||
110536ebb2 | |||
5ba7cfab8e | |||
2f7c58259d | |||
f42c0adfc0 | |||
2782277f3f | |||
3225f40c22 | |||
d63f831fff | |||
f62db5cfa2 | |||
68ce794098 | |||
60174f290e | |||
efa26b7062 | |||
7b777948fc | |||
1dc4299eb0 | |||
ce7daddc77 | |||
09e68cc0c0 | |||
fc59f87c4e | |||
7a2b23909f | |||
d3bf773445 | |||
1c29af9237 | |||
b53981a68c | |||
5000a9a20a | |||
2646dcd23a | |||
de8ec67a88 | |||
8dac30781c | |||
ba3f06f942 | |||
a10f0008fb | |||
741d166034 | |||
93d140875f | |||
eb7699388c | |||
585e4b30b2 | |||
aa4e9d5795 | |||
6d2c475c20 | |||
47736a2556 | |||
adde6df6e8 | |||
1393764dc5 | |||
0998f3dd4f | |||
577de67c0e | |||
ae38110d84 | |||
5ab699d6f4 | |||
976e98d6ff | |||
18b2ae103a | |||
52a34c21d0 | |||
9df86641f3 | |||
75af01670e |
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 }}
|
||||
|
4
.github/workflows/mqtt_cxx__build.yml
vendored
4
.github/workflows/mqtt_cxx__build.yml
vendored
@ -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
|
||||
|
2
.github/workflows/publish-docs-component.yml
vendored
2
.github/workflows/publish-docs-component.yml
vendored
@ -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}
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
/**
|
||||
|
@ -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)
|
||||
*/
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
47
components/esp_modem/test/README.md
Normal file
47
components/esp_modem/test/README.md
Normal 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
|
@ -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
|
||||
|
10
components/esp_modem/test/target_iperf/CMakeLists.txt
Normal file
10
components/esp_modem/test/target_iperf/CMakeLists.txt
Normal 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)
|
48
components/esp_modem/test/target_iperf/README.md
Normal file
48
components/esp_modem/test/target_iperf/README.md
Normal 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
|
||||
```
|
@ -0,0 +1,3 @@
|
||||
idf_component_register(SRCS "NetworkDCE.cpp"
|
||||
"cmd_pppclient.c"
|
||||
"pppd_iperf_main.c")
|
96
components/esp_modem/test/target_iperf/main/NetworkDCE.cpp
Normal file
96
components/esp_modem/test/target_iperf/main/NetworkDCE.cpp
Normal 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();
|
||||
}
|
289
components/esp_modem/test/target_iperf/main/cmd_pppclient.c
Normal file
289
components/esp_modem/test/target_iperf/main/cmd_pppclient.c
Normal 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));
|
||||
}
|
26
components/esp_modem/test/target_iperf/main/network_dce.h
Normal file
26
components/esp_modem/test/target_iperf/main/network_dce.h
Normal 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();
|
@ -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));
|
||||
}
|
112
components/esp_modem/test/target_iperf/pytest_ppp_iperf.py
Normal file
112
components/esp_modem/test/target_iperf/pytest_ppp_iperf.py
Normal 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()))
|
@ -0,0 +1,3 @@
|
||||
CONFIG_COMPILER_CXX_EXCEPTIONS=y
|
||||
CONFIG_LWIP_PPP_SUPPORT=y
|
||||
CONFIG_ESP_MAIN_TASK_STACK_SIZE=4096
|
@ -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();
|
||||
}
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
35
components/esp_websocket_client/examples/linux/README.md
Normal file
35
components/esp_websocket_client/examples/linux/README.md
Normal 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`):
|
@ -1,3 +1,4 @@
|
||||
dependencies:
|
||||
idf: ">5.2"
|
||||
protocol_examples_common:
|
||||
path: ${IDF_PATH}/examples/common_components/protocol_examples_common
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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"
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
@ -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
|
@ -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:
|
||||
|
@ -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
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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
8
docs/requirements.txt
Normal 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
22
examples/README.md
Normal 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`
|
@ -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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user