Compare commits

...

57 Commits

Author SHA1 Message Date
5d69d3f0ac Merge pull request #588 from gabsuren/mdns_v1.3.2
bump(mdns): 1.3.1 -> 1.3.2
2024-06-05 12:58:45 +04:00
39d59032a2 Merge pull request #582 from david-cermak/fix/wifi_remote_server_sync
[wifi-remote]: Fix server race when receiving command and posting events
2024-06-05 08:14:19 +02:00
e3418b5527 bump(wifi_remote): 0.2.2 -> 0.2.3
0.2.3
Bug Fixes
- Fix server event/command race condtion using eventfd (732b1d5)
- Lock server before marshalling events (9e13870)
2024-06-05 07:27:12 +02:00
21d1540b76 bump(mdns): 1.3.1 -> 1.3.2
1.3.2
Features
- add check of instance when handling PTR query (6af6ca5)
Bug Fixes
- Fix of mdns afl tests (139166c)
- remove same protocol services with different instances (042533a)
2024-06-04 16:43:44 +04:00
186e258798 Merge pull request #587 from gabsuren/fix_mdns_config
fix(mdns): Fix of mdns afl tests
2024-06-04 16:41:52 +04:00
139166c2c5 fix(mdns): Fix of mdns afl tests 2024-06-04 10:23:27 +04:00
7437d31368 Merge pull request #574 from DejinChen/fix/remove_same_protocol_service
fix(mdns): remove same protocol services with different instances
2024-06-03 14:26:40 +04:00
d20255a40c Merge pull request #559 from gytxxsy/feature/add_instance_check_for_existing_answer
feat(mdns): add check of instance when handling PTR query (IDFGH-12701)
2024-06-03 14:24:54 +04:00
6af6ca52a2 feat(mdns): add check of instance when handling PTR query 2024-05-31 17:29:14 +08:00
042533af90 fix(mdns): remove same protocol services with different instances 2024-05-31 16:37:22 +08:00
732b1d5084 fix(wifi_remote): Fix server event/command race condtion using eventfd 2024-05-31 07:47:37 +02:00
9e13870ad4 fix(wifi_remote): Lock server before marshalling events 2024-05-30 15:40:26 +02:00
3f12ef6eea Merge pull request #580 from david-cermak/fix/ci_build_jobs
ci(common): Fix build jobs to install only idf-build-apps in idf cotainer
2024-05-28 17:39:25 +02:00
f1bc070b86 Merge pull request #579 from david-cermak/fix/wifi_remote_netif_example_sta
[wifi-remote]: Pass more netif options to eppp
2024-05-28 17:39:01 +02:00
28c0e0b77b bump(wifi_remote): 0.2.1 -> 0.2.2
0.2.2
Bug Fixes
- Added more netif options for eppp connection (24ce867)
- Do not restrict EPPP config to RSA keys only (f05c765, #570)
2024-05-28 16:37:24 +02:00
24ce86756d fix(wifi_remote): Added more netif options for eppp connection
Configurable in Kconfig:
* routing priority
* netif description
2024-05-28 16:36:16 +02:00
39dfe268a3 Merge pull request #578 from david-cermak/fix/eppp_netif_config
[eppp]: Make some common esp_netif options configurable
2024-05-28 16:34:33 +02:00
d96f45a1f9 bump(eppp): 0.1.0 -> 0.1.1
0.1.1
Bug Fixes
- Make some common netif options configurable (7829e8f)
2024-05-28 16:11:19 +02:00
90fdcfc340 fix(eppp): Add build test for IDF v5.3, fix idf-build-apps deps 2024-05-28 16:10:19 +02:00
7829e8f976 fix(eppp): Make some common netif options configurable 2024-05-28 16:10:19 +02:00
ce27c13352 ci(console): Ignore latest ethernet deprecation warning 2024-05-28 14:57:17 +02:00
eab58de630 ci(common): Fix build jobs to install only idf-build-apps in idf container 2024-05-28 14:40:46 +02:00
fcb60806a9 Merge pull request #575 from david-cermak/fix/wifi_remote_keys
fix(wifi_remote): Do not restrict EPPP config to RSA keys only
2024-05-28 08:52:04 +02:00
22914d4b7b fix(wifi_remote): Fix build test to download only idf-build-apps deps 2024-05-27 17:18:27 +02:00
150a3ec06a Merge pull request #577 from david-cermak/fix/clang_tidy_deps
CI: Fixed clang-tidy job
2024-05-23 17:48:53 +02:00
c12616c91d ci: remove libtinfo5 installation step 2024-05-23 17:25:52 +02:00
f05c765e8b fix(wifi_remote): Do not restrict EPPP config to RSA keys only
Now we can use any kind of certificate and keys, as long as they're in
PEM format.

Closes https://github.com/espressif/esp-protocols/issues/570
2024-05-20 15:13:16 +02:00
ed021a90d4 Merge pull request #550 from gabsuren/fix_websokcet_params
fix(websocket): Fix locking issues of `esp_websocket_client_send_with_exact_opcode` IDF-9380
2024-05-17 13:20:23 +04:00
6393fcd79a fix(websocket): Fix locking issues of esp_websocket_client_send_with_exact_opcode API
Extended examples to cover more cases
Added new config CONFIG_ESP_WS_CLIENT_ENABLE_DYNAMIC_BUFFER for testing
2024-05-17 12:37:10 +04:00
c9439bd3d5 Merge pull request #571 from gabsuren/mdns_v1.3.1_
bump(mdns): 1.3.0 -> 1.3.1
2024-05-14 16:23:35 +04:00
2c4c88b4fb bump(mdns): 1.3.0 -> 1.3.1
1.3.1
Bug Fixes
- free txt value len (afd98bb)
2024-05-14 15:00:27 +04:00
d45c5cef9a Merge pull request #569 from DejinChen/fix/free_txt_value_len
fix(mdns): free txt value len (IDFGH-12817)
2024-05-14 14:58:31 +04:00
afd98bb9c5 fix(mdns): free txt value len 2024-05-10 17:44:48 +08:00
8f19c60c19 Merge pull request #567 from gabsuren/CI/idf_5.3
ci(common): added idf release-v5.2, release-v5.3 targets(IDF-9875)
2024-05-09 22:40:16 +04:00
281e933808 ci(common): added idf release-v5.2, release-v5.3 targets 2024-05-09 20:56:02 +04:00
f4bdf0ab6c Merge pull request #545 from david-cermak/feat/clang_tidy_check
ci(common): Add clang tidy check to esp-protocols
2024-05-09 14:56:01 +02:00
e25b2a1d9d Merge pull request #568 from david-cermak/bump/wifi_remote_with_eppp
[wifi-remote]: Updated eppp dependency and more WiFi functions
2024-05-07 22:53:39 +02:00
608b835680 bump(wifi_remote): 0.2.0 -> 0.2.1
0.2.1
Bug Fixes
- Added misc wifi API in eppp impl (93256d1)
- Updated eppp dependency not to use fixed version (3a48c06)
2024-05-07 20:06:43 +02:00
93256d159b fix(wifi_remote): Added misc wifi API in eppp impl
Adds missing implementation of:
* esp_wifi_deinit()
* esp_wifi_disconnect()
* esp_wifi_set_storage()
2024-05-07 20:06:24 +02:00
3a48c06e96 fix(wifi_remote): Updated eppp dependency not to use fixed version 2024-05-07 20:06:19 +02:00
e011188377 Merge pull request #566 from david-cermak/feat/eppp_force_lwip_opts
[eppp]: Force the `PPP` LWIP opts which are OFF by default
2024-05-07 19:48:18 +02:00
1fb1ea9300 bump(eppp): 0.0.1 -> 0.1.0
0.1.0
Features
- Added CI job to build examples and tests (7eefcf0)
Bug Fixes
- Fixed to select PPP LWIP opts which are OFF by default (16be2f9)
- Example to use iperf component from the registry (bd6b66d)
- Fixed defalt config designated init issue in C++ (8bd4712)
2024-05-07 10:32:55 +02:00
16be2f963b fix(eppp): Fixed to select PPP LWIP opts which are OFF by default 2024-05-07 10:30:43 +02:00
d786f0db88 Merge pull request #555 from gabsuren/websocket_keep_alirve
feat(websocket): adding support for `keep_alive_enable` when using WSS transport (IDFGH-11457)
2024-05-03 14:49:42 +04:00
f6f6ded001 Merge pull request #560 from david-cermak/fix/ci_build_v5.3
Fix CI build per IDFv5.3
2024-05-03 12:44:25 +02:00
eb84eed8d3 ci(common): Add clang tidy check to esp-protocols 2024-04-26 12:39:52 +02:00
5df46437f2 fix(console): Ignore eth_init hidden config warning 2024-04-26 11:57:06 +02:00
bd6b66d9d1 fix(eppp): Example to use iperf component from the registry 2024-04-26 11:32:46 +02:00
d0c17ef0d5 fix(modem): Fix CI build per IDFv5.3 2024-04-26 11:25:30 +02:00
06d013b20b Merge pull request #557 from euripedesrocha/fix_lastwill
Adds missing configuration fields
2024-04-26 02:50:23 -03:00
f032a9f023 Merge pull request #538 from david-cermak/feat/wifi_remote_example
[wifi remote]: Add example without `esp_hosted`
2024-04-25 16:03:15 +02:00
d16387859f bump(wifi_remote): 0.1.12 -> 0.2.0
0.2.0
Features
- Add support for simple eppp based RPC (fd168d8)
Bug Fixes
- Make services restartable, code cleanup (6c82ce2)
- Add examples to CI (d2b7c55)
2024-04-25 15:13:49 +02:00
6c82ce2915 fix(wifi_remote): Make services restartable, code cleanup 2024-04-25 15:11:17 +02:00
d2b7c55b89 fix(wifi_remote): Add examples to CI 2024-04-25 15:11:17 +02:00
fd168d86fc feat(wifi_remote): Add support for simple eppp based RPC 2024-04-25 15:11:09 +02:00
d4c6d5ed5d fix(mqtt_cxx): Adds missing configuration fields
Some aspects of the underlying mqtt client were not set.

Fix #554
2024-04-22 12:30:20 +02:00
c728eae5ea feat(websocket): adding support for keep_alive_enable when using WSS transport 2024-04-22 10:57:36 +04:00
84 changed files with 2125 additions and 252 deletions

View File

@ -13,7 +13,7 @@ jobs:
name: Build
strategy:
matrix:
idf_ver: ["latest", "release-v5.0", "release-v5.1"]
idf_ver: ["latest", "release-v5.0", "release-v5.1", "release-v5.2", "release-v5.3"]
idf_target: ["esp32", "esp32s2"]
example: ["asio_chat", "async_request", "socks4", "ssl_client_server", "tcp_echo_server", "udp_echo_server"]
runs-on: ubuntu-22.04
@ -64,7 +64,7 @@ jobs:
name: Target tests
strategy:
matrix:
idf_ver: ["latest", "release-v5.0"]
idf_ver: ["latest", "release-v5.0", "release-v5.2", "release-v5.3"]
idf_target: ["esp32"]
example: ["asio_chat", "tcp_echo_server", "udp_echo_server", "ssl_client_server"]
needs: build_asio

55
.github/workflows/clang-tidy.yml vendored Normal file
View File

@ -0,0 +1,55 @@
name: Run clang-tidy
on:
pull_request:
push:
branches:
- master
jobs:
build:
name: Run clang-tidy
runs-on: ubuntu-20.04
container: espressif/idf:latest
steps:
- uses: actions/checkout@v3
with:
submodules: 'true'
- name: Install esp-clang
run: |
${IDF_PATH}/tools/idf_tools.py --non-interactive install esp-clang
- name: Install clang-tidy-sarif
run: |
curl -sSL https://github.com/psastras/sarif-rs/releases/download/clang-tidy-sarif-v0.3.3/clang-tidy-sarif-x86_64-unknown-linux-gnu -o clang-tidy-sarif
chmod +x clang-tidy-sarif
curl -sSL https://raw.githubusercontent.com/espressif/idf-extra-components/master/.github/filter_sarif.py -o filter_sarif.py
- name: Install pyclang
run: |
. ${IDF_PATH}/export.sh
pip install pyclang~=0.2.0
- name: Run code analysis
shell: bash
env:
IDF_TOOLCHAIN: clang
IDF_TARGET: esp32
working-directory: test_app
run: |
. ${IDF_PATH}/export.sh
idf.py clang-check --include-paths $GITHUB_WORKSPACE --exclude-paths $PWD --run-clang-tidy-py run-clang-tidy
cp warnings.txt ../
- name: Convert clang-tidy results into SARIF output
run: |
export PATH=$PWD:$PATH
./clang-tidy-sarif -o results.sarif.raw warnings.txt
python3 filter_sarif.py -o results.sarif --include-prefix ${GITHUB_WORKSPACE}/ results.sarif.raw
- uses: actions/upload-artifact@v2
with:
path: |
warnings.txt
results.sarif
results.sarif.raw
- name: Upload SARIF file
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: results.sarif
category: clang-tidy

View File

@ -13,9 +13,13 @@ jobs:
name: Build
strategy:
matrix:
idf_ver: ["latest", "release-v5.0"]
idf_ver: ["latest", "release-v5.0", "release-v5.1", "release-v5.2", "release-v5.3"]
idf_target: ["esp32"]
test: [ { app: ifconfig-basic, path: "components/console_cmd_ifconfig/examples"}]
include:
- idf_ver: "latest"
warning: "the choice symbol ETHERNET_PHY_LAN867X\nis deprecated: Please use smi_gpio instead"
runs-on: ubuntu-22.04
container: espressif/idf:${{ matrix.idf_ver }}
steps:
@ -24,9 +28,11 @@ jobs:
with:
submodules: recursive
- name: Build ${{ matrix.test.app }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
env:
EXPECTED_WARNING: ${{ matrix.warning }}
shell: bash
working-directory: ${{matrix.test.path}}
run: |
${IDF_PATH}/install.sh --enable-pytest
. ${IDF_PATH}/export.sh
pip install idf-component-manager idf-build-apps --upgrade
python ../../../ci/build_apps.py ./${{ matrix.test.app }} --target ${{ matrix.idf_target }} -vv --preserve-all --pytest-app

View File

@ -13,7 +13,7 @@ jobs:
name: Build
strategy:
matrix:
idf_ver: ["latest", "release-v5.0"]
idf_ver: ["latest", "release-v5.0", "release-v5.1", "release-v5.2", "release-v5.3"]
idf_target: ["esp32"]
test: [ { app: ping-basic, path: "components/console_cmd_ping/examples" }]
runs-on: ubuntu-22.04
@ -27,6 +27,6 @@ jobs:
shell: bash
working-directory: ${{matrix.test.path}}
run: |
${IDF_PATH}/install.sh --enable-pytest
. ${IDF_PATH}/export.sh
pip install idf-component-manager idf-build-apps --upgrade
python ../../../ci/build_apps.py ./${{ matrix.test.app }} --target ${{ matrix.idf_target }} -vv --preserve-all --pytest-app

View File

@ -13,7 +13,7 @@ jobs:
name: Build
strategy:
matrix:
idf_ver: ["latest", "release-v5.0"]
idf_ver: ["latest", "release-v5.0", "release-v5.1", "release-v5.2", "release-v5.3"]
idf_target: ["esp32"]
test: [ { app: wifi-basic, path: "components/console_cmd_wifi/examples" }]
runs-on: ubuntu-22.04
@ -27,6 +27,6 @@ jobs:
shell: bash
working-directory: ${{matrix.test.path}}
run: |
${IDF_PATH}/install.sh --enable-pytest
. ${IDF_PATH}/export.sh
pip install idf-component-manager idf-build-apps --upgrade
python ../../../ci/build_apps.py ./${{ matrix.test.app }} --target ${{ matrix.idf_target }} -vv --preserve-all --pytest-app

View File

@ -13,7 +13,7 @@ jobs:
name: Build
strategy:
matrix:
idf_ver: ["latest", "release-v5.0"]
idf_ver: ["latest", "release-v5.0", "release-v5.1", "release-v5.2", "release-v5.3"]
idf_target: ["esp32"]
test: [ { app: console_basic, path: "components/console_simple_init/examples" }]
runs-on: ubuntu-22.04
@ -27,6 +27,6 @@ jobs:
shell: bash
working-directory: ${{matrix.test.path}}
run: |
${IDF_PATH}/install.sh --enable-pytest
. ${IDF_PATH}/export.sh
pip install idf-component-manager idf-build-apps --upgrade
python ../../../ci/build_apps.py ./${{ matrix.test.app }} --target ${{ matrix.idf_target }} -vv --preserve-all --pytest-app

View File

@ -13,7 +13,7 @@ jobs:
name: Build
strategy:
matrix:
idf_ver: ["latest"]
idf_ver: ["latest", "release-v5.3"]
test: [ { app: host, path: "examples/host" }, { app: slave, path: "examples/slave" }, { app: test_app, path: "test/test_app" }]
runs-on: ubuntu-20.04
container: espressif/idf:${{ matrix.idf_ver }}
@ -23,6 +23,6 @@ jobs:
- name: Build ${{ matrix.test.app }} with IDF-${{ matrix.idf_ver }}
shell: bash
run: |
${IDF_PATH}/install.sh --enable-pytest
. ${IDF_PATH}/export.sh
pip install idf-component-manager idf-build-apps --upgrade
python ./ci/build_apps.py ./components/eppp_link/${{matrix.test.path}} -vv --preserve-all

View File

@ -13,7 +13,7 @@ jobs:
name: Build examples
strategy:
matrix:
idf_ver: ["latest", "release-v5.1"]
idf_ver: ["latest", "release-v5.1", "release-v5.2", "release-v5.3"]
runs-on: ubuntu-22.04
container: espressif/idf:${{ matrix.idf_ver }}
steps:

View File

@ -13,7 +13,7 @@ jobs:
name: Build
strategy:
matrix:
idf_ver: ["latest", "release-v5.0"]
idf_ver: ["latest", "release-v5.0", "release-v5.2", "release-v5.3"]
test: [ { app: example, path: "examples/query_advertise" }, { app: unit_test, path: "tests/unit_test" }, { app: test_app, path: "tests/test_apps" } ]
runs-on: ubuntu-22.04
container: espressif/idf:${{ matrix.idf_ver }}

View File

@ -13,16 +13,12 @@ jobs:
name: Build examples
strategy:
matrix:
idf_ver: ["latest", "release-v4.3", "release-v4.4", "release-v5.0"]
idf_ver: ["latest", "release-v4.4", "release-v5.0", "release-v5.1", "release-v5.2", "release-v5.3"]
example: ["pppos_client", "modem_console", "modem_tcp_client", "ap_to_pppos", "simple_cmux_client"]
exclude:
- idf_ver: "release-v4.3"
example: modem_tcp_client
- idf_ver: "release-v4.4"
example: modem_tcp_client
include:
- idf_ver: "release-v4.3"
skip_config: usb
- idf_ver: "release-v5.0"
example: "simple_cmux_client"
warning: "Warning: The smallest app partition is nearly full"
@ -57,7 +53,7 @@ jobs:
name: Build tests
strategy:
matrix:
idf_ver: ["release-v5.0", "release-v5.1", "latest"]
idf_ver: ["release-v5.0", "release-v5.1", "release-v5.2", "release-v5.3", "latest"]
test: ["target", "target_ota", "target_iperf"]
runs-on: ubuntu-22.04

View File

@ -13,7 +13,7 @@ jobs:
name: Build
strategy:
matrix:
idf_ver: ["latest", "release-v5.0"]
idf_ver: ["latest", "release-v5.0", "release-v5.1", "release-v5.2", "release-v5.3"]
idf_target: ["esp32"]
test: [ { app: mqtt-basic, path: "components/esp_mqtt_cxx/examples" }]
runs-on: ubuntu-22.04
@ -27,6 +27,6 @@ jobs:
shell: bash
working-directory: ${{matrix.test.path}}
run: |
${IDF_PATH}/install.sh --enable-pytest
. ${IDF_PATH}/export.sh
pip install idf-component-manager idf-build-apps --upgrade
python ../../../ci/build_apps.py ./${{ matrix.test.app }} --target ${{ matrix.idf_target }} -vv --preserve-all --pytest-app

View File

@ -13,7 +13,7 @@ jobs:
name: Build
strategy:
matrix:
idf_ver: ["latest", "release-v5.2", "release-v5.1"]
idf_ver: ["latest", "release-v5.3", "release-v5.2", "release-v5.1"]
test: [ { app: client, path: "examples/tls_client" }, { app: udp, path: "examples/udp_mutual_auth" }, { app: test, path: "tests/uart_mutual_auth" } ]
runs-on: ubuntu-20.04
container: espressif/idf:${{ matrix.idf_ver }}
@ -25,6 +25,6 @@ jobs:
- name: Build ${{ matrix.test.app }} with IDF-${{ matrix.idf_ver }}
shell: bash
run: |
${IDF_PATH}/install.sh --enable-pytest
. ${IDF_PATH}/export.sh
pip install idf-component-manager idf-build-apps --upgrade
python ./ci/build_apps.py ./components/mbedtls_cxx/${{ matrix.test.path }} -vv --preserve-all

View File

@ -13,7 +13,7 @@ jobs:
name: Build
strategy:
matrix:
idf_ver: ["release-v5.0", "release-v5.1", "latest"]
idf_ver: ["release-v5.0", "release-v5.1", "release-v5.2", "release-v5.3", "latest"]
test: [ { app: example, path: "examples/target" }, { app: unit_test, path: "test" } ]
runs-on: ubuntu-22.04
container: espressif/idf:${{ matrix.idf_ver }}
@ -51,7 +51,7 @@ jobs:
strategy:
fail-fast: false
matrix:
idf_ver: ["release-v5.0", "release-v5.1", "latest"]
idf_ver: ["release-v5.0", "release-v5.1", "release-v5.2", "release-v5.3", "latest"]
idf_target: ["esp32"]
test: [ { app: example, path: "examples/target" }, { app: unit_test, path: "test" } ]
runs-on:

View File

@ -22,14 +22,14 @@ jobs:
- name: Check that headers are the same as generated
shell: bash
run: |
${IDF_PATH}/install.sh --enable-pytest
. ${IDF_PATH}/export.sh
pip install idf-component-manager idf-build-apps --upgrade
cd ./components/esp_wifi_remote/scripts
python generate_and_check.py
build_wifi_remote:
if: contains(github.event.pull_request.labels.*.name, 'wifi_remote') || github.event_name == 'push'
name: Build WiFi Remote
name: Build WiFi Remote Test
strategy:
matrix:
idf_ver: ["latest"]
@ -46,6 +46,32 @@ jobs:
- name: Build ${{ matrix.test.app }} with IDF-${{ matrix.idf_ver }}
shell: bash
run: |
${IDF_PATH}/install.sh --enable-pytest
. ${IDF_PATH}/export.sh
pip install idf-component-manager idf-build-apps --upgrade
python ./ci/build_apps.py ./components/esp_wifi_remote/${{matrix.test.path}} -vv --preserve-all
build_wifi_remote_example:
if: contains(github.event.pull_request.labels.*.name, 'wifi_remote') || github.event_name == 'push'
name: Build WiFi Remote Example
strategy:
matrix:
idf_ver: ["latest"]
example: [ { app: host, path: "examples/mqtt" }, { app: slave, path: "examples/server" }]
include:
- idf_ver: "latest"
example: { app: slave, path: "examples/server" }
warning: "Warning: The smallest app partition is nearly full"
runs-on: ubuntu-20.04
container: espressif/idf:${{ matrix.idf_ver }}
steps:
- name: Checkout esp-protocols
uses: actions/checkout@v3
- name: Build ${{ matrix.example.app }} with IDF-${{ matrix.idf_ver }}
env:
EXPECTED_WARNING: ${{ matrix.warning }}
shell: bash
run: |
. ${IDF_PATH}/export.sh
pip install idf-component-manager idf-build-apps --upgrade
python ./ci/build_apps.py ./components/esp_wifi_remote/${{matrix.example.path}} -vv --preserve-all

View File

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

View File

@ -1,5 +1,23 @@
# Changelog
## [0.1.1](https://github.com/espressif/esp-protocols/commits/eppp-v0.1.1)
### Bug Fixes
- Make some common netif options configurable ([7829e8f](https://github.com/espressif/esp-protocols/commit/7829e8f))
## [0.1.0](https://github.com/espressif/esp-protocols/commits/eppp-v0.1.0)
### Features
- Added CI job to build examples and tests ([7eefcf0](https://github.com/espressif/esp-protocols/commit/7eefcf0))
### Bug Fixes
- Fixed to select PPP LWIP opts which are OFF by default ([16be2f9](https://github.com/espressif/esp-protocols/commit/16be2f9))
- Example to use iperf component from the registry ([bd6b66d](https://github.com/espressif/esp-protocols/commit/bd6b66d))
- Fixed defalt config designated init issue in C++ ([8bd4712](https://github.com/espressif/esp-protocols/commit/8bd4712))
## [0.0.1](https://github.com/espressif/esp-protocols/commits/eppp-v0.0.1)
### Features

View File

@ -1,5 +1,11 @@
menu "eppp_link"
config EPPP_LINK_USES_LWIP
bool
default "y"
select LWIP_PPP_SUPPORT
select LWIP_PPP_SERVER_SUPPORT
choice EPPP_LINK_DEVICE
prompt "Choose PPP device"
default EPPP_LINK_DEVICE_UART

View File

@ -157,7 +157,7 @@ static void netif_deinit(esp_netif_t *netif)
}
}
static esp_netif_t *netif_init(eppp_type_t role)
static esp_netif_t *netif_init(eppp_type_t role, eppp_config_t *eppp_config)
{
if (s_eppp_netif_count > 9) { // Limit to max 10 netifs, since we use "EPPPx" as the unique key (where x is 0-9)
ESP_LOGE(TAG, "Cannot create more than 10 instances");
@ -217,10 +217,13 @@ static esp_netif_t *netif_init(eppp_type_t role)
char if_key[] = "EPPP0"; // netif key needs to be unique
if_key[sizeof(if_key) - 2 /* 2 = two chars before the terminator */ ] += s_eppp_netif_count++;
base_netif_cfg.if_key = if_key;
if (role == EPPP_CLIENT) {
base_netif_cfg.if_desc = "pppos_client";
if (eppp_config->ppp.netif_description) {
base_netif_cfg.if_desc = eppp_config->ppp.netif_description;
} else {
base_netif_cfg.if_desc = "pppos_server";
base_netif_cfg.if_desc = role == EPPP_CLIENT ? "pppos_client" : "pppos_server";
}
if (eppp_config->ppp.netif_prio) {
base_netif_cfg.route_prio = eppp_config->ppp.netif_prio;
}
esp_netif_config_t netif_ppp_config = { .base = &base_netif_cfg,
.driver = ppp_driver_cfg,
@ -703,7 +706,12 @@ void eppp_deinit(esp_netif_t *netif)
esp_netif_t *eppp_init(eppp_type_t role, eppp_config_t *config)
{
esp_netif_t *netif = netif_init(role);
if (config == NULL || (role != EPPP_SERVER && role != EPPP_CLIENT)) {
ESP_LOGE(TAG, "Invalid configuration or role");
return NULL;
}
esp_netif_t *netif = netif_init(role, config);
if (!netif) {
ESP_LOGE(TAG, "Failed to initialize PPP netif");
remove_handlers();
@ -730,6 +738,10 @@ esp_netif_t *eppp_init(eppp_type_t role, eppp_config_t *config)
esp_netif_t *eppp_open(eppp_type_t role, eppp_config_t *config, int connect_timeout_ms)
{
if (config == NULL || (role != EPPP_SERVER && role != EPPP_CLIENT)) {
ESP_LOGE(TAG, "Invalid configuration or role");
return NULL;
}
#if CONFIG_EPPP_LINK_DEVICE_UART
if (config->transport != EPPP_TRANSPORT_UART) {
ESP_LOGE(TAG, "Invalid transport: UART device must be enabled in Kconfig");

View File

@ -1,7 +1,6 @@
# The following four lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/iperf)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)

View File

@ -1,4 +1,5 @@
dependencies:
espressif/iperf-cmd: "^0.1.1"
espressif/eppp_link:
version: "*"
override_path: "../../.."

View File

@ -1,4 +1,4 @@
version: 0.0.1
version: 0.1.1
url: https://github.com/espressif/esp-protocols/tree/master/components/eppp_link
description: The component provides a general purpose PPP connectivity, typically used as WiFi-PPP router
dependencies:

View File

@ -37,6 +37,8 @@
. ppp = { \
.our_ip4_addr = { .addr = our_ip }, \
.their_ip4_addr = { .addr = their_ip }, \
.netif_prio = 0, \
.netif_description = NULL, \
} \
}
@ -88,6 +90,8 @@ typedef struct eppp_config_t {
struct eppp_config_pppos_s {
esp_ip4_addr_t our_ip4_addr;
esp_ip4_addr_t their_ip4_addr;
int netif_prio;
const char *netif_description;
} ppp;
} eppp_config_t;

View File

@ -1,6 +1,6 @@
components/esp_modem/examples/ap_to_pppos:
disable:
- if: IDF_TARGET in ["esp32h2"]
- if: IDF_TARGET in ["esp32h2", "esp32p4"]
components/esp_modem/examples/modem_console:
disable:

View File

@ -2,9 +2,5 @@
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/system/console/advanced/components
$ENV{IDF_PATH}/examples/common_components/iperf
"../..")
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(pppd_test)

View File

@ -0,0 +1,6 @@
## IDF Component Manager Manifest File
dependencies:
espressif/esp_modem:
version: "^1.1.0"
override_path: "../../.."
espressif/iperf-cmd: "^0.1.1"

View File

@ -8,7 +8,6 @@
#include "sdkconfig.h"
#include "esp_log.h"
#include "esp_console.h"
#include "cmd_system.h"
void register_pppd(void);
@ -22,7 +21,6 @@ void app_main(void)
ESP_ERROR_CHECK(esp_console_new_repl_uart(&uart_config, &repl_config, &repl));
/* Register commands */
register_system_common();
register_pppd();
printf("\n =======================================================\n");

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -7,12 +7,12 @@
#include <string>
#include <algorithm>
#include <stdexcept>
#include <variant>
#include "mqtt_client.h"
#include "esp_log.h"
#include "esp_mqtt.hpp"
#include "esp_mqtt_client_config.hpp"
namespace {
@ -133,6 +133,22 @@ esp_mqtt_client_config_t make_config(BrokerConfiguration const &broker, ClientCr
esp_mqtt_client_config_t mqtt_client_cfg{};
config_broker(mqtt_client_cfg, broker);
config_client_credentials(mqtt_client_cfg, credentials);
mqtt_client_cfg.session.keepalive = config.session.keepalive;
mqtt_client_cfg.session.last_will.msg = config.session.last_will.lwt_msg;
mqtt_client_cfg.session.last_will.topic = config.session.last_will.lwt_topic;
mqtt_client_cfg.session.last_will.msg_len = config.session.last_will.lwt_msg_len;
mqtt_client_cfg.session.last_will.qos = config.session.last_will.lwt_qos;
mqtt_client_cfg.session.last_will.retain = config.session.last_will.lwt_retain;
mqtt_client_cfg.session.protocol_ver = config.session.protocol_ver;
mqtt_client_cfg.session.disable_keepalive = config.session.disable_keepalive;
mqtt_client_cfg.network.reconnect_timeout_ms = config.connection.reconnect_timeout_ms;
mqtt_client_cfg.network.timeout_ms = config.connection.network_timeout_ms;
mqtt_client_cfg.network.disable_auto_reconnect = config.connection.disable_auto_reconnect;
mqtt_client_cfg.network.refresh_connection_after_ms = config.connection.refresh_connection_after_ms;
mqtt_client_cfg.task.priority = config.task.task_prio;
mqtt_client_cfg.task.stack_size = config.task.task_stack;
mqtt_client_cfg.buffer.size = config.buffer_size;
mqtt_client_cfg.buffer.out_size = config.out_buffer_size;
return mqtt_client_cfg;
}
}
@ -150,7 +166,6 @@ Client::Client(esp_mqtt_client_config_t const &config) : handler(esp_mqtt_clien
CHECK_THROW_SPECIFIC(esp_mqtt_client_start(handler.get()), mqtt::MQTTException);
}
void Client::mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) noexcept
{
ESP_LOGD(TAG, "Event dispatched from event loop base=%s, event_id=%" PRIu32, base, event_id);

View File

@ -497,6 +497,9 @@ static esp_err_t esp_websocket_client_create_transport(esp_websocket_client_hand
esp_transport_set_default_port(ssl, WEBSOCKET_SSL_DEFAULT_PORT);
esp_transport_list_add(client->transport_list, ssl, "_ssl"); // need to save to transport list, for cleanup
if (client->keep_alive_cfg.keep_alive_enable) {
esp_transport_ssl_set_keep_alive(ssl, &client->keep_alive_cfg);
}
if (client->config->use_global_ca_store == true) {
esp_transport_ssl_enable_global_ca_store(ssl);
} else if (client->config->cert) {
@ -552,9 +555,29 @@ static int esp_websocket_client_send_with_exact_opcode(esp_websocket_client_hand
int wlen = 0, widx = 0;
bool contained_fin = opcode & WS_TRANSPORT_OPCODES_FIN;
if (client == NULL || len < 0 || (data == NULL && len > 0)) {
ESP_LOGE(TAG, "Invalid arguments");
return -1;
}
if (!esp_websocket_client_is_connected(client)) {
ESP_LOGE(TAG, "Websocket client is not connected");
return -1;
}
if (client->transport == NULL) {
ESP_LOGE(TAG, "Invalid transport");
return -1;
}
if (xSemaphoreTakeRecursive(client->lock, timeout) != pdPASS) {
ESP_LOGE(TAG, "Could not lock ws-client within %" PRIu32 " timeout", timeout);
return -1;
}
if (esp_websocket_new_buf(client, true) != ESP_OK) {
ESP_LOGE(TAG, "Failed to setup tx buffer");
return -1;
goto unlock_and_return;
}
while (widx < len || opcode) { // allow for sending "current_opcode" only message with len==0
@ -580,14 +603,18 @@ static int esp_websocket_client_send_with_exact_opcode(esp_websocket_client_hand
esp_websocket_client_error(client, "esp_transport_write() returned %d, errno=%d", ret, errno);
}
esp_websocket_client_abort_connection(client, WEBSOCKET_ERROR_TYPE_TCP_TRANSPORT);
return ret;
goto unlock_and_return;
}
opcode = 0;
widx += wlen;
need_write = len - widx;
}
esp_websocket_free_buf(client, true);
return widx;
ret = widx;
unlock_and_return:
xSemaphoreGiveRecursive(client->lock);
return ret;
}
esp_websocket_client_handle_t esp_websocket_client_init(const esp_websocket_client_config_t *config)
@ -1208,35 +1235,7 @@ int esp_websocket_client_send_fin(esp_websocket_client_handle_t client, TickType
int esp_websocket_client_send_with_opcode(esp_websocket_client_handle_t client, ws_transport_opcodes_t opcode, const uint8_t *data, int len, TickType_t timeout)
{
int ret = -1;
if (client == NULL || len < 0 || (data == NULL && len > 0)) {
ESP_LOGE(TAG, "Invalid arguments");
return -1;
}
if (xSemaphoreTakeRecursive(client->lock, timeout) != pdPASS) {
ESP_LOGE(TAG, "Could not lock ws-client within %" PRIu32 " timeout", timeout);
return -1;
}
if (!esp_websocket_client_is_connected(client)) {
ESP_LOGE(TAG, "Websocket client is not connected");
goto unlock_and_return;
}
if (client->transport == NULL) {
ESP_LOGE(TAG, "Invalid transport");
goto unlock_and_return;
}
ret = esp_websocket_client_send_with_exact_opcode(client, opcode | WS_TRANSPORT_OPCODES_FIN, data, len, timeout);
if (ret < 0) {
ESP_LOGE(TAG, "Failed to send the buffer");
goto unlock_and_return;
}
unlock_and_return:
xSemaphoreGiveRecursive(client->lock);
return ret;
return esp_websocket_client_send_with_exact_opcode(client, opcode | WS_TRANSPORT_OPCODES_FIN, data, len, timeout);
}
bool esp_websocket_client_is_connected(esp_websocket_client_handle_t client)

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -96,14 +96,24 @@ static void websocket_app_start(void)
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
ESP_LOGI(TAG, "Sending fragmented message");
vTaskDelay(1000 / portTICK_PERIOD_MS);
// Sending text data
ESP_LOGI(TAG, "Sending fragmented text message");
memset(data, 'a', sizeof(data));
esp_websocket_client_send_text_partial(client, data, sizeof(data), portMAX_DELAY);
memset(data, 'b', sizeof(data));
esp_websocket_client_send_cont_msg(client, data, sizeof(data), portMAX_DELAY);
esp_websocket_client_send_fin(client, portMAX_DELAY);
vTaskDelay(1000 / portTICK_PERIOD_MS);
// Sending binary data
ESP_LOGI(TAG, "Sending fragmented binary message");
char binary_data[128];
memset(binary_data, 0, sizeof(binary_data));
esp_websocket_client_send_bin_partial(client, binary_data, sizeof(binary_data), portMAX_DELAY);
memset(binary_data, 1, sizeof(binary_data));
esp_websocket_client_send_cont_msg(client, binary_data, sizeof(binary_data), portMAX_DELAY);
esp_websocket_client_send_fin(client, portMAX_DELAY);
esp_websocket_client_destroy(client);
}

View File

@ -88,7 +88,9 @@ static void websocket_event_handler(void *handler_args, esp_event_base_t base, i
case WEBSOCKET_EVENT_DATA:
ESP_LOGI(TAG, "WEBSOCKET_EVENT_DATA");
ESP_LOGI(TAG, "Received opcode=%d", data->op_code);
if (data->op_code == 0x08 && data->data_len == 2) {
if (data->op_code == 0x2) { // Opcode 0x2 indicates binary data
ESP_LOG_BUFFER_HEX("Received binary data", data->data_ptr, data->data_len);
} else if (data->op_code == 0x08 && data->data_len == 2) {
ESP_LOGW(TAG, "Received closed message with code=%d", 256 * data->data_ptr[0] + data->data_ptr[1]);
} else {
ESP_LOGW(TAG, "Received=%.*s\n\n", data->data_len, (char *)data->data_ptr);
@ -183,13 +185,32 @@ static void websocket_app_start(void)
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
ESP_LOGI(TAG, "Sending fragmented message");
vTaskDelay(1000 / portTICK_PERIOD_MS);
// Sending text data
ESP_LOGI(TAG, "Sending fragmented text message");
memset(data, 'a', sizeof(data));
esp_websocket_client_send_text_partial(client, data, sizeof(data), portMAX_DELAY);
memset(data, 'b', sizeof(data));
esp_websocket_client_send_cont_msg(client, data, sizeof(data), portMAX_DELAY);
esp_websocket_client_send_fin(client, portMAX_DELAY);
vTaskDelay(1000 / portTICK_PERIOD_MS);
// Sending binary data
ESP_LOGI(TAG, "Sending fragmented binary message");
char binary_data[5];
memset(binary_data, 0, sizeof(binary_data));
esp_websocket_client_send_bin_partial(client, binary_data, sizeof(binary_data), portMAX_DELAY);
memset(binary_data, 1, sizeof(binary_data));
esp_websocket_client_send_cont_msg(client, binary_data, sizeof(binary_data), portMAX_DELAY);
esp_websocket_client_send_fin(client, portMAX_DELAY);
vTaskDelay(1000 / portTICK_PERIOD_MS);
// Sending text data longer than ws buffer (default 1024)
ESP_LOGI(TAG, "Sending text longer than ws buffer (default 1024)");
const int size = 2000;
char *long_data = malloc(size);
memset(long_data, 'a', size);
esp_websocket_client_send_text(client, long_data, size, portMAX_DELAY);
xSemaphoreTake(shutdown_sema, portMAX_DELAY);
esp_websocket_client_close(client, portMAX_DELAY);

View File

@ -27,10 +27,13 @@ def get_my_ip():
class WebsocketTestEcho(WebSocket):
def handleMessage(self):
self.sendMessage(self.data)
print('\n Server sent: {}\n'.format(self.data))
if isinstance(self.data, bytes):
print(f'\n Server received binary data: {self.data.hex()}\n')
self.sendMessage(self.data, binary=True)
else:
print(f'\n Server received: {self.data}\n')
self.sendMessage(self.data)
def handleConnected(self):
print('Connection from: {}'.format(self.address))
@ -86,6 +89,9 @@ def test_examples_protocol_websocket(dut):
3. send and receive data
"""
# Test for echo functionality:
# Sends a series of simple "hello" messages to the WebSocket server and verifies that each one is echoed back correctly.
# This tests the basic responsiveness and correctness of the WebSocket connection.
def test_echo(dut):
dut.expect('WEBSOCKET_EVENT_CONNECTED')
for i in range(0, 5):
@ -93,12 +99,16 @@ def test_examples_protocol_websocket(dut):
print('All echos received')
sys.stdout.flush()
# Test for clean closure of the WebSocket connection:
# Ensures that the WebSocket can correctly receive a close frame and terminate the connection without issues.
def test_close(dut):
code = dut.expect(
re.compile(
b'websocket: Received closed message with code=(\\d*)'))[0]
print('Received close frame with code {}'.format(code))
# Test for JSON message handling:
# Sends a JSON formatted string and verifies that the received message matches the expected JSON structure.
def test_json(dut, websocket):
json_string = """
[
@ -118,7 +128,7 @@ def test_examples_protocol_websocket(dut):
match = dut.expect(
re.compile(b'Json=({[a-zA-Z0-9]*).*}')).group(0).decode()[5:]
if match == str(data[0]):
print('Sent message and received message are equal \n')
print('\n Sent message and received message are equal \n')
sys.stdout.flush()
else:
raise ValueError(
@ -126,6 +136,8 @@ def test_examples_protocol_websocket(dut):
\nreceived: {}\nwith length {}'.format(
data[0], len(data[0]), match, len(match)))
# Test for receiving long messages:
# This sends a message with a specified length (2000 characters) to ensure the WebSocket can handle large data payloads. Repeated 3 times for reliability.
def test_recv_long_msg(dut, websocket, msg_len, repeats):
send_msg = ''.join(
@ -142,7 +154,7 @@ def test_examples_protocol_websocket(dut):
recv_msg += match
if recv_msg == send_msg:
print('Sent message and received message are equal \n')
print('\n Sent message and received message are equal \n')
sys.stdout.flush()
else:
raise ValueError(
@ -150,9 +162,50 @@ def test_examples_protocol_websocket(dut):
\nreceived: {}\nwith length {}'.format(
send_msg, len(send_msg), recv_msg, len(recv_msg)))
def test_fragmented_msg(dut):
# Test for receiving the first fragment of a large message:
# Verifies the WebSocket's ability to correctly process the initial segment of a fragmented message.
def test_recv_fragmented_msg1(dut):
dut.expect('websocket: Total payload length=2000, data_len=1024, current payload offset=0')
# Test for receiving the second fragment of a large message:
# Confirms that the WebSocket can correctly handle and process the subsequent segment of a fragmented message.
def test_recv_fragmented_msg2(dut):
dut.expect('websocket: Total payload length=2000, data_len=976, current payload offset=1024')
# Test for receiving fragmented text messages:
# Checks if the WebSocket can accurately reconstruct a message sent in several smaller parts.
def test_fragmented_txt_msg(dut):
dut.expect('Received=' + 32 * 'a' + 32 * 'b')
print('Fragmented data received')
print('\nFragmented data received\n')
# Extract the hexdump portion of the log line
def parse_hexdump(line):
match = re.search(r'\(.*\) Received binary data: ([0-9A-Fa-f ]+)', line)
if match:
hexdump = match.group(1).strip().replace(' ', '')
# Convert the hexdump string to a bytearray
return bytearray.fromhex(hexdump)
return bytearray()
# Capture the binary log output from the DUT
def test_fragmented_binary_msg(dut):
match = dut.expect(r'\(.*\) Received binary data: .*')
if match:
line = match.group(0).strip()
if isinstance(line, bytes):
line = line.decode('utf-8')
# Parse the hexdump from the log line
received_data = parse_hexdump(line)
# Create the expected bytearray with the specified pattern
expected_data = bytearray([0, 0, 0, 0, 0, 1, 1, 1, 1, 1])
# Validate the received data
assert received_data == expected_data, f'Received data does not match expected data. Received: {received_data}, Expected: {expected_data}'
print('\nFragmented data received\n')
else:
assert False, 'Log line with binary data not found'
# Starting of the test
try:
@ -184,10 +237,12 @@ def test_examples_protocol_websocket(dut):
dut.expect('Please enter uri of websocket endpoint', timeout=30)
dut.write(uri)
test_echo(dut)
# Message length should exceed DUT's buffer size to test fragmentation, default is 1024 byte
test_recv_long_msg(dut, ws, 2000, 3)
test_json(dut, ws)
test_fragmented_msg(dut)
test_fragmented_txt_msg(dut)
test_fragmented_binary_msg(dut)
test_recv_fragmented_msg1(dut)
test_recv_fragmented_msg2(dut)
test_close(dut)
else:
print('DUT connecting to {}'.format(uri))

View File

@ -0,0 +1,14 @@
CONFIG_IDF_TARGET="esp32"
CONFIG_IDF_TARGET_LINUX=n
CONFIG_WEBSOCKET_URI_FROM_STDIN=n
CONFIG_WEBSOCKET_URI_FROM_STRING=y
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_EXAMPLE_CONNECT_IPV6=y
CONFIG_ESP_WS_CLIENT_ENABLE_DYNAMIC_BUFFER=y

View File

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

View File

@ -1,5 +1,37 @@
# Changelog
## [0.2.3](https://github.com/espressif/esp-protocols/commits/wifi_remote-v0.2.3)
### Bug Fixes
- Fix server event/command race condtion using eventfd ([732b1d5](https://github.com/espressif/esp-protocols/commit/732b1d5))
- Lock server before marshalling events ([9e13870](https://github.com/espressif/esp-protocols/commit/9e13870))
## [0.2.2](https://github.com/espressif/esp-protocols/commits/wifi_remote-v0.2.2)
### Bug Fixes
- Added more netif options for eppp connection ([24ce867](https://github.com/espressif/esp-protocols/commit/24ce867))
- Do not restrict EPPP config to RSA keys only ([f05c765](https://github.com/espressif/esp-protocols/commit/f05c765), [#570](https://github.com/espressif/esp-protocols/issues/570))
## [0.2.1](https://github.com/espressif/esp-protocols/commits/wifi_remote-v0.2.1)
### Bug Fixes
- Added misc wifi API in eppp impl ([93256d1](https://github.com/espressif/esp-protocols/commit/93256d1))
- Updated eppp dependency not to use fixed version ([3a48c06](https://github.com/espressif/esp-protocols/commit/3a48c06))
## [0.2.0](https://github.com/espressif/esp-protocols/commits/wifi_remote-v0.2.0)
### Features
- Add support for simple eppp based RPC ([fd168d8](https://github.com/espressif/esp-protocols/commit/fd168d8))
### Bug Fixes
- Make services restartable, code cleanup ([6c82ce2](https://github.com/espressif/esp-protocols/commit/6c82ce2))
- Add examples to CI ([d2b7c55](https://github.com/espressif/esp-protocols/commit/d2b7c55))
## [0.1.12](https://github.com/espressif/esp-protocols/commits/wifi_remote-v0.1.12)
### Features

View File

@ -1,15 +1,20 @@
if(NOT CONFIG_ESP_WIFI_ENABLED)
set(src_wifi_is_remote esp_wifi_remote.c esp_wifi_with_remote.c)
set(src_wifi_is_remote esp_wifi_remote.c esp_wifi_with_remote.c esp_wifi_remote_net.c)
endif()
if(CONFIG_ESP_WIFI_REMOTE_LIBRARY_EPPP)
set(src_wifi_remote_eppp eppp/wifi_remote_rpc_client.cpp eppp/wifi_remote_rpc_server.cpp eppp/eppp_init.c)
else()
set(src_wifi_remote_weak esp_wifi_remote_weak.c)
endif()
idf_component_register(INCLUDE_DIRS include
SRCS ${src_wifi_is_remote}
esp_wifi_remote_net.c
esp_wifi_remote_weak.c
SRCS ${src_wifi_remote_weak}
${src_wifi_remote_eppp}
${src_wifi_is_remote}
PRIV_INCLUDE_DIRS eppp
REQUIRES esp_event esp_netif
PRIV_REQUIRES esp_wifi)
idf_component_optional_requires(PRIVATE esp_hosted)
PRIV_REQUIRES esp_wifi esp-tls vfs)
idf_component_get_property(wifi esp_wifi COMPONENT_LIB)
target_link_libraries(${wifi} PUBLIC ${COMPONENT_LIB})

View File

@ -5,6 +5,7 @@ menu "Wi-Fi Remote"
default y
orsource "./Kconfig.soc_wifi_caps.in"
orsource "./Kconfig.rpc.in"
config ESP_WIFI_STATIC_RX_BUFFER_NUM
int "Max number of WiFi static RX buffers"
@ -191,7 +192,7 @@ menu "Wi-Fi Remote"
Set the size of WiFi Block Ack RX window. Generally a bigger value means higher throughput and better
compatibility but more memory. Most of time we should NOT change the default value unless special
reason, e.g. test the maximum UDP RX throughput with iperf etc. For iperf test in shieldbox, the
recommended value is 9~12. If PSRAM is used and WiFi memory is prefered to allocat in PSRAM first,
recommended value is 9~12. If PSRAM is used and WiFi memory is preferred to allocate in PSRAM first,
the default and minimum value should be 16 to achieve better throughput and compatibility with both
stations and APs.
@ -228,14 +229,14 @@ menu "Wi-Fi Remote"
help
ESP-MESH utilizes beacon frames to detect and resolve root node conflicts (see documentation). However
the default length of a beacon frame can simultaneously hold only five root node identifier structures,
meaning that a root node conflict of up to five nodes can be detected at one time. In the occurence of
meaning that a root node conflict of up to five nodes can be detected at one time. In the occurrence of
more root nodes conflict involving more than five root nodes, the conflict resolution process will
detect five of the root nodes, resolve the conflict, and re-detect more root nodes. This process will
repeat until all root node conflicts are resolved. However this process can generally take a very long
time.
To counter this situation, the beacon frame length can be increased such that more root nodes can be
detected simultaneously. Each additional root node will require 36 bytes and should be added ontop of
detected simultaneously. Each additional root node will require 36 bytes and should be added on top of
the default beacon frame length of
752 bytes. For example, if you want to detect 10 root nodes simultaneously, you need to set the beacon
frame length as
@ -487,9 +488,9 @@ menu "Wi-Fi Remote"
help
Select this option to use MbedTLS TLS client for WPA2 enterprise connection.
Please note that from MbedTLS-3.0 onwards, MbedTLS does not support SSL-3.0
TLS-v1.0, TLS-v1.1 versions. Incase your server is using one of these version,
TLS-v1.0, TLS-v1.1 versions. In case your server is using one of these version,
it is advisable to update your server.
Please disable this option for compatibilty with older TLS versions.
Please disable this option for compatibility with older TLS versions.
config ESP_WIFI_EAP_TLS1_3
bool "Enable EAP-TLS v1.3 Support for WiFi Enterprise connection"
@ -556,6 +557,26 @@ menu "Wi-Fi Remote"
help
Select this option to enable WiFi Multiband operation certification support.
config ESP_WIFI_ENABLE_ROAMING_APP
bool "Advanced support for Wi-Fi Roaming (Experimental)"
depends on IDF_EXPERIMENTAL_FEATURES
default n
select ESP_WIFI_SCAN_CACHE
help
Enable Espressif's roaming app to allow for efficient Wi-Fi roaming.
This includes configurable periodic environment scans, maintaining a cache of the
best APs, handling low rssi events etc.
Risk Warning
Please note that this feature is still experimental and enabling this potentially can
lead to unpredictable scanning, connection and roaming attempts.
We are still working on tuning and optimising this feature to ensure reliable and stable use.
menu "Configure roaming App"
depends on ESP_WIFI_ENABLE_ROAMING_APP
rsource "wifi_apps/roaming_app/src/Kconfig.roaming"
endmenu
config ESP_WIFI_DPP_SUPPORT
bool "Enable DPP support"
default n
@ -597,7 +618,7 @@ menu "Wi-Fi Remote"
default n
help
Select this option to enable validate each WPS attribute
rigorously. Disabling this add the workaorunds with various APs.
rigorously. Disabling this add the workarounds with various APs.
Enabling this may cause inter operability issues with some APs.
config ESP_WIFI_WPS_PASSPHRASE
@ -605,9 +626,9 @@ menu "Wi-Fi Remote"
default n
help
Select this option to get passphrase during WPS configuration.
This option fakes the virtual display capabilites to get the
This option fakes the virtual display capabilities to get the
configuration in passphrase mode.
Not recommanded to be used since WPS credentials should not
Not recommended to be used since WPS credentials should not
be shared to other devices, making it in readable format increases
that risk, also passphrase requires pbkdf2 to convert in psk.

View File

@ -0,0 +1,74 @@
choice ESP_WIFI_REMOTE_LIBRARY
prompt "Choose WiFi-remote implementation"
default ESP_WIFI_REMOTE_LIBRARY_EPPP
help
Select type of WiFi Remote implementation
ESP-HOSTED is the default and most versatile option.
It's also possible to use EPPP, which uses PPPoS link between micros and NAPT, so it's slower
and less universal.
config ESP_WIFI_REMOTE_LIBRARY_HOSTED
bool "ESP-HOSTED"
config ESP_WIFI_REMOTE_LIBRARY_EPPP
bool "EPPP"
endchoice
if ESP_WIFI_REMOTE_LIBRARY_EPPP
config ESP_WIFI_REMOTE_EPPP_UART_TX_PIN
int "TXD Pin Number"
default 10
range 0 31
help
Pin number of UART TX.
config ESP_WIFI_REMOTE_EPPP_UART_RX_PIN
int "RXD Pin Number"
default 11
range 0 31
help
Pin number of UART RX.
config ESP_WIFI_REMOTE_EPPP_NETIF_PRIORITY
int "Routing priority of eppp netif"
default 100
range 0 256
help
Set the priority of the wifi-remote netif.
The bigger the number the higher the priority.
The interface which is up and with the highest priority will act as a default GW.
config ESP_WIFI_REMOTE_EPPP_NETIF_DESCRIPTION
string "eppp network interface description"
default "example_netif_sta"
help
Textual description of the wifi remote network interface.
By default it is set to "example_netif_sta" to be used in IDF protocol example
as default wifi station substitution.
config ESP_WIFI_REMOTE_EPPP_SERVER_CA
string "Servers CA certificate"
default "--- Please copy content of the CA certificate ---"
config ESP_WIFI_REMOTE_EPPP_CLIENT_CRT
string "Client certificate"
default "--- Please copy content of the Client certificate ---"
config ESP_WIFI_REMOTE_EPPP_CLIENT_KEY
string "Client key"
default "--- Please copy content of the Client key ---"
config ESP_WIFI_REMOTE_EPPP_CLIENT_CA
string "Clients CA certificate"
default "--- Please copy content of the CA certificate ---"
config ESP_WIFI_REMOTE_EPPP_SERVER_CRT
string "Server certificate"
default "--- Please copy content of the Client certificate ---"
config ESP_WIFI_REMOTE_EPPP_SERVER_KEY
string "Server key"
default "--- Please copy content of the Client key ---"
endif

View File

@ -227,3 +227,11 @@ endif # ESP32C6
if SLAVE_IDF_TARGET_ESP32H2
endif # ESP32H2
if SLAVE_IDF_TARGET_ESP32P4
config SLAVE_SOC_WIFI_LIGHT_SLEEP_CLK_WIDTH
int
default 12
endif # ESP32P4

View File

@ -0,0 +1,22 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_log.h"
#include "esp_wifi.h"
#include "eppp_link.h"
__attribute__((weak)) esp_netif_t *wifi_remote_eppp_init(eppp_type_t role)
{
uint32_t our_ip = role == EPPP_SERVER ? EPPP_DEFAULT_SERVER_IP() : EPPP_DEFAULT_CLIENT_IP();
uint32_t their_ip = role == EPPP_SERVER ? EPPP_DEFAULT_CLIENT_IP() : EPPP_DEFAULT_SERVER_IP();
eppp_config_t config = EPPP_DEFAULT_CONFIG(our_ip, their_ip);
// We currently support only UART transport
config.transport = EPPP_TRANSPORT_UART;
config.uart.tx_io = CONFIG_ESP_WIFI_REMOTE_EPPP_UART_TX_PIN;
config.uart.rx_io = CONFIG_ESP_WIFI_REMOTE_EPPP_UART_RX_PIN;
config.ppp.netif_description = CONFIG_ESP_WIFI_REMOTE_EPPP_NETIF_DESCRIPTION;
config.ppp.netif_prio = CONFIG_ESP_WIFI_REMOTE_EPPP_NETIF_PRIORITY;
return eppp_open(role, &config, portMAX_DELAY);
}

View File

@ -0,0 +1,318 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <netdb.h>
#include <memory>
#include <cinttypes>
#include "esp_log.h"
#include "esp_tls.h"
#include "esp_wifi.h"
#include "esp_check.h"
#include "wifi_remote_rpc_impl.hpp"
#include "eppp_link.h"
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "wifi_remote_rpc_params.h"
extern "C" esp_netif_t *wifi_remote_eppp_init(eppp_type_t role);
namespace eppp_rpc {
namespace client {
const char *TAG = "rpc_client";
const unsigned char ca_crt[] = "-----BEGIN CERTIFICATE-----\n" CONFIG_ESP_WIFI_REMOTE_EPPP_SERVER_CA "\n-----END CERTIFICATE-----";
const unsigned char crt[] = "-----BEGIN CERTIFICATE-----\n" CONFIG_ESP_WIFI_REMOTE_EPPP_CLIENT_CRT "\n-----END CERTIFICATE-----";
const unsigned char key[] = "-----BEGIN PRIVATE KEY-----\n" CONFIG_ESP_WIFI_REMOTE_EPPP_CLIENT_KEY "\n-----END PRIVATE KEY-----";
// TODO: Add option to supply keys and certs via a global symbol (file)
}
using namespace client;
class Sync {
friend class RpcInstance;
public:
void lock()
{
xSemaphoreTake(mutex, portMAX_DELAY);
}
void unlock()
{
xSemaphoreGive(mutex);
}
esp_err_t init()
{
mutex = xSemaphoreCreateMutex();
events = xEventGroupCreate();
return mutex == nullptr || events == nullptr ? ESP_ERR_NO_MEM : ESP_OK;
}
esp_err_t wait_for(EventBits_t bits, uint32_t timeout = portMAX_DELAY)
{
return (xEventGroupWaitBits(events, bits, pdTRUE, pdTRUE, timeout) & bits) == bits ? ESP_OK : ESP_FAIL;
}
esp_err_t notify(EventBits_t bits)
{
xEventGroupSetBits(events, bits);
return ESP_OK;
}
~Sync()
{
if (mutex) {
vSemaphoreDelete(mutex);
}
if (events) {
vEventGroupDelete(events);
}
}
private:
SemaphoreHandle_t mutex{nullptr};
EventGroupHandle_t events{nullptr};
const int request = 1;
const int resp_header = 2;
const int resp_payload = 4;
const int restart = 8;
};
class RpcInstance {
friend class Sync;
public:
template<typename T>
esp_err_t send(api_id id, T *t)
{
pending_resp = id;
ESP_RETURN_ON_ERROR(sync.notify(sync.request), TAG, "failed to notify req");
ESP_RETURN_ON_ERROR(rpc.send<T>(id, t), TAG, "Failed to send request");
return ESP_OK;
}
// overload of the templated method (used for functions with no arguments)
esp_err_t send(api_id id)
{
pending_resp = id;
ESP_RETURN_ON_ERROR(sync.notify(sync.request), TAG, "failed to notify req");
ESP_RETURN_ON_ERROR(rpc.send(id), TAG, "Failed to send request");
return ESP_OK;
}
template<typename T>
T get_resp(api_id id)
{
sync.wait_for(sync.resp_header);
auto ret = rpc.template get_payload<T>(id, pending_header);
sync.notify(sync.resp_payload);
return ret;
}
esp_err_t init()
{
ESP_RETURN_ON_FALSE(netif = wifi_remote_eppp_init(EPPP_CLIENT), ESP_FAIL, TAG, "Failed to connect to EPPP server");
ESP_RETURN_ON_ERROR(esp_event_handler_register(IP_EVENT, IP_EVENT_PPP_GOT_IP, got_ip, this), TAG, "Failed to register event");
ESP_RETURN_ON_ERROR(sync.init(), TAG, "Failed to init sync primitives");
ESP_RETURN_ON_ERROR(rpc.init(), TAG, "Failed to init RPC engine");
return xTaskCreate(task, "client", 8192, this, 5, nullptr) == pdTRUE ? ESP_OK : ESP_FAIL;
}
RpcEngine rpc{eppp_rpc::role::CLIENT};
Sync sync;
private:
api_id pending_resp{api_id::UNDEF};
RpcHeader pending_header{};
esp_err_t process_ip_event(RpcHeader &header)
{
auto event = rpc.get_payload<esp_wifi_remote_eppp_ip_event>(api_id::IP_EVENT, header);
// Now bypass network layers with EPPP interface
ESP_RETURN_ON_ERROR(esp_netif_set_dns_info(netif, ESP_NETIF_DNS_MAIN, &event.dns), TAG, "Failed to set DNS info");
ESP_RETURN_ON_ERROR(esp_netif_set_default_netif(netif), TAG, "Failed to set default netif to EPPP");
ip_event_got_ip_t evt = {
.esp_netif = netif,
.ip_info = {},
.ip_changed = true,
};
esp_netif_get_ip_info(netif, &evt.ip_info);
ESP_RETURN_ON_ERROR(esp_event_post(IP_EVENT, IP_EVENT_STA_GOT_IP, &evt, sizeof(evt), 0), TAG, "Failed to post IP event");
ESP_LOGI(TAG, "Main DNS:" IPSTR, IP2STR(&event.dns.ip.u_addr.ip4));
ESP_LOGI(TAG, "EPPP IP:" IPSTR, IP2STR(&event.ppp_ip.ip));
ESP_LOGI(TAG, "WIFI IP:" IPSTR, IP2STR(&event.wifi_ip.ip));
ESP_LOGI(TAG, "WIFI GW:" IPSTR, IP2STR(&event.wifi_ip.gw));
ESP_LOGI(TAG, "WIFI mask:" IPSTR, IP2STR(&event.wifi_ip.netmask));
return ESP_OK;
}
esp_err_t process_wifi_event(RpcHeader &header)
{
auto event_id = rpc.get_payload<int32_t>(api_id::WIFI_EVENT, header);
ESP_RETURN_ON_ERROR(esp_event_post(WIFI_EVENT, event_id, nullptr, 0, 0), TAG, "Failed to post WiFi event");
return ESP_OK;
}
esp_err_t perform()
{
auto header = rpc.get_header();
if (api_id(header.id) == api_id::ERROR) { // network error
return ESP_FAIL;
}
if (api_id(header.id) == api_id::UNDEF) { // network timeout
return ESP_OK;
}
if (api_id(header.id) == api_id::IP_EVENT) {
return process_ip_event(header);
}
if (api_id(header.id) == api_id::WIFI_EVENT) {
return process_wifi_event(header);
}
if (sync.wait_for(sync.request, 0) == ESP_OK && api_id(header.id) == pending_resp) {
pending_header = header;
pending_resp = api_id::UNDEF;
sync.notify(sync.resp_header);
sync.wait_for(sync.resp_payload);
return ESP_OK;
}
ESP_LOGE(TAG, "Unexpected header %" PRIi32, static_cast<uint32_t>(header.id));
return ESP_FAIL;
}
static void task(void *ctx)
{
auto instance = static_cast<RpcInstance *>(ctx);
do {
while (instance->perform() == ESP_OK) {}
} while (instance->restart() == ESP_OK);
vTaskDelete(nullptr);
}
esp_err_t restart()
{
rpc.deinit();
ESP_RETURN_ON_ERROR(sync.wait_for(sync.restart, pdMS_TO_TICKS(10000)), TAG, "Didn't receive EPPP address in time");
return rpc.init();
}
static void got_ip(void *ctx, esp_event_base_t base, int32_t id, void *data)
{
auto instance = static_cast<RpcInstance *>(ctx);
instance->sync.notify(instance->sync.restart);
}
esp_netif_t *netif{nullptr};
};
namespace client {
constinit RpcInstance instance;
} // namespace client
RpcInstance *RpcEngine::init_client()
{
char host[4 * 4 + 1] = {}; // IPv4: 4 x (3 numbers + '.') + \0
esp_ip4_addr_t ip = { .addr = EPPP_DEFAULT_SERVER_IP() };
if (esp_ip4addr_ntoa(&ip, host, sizeof(host)) == nullptr) {
return nullptr;
}
esp_tls_cfg_t cfg = {};
cfg.cacert_buf = client::ca_crt;
cfg.cacert_bytes = sizeof(client::ca_crt);
cfg.clientcert_buf = client::crt;
cfg.clientcert_bytes = sizeof(client::crt);
cfg.clientkey_buf = client::key;
cfg.clientkey_bytes = sizeof(client::key);
cfg.common_name = "espressif.local";
ESP_RETURN_ON_FALSE(tls_ = esp_tls_init(), nullptr, TAG, "Failed to create ESP-TLS instance");
int retries = 0;
while (esp_tls_conn_new_sync(host, strlen(host), rpc_port, &cfg, tls_) <= 0) {
esp_tls_conn_destroy(tls_);
tls_ = nullptr;
ESP_RETURN_ON_FALSE(retries++ < 3, nullptr, TAG, "Failed to open connection to %s", host);
ESP_LOGW(TAG, "Connection to RPC server failed! Will retry in %d second(s)", retries);
vTaskDelay(pdMS_TO_TICKS(1000 * retries));
ESP_RETURN_ON_FALSE(tls_ = esp_tls_init(), nullptr, TAG, "Failed to create ESP-TLS instance");
}
return &client::instance;
}
} // namespace eppp_rpc
//
// esp_wifi_remote API implementation
//
using namespace eppp_rpc;
using namespace client;
extern "C" esp_err_t esp_wifi_remote_init(const wifi_init_config_t *config)
{
// Here we initialize this client's RPC
ESP_RETURN_ON_ERROR(instance.init(), TAG, "Failed to initialize eppp-rpc");
std::lock_guard<Sync> lock(instance.sync);
ESP_RETURN_ON_ERROR(instance.send(api_id::INIT, config), TAG, "Failed to send request");
return instance.get_resp<esp_err_t>(api_id::INIT);
}
extern "C" esp_err_t esp_wifi_remote_set_config(wifi_interface_t interface, wifi_config_t *conf)
{
esp_wifi_remote_config params = { .interface = interface, .conf = {} };
memcpy(&params.conf, conf, sizeof(wifi_config_t));
std::lock_guard<Sync> lock(instance.sync);
ESP_RETURN_ON_ERROR(instance.send(api_id::SET_CONFIG, &params), TAG, "Failed to send request");
return instance.get_resp<esp_err_t>(api_id::SET_CONFIG);
}
extern "C" esp_err_t esp_wifi_remote_start(void)
{
std::lock_guard<Sync> lock(instance.sync);
ESP_RETURN_ON_ERROR(instance.send(api_id::START), TAG, "Failed to send request");
return instance.get_resp<esp_err_t>(api_id::START);
}
extern "C" esp_err_t esp_wifi_remote_stop(void)
{
std::lock_guard<Sync> lock(instance.sync);
ESP_RETURN_ON_ERROR(instance.send(api_id::STOP), TAG, "Failed to send request");
return instance.get_resp<esp_err_t>(api_id::STOP);
}
extern "C" esp_err_t esp_wifi_remote_connect(void)
{
std::lock_guard<Sync> lock(instance.sync);
ESP_RETURN_ON_ERROR(instance.send(api_id::CONNECT), TAG, "Failed to send request");
return instance.get_resp<esp_err_t>(api_id::CONNECT);
}
extern "C" esp_err_t esp_wifi_remote_get_mac(wifi_interface_t ifx, uint8_t mac[6])
{
std::lock_guard<Sync> lock(instance.sync);
ESP_RETURN_ON_ERROR(instance.send(api_id::GET_MAC, &ifx), TAG, "Failed to send request");
auto ret = instance.get_resp<esp_wifi_remote_mac_t>(api_id::GET_MAC);
ESP_LOG_BUFFER_HEXDUMP("MAC", ret.mac, 6, ESP_LOG_DEBUG);
memcpy(mac, ret.mac, 6);
return ret.err;
}
extern "C" esp_err_t esp_wifi_remote_set_mode(wifi_mode_t mode)
{
std::lock_guard<Sync> lock(instance.sync);
ESP_RETURN_ON_ERROR(instance.send(api_id::SET_MODE, &mode), TAG, "Failed to send request");
return instance.get_resp<esp_err_t>(api_id::SET_MODE);
}
extern "C" esp_err_t esp_wifi_remote_deinit(void)
{
std::lock_guard<Sync> lock(instance.sync);
ESP_RETURN_ON_ERROR(instance.send(api_id::DEINIT), TAG, "Failed to send request");
return instance.get_resp<esp_err_t>(api_id::DEINIT);
}
extern "C" esp_err_t esp_wifi_remote_disconnect(void)
{
std::lock_guard<Sync> lock(instance.sync);
ESP_RETURN_ON_ERROR(instance.send(api_id::DISCONNECT), TAG, "Failed to send request");
return instance.get_resp<esp_err_t>(api_id::DISCONNECT);
}
extern "C" esp_err_t esp_wifi_remote_set_storage(wifi_storage_t storage)
{
std::lock_guard<Sync> lock(instance.sync);
ESP_RETURN_ON_ERROR(instance.send(api_id::SET_STORAGE, &storage), TAG, "Failed to send request");
return instance.get_resp<esp_err_t>(api_id::SET_STORAGE);
}

View File

@ -0,0 +1,179 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <cstring>
#include <cerrno>
namespace eppp_rpc {
static constexpr int rpc_port = 3333;
/**
* @brief Currently supported RPC commands/events
*/
enum class api_id : uint32_t {
ERROR,
UNDEF,
INIT,
DEINIT,
SET_MODE,
SET_CONFIG,
START,
STOP,
CONNECT,
DISCONNECT,
GET_MAC,
SET_STORAGE,
WIFI_EVENT,
IP_EVENT,
};
enum class role {
SERVER,
CLIENT,
};
struct RpcHeader {
api_id id;
uint32_t size;
} __attribute((__packed__));
/**
* @brief Structure holding the outgoing or incoming parameter
*/
template<typename T>
struct RpcData {
RpcHeader head;
T value_{};
explicit RpcData(api_id id) : head{id, sizeof(T)} {}
uint8_t *value()
{
return (uint8_t *) &value_;
}
uint8_t *marshall(T *t, size_t &size)
{
size = head.size + sizeof(RpcHeader);
memcpy(value(), t, sizeof(T));
return (uint8_t *) this;
}
} __attribute((__packed__));
/**
* @brief Singleton holding the static data for either the client or server side
*/
class RpcInstance;
/**
* @brief Engine that implements a simple RPC mechanism
*/
class RpcEngine {
public:
constexpr explicit RpcEngine(role r) : tls_(nullptr), role_(r) {}
esp_err_t init()
{
if (tls_ != nullptr) {
return ESP_OK;
}
if (role_ == role::CLIENT) {
instance = init_client();
}
if (role_ == role::SERVER) {
instance = init_server();
}
return instance == nullptr ? ESP_FAIL : ESP_OK;
}
void deinit()
{
if (tls_ == nullptr) {
return;
}
if (role_ == role::CLIENT) {
esp_tls_conn_destroy(tls_);
} else if (role_ == role::SERVER) {
esp_tls_server_session_delete(tls_);
}
tls_ = nullptr;
}
template<typename T>
esp_err_t send(api_id id, T *t)
{
RpcData<T> req(id);
size_t size;
auto buf = req.marshall(t, size);
ESP_LOGD("rpc", "Sending API id:%d", (int) id);
ESP_LOG_BUFFER_HEXDUMP("rpc", buf, size, ESP_LOG_VERBOSE);
int len = esp_tls_conn_write(tls_, buf, size);
if (len <= 0) {
ESP_LOGE("rpc", "Failed to write data to the connection");
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t send(api_id id) // overload for (void)
{
RpcHeader head = {.id = id, .size = 0};
int len = esp_tls_conn_write(tls_, &head, sizeof(head));
if (len <= 0) {
ESP_LOGE("rpc", "Failed to write data to the connection");
return ESP_FAIL;
}
return ESP_OK;
}
int get_socket_fd()
{
int sock;
if (esp_tls_get_conn_sockfd(tls_, &sock) != ESP_OK) {
return -1;
}
return sock;
}
RpcHeader get_header()
{
RpcHeader header{};
int len = esp_tls_conn_read(tls_, (char *) &header, sizeof(header));
if (len <= 0) {
if (len < 0 && errno != EAGAIN) {
ESP_LOGE("rpc", "Failed to read header data from the connection %d %s", errno, strerror(errno));
return {.id = api_id::ERROR, .size = 0};
}
return {.id = api_id::UNDEF, .size = 0};
}
return header;
}
template<typename T>
T get_payload(api_id id, RpcHeader &head)
{
RpcData<T> resp(id);
if (head.id != id || head.size != resp.head.size) {
ESP_LOGE("rpc", "unexpected header %d %d or sizes %" PRIu32 " %" PRIu32, (int)head.id, (int)id, head.size, resp.head.size);
return {};
}
int len = esp_tls_conn_read(tls_, (char *) resp.value(), resp.head.size);
if (len <= 0) {
ESP_LOGE("rpc", "Failed to read data from the connection");
return {};
}
return resp.value_;
}
private:
RpcInstance *init_server();
RpcInstance *init_client();
esp_tls_t *tls_;
role role_;
RpcInstance *instance{nullptr};
};
};

View File

@ -0,0 +1,23 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
struct esp_wifi_remote_config {
wifi_interface_t interface;
wifi_config_t conf;
};
struct esp_wifi_remote_mac_t {
esp_err_t err;
uint8_t mac[6];
};
struct esp_wifi_remote_eppp_ip_event {
int32_t id;
esp_netif_ip_info_t wifi_ip;
esp_netif_ip_info_t ppp_ip;
esp_netif_dns_info_t dns;
};

View File

@ -0,0 +1,383 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <netdb.h>
#include <memory>
#include <cerrno>
#include <sys/socket.h>
#include "esp_log.h"
#include "esp_check.h"
#include "esp_tls.h"
#include "esp_wifi.h"
#include "wifi_remote_rpc_impl.hpp"
#include "eppp_link.h"
#include "wifi_remote_rpc_params.h"
#include "lwip/apps/snmp.h"
#include "esp_vfs.h"
#include "esp_vfs_eventfd.h"
extern "C" esp_netif_t *wifi_remote_eppp_init(eppp_type_t role);
namespace eppp_rpc {
namespace server {
const char *TAG = "rpc_server";
const unsigned char ca_crt[] = "-----BEGIN CERTIFICATE-----\n" CONFIG_ESP_WIFI_REMOTE_EPPP_CLIENT_CA "\n-----END CERTIFICATE-----";
const unsigned char crt[] = "-----BEGIN CERTIFICATE-----\n" CONFIG_ESP_WIFI_REMOTE_EPPP_SERVER_CRT "\n-----END CERTIFICATE-----";
const unsigned char key[] = "-----BEGIN PRIVATE KEY-----\n" CONFIG_ESP_WIFI_REMOTE_EPPP_SERVER_KEY "\n-----END PRIVATE KEY-----";
// TODO: Add option to supply keys and certs via a global symbol (file)
}
using namespace server;
struct Events {
api_id type;
int32_t id;
esp_wifi_remote_eppp_ip_event *ip_data{nullptr};
bool clean_ip_data{true};
esp_err_t create_ip_data()
{
ip_data = new (std::nothrow) esp_wifi_remote_eppp_ip_event;
return ip_data ? ESP_OK : ESP_ERR_NO_MEM;
}
~Events()
{
if (clean_ip_data) {
delete ip_data;
}
}
};
class Sync {
friend class RpcInstance;
public:
esp_err_t put(Events &ev)
{
ESP_RETURN_ON_FALSE(xQueueSend(queue, &ev, pdMS_TO_TICKS(queue_timeout)), ESP_FAIL, TAG, "Failed to queue event %" PRIi32, ev.id);
ev.clean_ip_data = false; // IP data were successfully sent to the queue, will free manually after receiving from it
uint64_t event_queued = 1;
write(fd, &event_queued, sizeof(event_queued)); // trigger the wait loop that
return ESP_OK;
}
Events get()
{
Events ev{};
if (!xQueueReceive(queue, &ev, 0)) {
ev.type = api_id::ERROR;
}
return ev;
}
esp_err_t init()
{
queue = xQueueCreate(max_items, sizeof(Events));
esp_vfs_eventfd_config_t config = ESP_VFS_EVENTD_CONFIG_DEFAULT();
esp_vfs_eventfd_register(&config);
fd = eventfd(0, EFD_SUPPORT_ISR);
return queue == nullptr || fd < 0 ? ESP_ERR_NO_MEM : ESP_OK;
}
~Sync()
{
if (queue) {
vQueueDelete(queue);
}
if (fd >= 0) {
close(fd);
}
}
int fd{-1};
// Used to trigger task by either an internal event or rpc command
static const int NONE = 0;
static const int ERROR = 1;
static const int EVENT = 2;
static const int RPC = 4;
private:
QueueHandle_t queue{nullptr};
const int max_items = 15;
const int queue_timeout = 200;
};
class RpcInstance {
friend class Sync;
public:
RpcEngine rpc{role::SERVER};
int sock{-1};
esp_err_t init()
{
ESP_RETURN_ON_FALSE(netif = wifi_remote_eppp_init(EPPP_SERVER), ESP_FAIL, TAG, "Failed to init EPPP connection");
ESP_RETURN_ON_ERROR(start_server(), TAG, "Failed to start RPC server");
ESP_RETURN_ON_ERROR(rpc.init(), TAG, "Failed to init RPC engine");
ESP_RETURN_ON_ERROR(esp_netif_napt_enable(netif), TAG, "Failed to enable NAPT");
ESP_RETURN_ON_ERROR(sync.init(), TAG, "Failed to init event queue");
ESP_RETURN_ON_ERROR(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, handler, this), TAG, "Failed to register event");
ESP_RETURN_ON_ERROR(esp_event_handler_register(IP_EVENT, ESP_EVENT_ANY_ID, handler, this), TAG, "Failed to register event");
return xTaskCreate(task, "server", 8192, this, 5, nullptr) == pdTRUE ? ESP_OK : ESP_FAIL;
}
Sync sync;
private:
esp_netif_t *netif{nullptr};
static void task(void *ctx)
{
auto instance = static_cast<RpcInstance *>(ctx);
while (instance->perform() == ESP_OK) {}
esp_restart();
}
esp_err_t start_server()
{
struct sockaddr_in dest_addr = {};
int ret;
int opt = 1;
dest_addr.sin_addr.s_addr = htonl(INADDR_ANY);
dest_addr.sin_family = AF_INET;
dest_addr.sin_port = htons(rpc_port);
int listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
ESP_RETURN_ON_FALSE(listen_sock >= 0, ESP_FAIL, TAG, "Failed to create listening socket");
setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
ret = bind(listen_sock, (struct sockaddr *) &dest_addr, sizeof(dest_addr));
ESP_RETURN_ON_FALSE(ret == 0, ESP_FAIL, TAG, "Failed to bind the listening socket");
ret = listen(listen_sock, 1);
ESP_RETURN_ON_FALSE(ret == 0, ESP_FAIL, TAG, "Failed to start listening");
struct sockaddr_storage source_addr {};
socklen_t addr_len = sizeof(source_addr);
sock = accept(listen_sock, (struct sockaddr *) &source_addr, &addr_len);
ESP_RETURN_ON_FALSE(sock >= 0, ESP_FAIL, TAG, "Failed to accept connections: errno %d", errno);
ESP_LOGI(TAG, "Socket accepted on: %s", inet_ntoa(((struct sockaddr_in *) &source_addr)->sin_addr));
return ESP_OK;
}
esp_err_t wifi_event(int32_t id)
{
ESP_LOGI(TAG, "Received WIFI event %" PRIi32, id);
Events ev{api_id::WIFI_EVENT, id, nullptr};
ESP_RETURN_ON_ERROR(sync.put(ev), TAG, "Failed to queue WiFi event");
return ESP_OK;
}
esp_err_t ip_event(int32_t id, ip_event_got_ip_t *ip_data)
{
ESP_LOGI(TAG, "Received IP event %" PRIi32, id);
Events ev{api_id::IP_EVENT, id, nullptr};
if (ip_data->esp_netif) {
ESP_RETURN_ON_ERROR(ev.create_ip_data(), TAG, "Failed to allocate event data");
ev.ip_data->id = id;
ESP_RETURN_ON_ERROR(esp_netif_get_dns_info(ip_data->esp_netif, ESP_NETIF_DNS_MAIN, &ev.ip_data->dns), TAG, "Failed to get DNS info");
ESP_LOGI(TAG, "Main DNS:" IPSTR, IP2STR(&ev.ip_data->dns.ip.u_addr.ip4));
memcpy(&ev.ip_data->wifi_ip, &ip_data->ip_info, sizeof(ev.ip_data->wifi_ip));
ESP_RETURN_ON_ERROR(esp_netif_get_ip_info(netif, &ev.ip_data->ppp_ip), TAG, "Failed to get IP info");
ESP_LOGI(TAG, "IP address:" IPSTR, IP2STR(&ip_data->ip_info.ip));
}
ESP_RETURN_ON_ERROR(sync.put(ev), TAG, "Failed to queue IP event");
return ESP_OK;
}
static void handler(void *ctx, esp_event_base_t base, int32_t id, void *data)
{
auto instance = static_cast<RpcInstance *>(ctx);
if (base == WIFI_EVENT) {
instance->wifi_event(id);
} else if (base == IP_EVENT) {
auto *ip_data = (ip_event_got_ip_t *)data;
instance->ip_event(id, ip_data);
}
}
int select()
{
struct timeval timeout = { .tv_sec = 1, .tv_usec = 0};
int rpc_sock = rpc.get_socket_fd();
ESP_RETURN_ON_FALSE(rpc_sock != -1, Sync::ERROR, TAG, "failed ot get rpc socket");
fd_set readset;
fd_set errset;
FD_ZERO(&readset);
FD_ZERO(&errset);
FD_SET(rpc_sock, &readset);
FD_SET(sync.fd, &readset);
FD_SET(rpc_sock, &errset);
int ret = ::select(std::max(rpc_sock, 5) + 1, &readset, nullptr, &errset, &timeout);
if (ret == 0) {
ESP_LOGV(TAG, "poll_read: select - Timeout before any socket was ready!");
return Sync::NONE;
}
if (ret < 0) {
ESP_LOGE(TAG, "select error: %d", errno);
return Sync::ERROR;
}
if (FD_ISSET(rpc_sock, &errset)) {
int sock_errno = 0;
uint32_t optlen = sizeof(sock_errno);
getsockopt(rpc_sock, SOL_SOCKET, SO_ERROR, &sock_errno, &optlen);
ESP_LOGE(TAG, "select failed, socket errno = %d", sock_errno);
return Sync::ERROR;
}
int result = Sync::NONE;
if (FD_ISSET(rpc_sock, &readset)) {
result |= Sync::RPC;
}
if (FD_ISSET(sync.fd, &readset)) {
result |= Sync::EVENT;
}
return result;
}
esp_err_t marshall_events()
{
api_id type;
do {
Events ev = sync.get();
type = ev.type;
if (ev.type == api_id::WIFI_EVENT) {
ESP_RETURN_ON_ERROR(rpc.send(api_id::WIFI_EVENT, &ev.id), TAG, "Failed to marshall WiFi event");
} else if (ev.type == api_id::IP_EVENT && ev.ip_data) {
ESP_RETURN_ON_ERROR(rpc.send(api_id::IP_EVENT, ev.ip_data), TAG, "Failed to marshal IP event");
}
} while (type != api_id::ERROR);
return ESP_OK;
}
esp_err_t perform()
{
auto res = select();
if (res == Sync::ERROR) {
return ESP_FAIL;
}
if (res & Sync::EVENT) {
uint64_t data;
read(sync.fd, &data, sizeof(data));
if (marshall_events() != ESP_OK) {
return ESP_FAIL;
}
}
if (res & Sync::RPC) {
if (handle_commands() != ESP_OK) {
return ESP_FAIL;
}
}
return ESP_OK;
}
esp_err_t handle_commands()
{
auto header = rpc.get_header();
ESP_LOGI(TAG, "Received header id %d", (int) header.id);
switch (header.id) {
case api_id::SET_MODE: {
auto req = rpc.get_payload<wifi_mode_t>(api_id::SET_MODE, header);
auto ret = esp_wifi_set_mode(req);
if (rpc.send(api_id::SET_MODE, &ret) != ESP_OK) {
return ESP_FAIL;
}
break;
}
case api_id::INIT: {
auto req = rpc.get_payload<wifi_init_config_t>(api_id::INIT, header);
req.osi_funcs = &g_wifi_osi_funcs;
req.wpa_crypto_funcs = g_wifi_default_wpa_crypto_funcs;
auto ret = esp_wifi_init(&req);
if (rpc.send(api_id::INIT, &ret) != ESP_OK) {
return ESP_FAIL;
}
break;
}
case api_id::SET_CONFIG: {
auto req = rpc.get_payload<esp_wifi_remote_config>(api_id::SET_CONFIG, header);
auto ret = esp_wifi_set_config(req.interface, &req.conf);
if (rpc.send(api_id::SET_CONFIG, &ret) != ESP_OK) {
return ESP_FAIL;
}
break;
}
case api_id::START: {
if (header.size != 0) {
return ESP_FAIL;
}
auto ret = esp_wifi_start();
if (rpc.send(api_id::START, &ret) != ESP_OK) {
return ESP_FAIL;
}
break;
}
case api_id::CONNECT: {
if (header.size != 0) {
return ESP_FAIL;
}
auto ret = esp_wifi_connect();
if (rpc.send(api_id::CONNECT, &ret) != ESP_OK) {
return ESP_FAIL;
}
break;
}
case api_id::DISCONNECT: {
if (header.size != 0) {
return ESP_FAIL;
}
auto ret = esp_wifi_disconnect();
if (rpc.send(api_id::DISCONNECT, &ret) != ESP_OK) {
return ESP_FAIL;
}
break;
}
case api_id::DEINIT: {
if (header.size != 0) {
return ESP_FAIL;
}
auto ret = esp_wifi_deinit();
if (rpc.send(api_id::DEINIT, &ret) != ESP_OK) {
return ESP_FAIL;
}
break;
}
case api_id::SET_STORAGE: {
auto req = rpc.get_payload<wifi_storage_t>(api_id::SET_STORAGE, header);
auto ret = esp_wifi_set_storage(req);
if (rpc.send(api_id::SET_STORAGE, &ret) != ESP_OK) {
return ESP_FAIL;
}
break;
}
case api_id::GET_MAC: {
auto req = rpc.get_payload<wifi_interface_t>(api_id::GET_MAC, header);
esp_wifi_remote_mac_t resp = {};
resp.err = esp_wifi_get_mac(req, resp.mac);
if (rpc.send(api_id::GET_MAC, &resp) != ESP_OK) {
return ESP_FAIL;
}
break;
}
default:
return ESP_FAIL;
}
return ESP_OK;
}
};
namespace server {
constinit RpcInstance instance;
}
RpcInstance *RpcEngine::init_server()
{
esp_tls_cfg_server_t cfg = {};
cfg.cacert_buf = server::ca_crt;
cfg.cacert_bytes = sizeof(server::ca_crt);
cfg.servercert_buf = server::crt;
cfg.servercert_bytes = sizeof(server::crt);
cfg.serverkey_buf = server::key;
cfg.serverkey_bytes = sizeof(server::key);
ESP_RETURN_ON_FALSE(tls_ = esp_tls_init(), nullptr, TAG, "Failed to create ESP-TLS instance");
ESP_RETURN_ON_FALSE(esp_tls_server_session_create(&cfg, server::instance.sock, tls_) == ESP_OK, nullptr, TAG, "Failed to create TLS session");
return &server::instance;
}
} // namespace eppp_rpc
using namespace eppp_rpc;
extern "C" esp_err_t server_init(void)
{
return server::instance.init();
}

View File

@ -271,26 +271,6 @@ WEAK esp_err_t esp_wifi_remote_set_csi(_Bool en)
LOG_UNSUPPORTED_AND_RETURN(ESP_ERR_NOT_SUPPORTED);
}
WEAK esp_err_t esp_wifi_remote_set_ant_gpio(const wifi_ant_gpio_config_t *config)
{
LOG_UNSUPPORTED_AND_RETURN(ESP_ERR_NOT_SUPPORTED);
}
WEAK esp_err_t esp_wifi_remote_get_ant_gpio(wifi_ant_gpio_config_t *config)
{
LOG_UNSUPPORTED_AND_RETURN(ESP_ERR_NOT_SUPPORTED);
}
WEAK esp_err_t esp_wifi_remote_set_ant(const wifi_ant_config_t *config)
{
LOG_UNSUPPORTED_AND_RETURN(ESP_ERR_NOT_SUPPORTED);
}
WEAK esp_err_t esp_wifi_remote_get_ant(wifi_ant_config_t *config)
{
LOG_UNSUPPORTED_AND_RETURN(ESP_ERR_NOT_SUPPORTED);
}
WEAK int64_t esp_wifi_remote_get_tsf_time(wifi_interface_t interface)
{
LOG_UNSUPPORTED_AND_RETURN(-1);

View File

@ -267,26 +267,6 @@ esp_err_t esp_wifi_set_csi(_Bool en)
return esp_wifi_remote_set_csi(en);
}
esp_err_t esp_wifi_set_ant_gpio(const wifi_ant_gpio_config_t *config)
{
return esp_wifi_remote_set_ant_gpio(config);
}
esp_err_t esp_wifi_get_ant_gpio(wifi_ant_gpio_config_t *config)
{
return esp_wifi_remote_get_ant_gpio(config);
}
esp_err_t esp_wifi_set_ant(const wifi_ant_config_t *config)
{
return esp_wifi_remote_set_ant(config);
}
esp_err_t esp_wifi_get_ant(wifi_ant_config_t *config)
{
return esp_wifi_remote_get_ant(config);
}
int64_t esp_wifi_get_tsf_time(wifi_interface_t interface)
{
return esp_wifi_remote_get_tsf_time(interface);

View File

@ -0,0 +1,5 @@
# This project serves as a demo to enable using esp-mqtt on ESP platform targets as well as on linux
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(esp_mqtt_demo)

View File

@ -0,0 +1,31 @@
# MQTT application running on WiFi station
This is a simple mqtt demo, that connects to WiFi AP first. This application has a dependency to `esp_wifi_remote`, so that if it's build and executed on a chipset without WiFI capabilities it redirects all wifi calls the remote target.
## Overview
When running this example on a target that doesn't natively support WiFi, please make sure that the remote target (slave application) is connected to your chipset via the configured transport interface.
Connection to the slave device also depends on RPC library used. It is recommended to use [`esp_hosted`](https://github.com/espressif/esp-hosted). Alternatively you can use [`eppp_link`](https://components.espressif.com/components/espressif/eppp_link).
Please note, that `esp_hosted` as a component is currently WIP, so the `wifi_remote` defaults to `eppp`, for now.
## HW connection
We currently support only `UART` transport, so the connection is very simple. You only need to connect Rx, Tx and GND with the remote target.
You need to configure these fields according to your connection:
* CONFIG_ESP_WIFI_REMOTE_EPPP_UART_TX_PIN
* CONFIG_ESP_WIFI_REMOTE_EPPP_UART_RX_PIN
## SW configuration
The RPC mechanism between the host and the slave micro uses TLS with mutual authentication, so you would have to configure certificates and keys for both parties. This application -- host target -- is considered RPC client, so it needs client's certificate and key, as well as the CA certificate to validate the server (slave application).
If self-signed certificates are acceptable, you can use [generate_test_certs](../test_certs/generate_test_certs.sh) script to generate both the CA and the keys itself and convert them to the PEM format that's accepted by the EPPP RPC engine.
You will have to configure these options:
* CONFIG_ESP_WIFI_REMOTE_EPPP_SERVER_CA
* CONFIG_ESP_WIFI_REMOTE_EPPP_CLIENT_CRT
* CONFIG_ESP_WIFI_REMOTE_EPPP_CLIENT_KEY
## Setting up slave device
You need to set up the connection and configuration in a similar way on the slave part (connection pins + certificates and keys). Please refer to the [slave_application](../server/README.md) README for more information.

View File

@ -0,0 +1,4 @@
idf_component_register(SRCS "app_main.c"
INCLUDE_DIRS ".")
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")

View File

@ -0,0 +1,21 @@
menu "Example Configuration"
config BROKER_URL
string "Broker URL"
default "mqtt://mqtt.eclipseprojects.io"
help
URL of the broker to connect to
config ESP_WIFI_SSID
string "WiFi SSID"
default "myssid"
help
SSID (network name) for the example to connect to.
config ESP_WIFI_PASSWORD
string "WiFi Password"
default "mypassword"
help
WiFi password (WPA or WPA2) for the example to use.
endmenu

View File

@ -0,0 +1,204 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include "esp_system.h"
#include "nvs_flash.h"
#include "esp_event.h"
#include "esp_netif.h"
#include "esp_netif.h"
#include "esp_system.h"
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_log.h"
#include "mqtt_client.h"
static const char *TAG = "esp_mqtt_demo";
static EventGroupHandle_t s_wifi_event_group;
static int s_retry_num = 0;
#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT BIT1
#define EXAMPLE_ESP_WIFI_SSID CONFIG_ESP_WIFI_SSID
#define EXAMPLE_ESP_WIFI_PASS CONFIG_ESP_WIFI_PASSWORD
#define EXAMPLE_ESP_MAXIMUM_RETRY 5
static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
{
ESP_LOGD(TAG, "Event dispatched from event loop base=%s, event_id=%d", base, event_id);
esp_mqtt_event_handle_t event = (esp_mqtt_event_handle_t)event_data;
esp_mqtt_client_handle_t client = event->client;
int msg_id;
switch ((esp_mqtt_event_id_t)event_id) {
case MQTT_EVENT_CONNECTED:
ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
msg_id = esp_mqtt_client_publish(client, "/topic/qos1", "data_3", 0, 1, 0);
ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);
msg_id = esp_mqtt_client_subscribe(client, "/topic/qos0", 0);
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
msg_id = esp_mqtt_client_subscribe(client, "/topic/qos1", 1);
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
msg_id = esp_mqtt_client_unsubscribe(client, "/topic/qos1");
ESP_LOGI(TAG, "sent unsubscribe successful, msg_id=%d", msg_id);
break;
case MQTT_EVENT_DISCONNECTED:
ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
break;
case MQTT_EVENT_SUBSCRIBED:
ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id);
msg_id = esp_mqtt_client_publish(client, "/topic/qos0", "data", 0, 0, 0);
ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);
break;
case MQTT_EVENT_UNSUBSCRIBED:
ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);
break;
case MQTT_EVENT_PUBLISHED:
ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
break;
case MQTT_EVENT_DATA:
ESP_LOGI(TAG, "MQTT_EVENT_DATA");
printf("TOPIC=%.*s\r\n", event->topic_len, event->topic);
printf("DATA=%.*s\r\n", event->data_len, event->data);
break;
case MQTT_EVENT_ERROR:
ESP_LOGI(TAG, "MQTT_EVENT_ERROR");
break;
default:
ESP_LOGI(TAG, "Other event id:%d", event->event_id);
break;
}
}
static void mqtt_app_start(void)
{
esp_mqtt_client_config_t mqtt_cfg = {};
mqtt_cfg.broker.address.uri = CONFIG_BROKER_URL;
mqtt_cfg.credentials.client_id = "idf_on_linux_client";
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);
/* The last argument may be used to pass data to the event handler, in this example mqtt_event_handler */
esp_mqtt_client_register_event(client, (esp_mqtt_event_id_t)ESP_EVENT_ANY_ID, mqtt_event_handler, NULL);
esp_mqtt_client_start(client);
}
static void event_handler(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data)
{
ESP_LOGI(TAG, "EVENT type %s id %d", event_base, (int)event_id);
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
esp_wifi_connect();
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
if (s_retry_num < EXAMPLE_ESP_MAXIMUM_RETRY) {
esp_wifi_connect();
s_retry_num++;
ESP_LOGI(TAG, "retry to connect to the AP");
} else {
xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
}
ESP_LOGI(TAG, "connect to the AP fail");
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data;
ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
s_retry_num = 0;
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
}
}
static void wifi_init_sta()
{
s_wifi_event_group = xEventGroupCreate();
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
esp_netif_create_default_wifi_sta();
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
esp_event_handler_instance_t instance_any_id;
esp_event_handler_instance_t instance_got_ip;
ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
ESP_EVENT_ANY_ID,
&event_handler,
NULL,
&instance_any_id));
ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
IP_EVENT_STA_GOT_IP,
&event_handler,
NULL,
&instance_got_ip));
wifi_config_t wifi_config = {
.sta = {
.ssid = EXAMPLE_ESP_WIFI_SSID,
.password = EXAMPLE_ESP_WIFI_PASS,
},
};
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );
ESP_ERROR_CHECK(esp_wifi_start() );
ESP_LOGI(TAG, "wifi_init_sta finished.");
/* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum
* number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */
EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
pdFALSE,
pdFALSE,
portMAX_DELAY);
/* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually
* happened. */
if (bits & WIFI_CONNECTED_BIT) {
ESP_LOGI(TAG, "connected to ap SSID:%s password:%s",
EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
} else if (bits & WIFI_FAIL_BIT) {
ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s",
EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
} else {
ESP_LOGE(TAG, "UNEXPECTED EVENT");
}
}
void app_main(void)
{
ESP_LOGI(TAG, "[APP] Startup..");
ESP_LOGI(TAG, "[APP] Free memory: %d bytes", esp_get_free_heap_size());
ESP_LOGI(TAG, "[APP] IDF version: %s", esp_get_idf_version());
esp_log_level_set("*", ESP_LOG_INFO);
esp_log_level_set("mqtt_client", ESP_LOG_VERBOSE);
esp_log_level_set("esp_mqtt_demo", ESP_LOG_VERBOSE);
esp_log_level_set("transport_base", ESP_LOG_VERBOSE);
esp_log_level_set("esp-tls", ESP_LOG_VERBOSE);
esp_log_level_set("transport", ESP_LOG_VERBOSE);
esp_log_level_set("outbox", ESP_LOG_VERBOSE);
//Initialize NVS
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
ESP_LOGI(TAG, "ESP_WIFI_MODE_STA");
wifi_init_sta();
mqtt_app_start();
}

View File

@ -0,0 +1,4 @@
dependencies:
esp_wifi_remote:
version: "*"
override_path: ../../..

View File

@ -0,0 +1,5 @@
CONFIG_ESP_WIFI_REMOTE_EPPP_UART_TX_PIN=17
CONFIG_ESP_WIFI_REMOTE_EPPP_UART_RX_PIN=16
CONFIG_ESP_WIFI_REMOTE_EPPP_SERVER_CA="MIIDIzCCAgugAwIBAgIULOncUeRLKxgrihIh1kHGGlPV7ecwDQYJKoZIhvcNAQELBQAwITELMAkGA1UEBhMCQ1oxEjAQBgNVBAMMCUVzcHJlc3NpZjAeFw0yNDA0MDMwOTE0MjNaFw0zNDA0MDEwOTE0MjNaMCExCzAJBgNVBAYTAkNaMRIwEAYDVQQDDAlFc3ByZXNzaWYwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCbayaZAuzQWrwRj3oiFP9AZK0ECaDvVlJec4M6yokded1pqNY+bNmA7VsHSQkf3d1rO1G5GwEXoMPli15m7rJodq9iYp1J2LhLhpKDNapm19reyH9A4rAfjSyk/WyvT+3Y5sNHVFdE2t1EetOyzy90CfOHT9JfWG9PiV6b1W65CqgjJVCHMWioppVAGQCoN+mDBf1VhD4am6onei+ijHdALJDfp74mSIOJGulm/IR7504s+yy7068PQ05V/wHkmd9O1Iww5fnJdRh2KvTFZVOB5u9y54MTJb0sGZj+JfxIbcFiIWAykLFVWBk5PO6yj8fNMmk/Ogb2K4wo7AZnJ3qBAgMBAAGjUzBRMB0GA1UdDgQWBBT3j77hJHm/hI34fEn3tocHqB4INzAfBgNVHSMEGDAWgBT3j77hJHm/hI34fEn3tocHqB4INzAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBstXfBIRvqZp4OBQ2kCJig/CErcfdB4qQOS2LzQmpIOUQ4d/zvZOQD2WIw/x2Rd1/hto/+f57pOZNHsi8vfX2Z7kPOlD9ZG1wTznl1v8wOMP01AFJuVtmJQV0C4lVupb2/Mmu42xqP9pr/uL5pJ2rFb8ujl2xakhSvYVdMONtZL0mh9+hdnUb7Fj7KI3qWxzc7+uXGjCzh6LkOmcMBOB6+0V6xW2NVpUUPtuXytK0t2oyWpDvwFIrl0J6qBNRlH1ON1iz33HOo73IjprMNx3hIo5y/N8+TTxY6KEegbP67hSnJJhQ7tezoOu4OE0xmJp0XmGPMNewYARqL2UvHnZyf"
CONFIG_ESP_WIFI_REMOTE_EPPP_CLIENT_CRT="MIICwjCCAaoCFAWE4aJdYWbMJAaBTMxVpoXMrhzvMA0GCSqGSIb3DQEBCwUAMCExCzAJBgNVBAYTAkNaMRIwEAYDVQQDDAlFc3ByZXNzaWYwHhcNMjQwNDAzMDkxNjE4WhcNMzQwNDAxMDkxNjE4WjAaMRgwFgYDVQQDDA9lc3ByZXNzaWYubG9jYWwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDcjdBQ3sHbfuWRo2LlqZF37Dfuymz5/fq+szcOLUUWCccxku9qNNEdZAcZHMsINurezpHXa6ZNKGqmbmqZPVrEKzMUIolpnQmcerRt/yKqxCZ/kgsJE3IZyqi1T+xDwaBEhgdB6+wxyrL0/uBlLCbEdZAA7MPcauIKz8ykfIwo7Ht/vcHNxGaFFu+DcNoJI/Pw6hERlC9DHuUftK0/Lap1K2o+6kFQKqhVrvNQmaiqnz3Dr9psPO90AvbRqeODmfpi7rtU4MKOprQhUrMS9s9d5yVdJILp74pt6nzu3EnFiixRD5XD9PtK5NvP1sgDAgbWgTttwM9X7N6mzEe/gVUZAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAJVsbAamDRuZ1J2ogHLo/UmjmcmIATmqO7Ebaoid7+FYme/2NFzofOFtJNaCumdhwxSyf7ER6m2DUO6bDseblqNCTyRDNNXzTHEFQiYh2PThKSDdH0fbEf4IpcbOCnpSEpIg9C/ywEhq/wzYiOlxPhNWxBKHLhEkM7aWBerAhInCRRXymfus2HUf6aTWZ0wigMoUVKwOu16Zh04D2d6qb314cEMgKvANPiTTdgEae7Ot+rP1s2Zp75zUbWuz4uWd4wJDOHWR25mkD3ZELfbrpmEymbOTQ26zOpIUiPNfYZ1t9KwEjkKN+jBTXKu7QhB/u+g5yBHjRL++LEli4YGGGiA="
CONFIG_ESP_WIFI_REMOTE_EPPP_CLIENT_KEY="MIIEpQIBAAKCAQEA3I3QUN7B237lkaNi5amRd+w37sps+f36vrM3Di1FFgnHMZLvajTRHWQHGRzLCDbq3s6R12umTShqpm5qmT1axCszFCKJaZ0JnHq0bf8iqsQmf5ILCRNyGcqotU/sQ8GgRIYHQevsMcqy9P7gZSwmxHWQAOzD3GriCs/MpHyMKOx7f73BzcRmhRbvg3DaCSPz8OoREZQvQx7lH7StPy2qdStqPupBUCqoVa7zUJmoqp89w6/abDzvdAL20anjg5n6Yu67VODCjqa0IVKzEvbPXeclXSSC6e+Kbep87txJxYosUQ+Vw/T7SuTbz9bIAwIG1oE7bcDPV+zepsxHv4FVGQIDAQABAoIBAQDPzzc224yg+iHoZaArcOhFrGbPMiAYNLxrroTzcKglqbTr+txmn7lhDfy6Jq0O4l/O66fy59Vb4fcLNgJuvKanK2UHVbtPrc1+iQc0lS7e4866aKrJNG9P6emoXNPqy6fsqLRx4o88IxcXTIe2DDHC7lpu5KdvKa4uLblOSqPtcZTHXPD9olVe8ZYF5CttMUTc4SkF4HSkY2jb0j+6kASN4eQ2CqEt+IW4IxI5NiEzrlzZSOdyqIOeyGUZz+QcfILOProWZHYzH3jOHQe4PJSXO57f2dojY1GqRcjnr3guQMpw1s7wmDYO1QekiBYwRERNzjEY7VhgDq8T0rwJPHP5AoGBAPO13QpJVSj1NfQ/H0AgZlsJIIlIwIC2YwuwjA7b36A3JOFolkHjtq4eNntThNRQbTL9OficbxJSHXQcOsQeo7dvwEhJjuVwEajL4/6cjc9b4oyGJxLlTKTshUPmeKPfGWUjRZKGbVWbT3m4BXqGiv4laCZ0LDHiCt4DvEzQ1Bo3AoGBAOetBClbcbUJhxkAme5HHI9A5VcqyOi2CrRh+HjKd/2IJlDA+Vmbl2iEB+9cMRGRubazbrk1yAzgtW29GX8kngr8yxDtIM8M7lPR2NhXx7XbmCKwKosZ7l6hHNdnD12TFyLCjuuJlUA37sWXw8r33623mLFQlNVjnL0onUa1XSMvAoGACw47+cR73YDKMstOQp11pzmRxUiMmworEhOvNtlYmq8FuEgDUPfgiKOMOyn9w5fmbEK6h4GpND6PYX4KWG0/ZgnmwiC8H8Jmuq6NKDa35Ck57MAFM8E9Kdok7YCeBmkPgNwJwuzgNtr1zwK/FODXm1HdGKl6e8TSU2H9/8oVZR8CgYEAoHSWI0awNCCLLufZtMwPna/mpz58s6ARPel0u8QO4st/LgLZMBSxArQfAsqpOW/iXgVcNG5pRXIEdiK4G/TyeM2onup9BKoCDo+SThRNv0h9z9iPPpQRIf0YCp/YZojPR0XU0pERi86xUqzP8C1I//neiUA0NK6vCdutQiGuhgUCgYEAp89EFcM1WvtPRJE+md8N8BUef5MJ+JJ0nb+BW1kkLY50Q1MVmsVXdUowYupWLBgEfMn8fy8Q+xD9EeiISTF9MtT1X4iQSI/pzKW5LLd0OJYnqPMWzyggASzSNWdYBIGNkqsQGmGCtF9+i6V4acfTTbMD9LiB7u5/enQa8N0Qg+s="

View File

@ -0,0 +1,3 @@
CONFIG_LWIP_PPP_SUPPORT=y
CONFIG_LWIP_PPP_SERVER_SUPPORT=y
CONFIG_LWIP_PPP_VJ_HEADER_COMPRESSION=n

View File

@ -0,0 +1,6 @@
# 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.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(pppos_slave)

View File

@ -0,0 +1,21 @@
# WiFi remote EPPP RPC server
This is a standalone application serving as the slave device for `esp_wifi_remote` users (with `eppp` RPC).
## Overview
You need to configure and connect a slave device to the `esp_wifi_remote` host and run this application. Please fallow carefully these guidelines on HW connection and configuration of the slave device, based on the host device.
## HW connection
We currently support only `UART` transport you just need to connect Rx, Tx and GND and configure these fields accordingly:
* CONFIG_ESP_WIFI_REMOTE_EPPP_UART_TX_PIN
* CONFIG_ESP_WIFI_REMOTE_EPPP_UART_RX_PIN
## SW configuration
You will have to install server side certificates and keys, as well as the CA which should verify the client side.
Please configure these options:
* CONFIG_ESP_WIFI_REMOTE_EPPP_CLIENT_CA
* CONFIG_ESP_WIFI_REMOTE_EPPP_SERVER_CRT
* CONFIG_ESP_WIFI_REMOTE_EPPP_SERVER_KEY

View File

@ -0,0 +1,2 @@
idf_component_register(SRCS "station_example_main.c"
INCLUDE_DIRS ".")

View File

@ -0,0 +1,4 @@
dependencies:
esp_wifi_remote:
version: "*"
override_path: ../../..

View File

@ -0,0 +1,36 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <string.h>
#include <esp_private/wifi.h>
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "eppp_link.h"
#include "esp_wifi_remote.h"
esp_err_t server_init(void);
void app_main(void)
{
//Initialize NVS
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
esp_netif_create_default_wifi_sta();
server_init();
}

View File

@ -0,0 +1,6 @@
CONFIG_IDF_TARGET="esp32c6"
CONFIG_ESP_WIFI_REMOTE_EPPP_UART_TX_PIN=22
CONFIG_ESP_WIFI_REMOTE_EPPP_UART_RX_PIN=23
CONFIG_ESP_WIFI_REMOTE_EPPP_CLIENT_CA="MIIDIzCCAgugAwIBAgIUTWOEAhITHAm2ixn5i2XlSeL01mowDQYJKoZIhvcNAQELBQAwITELMAkGA1UEBhMCQ1oxEjAQBgNVBAMMCUVzcHJlc3NpZjAeFw0yNDA0MTAxNTEzNTdaFw0yNTA0MTAxNTEzNTdaMCExCzAJBgNVBAYTAkNaMRIwEAYDVQQDDAlFc3ByZXNzaWYwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCSewupiSiyZNfLdVW0/smQB0yJ0Ua0KNU423ZZ7HMSrBPhfHtnQQ6SJqTdfqGCl1lvSsJZN9aT4iaEtyAm6N9trmSbSWVlkn0D8MQuBHwHCT7jRsLnyRYURRPUs11TkQdqvxtsIFqFVFB/8nJqy4IuU6JFTobCbUappQMdHKCyidXJUVHZ5y+KK2kEYFiv26rHlry+D0O/VO5/xl97uFIzP0JVdnGNu5sy9uoRYp+ua0moD3tx12tYe83XIuHKbKHMpIayjPIoaZzhCwomZMh0NETEQ5t7RXYneRGZvXXyIb/O8jPCmbfSqJ6umhPhf757xBXHaC0iG/xlND0dnRIvAgMBAAGjUzBRMB0GA1UdDgQWBBTgqejeFi/5UAgNhNv4aH7UniqmQjAfBgNVHSMEGDAWgBTgqejeFi/5UAgNhNv4aH7UniqmQjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCQnqIue6KLXkjOXGtO5Bl4TkZpYAPkQuGiM6RgaBhdt3P5J1mF4T6aav8qGXSHShy1E3XkMR5OC3hkhG+FKBVKSaQLsRipuo+CeHp5RfOCNEzNI0RZwKJI92RcdWlhOA+pOTruXSoYuZvj0xnaePEghTrr7PLdgirpzIffLjvgh8BcQAz5QzP0U1XHkAVzbQjUBChiEiXVAlKChk7kKB/wEzwX3cvYKlTc89RB6I3+a+KhYJt3LIAOIDeyVp+Bhmb1JSo3H7zMpJAksG2RMnZCwlHeR6cMbb/OtJYeUKpNUxj0SaeNyHo3y8Q21G8TXcc9suU6sYJi780ArulC3cbQ"
CONFIG_ESP_WIFI_REMOTE_EPPP_SERVER_CRT="MIICvzCCAacCFCanehvaDq0bhjZA/3W/h4b0p1VHMA0GCSqGSIb3DQEBCwUAMCExCzAJBgNVBAYTAkNaMRIwEAYDVQQDDAlFc3ByZXNzaWYwHhcNMjQwNDEwMTUxMzU3WhcNMjUwNDEwMTUxMzU3WjAXMRUwEwYDVQQDDAwxOTIuMTY4LjExLjEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsyR1FqBhBT3mr9AH/6iYoo1VCHbzB+V/StfCokv6LnMm6t7yiu1GgzqVk1aiHrUJGor5tBfpXywLnfVjFByZSBhhEkI26xQVdK5pZUsU1hMCJ6CWd105CD+0e5tTbGzF0PNH2KzFdg2YUqOSWBsfmgSNtnp3az8XmZN5i4958Sxe1kMN3f6EQwvkxZHGVgXCrUsdsHAEyV5NVfYq7P2nBxz3HJSGkTScFd+PRp3nfVFbBbCQDmqwoPZ7E/gUXjoLIFf7zjIMzCXTsZd/dKgXWWEFHq8SPWmLtAEvPCProT5QUaZ3gJSHup9Wmh+ok9W8wrwMj1sHlfiZWo3tatFmvAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAAeWiWyTTyNbZRHq8X9qbr7oG6SYWOqDR3lPfs8wB8B+1Hez/JCrI/8quNqVAjhoTtebtp/2mcEseQDj5BOx8NBCDAmUOwB+ZKPzUoGiALy5XFGqUXzTv9tBMotC6dAMTIbT2Ql1mPJgtg2+Qv7vg6hsk4rlPMoICqN3lW6zXo2GOuJ56Tj5NkvVxv6MOVN2e3p67c92rRBysAxP6MaV8S9s2+VvnENuxpU5cq8sfzaxFkTn4UD9PoQSYGPNL9kv7Y/h7H5wlKiFY24KowPTHjulaH/DC9Fk4F1gNWjnkFcOgepzhiw/ibLrivMptUFtplFFbxGuwY5PaA26yhliBv8="
CONFIG_ESP_WIFI_REMOTE_EPPP_SERVER_KEY="MIIEowIBAAKCAQEArMkdRagYQU95q/QB/+omKKNVQh28wflf0rXwqJL+i5zJure8ortRoM6lZNWoh61CRqK+bQX6V8sC531YxQcmUgYYRJCNusUFXSuaWVLFNYTAieglnddOQg/tHubU2xsxdDzR9isxXYNmFKjklgbH5oEjbZ6d2s/F5mTeYuPefEsXtZDDd3+hEML5MWRxlYFwq1LHbBwBMleTVX2Kuz9pwcc9xyUhpE0nBXfj0ad531RWwWwkA5qsKD2exP4FF46CyBX+84yDMwl07GXf3SoF1lhBR6vEj1pi7QBLzwj66E+UFGmd4CUh7qfVpofqJPVvMK8DI9bB5X4mVqN7WrRZrwIDAQABAoIBAHDh833OlAoXIiZ1A9lt4AAstUa8ptUTVscSlmeLoUEU7bZO0659MpccanG2JKR/TQ1YxY/0l9lDiGI0Qgp24VI1KSWiSvX6Qcbc9bnlmXGdiSyPvgOg5j/Cp+fIZse+vFB0a7eoAFhXwBk/PhfF1lOBiuPS/M43b9NVkvSIapJIaS4pvmkBvKSzHEvSArDHcr+1vFuFssZyHTnXmVgB4WiYPX4ACE8S18cnjXIQDfx8zpBbF/itnqeHDC5echnto63UDB7qHZa+DVvakhEtv50rzAuhq3/uspBClucuQUhlAAimd4OeKuwB1UC0K9AamDZRCnsf0O/Bo8/W4SWYAgECgYEA5LpRmcQ9ghW8V6bzwYvK8XGWyeNy94qOpZysFeOjxqe2sUTHVY2Ty1s44RbDd/bm0n3xcxMtLof/6Oz4TX+JseskQWBQlRiwuqc46CcHHjUQ8qokfWtASwWYgb6AzLa4B/D+H91wP/AzRfYNdRB9xhSCr7AOk9Vo5KmEPRLN/VMCgYEAwWM3oDaCkMicoMgngz/9dZ2/1yohfYdrupC0pGPhtBFNKghP+9S+e6cwWKzwQJbbRjGgt1OA3e4UEuTHJjp1tw+BRkNQ/1FI0psJGwmOtveAE7yiHf7Tw7mNDk+j32vpAPWnL7I3222Kv4G8xi2vSbn3IaI2sl7M0RHLJc/JCrUCgYBh4dI16aMg3khhglLiSv6oYKHU9/8lLChreyaxn19hDjjCl9puJE5RQlKPEPzJg+G3xqnjQxucxBqiBXclQyUb/LLhP2R8ybonxpQ11S3YoYEFOAaxnYpAEL75Fxtrf+41h85YuJzm39YxZGDR7iLE99YNdVxnq3ZeFKVAtaFtfQKBgEalPRvc7eOANZ+SnsSWqru9regnLubRgqw70pG/HyONsnepY7amaBN55vJt8rJVqbLBzGlMKuZn45NnWc0ATCJcmqgVTVCH3Cd7lV74Jdd3IKWVIk/82FVGwl25AC9NF2hPVQzaeQdCxA3jkhd/dupi8gGqZXrRoNa7PlAI0POFAoGBAJDlvddpEYcKhT3pncXIorVfYR67TlXVcKZHvL9XljwgDuf1j52ZhAs8UuoWW+NSgOdWVxocAshrLbu5fjSIN92oDAq6YVeXvxis6e8l79xd6A5iFH9Po+dEuQSaOR8XgW56n39oVR2hfaFwqijawIEzDNlYpiXAD3qNyW5e0MKA"

View File

@ -0,0 +1,6 @@
CONFIG_LWIP_IP_FORWARD=y
CONFIG_LWIP_IPV4_NAPT=y
CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=4096
CONFIG_LWIP_PPP_SUPPORT=y
CONFIG_LWIP_PPP_SERVER_SUPPORT=y
CONFIG_LWIP_PPP_VJ_HEADER_COMPRESSION=n

View File

@ -0,0 +1,52 @@
#!/usr/bin/env bash
function gen_pkey { # Params: [KEY_FILE]
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 | openssl pkcs8 -topk8 -outform PEM -nocrypt -out $1
}
function sign_with_ca { # Params: [KEY_FILE] [CN] [CRT_FILE]
openssl req -out request.csr -key $1 -subj "/CN=$2" -new -sha256
openssl x509 -req -in request.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out $3 -days 365 -sha256
}
function export_config { # Params: [FILE/CONFIG_NAME]
content=`cat $1 | sed '/---/d' | tr -d '\n'`
echo "CONFIG_ESP_WIFI_REMOTE_EPPP_$1=\"${content}\""
}
if [ -z "$1" ]; then
echo "Usage $0 <SERVER_CN> [CLIENT_CN]"
exit 1;
fi
SERVER_CN=$1
CLIENT_CN="${2-client_cn}"
echo "Server's CN: $SERVER_CN"
echo "Client's CN: $CLIENT_CN"
## First create our own CA
gen_pkey ca.key
openssl req -new -x509 -subj "/C=CZ/CN=Espressif" -days 365 -key ca.key -out ca.crt
# will use the same CA for both server and client side
cp ca.crt SERVER_CA
cp ca.crt CLIENT_CA
# Server side
gen_pkey SERVER_KEY
sign_with_ca SERVER_KEY $SERVER_CN SERVER_CRT
# Client side
gen_pkey CLIENT_KEY
sign_with_ca CLIENT_KEY $CLIENT_CN CLIENT_CRT
## Generate config options
echo -e "\n# Client side: need own cert and key and ca-cert for server validation"
for f in SERVER_CA CLIENT_CRT CLIENT_KEY; do
export_config $f
done
echo -e "\n# Server side: need own cert and key and ca-cert for client validation"
for f in CLIENT_CA SERVER_CRT SERVER_KEY; do
export_config $f
done

View File

@ -1,8 +1,10 @@
version: 0.1.12
version: 0.2.3
url: https://github.com/espressif/esp-protocols/tree/master/components/esp_wifi_remote
description: Utility wrapper for esp_wifi functionality on remote targets
dependencies:
espressif/eppp_link:
version: '>=0.1'
idf:
version: '5.3'
version: '>=5.3'
# espressif/esp_hosted:
# version: '*'

View File

@ -57,10 +57,6 @@ esp_err_t esp_wifi_remote_80211_tx(wifi_interface_t ifx, const void *buffer, int
esp_err_t esp_wifi_remote_set_csi_rx_cb(wifi_csi_cb_t cb, void *ctx);
esp_err_t esp_wifi_remote_set_csi_config(const wifi_csi_config_t *config);
esp_err_t esp_wifi_remote_set_csi(_Bool en);
esp_err_t esp_wifi_remote_set_ant_gpio(const wifi_ant_gpio_config_t *config);
esp_err_t esp_wifi_remote_get_ant_gpio(wifi_ant_gpio_config_t *config);
esp_err_t esp_wifi_remote_set_ant(const wifi_ant_config_t *config);
esp_err_t esp_wifi_remote_get_ant(wifi_ant_config_t *config);
int64_t esp_wifi_remote_get_tsf_time(wifi_interface_t interface);
esp_err_t esp_wifi_remote_set_inactive_time(wifi_interface_t ifx, uint16_t sec);
esp_err_t esp_wifi_remote_get_inactive_time(wifi_interface_t ifx, uint16_t *sec);

View File

@ -15,6 +15,7 @@ Param = namedtuple('Param', ['ptr', 'array', 'qual', 'type', 'name'])
AUTO_GENERATED = 'This file is auto-generated'
COPYRIGHT_HEADER = open('copyright_header.h', 'r').read()
NAMESPACE = re.compile(r'^esp_wifi')
DEPRECATED_API = ['esp_wifi_set_ant_gpio', 'esp_wifi_get_ant', 'esp_wifi_get_ant_gpio', 'esp_wifi_set_ant']
class FunctionVisitor(c_ast.NodeVisitor):
@ -51,6 +52,8 @@ class FunctionVisitor(c_ast.NodeVisitor):
if isinstance(node.type, c_ast.TypeDecl):
func_name = node.type.declname
if func_name.startswith('esp_wifi') and func_name in self.content:
if func_name in DEPRECATED_API:
return
ret = node.type.type.names[0]
args = []
for param in node.args.params:
@ -309,6 +312,7 @@ def generate_kconfig(idf_path, component_path):
f.write(' bool\n')
f.write(' default y\n\n')
f.write(' orsource "./Kconfig.soc_wifi_caps.in"\n')
f.write(' orsource "./Kconfig.rpc.in"\n')
for line1 in lines:
line = line1.strip()
if re.match(r'^if\s+[A-Z_0-9]+\s*$', line):
@ -322,7 +326,7 @@ def generate_kconfig(idf_path, component_path):
line1 = re.compile(config).sub('SLAVE_' + config, line1)
f.write(line1)
if line.startswith('if ESP_WIFI_ENABLED'):
if re.match(r'^if\s+\(?ESP_WIFI_ENABLED', line):
copy = nested_if
f.write('endmenu # Wi-Fi Remote\n')
return [remote_kconfig]

View File

@ -17,5 +17,7 @@ menu "ESP Hosted Mock"
bool "esp32c6"
config SLAVE_IDF_TARGET_ESP32H2
bool "esp32h2"
config SLAVE_IDF_TARGET_ESP32P4
bool "esp32p4"
endchoice
endmenu

View File

@ -267,26 +267,6 @@ esp_err_t esp_wifi_remote_set_csi(_Bool en)
return ESP_OK;
}
esp_err_t esp_wifi_remote_set_ant_gpio(const wifi_ant_gpio_config_t *config)
{
return ESP_OK;
}
esp_err_t esp_wifi_remote_get_ant_gpio(wifi_ant_gpio_config_t *config)
{
return ESP_OK;
}
esp_err_t esp_wifi_remote_set_ant(const wifi_ant_config_t *config)
{
return ESP_OK;
}
esp_err_t esp_wifi_remote_get_ant(wifi_ant_config_t *config)
{
return ESP_OK;
}
int64_t esp_wifi_remote_get_tsf_time(wifi_interface_t interface)
{
return 0;

View File

@ -57,10 +57,6 @@ esp_err_t esp_wifi_remote_80211_tx(wifi_interface_t ifx, const void *buffer, int
esp_err_t esp_wifi_remote_set_csi_rx_cb(wifi_csi_cb_t cb, void *ctx);
esp_err_t esp_wifi_remote_set_csi_config(const wifi_csi_config_t *config);
esp_err_t esp_wifi_remote_set_csi(_Bool en);
esp_err_t esp_wifi_remote_set_ant_gpio(const wifi_ant_gpio_config_t *config);
esp_err_t esp_wifi_remote_get_ant_gpio(wifi_ant_gpio_config_t *config);
esp_err_t esp_wifi_remote_set_ant(const wifi_ant_config_t *config);
esp_err_t esp_wifi_remote_get_ant(wifi_ant_config_t *config);
int64_t esp_wifi_remote_get_tsf_time(wifi_interface_t interface);
esp_err_t esp_wifi_remote_set_inactive_time(wifi_interface_t ifx, uint16_t sec);
esp_err_t esp_wifi_remote_get_inactive_time(wifi_interface_t ifx, uint16_t *sec);

View File

@ -280,26 +280,6 @@ void run_all_wifi_apis(void)
esp_wifi_set_csi(en);
}
{
const wifi_ant_gpio_config_t *config = NULL;
esp_wifi_set_ant_gpio(config);
}
{
wifi_ant_gpio_config_t *config = NULL;
esp_wifi_get_ant_gpio(config);
}
{
const wifi_ant_config_t *config = NULL;
esp_wifi_set_ant(config);
}
{
wifi_ant_config_t *config = NULL;
esp_wifi_get_ant(config);
}
{
wifi_interface_t interface = 0;
esp_wifi_get_tsf_time(interface);

View File

@ -280,26 +280,6 @@ void run_all_wifi_remote_apis(void)
esp_wifi_remote_set_csi(en);
}
{
const wifi_ant_gpio_config_t *config = NULL;
esp_wifi_remote_set_ant_gpio(config);
}
{
wifi_ant_gpio_config_t *config = NULL;
esp_wifi_remote_get_ant_gpio(config);
}
{
const wifi_ant_config_t *config = NULL;
esp_wifi_remote_set_ant(config);
}
{
wifi_ant_config_t *config = NULL;
esp_wifi_remote_get_ant(config);
}
{
wifi_interface_t interface = 0;
esp_wifi_remote_get_tsf_time(interface);

View File

@ -2,7 +2,7 @@
dependencies:
## Required IDF version
idf:
version: "5.3"
version: '>=5.3'
espressif/esp_wifi_remote:
version: "*"
override_path: ../../..

View File

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

View File

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

View File

@ -1,5 +1,22 @@
# Changelog
## [1.3.2](https://github.com/espressif/esp-protocols/commits/mdns-v1.3.2)
### Features
- add check of instance when handling PTR query ([6af6ca5](https://github.com/espressif/esp-protocols/commit/6af6ca5))
### Bug Fixes
- Fix of mdns afl tests ([139166c](https://github.com/espressif/esp-protocols/commit/139166c))
- remove same protocol services with different instances ([042533a](https://github.com/espressif/esp-protocols/commit/042533a))
## [1.3.1](https://github.com/espressif/esp-protocols/commits/mdns-v1.3.1)
### Bug Fixes
- free txt value len ([afd98bb](https://github.com/espressif/esp-protocols/commit/afd98bb))
## [1.3.0](https://github.com/espressif/esp-protocols/commits/mdns-v1.3.0)
### Features

View File

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

View File

@ -1871,6 +1871,7 @@ static void _mdns_create_answer_from_parsed_packet(mdns_parsed_packet_t *parsed_
packet->id = parsed_packet->id;
mdns_parsed_question_t *q = parsed_packet->questions;
uint32_t out_record_nums = 0;
while (q) {
shared = q->type == MDNS_TYPE_PTR || q->type == MDNS_TYPE_SDPTR || !parsed_packet->probe;
if (q->type == MDNS_TYPE_SRV || q->type == MDNS_TYPE_TXT) {
@ -1878,14 +1879,36 @@ static void _mdns_create_answer_from_parsed_packet(mdns_parsed_packet_t *parsed_
if (service == NULL || !_mdns_create_answer_from_service(packet, service->service, q, shared, send_flush)) {
_mdns_free_tx_packet(packet);
return;
} else {
out_record_nums++;
}
} else if (q->service && q->proto) {
mdns_srv_item_t *service = _mdns_server->services;
while (service) {
if (_mdns_service_match_ptr_question(service->service, q)) {
if (!_mdns_create_answer_from_service(packet, service->service, q, shared, send_flush)) {
_mdns_free_tx_packet(packet);
return;
mdns_parsed_record_t *r = parsed_packet->records;
bool is_record_exist = false;
while (r) {
if (service->service->instance && r->host) {
if (_mdns_service_match_instance(service->service, r->host, r->service, r->proto, NULL) && r->ttl > (MDNS_ANSWER_PTR_TTL / 2)) {
is_record_exist = true;
break;
}
} else if (!service->service->instance && !r->host) {
if (_mdns_service_match(service->service, r->service, r->proto, NULL) && r->ttl > (MDNS_ANSWER_PTR_TTL / 2)) {
is_record_exist = true;
break;
}
}
r = r->next;
}
if (!is_record_exist) {
if (!_mdns_create_answer_from_service(packet, service->service, q, shared, send_flush)) {
_mdns_free_tx_packet(packet);
return;
} else {
out_record_nums++;
}
}
}
service = service->next;
@ -1894,22 +1917,31 @@ static void _mdns_create_answer_from_parsed_packet(mdns_parsed_packet_t *parsed_
if (!_mdns_create_answer_from_hostname(packet, q->host, send_flush)) {
_mdns_free_tx_packet(packet);
return;
} else {
out_record_nums++;
}
} else if (q->type == MDNS_TYPE_ANY) {
if (!_mdns_append_host_list(&packet->answers, send_flush, false)) {
_mdns_free_tx_packet(packet);
return;
} else {
out_record_nums++;
}
#ifdef CONFIG_MDNS_RESPOND_REVERSE_QUERIES
} else if (q->type == MDNS_TYPE_PTR) {
mdns_host_item_t *host = mdns_get_host_item(q->host);
if (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_PTR, NULL, host, send_flush, false)) {
_mdns_free_tx_packet(packet);
return;
} else {
out_record_nums++;
}
#endif /* CONFIG_MDNS_RESPOND_REVERSE_QUERIES */
} else if (!_mdns_alloc_answer(&packet->answers, q->type, NULL, NULL, send_flush, false)) {
_mdns_free_tx_packet(packet);
return;
} else {
out_record_nums++;
}
if (parsed_packet->src_port != MDNS_SERVICE_PORT && // Repeat the queries only for "One-Shot mDNS queries"
@ -1943,6 +1975,10 @@ static void _mdns_create_answer_from_parsed_packet(mdns_parsed_packet_t *parsed_
}
q = q->next;
}
if (out_record_nums == 0) {
_mdns_free_tx_packet(packet);
return;
}
if (unicast || !send_flush) {
memcpy(&packet->dst, &parsed_packet->src, sizeof(esp_ip_addr_t));
packet->port = parsed_packet->src_port;
@ -3336,7 +3372,11 @@ static bool _mdns_question_matches(mdns_parsed_question_t *question, uint16_t ty
&& !strcasecmp(service->service->service, question->service)
&& !strcasecmp(service->service->proto, question->proto)
&& !strcasecmp(MDNS_DEFAULT_DOMAIN, question->domain)) {
return true;
if (!service->service->instance) {
return true;
} else if (service->service->instance && question->host && !strcasecmp(service->service->instance, question->host)) {
return true;
}
}
} else if (service && (type == MDNS_TYPE_SRV || type == MDNS_TYPE_TXT)) {
const char *name = _mdns_get_service_instance_name(service->service);
@ -3635,6 +3675,7 @@ void mdns_parse_packet(mdns_rx_packet_t *packet)
parsed_packet->id = header.id;
esp_netif_ip_addr_copy(&parsed_packet->src, &packet->src);
parsed_packet->src_port = packet->src_port;
parsed_packet->records = NULL;
if (header.questions) {
uint8_t qs = header.questions;
@ -3821,7 +3862,12 @@ void mdns_parse_packet(mdns_rx_packet_t *packet)
_mdns_search_result_add_ptr(search_result, name->host, name->service, name->proto,
packet->tcpip_if, packet->ip_protocol, ttl);
} else if ((discovery || ours) && !name->sub && _mdns_name_is_ours(name)) {
if (discovery && (service = _mdns_get_service_item(name->service, name->proto, NULL))) {
if (name->host[0]) {
service = _mdns_get_service_item_instance(name->host, name->service, name->proto, NULL);
} else {
service = _mdns_get_service_item(name->service, name->proto, NULL);
}
if (discovery && service) {
_mdns_remove_parsed_question(parsed_packet, MDNS_TYPE_SDPTR, service);
} else if (service && parsed_packet->questions && !parsed_packet->probe) {
_mdns_remove_parsed_question(parsed_packet, type, service);
@ -3831,6 +3877,45 @@ void mdns_parse_packet(mdns_rx_packet_t *packet)
_mdns_remove_scheduled_answer(packet->tcpip_if, packet->ip_protocol, type, service);
}
}
if (service) {
mdns_parsed_record_t *record = malloc(sizeof(mdns_parsed_record_t));
if (!record) {
HOOK_MALLOC_FAILED;
goto clear_rx_packet;
}
record->next = parsed_packet->records;
parsed_packet->records = record;
record->type = MDNS_TYPE_PTR;
record->record_type = MDNS_ANSWER;
record->ttl = ttl;
record->host = NULL;
record->service = NULL;
record->proto = NULL;
if (name->host[0]) {
record->host = malloc(MDNS_NAME_BUF_LEN);
if (!record->host) {
HOOK_MALLOC_FAILED;
goto clear_rx_packet;
}
memcpy(record->host, name->host, MDNS_NAME_BUF_LEN);
}
if (name->service[0]) {
record->service = malloc(MDNS_NAME_BUF_LEN);
if (!record->service) {
HOOK_MALLOC_FAILED;
goto clear_rx_packet;
}
memcpy(record->service, name->service, MDNS_NAME_BUF_LEN);
}
if (name->proto[0]) {
record->proto = malloc(MDNS_NAME_BUF_LEN);
if (!record->proto) {
HOOK_MALLOC_FAILED;
goto clear_rx_packet;
}
memcpy(record->proto, name->proto, MDNS_NAME_BUF_LEN);
}
}
}
} else if (type == MDNS_TYPE_SRV) {
mdns_result_t *result = NULL;
@ -4161,6 +4246,21 @@ clear_rx_packet:
}
free(question);
}
while (parsed_packet->records) {
mdns_parsed_record_t *record = parsed_packet->records;
parsed_packet->records = parsed_packet->records->next;
if (record->host) {
free(record->host);
}
if (record->service) {
free(record->service);
}
if (record->proto) {
free(record->proto);
}
record->next = NULL;
free(record);
}
free(parsed_packet);
if (browse_result_instance) {
free(browse_result_instance);
@ -4739,7 +4839,7 @@ free_txt:
free((char *)(txt[i].value));
}
free(txt);
free(r->txt_value_len);
free(txt_value_len);
}
/**
@ -5200,28 +5300,57 @@ static void _mdns_execute_action(mdns_action_t *action)
break;
case ACTION_SERVICE_DEL:
a = _mdns_server->services;
if (action->data.srv_del.service) {
if (_mdns_server->services == action->data.srv_del.service) {
_mdns_server->services = a->next;
_mdns_send_bye(&a, 1, false);
_mdns_remove_scheduled_service_packets(a->service);
_mdns_free_service(a->service);
free(a);
} else {
while (a->next && a->next != action->data.srv_del.service) {
a = a->next;
mdns_srv_item_t *b = a;
if (action->data.srv_del.instance) {
while (a) {
if (_mdns_service_match_instance(a->service, action->data.srv_del.instance,
action->data.srv_del.service, action->data.srv_del.proto,
action->data.srv_del.hostname)) {
if (_mdns_server->services != a) {
b->next = a->next;
} else {
_mdns_server->services = a->next;
}
_mdns_send_bye(&a, 1, false);
_mdns_remove_scheduled_service_packets(a->service);
_mdns_free_service(a->service);
free(a);
break;
}
if (a->next == action->data.srv_del.service) {
mdns_srv_item_t *b = a->next;
a->next = a->next->next;
_mdns_send_bye(&b, 1, false);
_mdns_remove_scheduled_service_packets(b->service);
_mdns_free_service(b->service);
free(b);
b = a;
a = a->next;
}
} else {
while (a) {
if (_mdns_service_match(a->service, action->data.srv_del.service, action->data.srv_del.proto,
action->data.srv_del.hostname)) {
if (_mdns_server->services != a) {
b->next = a->next;
_mdns_send_bye(&a, 1, false);
_mdns_remove_scheduled_service_packets(a->service);
_mdns_free_service(a->service);
free(a);
a = b->next;
continue;
} else {
_mdns_server->services = a->next;
_mdns_send_bye(&a, 1, false);
_mdns_remove_scheduled_service_packets(a->service);
_mdns_free_service(a->service);
free(a);
a = _mdns_server->services;
b = a;
continue;
}
}
b = a;
a = a->next;
}
}
free((char *)action->data.srv_del.instance);
free((char *)action->data.srv_del.service);
free((char *)action->data.srv_del.proto);
free((char *)action->data.srv_del.hostname);
break;
case ACTION_SERVICES_CLEAR:
_mdns_send_final_bye(false);
@ -6401,6 +6530,16 @@ esp_err_t mdns_service_subtype_add_for_host(const char *instance_name, const cha
if (!s) {
return ESP_ERR_NOT_FOUND;
}
mdns_subtype_t *srv_subtype = s->service->subtype;
while (srv_subtype) {
if (strcmp(srv_subtype->subtype, subtype) == 0) {
// The same subtype has already been added
return ESP_ERR_INVALID_ARG;
}
srv_subtype = srv_subtype->next;
}
mdns_action_t *action = (mdns_action_t *)malloc(sizeof(mdns_action_t));
if (!action) {
HOOK_MALLOC_FAILED;
@ -6489,12 +6628,40 @@ esp_err_t mdns_service_remove_for_host(const char *instance, const char *service
return ESP_ERR_NO_MEM;
}
action->type = ACTION_SERVICE_DEL;
action->data.srv_del.service = s;
action->data.srv_del.instance = NULL;
action->data.srv_del.hostname = NULL;
if (!_str_null_or_empty(instance)) {
action->data.srv_del.instance = strndup(instance, MDNS_NAME_BUF_LEN - 1);
if (!action->data.srv_del.instance) {
goto fail;
}
}
if (!_str_null_or_empty(hostname)) {
action->data.srv_del.hostname = strndup(hostname, MDNS_NAME_BUF_LEN - 1);
if (!action->data.srv_del.hostname) {
goto fail;
}
}
action->data.srv_del.service = strndup(service, MDNS_NAME_BUF_LEN - 1);
action->data.srv_del.proto = strndup(proto, MDNS_NAME_BUF_LEN - 1);
if (!action->data.srv_del.service || !action->data.srv_del.proto) {
goto fail;
}
if (xQueueSend(_mdns_server->action_queue, &action, (TickType_t)0) != pdPASS) {
free(action);
return ESP_ERR_NO_MEM;
goto fail;
}
return ESP_OK;
fail:
free((char *)action->data.srv_del.instance);
free((char *)action->data.srv_del.service);
free((char *)action->data.srv_del.proto);
free((char *)action->data.srv_del.hostname);
free(action);
return ESP_ERR_NO_MEM;
}
esp_err_t mdns_service_remove(const char *service_type, const char *proto)
@ -7437,7 +7604,7 @@ free_txt:
free((char *)(txt[i].value));
}
free(txt);
free(r->txt_value_len);
free(txt_value_len);
return;
}

View File

@ -450,7 +450,10 @@ typedef struct {
mdns_srv_item_t *service;
} srv_add;
struct {
mdns_srv_item_t *service;
char *instance;
char *service;
char *proto;
char *hostname;
} srv_del;
struct {
mdns_srv_item_t *service;

View File

@ -195,6 +195,7 @@
#define CONFIG_HEAP_TRACING_OFF 1
#define CONFIG_LOG_DEFAULT_LEVEL_INFO 1
#define CONFIG_LOG_DEFAULT_LEVEL 3
#define CONFIG_LOG_MAXIMUM_LEVEL 3
#define CONFIG_LOG_COLORS 1
#define CONFIG_LOG_TIMESTAMP_SOURCE_RTOS 1
#define CONFIG_LWIP_LOCAL_HOSTNAME "espressif"

30
test_app/CMakeLists.txt Normal file
View File

@ -0,0 +1,30 @@
# The following lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/version.cmake)
# Add newly added components to one of these lines:
set(EXTRA_COMPONENT_DIRS
../components/eppp_link
../components/esp_modem
../components/esp_mqtt_cxx
../components/esp_websocket_client
../components/console_cmd_ifconfig
../components/console_cmd_ping
../components/console_cmd_wifi
../components/console_simple_init
../components/mbedtls_cxx
../components/mdns)
# !This section should NOT be touched when adding new component!
# Take all components in EXTRA_COMPONENT_DIRS, strip leading '../' and add it to TEST_COMPONENTS
# The build system will build and link unit tests, if the component contains 'test' subdirectory
set(TEST_COMPONENTS "" CACHE STRING "List of components to test")
foreach (CMP_DIR ${EXTRA_COMPONENT_DIRS})
string(SUBSTRING ${CMP_DIR} 3 100 STRIPPED_CMP) # There should be no component name longer than 100 bytes...
list(APPEND TEST_COMPONENTS ${STRIPPED_CMP})
endforeach()
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(esp_protocols_test_app)

View File

@ -0,0 +1,3 @@
idf_component_register(SRCS "test_app_main.c"
INCLUDE_DIRS ""
REQUIRES unity)

View File

@ -0,0 +1,14 @@
/*
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "unity.h"
void app_main(void)
{
UNITY_BEGIN();
unity_run_all_tests();
UNITY_END();
}

5
test_app/partitions.csv Normal file
View File

@ -0,0 +1,5 @@
# Name, Type, SubType, Offset, Size, Flags
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
nvs, data, nvs, , 0x6000,
phy_init, data, phy, , 0x1000,
factory, app, factory, , 2M,
1 # Name, Type, SubType, Offset, Size, Flags
2 # Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
3 nvs, data, nvs, , 0x6000,
4 phy_init, data, phy, , 0x1000,
5 factory, app, factory, , 2M,

View File

@ -0,0 +1,4 @@
# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
def test_app(dut):
dut.expect_unity_test_output(timeout=240)

View File

@ -0,0 +1,15 @@
CONFIG_ESP_INT_WDT=n
CONFIG_ESP_TASK_WDT=n
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
# Run-time checks of Heap and Stack
CONFIG_HEAP_POISONING_COMPREHENSIVE=y
CONFIG_COMPILER_STACK_CHECK_MODE_STRONG=y
CONFIG_COMPILER_STACK_CHECK=y
CONFIG_ESP_MAIN_TASK_STACK_SIZE=16000
CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK=y
CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL=y