Compare commits

..

79 Commits

Author SHA1 Message Date
8195fc4b8f Merge pull request #601 from david-cermak/bump/wifi_remote
bump(wifi_remote): 0.2.3 -> 0.3.0
2024-06-28 08:44:02 +02:00
68da69e4d8 Merge pull request #602 from david-cermak/bump/eppp
bump(eppp): 0.1.1 -> 0.2.0
2024-06-28 07:55:05 +02:00
c6e2eb2dac Merge pull request #556 from leeebo/master
feat(esp_modem): example add esp32p4 usb support (IDFGH-12673)
2024-06-24 15:51:57 +02:00
a9dd78ffad bump(eppp): 0.1.1 -> 0.2.0
0.2.0
Features
- Add support for SDIO transport (085dd790)
Bug Fixes
- Fixed strict prototype API decl issue in SDIO (eb09e426)
- Fix SIDO host to check/clear interrupts atomically (402176c9)
2024-06-24 15:50:50 +02:00
eb09e42638 fix(eppp): Fixed strict prototype API decl issue in SDIO 2024-06-24 15:50:40 +02:00
adafeae5cf feat(esp_modem): example add esp32p4 usb support
1. support ec20 cat.4 module in example modem_console and pppos_client
2. support esp32p4 in example modem_console and pppos_client
2024-06-24 18:55:20 +08:00
d7eaa77b89 Merge pull request #511 from david-cermak/feat/eppp_sdio
[eppp]: Add support for SDIO transport
2024-06-24 09:52:20 +02:00
5fe3870494 bump(wifi_remote): 0.2.3 -> 0.3.0
0.3.0
Features
- add esp_wifi_internal_tx_by_ref (ba35d14e)
- Make wifi_remote depend on esp_hosted (ac9972aa)
2024-06-24 09:40:25 +02:00
402176c9e0 fix(eppp): Fix SIDO host to check/clear interrupts atomically 2024-06-24 09:29:42 +02:00
085dd79079 feat(eppp): Add support for SDIO transport 2024-06-24 09:29:42 +02:00
a05fbc7ed9 Merge pull request #599 from SohKamYung-Espressif/feat/wifi_internal_tx_by_ref
feat(wifi_remote): add esp_wifi_internal_tx_by_ref
2024-06-21 17:42:00 +02:00
ba35d14e43 feat(wifi_remote): add esp_wifi_internal_tx_by_ref
Add esp_wifi_internal_tx_by_ref as building with CONFIG_SPIRAM=y will
get a linker error caused by an undefined reference to the function.
2024-06-21 15:24:16 +08:00
2b64e80acd Merge pull request #596 from SohKamYung-Espressif/feat/depend_on_esp_hosted
feat(wifi_remote): Make wifi_remote depend on esp_hosted (IDFGH-13027)
2024-06-18 11:02:11 +02:00
ac9972aa48 feat(wifi_remote): Make wifi_remote depend on esp_hosted
Co-authored-by: david-cermak <38914379+david-cermak@users.noreply.github.com>
2024-06-18 11:14:09 +08:00
1c5a149b14 Merge pull request #597 from david-cermak/fix/pre_commit_hook_astyle
fix(common): Fix pre-commit hook to use released astyle_py
2024-06-14 15:33:56 +02:00
8d0152f612 fix(common): Fix pre-commit hook to use released astyle_py
The previous version (c00138088) required pyyaml 3.0.0 which is broken
on certain plafroms (e.g. Fedora 39)

Closes https://github.com/espressif/esp-protocols/issues/592
2024-06-14 12:24:31 +02:00
b2272b410d Merge pull request #513 from espressif-abhikroy/component/console_cmd_wifi
feat(console): wifi commands updates
2024-06-11 21:03:09 +10:00
5d43f9660f bump(console): 1.0.1 -> 1.1.0
1.1.0
Features
- Added support to join pre-configured network (bdbf16c1)
2024-06-11 20:50:49 +10:00
bdbf16c113 feat(console): Added support to join pre-configured network 2024-06-11 20:34:01 +10:00
7f248bd03f Merge pull request #591 from david-cermak/fix/modem_clang_tidy
[modem]: Fixes clang-tidy warnings
2024-06-07 17:01:02 +02:00
dabd4bfd0e fix(modem): Fix host tests to run gcov in python virt env 2024-06-07 12:45:23 +02:00
70fa3af771 fix(modem): Fixed clang-tidy warnings
* private field 'netif' is not used [clang-diagnostic-unused-private-field]
* private field 'instance' is not used [clang-diagnostic-unused-private-field]
* Call to virtual method 'FdTerminal::stop' during destruction bypasses virtual dispatch [clang-analyzer-optin.cplusplus.VirtualCall]
* unused variable 'TAG' [clang-diagnostic-unused-const-variable]
* Null pointer passed as 2nd argument to memory copy function [clang-analyzer-unix.cstring.NullArg]
* Array access (from variable 'data') results in a null pointer dereference [clang-analyzer-core.NullDereference]
2024-06-07 12:43:23 +02:00
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
121 changed files with 2788 additions and 310 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

@ -26,7 +26,7 @@ jobs:
- name: Set up Python environment
uses: actions/setup-python@master
with:
python-version: v3.7
python-version: v3.8
- name: Install python packages
run: |
pip install pre-commit

View File

@ -87,8 +87,10 @@ jobs:
shell: bash
if: ${{ inputs.run_coverage }}
run: |
apt-get update && apt-get install -y python3-pip rsync
python -m pip install gcovr
apt-get update && apt-get install -y rsync
python3 -m venv .venv
source .venv/bin/activate
python3 -m pip install gcovr
cd $GITHUB_WORKSPACE/${{inputs.component_path}}
component=$(basename ${{ inputs.component_path }})
gcov `find . -name "$component*gcda"`

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

@ -48,7 +48,7 @@ repos:
- id: check-copyright
args: ['--ignore', 'ci/check_copyright_ignore.txt', '--config', 'ci/check_copyright_config.yaml']
- repo: https://github.com/igrr/astyle_py.git
rev: c0013808882a15a0c0c2c1a9b5c903866c53a653
rev: v1.0.5
hooks:
- id: astyle_py
args: ['--style=otbs', '--attach-namespaces', '--attach-classes', '--indent=spaces=4', '--convert-tabs', '--align-pointer=name', '--align-reference=name', '--keep-one-line-statements', '--pad-header', '--pad-oper', '--exclude-list=ci/ignore_astyle.txt']

View File

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

View File

@ -1,5 +1,11 @@
# Changelog
## [1.1.0](https://github.com/espressif/esp-protocols/commits/console_cmd_wifi-v1.1.0)
### Features
- Added support to join pre-configured network ([bdbf16c1](https://github.com/espressif/esp-protocols/commit/bdbf16c1))
## [1.0.1](https://github.com/espressif/esp-protocols/commits/console_cmd_wifi-v1.0.1)
### Features

View File

@ -1,4 +1,8 @@
idf_component_register(SRCS "console_wifi.c"
INCLUDE_DIRS "."
PRIV_REQUIRES esp_netif console esp_wifi
WHOLE_ARCHIVE)
INCLUDE_DIRS "include"
REQUIRES lwip
PRIV_REQUIRES esp_netif console esp_wifi esp_timer)
if(CONFIG_WIFI_CMD_AUTO_REGISTRATION)
target_link_libraries(${COMPONENT_LIB} "-u console_cmd_wifi_register")
endif()

View File

@ -0,0 +1,22 @@
menu "Wifi command Configuration"
config WIFI_CMD_AUTO_REGISTRATION
bool "Enable Console command wifi Auto-registration"
default y
help
Enabling this allows for the autoregistration of the wifi command.
config WIFI_CMD_NETWORK_SSID
string "WiFi SSID"
default "myssid"
help
SSID (network name) to connect to.
config WIFI_CMD_NETWORK_PASSWORD
string "WiFi Password"
default "mypassword"
help
WiFi password (WPA or WPA2) to use.
Can be left blank if the network has no security set.
endmenu

View File

@ -33,12 +33,16 @@ The component offers a console with a command that enables runtime wifi configur
ESP_ERROR_CHECK(console_cmd_start()); // Start console
```
Note: Auto-registration of a specific plugin command can be disabled from menuconfig.
## Suported command:
### wifi:
* ```wifi help```: Prints the help text for all wifi commands
* ```wifi show network```: Scans and displays upto 10 available wifi networks.
* ```wifi show sta```: Shows the details of wifi station.
* ```wifi sta join <network ssid> <password>```: Station joins the given wifi network.
* ```wifi sta join <network ssid>```: Station joins the given unsecured wifi network.
* ```wifi sta leave```: Station leaves the wifi network.
```
wifi help: Prints the help text for all wifi commands
wifi show network/sta: Scans and displays all available wifi APs./ Shows the details of wifi station.
wifi sta join <network ssid> <password>: Station joins the given wifi network.
wifi sta join <network ssid>: Station joins the given unsecured wifi network.
wifi sta join: Station joins the pre-configured wifi network.
wifi sta leave: Station leaves the wifi network.
```

View File

@ -21,6 +21,7 @@
#define DEFAULT_SCAN_LIST_SIZE 10
#if CONFIG_WIFI_CMD_AUTO_REGISTRATION
/**
* Static registration of this plugin is achieved by defining the plugin description
* structure and placing it into .console_cmd_desc section.
@ -30,6 +31,7 @@ static const console_cmd_plugin_desc_t __attribute__((section(".console_cmd_desc
.name = "console_cmd_wifi",
.plugin_regd_fn = &console_cmd_wifi_register
};
#endif
typedef struct wifi_op_t {
char *name;
@ -55,8 +57,9 @@ static const int CONNECTED_BIT = BIT1;
static wifi_op_t cmd_list[] = {
{.name = "help", .operation = wifi_help_op, .arg_cnt = 2, .start_index = 1, .help = "wifi help: Prints the help text for all wifi commands"},
{.name = "show", .operation = wifi_show_op, .arg_cnt = 3, .start_index = 1, .help = "wifi show network/sta: Scans and displays all available wifi APs./ Shows the details of wifi station."},
{.name = "join", .operation = wifi_sta_join_op, .arg_cnt = 4, .start_index = 2, .help = "wifi sta join <network ssid> <password>: Station joins the given wifi network."},
{.name = "join", .operation = wifi_sta_join_op, .arg_cnt = 5, .start_index = 2, .help = "wifi sta join <network ssid>: Station joins the given unsecured wifi network."},
{.name = "join", .operation = wifi_sta_join_op, .arg_cnt = 5, .start_index = 2, .help = "wifi sta join <network ssid> <password>: Station joins the given wifi network."},
{.name = "join", .operation = wifi_sta_join_op, .arg_cnt = 4, .start_index = 2, .help = "wifi sta join <network ssid>: Station joins the given unsecured wifi network."},
{.name = "join", .operation = wifi_sta_join_op, .arg_cnt = 3, .start_index = 2, .help = "wifi sta join: Station joins the pre-configured wifi network."},
{.name = "leave", .operation = wifi_sta_leave_op, .arg_cnt = 3, .start_index = 2, .help = "wifi sta leave: Station leaves the wifi network."},
};
@ -162,7 +165,6 @@ static esp_err_t wifi_show_op(wifi_op_t *self, int argc, char *argv[])
ESP_LOGI(TAG, "Showing Joind AP details:");
ESP_LOGI(TAG, "*************************");
ESP_LOGI(TAG, "SSID: %s", wifi_config.sta.ssid);
ESP_LOGI(TAG, "Password: %s", wifi_config.sta.password);
ESP_LOGI(TAG, "Channel: %d", wifi_config.sta.channel);
ESP_LOGI(TAG, "bssid: %02x:%02x:%02x:%02x:%02x:%02x", wifi_config.sta.bssid[0],
wifi_config.sta.bssid[1], wifi_config.sta.bssid[2], wifi_config.sta.bssid[3],
@ -184,7 +186,13 @@ static esp_err_t wifi_sta_join_op(wifi_op_t *self, int argc, char *argv[])
return ESP_FAIL;
}
strlcpy((char *) wifi_config.sta.ssid, argv[self->start_index + 1], sizeof(wifi_config.sta.ssid));
if (self->arg_cnt == 3) {
strlcpy((char *) wifi_config.sta.ssid, CONFIG_WIFI_CMD_NETWORK_SSID, sizeof(wifi_config.sta.ssid));
strlcpy((char *) wifi_config.sta.password, CONFIG_WIFI_CMD_NETWORK_PASSWORD, sizeof(wifi_config.sta.password));
} else {
strlcpy((char *) wifi_config.sta.ssid, argv[self->start_index + 1], sizeof(wifi_config.sta.ssid));
}
if (self->arg_cnt == 5) {
strlcpy((char *) wifi_config.sta.password, argv[self->start_index + 2], sizeof(wifi_config.sta.password));
}
@ -260,7 +268,7 @@ static esp_err_t do_cmd_wifi(int argc, char **argv)
*/
esp_err_t console_cmd_wifi_register(void)
{
esp_err_t ret;
esp_err_t ret = ESP_OK;
esp_console_cmd_t command = {
.command = "wifi",
.help = "Command for wifi configuration and monitoring\n For more info run 'wifi help'",

View File

@ -1,4 +1,4 @@
version: 1.0.1
version: 1.1.0
url: https://github.com/espressif/esp-protocols/tree/master/components/console_cmd_wifi
description: The component offers a console that enables runtime wifi configuration and monitoring.
dependencies:

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.2.0
version_files:
- idf_component.yml

View File

@ -1,5 +1,34 @@
# Changelog
## [0.2.0](https://github.com/espressif/esp-protocols/commits/eppp-v0.2.0)
### Features
- Add support for SDIO transport ([085dd790](https://github.com/espressif/esp-protocols/commit/085dd790))
### Bug Fixes
- Fixed strict prototype API decl issue in SDIO ([eb09e426](https://github.com/espressif/esp-protocols/commit/eb09e426))
- Fix SIDO host to check/clear interrupts atomically ([402176c9](https://github.com/espressif/esp-protocols/commit/402176c9))
## [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,3 +1,3 @@
idf_component_register(SRCS "eppp_link.c"
idf_component_register(SRCS eppp_link.c eppp_sdio_slave.c eppp_sdio_host.c
INCLUDE_DIRS "include"
PRIV_REQUIRES esp_netif esp_driver_spi esp_driver_gpio esp_timer driver)

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
@ -15,6 +21,13 @@ menu "eppp_link"
bool "SPI"
help
Use SPI.
config EPPP_LINK_DEVICE_SDIO
bool "SDIO"
depends on SOC_SDMMC_HOST_SUPPORTED || SOC_SDIO_SLAVE_SUPPORTED
help
Use SDIO.
endchoice
config EPPP_LINK_CONN_MAX_RETRY
@ -28,8 +41,30 @@ menu "eppp_link"
config EPPP_LINK_PACKET_QUEUE_SIZE
int "Packet queue size"
default 64
depends on EPPP_LINK_DEVICE_SPI
help
Size of the Tx packet queue.
You can decrease the number for slower bit rates.
choice EPPP_LINK_SDIO_ROLE
prompt "Choose SDIO host or slave"
depends on EPPP_LINK_DEVICE_SDIO
default EPPP_LINK_DEVICE_SDIO_HOST if SOC_SDMMC_HOST_SUPPORTED
help
Select which either SDIO host or slave
config EPPP_LINK_DEVICE_SDIO_HOST
bool "Host"
depends on SOC_SDMMC_HOST_SUPPORTED
help
Use SDIO host.
config EPPP_LINK_DEVICE_SDIO_SLAVE
bool "SLAVE"
depends on SOC_SDIO_SLAVE_SUPPORTED
help
Use SDIO slave.
endchoice
endmenu

View File

@ -14,7 +14,7 @@ brings in the WiFi connectivity from the "SLAVE" microcontroller.
SLAVE micro HOST micro
\|/ +----------------+ +----------------+
| | | serial line | |
+---+ WiFi NAT PPPoS |======== UART / SPI =======| PPPoS client |
+---+ WiFi NAT PPPoS |=== UART / SPI / SDIO =====| PPPoS client |
| (server)| | |
+----------------+ +----------------+
```
@ -39,14 +39,19 @@ brings in the WiFi connectivity from the "SLAVE" microcontroller.
## Throughput
Tested with WiFi-NAPT example, no IRAM optimizations
Tested with WiFi-NAPT example
### UART @ 3Mbauds
* TCP - 2Mbits/s
* UDP - 2Mbits/s
### SPI @ 20MHz
### SPI @ 16MHz
* TCP - 6Mbits/s
* UDP - 10Mbits/s
* TCP - 5Mbits/s
* UDP - 8Mbits/s
### SDIO
* TCP - 9Mbits/s
* UDP - 11Mbits/s

View File

@ -12,6 +12,7 @@
#include "esp_event.h"
#include "esp_netif_ppp.h"
#include "eppp_link.h"
#include "esp_serial_slave_link/essl_sdio.h"
#if CONFIG_EPPP_LINK_DEVICE_SPI
#include "driver/spi_master.h"
@ -86,7 +87,18 @@ struct eppp_handle {
bool netif_stop;
};
typedef esp_err_t (*transmit_t)(void *h, void *buffer, size_t len);
#if CONFIG_EPPP_LINK_DEVICE_SDIO
esp_err_t eppp_sdio_host_tx(void *h, void *buffer, size_t len);
esp_err_t eppp_sdio_host_rx(esp_netif_t *netif);
esp_err_t eppp_sdio_slave_rx(esp_netif_t *netif);
esp_err_t eppp_sdio_slave_tx(void *h, void *buffer, size_t len);
esp_err_t eppp_sdio_host_init(struct eppp_config_sdio_s *config);
esp_err_t eppp_sdio_slave_init(void);
void eppp_sdio_slave_deinit(void);
void eppp_sdio_host_deinit(void);
#else
static esp_err_t transmit(void *h, void *buffer, size_t len)
{
struct eppp_handle *handle = h;
@ -125,9 +137,10 @@ static esp_err_t transmit(void *h, void *buffer, size_t len)
#elif CONFIG_EPPP_LINK_DEVICE_UART
ESP_LOG_BUFFER_HEXDUMP("ppp_uart_send", buffer, len, ESP_LOG_VERBOSE);
uart_write_bytes(handle->uart_port, buffer, len);
#endif
#endif // DEVICE UART or SPI
return ESP_OK;
}
#endif
static void netif_deinit(esp_netif_t *netif)
{
@ -157,7 +170,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");
@ -209,7 +222,11 @@ static esp_netif_t *netif_init(eppp_type_t role)
esp_netif_driver_ifconfig_t driver_cfg = {
.handle = h,
#if CONFIG_EPPP_LINK_DEVICE_SDIO
.transmit = role == EPPP_CLIENT ? eppp_sdio_host_tx : eppp_sdio_slave_tx,
#else
.transmit = transmit,
#endif
};
const esp_netif_driver_ifconfig_t *ppp_driver_cfg = &driver_cfg;
@ -217,10 +234,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,
@ -654,6 +674,20 @@ esp_err_t eppp_perform(esp_netif_t *netif)
}
return ESP_OK;
}
#elif CONFIG_EPPP_LINK_DEVICE_SDIO
esp_err_t eppp_perform(esp_netif_t *netif)
{
struct eppp_handle *h = esp_netif_get_io_driver(netif);
if (h->stop) {
return ESP_ERR_TIMEOUT;
}
if (h->role == EPPP_SERVER) {
return eppp_sdio_slave_rx(netif);
} else {
return eppp_sdio_host_rx(netif);
}
}
#endif // CONFIG_EPPP_LINK_DEVICE_SPI / UART
@ -697,16 +731,27 @@ void eppp_deinit(esp_netif_t *netif)
}
#elif CONFIG_EPPP_LINK_DEVICE_UART
deinit_uart(esp_netif_get_io_driver(netif));
#elif CONFIG_EPPP_LINK_DEVICE_SDIO
struct eppp_handle *h = esp_netif_get_io_driver(netif);
if (h->role == EPPP_CLIENT) {
eppp_sdio_host_deinit();
} else {
eppp_sdio_slave_deinit();
}
#endif
netif_deinit(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();
return NULL;
}
esp_netif_ppp_config_t netif_params;
@ -724,12 +769,28 @@ esp_netif_t *eppp_init(eppp_type_t role, eppp_config_t *config)
}
#elif CONFIG_EPPP_LINK_DEVICE_UART
init_uart(esp_netif_get_io_driver(netif), config);
#elif CONFIG_EPPP_LINK_DEVICE_SDIO
esp_err_t ret;
if (role == EPPP_SERVER) {
ret = eppp_sdio_slave_init();
} else {
ret = eppp_sdio_host_init(&config->sdio);
}
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to initialize SDIO %d", ret);
return NULL;
}
#endif
return netif;
}
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");
@ -742,6 +803,12 @@ esp_netif_t *eppp_open(eppp_type_t role, eppp_config_t *config, int connect_time
return NULL;
}
#endif
#if CONFIG_EPPP_LINK_DEVICE_SDIO
if (config->transport != EPPP_TRANSPORT_SDIO) {
ESP_LOGE(TAG, "Invalid transport: SDIO device must be enabled in Kconfig");
return NULL;
}
#endif
if (config->task.run_task == false) {
ESP_LOGE(TAG, "task.run_task == false is invalid in this API. Please use eppp_init()");

View File

@ -0,0 +1,19 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#define MAX_SDIO_PAYLOAD 1500
#define SDIO_ALIGN(size) (((size) + 3U) & ~(3U))
#define SDIO_PAYLOAD SDIO_ALIGN(MAX_SDIO_PAYLOAD)
#define PPP_SOF 0x7E
// Interrupts and registers
#define SLAVE_INTR 0
#define SLAVE_REG_REQ 0
// Requests from host to slave
#define REQ_RESET 1
#define REQ_INIT 2

View File

@ -0,0 +1,200 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include <stdint.h>
#include "sdkconfig.h"
#include "esp_log.h"
#include "esp_netif.h"
#include "driver/sdio_slave.h"
#include "esp_serial_slave_link/essl_sdio.h"
#include "eppp_sdio.h"
#include "driver/sdmmc_host.h"
#include "sdmmc_cmd.h"
#include "esp_check.h"
#include "eppp_link.h"
#if CONFIG_EPPP_LINK_DEVICE_SDIO_HOST
// For blocking operations
#define TIMEOUT_MAX UINT32_MAX
// Short timeout for sending/receiving ESSL packets
#define PACKET_TIMEOUT_MS 50
static const char *TAG = "eppp_sdio_host";
static SemaphoreHandle_t s_essl_mutex = NULL;
static essl_handle_t s_essl = NULL;
static sdmmc_card_t *s_card = NULL;
static DRAM_DMA_ALIGNED_ATTR uint8_t send_buffer[SDIO_PAYLOAD];
static DMA_ATTR uint8_t rcv_buffer[SDIO_PAYLOAD];
esp_err_t eppp_sdio_host_tx(void *h, void *buffer, size_t len)
{
if (s_essl == NULL || s_essl_mutex == NULL) {
// silently skip the Tx if the SDIO not fully initialized
return ESP_OK;
}
memcpy(send_buffer, buffer, len);
size_t send_len = SDIO_ALIGN(len);
if (send_len > len) {
// pad with SOF's
memset(&send_buffer[len], PPP_SOF, send_len - len);
}
xSemaphoreTake(s_essl_mutex, portMAX_DELAY);
esp_err_t ret = essl_send_packet(s_essl, send_buffer, send_len, PACKET_TIMEOUT_MS);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Slave not ready to receive packet %x", ret);
vTaskDelay(pdMS_TO_TICKS(1000));
ret = ESP_ERR_NO_MEM; // to inform the upper layers
}
ESP_LOG_BUFFER_HEXDUMP(TAG, send_buffer, send_len, ESP_LOG_VERBOSE);
xSemaphoreGive(s_essl_mutex);
return ret;
}
static esp_err_t request_slave_reset(void)
{
esp_err_t ret = ESP_OK;
ESP_LOGI(TAG, "send reset to slave...");
ESP_GOTO_ON_ERROR(essl_write_reg(s_essl, SLAVE_REG_REQ, REQ_RESET, NULL, TIMEOUT_MAX), err, TAG, "write-reg failed");
ESP_GOTO_ON_ERROR(essl_send_slave_intr(s_essl, BIT(SLAVE_INTR), TIMEOUT_MAX), err, TAG, "send-intr failed");
vTaskDelay(pdMS_TO_TICKS(PACKET_TIMEOUT_MS));
ESP_GOTO_ON_ERROR(essl_wait_for_ready(s_essl, TIMEOUT_MAX), err, TAG, "wait-for-ready failed");
ESP_LOGI(TAG, "slave io ready");
err:
return ret;
}
esp_err_t eppp_sdio_host_init(struct eppp_config_sdio_s *eppp_config)
{
esp_err_t ret = ESP_OK;
ESP_GOTO_ON_ERROR(sdmmc_host_init(), err, TAG, "sdmmc host init failed");
// configure SDIO interface and slot
sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT();
slot_config.width = eppp_config->width;
#ifdef CONFIG_SOC_SDMMC_USE_GPIO_MATRIX
slot_config.clk = eppp_config->clk;
slot_config.cmd = eppp_config->cmd;
slot_config.d0 = eppp_config->d0;
slot_config.d1 = eppp_config->d1;
slot_config.d2 = eppp_config->d2;
slot_config.d3 = eppp_config->d3;
#endif
ESP_GOTO_ON_ERROR(sdmmc_host_init_slot(SDMMC_HOST_SLOT_1, &slot_config), err, TAG, "init sdmmc host slot failed");
sdmmc_host_t config = SDMMC_HOST_DEFAULT();
config.flags = SDMMC_HOST_FLAG_4BIT;
config.flags |= SDMMC_HOST_FLAG_ALLOC_ALIGNED_BUF;
config.max_freq_khz = SDMMC_FREQ_HIGHSPEED;
s_card = (sdmmc_card_t *)malloc(sizeof(sdmmc_card_t));
ESP_GOTO_ON_FALSE(s_card, ESP_ERR_NO_MEM, err, TAG, "card allocation failed");
ESP_GOTO_ON_ERROR(sdmmc_card_init(&config, s_card), err, TAG, "sdmmc card init failed");
essl_sdio_config_t ser_config = {
.card = s_card,
.recv_buffer_size = SDIO_PAYLOAD,
};
ESP_GOTO_ON_FALSE(essl_sdio_init_dev(&s_essl, &ser_config) == ESP_OK && s_essl, ESP_FAIL, err, TAG, "essl_sdio_init_dev failed");
ESP_GOTO_ON_ERROR(essl_init(s_essl, TIMEOUT_MAX), err, TAG, "essl-init failed");
ESP_GOTO_ON_ERROR(request_slave_reset(), err, TAG, "failed to reset the slave");
ESP_GOTO_ON_FALSE((s_essl_mutex = xSemaphoreCreateMutex()), ESP_ERR_NO_MEM, err, TAG, "failed to create semaphore");
return ret;
err:
essl_sdio_deinit_dev(s_essl);
s_essl = NULL;
return ret;
}
static esp_err_t get_intr(uint32_t *out_raw)
{
esp_err_t ret = ESP_OK;
ESP_GOTO_ON_ERROR(essl_get_intr(s_essl, out_raw, NULL, 0), err, TAG, "essl-get-int failed");
ESP_GOTO_ON_ERROR(essl_clear_intr(s_essl, *out_raw, 0), err, TAG, "essl-clear-int failed");
ESP_LOGD(TAG, "intr: %08"PRIX32, *out_raw);
err:
return ret;
}
esp_err_t eppp_sdio_host_rx(esp_netif_t *netif)
{
uint32_t intr;
esp_err_t err = essl_wait_int(s_essl, TIMEOUT_MAX);
if (err == ESP_ERR_TIMEOUT) {
return ESP_OK;
}
xSemaphoreTake(s_essl_mutex, portMAX_DELAY);
err = get_intr(&intr);
if (err == ESP_ERR_TIMEOUT) {
xSemaphoreGive(s_essl_mutex);
return ESP_OK;
}
if (err != ESP_OK) {
ESP_LOGE(TAG, "failed to check for interrupts %d", err);
xSemaphoreGive(s_essl_mutex);
return ESP_FAIL;
}
if (intr & ESSL_SDIO_DEF_ESP32.new_packet_intr_mask) {
esp_err_t ret;
do {
size_t size_read = SDIO_PAYLOAD;
ret = essl_get_packet(s_essl, rcv_buffer, SDIO_PAYLOAD, &size_read, PACKET_TIMEOUT_MS);
if (ret == ESP_ERR_NOT_FOUND) {
ESP_LOGE(TAG, "interrupt but no data can be read");
break;
} else if (ret == ESP_OK) {
ESP_LOGD(TAG, "receive data, size: %d", size_read);
ESP_LOG_BUFFER_HEXDUMP(TAG, rcv_buffer, size_read, ESP_LOG_VERBOSE);
esp_netif_receive(netif, rcv_buffer, size_read, NULL);
break;
} else {
ESP_LOGE(TAG, "rx packet error: %08X", ret);
if (request_slave_reset() != ESP_OK) {
ESP_LOGE(TAG, "Failed to request slave reset %x", ret);
break;
}
}
} while (ret == ESP_ERR_NOT_FINISHED);
}
xSemaphoreGive(s_essl_mutex);
return ESP_OK;
}
void eppp_sdio_host_deinit(void)
{
essl_sdio_deinit_dev(s_essl);
sdmmc_host_deinit();
free(s_card);
s_card = NULL;
s_essl = NULL;
}
#else // SDMMC_HOST NOT-SUPPORTED
esp_err_t eppp_sdio_host_tx(void *handle, void *buffer, size_t len)
{
return ESP_ERR_NOT_SUPPORTED;
}
esp_err_t eppp_sdio_host_rx(esp_netif_t *netif)
{
return ESP_ERR_NOT_SUPPORTED;
}
void eppp_sdio_host_deinit(void)
{
}
esp_err_t eppp_sdio_host_init(struct eppp_config_sdio_s *config)
{
return ESP_ERR_NOT_SUPPORTED;
}
#endif // CONFIG_SOC_SDIO_SLAVE_SUPPORTED

View File

@ -0,0 +1,174 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include <stdint.h>
#include "sdkconfig.h"
#include "esp_log.h"
#include "esp_netif.h"
#include "driver/sdio_slave.h"
#include "eppp_sdio.h"
#include "esp_check.h"
#if CONFIG_EPPP_LINK_DEVICE_SDIO_SLAVE
#define BUFFER_NUM 4
#define BUFFER_SIZE SDIO_PAYLOAD
static const char *TAG = "eppp_sdio_slave";
static DMA_ATTR uint8_t sdio_slave_rx_buffer[BUFFER_NUM][BUFFER_SIZE];
static DMA_ATTR uint8_t sdio_slave_tx_buffer[SDIO_PAYLOAD];
static int s_slave_request = 0;
esp_err_t eppp_sdio_slave_tx(void *h, void *buffer, size_t len)
{
if (s_slave_request != REQ_INIT) {
// silently skip the Tx if the SDIO not fully initialized
return ESP_OK;
}
memcpy(sdio_slave_tx_buffer, buffer, len);
size_t send_len = SDIO_ALIGN(len);
if (send_len > len) {
// pad with SOF's if the size is not 4 bytes aligned
memset(&sdio_slave_tx_buffer[len], PPP_SOF, send_len - len);
}
ESP_LOG_BUFFER_HEXDUMP(TAG, sdio_slave_tx_buffer, send_len, ESP_LOG_VERBOSE);
esp_err_t ret = sdio_slave_transmit(sdio_slave_tx_buffer, send_len);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "sdio slave transmit error, ret : 0x%x", ret);
// to inform the upper layers
return ESP_ERR_NO_MEM;
}
return ESP_OK;
}
static esp_err_t slave_reset(void)
{
esp_err_t ret = ESP_OK;
ESP_LOGI(TAG, "SDIO slave reset");
sdio_slave_stop();
ESP_GOTO_ON_ERROR(sdio_slave_reset(), err, TAG, "slave reset failed");
ESP_GOTO_ON_ERROR(sdio_slave_start(), err, TAG, "slave start failed");
while (1) {
sdio_slave_buf_handle_t handle;
ret = sdio_slave_send_get_finished(&handle, 0);
if (ret == ESP_ERR_TIMEOUT) {
break;
}
ESP_GOTO_ON_ERROR(ret, err, TAG, "slave-get-finished failed");
ESP_GOTO_ON_ERROR(sdio_slave_recv_load_buf(handle), err, TAG, "slave-load-buf failed");
}
err:
return ret;
}
esp_err_t eppp_sdio_slave_rx(esp_netif_t *netif)
{
if (s_slave_request == REQ_RESET) {
ESP_LOGD(TAG, "request: %x", s_slave_request);
slave_reset();
s_slave_request = REQ_INIT;
}
sdio_slave_buf_handle_t handle;
size_t length;
uint8_t *ptr;
esp_err_t ret = sdio_slave_recv_packet(&handle, pdMS_TO_TICKS(1000));
if (ret == ESP_ERR_TIMEOUT) {
return ESP_OK;
}
if (ret == ESP_ERR_NOT_FINISHED || ret == ESP_OK) {
again:
ptr = sdio_slave_recv_get_buf(handle, &length);
esp_netif_receive(netif, ptr, length, NULL);
if (sdio_slave_recv_load_buf(handle) != ESP_OK) {
ESP_LOGE(TAG, "Failed to recycle packet buffer");
return ESP_FAIL;
}
if (ret == ESP_ERR_NOT_FINISHED) {
ret = sdio_slave_recv_packet(&handle, 0);
if (ret == ESP_ERR_NOT_FINISHED || ret == ESP_OK) {
goto again;
}
}
ESP_LOG_BUFFER_HEXDUMP(TAG, ptr, length, ESP_LOG_VERBOSE);
return ESP_OK;
}
ESP_LOGE(TAG, "Error when receiving packet %d", ret);
return ESP_FAIL;
}
static void event_cb(uint8_t pos)
{
ESP_EARLY_LOGI(TAG, "SDIO event: %d", pos);
if (pos == SLAVE_INTR) {
s_slave_request = sdio_slave_read_reg(SLAVE_REG_REQ);
sdio_slave_write_reg(SLAVE_REG_REQ, 0);
}
}
esp_err_t eppp_sdio_slave_init(void)
{
sdio_slave_config_t config = {
.sending_mode = SDIO_SLAVE_SEND_PACKET,
.send_queue_size = BUFFER_NUM,
.recv_buffer_size = BUFFER_SIZE,
.event_cb = event_cb,
};
esp_err_t ret = sdio_slave_initialize(&config);
if (ret != ESP_OK) {
return ret;
}
for (int i = 0; i < BUFFER_NUM; i++) {
sdio_slave_buf_handle_t handle = sdio_slave_recv_register_buf(sdio_slave_rx_buffer[i]);
if (handle == NULL) {
sdio_slave_deinit();
return ESP_FAIL;
}
ret = sdio_slave_recv_load_buf(handle);
if (ret != ESP_OK) {
sdio_slave_deinit();
return ESP_FAIL;
}
}
sdio_slave_set_host_intena(SDIO_SLAVE_HOSTINT_SEND_NEW_PACKET); // only need one interrupt to notify of a new packet
ret = sdio_slave_start();
if (ret != ESP_OK) {
sdio_slave_deinit();
return ESP_FAIL;
}
return ESP_OK;
}
void eppp_sdio_slave_deinit(void)
{
sdio_slave_stop();
sdio_slave_deinit();
}
#else // SOC_SDIO_SLAVE NOT-SUPPORTED
esp_err_t eppp_sdio_slave_tx(void *h, void *buffer, size_t len)
{
return ESP_ERR_NOT_SUPPORTED;
}
esp_err_t eppp_sdio_slave_rx(esp_netif_t *netif)
{
return ESP_ERR_NOT_SUPPORTED;
}
void eppp_sdio_slave_deinit(void)
{
}
esp_err_t eppp_sdio_slave_init(void)
{
return ESP_ERR_NOT_SUPPORTED;
}
#endif // CONFIG_SOC_SDIO_SLAVE_SUPPORTED

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

@ -104,11 +104,13 @@ void app_main(void)
eppp_config_t config = EPPP_DEFAULT_CLIENT_CONFIG();
#if CONFIG_EPPP_LINK_DEVICE_SPI
config.transport = EPPP_TRANSPORT_SPI;
#else
#elif CONFIG_EPPP_LINK_DEVICE_UART
config.transport = EPPP_TRANSPORT_UART;
config.uart.tx_io = CONFIG_EXAMPLE_UART_TX_PIN;
config.uart.rx_io = CONFIG_EXAMPLE_UART_RX_PIN;
config.uart.baud = CONFIG_EXAMPLE_UART_BAUDRATE;
#else
config.transport = EPPP_TRANSPORT_SDIO;
#endif
esp_netif_t *eppp_netif = eppp_connect(&config);
if (eppp_netif == NULL) {

View File

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

View File

@ -128,16 +128,21 @@ void app_main(void)
ESP_ERROR_CHECK(ret);
init_network_interface(); // WiFi station if withing SoC capabilities (otherwise a placeholder)
// ESP_ERROR_CHECK(esp_netif_init());
// ESP_ERROR_CHECK(esp_event_loop_create_default());
eppp_config_t config = EPPP_DEFAULT_SERVER_CONFIG();
#if CONFIG_EPPP_LINK_DEVICE_SPI
config.transport = EPPP_TRANSPORT_SPI;
#else
#elif CONFIG_EPPP_LINK_DEVICE_UART
config.transport = EPPP_TRANSPORT_UART;
config.uart.tx_io = CONFIG_EXAMPLE_UART_TX_PIN;
config.uart.rx_io = CONFIG_EXAMPLE_UART_RX_PIN;
config.uart.baud = CONFIG_EXAMPLE_UART_BAUDRATE;
#endif
#elif CONFIG_EPPP_LINK_DEVICE_SDIO
config.transport = EPPP_TRANSPORT_SDIO;
#endif // transport device
esp_netif_t *eppp_netif = eppp_listen(&config);
if (eppp_netif == NULL) {
ESP_LOGE(TAG, "Failed to setup connection");

View File

@ -1,6 +1,6 @@
version: 0.0.1
version: 0.2.0
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:
idf:
version: '>=5.2'
idf: '>=5.2'
espressif/esp_serial_slave_link: "^1.1.0"

View File

@ -28,7 +28,16 @@
.rx_io = 26, \
.queue_size = 16, \
.rx_buffer_size = 1024, \
}, \
}, \
.sdio = { \
.width = 4, \
.clk = 18, \
.cmd = 19, \
.d0 = 49, \
.d1 = 50, \
.d2 = 16, \
.d3 = 17, \
}, \
. task = { \
.run_task = true, \
.stack_size = 4096, \
@ -37,6 +46,8 @@
. ppp = { \
.our_ip4_addr = { .addr = our_ip }, \
.their_ip4_addr = { .addr = their_ip }, \
.netif_prio = 0, \
.netif_description = NULL, \
} \
}
@ -51,6 +62,7 @@ typedef enum eppp_type {
typedef enum eppp_transport {
EPPP_TRANSPORT_UART,
EPPP_TRANSPORT_SPI,
EPPP_TRANSPORT_SDIO,
} eppp_transport_t;
@ -79,6 +91,16 @@ typedef struct eppp_config_t {
int rx_buffer_size;
} uart;
struct eppp_config_sdio_s {
int width;
int clk;
int cmd;
int d0;
int d1;
int d2;
int d3;
} sdio;
struct eppp_config_task_s {
bool run_task;
int stack_size;
@ -88,6 +110,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

@ -16,9 +16,9 @@ class.
### USB DTE support
For USB enabled targets (ESP32-S2 and ESP32-S3), it is possible to connect to the modem device via USB.
For USB enabled targets (ESP32-S2, ESP32-S3, or ESP32-P4), it is possible to connect to the modem device via USB.
1. In menuconfig, navigate to `Example Configuration->Type of serial connection to the modem` and choose `USB`.
2. Connect the modem USB signals to pin 19 (DATA-) and 20 (DATA+) on your ESP chip.
2. Connect the modem USB signals to your ESP chip (pin 19 (DATA-) and 20 (DATA+) for ESP32-S2/S3).
USB example uses Quactel BG96 modem device. BG96 needs a positive pulse on its PWK pin to boot-up.

View File

@ -10,7 +10,7 @@ menu "Example Configuration"
Connect to modem via UART.
config EXAMPLE_SERIAL_CONFIG_USB
bool "USB"
depends on IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
depends on IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32P4
help
Connect to modem via USB (CDC-ACM class). For IDF version >= 4.4.
endchoice
@ -36,6 +36,11 @@ menu "Example Configuration"
bool "BG96"
help
Quectel BG96 is a series of LTE Cat M1/Cat NB1/EGPRS module.
config EXAMPLE_MODEM_DEVICE_EC20
depends on EXAMPLE_SERIAL_CONFIG_USB
bool "EC20"
help
Quectel EC20 is a series of LTE Cat M4 module.
config EXAMPLE_MODEM_DEVICE_SIM7000
depends on EXAMPLE_SERIAL_CONFIG_UART
bool "SIM7000"

View File

@ -6,7 +6,7 @@ dependencies:
version: "^1.0.0"
override_path: "../../../"
espressif/esp_modem_usb_dte:
version: "^1.1.0"
version: "^1.2.0"
rules:
- if: "idf_version >=4.4"
- if: "target in [esp32s2, esp32s3]"
- if: "target in [esp32s2, esp32s3, esp32p4]"

View File

@ -160,6 +160,9 @@ extern "C" void app_main(void)
#if CONFIG_EXAMPLE_MODEM_DEVICE_BG96 == 1
ESP_LOGI(TAG, "Initializing esp_modem for the BG96 module...");
struct esp_modem_usb_term_config usb_config = ESP_MODEM_BG96_USB_CONFIG();
#elif CONFIG_EXAMPLE_MODEM_DEVICE_EC20 == 1
ESP_LOGI(TAG, "Initializing esp_modem for the EC20 module...");
struct esp_modem_usb_term_config usb_config = ESP_MODEM_EC20_USB_CONFIG();
#elif CONFIG_EXAMPLE_MODEM_DEVICE_SIM7600 == 1
ESP_LOGI(TAG, "Initializing esp_modem for the SIM7600 module...");
struct esp_modem_usb_term_config usb_config = ESP_MODEM_SIM7600_USB_CONFIG();
@ -180,7 +183,7 @@ extern "C" void app_main(void)
});
#if CONFIG_EXAMPLE_MODEM_DEVICE_BG96 == 1
std::unique_ptr<DCE> dce = create_BG96_dce(&dce_config, dte, esp_netif);
#elif CONFIG_EXAMPLE_MODEM_DEVICE_SIM7600 == 1 || CONFIG_EXAMPLE_MODEM_DEVICE_A7670 == 1
#elif CONFIG_EXAMPLE_MODEM_DEVICE_SIM7600 == 1 || CONFIG_EXAMPLE_MODEM_DEVICE_A7670 == 1 || CONFIG_EXAMPLE_MODEM_DEVICE_EC20 == 1
std::unique_ptr<DCE> dce = create_SIM7600_dce(&dce_config, dte, esp_netif);
#else
#error USB modem not selected

View File

@ -0,0 +1,2 @@
CONFIG_IDF_TARGET="esp32p4"
CONFIG_EXAMPLE_SERIAL_CONFIG_USB=y

View File

@ -11,9 +11,9 @@ See the README.md file in the upper level `pppos` directory for more information
### USB DTE support
For USB enabled targets (ESP32-S2 and ESP32-S3), it is possible to connect to the modem device via USB.
For USB enabled targets (ESP32-S2, ESP32-S3, or ESP32-P4), it is possible to connect to the modem device via USB.
1. In menuconfig, navigate to `Example Configuration->Type of serial connection to the modem` and choose `USB`.
2. Connect the modem USB signals to pin 19 (DATA-) and 20 (DATA+) on your ESP chip.
2. Connect the modem USB signals to your ESP chip (pin 19 (DATA-) and 20 (DATA+) for ESP32-S2/S3).
USB example uses Quactel BG96 modem device. BG96 needs a positive pulse on its PWK pin to boot-up.

View File

@ -9,7 +9,7 @@ menu "Example Configuration"
Connect to modem via UART.
config EXAMPLE_SERIAL_CONFIG_USB
bool "USB"
depends on IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
depends on IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32P4
help
Connect to modem via USB (CDC-ACM class). For IDF version >= 4.4.
endchoice
@ -29,6 +29,11 @@ menu "Example Configuration"
bool "BG96"
help
Quectel BG96 is a series of LTE Cat M1/Cat NB1/EGPRS module.
config EXAMPLE_MODEM_DEVICE_EC20
depends on EXAMPLE_SERIAL_CONFIG_USB
bool "EC20"
help
Quectel EC20 is a series of LTE Cat M4 module.
config EXAMPLE_MODEM_DEVICE_SIM7000
depends on EXAMPLE_SERIAL_CONFIG_UART
bool "SIM7000"

View File

@ -6,7 +6,7 @@ dependencies:
version: "^1.0.0"
override_path: "../../../"
espressif/esp_modem_usb_dte:
version: "^1.1.0"
version: "^1.2.0"
rules:
- if: "idf_version >=4.4"
- if: "target in [esp32s2, esp32s3]"
- if: "target in [esp32s2, esp32s3, esp32p4]"

View File

@ -219,6 +219,10 @@ void app_main(void)
ESP_LOGI(TAG, "Initializing esp_modem for the BG96 module...");
struct esp_modem_usb_term_config usb_config = ESP_MODEM_BG96_USB_CONFIG();
esp_modem_dce_device_t usb_dev_type = ESP_MODEM_DCE_BG96;
#elif CONFIG_EXAMPLE_MODEM_DEVICE_EC20 == 1
ESP_LOGI(TAG, "Initializing esp_modem for the EC20 module...");
struct esp_modem_usb_term_config usb_config = ESP_MODEM_EC20_USB_CONFIG();
esp_modem_dce_device_t usb_dev_type = ESP_MODEM_DCE_EC20;
#elif CONFIG_EXAMPLE_MODEM_DEVICE_SIM7600 == 1
ESP_LOGI(TAG, "Initializing esp_modem for the SIM7600 module...");
struct esp_modem_usb_term_config usb_config = ESP_MODEM_SIM7600_USB_CONFIG();

View File

@ -0,0 +1,2 @@
CONFIG_IDF_TARGET="esp32p4"
CONFIG_EXAMPLE_SERIAL_CONFIG_USB=y

View File

@ -142,7 +142,6 @@ private:
size_t frame_header_offset;
uint8_t *payload_start;
size_t total_payload_size;
int instance;
int sabm_ack;
/**

View File

@ -65,7 +65,6 @@ private:
static void on_ppp_changed(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data);
std::shared_ptr<DTE> ppp_dte;
esp_netif_t *netif;
struct ppp_netif_driver driver {};
SignalGroup signal;
static const size_t PPP_STARTED = SignalGroup::bit0;

View File

@ -52,6 +52,7 @@ typedef enum esp_modem_dce_device {
ESP_MODEM_DCE_SIM7070,
ESP_MODEM_DCE_SIM7000,
ESP_MODEM_DCE_BG96,
ESP_MODEM_DCE_EC20,
ESP_MODEM_DCE_SIM800,
ESP_MODEM_DCE_CUSTOM
} esp_modem_dce_device_t;

View File

@ -150,7 +150,7 @@ bool CMux::data_available(uint8_t *data, size_t len)
return false;
}
} else if ((type & FT_UIH) == FT_UIH && dlci == 0) { // notify the internal DISC command
if ((len > 0 && (data[0] & 0xE1) == 0xE1) || (data == nullptr)) {
if ((data == nullptr) || (len > 0 && (data[0] & 0xE1) == 0xE1)) {
// Not a DISC, ignore (MSC frame)
return true;
}
@ -346,6 +346,9 @@ bool CMux::on_cmux_data(uint8_t *data, size_t actual_len)
actual_len = term->read(data, buffer.size);
#endif
}
if (data == nullptr) {
return false;
}
ESP_LOG_BUFFER_HEXDUMP("CMUX Received", data, actual_len, ESP_LOG_VERBOSE);
CMuxFrame frame = { .ptr = data, .len = actual_len };
while (frame.len > 0) {

View File

@ -69,7 +69,7 @@ void Netif::receive(uint8_t *data, size_t len)
}
Netif::Netif(std::shared_ptr<DTE> e, esp_netif_t *ppp_netif) :
ppp_dte(std::move(e)), netif(ppp_netif)
ppp_dte(std::move(e))
{
driver.base.netif = ppp_netif;
driver.ppp = this;

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -29,11 +29,15 @@ esp_err_t Netif::esp_modem_post_attach(esp_netif_t *esp_netif, void *args)
void Netif::receive(uint8_t *data, size_t len)
{
esp_netif_receive(netif, data, len);
esp_netif_receive(driver.base.netif, data, len);
}
Netif::Netif(std::shared_ptr<DTE> e, esp_netif_t *ppp_netif) :
ppp_dte(std::move(e)), netif(ppp_netif) {}
ppp_dte(std::move(e))
{
driver.base.netif = ppp_netif;
driver.ppp = this;
}
void Netif::start()
{
@ -41,8 +45,8 @@ void Netif::start()
receive(data, len);
return true;
});
netif->transmit = esp_modem_dte_transmit;
netif->ctx = (void *)this;
driver.base.netif->transmit = esp_modem_dte_transmit;
driver.base.netif->ctx = (void *)this;
signal.set(PPP_STARTED);
}

View File

@ -155,7 +155,7 @@ int FdTerminal::write(uint8_t *data, size_t len)
FdTerminal::~FdTerminal()
{
stop();
FdTerminal::stop();
}
} // namespace esp_modem

View File

@ -14,7 +14,7 @@
#include "uart_resource.hpp"
#include "vfs_resource/vfs_create.hpp"
constexpr const char *TAG = "vfs_uart_creator";
[[maybe_unused]] constexpr const char *TAG = "vfs_uart_creator";
struct esp_modem_vfs_resource {

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.3.0
version_files:
- idf_component.yml

View File

@ -1,5 +1,44 @@
# Changelog
## [0.3.0](https://github.com/espressif/esp-protocols/commits/wifi_remote-v0.3.0)
### Features
- add esp_wifi_internal_tx_by_ref ([ba35d14e](https://github.com/espressif/esp-protocols/commit/ba35d14e))
- Make wifi_remote depend on esp_hosted ([ac9972aa](https://github.com/espressif/esp-protocols/commit/ac9972aa))
## [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

@ -59,6 +59,11 @@ WEAK void esp_wifi_internal_free_rx_buffer(void *buffer)
free(buffer);
}
WEAK esp_err_t esp_wifi_internal_tx_by_ref(wifi_interface_t ifx, void *buffer, size_t len, void *netstack_buf)
{
return esp_wifi_internal_tx(ifx, buffer, (uint16_t)len);
}
WEAK int esp_wifi_internal_tx(wifi_interface_t ifx, void *buffer, uint16_t len)
{
if (ifx == WIFI_IF_STA && s_tx_cb[0]) {

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.3.0
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'
# espressif/esp_hosted:
# version: '*'
version: '>=5.3'
espressif/esp_hosted:
version: '>=0.0.6'

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);

Some files were not shown because too many files have changed in this diff Show More