mirror of
https://github.com/espressif/esp-protocols.git
synced 2025-12-23 15:18:08 +01:00
Compare commits
221 Commits
eppp-v0.3.
...
mqtt_cxx-v
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
072781fcd9 | ||
|
|
7ce85c7389 | ||
|
|
1cc2c97022 | ||
|
|
f41c4a0ad0 | ||
|
|
7336451109 | ||
|
|
c5b9375b4c | ||
|
|
25513d0dc3 | ||
|
|
c0cf91e174 | ||
|
|
d979e1b333 | ||
|
|
9f9c6c12f3 | ||
|
|
742adea26d | ||
|
|
2535b3fefc | ||
|
|
ba0ef10038 | ||
|
|
f1e35977e5 | ||
|
|
25735ead9c | ||
|
|
bf9e955514 | ||
|
|
726c41f842 | ||
|
|
c7de9251ed | ||
|
|
0f6235f13e | ||
|
|
6c2c2cd22b | ||
|
|
9e0bcd4b08 | ||
|
|
07b1bcdc34 | ||
|
|
f20a234f65 | ||
|
|
63082b996d | ||
|
|
27d43277d2 | ||
|
|
4d8d25a345 | ||
|
|
bed116d98b | ||
|
|
9ec006a3e4 | ||
|
|
245b5a2ffb | ||
|
|
b9ea0c31ce | ||
|
|
4aa0e4ba49 | ||
|
|
c48c2ebe7e | ||
|
|
0ccaf2c0bb | ||
|
|
ed569d8509 | ||
|
|
9b2b1f680d | ||
|
|
370dfecc15 | ||
|
|
e50c5eb40e | ||
|
|
6f6110e30e | ||
|
|
41f7157ffb | ||
|
|
858f67c280 | ||
|
|
83ffeb0d12 | ||
|
|
6e99202a18 | ||
|
|
fb5279ae88 | ||
|
|
b70cc3fc09 | ||
|
|
911c2dbe9f | ||
|
|
c620855d56 | ||
|
|
cccfdd9315 | ||
|
|
ecc7258093 | ||
|
|
0caea67542 | ||
|
|
11a8567598 | ||
|
|
9b80a7ef7d | ||
|
|
12028ab250 | ||
|
|
68e299a357 | ||
|
|
2681b9b3c6 | ||
|
|
782b7cd119 | ||
|
|
3141d6cab5 | ||
|
|
7b8770e2fc | ||
|
|
6153c0002a | ||
|
|
3d5e11b82f | ||
|
|
eacc3a0aa8 | ||
|
|
2826287d43 | ||
|
|
3bfa00389d | ||
|
|
ace7fca8c6 | ||
|
|
2b2f009a65 | ||
|
|
1444d575f0 | ||
|
|
081eef88cf | ||
|
|
8b0704eaf4 | ||
|
|
4889dd6fcb | ||
|
|
134247d88f | ||
|
|
e772ce673d | ||
|
|
3d4712b905 | ||
|
|
67188fd7b4 | ||
|
|
4d7c6848b2 | ||
|
|
1e83bee4fe | ||
|
|
3838485229 | ||
|
|
ba3377b262 | ||
|
|
e5bed394ee | ||
|
|
65b58aa05a | ||
|
|
d1e6708063 | ||
|
|
318bca1657 | ||
|
|
9e1b9cdd20 | ||
|
|
7f424325d8 | ||
|
|
9ef228f247 | ||
|
|
5068f2217e | ||
|
|
1ceb42c5a2 | ||
|
|
e52a5757f1 | ||
|
|
732cd29ec0 | ||
|
|
7a203cf085 | ||
|
|
d665e6f18e | ||
|
|
2e269640c6 | ||
|
|
c078c36361 | ||
|
|
90ddb04e53 | ||
|
|
cee3bdea9d | ||
|
|
fa96de3bd7 | ||
|
|
18f0d02806 | ||
|
|
bfa604b5f6 | ||
|
|
92a31187ff | ||
|
|
0197c994ee | ||
|
|
487a746d14 | ||
|
|
af6bb1b5ee | ||
|
|
f5e62e83e9 | ||
|
|
cad527d2fc | ||
|
|
16cc2dcffb | ||
|
|
d622e41a54 | ||
|
|
ca6e39aac7 | ||
|
|
e45944e143 | ||
|
|
fe657b9737 | ||
|
|
453be4cd79 | ||
|
|
018ba58ec5 | ||
|
|
67c682d911 | ||
|
|
91915ce1c7 | ||
|
|
ae052e5507 | ||
|
|
44524f5de0 | ||
|
|
1ace92c279 | ||
|
|
7a6cf0f9c0 | ||
|
|
54eb002758 | ||
|
|
318e41b3c3 | ||
|
|
6f6237a0cc | ||
|
|
18faeb3dfa | ||
|
|
296123c14e | ||
|
|
4e178f06bd | ||
|
|
5ab7e8327e | ||
|
|
91e7e9fa08 | ||
|
|
ff5d6021be | ||
|
|
2432e41dcb | ||
|
|
870ac91db7 | ||
|
|
94bd5b074a | ||
|
|
db7baaffba | ||
|
|
1ea93a866b | ||
|
|
92e1460721 | ||
|
|
858d38b55f | ||
|
|
6428e68c8e | ||
|
|
94563cdc1f | ||
|
|
e0b8de8f38 | ||
|
|
34b6681576 | ||
|
|
1f7828f629 | ||
|
|
e74db36ebb | ||
|
|
f8d2ed2eed | ||
|
|
8bba3a9734 | ||
|
|
9fbb6e6d0a | ||
|
|
e599cd826b | ||
|
|
e2d36b4fbd | ||
|
|
82a784baf4 | ||
|
|
15140e04c6 | ||
|
|
ce1560acb1 | ||
|
|
e1be830fb7 | ||
|
|
b7cfa31a0b | ||
|
|
845a1e2ef8 | ||
|
|
6ae7a4d2ba | ||
|
|
4d52982a69 | ||
|
|
6318022cda | ||
|
|
13591ade3d | ||
|
|
d09b302b9e | ||
|
|
39e2333adb | ||
|
|
cd57f1bb13 | ||
|
|
497ee2d6d4 | ||
|
|
b2568a3d83 | ||
|
|
58a21e39d0 | ||
|
|
9c7ee07755 | ||
|
|
14d3cb6bd1 | ||
|
|
ccdb45ee94 | ||
|
|
18418c83ff | ||
|
|
ecb7dae502 | ||
|
|
958ff6a584 | ||
|
|
5ea83be7ce | ||
|
|
33a3ec54b6 | ||
|
|
c91578c827 | ||
|
|
653328ba07 | ||
|
|
858f85706d | ||
|
|
f8748e026d | ||
|
|
479122b21d | ||
|
|
e8ce8f4739 | ||
|
|
03df9ae957 | ||
|
|
35fa0b1d42 | ||
|
|
e9d9b3a8bd | ||
|
|
07e8eddcb6 | ||
|
|
78ae25598b | ||
|
|
ffeee3e87a | ||
|
|
6d5411941b | ||
|
|
e71365f835 | ||
|
|
8dbf0e4561 | ||
|
|
63bf70914b | ||
|
|
29f1dec408 | ||
|
|
05715d80d7 | ||
|
|
75d6845194 | ||
|
|
250eebf3fc | ||
|
|
84b61dca16 | ||
|
|
76e45f7254 | ||
|
|
462561b8d9 | ||
|
|
ae8cf218c8 | ||
|
|
c340f85a90 | ||
|
|
b95d8be41d | ||
|
|
9302994673 | ||
|
|
e5787e3d9f | ||
|
|
7cddc8c6f5 | ||
|
|
fac2edbe59 | ||
|
|
ed0f633418 | ||
|
|
a8631eecf5 | ||
|
|
3e28a7264c | ||
|
|
4ee9360f53 | ||
|
|
e9b21ea7a3 | ||
|
|
ac1b2b7573 | ||
|
|
13b90ad14b | ||
|
|
fd41006193 | ||
|
|
e71926f6ed | ||
| c4169765af | |||
|
|
f43dd5012f | ||
|
|
b143894874 | ||
|
|
d1c912c833 | ||
|
|
4fbd86b278 | ||
|
|
af8272d441 | ||
|
|
8b328a6904 | ||
|
|
5f54d9075e | ||
|
|
01952f21cb | ||
|
|
5dfe076c94 | ||
|
|
ea9f29ad14 | ||
|
|
217e6d90c8 | ||
|
|
077ea0bb1f | ||
|
|
6eceb28f7d | ||
|
|
b7b8c5dbd7 | ||
|
|
19891d8c3c |
24
.github/workflows/asio__build-target-test.yml
vendored
24
.github/workflows/asio__build-target-test.yml
vendored
@@ -81,18 +81,24 @@ jobs:
|
||||
with:
|
||||
name: examples_app_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.example }}
|
||||
path: ${{ env.TEST_DIR }}/${{ matrix.example }}/build
|
||||
- name: Install Python packages
|
||||
env:
|
||||
PIP_EXTRA_INDEX_URL: "https://www.piwheels.org/simple"
|
||||
run: |
|
||||
sudo apt-get install -y dnsutils
|
||||
- name: Download Example Test to target ${{ matrix.config }}
|
||||
run: |
|
||||
python -m esptool --chip ${{ matrix.idf_target }} write_flash 0x0 ${{ env.TEST_DIR }}/${{ matrix.example }}/build/flash_image.bin
|
||||
- name: Run Example Test ${{ matrix.example }} on target
|
||||
working-directory: ${{ env.TEST_DIR }}/${{ matrix.example }}
|
||||
run: |
|
||||
python -m pytest --log-cli-level DEBUG --junit-xml=./examples_results_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.config }}.xml --target=${{ matrix.idf_target }}
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init --path)"
|
||||
eval "$(pyenv init -)"
|
||||
if ! pyenv versions --bare | grep -q '^3\.12\.6$'; then
|
||||
echo "Installing Python 3.12.6..."
|
||||
pyenv install -s 3.12.6
|
||||
fi
|
||||
if ! pyenv virtualenvs --bare | grep -q '^myenv$'; then
|
||||
echo "Creating pyenv virtualenv 'myenv'..."
|
||||
pyenv virtualenv 3.12.6 myenv
|
||||
fi
|
||||
pyenv activate myenv
|
||||
python --version
|
||||
python -m pytest --log-cli-level DEBUG --junit-xml=./examples_results_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.config }}.xml --target=${{ matrix.idf_target }}
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: always()
|
||||
with:
|
||||
|
||||
@@ -13,7 +13,7 @@ jobs:
|
||||
name: Build
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest", "release-v5.0", "release-v5.1", "release-v5.2", "release-v5.3"]
|
||||
idf_ver: ["latest", "release-v5.1", "release-v5.2", "release-v5.3", "release-v5.4", "release-v5.5", "release-v6.0"]
|
||||
idf_target: ["esp32"]
|
||||
test: [ { app: ifconfig-basic, path: "components/console_cmd_ifconfig/examples"}]
|
||||
include:
|
||||
|
||||
@@ -13,7 +13,7 @@ jobs:
|
||||
name: Build
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest", "release-v5.0", "release-v5.1", "release-v5.2", "release-v5.3"]
|
||||
idf_ver: ["latest", "release-v5.1", "release-v5.2", "release-v5.3", "release-v5.4", "release-v5.5", "release-v6.0"]
|
||||
idf_target: ["esp32"]
|
||||
test: [ { app: mqtt_ssl_auth_console, path: "components/console_cmd_mqtt/examples" }]
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
@@ -13,7 +13,7 @@ jobs:
|
||||
name: Build
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest", "release-v5.0", "release-v5.1", "release-v5.2", "release-v5.3"]
|
||||
idf_ver: ["latest", "release-v5.1", "release-v5.2", "release-v5.3", "release-v5.4", "release-v5.5", "release-v6.0"]
|
||||
idf_target: ["esp32"]
|
||||
test: [ { app: ping-basic, path: "components/console_cmd_ping/examples" }]
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
@@ -13,7 +13,7 @@ jobs:
|
||||
name: Build
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest", "release-v5.0", "release-v5.1", "release-v5.2", "release-v5.3"]
|
||||
idf_ver: ["latest", "release-v5.1", "release-v5.2", "release-v5.3", "release-v5.4", "release-v5.5", "release-v6.0"]
|
||||
idf_target: ["esp32"]
|
||||
test: [ { app: wifi-basic, path: "components/console_cmd_wifi/examples" }]
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
@@ -13,7 +13,7 @@ jobs:
|
||||
name: Build
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest", "release-v5.0", "release-v5.1", "release-v5.2", "release-v5.3"]
|
||||
idf_ver: ["latest", "release-v5.1", "release-v5.2", "release-v5.3", "release-v5.4", "release-v5.5", "release-v6.0"]
|
||||
idf_target: ["esp32"]
|
||||
test: [ { app: console_basic, path: "components/console_simple_init/examples" }]
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
2
.github/workflows/eppp__build.yml
vendored
2
.github/workflows/eppp__build.yml
vendored
@@ -13,7 +13,7 @@ jobs:
|
||||
name: Build
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest", "release-v5.5", "release-v5.4", "release-v5.3"]
|
||||
idf_ver: ["latest", "release-v6.0", "release-v5.5", "release-v5.4", "release-v5.3"]
|
||||
test: [ { app: host, path: "examples/host" }, { app: slave, path: "examples/slave" }, { app: test_app, path: "test/test_app" }]
|
||||
runs-on: ubuntu-22.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
|
||||
3
.github/workflows/esp_dns__build.yml
vendored
3
.github/workflows/esp_dns__build.yml
vendored
@@ -33,6 +33,9 @@ jobs:
|
||||
shell: bash
|
||||
working-directory: ${{matrix.test.path}}
|
||||
run: |
|
||||
if [[ "${{ matrix.idf_ver }}" == "release-v5.3" || "${{ matrix.idf_ver }}" == "release-v5.4" ]]; then
|
||||
export EXPECTED_WARNING="unknown kconfig symbol 'LWIP_USE_ESP_GETADDRINFO'"
|
||||
fi
|
||||
. ${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
|
||||
|
||||
14
.github/workflows/examples_build-host-test.yml
vendored
14
.github/workflows/examples_build-host-test.yml
vendored
@@ -13,10 +13,7 @@ jobs:
|
||||
name: Build examples
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest", "release-v5.1", "release-v5.2", "release-v5.3", "release-v5.4"]
|
||||
include:
|
||||
- idf_ver: "latest"
|
||||
warning: "Warning: The smallest app partition is nearly full"
|
||||
idf_ver: ["latest", "release-v5.1", "release-v5.2", "release-v5.3", "release-v5.4", "release-v5.5", "release-v6.0"]
|
||||
runs-on: ubuntu-22.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
env:
|
||||
@@ -27,7 +24,7 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
- name: Build with IDF-${{ matrix.idf_ver }}
|
||||
env:
|
||||
EXPECTED_WARNING: ${{ matrix.warning }}
|
||||
EXPECTED_WARNING: "Warning: The smallest app partition is nearly full"
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
@@ -59,10 +56,11 @@ jobs:
|
||||
- name: Build with IDF-${{ matrix.idf_ver }}
|
||||
shell: bash
|
||||
run: |
|
||||
. ${GITHUB_WORKSPACE}/ci/config_env.sh
|
||||
. ${IDF_PATH}/export.sh
|
||||
python -m pip install idf-build-apps
|
||||
python ./ci/build_apps.py examples/mqtt -l -t linux
|
||||
timeout 5 ./examples/mqtt/build_linux_default/esp_mqtt_demo.elf | tee test.log || true
|
||||
python ./ci/build_apps.py examples/mqtt -l -t linux -r 'sdkconfig.ci'
|
||||
timeout 5 ./examples/mqtt/build_linux/esp_mqtt_demo.elf | tee test.log || true
|
||||
grep 'MQTT_EVENT_DATA' test.log
|
||||
|
||||
run_on_target:
|
||||
@@ -74,7 +72,7 @@ jobs:
|
||||
needs: build_all_examples
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["release-v5.4", "latest"]
|
||||
idf_ver: ["release-v5.5", "latest"]
|
||||
runs-on:
|
||||
- self-hosted
|
||||
- modem
|
||||
|
||||
24
.github/workflows/lws_build.yml
vendored
24
.github/workflows/lws_build.yml
vendored
@@ -13,7 +13,7 @@ jobs:
|
||||
name: Libwebsockets build
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest", "release-v5.3", "release-v5.4"]
|
||||
idf_ver: ["release-v5.3", "release-v5.4", "release-v5.5"]
|
||||
test: [ { app: example, path: "examples/client" }]
|
||||
runs-on: ubuntu-22.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
@@ -51,7 +51,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
idf_ver: ["latest", "release-v5.3", "release-v5.4"]
|
||||
idf_ver: ["release-v5.3", "release-v5.4", "release-v5.5"]
|
||||
idf_target: ["esp32"]
|
||||
test: [ { app: example, path: "examples/client" }]
|
||||
runs-on:
|
||||
@@ -65,14 +65,24 @@ jobs:
|
||||
with:
|
||||
name: lws_target_esp32_${{ matrix.idf_ver }}_${{ matrix.test.app }}
|
||||
path: ${{ env.TEST_DIR }}/ci/
|
||||
- name: Install Python packages
|
||||
env:
|
||||
PIP_EXTRA_INDEX_URL: "https://www.piwheels.org/simple"
|
||||
run: |
|
||||
pip install --only-binary cryptography --extra-index-url https://dl.espressif.com/pypi/ -r $GITHUB_WORKSPACE/ci/requirements.txt
|
||||
- name: Run Example Test on target
|
||||
working-directory: ${{ env.TEST_DIR }}
|
||||
run: |
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init --path)"
|
||||
eval "$(pyenv init -)"
|
||||
if ! pyenv versions --bare | grep -q '^3\.12\.6$'; then
|
||||
echo "Installing Python 3.12.6..."
|
||||
pyenv install -s 3.12.6
|
||||
fi
|
||||
if ! pyenv virtualenvs --bare | grep -q '^myenv$'; then
|
||||
echo "Creating pyenv virtualenv 'myenv'..."
|
||||
pyenv virtualenv 3.12.6 myenv
|
||||
fi
|
||||
pyenv activate myenv
|
||||
python --version
|
||||
pip install --only-binary cryptography --extra-index-url https://dl.espressif.com/pypi/ -r $GITHUB_WORKSPACE/ci/requirements.txt
|
||||
unzip ci/artifacts.zip -d ci
|
||||
for dir in `ls -d ci/build_*`; do
|
||||
rm -rf build sdkconfig.defaults
|
||||
|
||||
21
.github/workflows/mdns__build-target-test.yml
vendored
21
.github/workflows/mdns__build-target-test.yml
vendored
@@ -24,6 +24,11 @@ jobs:
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
if [[ "${{ matrix.idf_ver }}" == "latest" ]]; then
|
||||
export EXPECTED_WARNING="warning: unknown kconfig symbol 'EXAMPLE_ETH_PHY_IP101'"
|
||||
else
|
||||
export EXPECTED_WARNING="warning: unknown kconfig symbol 'EXAMPLE_ETH_PHY_GENERIC'"
|
||||
fi
|
||||
python -m pip install idf-build-apps
|
||||
# Build default configs for all targets
|
||||
python ./ci/build_apps.py components/mdns/${{ matrix.test.path }} -r default -d
|
||||
@@ -71,6 +76,22 @@ jobs:
|
||||
- name: Run ${{ matrix.test.app }} application on ${{ matrix.idf_target }}
|
||||
working-directory: components/mdns/${{ matrix.test.path }}
|
||||
run: |
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init --path)"
|
||||
eval "$(pyenv init -)"
|
||||
if ! pyenv versions --bare | grep -q '^3\.12\.6$'; then
|
||||
echo "Installing Python 3.12.6..."
|
||||
pyenv install -s 3.12.6
|
||||
fi
|
||||
if ! pyenv virtualenvs --bare | grep -q '^myenv$'; then
|
||||
echo "Creating pyenv virtualenv 'myenv'..."
|
||||
pyenv virtualenv 3.12.6 myenv
|
||||
fi
|
||||
pyenv activate myenv
|
||||
python --version
|
||||
pip install --prefer-binary cryptography pytest-embedded pytest-embedded-serial-esp pytest-embedded-idf pytest-custom_exit_code esptool
|
||||
pip install --extra-index-url https://dl.espressif.com/pypi/ -r $GITHUB_WORKSPACE/ci/requirements.txt
|
||||
unzip ci/artifacts.zip -d ci
|
||||
for dir in `ls -d ci/build_*`; do
|
||||
rm -rf build sdkconfig.defaults
|
||||
|
||||
97
.github/workflows/mdns__host-tests.yml
vendored
97
.github/workflows/mdns__host-tests.yml
vendored
@@ -24,11 +24,13 @@ jobs:
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
python -m pip install idf-build-apps dnspython pytest pytest-embedded pytest-embedded-serial-esp pytest-embedded-idf
|
||||
python -m pip install idf-build-apps==2.10.0 dnspython pytest pytest-embedded pytest-embedded-serial-esp pytest-embedded-idf
|
||||
cd $GITHUB_WORKSPACE/protocols
|
||||
# Build host tests app (with all configs and targets supported)
|
||||
python ./ci/build_apps.py components/mdns/tests/host_test/
|
||||
cd components/mdns/tests/host_test
|
||||
ls -la
|
||||
ls -ls build*
|
||||
# First run the linux_app and send a quick A query and a reverse query
|
||||
./build_linux_app/mdns_host.elf &
|
||||
python dnsfixture.py A myesp.local --ip_only | xargs python dnsfixture.py X
|
||||
@@ -55,8 +57,11 @@ jobs:
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
cd components/mdns/tests/test_afl_fuzz_host/
|
||||
make INSTR=off
|
||||
cd components/mdns/tests/host_unit_test/
|
||||
idf.py reconfigure
|
||||
mkdir build2 && cd build2
|
||||
cmake ..
|
||||
cmake --build .
|
||||
- name: Test no malloc functions
|
||||
shell: bash
|
||||
run: |
|
||||
@@ -68,3 +73,89 @@ jobs:
|
||||
diff -q $file /tmp/$file || exit 1
|
||||
echo "OK"
|
||||
done
|
||||
|
||||
host_unit_test:
|
||||
if: contains(github.event.pull_request.labels.*.name, 'mdns') || github.event_name == 'push'
|
||||
name: Unit tests on host
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest"]
|
||||
|
||||
runs-on: ubuntu-22.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v4
|
||||
- name: Install bsdlib and ruby
|
||||
run: |
|
||||
apt-get update -y
|
||||
apt-get install -y libbsd-dev ruby
|
||||
- name: Build and run unit tests
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
cd components/mdns/tests/host_unit_test/
|
||||
idf.py reconfigure
|
||||
mkdir build2 && cd build2
|
||||
cmake -DUNIT_TESTS=test_receiver ..
|
||||
cmake --build .
|
||||
ctest --extra-verbose
|
||||
cd ..
|
||||
mkdir build3 && cd build3
|
||||
cmake -DUNIT_TESTS=test_sender ..
|
||||
cmake --build .
|
||||
ctest --extra-verbose
|
||||
|
||||
|
||||
fuzz_test:
|
||||
if: contains(github.event.pull_request.labels.*.name, 'mdns-fuzz') || github.event_name == 'push'
|
||||
name: Fuzzer tests for mdns lib
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest"]
|
||||
|
||||
runs-on: ubuntu-22.04
|
||||
container: aflplusplus/aflplusplus:v4.34c
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Checkout ESP-IDF
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: espressif/esp-idf
|
||||
path: idf
|
||||
submodules: recursive
|
||||
|
||||
- name: Install Necessary Libs
|
||||
run: |
|
||||
apt-get update -y
|
||||
apt-get install -y libbsd-dev
|
||||
|
||||
- name: Run AFL++
|
||||
shell: bash
|
||||
run: |
|
||||
export IDF_PATH=$GITHUB_WORKSPACE/idf
|
||||
cd components/mdns/tests/host_unit_test/
|
||||
pip install dnslib
|
||||
cd input && python generate_cases.py && cd ..
|
||||
cmake -B build2 -S . -G "Ninja" -DCMAKE_C_COMPILER=afl-cc
|
||||
cmake --build build2
|
||||
timeout 10m afl-fuzz -i input -o out -- build2/mdns_host_unit_test || \
|
||||
if [ $? -eq 124 ]; then # timeout exit code
|
||||
if [ -n "$(find out/default/crashes -type f 2>/dev/null)" ]; then
|
||||
echo "Crashes found!";
|
||||
tar -czf out/default/crashes.tar.gz -C out/default crashes;
|
||||
exit 1;
|
||||
fi
|
||||
else
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
- name: Upload Crash Artifacts
|
||||
if: failure()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: fuzz-crashes
|
||||
path: components/mdns/tests/host_unit_test/out/default/crashes.tar.gz
|
||||
if-no-files-found: ignore
|
||||
|
||||
15
.github/workflows/modem__build-host-tests.yml
vendored
15
.github/workflows/modem__build-host-tests.yml
vendored
@@ -13,13 +13,8 @@ jobs:
|
||||
name: Build examples
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest", "release-v5.0", "release-v5.1", "release-v5.2", "release-v5.3", "release-v5.4"]
|
||||
idf_ver: ["latest", "release-v5.1", "release-v5.2", "release-v5.3", "release-v5.4", "release-v5.5", "release-v6.0"]
|
||||
example: ["pppos_client", "modem_console", "modem_tcp_client", "ap_to_pppos", "simple_cmux_client"]
|
||||
include:
|
||||
- idf_ver: "release-v5.0"
|
||||
example: "simple_cmux_client"
|
||||
warning: "Warning: The smallest app partition is nearly full"
|
||||
|
||||
runs-on: ubuntu-22.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
@@ -30,9 +25,9 @@ jobs:
|
||||
- if: ${{ matrix.skip_config }}
|
||||
run: rm -f $GITHUB_WORKSPACE/protocols/components/esp_modem/examples/${{ matrix.example }}/sdkconfig.ci.${{ matrix.skip_config }}*
|
||||
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }}
|
||||
env:
|
||||
EXPECTED_WARNING: ${{ matrix.warning }}
|
||||
shell: bash
|
||||
env:
|
||||
EXPECTED_WARNING: "Warning: The smallest app partition is nearly full\nwarning: unknown kconfig symbol 'ESP32_PANIC_PRINT_HALT'"
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
python -m pip install idf-build-apps
|
||||
@@ -44,8 +39,8 @@ jobs:
|
||||
name: Build tests
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["release-v5.0", "release-v5.1", "release-v5.2", "release-v5.3", "release-v5.4", "latest"]
|
||||
test: ["target", "target_ota", "target_iperf"]
|
||||
idf_ver: ["latest","release-v5.0", "release-v5.1", "release-v5.2", "release-v5.3", "release-v5.4", "release-v5.5", "release-v6.0"]
|
||||
test: ["target", "target_ota", "target_iperf", "target_urc"]
|
||||
|
||||
runs-on: ubuntu-22.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
|
||||
16
.github/workflows/modem__target-test.yml
vendored
16
.github/workflows/modem__target-test.yml
vendored
@@ -13,7 +13,7 @@ jobs:
|
||||
name: Build Target tests
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest"]
|
||||
idf_ver: ["latest", "release-v5.5", "release-v6.0"]
|
||||
idf_target: ["esp32c3"]
|
||||
test: [ { app: pppd, path: test/target }, { app: pppd_chap_auth, path: test/target }, { app: sim800_c3, path: examples/pppos_client }, { app: sim800_cmux, path: examples/simple_cmux_client } ]
|
||||
include:
|
||||
@@ -34,18 +34,16 @@ jobs:
|
||||
IDF_TARGET: ${{ matrix.idf_target }}
|
||||
SDKCONFIG: sdkconfig.ci.${{ matrix.test.app }}
|
||||
shell: bash
|
||||
working-directory: ${{ env.TEST_DIR }}
|
||||
run: |
|
||||
. ${GITHUB_WORKSPACE}/ci/config_env.sh
|
||||
. ${IDF_PATH}/export.sh
|
||||
rm -rf sdkconfig build
|
||||
[ -f ${SDKCONFIG} ] && cp ${SDKCONFIG} sdkconfig.defaults
|
||||
idf.py set-target ${{ matrix.idf_target }}
|
||||
idf.py build
|
||||
$GITHUB_WORKSPACE/ci/clean_build_artifacts.sh ${GITHUB_WORKSPACE}/${TEST_DIR}/build
|
||||
python -m pip install idf-build-apps
|
||||
python ./ci/build_apps.py ${{ env.TEST_DIR }} -t ${{ matrix.idf_target }} -r 'sdkconfig.ci.${{ matrix.test.app }}'
|
||||
$GITHUB_WORKSPACE/ci/clean_build_artifacts.sh ${GITHUB_WORKSPACE}/${TEST_DIR}/build_${{ matrix.idf_target }}
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: modem_target_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.test.app }}
|
||||
path: ${{ env.TEST_DIR }}/build
|
||||
path: ${{ env.TEST_DIR }}/build_${{ matrix.idf_target }}
|
||||
if-no-files-found: error
|
||||
|
||||
target_tests_esp_modem:
|
||||
@@ -56,7 +54,7 @@ jobs:
|
||||
name: Run Target tests
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest"]
|
||||
idf_ver: ["latest", "release-v5.5", "release-v6.0"]
|
||||
idf_target: ["esp32c3"]
|
||||
test: [ { app: pppd, path: test/target }, { app: pppd_chap_auth, path: test/target }, { app: sim800_c3, path: examples/pppos_client }, { app: sim800_cmux, path: examples/simple_cmux_client } ]
|
||||
include:
|
||||
|
||||
32
.github/workflows/modem_sim__build.yml
vendored
Normal file
32
.github/workflows/modem_sim__build.yml
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
name: "modem_sim: build-tests"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, labeled]
|
||||
|
||||
jobs:
|
||||
build_modem_sim:
|
||||
if: contains(github.event.pull_request.labels.*.name, 'modem_sim') || github.event_name == 'push'
|
||||
name: Build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v3
|
||||
- name: Checkout idf
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: espressif/esp-idf
|
||||
ref: 8ad0d3d8f2faab752635bee36070313c47c07a13
|
||||
path: idf
|
||||
- name: Build ESP-AT with IDF-${{ matrix.idf_ver }}
|
||||
shell: bash
|
||||
run: |
|
||||
export IDF_PATH=$GITHUB_WORKSPACE/idf
|
||||
${IDF_PATH}/install.sh
|
||||
cd common_components/modem_sim
|
||||
./install.sh
|
||||
source export.sh
|
||||
idf.py build
|
||||
61
.github/workflows/mosq__build.yml
vendored
61
.github/workflows/mosq__build.yml
vendored
@@ -13,11 +13,21 @@ jobs:
|
||||
name: Mosquitto build
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest", "release-v5.3"]
|
||||
idf_ver: ["latest", "release-v6.0", "release-v5.5", "release-v5.4", "release-v5.3", "release-v5.2", "release-v5.1"]
|
||||
example: ["broker"]
|
||||
include:
|
||||
# serverless_mqtt is not supported on >=v6.0 (esp-peer dependency)
|
||||
- idf_ver: "release-v5.3"
|
||||
example: "serverless_mqtt"
|
||||
- idf_ver: "release-v5.4"
|
||||
example: "serverless_mqtt"
|
||||
- idf_ver: "release-v5.5"
|
||||
example: "serverless_mqtt"
|
||||
|
||||
runs-on: ubuntu-22.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
env:
|
||||
TEST_DIR: components/mosquitto/examples
|
||||
TEST_DIR: components/mosquitto/examples/${{ matrix.example }}
|
||||
TARGET_TEST: broker
|
||||
TARGET_TEST_DIR: build_esp32_default
|
||||
steps:
|
||||
@@ -31,14 +41,17 @@ jobs:
|
||||
. ${IDF_PATH}/export.sh
|
||||
pip install idf-component-manager idf-build-apps --upgrade
|
||||
python ci/build_apps.py -c ${TEST_DIR} -m components/mosquitto/.build-test-rules.yml
|
||||
# upload only the target test artifacts
|
||||
cd ${TEST_DIR}/${TARGET_TEST}
|
||||
${GITHUB_WORKSPACE}/ci/clean_build_artifacts.sh `pwd`/${TARGET_TEST_DIR}
|
||||
zip -qur artifacts.zip ${TARGET_TEST_DIR}
|
||||
if [ "${{ matrix.example }}" == "${TARGET_TEST}" ]; then
|
||||
# upload only the target test artifacts
|
||||
cd ${TEST_DIR}
|
||||
${GITHUB_WORKSPACE}/ci/clean_build_artifacts.sh `pwd`/${TARGET_TEST_DIR}
|
||||
zip -qur artifacts.zip ${TARGET_TEST_DIR}
|
||||
fi
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: ${{ matrix.example == 'broker' }}
|
||||
with:
|
||||
name: mosq_target_esp32_${{ matrix.idf_ver }}
|
||||
path: ${{ env.TEST_DIR }}/${{ env.TARGET_TEST }}/artifacts.zip
|
||||
path: ${{ env.TEST_DIR }}/artifacts.zip
|
||||
if-no-files-found: error
|
||||
|
||||
test_mosq:
|
||||
@@ -50,7 +63,7 @@ jobs:
|
||||
needs: build_mosq
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest", "release-v5.3"]
|
||||
idf_ver: ["release-v5.4", "release-v5.5", "release-v6.0", "latest"]
|
||||
runs-on:
|
||||
- self-hosted
|
||||
- ESP32-ETHERNET-KIT
|
||||
@@ -66,6 +79,20 @@ jobs:
|
||||
- name: Run Test
|
||||
working-directory: ${{ env.TEST_DIR }}
|
||||
run: |
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init --path)"
|
||||
eval "$(pyenv init -)"
|
||||
if ! pyenv versions --bare | grep -q '^3\.12\.6$'; then
|
||||
echo "Installing Python 3.12.6..."
|
||||
pyenv install -s 3.12.6
|
||||
fi
|
||||
if ! pyenv virtualenvs --bare | grep -q '^myenv$'; then
|
||||
echo "Creating pyenv virtualenv 'myenv'..."
|
||||
pyenv virtualenv 3.12.6 myenv
|
||||
fi
|
||||
pyenv activate myenv
|
||||
python --version
|
||||
python -m pip install pytest-embedded-serial-esp pytest-embedded-idf pytest-rerunfailures pytest-timeout pytest-ignore-test-results
|
||||
unzip ci/artifacts.zip -d ci
|
||||
for dir in `ls -d ci/build_*`; do
|
||||
@@ -109,7 +136,7 @@ jobs:
|
||||
name: Build IDF tests
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest"]
|
||||
idf_ver: ["release-v5.5"] # TODO: add release-v6.0/latest with esp-mqtt directly
|
||||
idf_target: ["esp32"]
|
||||
test: [ { app: publish, path: "tools/test_apps/protocols/mqtt/publish_connect_test" }]
|
||||
runs-on: ubuntu-22.04
|
||||
@@ -154,7 +181,7 @@ jobs:
|
||||
needs: build_idf_tests_with_mosq
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest"]
|
||||
idf_ver: ["release-v5.5"]
|
||||
runs-on:
|
||||
- self-hosted
|
||||
- ESP32-ETHERNET-KIT
|
||||
@@ -169,6 +196,20 @@ jobs:
|
||||
- name: Run Test
|
||||
working-directory: ${{ env.TEST_DIR }}
|
||||
run: |
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init --path)"
|
||||
eval "$(pyenv init -)"
|
||||
if ! pyenv versions --bare | grep -q '^3\.12\.6$'; then
|
||||
echo "Installing Python 3.12.6..."
|
||||
pyenv install -s 3.12.6
|
||||
fi
|
||||
if ! pyenv virtualenvs --bare | grep -q '^myenv$'; then
|
||||
echo "Creating pyenv virtualenv 'myenv'..."
|
||||
pyenv virtualenv 3.12.6 myenv
|
||||
fi
|
||||
pyenv activate myenv
|
||||
python --version
|
||||
python -m pip install pytest-embedded-serial-esp pytest-embedded-idf pytest-rerunfailures pytest-timeout pytest-ignore-test-results "paho-mqtt<2" --upgrade
|
||||
unzip ci/artifacts.zip -d ci
|
||||
for dir in `ls -d ci/build_*`; do
|
||||
|
||||
7
.github/workflows/mqtt_cxx__build.yml
vendored
7
.github/workflows/mqtt_cxx__build.yml
vendored
@@ -13,9 +13,9 @@ jobs:
|
||||
name: Build
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest", "release-v5.0", "release-v5.1", "release-v5.2", "release-v5.3"]
|
||||
idf_ver: ["release-v5.1", "release-v5.2", "release-v5.3", "release-v5.4", "release-v5.5"]
|
||||
idf_target: ["esp32"]
|
||||
test: [ { app: mqtt-basic, path: "components/esp_mqtt_cxx/examples" }]
|
||||
test: [ { app: mqtt-basic, path: "components/esp_mqtt_cxx/examples" }, { app: test, path: "components/esp_mqtt_cxx/test/unit" }]
|
||||
runs-on: ubuntu-22.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
@@ -25,8 +25,7 @@ jobs:
|
||||
submodules: recursive
|
||||
- name: Build ${{ matrix.test.app }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
|
||||
shell: bash
|
||||
working-directory: ${{matrix.test.path}}
|
||||
run: |
|
||||
. ${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
|
||||
python ./ci/build_apps.py ./${{ matrix.test.path }} --target ${{ matrix.idf_target }} -vv --preserve-all -c
|
||||
|
||||
2
.github/workflows/pre_commit_check.yml
vendored
2
.github/workflows/pre_commit_check.yml
vendored
@@ -39,7 +39,7 @@ jobs:
|
||||
if ! pre-commit run --from-ref origin/HEAD --to-ref HEAD --hook-stage manual --show-diff-on-failure ; then
|
||||
echo ""
|
||||
echo "::notice::It looks like the commits in this PR have been made without having pre-commit hooks installed."
|
||||
echo "::notice::Please see https://github.com/espressif/esp-protocols/CONTRIBUTING.md for instructions."
|
||||
echo "::notice::Please see https://github.com/espressif/esp-protocols/blob/master/CONTRIBUTING.md for instructions."
|
||||
echo ""
|
||||
exit 1
|
||||
fi
|
||||
|
||||
16
.github/workflows/sockutls_build.yml
vendored
16
.github/workflows/sockutls_build.yml
vendored
@@ -28,7 +28,7 @@ jobs:
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
pip install idf-component-manager idf-build-apps --upgrade
|
||||
pip install idf-build-apps --upgrade
|
||||
python ci/build_apps.py ${TEST_DIR}
|
||||
cd ${TEST_DIR}
|
||||
${GITHUB_WORKSPACE}/ci/clean_build_artifacts.sh `pwd`/${TARGET_TEST_DIR}
|
||||
@@ -87,6 +87,20 @@ jobs:
|
||||
- name: Run Test
|
||||
working-directory: ${{ env.TEST_DIR }}
|
||||
run: |
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init --path)"
|
||||
eval "$(pyenv init -)"
|
||||
if ! pyenv versions --bare | grep -q '^3\.12\.6$'; then
|
||||
echo "Installing Python 3.12.6..."
|
||||
pyenv install -s 3.12.6
|
||||
fi
|
||||
if ! pyenv virtualenvs --bare | grep -q '^myenv$'; then
|
||||
echo "Creating pyenv virtualenv 'myenv'..."
|
||||
pyenv virtualenv 3.12.6 myenv
|
||||
fi
|
||||
pyenv activate myenv
|
||||
python --version
|
||||
unzip ci/artifacts.zip -d ci
|
||||
for dir in `ls -d ci/build_*`; do
|
||||
rm -rf build sdkconfig.defaults
|
||||
|
||||
2
.github/workflows/tls_cxx__build.yml
vendored
2
.github/workflows/tls_cxx__build.yml
vendored
@@ -26,5 +26,5 @@ jobs:
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
pip install idf-component-manager idf-build-apps --upgrade
|
||||
pip install idf-build-apps --upgrade
|
||||
python ./ci/build_apps.py ./components/mbedtls_cxx/${{ matrix.test.path }} -vv --preserve-all
|
||||
|
||||
@@ -65,14 +65,27 @@ jobs:
|
||||
with:
|
||||
name: websocket_bin_esp32_${{ matrix.idf_ver }}_${{ matrix.test.app }}
|
||||
path: ${{ env.TEST_DIR }}/ci/
|
||||
- name: Install Python packages
|
||||
- name: Run Example Test on target
|
||||
working-directory: ${{ env.TEST_DIR }}
|
||||
env:
|
||||
PIP_EXTRA_INDEX_URL: "https://www.piwheels.org/simple"
|
||||
run: |
|
||||
pip install --only-binary cryptography --extra-index-url https://dl.espressif.com/pypi/ -r $GITHUB_WORKSPACE/ci/requirements.txt
|
||||
- name: Run Example Test on target
|
||||
working-directory: ${{ env.TEST_DIR }}
|
||||
run: |
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
eval "$(pyenv init --path)"
|
||||
eval "$(pyenv init -)"
|
||||
if ! pyenv versions --bare | grep -q '^3\.12\.6$'; then
|
||||
echo "Installing Python 3.12.6..."
|
||||
pyenv install -s 3.12.6
|
||||
fi
|
||||
if ! pyenv virtualenvs --bare | grep -q '^myenv$'; then
|
||||
echo "Creating pyenv virtualenv 'myenv'..."
|
||||
pyenv virtualenv 3.12.6 myenv
|
||||
fi
|
||||
pyenv activate myenv
|
||||
python --version
|
||||
pip install --prefer-binary cryptography pytest-embedded pytest-embedded-serial-esp pytest-embedded-idf pytest-custom_exit_code esptool
|
||||
pip install --extra-index-url https://dl.espressif.com/pypi/ -r $GITHUB_WORKSPACE/ci/requirements.txt
|
||||
unzip ci/artifacts.zip -d ci
|
||||
for dir in `ls -d ci/build_*`; do
|
||||
rm -rf build sdkconfig.defaults
|
||||
|
||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -94,3 +94,9 @@ docs/html
|
||||
|
||||
# esp-idf managed components
|
||||
**/managed_components/**
|
||||
|
||||
# modem simulator uses esp-at clone
|
||||
common_components/modem_sim/modem_sim_esp32/
|
||||
|
||||
# repository release tools
|
||||
release_notes.txt
|
||||
|
||||
@@ -25,12 +25,8 @@ repos:
|
||||
(?x)^(
|
||||
.*.py
|
||||
)$
|
||||
- repo: https://github.com/myint/unify
|
||||
rev: v0.5
|
||||
hooks:
|
||||
- id: unify
|
||||
- repo: https://github.com/pre-commit/mirrors-yapf
|
||||
rev: "v0.32.0"
|
||||
- repo: https://github.com/google/yapf
|
||||
rev: "v0.43.0"
|
||||
hooks:
|
||||
- id: yapf
|
||||
args: ['style={based_on_style: google, column_limit: 160, indent_width: 4}']
|
||||
@@ -39,7 +35,7 @@ repos:
|
||||
hooks:
|
||||
- id: isort
|
||||
- repo: https://github.com/myint/eradicate/
|
||||
rev: v2.1.0
|
||||
rev: 3.0.0
|
||||
hooks:
|
||||
- id: eradicate
|
||||
- repo: https://github.com/espressif/check-copyright/
|
||||
@@ -61,8 +57,8 @@ repos:
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: commit message scopes
|
||||
name: "commit message must be scoped with: mdns, dns, modem, websocket, asio, mqtt_cxx, console, common, eppp, tls_cxx, mosq, sockutls, lws"
|
||||
entry: '\A(?!(feat|fix|ci|bump|test|docs|chore)\((mdns|dns|modem|common|console|websocket|asio|mqtt_cxx|examples|eppp|tls_cxx|mosq|sockutls|lws)\)\:)'
|
||||
name: "commit message must be scoped with: mdns, dns, modem, websocket, asio, mqtt_cxx, console, common, eppp, tls_cxx, mosq, sockutls, lws, modem_sim"
|
||||
entry: '\A(?!(feat|fix|ci|bump|test|docs|chore)\((mdns|dns|modem|common|console|websocket|asio|mqtt_cxx|examples|eppp|tls_cxx|mosq|sockutls|lws|modem_sim)\)\:)'
|
||||
language: pygrep
|
||||
args: [--multiline]
|
||||
stages: [commit-msg]
|
||||
|
||||
@@ -56,7 +56,7 @@ if __name__ == '__main__':
|
||||
build_dir='build_@t_@w',
|
||||
config_rules_str=args.rules,
|
||||
build_log_filename='build_log.txt',
|
||||
size_json_filename='size.json' if not args.linux else None,
|
||||
size_json_filename=None,
|
||||
check_warnings=True,
|
||||
manifest_files=args.manifests,
|
||||
default_build_targets=SUPPORTED_TARGETS,
|
||||
@@ -65,6 +65,7 @@ if __name__ == '__main__':
|
||||
|
||||
sys.exit(
|
||||
build_apps(apps,
|
||||
verbose=2,
|
||||
dry_run=False,
|
||||
keep_going=False,
|
||||
no_preserve=args.delete,
|
||||
|
||||
7
ci/config_env.sh
Executable file
7
ci/config_env.sh
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
# This script is used to set some common variables for the CI pipeline.
|
||||
|
||||
set -e
|
||||
|
||||
# MQTT public broker URI
|
||||
export CI_MQTT_BROKER_URI="test.mosquitto.org"
|
||||
@@ -1 +1,8 @@
|
||||
DeprecationWarning: pkg_resources is deprecated as an API
|
||||
Warning: Deprecated: Option '--flash_size' is deprecated. Use '--flash-size' instead.
|
||||
Warning: Deprecated: Option '--flash_mode' is deprecated. Use '--flash-mode' instead.
|
||||
Warning: Deprecated: Option '--flash_freq' is deprecated. Use '--flash-freq' instead.
|
||||
Warning: Deprecated: Command 'sign_data' is deprecated. Use 'sign-data' instead.
|
||||
Warning: Deprecated: Command 'extract_public_key' is deprecated. Use 'extract-public-key' instead.
|
||||
warning: unknown kconfig symbol 'EXAMPLE_ETH_PHY_IP101'
|
||||
WARNING: The following Kconfig variables were used in "if" clauses, but not
|
||||
|
||||
@@ -6,3 +6,4 @@ dpkt
|
||||
pytest
|
||||
idf_build_apps
|
||||
netifaces
|
||||
esptool>=5.1.0
|
||||
|
||||
51
common_components/modem_sim/README.md
Normal file
51
common_components/modem_sim/README.md
Normal file
@@ -0,0 +1,51 @@
|
||||
# Modem Simulator Component
|
||||
|
||||
A Wi-Fi modem simulator that extends ESP-AT with PPP server capabilities, turning ESP32 into a fully functional Wi-Fi modem. Perfect for testing AT commands and PPP connections without real hardware dependencies.
|
||||
|
||||
## What it does
|
||||
|
||||
- Extends ESP-AT firmware with PPP server functionality
|
||||
- Provides DATA mode for raw IP communication
|
||||
- Enables existing communication stacks (MQTT, HTTP, custom protocols) to work over Wi-Fi
|
||||
- Ideal for testing ESP-Modem library and CI reliability
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
cd common_components/modem_sim
|
||||
./install.sh
|
||||
source export.sh
|
||||
idf.py build
|
||||
```
|
||||
|
||||
## Custom Platform/Module
|
||||
|
||||
```bash
|
||||
./install.sh PLATFORM_ESP32S3 WROOM-32
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
The `sdkconfig.defaults` includes:
|
||||
- Wi-Fi and Bluetooth enabled
|
||||
- PPP server support
|
||||
- AT commands for HTTP/MQTT
|
||||
- 4MB flash configuration
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
modem_sim/
|
||||
├── install.sh # Installation script
|
||||
├── export.sh # Environment setup
|
||||
├── sdkconfig.defaults # Default configuration
|
||||
├── pppd_cmd/ # Custom PPP commands
|
||||
└── modem_sim_esp32/ # Generated ESP-AT build
|
||||
```
|
||||
|
||||
## Use Cases
|
||||
|
||||
- Testing ESP-Modem library without real hardware
|
||||
- Quick Wi-Fi connectivity for existing communication stacks
|
||||
- CI/CD testing with reliable modem simulation
|
||||
- Development and debugging of AT command implementations
|
||||
79
common_components/modem_sim/esp32.sdkconfig.defaults
Normal file
79
common_components/modem_sim/esp32.sdkconfig.defaults
Normal file
@@ -0,0 +1,79 @@
|
||||
# This file was generated using idf.py save-defconfig. It can be edited manually.
|
||||
# Espressif IoT Development Framework (ESP-IDF) 5.4.1 Project Minimal Configuration
|
||||
#
|
||||
CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE=y
|
||||
CONFIG_APP_PROJECT_VER_FROM_CONFIG=y
|
||||
CONFIG_APP_PROJECT_VER="v4.1.0.0-dev"
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="module_config/module_esp32_default/partitions_at.csv"
|
||||
CONFIG_PARTITION_TABLE_MD5=n
|
||||
CONFIG_AT_CUSTOMIZED_PARTITION_TABLE_FILE="module_config/module_esp32_default/at_customize.csv"
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BT_BTU_TASK_STACK_SIZE=5120
|
||||
CONFIG_BT_BLE_BLUFI_ENABLE=y
|
||||
CONFIG_BT_STACK_NO_LOG=y
|
||||
CONFIG_BT_BLE_DYNAMIC_ENV_MEMORY=y
|
||||
CONFIG_BTDM_CTRL_MODE_BTDM=y
|
||||
CONFIG_BTDM_CTRL_LPCLK_SEL_EXT_32K_XTAL=y
|
||||
CONFIG_BTDM_SCAN_DUPL_CACHE_SIZE=200
|
||||
CONFIG_ESP_TLS_PSK_VERIFICATION=y
|
||||
CONFIG_ESP_TLS_INSECURE=y
|
||||
CONFIG_ESP_TLS_SKIP_SERVER_CERT_VERIFY=y
|
||||
CONFIG_ESP_ERR_TO_NAME_LOOKUP=n
|
||||
CONFIG_GPIO_ESP32_SUPPORT_SWITCH_SLP_PULL=y
|
||||
CONFIG_ETH_DMA_RX_BUFFER_NUM=3
|
||||
CONFIG_ETH_DMA_TX_BUFFER_NUM=3
|
||||
CONFIG_HTTPD_MAX_REQ_HDR_LEN=1024
|
||||
CONFIG_HTTPD_MAX_URI_LEN=1024
|
||||
CONFIG_ESP_HTTPS_OTA_ALLOW_HTTP=y
|
||||
CONFIG_RTC_CLK_SRC_EXT_CRYS=y
|
||||
CONFIG_RTC_EXT_CRYST_ADDIT_CURRENT=y
|
||||
CONFIG_RTC_CLK_CAL_CYCLES=1024
|
||||
CONFIG_PM_ENABLE=y
|
||||
CONFIG_PM_SLP_DISABLE_GPIO=y
|
||||
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_80=y
|
||||
CONFIG_ESP_TASK_WDT_PANIC=y
|
||||
CONFIG_ESP_TASK_WDT_TIMEOUT_S=60
|
||||
CONFIG_ESP_DEBUG_OCDAWARE=n
|
||||
CONFIG_ESP_WIFI_IRAM_OPT=n
|
||||
CONFIG_ESP_WIFI_RX_IRAM_OPT=n
|
||||
CONFIG_ESP_WIFI_SLP_IRAM_OPT=y
|
||||
CONFIG_ESP_WIFI_SLP_BEACON_LOST_OPT=y
|
||||
CONFIG_ESP_WIFI_ESPNOW_MAX_ENCRYPT_NUM=0
|
||||
CONFIG_FATFS_LFN_HEAP=y
|
||||
CONFIG_FREERTOS_UNICORE=y
|
||||
CONFIG_FREERTOS_HZ=1000
|
||||
CONFIG_FREERTOS_USE_TICKLESS_IDLE=y
|
||||
CONFIG_FREERTOS_CHECK_MUTEX_GIVEN_BY_OWNER=n
|
||||
CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH=y
|
||||
CONFIG_HEAP_PLACE_FUNCTION_INTO_FLASH=y
|
||||
CONFIG_LOG_DEFAULT_LEVEL_ERROR=y
|
||||
CONFIG_LWIP_MAX_SOCKETS=16
|
||||
CONFIG_LWIP_SO_LINGER=y
|
||||
CONFIG_LWIP_SO_RCVBUF=y
|
||||
CONFIG_LWIP_IP4_REASSEMBLY=y
|
||||
CONFIG_LWIP_IP6_REASSEMBLY=y
|
||||
CONFIG_LWIP_IPV6_AUTOCONFIG=y
|
||||
CONFIG_LWIP_TCP_MAXRTX=6
|
||||
CONFIG_LWIP_TCP_SYNMAXRTX=3
|
||||
CONFIG_LWIP_PPP_SUPPORT=y
|
||||
CONFIG_LWIP_PPP_SERVER_SUPPORT=y
|
||||
CONFIG_LWIP_SNTP_MAX_SERVERS=3
|
||||
CONFIG_LWIP_SNTP_STARTUP_DELAY=n
|
||||
CONFIG_MBEDTLS_DYNAMIC_BUFFER=y
|
||||
CONFIG_MBEDTLS_DYNAMIC_FREE_CONFIG_DATA=y
|
||||
CONFIG_MBEDTLS_SSL_KEEP_PEER_CERTIFICATE=n
|
||||
CONFIG_MBEDTLS_HAVE_TIME_DATE=y
|
||||
CONFIG_MBEDTLS_DHM_C=y
|
||||
CONFIG_NEWLIB_NANO_FORMAT=y
|
||||
CONFIG_VFS_SUPPORT_TERMIOS=n
|
||||
CONFIG_WL_SECTOR_SIZE_512=y
|
||||
CONFIG_AT_PROCESS_TASK_STACK_SIZE=6144
|
||||
CONFIG_AT_MQTT_COMMAND_SUPPORT=y
|
||||
CONFIG_AT_HTTP_COMMAND_SUPPORT=y
|
||||
CONFIG_AT_BLE_COMMAND_SUPPORT=n
|
||||
CONFIG_AT_BLE_HID_COMMAND_SUPPORT=n
|
||||
CONFIG_AT_BLUFI_COMMAND_SUPPORT=n
|
||||
CONFIG_LWIP_IP_FORWARD=y
|
||||
CONFIG_LWIP_IPV4_NAPT=y
|
||||
63
common_components/modem_sim/esp32c6.sdkconfig.defaults
Normal file
63
common_components/modem_sim/esp32c6.sdkconfig.defaults
Normal file
@@ -0,0 +1,63 @@
|
||||
# This file was generated using idf.py save-defconfig. It can be edited manually.
|
||||
# Espressif IoT Development Framework (ESP-IDF) 5.4.1 Project Minimal Configuration
|
||||
#
|
||||
CONFIG_IDF_TARGET="esp32c6"
|
||||
CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE=y
|
||||
CONFIG_APP_PROJECT_VER_FROM_CONFIG=y
|
||||
CONFIG_APP_PROJECT_VER="v4.1.0.0-dev"
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="module_config/module_esp32c6_default/partitions_at.csv"
|
||||
CONFIG_PARTITION_TABLE_MD5=n
|
||||
CONFIG_AT_CUSTOMIZED_PARTITION_TABLE_FILE="module_config/module_esp32c6_default/at_customize.csv"
|
||||
CONFIG_AT_CUSTOMIZED_PARTITION_TABLE_OFFSET=0x1e000
|
||||
CONFIG_ESP_TLS_PSK_VERIFICATION=y
|
||||
CONFIG_ESP_TLS_INSECURE=y
|
||||
CONFIG_ESP_TLS_SKIP_SERVER_CERT_VERIFY=y
|
||||
CONFIG_ESP_ERR_TO_NAME_LOOKUP=n
|
||||
CONFIG_HTTPD_MAX_REQ_HDR_LEN=1024
|
||||
CONFIG_HTTPD_MAX_URI_LEN=1024
|
||||
CONFIG_ESP_HTTPS_OTA_ALLOW_HTTP=y
|
||||
CONFIG_RTC_CLK_SRC_EXT_CRYS=y
|
||||
CONFIG_RTC_CLK_CAL_CYCLES=1024
|
||||
CONFIG_ESP_PHY_MAC_BB_PD=y
|
||||
CONFIG_PM_ENABLE=y
|
||||
CONFIG_PM_DFS_INIT_AUTO=y
|
||||
CONFIG_ESP_TASK_WDT_PANIC=y
|
||||
CONFIG_ESP_TASK_WDT_TIMEOUT_S=60
|
||||
CONFIG_ESP_DEBUG_OCDAWARE=n
|
||||
CONFIG_ESP_WIFI_SLP_BEACON_LOST_OPT=y
|
||||
CONFIG_ESP_WIFI_ESPNOW_MAX_ENCRYPT_NUM=0
|
||||
CONFIG_FATFS_LFN_HEAP=y
|
||||
CONFIG_FREERTOS_HZ=1000
|
||||
CONFIG_FREERTOS_USE_TICKLESS_IDLE=y
|
||||
CONFIG_FREERTOS_CHECK_MUTEX_GIVEN_BY_OWNER=n
|
||||
CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH=y
|
||||
CONFIG_LOG_DEFAULT_LEVEL_ERROR=y
|
||||
CONFIG_LWIP_MAX_SOCKETS=16
|
||||
CONFIG_LWIP_SO_LINGER=y
|
||||
CONFIG_LWIP_SO_RCVBUF=y
|
||||
CONFIG_LWIP_IP4_REASSEMBLY=y
|
||||
CONFIG_LWIP_IP6_REASSEMBLY=y
|
||||
CONFIG_LWIP_IPV6_AUTOCONFIG=y
|
||||
CONFIG_LWIP_TCP_MAXRTX=6
|
||||
CONFIG_LWIP_TCP_SYNMAXRTX=3
|
||||
CONFIG_LWIP_PPP_SUPPORT=y
|
||||
CONFIG_LWIP_PPP_SERVER_SUPPORT=y
|
||||
CONFIG_LWIP_SNTP_MAX_SERVERS=3
|
||||
CONFIG_LWIP_SNTP_STARTUP_DELAY=n
|
||||
CONFIG_MBEDTLS_DYNAMIC_BUFFER=y
|
||||
CONFIG_MBEDTLS_DYNAMIC_FREE_CONFIG_DATA=y
|
||||
CONFIG_MBEDTLS_SSL_KEEP_PEER_CERTIFICATE=n
|
||||
CONFIG_MBEDTLS_HAVE_TIME_DATE=y
|
||||
CONFIG_MBEDTLS_DHM_C=y
|
||||
CONFIG_NEWLIB_NANO_FORMAT=y
|
||||
CONFIG_VFS_SUPPORT_TERMIOS=n
|
||||
CONFIG_WL_SECTOR_SIZE_512=y
|
||||
CONFIG_AT_PROCESS_TASK_STACK_SIZE=6144
|
||||
CONFIG_AT_MDNS_COMMAND_SUPPORT=n
|
||||
CONFIG_AT_WPS_COMMAND_SUPPORT=n
|
||||
CONFIG_AT_SMARTCONFIG_COMMAND_SUPPORT=n
|
||||
CONFIG_AT_PING_COMMAND_SUPPORT=n
|
||||
CONFIG_LWIP_IP_FORWARD=y
|
||||
CONFIG_LWIP_IPV4_NAPT=y
|
||||
11
common_components/modem_sim/export.sh
Executable file
11
common_components/modem_sim/export.sh
Executable file
@@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
|
||||
source $IDF_PATH/export.sh
|
||||
|
||||
export AT_CUSTOM_COMPONENTS="`pwd`/pppd_cmd"
|
||||
|
||||
cd modem_sim_esp32/esp-at
|
||||
|
||||
python -m pip install -r requirements.txt
|
||||
|
||||
python build.py reconfigure
|
||||
98
common_components/modem_sim/install.sh
Executable file
98
common_components/modem_sim/install.sh
Executable file
@@ -0,0 +1,98 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Create directory "modem_sim_esp32", go inside it
|
||||
# Usage: ./install.sh [platform] [module] [uart_tx_pin] [uart_rx_pin]
|
||||
|
||||
SCRIPT_DIR=$(pwd)
|
||||
UPDATE_UART_PINS_SCRIPT="$(cd "$(dirname "$0")" && pwd)/update_uart_pins.py"
|
||||
mkdir -p modem_sim_esp32
|
||||
cd modem_sim_esp32
|
||||
|
||||
if [ -z "$IDF_PATH" ]; then
|
||||
echo "Error: IDF_PATH environment variable is not set"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Default ESP_AT_VERSION uses this specific commit from master to support new chips and features
|
||||
ESP_AT_VERSION="aa9d7e0e9b741744f7bf5bec3bbf887cff033d5f"
|
||||
|
||||
# Shallow clone of esp-at.git at $ESP_AT_VERSION
|
||||
if [ ! -d "esp-at" ]; then
|
||||
# cannot shallow clone from a specific commit, so we init, shallow fetch, and checkout
|
||||
mkdir -p esp-at && cd esp-at && git init && git remote add origin https://github.com/espressif/esp-at.git
|
||||
git fetch --depth 1 origin $ESP_AT_VERSION && git checkout $ESP_AT_VERSION
|
||||
else
|
||||
echo "esp-at directory already exists, skipping clone."
|
||||
cd esp-at
|
||||
fi
|
||||
|
||||
# Add esp-idf directory which is a symlink to the $IDF_PATH
|
||||
if [ ! -L "esp-idf" ]; then
|
||||
ln -sf "$IDF_PATH" esp-idf
|
||||
else
|
||||
echo "esp-idf symlink already exists, skipping."
|
||||
fi
|
||||
|
||||
# Create "build" directory
|
||||
mkdir -p build
|
||||
|
||||
# Default values for platform and module
|
||||
platform="PLATFORM_ESP32"
|
||||
module="WROOM-32"
|
||||
uart_tx_pin=""
|
||||
uart_rx_pin=""
|
||||
|
||||
# Override defaults if parameters are provided
|
||||
if [ ! -z "$1" ]; then
|
||||
platform="$1"
|
||||
fi
|
||||
if [ ! -z "$2" ]; then
|
||||
module="$2"
|
||||
fi
|
||||
if [ ! -z "$3" ]; then
|
||||
uart_tx_pin="$3"
|
||||
fi
|
||||
if [ ! -z "$4" ]; then
|
||||
uart_rx_pin="$4"
|
||||
fi
|
||||
|
||||
target="${platform##*_}"
|
||||
target="${target,,}"
|
||||
|
||||
# Use provided pins for description when present; otherwise keep defaults
|
||||
description="4MB, Wi-Fi + BLE, OTA, TX:17 RX:16"
|
||||
if [ -n "$uart_tx_pin" ] || [ -n "$uart_rx_pin" ]; then
|
||||
desc_tx=${uart_tx_pin:-17}
|
||||
desc_rx=${uart_rx_pin:-16}
|
||||
description="4MB, Wi-Fi + BLE, OTA, TX:${desc_tx} RX:${desc_rx}"
|
||||
fi
|
||||
|
||||
# Create file "build/module_info.json" with content
|
||||
cat > build/module_info.json << EOF
|
||||
{
|
||||
"platform": "$platform",
|
||||
"module": "$module",
|
||||
"description": "$description",
|
||||
"silence": 0
|
||||
}
|
||||
EOF
|
||||
|
||||
# Optionally update UART pins in factory_param_data.csv for the selected module
|
||||
if [ -n "$uart_tx_pin" ] || [ -n "$uart_rx_pin" ]; then
|
||||
csv_path="components/customized_partitions/raw_data/factory_param/factory_param_data.csv"
|
||||
if [ ! -f "$csv_path" ]; then
|
||||
echo "Warning: $csv_path not found; skipping UART pin update."
|
||||
else
|
||||
python3 "$UPDATE_UART_PINS_SCRIPT" "$platform" "$module" "$uart_tx_pin" "$uart_rx_pin" "$csv_path"
|
||||
echo "Updated UART pins in $csv_path"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Copy the platform-specific sdkconfig.defaults file if it exists
|
||||
if [ -f "$SCRIPT_DIR/${target}.sdkconfig.defaults" ]; then
|
||||
cp "$SCRIPT_DIR/${target}.sdkconfig.defaults" "module_config/module_${target}_default/sdkconfig.defaults"
|
||||
fi
|
||||
|
||||
echo "Installation completed successfully!"
|
||||
echo "Created modem_sim_esp32 directory with esp-at repository and configuration"
|
||||
6
common_components/modem_sim/pppd_cmd/CMakeLists.txt
Normal file
6
common_components/modem_sim/pppd_cmd/CMakeLists.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
idf_component_register(
|
||||
SRCS additional_commands.c
|
||||
INCLUDE_DIRS include
|
||||
REQUIRES at freertos nvs_flash)
|
||||
|
||||
idf_component_set_property(${COMPONENT_NAME} WHOLE_ARCHIVE TRUE)
|
||||
411
common_components/modem_sim/pppd_cmd/additional_commands.c
Normal file
411
common_components/modem_sim/pppd_cmd/additional_commands.c
Normal file
@@ -0,0 +1,411 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include "esp_at.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/uart.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "esp_netif.h"
|
||||
#include "esp_netif_ppp.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_http_server.h"
|
||||
#include "esp_timer.h"
|
||||
|
||||
static uint8_t at_test_cmd_test(uint8_t *cmd_name)
|
||||
{
|
||||
uint8_t buffer[64] = {0};
|
||||
snprintf((char *)buffer, 64, "test command: <AT%s=?> is executed\r\n", cmd_name);
|
||||
esp_at_port_write_data(buffer, strlen((char *)buffer));
|
||||
|
||||
return ESP_AT_RESULT_CODE_OK;
|
||||
}
|
||||
|
||||
static uint8_t at_query_cmd_test(uint8_t *cmd_name)
|
||||
{
|
||||
uint8_t buffer[64] = {0};
|
||||
snprintf((char *)buffer, 64, "query command: <AT%s?> is executed\r\n", cmd_name);
|
||||
esp_at_port_write_data(buffer, strlen((char *)buffer));
|
||||
|
||||
return ESP_AT_RESULT_CODE_OK;
|
||||
}
|
||||
|
||||
static uint8_t at_setup_cmd_test(uint8_t para_num)
|
||||
{
|
||||
uint8_t index = 0;
|
||||
printf("setup command: <AT%s=%d> is executed\r\n", esp_at_get_current_cmd_name(), para_num);
|
||||
|
||||
// get first parameter, and parse it into a digit
|
||||
int32_t digit = 0;
|
||||
if (esp_at_get_para_as_digit(index++, &digit) != ESP_AT_PARA_PARSE_RESULT_OK) {
|
||||
return ESP_AT_RESULT_CODE_ERROR;
|
||||
}
|
||||
printf("digit: %d\r\n", digit);
|
||||
|
||||
// get second parameter, and parse it into a string
|
||||
uint8_t *str = NULL;
|
||||
if (esp_at_get_para_as_str(index++, &str) != ESP_AT_PARA_PARSE_RESULT_OK) {
|
||||
return ESP_AT_RESULT_CODE_ERROR;
|
||||
}
|
||||
printf("string: %s\r\n", str);
|
||||
|
||||
// allocate a buffer and construct the data, then send the data to mcu via interface (uart/spi/sdio/socket)
|
||||
uint8_t *buffer = (uint8_t *)malloc(512);
|
||||
if (!buffer) {
|
||||
return ESP_AT_RESULT_CODE_ERROR;
|
||||
}
|
||||
int len = snprintf((char *)buffer, 512, "setup command: <AT%s=%d,\"%s\"> is executed\r\n",
|
||||
esp_at_get_current_cmd_name(), digit, str);
|
||||
esp_at_port_write_data(buffer, len);
|
||||
|
||||
// remember to free the buffer
|
||||
free(buffer);
|
||||
|
||||
return ESP_AT_RESULT_CODE_OK;
|
||||
}
|
||||
|
||||
#define TAG "at_custom_cmd"
|
||||
static esp_netif_t *s_netif = NULL;
|
||||
static httpd_handle_t http_server = NULL;
|
||||
|
||||
static void on_ppp_event(void *arg, esp_event_base_t base, int32_t event_id, void *data)
|
||||
{
|
||||
esp_netif_t **netif = data;
|
||||
if (base == NETIF_PPP_STATUS && event_id == NETIF_PPP_ERRORUSER) {
|
||||
printf("Disconnected!");
|
||||
}
|
||||
}
|
||||
|
||||
static void on_ip_event(void *arg, esp_event_base_t base, int32_t event_id, void *data)
|
||||
{
|
||||
ip_event_got_ip_t *event = (ip_event_got_ip_t *)data;
|
||||
esp_netif_t *netif = event->esp_netif;
|
||||
if (event_id == IP_EVENT_PPP_GOT_IP) {
|
||||
printf("Got IPv4 event: Interface \"%s(%s)\" address: " IPSTR, esp_netif_get_desc(netif),
|
||||
esp_netif_get_ifkey(netif), IP2STR(&event->ip_info.ip));
|
||||
ESP_ERROR_CHECK(esp_netif_napt_enable(s_netif));
|
||||
|
||||
} else if (event_id == IP_EVENT_PPP_LOST_IP) {
|
||||
ESP_LOGI(TAG, "Disconnected");
|
||||
}
|
||||
}
|
||||
|
||||
static SemaphoreHandle_t at_sync_sema = NULL;
|
||||
static void wait_data_callback(void)
|
||||
{
|
||||
static uint8_t buffer[1500] = {0};
|
||||
int len = esp_at_port_read_data(buffer, sizeof(buffer) - 1);
|
||||
|
||||
// Check for the escape sequence "+++" in the received data
|
||||
const uint8_t escape_seq[] = "+++";
|
||||
uint8_t *escape_ptr = memmem(buffer, len, escape_seq, 3);
|
||||
|
||||
if (escape_ptr != NULL) {
|
||||
printf("Found +++ sequence, signal to the command processing thread\n");
|
||||
|
||||
int data_before_escape = escape_ptr - buffer;
|
||||
if (data_before_escape > 0) {
|
||||
esp_netif_receive(s_netif, buffer, data_before_escape, NULL);
|
||||
}
|
||||
|
||||
if (at_sync_sema) {
|
||||
xSemaphoreGive(at_sync_sema);
|
||||
}
|
||||
return;
|
||||
}
|
||||
esp_netif_receive(s_netif, buffer, len, NULL);
|
||||
}
|
||||
|
||||
static esp_err_t transmit(void *h, void *buffer, size_t len)
|
||||
{
|
||||
printf("transmit: %d bytes\n", len);
|
||||
esp_at_port_write_data(buffer, len);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static uint8_t at_exe_cmd_test(uint8_t *cmd_name)
|
||||
{
|
||||
uint8_t buffer[64] = {0};
|
||||
snprintf((char *)buffer, 64, "execute command: <AT%s> is executed\r\n", cmd_name);
|
||||
esp_at_port_write_data(buffer, strlen((char *)buffer));
|
||||
printf("Command <AT%s> executed successfully\r\n", cmd_name);
|
||||
if (!at_sync_sema) {
|
||||
at_sync_sema = xSemaphoreCreateBinary();
|
||||
assert(at_sync_sema != NULL);
|
||||
esp_netif_driver_ifconfig_t driver_cfg = {
|
||||
.handle = (void *)1,
|
||||
.transmit = transmit,
|
||||
};
|
||||
const esp_netif_driver_ifconfig_t *ppp_driver_cfg = &driver_cfg;
|
||||
|
||||
esp_netif_inherent_config_t base_netif_cfg = ESP_NETIF_INHERENT_DEFAULT_PPP();
|
||||
esp_netif_config_t netif_ppp_config = { .base = &base_netif_cfg,
|
||||
.driver = ppp_driver_cfg,
|
||||
.stack = ESP_NETIF_NETSTACK_DEFAULT_PPP
|
||||
};
|
||||
|
||||
s_netif = esp_netif_new(&netif_ppp_config);
|
||||
esp_netif_ppp_config_t netif_params;
|
||||
ESP_ERROR_CHECK(esp_netif_ppp_get_params(s_netif, &netif_params));
|
||||
netif_params.ppp_our_ip4_addr.addr = ESP_IP4TOADDR(192, 168, 11, 1);
|
||||
netif_params.ppp_their_ip4_addr.addr = ESP_IP4TOADDR(192, 168, 11, 2);
|
||||
netif_params.ppp_error_event_enabled = true;
|
||||
ESP_ERROR_CHECK(esp_netif_ppp_set_params(s_netif, &netif_params));
|
||||
if (esp_event_handler_register(IP_EVENT, ESP_EVENT_ANY_ID, on_ip_event, NULL) != ESP_OK) {
|
||||
printf("Failed to register IP event handler");
|
||||
}
|
||||
if (esp_event_handler_register(NETIF_PPP_STATUS, ESP_EVENT_ANY_ID, on_ppp_event, NULL) != ESP_OK) {
|
||||
printf("Failed to register NETIF_PPP_STATUS event handler");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
esp_at_port_write_data((uint8_t *)"CONNECT\r\n", strlen("CONNECT\r\n"));
|
||||
|
||||
// set the callback function which will be called by AT port after receiving the input data
|
||||
esp_at_port_enter_specific(wait_data_callback);
|
||||
esp_netif_action_start(s_netif, 0, 0, 0);
|
||||
esp_netif_action_connected(s_netif, 0, 0, 0);
|
||||
|
||||
while (xSemaphoreTake(at_sync_sema, pdMS_TO_TICKS(1000)) == pdFALSE) {
|
||||
printf(".");
|
||||
}
|
||||
return ESP_AT_RESULT_CODE_OK;
|
||||
}
|
||||
|
||||
static uint8_t at_test_cereg(uint8_t *cmd_name)
|
||||
{
|
||||
printf("%s: AT command <AT%s> is executed\r\n", __func__, cmd_name);
|
||||
return ESP_AT_RESULT_CODE_OK;
|
||||
}
|
||||
|
||||
static uint8_t at_query_cereg(uint8_t *cmd_name)
|
||||
{
|
||||
printf("%s: AT command <AT%s> is executed\r\n", __func__, cmd_name);
|
||||
static uint8_t buffer[] = "+CEREG: 7,8\r\n";
|
||||
esp_at_port_write_data(buffer, sizeof(buffer));
|
||||
return ESP_AT_RESULT_CODE_OK;
|
||||
}
|
||||
|
||||
static uint8_t at_setup_cereg(uint8_t num)
|
||||
{
|
||||
printf("%s: AT command <AT%d> is executed\r\n", __func__, num);
|
||||
return ESP_AT_RESULT_CODE_OK;
|
||||
}
|
||||
|
||||
static uint8_t at_exe_cereg(uint8_t *cmd_name)
|
||||
{
|
||||
printf("%s: AT command <AT%s> is executed\r\n", __func__, cmd_name);
|
||||
return ESP_AT_RESULT_CODE_OK;
|
||||
}
|
||||
|
||||
static esp_err_t hello_get_handler(httpd_req_t *req)
|
||||
{
|
||||
const char* resp_str = "Hello from ESP-AT HTTP Server!";
|
||||
httpd_resp_send(req, resp_str, HTTPD_RESP_USE_STRLEN);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t root_get_handler(httpd_req_t *req)
|
||||
{
|
||||
const char* resp_str = "ESP-AT HTTP Server is running";
|
||||
httpd_resp_send(req, resp_str, HTTPD_RESP_USE_STRLEN);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t test_get_handler(httpd_req_t *req)
|
||||
{
|
||||
const char* resp_str = "{\"status\":\"success\",\"message\":\"Test endpoint working\",\"timestamp\":12345}";
|
||||
httpd_resp_set_type(req, "application/json");
|
||||
httpd_resp_send(req, resp_str, HTTPD_RESP_USE_STRLEN);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t async_get_handler(httpd_req_t *req)
|
||||
{
|
||||
printf("Starting async chunked response handler\r\n");
|
||||
|
||||
// Set content type for plain text response
|
||||
httpd_resp_set_type(req, "text/plain");
|
||||
|
||||
// Static counter to track requests
|
||||
static uint8_t req_count = 0;
|
||||
req_count++;
|
||||
|
||||
// Send initial response with request count
|
||||
char buffer[256];
|
||||
snprintf(buffer, sizeof(buffer), "=== Async Response #%d ===\r\n", req_count);
|
||||
httpd_resp_sendstr_chunk(req, buffer);
|
||||
|
||||
// Long message broken into chunks
|
||||
const char* chunks[] = {
|
||||
"This is a simulated slow server response.\r\n",
|
||||
"Chunk 1: The ESP-AT HTTP server is demonstrating...\r\n",
|
||||
"Chunk 2: ...asynchronous chunked transfer encoding...\r\n",
|
||||
"Chunk 3: ...with artificial delays between chunks...\r\n",
|
||||
"Chunk 4: ...to simulate real-world network conditions.\r\n",
|
||||
"Chunk 5: Processing data... please wait...\r\n",
|
||||
"Chunk 6: Still processing... almost done...\r\n",
|
||||
"Chunk 7: Final chunk - transfer complete!\r\n",
|
||||
"=== END OF RESPONSE ===\r\n"
|
||||
};
|
||||
|
||||
int num_chunks = sizeof(chunks) / sizeof(chunks[0]);
|
||||
|
||||
// Send each chunk with delays
|
||||
for (int i = 0; i < num_chunks; i++) {
|
||||
// Add a delay to simulate slow processing
|
||||
vTaskDelay(pdMS_TO_TICKS(1500)); // 1.5 second delay between chunks
|
||||
|
||||
// Add chunk number and timestamp
|
||||
snprintf(buffer, sizeof(buffer), "[%d/%d] [%d ms] %s",
|
||||
i + 1, num_chunks, (int)(esp_timer_get_time() / 1000), chunks[i]);
|
||||
|
||||
printf("Sending chunk %d: %s", i + 1, chunks[i]);
|
||||
httpd_resp_sendstr_chunk(req, buffer);
|
||||
}
|
||||
|
||||
// Add final summary
|
||||
vTaskDelay(pdMS_TO_TICKS(500));
|
||||
snprintf(buffer, sizeof(buffer), "\r\nTransfer completed in %d chunks with delays.\r\n", num_chunks);
|
||||
httpd_resp_sendstr_chunk(req, buffer);
|
||||
|
||||
// Send NULL to signal end of chunked transfer
|
||||
httpd_resp_sendstr_chunk(req, NULL);
|
||||
|
||||
printf("Async chunked response completed\r\n");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static const httpd_uri_t hello = {
|
||||
.uri = "/hello",
|
||||
.method = HTTP_GET,
|
||||
.handler = hello_get_handler,
|
||||
.user_ctx = NULL
|
||||
};
|
||||
|
||||
static const httpd_uri_t root = {
|
||||
.uri = "/",
|
||||
.method = HTTP_GET,
|
||||
.handler = root_get_handler,
|
||||
.user_ctx = NULL
|
||||
};
|
||||
|
||||
static const httpd_uri_t test = {
|
||||
.uri = "/test",
|
||||
.method = HTTP_GET,
|
||||
.handler = test_get_handler,
|
||||
.user_ctx = NULL
|
||||
};
|
||||
|
||||
static const httpd_uri_t async_uri = {
|
||||
.uri = "/async",
|
||||
.method = HTTP_GET,
|
||||
.handler = async_get_handler,
|
||||
.user_ctx = NULL
|
||||
};
|
||||
|
||||
static esp_err_t start_http_server(void)
|
||||
{
|
||||
if (http_server != NULL) {
|
||||
printf("HTTP server already running\r\n");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
|
||||
config.server_port = 8080;
|
||||
config.lru_purge_enable = true;
|
||||
|
||||
printf("Starting HTTP server on port: %d\r\n", config.server_port);
|
||||
if (httpd_start(&http_server, &config) == ESP_OK) {
|
||||
printf("Registering URI handlers\r\n");
|
||||
httpd_register_uri_handler(http_server, &hello);
|
||||
httpd_register_uri_handler(http_server, &root);
|
||||
httpd_register_uri_handler(http_server, &test);
|
||||
httpd_register_uri_handler(http_server, &async_uri);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
printf("Error starting HTTP server!\r\n");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
static esp_err_t stop_http_server(void)
|
||||
{
|
||||
if (http_server != NULL) {
|
||||
httpd_stop(http_server);
|
||||
http_server = NULL;
|
||||
printf("HTTP server stopped\r\n");
|
||||
return ESP_OK;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/* HTTP Server AT Commands */
|
||||
static uint8_t at_test_httpd(uint8_t *cmd_name)
|
||||
{
|
||||
uint8_t buffer[64] = {0};
|
||||
snprintf((char *)buffer, 64, "AT%s=<0/1> - Start/Stop HTTP server\r\n", cmd_name);
|
||||
esp_at_port_write_data(buffer, strlen((char *)buffer));
|
||||
return ESP_AT_RESULT_CODE_OK;
|
||||
}
|
||||
|
||||
static uint8_t at_query_httpd(uint8_t *cmd_name)
|
||||
{
|
||||
uint8_t buffer[64] = {0};
|
||||
snprintf((char *)buffer, 64, "+HTTPD:%d\r\n", http_server != NULL ? 1 : 0);
|
||||
esp_at_port_write_data(buffer, strlen((char *)buffer));
|
||||
return ESP_AT_RESULT_CODE_OK;
|
||||
}
|
||||
|
||||
static uint8_t at_setup_httpd(uint8_t para_num)
|
||||
{
|
||||
int32_t action = 0;
|
||||
if (esp_at_get_para_as_digit(0, &action) != ESP_AT_PARA_PARSE_RESULT_OK) {
|
||||
return ESP_AT_RESULT_CODE_ERROR;
|
||||
}
|
||||
|
||||
if (action == 1) {
|
||||
if (start_http_server() == ESP_OK) {
|
||||
printf("HTTP server started successfully\r\n");
|
||||
return ESP_AT_RESULT_CODE_OK;
|
||||
}
|
||||
} else if (action == 0) {
|
||||
if (stop_http_server() == ESP_OK) {
|
||||
return ESP_AT_RESULT_CODE_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return ESP_AT_RESULT_CODE_ERROR;
|
||||
}
|
||||
|
||||
static uint8_t at_exe_httpd(uint8_t *cmd_name)
|
||||
{
|
||||
// Default action: start server
|
||||
if (start_http_server() == ESP_OK) {
|
||||
printf("HTTP server started via execute command\r\n");
|
||||
return ESP_AT_RESULT_CODE_OK;
|
||||
}
|
||||
return ESP_AT_RESULT_CODE_ERROR;
|
||||
}
|
||||
|
||||
|
||||
static const esp_at_cmd_struct at_custom_cmd[] = {
|
||||
{"+PPPD", at_test_cmd_test, at_query_cmd_test, at_setup_cmd_test, at_exe_cmd_test},
|
||||
{"+CEREG", at_test_cereg, at_query_cereg, at_setup_cereg, at_exe_cereg},
|
||||
{"+HTTPD", at_test_httpd, at_query_httpd, at_setup_httpd, at_exe_httpd},
|
||||
};
|
||||
|
||||
bool esp_at_custom_cmd_register(void)
|
||||
{
|
||||
return esp_at_custom_cmd_array_regist(at_custom_cmd, sizeof(at_custom_cmd) / sizeof(esp_at_cmd_struct));
|
||||
}
|
||||
|
||||
ESP_AT_CMD_SET_INIT_FN(esp_at_custom_cmd_register, 1);
|
||||
12
common_components/modem_sim/pppd_cmd/include/at_custom_cmd.h
Normal file
12
common_components/modem_sim/pppd_cmd/include/at_custom_cmd.h
Normal file
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
#include "esp_at_core.h"
|
||||
#include "esp_at.h"
|
||||
|
||||
/**
|
||||
* @brief You can include more header files here for your own AT commands.
|
||||
*/
|
||||
46
common_components/modem_sim/update_uart_pins.py
Normal file
46
common_components/modem_sim/update_uart_pins.py
Normal file
@@ -0,0 +1,46 @@
|
||||
#!/usr/bin/env python3
|
||||
# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
import csv
|
||||
import pathlib
|
||||
import sys
|
||||
|
||||
|
||||
def update_uart_pins(platform: str, module: str, tx_pin: str, rx_pin: str, csv_path: str) -> None:
|
||||
path = pathlib.Path(csv_path)
|
||||
rows = []
|
||||
found = False
|
||||
|
||||
with path.open(newline="") as f:
|
||||
reader = csv.DictReader(f)
|
||||
fieldnames = reader.fieldnames
|
||||
for row in reader:
|
||||
if row.get("platform") == platform and row.get("module_name") == module:
|
||||
if tx_pin:
|
||||
row["uart_tx_pin"] = tx_pin
|
||||
if rx_pin:
|
||||
row["uart_rx_pin"] = rx_pin
|
||||
found = True
|
||||
rows.append(row)
|
||||
|
||||
if not found:
|
||||
print(f"Warning: no row updated for platform={platform} module={module}")
|
||||
|
||||
with path.open("w", newline="") as f:
|
||||
writer = csv.DictWriter(f, fieldnames=fieldnames)
|
||||
writer.writeheader()
|
||||
writer.writerows(rows)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
if len(sys.argv) != 6:
|
||||
print("Usage: update_uart_pins.py <platform> <module> <uart_tx_pin> <uart_rx_pin> <csv_path>")
|
||||
return 1
|
||||
|
||||
platform, module, tx_pin, rx_pin, csv_path = sys.argv[1:6]
|
||||
update_uart_pins(platform, module, tx_pin, rx_pin, csv_path)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -28,7 +28,7 @@ posix_event::posix_event()
|
||||
}
|
||||
} // namespace asio::detail
|
||||
|
||||
extern "C" int pause (void)
|
||||
extern "C" int pause(void)
|
||||
{
|
||||
while (true) {
|
||||
::sleep(UINT_MAX);
|
||||
|
||||
@@ -9,4 +9,8 @@ dependencies:
|
||||
override_path: '../console_simple_init'
|
||||
public: true
|
||||
espressif/ethernet_init:
|
||||
version: '>=0.0.7'
|
||||
matches:
|
||||
- if: idf_version >=6.0
|
||||
version: ^1.0.0
|
||||
- if: idf_version <6.0
|
||||
version: '==0.3.0'
|
||||
|
||||
@@ -9,3 +9,7 @@ dependencies:
|
||||
version: '>=1.1.0'
|
||||
override_path: '../console_simple_init'
|
||||
public: true
|
||||
espressif/mqtt:
|
||||
rules:
|
||||
- if: idf_version >=6.0
|
||||
version: ^1.0.0
|
||||
|
||||
@@ -3,6 +3,6 @@ commitizen:
|
||||
bump_message: 'bump(console): $current_version -> $new_version'
|
||||
pre_bump_hooks: python ../../ci/changelog.py console_cmd_ping
|
||||
tag_format: console_cmd_ping-v$version
|
||||
version: 1.1.0
|
||||
version: 1.2.0
|
||||
version_files:
|
||||
- idf_component.yml
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# Changelog
|
||||
|
||||
## [1.2.0](https://github.com/espressif/esp-protocols/commits/console_cmd_ping-v1.2.0)
|
||||
|
||||
### Features
|
||||
|
||||
- Add support for interface argument ([90ddb04e](https://github.com/espressif/esp-protocols/commit/90ddb04e))
|
||||
|
||||
## [1.1.0](https://github.com/espressif/esp-protocols/commits/console_cmd_ping-v1.1.0)
|
||||
|
||||
### Features
|
||||
|
||||
@@ -48,7 +48,7 @@ For more details refer [IDF Component Manager](https://docs.espressif.com/projec
|
||||
|
||||
### ping:
|
||||
```
|
||||
ping [-W <t>] [-i <t>] [-s <n>] [-c <n>] [-Q <n>] [-T <n>] <host>
|
||||
ping [-W <t>] [-i <t>] [-s <n>] [-c <n>] [-Q <n>] [-T <n>] [-I <n>] <host>
|
||||
send ICMP ECHO_REQUEST to network hosts
|
||||
-W, --timeout=<t> Time to wait for a response, in seconds
|
||||
-i, --interval=<t> Wait interval seconds between sending each packet
|
||||
@@ -56,6 +56,7 @@ ping [-W <t>] [-i <t>] [-s <n>] [-c <n>] [-Q <n>] [-T <n>] <host>
|
||||
-c, --count=<n> Stop after sending count packets
|
||||
-Q, --tos=<n> Set Type of Service related bits in IP datagrams
|
||||
-T, --ttl=<n> Set Time to Live related bits in IP datagrams
|
||||
-I, --interface=<n> Set Interface number 0=no-interface selected, >0 netif number + 1 (1 is usually 'lo0')
|
||||
<host> Host address
|
||||
|
||||
getaddrinfo [-f <AF>] [-F <FLAGS>]... [-p <port>] <hostname>
|
||||
@@ -121,8 +122,8 @@ getaddrinfo -f AF_INET -F AI_PASSIVE www.example.com
|
||||
ping www.example.com
|
||||
```
|
||||
|
||||
2. To specify additional options, such as timeout, interval, packet size, etc.:
|
||||
2. To specify additional options, such as timeout, interval, packet size, interface, etc.:
|
||||
|
||||
```
|
||||
ping -W 5 -i 1 -s 64 -c 4 -Q 0x10 -T 64 www.example.com
|
||||
ping -W 5 -i 1 -s 64 -c 4 -Q 0x10 -T 64 -I 0 www.example.com
|
||||
```
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -99,6 +99,7 @@ static struct {
|
||||
struct arg_int *count;
|
||||
struct arg_int *tos;
|
||||
struct arg_int *ttl;
|
||||
struct arg_int *interface;
|
||||
struct arg_str *host;
|
||||
struct arg_end *end;
|
||||
} ping_args;
|
||||
@@ -137,6 +138,10 @@ static int do_ping_cmd(int argc, char **argv)
|
||||
config.ttl = (uint32_t)(ping_args.ttl->ival[0]);
|
||||
}
|
||||
|
||||
if (ping_args.interface->count > 0) {
|
||||
config.interface = (uint32_t)(ping_args.interface->ival[0]);
|
||||
}
|
||||
|
||||
// parse IP address
|
||||
struct sockaddr_in6 sock_addr6;
|
||||
ip_addr_t target_addr = {0};
|
||||
@@ -155,12 +160,12 @@ static int do_ping_cmd(int argc, char **argv)
|
||||
}
|
||||
if (res->ai_family == AF_INET) {
|
||||
#if CONFIG_LWIP_IPV4
|
||||
struct in_addr addr4 = ((struct sockaddr_in *) (res->ai_addr))->sin_addr;
|
||||
struct in_addr addr4 = ((struct sockaddr_in *)(res->ai_addr))->sin_addr;
|
||||
inet_addr_to_ip4addr(ip_2_ip4(&target_addr), &addr4);
|
||||
#endif
|
||||
} else {
|
||||
#if CONFIG_LWIP_IPV6
|
||||
struct in6_addr addr6 = ((struct sockaddr_in6 *) (res->ai_addr))->sin6_addr;
|
||||
struct in6_addr addr6 = ((struct sockaddr_in6 *)(res->ai_addr))->sin6_addr;
|
||||
inet6_addr_to_ip6addr(ip_2_ip6(&target_addr), &addr6);
|
||||
#endif
|
||||
}
|
||||
@@ -204,6 +209,7 @@ esp_err_t console_cmd_ping_register(void)
|
||||
ping_args.count = arg_int0("c", "count", "<n>", "Stop after sending count packets");
|
||||
ping_args.tos = arg_int0("Q", "tos", "<n>", "Set Type of Service related bits in IP datagrams");
|
||||
ping_args.ttl = arg_int0("T", "ttl", "<n>", "Set Time to Live related bits in IP datagrams");
|
||||
ping_args.interface = arg_int0("I", "interface", "<n>", "Set Interface number");
|
||||
ping_args.host = arg_str1(NULL, NULL, "<host>", "Host address");
|
||||
ping_args.end = arg_end(1);
|
||||
const esp_console_cmd_t ping_cmd = {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
version: 1.1.0
|
||||
version: 1.2.0
|
||||
url: https://github.com/espressif/esp-protocols/tree/master/components/console_cmd_ping
|
||||
description: The component provides a console where the 'ping' command can be executed.
|
||||
dependencies:
|
||||
|
||||
@@ -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.3.0
|
||||
version: 1.1.4
|
||||
version_files:
|
||||
- idf_component.yml
|
||||
|
||||
@@ -1,5 +1,65 @@
|
||||
# Changelog
|
||||
|
||||
## [1.1.4](https://github.com/espressif/esp-protocols/commits/eppp-v1.1.4)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Fixed missing freertos deps ([f1e35977](https://github.com/espressif/esp-protocols/commit/f1e35977))
|
||||
- Add optional mqtt dependency ([911c2dbe](https://github.com/espressif/esp-protocols/commit/911c2dbe))
|
||||
|
||||
## [1.1.3](https://github.com/espressif/esp-protocols/commits/eppp-v1.1.3)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Fix test dependency issue on driver ([1ace92c2](https://github.com/espressif/esp-protocols/commit/1ace92c2))
|
||||
- Fix tun netif to (optionally) return errors ([7a6cf0f9](https://github.com/espressif/esp-protocols/commit/7a6cf0f9))
|
||||
|
||||
## [1.1.2](https://github.com/espressif/esp-protocols/commits/eppp-v1.1.2)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Update uart driver deps per IDF > v5.3 ([92e14607](https://github.com/espressif/esp-protocols/commit/92e14607))
|
||||
|
||||
## [1.1.1](https://github.com/espressif/esp-protocols/commits/eppp-v1.1.1)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Fix getting context for channel API ([94563cdc](https://github.com/espressif/esp-protocols/commit/94563cdc))
|
||||
- Cover more combinations in build tests ([e0b8de8f](https://github.com/espressif/esp-protocols/commit/e0b8de8f))
|
||||
|
||||
## [1.1.0](https://github.com/espressif/esp-protocols/commits/eppp-v1.1.0)
|
||||
|
||||
### Features
|
||||
|
||||
- Add support for UART flow control ([cd57f1bb](https://github.com/espressif/esp-protocols/commit/cd57f1bb), [#870](https://github.com/espressif/esp-protocols/issues/870))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Fix SPI transport to allow already init GPIO ISR ([497ee2d6](https://github.com/espressif/esp-protocols/commit/497ee2d6), [#868](https://github.com/espressif/esp-protocols/issues/868))
|
||||
- Fix stack-overflow in ping task for TUN netif ([b2568a3d](https://github.com/espressif/esp-protocols/commit/b2568a3d), [#867](https://github.com/espressif/esp-protocols/issues/867))
|
||||
|
||||
### Updated
|
||||
|
||||
- ci(common): Update test component dir for IDFv6.0 ([18418c83](https://github.com/espressif/esp-protocols/commit/18418c83))
|
||||
|
||||
## [1.0.1](https://github.com/espressif/esp-protocols/commits/eppp-v1.0.1)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Support for IPv4-only mode ([653328ba](https://github.com/espressif/esp-protocols/commit/653328ba), [#864](https://github.com/espressif/esp-protocols/issues/864))
|
||||
|
||||
## [1.0.0](https://github.com/espressif/esp-protocols/commits/eppp-v1.0.0)
|
||||
|
||||
### Features
|
||||
|
||||
- Add support for custom channels ([4ee9360f](https://github.com/espressif/esp-protocols/commit/4ee9360f))
|
||||
|
||||
## [0.3.1](https://github.com/espressif/esp-protocols/commits/eppp-v0.3.1)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Fix NETIF_PPP_STATUS link issue if PPP disabled in lwip ([077ea0bb](https://github.com/espressif/esp-protocols/commit/077ea0bb))
|
||||
|
||||
## [0.3.0](https://github.com/espressif/esp-protocols/commits/eppp-v0.3.0)
|
||||
|
||||
### Features
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
if("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_GREATER "5.3")
|
||||
set(driver_deps esp_driver_gpio esp_driver_spi)
|
||||
set(driver_deps esp_driver_gpio esp_driver_spi esp_driver_uart esp_driver_sdio)
|
||||
else()
|
||||
set(driver_deps driver)
|
||||
endif()
|
||||
|
||||
@@ -93,4 +93,21 @@ menu "eppp_link"
|
||||
default "06:00:00:00:00:02"
|
||||
depends on EPPP_LINK_DEVICE_ETH
|
||||
|
||||
config EPPP_LINK_CHANNELS_SUPPORT
|
||||
bool "Enable channel support (multiple logical channels)"
|
||||
default n
|
||||
depends on !EPPP_LINK_DEVICE_ETH
|
||||
help
|
||||
Enable support for multiple logical channels in the EPPP link layer.
|
||||
When enabled, you can configure the number of channels used for communication.
|
||||
|
||||
config EPPP_LINK_NR_OF_CHANNELS
|
||||
int "Number of logical channels"
|
||||
depends on EPPP_LINK_CHANNELS_SUPPORT && !EPPP_LINK_DEVICE_ETH
|
||||
range 1 8
|
||||
default 2
|
||||
help
|
||||
Set the number of logical channels for EPPP link communication.
|
||||
Each channel can be used for independent data streams.
|
||||
|
||||
endmenu
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# ESP PPP Link component (eppp_link)
|
||||
|
||||
The component provides a general purpose connectivity engine between two microcontrollers, one acting as PPP server, the other one as PPP client.
|
||||
This component could be used for extending network using physical serial connection. Applications could vary from providing PRC engine for multiprocessor solutions to serial connection to POSIX machine. This uses a standard PPP protocol (if enabled) to negotiate IP addresses and networking, so standard PPP toolset could be used, e.g. a `pppd` service on linux. Typical application is a WiFi connectivity provider for chips that do not have WiFi.
|
||||
This component could be used for extending network using physical serial connection. Applications could vary from providing RPC engine for multiprocessor solutions to serial connection to POSIX machine. This uses a standard PPP protocol (if enabled) to negotiate IP addresses and networking, so standard PPP toolset could be used, e.g. a `pppd` service on linux. Typical application is a WiFi connectivity provider for chips that do not have WiFi.
|
||||
Uses simplified TUN network interface by default to enable faster data transfer on non-UART transports.
|
||||
|
||||
## Typical application
|
||||
@@ -21,6 +21,27 @@ brings in the WiFi connectivity from the communication coprocessor.
|
||||
+----------------+ +----------------+
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
### Network Interface Modes
|
||||
|
||||
Standard PPP Mode (where PPP protocols is preferred) or simple tunnel using TUN Mode.
|
||||
|
||||
### Transport layer
|
||||
|
||||
UART, SPI, SDIO, Ethernet
|
||||
|
||||
### Support for logical channels
|
||||
|
||||
Allows channeling custom data (e.g. 802.11 frames)
|
||||
|
||||
## (Other) usecases
|
||||
|
||||
Besides the communication coprocessor example mentioned above, this component could be used to:
|
||||
* Bring Wi-Fi connectivity to a computer using ESP32 chip.
|
||||
* Connect your microcontroller to the internet via a pppd server (running on a raspberry)
|
||||
* Bridging two networks with two microcontrollers
|
||||
|
||||
## Configuration
|
||||
|
||||
### Choose the transport layer
|
||||
@@ -39,6 +60,14 @@ Use `idf.py menuconfig` to select the transport layer:
|
||||
|
||||
Use PPP netif for UART; Keep the default (TUN) for others
|
||||
|
||||
### Channel support (multiple logical channels)
|
||||
|
||||
* `CONFIG_EPPP_LINK_CHANNELS_SUPPORT` -- Enable support for multiple logical channels (default: disabled)
|
||||
* `CONFIG_EPPP_LINK_NR_OF_CHANNELS` -- Number of logical channels (default: 2, range: 1-8, only visible if channel support is enabled)
|
||||
|
||||
When channel support is enabled, the EPPP link can multiplex multiple logical data streams over the same transport. The number of channels is configurable. Channel support is not available for Ethernet transport.
|
||||
|
||||
To use channels in your application, use the `eppp_add_channels()` API and provide your own channel transmit/receive callbacks. These APIs and related types are only available when channel support is enabled in Kconfig.
|
||||
|
||||
## API
|
||||
|
||||
@@ -57,6 +86,9 @@ Use PPP netif for UART; Keep the default (TUN) for others
|
||||
* `eppp_netif_start()` -- Starts the network, could be called after startup or whenever a connection is lost
|
||||
* `eppp_netif_stop()` -- Stops the network
|
||||
* `eppp_perform()` -- Perform one iteration of the PPP task (need to be called regularly in task-less configuration)
|
||||
#ifdef CONFIG_EPPP_LINK_CHANNELS_SUPPORT
|
||||
* `eppp_add_channels()` -- Register channel transmit/receive callbacks (only available if channel support is enabled)
|
||||
#endif
|
||||
|
||||
## Throughput
|
||||
|
||||
|
||||
370
components/eppp_link/detailed_description.md
Normal file
370
components/eppp_link/detailed_description.md
Normal file
@@ -0,0 +1,370 @@
|
||||
# ESP PPP Link Component (eppp_link) - Detailed Documentation
|
||||
|
||||
## Overview
|
||||
|
||||
The ESP PPP Link component provides a versatile communication bridge between two ESP32 microcontrollers, enabling network connectivity over various physical transport layers. One device acts as a server (typically providing connectivity), while the other acts as a client (consuming connectivity).
|
||||
|
||||
## Network Interface Modes
|
||||
|
||||
### PPP Mode vs TUN Mode
|
||||
|
||||
The component supports two distinct network interface modes:
|
||||
|
||||
#### PPP Mode (`CONFIG_EPPP_LINK_USES_PPP=y`)
|
||||
- **Standard PPP Protocol**: Uses the Point-to-Point Protocol (RFC 1661) with full LCP negotiation
|
||||
- **Compatibility**: Compatible with standard PPP implementations like Linux `pppd`
|
||||
- **Features**:
|
||||
- Automatic IP address negotiation
|
||||
- Link Control Protocol (LCP) for connection establishment
|
||||
- Authentication support (if configured)
|
||||
- Standard PPP framing with escape sequences
|
||||
- **Use Case**: When interfacing with standard PPP-capable systems or when full PPP compatibility is required
|
||||
- **Transport Limitation**: Primarily designed for UART transport due to PPP's serial nature
|
||||
|
||||
#### TUN Mode (`CONFIG_EPPP_LINK_USES_PPP=n`, default)
|
||||
- **Simplified Packet Interface**: Uses a custom packet-based protocol without PPP negotiation
|
||||
- **Performance**: Faster data transfer due to reduced protocol overhead
|
||||
- **Features**:
|
||||
- Direct IP packet transmission
|
||||
- Custom framing for packet boundaries
|
||||
- No negotiation overhead
|
||||
- Static IP address configuration
|
||||
- **Use Case**: Default mode for ESP-to-ESP communication, optimal for non-UART transports
|
||||
- **Transport Support**: Works efficiently with all transport types (UART, SPI, SDIO, Ethernet)
|
||||
|
||||
**Mode Selection**: Configure via `idf.py menuconfig` → `Component config` → `eppp_link` → `Use PPP network interface`
|
||||
|
||||
## Transport Layer Options
|
||||
|
||||
### UART Transport
|
||||
- **Configuration**: `CONFIG_EPPP_LINK_DEVICE_UART=y`
|
||||
- **Features**:
|
||||
- Simple serial communication
|
||||
- Configurable baud rate (up to 3Mbps tested)
|
||||
- Hardware flow control support
|
||||
- Custom framing for packet boundaries in TUN mode
|
||||
- **Performance**: ~2 Mbps (TCP/UDP) @ 3 Mbaud
|
||||
- **Use Case**: Basic connectivity, long-distance communication, debugging
|
||||
- **Pins**: TX, RX configurable
|
||||
|
||||
```c
|
||||
eppp_config_t config = EPPP_DEFAULT_CLIENT_CONFIG();
|
||||
config.transport = EPPP_TRANSPORT_UART;
|
||||
config.uart.tx_io = 25;
|
||||
config.uart.rx_io = 26;
|
||||
config.uart.baud = 921600;
|
||||
```
|
||||
|
||||
### SPI Transport
|
||||
- **Configuration**: `CONFIG_EPPP_LINK_DEVICE_SPI=y`
|
||||
- **Features**:
|
||||
- Master/slave configuration
|
||||
- GPIO interrupt signaling for flow control
|
||||
- Configurable clock frequency
|
||||
- Full-duplex communication
|
||||
- Packet queue for transmission
|
||||
- **Performance**: ~5 Mbps (TCP), ~8 Mbps (UDP) @ 16MHz
|
||||
- **Use Case**: High-speed local communication, PCB-level connections
|
||||
- **Pins**: MOSI, MISO, SCLK, CS, interrupt GPIO
|
||||
|
||||
```c
|
||||
eppp_config_t config = EPPP_DEFAULT_CLIENT_CONFIG();
|
||||
config.transport = EPPP_TRANSPORT_SPI;
|
||||
config.spi.is_master = true;
|
||||
config.spi.freq = 16000000;
|
||||
config.spi.mosi = 11;
|
||||
config.spi.miso = 13;
|
||||
config.spi.sclk = 12;
|
||||
config.spi.cs = 10;
|
||||
config.spi.intr = 2;
|
||||
```
|
||||
|
||||
### SDIO Transport
|
||||
- **Configuration**: `CONFIG_EPPP_LINK_DEVICE_SDIO=y`
|
||||
- **Features**:
|
||||
- Host/slave configuration
|
||||
- High-speed data transfer
|
||||
- 1-bit or 4-bit bus width
|
||||
- Hardware flow control
|
||||
- **Performance**: ~9 Mbps (TCP), ~11 Mbps (UDP)
|
||||
- **Use Case**: Highest throughput applications, module-to-module communication
|
||||
- **Pins**: CLK, CMD, D0-D3 (configurable width)
|
||||
|
||||
```c
|
||||
eppp_config_t config = EPPP_DEFAULT_CLIENT_CONFIG();
|
||||
config.transport = EPPP_TRANSPORT_SDIO;
|
||||
config.sdio.is_host = true;
|
||||
config.sdio.width = 4;
|
||||
config.sdio.clk = 18;
|
||||
config.sdio.cmd = 19;
|
||||
config.sdio.d0 = 14;
|
||||
// ... additional data pins
|
||||
```
|
||||
|
||||
### Ethernet Transport
|
||||
- **Configuration**: `CONFIG_EPPP_LINK_DEVICE_ETH=y`
|
||||
- **Features**:
|
||||
- Direct MAC-to-MAC communication
|
||||
- Can work with or without PHY chips
|
||||
- Standard Ethernet framing
|
||||
- Automatic task management (no `eppp_perform()` needed)
|
||||
- **Performance**: ~5 Mbps (TCP), ~8 Mbps (UDP) with internal EMAC
|
||||
- **Use Case**: Board-to-board communication, integration with existing Ethernet infrastructure
|
||||
- **Pins**: MDC, MDIO, plus PHY-specific pins
|
||||
|
||||
```c
|
||||
eppp_config_t config = EPPP_DEFAULT_CLIENT_CONFIG();
|
||||
config.transport = EPPP_TRANSPORT_ETHERNET;
|
||||
config.ethernet.mdc_io = 23;
|
||||
config.ethernet.mdio_io = 18;
|
||||
config.ethernet.phy_addr = 1;
|
||||
config.ethernet.rst_io = 5;
|
||||
```
|
||||
|
||||
## Channel Support (Multiple Logical Channels)
|
||||
|
||||
### Overview
|
||||
Channel support allows multiplexing multiple independent data streams over a single transport connection. This enables applications to separate different types of data (e.g., network traffic, control commands, sensor data) into distinct logical channels.
|
||||
|
||||
### Configuration
|
||||
- **Enable**: `CONFIG_EPPP_LINK_CHANNELS_SUPPORT=y`
|
||||
- **Count**: `CONFIG_EPPP_LINK_NR_OF_CHANNELS` (1-8 channels, default 2)
|
||||
- **Limitation**: Not available for Ethernet transport
|
||||
|
||||
### Channel Usage
|
||||
```c
|
||||
// Channel callback function type
|
||||
typedef esp_err_t (*eppp_channel_fn_t)(esp_netif_t *netif, int nr, void *buffer, size_t len);
|
||||
|
||||
// Register channel callbacks
|
||||
esp_err_t eppp_add_channels(esp_netif_t *netif,
|
||||
eppp_channel_fn_t *tx, // Transmit function pointer (output)
|
||||
const eppp_channel_fn_t rx, // Receive callback (input)
|
||||
void* context); // User context
|
||||
|
||||
// Get user context
|
||||
void* eppp_get_context(esp_netif_t *netif);
|
||||
```
|
||||
|
||||
### Channel Example
|
||||
```c
|
||||
// Channel 0: Default network traffic (handled automatically)
|
||||
// Channel 1: Control/chat messages
|
||||
// Channel 2: WiFi data forwarding
|
||||
|
||||
static esp_err_t channel_receive(esp_netif_t *netif, int channel, void *buffer, size_t len)
|
||||
{
|
||||
switch(channel) {
|
||||
case 1: // Control channel
|
||||
process_control_message(buffer, len);
|
||||
break;
|
||||
case 2: // WiFi channel
|
||||
forward_to_wifi(buffer, len);
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE(TAG, "Unknown channel %d", channel);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
// Register channels
|
||||
eppp_channel_fn_t tx_func;
|
||||
eppp_add_channels(netif, &tx_func, channel_receive, user_context);
|
||||
|
||||
// Transmit on specific channel
|
||||
tx_func(netif, 1, "Hello", 5); // Send to channel 1
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### Simple API (Recommended for most use cases)
|
||||
|
||||
#### Client Side
|
||||
```c
|
||||
esp_netif_t *eppp_connect(eppp_config_t *config);
|
||||
```
|
||||
- **Purpose**: Simplified client connection
|
||||
- **Behavior**: Blocks until connection is established
|
||||
- **Returns**: Configured network interface or NULL on failure
|
||||
- **Use Case**: Simple applications that don't need fine-grained control
|
||||
|
||||
#### Server Side
|
||||
```c
|
||||
esp_netif_t *eppp_listen(eppp_config_t *config);
|
||||
```
|
||||
- **Purpose**: Simplified server listening
|
||||
- **Behavior**: Blocks until client connects
|
||||
- **Returns**: Configured network interface or NULL on failure
|
||||
- **Use Case**: Simple applications that don't need fine-grained control
|
||||
|
||||
#### Connection Management
|
||||
```c
|
||||
void eppp_close(esp_netif_t *netif);
|
||||
```
|
||||
- **Purpose**: Close connection and cleanup resources
|
||||
- **Behavior**: Stops tasks, closes transport, destroys network interface
|
||||
|
||||
### Advanced API (Manual Control)
|
||||
|
||||
#### Initialization
|
||||
```c
|
||||
esp_netif_t *eppp_init(eppp_type_t role, eppp_config_t *config);
|
||||
```
|
||||
- **Purpose**: Initialize endpoint without starting communication
|
||||
- **Parameters**:
|
||||
- `role`: `EPPP_SERVER` or `EPPP_CLIENT`
|
||||
- `config`: Transport and network configuration
|
||||
- **Returns**: Network interface handle
|
||||
- **Use Case**: Applications needing manual control over connection lifecycle
|
||||
|
||||
#### Connection Control
|
||||
```c
|
||||
esp_err_t eppp_netif_start(esp_netif_t *netif);
|
||||
esp_err_t eppp_netif_stop(esp_netif_t *netif, int stop_timeout_ms);
|
||||
```
|
||||
- **Purpose**: Manual network interface start/stop
|
||||
- **Use Case**: Dynamic connection management, error recovery
|
||||
|
||||
#### Task Management
|
||||
```c
|
||||
esp_err_t eppp_perform(esp_netif_t *netif);
|
||||
```
|
||||
- **Purpose**: Single iteration of communication task
|
||||
- **Returns**:
|
||||
- `ESP_OK`: Continue operation
|
||||
- `ESP_FAIL`: Operation failed but should continue
|
||||
- `ESP_ERR_TIMEOUT`: Stop operation requested
|
||||
- **Use Case**: Task-less operation, integration with custom task schedulers
|
||||
- **Note**: Not needed for Ethernet transport (has its own task)
|
||||
|
||||
#### Resource Management
|
||||
```c
|
||||
void eppp_deinit(esp_netif_t *netif);
|
||||
```
|
||||
- **Purpose**: Clean up resources without stopping tasks
|
||||
- **Use Case**: Manual resource management
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
### Basic Client-Server Setup
|
||||
|
||||
**Client (Host) Configuration:**
|
||||
```c
|
||||
void app_main(void)
|
||||
{
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
|
||||
eppp_config_t config = EPPP_DEFAULT_CLIENT_CONFIG();
|
||||
config.transport = EPPP_TRANSPORT_UART;
|
||||
config.uart.tx_io = 25;
|
||||
config.uart.rx_io = 26;
|
||||
config.uart.baud = 921600;
|
||||
|
||||
esp_netif_t *netif = eppp_connect(&config);
|
||||
if (netif == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to connect");
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Connected successfully");
|
||||
// Use network interface for communication
|
||||
}
|
||||
```
|
||||
|
||||
**Server (Slave) Configuration:**
|
||||
```c
|
||||
void app_main(void)
|
||||
{
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
|
||||
// Initialize WiFi or other network interface
|
||||
init_wifi();
|
||||
|
||||
eppp_config_t config = EPPP_DEFAULT_SERVER_CONFIG();
|
||||
config.transport = EPPP_TRANSPORT_UART;
|
||||
config.uart.tx_io = 26; // Crossed with client
|
||||
config.uart.rx_io = 25; // Crossed with client
|
||||
config.uart.baud = 921600;
|
||||
|
||||
esp_netif_t *netif = eppp_listen(&config);
|
||||
if (netif == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to setup server");
|
||||
return;
|
||||
}
|
||||
|
||||
// Enable NAT to share WiFi connection
|
||||
ESP_ERROR_CHECK(esp_netif_napt_enable(netif));
|
||||
ESP_LOGI(TAG, "Server ready");
|
||||
}
|
||||
```
|
||||
|
||||
### Advanced Manual Control
|
||||
```c
|
||||
void app_main(void)
|
||||
{
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
|
||||
eppp_config_t config = EPPP_DEFAULT_CLIENT_CONFIG();
|
||||
config.task.run_task = false; // Disable automatic task
|
||||
|
||||
esp_netif_t *netif = eppp_init(EPPP_CLIENT, &config);
|
||||
if (netif == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to initialize");
|
||||
return;
|
||||
}
|
||||
|
||||
// Start network interface
|
||||
ESP_ERROR_CHECK(eppp_netif_start(netif));
|
||||
|
||||
// Custom task loop
|
||||
while (true) {
|
||||
esp_err_t ret = eppp_perform(netif);
|
||||
if (ret == ESP_ERR_TIMEOUT) {
|
||||
ESP_LOGI(TAG, "Operation stopped");
|
||||
break;
|
||||
} else if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Operation failed: %s", esp_err_to_name(ret));
|
||||
}
|
||||
|
||||
// Add custom processing here
|
||||
vTaskDelay(pdMS_TO_TICKS(1));
|
||||
}
|
||||
|
||||
eppp_deinit(netif);
|
||||
}
|
||||
```
|
||||
|
||||
### Multi-Channel Configuration
|
||||
```c
|
||||
typedef struct {
|
||||
eppp_channel_fn_t tx_func;
|
||||
esp_netif_t *netif;
|
||||
} channel_context_t;
|
||||
|
||||
static esp_err_t channel_rx(esp_netif_t *netif, int channel, void *buffer, size_t len)
|
||||
{
|
||||
ESP_LOGI(TAG, "Channel %d received %d bytes", channel, len);
|
||||
// Process channel data based on channel number
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void setup_channels(void)
|
||||
{
|
||||
eppp_config_t config = EPPP_DEFAULT_CLIENT_CONFIG();
|
||||
esp_netif_t *netif = eppp_connect(&config);
|
||||
|
||||
channel_context_t *ctx = calloc(1, sizeof(channel_context_t));
|
||||
ctx->netif = netif;
|
||||
|
||||
// Register channel callbacks
|
||||
ESP_ERROR_CHECK(eppp_add_channels(netif, &ctx->tx_func, channel_rx, ctx));
|
||||
|
||||
// Send data on channel 1
|
||||
const char *msg = "Hello on channel 1";
|
||||
ctx->tx_func(netif, 1, (void*)msg, strlen(msg));
|
||||
}
|
||||
```
|
||||
@@ -163,6 +163,7 @@ static int get_netif_num(esp_netif_t *netif)
|
||||
return netif_cnt;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_EPPP_LINK_USES_PPP
|
||||
static void on_ppp_event(void *arg, esp_event_base_t base, int32_t event_id, void *data)
|
||||
{
|
||||
esp_netif_t **netif = data;
|
||||
@@ -172,6 +173,7 @@ static void on_ppp_event(void *arg, esp_event_base_t base, int32_t event_id, voi
|
||||
h->netif_stop = true;
|
||||
}
|
||||
}
|
||||
#endif // CONFIG_EPPP_LINK_USES_PPP
|
||||
|
||||
static void on_ip_event(void *arg, esp_event_base_t base, int32_t event_id, void *data)
|
||||
{
|
||||
@@ -222,7 +224,9 @@ static void remove_handlers(void)
|
||||
vEventGroupDelete(s_event_group);
|
||||
s_event_group = NULL;
|
||||
esp_event_handler_unregister(IP_EVENT, ESP_EVENT_ANY_ID, on_ip_event);
|
||||
#ifdef CONFIG_EPPP_LINK_USES_PPP
|
||||
esp_event_handler_unregister(NETIF_PPP_STATUS, ESP_EVENT_ANY_ID, on_ppp_event);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -296,11 +300,13 @@ esp_netif_t *eppp_open(eppp_type_t role, eppp_config_t *config, int connect_time
|
||||
remove_handlers();
|
||||
return NULL;
|
||||
}
|
||||
#ifdef CONFIG_EPPP_LINK_USES_PPP
|
||||
if (esp_event_handler_register(NETIF_PPP_STATUS, ESP_EVENT_ANY_ID, on_ppp_event, NULL) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to register PPP status handler");
|
||||
remove_handlers();
|
||||
return NULL;
|
||||
}
|
||||
#endif // CONFIG_EPPP_LINK_USES_PPP
|
||||
}
|
||||
esp_netif_t *netif = eppp_init(role, config);
|
||||
if (!netif) {
|
||||
@@ -361,3 +367,24 @@ void eppp_close(esp_netif_t *netif)
|
||||
eppp_deinit(netif);
|
||||
remove_handlers();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_EPPP_LINK_CHANNELS_SUPPORT
|
||||
esp_err_t eppp_add_channels(esp_netif_t *netif, eppp_channel_fn_t *tx, const eppp_channel_fn_t rx, void* context)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(netif != NULL && tx != NULL && rx != NULL, ESP_ERR_INVALID_ARG, TAG, "Invalid arguments");
|
||||
struct eppp_handle *h = esp_netif_get_io_driver(netif);
|
||||
ESP_RETURN_ON_FALSE(h != NULL && h->channel_tx != NULL, ESP_ERR_INVALID_STATE, TAG, "Transport not initialized");
|
||||
*tx = h->channel_tx;
|
||||
h->channel_rx = rx;
|
||||
h->context = context;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void* eppp_get_context(esp_netif_t *netif)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(netif != NULL, NULL, TAG, "Invalid netif");
|
||||
struct eppp_handle *h = esp_netif_get_io_driver(netif);
|
||||
ESP_RETURN_ON_FALSE(h != NULL, NULL, TAG, "EPPP Not initialized");
|
||||
return h->context;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -17,9 +17,17 @@
|
||||
#include "esp_check.h"
|
||||
#include "esp_idf_version.h"
|
||||
|
||||
#if defined(CONFIG_ESP_NETIF_RECEIVE_REPORT_ERRORS)
|
||||
typedef esp_err_t esp_netif_recv_ret_t;
|
||||
#define ESP_NETIF_OPTIONAL_RETURN_CODE(expr) expr
|
||||
#else
|
||||
typedef void esp_netif_recv_ret_t;
|
||||
#define ESP_NETIF_OPTIONAL_RETURN_CODE(expr)
|
||||
#endif // CONFIG_ESP_NETIF_RECEIVE_REPORT_ERRORS
|
||||
|
||||
static const char *TAG = "eppp_tun_netif";
|
||||
|
||||
static void tun_input(void *h, void *buffer, unsigned int len, void *eb)
|
||||
static esp_netif_recv_ret_t tun_input(void *h, void *buffer, unsigned int len, void *eb)
|
||||
{
|
||||
__attribute__((unused)) esp_err_t ret = ESP_OK;
|
||||
struct netif *netif = h;
|
||||
@@ -31,11 +39,12 @@ static void tun_input(void *h, void *buffer, unsigned int len, void *eb)
|
||||
ESP_GOTO_ON_FALSE(pbuf_remove_header(p, SIZEOF_ETH_HDR) == 0, ESP_FAIL, err, TAG, "pbuf_remove_header failed");
|
||||
memcpy(p->payload, buffer, len);
|
||||
ESP_GOTO_ON_FALSE(netif->input(p, netif) == ERR_OK, ESP_FAIL, err, TAG, "failed to input packet to lwip");
|
||||
return;
|
||||
return ESP_NETIF_OPTIONAL_RETURN_CODE(ESP_OK);
|
||||
err:
|
||||
if (p) {
|
||||
pbuf_free(p);
|
||||
}
|
||||
return ESP_NETIF_OPTIONAL_RETURN_CODE(ret);
|
||||
}
|
||||
|
||||
static err_t tun_output(struct netif *netif, struct pbuf *p)
|
||||
@@ -65,12 +74,13 @@ static err_t tun_output_v4(struct netif *netif, struct pbuf *p, const ip4_addr_t
|
||||
LWIP_UNUSED_ARG(ipaddr);
|
||||
return tun_output(netif, p);
|
||||
}
|
||||
#if LWIP_IPV6
|
||||
static err_t tun_output_v6(struct netif *netif, struct pbuf *p, const ip6_addr_t *ipaddr)
|
||||
{
|
||||
LWIP_UNUSED_ARG(ipaddr);
|
||||
return tun_output(netif, p);
|
||||
}
|
||||
|
||||
#endif
|
||||
static err_t tun_init(struct netif *netif)
|
||||
{
|
||||
if (netif == NULL) {
|
||||
@@ -151,9 +161,12 @@ static void cmd_ping_on_ping_end(esp_ping_handle_t hdl, void *args)
|
||||
}
|
||||
if (IP_IS_V4(&target_addr)) {
|
||||
ESP_LOGD(TAG, "\n--- %s ping statistics ---\n", inet_ntoa(*ip_2_ip4(&target_addr)));
|
||||
} else {
|
||||
}
|
||||
#if LWIP_IPV6
|
||||
else {
|
||||
ESP_LOGD(TAG, "\n--- %s ping statistics ---\n", inet6_ntoa(*ip_2_ip6(&target_addr)));
|
||||
}
|
||||
#endif
|
||||
ESP_LOGI(TAG, "%" PRIu32 " packets transmitted, %" PRIu32 " received, %" PRIu32 "%% packet loss, time %" PRIu32 "ms\n",
|
||||
transmitted, received, loss, total_time_ms);
|
||||
esp_ping_delete_session(hdl);
|
||||
@@ -163,12 +176,19 @@ esp_err_t eppp_check_connection(esp_netif_t *netif)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
esp_ping_config_t config = ESP_PING_DEFAULT_CONFIG();
|
||||
#if CONFIG_LOG_MAXIMUM_LEVEL > 3
|
||||
config.task_stack_size += 1024; // Some additional stack needed for verbose logs
|
||||
#endif
|
||||
config.count = 100;
|
||||
ESP_LOGI(TAG, "Checking connection on EPPP interface #%" PRIu32, config.interface);
|
||||
ip_addr_t target_addr = {0};
|
||||
esp_netif_ip_info_t ip;
|
||||
esp_netif_get_ip_info(netif, &ip);
|
||||
#if LWIP_IPV6
|
||||
target_addr.u_addr.ip4.addr = ip.gw.addr;
|
||||
#else
|
||||
target_addr.addr = ip.gw.addr;
|
||||
#endif
|
||||
config.target_addr = target_addr;
|
||||
esp_ping_callbacks_t cbs = {
|
||||
.cb_args = netif,
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "eppp_link.h"
|
||||
#include "eppp_transport.h"
|
||||
#include "eppp_transport_sdio.h"
|
||||
#include "eppp_sdio.h"
|
||||
|
||||
#define TAG "eppp_sdio"
|
||||
|
||||
@@ -67,6 +68,9 @@ eppp_transport_handle_t eppp_sdio_init(struct eppp_config_sdio_s *config)
|
||||
ESP_RETURN_ON_FALSE(config, NULL, TAG, "Config cannot be null");
|
||||
struct eppp_sdio *h = calloc(1, sizeof(struct eppp_sdio));
|
||||
ESP_RETURN_ON_FALSE(h, NULL, TAG, "Failed to allocate eppp_handle");
|
||||
#ifdef CONFIG_EPPP_LINK_CHANNELS_SUPPORT
|
||||
h->parent.channel_tx = eppp_sdio_transmit_channel;
|
||||
#endif
|
||||
h->parent.base.post_attach = post_attach;
|
||||
h->is_host = config->is_host;
|
||||
esp_err_t (*init_fn)(struct eppp_config_sdio_s * eppp_config) = h->is_host ? eppp_sdio_host_init : eppp_sdio_slave_init;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -8,8 +8,10 @@
|
||||
#define MAX_SDIO_PAYLOAD 1500
|
||||
#define SDIO_ALIGN(size) (((size) + 3U) & ~(3U))
|
||||
#define SDIO_PAYLOAD SDIO_ALIGN(MAX_SDIO_PAYLOAD)
|
||||
#define SDIO_PACKET_SIZE SDIO_ALIGN(MAX_SDIO_PAYLOAD + 4)
|
||||
#define PPP_SOF 0x7E
|
||||
|
||||
|
||||
// Interrupts and registers
|
||||
#define SLAVE_INTR 0
|
||||
#define SLAVE_REG_REQ 0
|
||||
@@ -17,3 +19,11 @@
|
||||
// Requests from host to slave
|
||||
#define REQ_RESET 1
|
||||
#define REQ_INIT 2
|
||||
|
||||
struct header {
|
||||
uint8_t magic;
|
||||
uint8_t channel;
|
||||
uint16_t size;
|
||||
} __attribute__((packed));
|
||||
|
||||
esp_err_t eppp_sdio_transmit_channel(esp_netif_t *netif, int channel, void *buffer, size_t len);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -8,6 +8,8 @@
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_netif.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "driver/sdio_slave.h"
|
||||
#include "esp_serial_slave_link/essl_sdio.h"
|
||||
#include "eppp_sdio.h"
|
||||
@@ -15,6 +17,7 @@
|
||||
#include "sdmmc_cmd.h"
|
||||
#include "esp_check.h"
|
||||
#include "eppp_link.h"
|
||||
#include "eppp_transport.h"
|
||||
|
||||
#if CONFIG_EPPP_LINK_DEVICE_SDIO_HOST
|
||||
|
||||
@@ -28,22 +31,23 @@ 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];
|
||||
static DRAM_DMA_ALIGNED_ATTR uint8_t send_buffer[SDIO_PACKET_SIZE];
|
||||
static DMA_ATTR uint8_t rcv_buffer[SDIO_PACKET_SIZE];
|
||||
|
||||
esp_err_t eppp_sdio_host_tx(void *h, void *buffer, size_t len)
|
||||
static esp_err_t eppp_sdio_host_tx_generic(int channel, 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);
|
||||
}
|
||||
|
||||
struct header *head = (void *)send_buffer;
|
||||
head->magic = PPP_SOF;
|
||||
head->channel = channel;
|
||||
head->size = len;
|
||||
memcpy(send_buffer + sizeof(struct header), buffer, len);
|
||||
size_t send_len = SDIO_ALIGN(len + sizeof(struct header));
|
||||
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) {
|
||||
@@ -56,6 +60,19 @@ esp_err_t eppp_sdio_host_tx(void *h, void *buffer, size_t len)
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t eppp_sdio_host_tx(void *h, void *buffer, size_t len)
|
||||
{
|
||||
return eppp_sdio_host_tx_generic(0, buffer, len);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_EPPP_LINK_CHANNELS_SUPPORT
|
||||
esp_err_t eppp_sdio_transmit_channel(esp_netif_t *netif, int channel, void *buffer, size_t len)
|
||||
{
|
||||
return eppp_sdio_host_tx_generic(channel, buffer, len);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static esp_err_t request_slave_reset(void)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
@@ -145,15 +162,37 @@ esp_err_t eppp_sdio_host_rx(esp_netif_t *netif)
|
||||
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);
|
||||
size_t size_read = SDIO_PACKET_SIZE;
|
||||
ret = essl_get_packet(s_essl, rcv_buffer, SDIO_PACKET_SIZE, &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);
|
||||
struct header *head = (void *)rcv_buffer;
|
||||
if (head->magic != PPP_SOF) {
|
||||
ESP_LOGE(TAG, "invalid magic %x", head->magic);
|
||||
break;
|
||||
}
|
||||
if (head->channel > NR_OF_CHANNELS) {
|
||||
ESP_LOGE(TAG, "invalid channel %x", head->channel);
|
||||
break;
|
||||
}
|
||||
if (head->size > SDIO_PAYLOAD || head->size > size_read) {
|
||||
ESP_LOGE(TAG, "invalid size %x", head->size);
|
||||
break;
|
||||
}
|
||||
ESP_LOG_BUFFER_HEXDUMP(TAG, rcv_buffer, size_read, ESP_LOG_VERBOSE);
|
||||
esp_netif_receive(netif, rcv_buffer, size_read, NULL);
|
||||
if (head->channel == 0) {
|
||||
esp_netif_receive(netif, rcv_buffer + sizeof(struct header), head->size, NULL);
|
||||
} else {
|
||||
#if defined(CONFIG_EPPP_LINK_CHANNELS_SUPPORT)
|
||||
struct eppp_handle *h = esp_netif_get_io_driver(netif);
|
||||
if (h->channel_rx) {
|
||||
h->channel_rx(netif, head->channel, rcv_buffer + sizeof(struct header), head->size);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
ESP_LOGE(TAG, "rx packet error: %08X", ret);
|
||||
|
||||
@@ -8,11 +8,13 @@
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_netif.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "driver/sdio_slave.h"
|
||||
#include "eppp_link.h"
|
||||
#include "eppp_transport.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
|
||||
@@ -21,19 +23,18 @@ 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)
|
||||
static esp_err_t eppp_sdio_host_tx_generic(int channel, 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);
|
||||
}
|
||||
|
||||
struct header *head = (void *)sdio_slave_tx_buffer;
|
||||
head->magic = PPP_SOF;
|
||||
head->channel = channel;
|
||||
head->size = len;
|
||||
memcpy(sdio_slave_tx_buffer + sizeof(struct header), buffer, len);
|
||||
size_t send_len = SDIO_ALIGN(len + sizeof(struct header));
|
||||
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) {
|
||||
@@ -44,6 +45,18 @@ esp_err_t eppp_sdio_slave_tx(void *h, void *buffer, size_t len)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t eppp_sdio_slave_tx(void *h, void *buffer, size_t len)
|
||||
{
|
||||
return eppp_sdio_host_tx_generic(0, buffer, len);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_EPPP_LINK_CHANNELS_SUPPORT
|
||||
esp_err_t eppp_sdio_transmit_channel(esp_netif_t *netif, int channel, void *buffer, size_t len)
|
||||
{
|
||||
return eppp_sdio_host_tx_generic(channel, buffer, len);
|
||||
}
|
||||
#endif
|
||||
|
||||
static esp_err_t slave_reset(void)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
@@ -82,7 +95,29 @@ esp_err_t eppp_sdio_slave_rx(esp_netif_t *netif)
|
||||
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);
|
||||
struct header *head = (void *)ptr;
|
||||
if (head->magic != PPP_SOF) {
|
||||
ESP_LOGE(TAG, "invalid magic %x", head->magic);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
if (head->channel > NR_OF_CHANNELS) {
|
||||
ESP_LOGE(TAG, "invalid channel %x", head->channel);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
if (head->size > SDIO_PAYLOAD || head->size > length) {
|
||||
ESP_LOGE(TAG, "invalid size %x", head->size);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
if (head->channel == 0) {
|
||||
esp_netif_receive(netif, ptr + sizeof(struct header), head->size, NULL);
|
||||
} else {
|
||||
#if defined(CONFIG_EPPP_LINK_CHANNELS_SUPPORT)
|
||||
struct eppp_handle *h = esp_netif_get_io_driver(netif);
|
||||
if (h->channel_rx) {
|
||||
h->channel_rx(netif, head->channel, ptr + sizeof(struct header), head->size);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (sdio_slave_recv_load_buf(handle) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to recycle packet buffer");
|
||||
return ESP_FAIL;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_netif.h"
|
||||
#include "esp_check.h"
|
||||
@@ -24,7 +25,8 @@
|
||||
|
||||
#define MAX_PAYLOAD 1500
|
||||
#define MIN_TRIGGER_US 20
|
||||
#define SPI_HEADER_MAGIC 0x1234
|
||||
#define PPP_SOF 0x7E
|
||||
#define SPI_HEADER_MAGIC PPP_SOF
|
||||
#define SPI_ALIGN(size) (((size) + 3U) & ~(3U))
|
||||
#define TRANSFER_SIZE SPI_ALIGN((MAX_PAYLOAD + 6))
|
||||
#define NEXT_TRANSACTION_SIZE(a,b) (((a)>(b))?(a):(b)) /* next transaction: whichever is bigger */
|
||||
@@ -32,10 +34,12 @@
|
||||
struct packet {
|
||||
size_t len;
|
||||
uint8_t *data;
|
||||
int channel;
|
||||
};
|
||||
|
||||
struct header {
|
||||
uint16_t magic;
|
||||
uint8_t magic;
|
||||
uint8_t channel;
|
||||
uint16_t size;
|
||||
uint16_t next_size;
|
||||
uint16_t check;
|
||||
@@ -65,12 +69,10 @@ struct eppp_spi {
|
||||
esp_timer_handle_t timer;
|
||||
};
|
||||
|
||||
static esp_err_t transmit(void *h, void *buffer, size_t len)
|
||||
static esp_err_t transmit_generic(struct eppp_spi *handle, int channel, void *buffer, size_t len)
|
||||
{
|
||||
struct eppp_handle *common = h;
|
||||
struct eppp_spi *handle = __containerof(common, struct eppp_spi, parent);;
|
||||
#if CONFIG_EPPP_LINK_DEVICE_SPI
|
||||
struct packet buf = { };
|
||||
|
||||
struct packet buf = { .channel = channel };
|
||||
uint8_t *current_buffer = buffer;
|
||||
size_t remaining = len;
|
||||
do { // TODO(IDF-9194): Refactor this loop to allocate only once and perform
|
||||
@@ -100,14 +102,25 @@ static esp_err_t transmit(void *h, void *buffer, size_t len)
|
||||
}
|
||||
gpio_set_level(handle->gpio_intr, 0);
|
||||
}
|
||||
|
||||
#elif CONFIG_EPPP_LINK_DEVICE_UART
|
||||
ESP_LOG_BUFFER_HEXDUMP("ppp_uart_send", buffer, len, ESP_LOG_WARN);
|
||||
uart_write_bytes(handle->uart_port, buffer, len);
|
||||
#endif // DEVICE UART or SPI
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t transmit(void *h, void *buffer, size_t len)
|
||||
{
|
||||
struct eppp_handle *handle = h;
|
||||
struct eppp_spi *spi_handle = __containerof(handle, struct eppp_spi, parent);;
|
||||
return transmit_generic(spi_handle, 0, buffer, len);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_EPPP_LINK_CHANNELS_SUPPORT
|
||||
static esp_err_t transmit_channel(esp_netif_t *netif, int channel, void *buffer, size_t len)
|
||||
{
|
||||
struct eppp_handle *handle = esp_netif_get_io_driver(netif);
|
||||
struct eppp_spi *spi_handle = __containerof(handle, struct eppp_spi, parent);;
|
||||
return transmit_generic(spi_handle, channel, buffer, len);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void IRAM_ATTR timer_callback(void *arg)
|
||||
{
|
||||
struct eppp_spi *h = arg;
|
||||
@@ -195,7 +208,9 @@ static esp_err_t init_master(struct eppp_config_spi_s *config, struct eppp_spi *
|
||||
};
|
||||
|
||||
ESP_GOTO_ON_ERROR(gpio_config(&io_conf), err_dev, TAG, "Failed to config interrupt GPIO");
|
||||
ESP_GOTO_ON_ERROR(gpio_install_isr_service(0), err_dev, TAG, "Failed to install GPIO ISR");
|
||||
ret = gpio_install_isr_service(0);
|
||||
ESP_GOTO_ON_FALSE(ret == ESP_OK || ret == ESP_ERR_INVALID_STATE /* In case the GPIO ISR already installed */,
|
||||
ret, err_dev, TAG, "Failed to install GPIO ISR");
|
||||
ESP_GOTO_ON_ERROR(gpio_set_intr_type(config->intr, GPIO_INTR_ANYEDGE), err_dev, TAG, "Failed to set ISR type");
|
||||
ESP_GOTO_ON_ERROR(gpio_isr_handler_add(config->intr, gpio_isr_handler, h), err_dev, TAG, "Failed to add ISR handler");
|
||||
return ESP_OK;
|
||||
@@ -339,6 +354,7 @@ esp_err_t eppp_perform(esp_netif_t *netif)
|
||||
if (h->outbound.len <= h->transaction_size && allow_test_tx == false) {
|
||||
// sending outbound
|
||||
head->size = h->outbound.len;
|
||||
head->channel = h->outbound.channel;
|
||||
if (h->outbound.len > 0) {
|
||||
memcpy(out_buf + sizeof(struct header), h->outbound.data, h->outbound.len);
|
||||
free(h->outbound.data);
|
||||
@@ -355,6 +371,7 @@ esp_err_t eppp_perform(esp_netif_t *netif)
|
||||
} else {
|
||||
// outbound is bigger, need to transmit in another transaction (keep this empty)
|
||||
head->size = 0;
|
||||
head->channel = 0;
|
||||
}
|
||||
next_tx_size = head->next_size = h->outbound.len;
|
||||
head->magic = SPI_HEADER_MAGIC;
|
||||
@@ -367,17 +384,25 @@ esp_err_t eppp_perform(esp_netif_t *netif)
|
||||
}
|
||||
head = (void *)in_buf;
|
||||
uint16_t check = esp_rom_crc16_le(0, in_buf, sizeof(struct header) - sizeof(uint16_t));
|
||||
if (check != head->check || head->magic != SPI_HEADER_MAGIC) {
|
||||
if (check != head->check || head->magic != SPI_HEADER_MAGIC || head->channel > NR_OF_CHANNELS) {
|
||||
h->transaction_size = 0; // need to start with HEADER only transaction
|
||||
if (allow_test_tx) {
|
||||
return ESP_OK;
|
||||
}
|
||||
ESP_LOGE(TAG, "Wrong checksum or magic");
|
||||
ESP_LOGE(TAG, "Wrong checksum, magic, or channel: %x %x %x", check, head->magic, head->channel);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
if (head->size > 0) {
|
||||
ESP_LOG_BUFFER_HEXDUMP(TAG, in_buf + sizeof(struct header), head->size, ESP_LOG_VERBOSE);
|
||||
esp_netif_receive(netif, in_buf + sizeof(struct header), head->size, NULL);
|
||||
if (head->channel == 0) {
|
||||
esp_netif_receive(netif, in_buf + sizeof(struct header), head->size, NULL);
|
||||
} else {
|
||||
#if defined(CONFIG_EPPP_LINK_CHANNELS_SUPPORT)
|
||||
if (h->parent.channel_rx) {
|
||||
h->parent.channel_rx(netif, head->channel, in_buf + sizeof(struct header), head->size);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
h->transaction_size = NEXT_TRANSACTION_SIZE(next_tx_size, head->next_size);
|
||||
return ESP_OK;
|
||||
@@ -415,6 +440,9 @@ eppp_transport_handle_t eppp_spi_init(struct eppp_config_spi_s *config)
|
||||
ESP_RETURN_ON_FALSE(config, NULL, TAG, "Config cannot be null");
|
||||
struct eppp_spi *h = calloc(1, sizeof(struct eppp_spi));
|
||||
ESP_RETURN_ON_FALSE(h, NULL, TAG, "Failed to allocate eppp_handle");
|
||||
#ifdef CONFIG_EPPP_LINK_CHANNELS_SUPPORT
|
||||
h->parent.channel_tx = transmit_channel;
|
||||
#endif
|
||||
h->is_master = config->is_master;
|
||||
h->parent.base.post_attach = post_attach;
|
||||
h->out_queue = xQueueCreate(CONFIG_EPPP_LINK_PACKET_QUEUE_SIZE, sizeof(struct packet));
|
||||
@@ -442,9 +470,6 @@ err:
|
||||
if (h->ready_semaphore) {
|
||||
vSemaphoreDelete(h->ready_semaphore);
|
||||
}
|
||||
if (h->out_queue) {
|
||||
vQueueDelete(h->out_queue);
|
||||
}
|
||||
free(h);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,13 @@
|
||||
*/
|
||||
#pragma once
|
||||
#include "esp_netif_types.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#ifdef CONFIG_EPPP_LINK_CHANNELS_SUPPORT
|
||||
#define NR_OF_CHANNELS CONFIG_EPPP_LINK_NR_OF_CHANNELS
|
||||
#else
|
||||
#define NR_OF_CHANNELS 1
|
||||
#endif
|
||||
|
||||
struct eppp_handle {
|
||||
esp_netif_driver_base_t base;
|
||||
@@ -12,6 +19,11 @@ struct eppp_handle {
|
||||
bool stop;
|
||||
bool exited;
|
||||
bool netif_stop;
|
||||
#ifdef CONFIG_EPPP_LINK_CHANNELS_SUPPORT
|
||||
eppp_channel_fn_t channel_tx;
|
||||
eppp_channel_fn_t channel_rx;
|
||||
void* context;
|
||||
#endif
|
||||
};
|
||||
|
||||
esp_err_t eppp_check_connection(esp_netif_t *netif);
|
||||
|
||||
@@ -31,19 +31,19 @@ struct eppp_uart {
|
||||
|
||||
struct header {
|
||||
uint8_t magic;
|
||||
uint8_t channel;
|
||||
uint8_t check;
|
||||
uint16_t size;
|
||||
} __attribute__((packed));
|
||||
|
||||
static esp_err_t transmit(void *h, void *buffer, size_t len)
|
||||
static esp_err_t transmit_generic(struct eppp_uart *handle, int channel, void *buffer, size_t len)
|
||||
{
|
||||
struct eppp_handle *common = h;
|
||||
struct eppp_uart *handle = __containerof(common, struct eppp_uart, parent);
|
||||
#ifndef CONFIG_EPPP_LINK_USES_PPP
|
||||
static uint8_t out_buf[MAX_PACKET_SIZE] = {};
|
||||
struct header *head = (void *)out_buf;
|
||||
head->magic = HEADER_MAGIC;
|
||||
head->check = 0;
|
||||
head->channel = channel;
|
||||
head->size = len;
|
||||
head->check = (0xFF & len) ^ (len >> 8);
|
||||
memcpy(out_buf + sizeof(struct header), buffer, len);
|
||||
@@ -56,6 +56,22 @@ static esp_err_t transmit(void *h, void *buffer, size_t len)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t transmit(void *h, void *buffer, size_t len)
|
||||
{
|
||||
struct eppp_handle *handle = h;
|
||||
struct eppp_uart *uart_handle = __containerof(handle, struct eppp_uart, parent);
|
||||
return transmit_generic(uart_handle, 0, buffer, len);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_EPPP_LINK_CHANNELS_SUPPORT
|
||||
static esp_err_t transmit_channel(esp_netif_t *netif, int channel, void *buffer, size_t len)
|
||||
{
|
||||
struct eppp_handle *handle = esp_netif_get_io_driver(netif);
|
||||
struct eppp_uart *uart_handle = __containerof(handle, struct eppp_uart, parent);
|
||||
return transmit_generic(uart_handle, channel, buffer, len);
|
||||
}
|
||||
#endif
|
||||
|
||||
static esp_err_t init_uart(struct eppp_uart *h, struct eppp_config_uart_s *config)
|
||||
{
|
||||
h->uart_port = config->port;
|
||||
@@ -64,12 +80,12 @@ static esp_err_t init_uart(struct eppp_uart *h, struct eppp_config_uart_s *confi
|
||||
uart_config.data_bits = UART_DATA_8_BITS;
|
||||
uart_config.parity = UART_PARITY_DISABLE;
|
||||
uart_config.stop_bits = UART_STOP_BITS_1;
|
||||
uart_config.flow_ctrl = UART_HW_FLOWCTRL_DISABLE;
|
||||
uart_config.flow_ctrl = config->flow_control;
|
||||
uart_config.source_clk = UART_SCLK_DEFAULT;
|
||||
|
||||
ESP_RETURN_ON_ERROR(uart_driver_install(h->uart_port, config->rx_buffer_size, 0, config->queue_size, &h->uart_event_queue, 0), TAG, "Failed to install UART");
|
||||
ESP_RETURN_ON_ERROR(uart_param_config(h->uart_port, &uart_config), TAG, "Failed to set params");
|
||||
ESP_RETURN_ON_ERROR(uart_set_pin(h->uart_port, config->tx_io, config->rx_io, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE), TAG, "Failed to set UART pins");
|
||||
ESP_RETURN_ON_ERROR(uart_set_pin(h->uart_port, config->tx_io, config->rx_io, config->rts_io, config->cts_io), TAG, "Failed to set UART pins");
|
||||
ESP_RETURN_ON_ERROR(uart_set_rx_timeout(h->uart_port, 1), TAG, "Failed to set UART Rx timeout");
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -122,6 +138,7 @@ static void process_packet(esp_netif_t *netif, uart_port_t uart_port, size_t ava
|
||||
|
||||
// Check if we have the complete packet
|
||||
uint16_t payload_size = head->size;
|
||||
int channel = head->channel;
|
||||
size_t total_packet_size = sizeof(struct header) + payload_size;
|
||||
|
||||
if (payload_size > MAX_PAYLOAD) {
|
||||
@@ -136,7 +153,17 @@ static void process_packet(esp_netif_t *netif, uart_port_t uart_port, size_t ava
|
||||
}
|
||||
|
||||
// Got a complete packet, pass it to network
|
||||
esp_netif_receive(netif, in_buf + buf_start + sizeof(struct header), payload_size, NULL);
|
||||
if (channel == 0) {
|
||||
esp_netif_receive(netif, in_buf + buf_start + sizeof(struct header), payload_size, NULL);
|
||||
} else {
|
||||
#ifdef CONFIG_EPPP_LINK_CHANNELS_SUPPORT
|
||||
struct eppp_handle *handle = esp_netif_get_io_driver(netif);
|
||||
struct eppp_uart *h = __containerof(handle, struct eppp_uart, parent);
|
||||
if (h->parent.channel_rx) {
|
||||
h->parent.channel_rx(netif, channel, in_buf + buf_start + sizeof(struct header), payload_size);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Advance start pointer past this packet
|
||||
buf_start += total_packet_size;
|
||||
@@ -237,10 +264,14 @@ eppp_transport_handle_t eppp_uart_init(struct eppp_config_uart_s *config)
|
||||
ESP_RETURN_ON_FALSE(config, NULL, TAG, "Config cannot be null");
|
||||
struct eppp_uart *h = calloc(1, sizeof(struct eppp_uart));
|
||||
ESP_RETURN_ON_FALSE(h, NULL, TAG, "Failed to allocate eppp_handle");
|
||||
#ifdef CONFIG_EPPP_LINK_CHANNELS_SUPPORT
|
||||
h->parent.channel_tx = transmit_channel;
|
||||
#endif
|
||||
h->parent.base.post_attach = post_attach;
|
||||
ESP_GOTO_ON_ERROR(init_uart(h, config), err, TAG, "Failed to init UART");
|
||||
return &h->parent;
|
||||
err:
|
||||
free(h);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,2 +1,6 @@
|
||||
if(CONFIG_EXAMPLE_WIFI_OVER_EPPP_CHANNEL)
|
||||
set(wifi_over_channels channel_wifi_station.c)
|
||||
endif()
|
||||
idf_component_register(SRCS app_main.c register_iperf.c
|
||||
INCLUDE_DIRS ".")
|
||||
${wifi_over_channels}
|
||||
INCLUDE_DIRS ".")
|
||||
|
||||
@@ -106,4 +106,14 @@ menu "Example Configuration"
|
||||
help
|
||||
Baudrate used by the PPP over UART
|
||||
|
||||
config EXAMPLE_WIFI_OVER_EPPP_CHANNEL
|
||||
bool "Use WiFi over EPPP channel"
|
||||
default n
|
||||
depends on EPPP_LINK_CHANNELS_SUPPORT && ESP_WIFI_REMOTE_ENABLED
|
||||
help
|
||||
Enable this option to use WiFi over EPPP channel.
|
||||
If this option is enabled, the example will only start the Wi-Fi driver,
|
||||
but the Wi-Fi netif will reside on client's end and will channel
|
||||
the Rx and Tx data via EPPP channels.
|
||||
|
||||
endmenu
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "esp_netif.h"
|
||||
#include "eppp_link.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_check.h"
|
||||
#include "mqtt_client.h"
|
||||
#include "console_ping.h"
|
||||
|
||||
@@ -88,6 +89,7 @@ static void mqtt_app_start(void)
|
||||
}
|
||||
#endif // MQTT
|
||||
|
||||
void station_over_eppp_channel(void *arg);
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
@@ -156,6 +158,9 @@ void app_main(void)
|
||||
// start console REPL
|
||||
ESP_ERROR_CHECK(console_cmd_start());
|
||||
|
||||
#ifdef CONFIG_EXAMPLE_WIFI_OVER_EPPP_CHANNEL
|
||||
station_over_eppp_channel(eppp_netif);
|
||||
#endif
|
||||
#if CONFIG_EXAMPLE_MQTT
|
||||
mqtt_app_start();
|
||||
#endif
|
||||
|
||||
185
components/eppp_link/examples/host/main/channel_wifi_station.c
Normal file
185
components/eppp_link/examples/host/main/channel_wifi_station.c
Normal file
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 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 "esp_event.h"
|
||||
#include "esp_netif.h"
|
||||
#include "eppp_link.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_wifi_remote.h"
|
||||
|
||||
#define CHAT_CHANNEL 1
|
||||
#define WIFI_CHANNEL 2
|
||||
|
||||
typedef enum {
|
||||
UNKNOWN,
|
||||
HELLO,
|
||||
START,
|
||||
ERROR,
|
||||
} state_t;
|
||||
|
||||
typedef struct context {
|
||||
eppp_channel_fn_t transmit;
|
||||
EventGroupHandle_t flags;
|
||||
state_t state;
|
||||
esp_netif_t *eppp;
|
||||
} context_t;
|
||||
|
||||
#define HELLO_BIT BIT0
|
||||
#define START_BIT BIT1
|
||||
#define CONNECT_BIT BIT2
|
||||
#define SERVER_UP_BIT BIT3
|
||||
|
||||
#define ALL_BITS (HELLO_BIT | START_BIT | CONNECT_BIT | SERVER_UP_BIT)
|
||||
|
||||
static uint8_t s_wifi_mac_addr[6] = { 0 };
|
||||
static const char *TAG = "eppp_host_example_with_channels";
|
||||
|
||||
esp_netif_t* esp_wifi_remote_create_default_sta(void);
|
||||
|
||||
static void event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data)
|
||||
{
|
||||
ESP_LOGI(TAG, "IP event_handler: event_base=%s event_id=%d", event_base, event_id);
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t esp_wifi_remote_get_mac(wifi_interface_t ifx, uint8_t mac[6])
|
||||
{
|
||||
if (ifx != WIFI_IF_STA) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
|
||||
}
|
||||
for (int i = 0; i < sizeof(s_wifi_mac_addr); i++) {
|
||||
if (s_wifi_mac_addr[i] == 0) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
}
|
||||
memcpy(mac, s_wifi_mac_addr, sizeof(s_wifi_mac_addr));
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t eppp_receive(esp_netif_t *netif, int nr, void *buffer, size_t len)
|
||||
{
|
||||
context_t *ctx = eppp_get_context(netif);
|
||||
if (nr == CHAT_CHANNEL) {
|
||||
ESP_LOGI(TAG, "Received channel=%d len=%d %.*s", nr, (int)len, (int)len, (char *)buffer);
|
||||
const char hello[] = "Hello client";
|
||||
const char mac[] = "MAC: ";
|
||||
const char connected[] = "Connected";
|
||||
const char server_up[] = "Server up";
|
||||
size_t mac_len = 5 /* MAC: */ + 6 * 2 /* 6 bytes per char */ + 5 /* : */ + 1 /* \0 */;
|
||||
if (len == sizeof(server_up) && memcmp(buffer, server_up, len) == 0) {
|
||||
if (ctx->state == UNKNOWN) {
|
||||
ESP_LOGI(TAG, "Server is up");
|
||||
ctx->state = HELLO;
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Received server up in unexpected state %d", ctx->state);
|
||||
ctx->state = ERROR;
|
||||
}
|
||||
xEventGroupSetBits(ctx->flags, SERVER_UP_BIT);
|
||||
} else if (len == sizeof(hello) && memcmp(buffer, hello, len) == 0) {
|
||||
if (ctx->state == HELLO) {
|
||||
xEventGroupSetBits(ctx->flags, HELLO_BIT);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Received hello in unexpected state %d", ctx->state);
|
||||
ctx->state = ERROR;
|
||||
}
|
||||
} else if (len == mac_len && memcmp(buffer, mac, 5) == 0) {
|
||||
if (ctx->state == HELLO) {
|
||||
uint8_t mac_addr[6];
|
||||
sscanf((char *)buffer + 5, "%2" PRIx8 ":%2" PRIx8 ":%2" PRIx8 ":%2" PRIx8 ":%2" PRIx8 ":%2" PRIx8,
|
||||
&mac_addr[0], &mac_addr[1], &mac_addr[2], &mac_addr[3], &mac_addr[4], &mac_addr[5]);
|
||||
ESP_LOGI(TAG, "Parsed MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
|
||||
memcpy(s_wifi_mac_addr, mac_addr, sizeof(s_wifi_mac_addr));
|
||||
xEventGroupSetBits(ctx->flags, START_BIT);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Received MAC in unexpected state %d", ctx->state);
|
||||
ctx->state = ERROR;
|
||||
}
|
||||
} else if (len == sizeof(connected) && memcmp(buffer, connected, len) == 0) {
|
||||
if (ctx->state == START) {
|
||||
xEventGroupSetBits(ctx->flags, CONNECT_BIT);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Received connected in unexpected state %d", ctx->state);
|
||||
ctx->state = ERROR;
|
||||
}
|
||||
}
|
||||
} else if (nr == WIFI_CHANNEL) {
|
||||
ESP_LOGD(TAG, "Received WIFI channel=%d len=%d", nr, (int)len);
|
||||
ESP_LOG_BUFFER_HEXDUMP("wifi-receive", buffer, len, ESP_LOG_VERBOSE);
|
||||
return esp_wifi_remote_channel_rx(ctx->eppp, buffer, NULL, len);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Incorrect channel number %d", nr);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t wifi_transmit(void *h, void *buffer, size_t len)
|
||||
{
|
||||
esp_netif_t *eppp = (esp_netif_t *)h;
|
||||
context_t *ctx = eppp_get_context(eppp);
|
||||
ESP_LOG_BUFFER_HEXDUMP("wifi-transmit", buffer, len, ESP_LOG_VERBOSE);
|
||||
return ctx->transmit(eppp, WIFI_CHANNEL, buffer, len);
|
||||
}
|
||||
|
||||
void esp_netif_destroy_wifi_remote(void *esp_netif);
|
||||
|
||||
void station_over_eppp_channel(void *arg)
|
||||
{
|
||||
__attribute__((unused)) esp_err_t ret;
|
||||
esp_netif_t *wifi = NULL;
|
||||
context_t ctx = {
|
||||
.transmit = NULL,
|
||||
.flags = NULL,
|
||||
.state = UNKNOWN,
|
||||
.eppp = (esp_netif_t *)arg
|
||||
};
|
||||
ESP_GOTO_ON_FALSE(ctx.eppp != NULL, ESP_FAIL, err, TAG, "Incorrect EPPP netif");
|
||||
ESP_GOTO_ON_FALSE(ctx.flags = xEventGroupCreate(), ESP_FAIL, err, TAG, "Failed to create event group");
|
||||
ESP_GOTO_ON_ERROR(eppp_add_channels(ctx.eppp, &ctx.transmit, eppp_receive, &ctx), err, TAG, "Failed to add channels");
|
||||
ESP_GOTO_ON_FALSE(ctx.transmit, ESP_FAIL, err, TAG, "Channel tx function is not set");
|
||||
ESP_GOTO_ON_ERROR(esp_wifi_remote_channel_set(WIFI_IF_STA, ctx.eppp, wifi_transmit), err, TAG, "Failed to set wifi channel tx function");
|
||||
esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, event_handler, &ctx);
|
||||
|
||||
while (1) {
|
||||
EventBits_t bits = xEventGroupWaitBits(ctx.flags, ALL_BITS, pdTRUE, pdFALSE, pdMS_TO_TICKS(1000));
|
||||
if (bits & HELLO_BIT) {
|
||||
ESP_LOGI(TAG, "Hello done");
|
||||
if (wifi == NULL) {
|
||||
wifi = esp_wifi_remote_create_default_sta();
|
||||
}
|
||||
const char command[] = "Get MAC";
|
||||
ctx.transmit(ctx.eppp, CHAT_CHANNEL, (void*)command, sizeof(command));
|
||||
} else if (bits & START_BIT) {
|
||||
ctx.state = START;
|
||||
ESP_LOGI(TAG, "Starting WIFI");
|
||||
esp_event_post(WIFI_REMOTE_EVENT, WIFI_EVENT_STA_START, NULL, 0, 0);
|
||||
} else if (bits & CONNECT_BIT) {
|
||||
ESP_LOGI(TAG, "WIFI connected");
|
||||
esp_event_post(WIFI_REMOTE_EVENT, WIFI_EVENT_STA_CONNECTED, NULL, 0, 0);
|
||||
} else if ((bits & SERVER_UP_BIT) == SERVER_UP_BIT || ctx.state != START) {
|
||||
if (ctx.state == ERROR) {
|
||||
esp_netif_destroy_wifi_remote(wifi);
|
||||
wifi = NULL;
|
||||
ESP_LOGI(TAG, "WiFi netif has been destroyed");
|
||||
}
|
||||
const char hello[] = "Hello server";
|
||||
ctx.transmit(ctx.eppp, CHAT_CHANNEL, (void*)hello, sizeof(hello));
|
||||
ctx.state = HELLO;
|
||||
}
|
||||
}
|
||||
|
||||
err:
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
@@ -1,7 +1,11 @@
|
||||
dependencies:
|
||||
espressif/iperf-cmd: "^0.1.1"
|
||||
espressif/iperf-cmd: ^0.1.1
|
||||
espressif/eppp_link:
|
||||
version: "*"
|
||||
override_path: "../../.."
|
||||
version: '*'
|
||||
override_path: ../../..
|
||||
console_cmd_ping:
|
||||
version: "*"
|
||||
version: '*'
|
||||
espressif/mqtt:
|
||||
rules:
|
||||
- if: idf_version >=6.0
|
||||
version: ^1.0.0
|
||||
|
||||
4
components/eppp_link/examples/host/sdkconfig.ci.1
Normal file
4
components/eppp_link/examples/host/sdkconfig.ci.1
Normal file
@@ -0,0 +1,4 @@
|
||||
CONFIG_IDF_TARGET="esp32s3"
|
||||
CONFIG_EPPP_LINK_DEVICE_SPI=y
|
||||
CONFIG_EPPP_LINK_CHANNELS_SUPPORT=y
|
||||
CONFIG_EPPP_LINK_USES_PPP=y
|
||||
3
components/eppp_link/examples/host/sdkconfig.ci.2
Normal file
3
components/eppp_link/examples/host/sdkconfig.ci.2
Normal file
@@ -0,0 +1,3 @@
|
||||
CONFIG_IDF_TARGET="esp32c3"
|
||||
CONFIG_EPPP_LINK_DEVICE_UART=y
|
||||
CONFIG_EPPP_LINK_CHANNELS_SUPPORT=y
|
||||
@@ -1,4 +1 @@
|
||||
CONFIG_LWIP_PPP_SUPPORT=y
|
||||
CONFIG_LWIP_PPP_SERVER_SUPPORT=y
|
||||
CONFIG_LWIP_PPP_VJ_HEADER_COMPRESSION=n
|
||||
CONFIG_LWIP_PPP_DEBUG_ON=y
|
||||
|
||||
@@ -1,2 +1,6 @@
|
||||
idf_component_register(SRCS "eppp_slave.c"
|
||||
INCLUDE_DIRS ".")
|
||||
if(CONFIG_EXAMPLE_WIFI_OVER_EPPP_CHANNEL)
|
||||
set(wifi_over_channels channel_wifi_station.c)
|
||||
endif()
|
||||
idf_component_register(SRCS eppp_slave.c
|
||||
${wifi_over_channels}
|
||||
INCLUDE_DIRS ".")
|
||||
|
||||
@@ -98,4 +98,14 @@ menu "Example Configuration"
|
||||
help
|
||||
Baudrate used by the PPP over UART
|
||||
|
||||
config EXAMPLE_WIFI_OVER_EPPP_CHANNEL
|
||||
bool "Use WiFi over EPPP channel"
|
||||
default n
|
||||
depends on EPPP_LINK_CHANNELS_SUPPORT
|
||||
help
|
||||
Enable this option to use WiFi over EPPP channel.
|
||||
If this option is enabled, the example will only start the Wi-Fi driver,
|
||||
but the Wi-Fi netif will reside on client's end and will channel
|
||||
the Rx and Tx data via EPPP channels.
|
||||
|
||||
endmenu
|
||||
|
||||
169
components/eppp_link/examples/slave/main/channel_wifi_station.c
Normal file
169
components/eppp_link/examples/slave/main/channel_wifi_station.c
Normal file
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 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 "esp_event.h"
|
||||
#include "esp_netif.h"
|
||||
#include "eppp_link.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_private/wifi.h"
|
||||
|
||||
#define CHAT_CHANNEL 1
|
||||
#define WIFI_CHANNEL 2
|
||||
|
||||
typedef enum {
|
||||
UNKNOWN,
|
||||
HELLO,
|
||||
START,
|
||||
ERROR,
|
||||
} state_t;
|
||||
|
||||
typedef struct context {
|
||||
eppp_channel_fn_t transmit;
|
||||
EventGroupHandle_t flags;
|
||||
state_t state;
|
||||
esp_netif_t *eppp;
|
||||
} context_t;
|
||||
|
||||
#define HELLO_BIT BIT0
|
||||
#define START_BIT BIT1
|
||||
#define CONNECT_BIT BIT2
|
||||
#define DISCONNECT_BIT BIT3
|
||||
|
||||
#define ALL_BITS (HELLO_BIT | START_BIT | CONNECT_BIT | DISCONNECT_BIT)
|
||||
|
||||
static const char *TAG = "eppp_host_example_with_channels";
|
||||
static context_t *s_eppp_channel_ctx = NULL;
|
||||
|
||||
static esp_err_t eppp_receive(esp_netif_t *netif, int nr, void *buffer, size_t len)
|
||||
{
|
||||
context_t *ctx = eppp_get_context(netif);
|
||||
if (nr == CHAT_CHANNEL) {
|
||||
ESP_LOGI(TAG, "Received channel=%d len=%d %.*s", nr, (int)len, (int)len, (char *)buffer);
|
||||
const char hello[] = "Hello server";
|
||||
const char mac[] = "Get MAC";
|
||||
if (len == sizeof(hello) && memcmp(buffer, hello, len) == 0) {
|
||||
if (ctx->state == HELLO) {
|
||||
xEventGroupSetBits(ctx->flags, HELLO_BIT);
|
||||
} else {
|
||||
ctx->state = ERROR;
|
||||
}
|
||||
} else if (len == sizeof(mac) && memcmp(buffer, mac, 5) == 0) {
|
||||
if (ctx->state == HELLO) {
|
||||
xEventGroupSetBits(ctx->flags, START_BIT);
|
||||
} else {
|
||||
ctx->state = ERROR;
|
||||
}
|
||||
}
|
||||
} else if (nr == WIFI_CHANNEL) {
|
||||
ESP_LOGD(TAG, "Received WIFI channel=%d len=%d", nr, (int)len);
|
||||
ESP_LOG_BUFFER_HEXDUMP("wifi-receive", buffer, len, ESP_LOG_VERBOSE);
|
||||
return esp_wifi_internal_tx(WIFI_IF_STA, buffer, len);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Incorrect channel number %d", nr);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t wifi_receive(void *buffer, uint16_t len, void *eb)
|
||||
{
|
||||
s_eppp_channel_ctx->transmit(s_eppp_channel_ctx->eppp, WIFI_CHANNEL, buffer, len);
|
||||
esp_wifi_internal_free_rx_buffer(eb);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data)
|
||||
{
|
||||
context_t *ctx = arg;
|
||||
ESP_LOGI(TAG, "event_handler: event_base=%s event_id=%d", event_base, event_id);
|
||||
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
|
||||
ESP_LOGI(TAG, "WIFI start event");
|
||||
esp_wifi_connect();
|
||||
xEventGroupSetBits(ctx->flags, CONNECT_BIT);
|
||||
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
|
||||
ESP_LOGI(TAG, "connect to the AP fail");
|
||||
xEventGroupSetBits(ctx->flags, DISCONNECT_BIT);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void init_wifi_driver(context_t *ctx)
|
||||
{
|
||||
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||||
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID,
|
||||
event_handler, ctx));
|
||||
wifi_config_t wifi_config = {
|
||||
.sta = {
|
||||
.ssid = CONFIG_ESP_WIFI_SSID,
|
||||
.password = CONFIG_ESP_WIFI_PASSWORD,
|
||||
},
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
|
||||
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
|
||||
}
|
||||
|
||||
void station_over_eppp_channel(void *arg)
|
||||
{
|
||||
__attribute__((unused)) esp_err_t ret;
|
||||
context_t ctx = {
|
||||
.transmit = NULL,
|
||||
.flags = NULL,
|
||||
.state = UNKNOWN,
|
||||
.eppp = (esp_netif_t *)arg
|
||||
};
|
||||
ESP_GOTO_ON_FALSE(ctx.flags = xEventGroupCreate(), ESP_FAIL, err, TAG, "Failed to create event group");
|
||||
ESP_GOTO_ON_ERROR(eppp_add_channels(ctx.eppp, &ctx.transmit, eppp_receive, &ctx), err, TAG, "Failed to add channels");
|
||||
ESP_GOTO_ON_FALSE(ctx.transmit, ESP_FAIL, err, TAG, "Channel tx function is not set");
|
||||
init_wifi_driver(&ctx);
|
||||
|
||||
while (1) {
|
||||
EventBits_t bits = xEventGroupWaitBits(ctx.flags, ALL_BITS, pdTRUE, pdFALSE, pdMS_TO_TICKS(1000));
|
||||
if (bits & HELLO_BIT) {
|
||||
ESP_LOGI(TAG, "Hello from client received");
|
||||
const char hello[] = "Hello client";
|
||||
ctx.transmit(ctx.eppp, CHAT_CHANNEL, (void*)hello, sizeof(hello));
|
||||
} else if (bits & START_BIT) {
|
||||
ctx.state = START;
|
||||
ESP_LOGI(TAG, "Starting WIFI");
|
||||
uint8_t mac[6];
|
||||
if (esp_wifi_get_mac(WIFI_IF_STA, mac) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "esp_wifi_get_mac failed");
|
||||
ctx.state = ERROR;
|
||||
continue;
|
||||
}
|
||||
char mac_data[5 /* MAC: */ + 6 * 2 /* 6 bytes per char */ + 5 /* : */ + 1 /* \0 */];
|
||||
sprintf(mac_data, "MAC: %02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||
ESP_LOGI(TAG, "Sending MAC: %.*s", (int)sizeof(mac_data), mac_data);
|
||||
ctx.transmit(ctx.eppp, CHAT_CHANNEL, (void*)mac_data, sizeof(mac_data));
|
||||
ret = esp_wifi_start();
|
||||
ESP_LOGI(TAG, "WIFI start result: %d", ret);
|
||||
s_eppp_channel_ctx = &ctx;
|
||||
esp_wifi_internal_reg_rxcb(WIFI_IF_STA, wifi_receive);
|
||||
} else if (bits & CONNECT_BIT) {
|
||||
ESP_LOGI(TAG, "WIFI connected");
|
||||
const char connected[] = "Connected";
|
||||
ctx.transmit(ctx.eppp, CHAT_CHANNEL, (void*)connected, sizeof(connected));
|
||||
} else if (bits & DISCONNECT_BIT) {
|
||||
const char disconnected[] = "Disconnected";
|
||||
ctx.transmit(ctx.eppp, CHAT_CHANNEL, (void*)disconnected, sizeof(disconnected));
|
||||
} else if (ctx.state != START) {
|
||||
ctx.state = HELLO;
|
||||
const char up[] = "Server up";
|
||||
esp_wifi_disconnect();
|
||||
esp_wifi_stop();
|
||||
ctx.transmit(ctx.eppp, CHAT_CHANNEL, (void*)up, sizeof(up));
|
||||
}
|
||||
}
|
||||
|
||||
err:
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
@@ -11,12 +11,14 @@
|
||||
#include "esp_wifi.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_check.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "eppp_link.h"
|
||||
#include "inttypes.h"
|
||||
|
||||
static const char *TAG = "eppp_slave";
|
||||
|
||||
#if CONFIG_SOC_WIFI_SUPPORTED
|
||||
#if defined(CONFIG_SOC_WIFI_SUPPORTED) && !defined(CONFIG_EXAMPLE_WIFI_OVER_EPPP_CHANNEL)
|
||||
|
||||
/* FreeRTOS event group to signal when we are connected*/
|
||||
static EventGroupHandle_t s_wifi_event_group;
|
||||
@@ -27,12 +29,13 @@ static EventGroupHandle_t s_wifi_event_group;
|
||||
#define WIFI_CONNECTED_BIT BIT0
|
||||
#define WIFI_FAIL_BIT BIT1
|
||||
|
||||
|
||||
static int s_retry_num = 0;
|
||||
|
||||
static void event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data)
|
||||
{
|
||||
ESP_LOGI(TAG, "event_handler: event_base=%s event_id=%" PRIi32, event_base, event_id);
|
||||
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
|
||||
ESP_LOGI(TAG, "WIFI start event");
|
||||
esp_wifi_connect();
|
||||
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
|
||||
if (s_retry_num < CONFIG_ESP_MAXIMUM_RETRY) {
|
||||
@@ -107,12 +110,15 @@ void init_network_interface(void)
|
||||
}
|
||||
#else
|
||||
|
||||
// If the SoC does not have WiFi capabilities, we can initialize a different network interface, this function is a placeholder for that purpose.
|
||||
// This function is also a no-op if EXAMPLE_WIFI_OVER_EPPP_CHANNEL==1, since the Wi-Fi network interface will live on the other peer (on the host side).
|
||||
void init_network_interface(void)
|
||||
{
|
||||
// placeholder to initialize any other network interface if WiFi is not available
|
||||
}
|
||||
|
||||
#endif // SoC WiFi capable chip
|
||||
#endif // SoC WiFi capable chip || WiFi over EPPP channel
|
||||
|
||||
void station_over_eppp_channel(void *arg);
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
@@ -153,5 +159,9 @@ void app_main(void)
|
||||
ESP_LOGE(TAG, "Failed to setup connection");
|
||||
return ;
|
||||
}
|
||||
#ifdef CONFIG_EXAMPLE_WIFI_OVER_EPPP_CHANNEL
|
||||
station_over_eppp_channel(eppp_netif);
|
||||
#else
|
||||
ESP_ERROR_CHECK(esp_netif_napt_enable(eppp_netif));
|
||||
#endif // CONFIG_EXAMPLE_WIFI_OVER_EPPP_CHANNEL
|
||||
}
|
||||
|
||||
4
components/eppp_link/examples/slave/sdkconfig.ci.1
Normal file
4
components/eppp_link/examples/slave/sdkconfig.ci.1
Normal file
@@ -0,0 +1,4 @@
|
||||
CONFIG_IDF_TARGET="esp32s2"
|
||||
CONFIG_EPPP_LINK_DEVICE_SPI=y
|
||||
CONFIG_EPPP_LINK_CHANNELS_SUPPORT=y
|
||||
CONFIG_LWIP_PPP_VJ_HEADER_COMPRESSION=n
|
||||
4
components/eppp_link/examples/slave/sdkconfig.ci.2
Normal file
4
components/eppp_link/examples/slave/sdkconfig.ci.2
Normal file
@@ -0,0 +1,4 @@
|
||||
CONFIG_IDF_TARGET="esp32c2"
|
||||
CONFIG_EPPP_LINK_DEVICE_UART=y
|
||||
CONFIG_LWIP_PPP_VJ_HEADER_COMPRESSION=n
|
||||
CONFIG_EPPP_LINK_USES_PPP=y
|
||||
@@ -0,0 +1 @@
|
||||
CONFIG_LWIP_IPV6=n
|
||||
@@ -1,6 +1,3 @@
|
||||
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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
version: 0.3.0
|
||||
version: 1.1.4
|
||||
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:
|
||||
|
||||
@@ -5,6 +5,10 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define EPPP_DEFAULT_SERVER_IP() ESP_IP4TOADDR(192, 168, 11, 1)
|
||||
#define EPPP_DEFAULT_CLIENT_IP() ESP_IP4TOADDR(192, 168, 11, 2)
|
||||
|
||||
@@ -30,6 +34,9 @@
|
||||
.rx_io = 26, \
|
||||
.queue_size = 16, \
|
||||
.rx_buffer_size = 1024, \
|
||||
.rts_io = -1, \
|
||||
.cts_io = -1, \
|
||||
.flow_control = 0, \
|
||||
}, \
|
||||
|
||||
#define EPPP_DEFAULT_SDIO_CONFIG() \
|
||||
@@ -110,7 +117,6 @@ typedef enum eppp_transport {
|
||||
|
||||
typedef struct eppp_config_t {
|
||||
eppp_transport_t transport;
|
||||
|
||||
struct eppp_config_spi_s {
|
||||
int host;
|
||||
bool is_master;
|
||||
@@ -132,6 +138,9 @@ typedef struct eppp_config_t {
|
||||
int rx_io;
|
||||
int queue_size;
|
||||
int rx_buffer_size;
|
||||
int rts_io;
|
||||
int cts_io;
|
||||
int flow_control;
|
||||
} uart;
|
||||
|
||||
struct eppp_config_sdio_s {
|
||||
@@ -203,3 +212,15 @@ void eppp_netif_deinit(esp_netif_t *netif);
|
||||
* - ESP_ERR_TIMEOUT indicates that the operation was requested to stop
|
||||
*/
|
||||
esp_err_t eppp_perform(esp_netif_t *netif);
|
||||
|
||||
#ifdef CONFIG_EPPP_LINK_CHANNELS_SUPPORT
|
||||
typedef esp_err_t (*eppp_channel_fn_t)(esp_netif_t *netif, int nr, void *buffer, size_t len);
|
||||
|
||||
esp_err_t eppp_add_channels(esp_netif_t *netif, eppp_channel_fn_t *tx, const eppp_channel_fn_t rx, void* context);
|
||||
|
||||
void* eppp_get_context(esp_netif_t *netif);
|
||||
#endif // CONFIG_EPPP_LINK_CHANNELS_SUPPORT
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,7 +1,15 @@
|
||||
# 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}/tools/unit-test-app/components)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
|
||||
if("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_GREATER_EQUAL "6.0")
|
||||
set(test_component_dir $ENV{IDF_PATH}/tools/test_apps/components)
|
||||
else()
|
||||
set(test_component_dir $ENV{IDF_PATH}/tools/unit-test-app/components)
|
||||
endif()
|
||||
|
||||
set(EXTRA_COMPONENT_DIRS ${test_component_dir})
|
||||
|
||||
project(test_app)
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
if("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_GREATER "5.3")
|
||||
set(driver_deps esp_driver_gpio esp_driver_spi esp_driver_uart esp_driver_sdio)
|
||||
else()
|
||||
set(driver_deps driver)
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS app_main.c
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES test_utils
|
||||
PRIV_REQUIRES unity nvs_flash esp_netif driver esp_event)
|
||||
PRIV_REQUIRES unity nvs_flash esp_netif esp_event ${driver_deps})
|
||||
|
||||
@@ -177,6 +177,9 @@ esp_err_t esp_dns_http_event_handler(esp_http_client_event_t *evt)
|
||||
case HTTP_EVENT_REDIRECT:
|
||||
ESP_LOGE(TAG, "HTTP_EVENT_REDIRECT: Not supported(%d)", esp_http_client_get_status_code(evt->client));
|
||||
break;
|
||||
default:
|
||||
ESP_LOGD(TAG, "Other HTTP event: %d", evt->event_id);
|
||||
break;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,6 @@ commitizen:
|
||||
bump_message: 'bump(modem): $current_version -> $new_version'
|
||||
pre_bump_hooks: python ../../ci/changelog.py esp_modem
|
||||
tag_format: modem-v$version
|
||||
version: 1.4.0
|
||||
version: 2.0.0
|
||||
version_files:
|
||||
- idf_component.yml
|
||||
|
||||
@@ -1,5 +1,41 @@
|
||||
# Changelog
|
||||
|
||||
## [2.0.0](https://github.com/espressif/esp-protocols/commits/modem-v2.0.0)
|
||||
|
||||
### Breaking changes
|
||||
|
||||
- inc headers for AT command definitions are no longer used directly, but pregenerated into *.h(pp) ([Use generated AT command definitions for IDE navigation](https://github.com/espressif/esp-protocols/commit/e2fa1110))
|
||||
|
||||
### Features
|
||||
|
||||
- Add support for multiple connection in AT based example ([2826287d](https://github.com/espressif/esp-protocols/commit/2826287d))
|
||||
- Add enhanced URC observer API ([4889dd6f](https://github.com/espressif/esp-protocols/commit/4889dd6f))
|
||||
- Support esp-modem use without PPP ([858f8570](https://github.com/espressif/esp-protocols/commit/858f8570), [#851](https://github.com/espressif/esp-protocols/issues/851))
|
||||
- Modem simulator based on esp-at ([e5787e3d](https://github.com/espressif/esp-protocols/commit/e5787e3d))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Update tests and examples to use modem-v2.0 ([4aa0e4ba](https://github.com/espressif/esp-protocols/commit/4aa0e4ba))
|
||||
- Replace MQTT client with simple ping command ([0ccaf2c0](https://github.com/espressif/esp-protocols/commit/0ccaf2c0))
|
||||
- Replace MQTT client with simple ping command ([9b2b1f68](https://github.com/espressif/esp-protocols/commit/9b2b1f68))
|
||||
- Update example to use optional mqtt deps ([3141d6ca](https://github.com/espressif/esp-protocols/commit/3141d6ca))
|
||||
- Minor fixed in the test code ([e772ce67](https://github.com/espressif/esp-protocols/commit/e772ce67))
|
||||
- Add missing set_echo() C wrapper ([d1e67080](https://github.com/espressif/esp-protocols/commit/d1e67080), [#926](https://github.com/espressif/esp-protocols/issues/926))
|
||||
- Fix modem console dependencies ([453be4cd](https://github.com/espressif/esp-protocols/commit/453be4cd))
|
||||
- Address build issues ([018ba58e](https://github.com/espressif/esp-protocols/commit/018ba58e))
|
||||
- Fix driver dependency issue on v6.0 ([67c682d9](https://github.com/espressif/esp-protocols/commit/67c682d9))
|
||||
- Fix CI build issues with IDFv6.0 ([15140e04](https://github.com/espressif/esp-protocols/commit/15140e04))
|
||||
- Add support for ESP-AT based tcp-client example ([14d3cb6b](https://github.com/espressif/esp-protocols/commit/14d3cb6b))
|
||||
- Use idf-build-apps for building target tests ([e9d9b3a8](https://github.com/espressif/esp-protocols/commit/e9d9b3a8))
|
||||
- Make MQTT public broker endpoint configurable ([6d541194](https://github.com/espressif/esp-protocols/commit/6d541194))
|
||||
- Fix URC handling in DTE data callback ([93029946](https://github.com/espressif/esp-protocols/commit/93029946))
|
||||
- Use another public broker for examples and tests ([fac2edbe](https://github.com/espressif/esp-protocols/commit/fac2edbe))
|
||||
- Fix incompatible iterator in std::search() in new gcc ([ed0f6334](https://github.com/espressif/esp-protocols/commit/ed0f6334))
|
||||
- Fix autodetect to support ACFC mode in PPP frames ([8b328a69](https://github.com/espressif/esp-protocols/commit/8b328a69), [#801](https://github.com/espressif/esp-protocols/issues/801))
|
||||
- Fix get_network_registration_state() to accept two params ([5f54d907](https://github.com/espressif/esp-protocols/commit/5f54d907), [#826](https://github.com/espressif/esp-protocols/issues/826))
|
||||
- Consume buffer after handled URC ([6eceb28f](https://github.com/espressif/esp-protocols/commit/6eceb28f))
|
||||
- Use generated AT command definitions for IDE navigation ([e2fa1110](https://github.com/espressif/esp-protocols/commit/e2fa1110), !BREAKING)
|
||||
|
||||
## [1.4.0](https://github.com/espressif/esp-protocols/commits/modem-v1.4.0)
|
||||
|
||||
### Features
|
||||
|
||||
@@ -11,7 +11,12 @@ else()
|
||||
src/esp_modem_uart.cpp
|
||||
src/esp_modem_term_uart.cpp
|
||||
src/esp_modem_netif.cpp)
|
||||
set(dependencies driver esp_event esp_netif)
|
||||
set(dependencies esp_event esp_netif)
|
||||
if("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_GREATER "5.3")
|
||||
list(APPEND dependencies esp_driver_uart)
|
||||
else()
|
||||
list(APPEND dependencies driver)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
|
||||
@@ -103,4 +103,14 @@ menu "esp-modem"
|
||||
Set this to 'y' if you're making changes to the actual sources of
|
||||
the AT command definitions (typically in esp_modem_command_declare.inc)
|
||||
|
||||
config ESP_MODEM_USE_PPP_MODE
|
||||
bool "Use PPP mode"
|
||||
default y
|
||||
select LWIP_PPP_SUPPORT
|
||||
help
|
||||
If enabled, the library can use PPP netif from lwip.
|
||||
This is the default and most common setting.
|
||||
But it's possible to disable it and use only AT commands,
|
||||
in this case it's not required to enable LWIP_PPP_SUPPORT.
|
||||
|
||||
endmenu
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
@@ -100,10 +100,10 @@ void wifi_init_softap(void)
|
||||
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
|
||||
|
||||
ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
|
||||
ESP_EVENT_ANY_ID,
|
||||
&wifi_event_handler,
|
||||
NULL,
|
||||
NULL));
|
||||
ESP_EVENT_ANY_ID,
|
||||
&wifi_event_handler,
|
||||
NULL,
|
||||
NULL));
|
||||
|
||||
wifi_config_t wifi_config = {
|
||||
.ap = {
|
||||
@@ -120,7 +120,7 @@ void wifi_init_softap(void)
|
||||
}
|
||||
|
||||
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));
|
||||
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_AP, &wifi_config));
|
||||
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &wifi_config));
|
||||
ESP_ERROR_CHECK(esp_wifi_start());
|
||||
|
||||
ESP_LOGI(TAG, "wifi_init_softap finished. SSID:%s password:%s channel:%d",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
dependencies:
|
||||
espressif/esp_modem:
|
||||
version: "^1.0.1"
|
||||
version: "^2"
|
||||
override_path: "../../../"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
dependencies:
|
||||
espressif/esp_modem:
|
||||
version: "^1.0.1"
|
||||
version: "^2"
|
||||
override_path: "../../../"
|
||||
|
||||
@@ -9,5 +9,4 @@ idf_component_register(SRCS "modem_console_main.cpp"
|
||||
"${command_dir}/my_module_dce.cpp"
|
||||
"httpget_handle.c"
|
||||
"ping_handle.c"
|
||||
REQUIRES console esp_http_client nvs_flash
|
||||
INCLUDE_DIRS "." "${command_dir}")
|
||||
|
||||
@@ -63,13 +63,12 @@ void ConsoleCommand::RegisterCommand(const char *command, const char *help, cons
|
||||
|
||||
arg_type end = { .end = arg_end(1) };
|
||||
arg_table.emplace_back(end);
|
||||
const esp_console_cmd_t command_def = {
|
||||
.command = command,
|
||||
.help = help,
|
||||
.hint = nullptr,
|
||||
.func = command_func_pts[last_command],
|
||||
.argtable = &arg_table[0]
|
||||
};
|
||||
esp_console_cmd_t command_def = { };
|
||||
command_def.command = command;
|
||||
command_def.help = help;
|
||||
command_def.hint = nullptr;
|
||||
command_def.func = command_func_pts[last_command];
|
||||
command_def.argtable = &arg_table[0];
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&command_def));
|
||||
last_command++;
|
||||
console_commands.emplace_back(this);
|
||||
|
||||
@@ -3,7 +3,7 @@ dependencies:
|
||||
## Required IDF version
|
||||
idf: ">=4.1.0"
|
||||
espressif/esp_modem:
|
||||
version: "^1.0.0"
|
||||
version: "^2"
|
||||
override_path: "../../../"
|
||||
espressif/esp_modem_usb_dte:
|
||||
version: "^1.2.0"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "cxx_include/esp_modem_dte.hpp"
|
||||
#include "esp_modem_config.h"
|
||||
#include "cxx_include/esp_modem_api.hpp"
|
||||
#include "esp_idf_version.h"
|
||||
#if defined(CONFIG_EXAMPLE_SERIAL_CONFIG_USB)
|
||||
#include "esp_modem_usb_config.h"
|
||||
#include "cxx_include/esp_modem_usb_api.hpp"
|
||||
@@ -29,6 +30,12 @@
|
||||
#include "console_helper.hpp"
|
||||
#include "my_module_dce.hpp"
|
||||
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(6, 0, 0)
|
||||
#define GET_WAKEUP_CAUSE() esp_sleep_get_wakeup_causes()
|
||||
#else
|
||||
#define GET_WAKEUP_CAUSE() esp_sleep_get_wakeup_cause()
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_EXAMPLE_FLOW_CONTROL_NONE)
|
||||
#define EXAMPLE_FLOW_CONTROL ESP_MODEM_FLOW_CONTROL_NONE
|
||||
#elif defined(CONFIG_EXAMPLE_FLOW_CONTROL_SW)
|
||||
@@ -90,10 +97,21 @@ void wakeup_modem(void)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ESP_MODEM_URC_HANDLER
|
||||
command_result handle_urc(uint8_t *data, size_t len)
|
||||
esp_modem::DTE::UrcConsumeInfo handle_enhanced_urc(const esp_modem::DTE::UrcBufferInfo &info)
|
||||
{
|
||||
ESP_LOG_BUFFER_HEXDUMP("on_read", data, len, ESP_LOG_INFO);
|
||||
return command_result::TIMEOUT;
|
||||
// Log buffer information for debugging
|
||||
ESP_LOGI(TAG, "URC Buffer Info: total_size=%zu, processed_offset=%zu, new_data_size=%zu, command_active=%s",
|
||||
info.buffer_total_size, info.processed_offset, info.new_data_size,
|
||||
info.is_command_active ? "true" : "false");
|
||||
|
||||
// Log the new data content
|
||||
if (info.new_data_size > 0) {
|
||||
ESP_LOG_BUFFER_HEXDUMP("on_read", info.new_data_start, info.new_data_size, ESP_LOG_INFO);
|
||||
}
|
||||
|
||||
// For console example, we just log and don't consume anything
|
||||
// This allows the data to be processed by command handlers
|
||||
return {esp_modem::DTE::UrcConsumeResult::CONSUME_NONE, 0};
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -208,7 +226,7 @@ extern "C" void app_main(void)
|
||||
esp_console_dev_uart_config_t uart_config = ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT();
|
||||
ESP_ERROR_CHECK(esp_console_new_repl_uart(&uart_config, &repl_config, &s_repl));
|
||||
|
||||
switch (esp_sleep_get_wakeup_cause()) {
|
||||
switch (GET_WAKEUP_CAUSE()) {
|
||||
case ESP_SLEEP_WAKEUP_TIMER:
|
||||
if (esp_modem::modem_mode::CMUX_MODE == mode_rtc) {
|
||||
ESP_LOGI(TAG, "Deep sleep reset\n");
|
||||
@@ -374,14 +392,14 @@ extern "C" void app_main(void)
|
||||
CHECK_ERR(dce->reset(), ESP_LOGI(TAG, "OK"));
|
||||
});
|
||||
#ifdef CONFIG_ESP_MODEM_URC_HANDLER
|
||||
const ConsoleCommand HandleURC("urc", "toggle urc handling", no_args, [&](ConsoleCommand * c) {
|
||||
const ConsoleCommand HandleURC("urc", "toggle enhanced urc handling", no_args, [&](ConsoleCommand * c) {
|
||||
static int cnt = 0;
|
||||
if (++cnt % 2) {
|
||||
ESP_LOGI(TAG, "Adding URC handler");
|
||||
dce->set_urc(handle_urc);
|
||||
ESP_LOGI(TAG, "Adding enhanced URC handler");
|
||||
dce->set_enhanced_urc(handle_enhanced_urc);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "URC removed");
|
||||
dce->set_urc(nullptr);
|
||||
ESP_LOGI(TAG, "Enhanced URC removed");
|
||||
dce->set_enhanced_urc(nullptr);
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
@@ -428,7 +446,7 @@ extern "C" void app_main(void)
|
||||
const ConsoleCommand SetDeepSleep("set_deep_sleep", "Put esp32 to deep sleep", &deep_sleep_args, sizeof(deep_sleep_args), [&](ConsoleCommand * c) {
|
||||
int tout = c->get_int_of(&DeepSleepArgs::timeout);
|
||||
ESP_LOGI(TAG, "Entering deep sleep for %d sec", tout);
|
||||
ESP_LOGI(TAG, "Wakeup Cause: %d ", esp_sleep_get_wakeup_cause());
|
||||
ESP_LOGI(TAG, "Wakeup Cause: %d ", GET_WAKEUP_CAUSE());
|
||||
esp_deep_sleep(tout * 1000000);
|
||||
return 0;
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
dependencies:
|
||||
espressif/esp_modem:
|
||||
version: "^1.0.1"
|
||||
version: "^2"
|
||||
override_path: "../../../"
|
||||
|
||||
@@ -22,3 +22,18 @@ To enable this mode, please set `EXAMPLE_CUSTOM_TCP_TRANSPORT=y`
|
||||
This configuration could be used with any network library, which is connecting to a localhost endpoint instead of remote one. This example creates a localhost listener which basically mimics the remote endpoint by forwarding the traffic between the library and the TCP/socket layer of the modem (which is already secure if the TLS is used in the network library)
|
||||
|
||||

|
||||
|
||||
### Multi-connection support
|
||||
|
||||
This example supports opening multiple TCP connections concurrently when the modem firmware allows it.
|
||||
|
||||
- ESP-AT: Multi-connection mode is enabled via `AT+CIPMUX=1`. The example assigns a unique link ID per DCE instance and includes the link ID in `CIPSTART/CIPSEND/CIPRECVDATA` commands.
|
||||
- BG96/SIM7600: The example uses module-specific multi-connection syntax (for example `QIOPEN/CIPOPEN` with a connection ID) and tracks link IDs internally.
|
||||
|
||||
How it works:
|
||||
- The `sock_dce` layer creates multiple DCE instances over a shared DTE. A lightweight mutex coordinates access to the UART so only one DCE issues AT commands at a time.
|
||||
- Asynchronous URCs (for example `+IPD`, `+QIURC`, `+CIPRXGET: 1,<cid>`) wake the corresponding DCE which then performs receive operations for its link.
|
||||
|
||||
Usage:
|
||||
- `app_main` starts two DCE tasks to demonstrate concurrent connections. Adjust the number of DCE instances as needed.
|
||||
- For ESP-AT, ensure your firmware supports `CIPMUX=1` and passive receive (`CIPRECVTYPE`).
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
set(module_dir "generic_module")
|
||||
if (CONFIG_EXAMPLE_MODEM_DEVICE_BG96)
|
||||
set(device_srcs sock_commands_bg96.cpp)
|
||||
elseif(CONFIG_EXAMPLE_MODEM_DEVICE_SIM7600)
|
||||
set(device_srcs sock_commands_sim7600.cpp)
|
||||
elseif(CONFIG_EXAMPLE_MODEM_DEVICE_ESPAT)
|
||||
set(device_srcs sock_commands_espat.cpp)
|
||||
set(module_dir "espat_module")
|
||||
endif()
|
||||
|
||||
if(CONFIG_ESP_MODEM_ENABLE_DEVELOPMENT_MODE)
|
||||
@@ -14,4 +18,4 @@ idf_component_register(SRCS "modem_client.cpp"
|
||||
"${command_dir}/sock_dce.cpp"
|
||||
"tcp_transport_at.cpp"
|
||||
"${device_srcs}"
|
||||
INCLUDE_DIRS "." "${command_dir}")
|
||||
INCLUDE_DIRS "." "${command_dir}" "${module_dir}")
|
||||
|
||||
@@ -18,14 +18,44 @@ menu "Example Configuration"
|
||||
bool "SIM7600"
|
||||
help
|
||||
SIM7600 is Multi-Band LTE-TDD/LTE-FDD/HSPA+ and GSM/GPRS/EDGE module
|
||||
config EXAMPLE_MODEM_DEVICE_ESPAT
|
||||
bool "ESP-AT"
|
||||
help
|
||||
ESP-AT firmware for ESP32 modules with WiFi connectivity
|
||||
endchoice
|
||||
|
||||
if EXAMPLE_MODEM_DEVICE_ESPAT
|
||||
config EXAMPLE_WIFI_SSID
|
||||
string "WiFi SSID"
|
||||
default "myssid"
|
||||
help
|
||||
SSID (network name) to connect to.
|
||||
|
||||
config EXAMPLE_WIFI_PASSWORD
|
||||
string "WiFi Password"
|
||||
default "mypassword"
|
||||
help
|
||||
WiFi password (WPA or WPA2).
|
||||
endif
|
||||
|
||||
config EXAMPLE_MODEM_APN
|
||||
string "Set MODEM APN"
|
||||
default "internet"
|
||||
help
|
||||
Set APN (Access Point Name), a logical name to choose data network
|
||||
|
||||
config EXAMPLE_USE_TLS
|
||||
bool "Use TLS for MQTT broker"
|
||||
default n
|
||||
help
|
||||
Enable TLS for connection to the MQTT broker.
|
||||
|
||||
config EXAMPLE_BROKER_HOST
|
||||
string "MQTT broker host"
|
||||
default "test.mosquitto.org"
|
||||
help
|
||||
Hostname or IP address of the MQTT broker.
|
||||
|
||||
menu "UART Configuration"
|
||||
config EXAMPLE_MODEM_UART_TX_PIN
|
||||
int "TXD Pin Number"
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <charconv>
|
||||
#include <sys/socket.h>
|
||||
#include "esp_vfs.h"
|
||||
@@ -14,6 +15,29 @@
|
||||
namespace sock_dce {
|
||||
|
||||
constexpr auto const *TAG = "sock_dce";
|
||||
constexpr auto WAIT_TO_IDLE_TIMEOUT = 5000;
|
||||
|
||||
// Definition of the static member variables
|
||||
std::vector<DCE *> DCE::dce_list{};
|
||||
bool DCE::network_init = false;
|
||||
int Responder::s_link_id = 0;
|
||||
SemaphoreHandle_t Responder::s_dte_mutex{};
|
||||
|
||||
// Constructor - add this DCE instance to the static list
|
||||
DCE::DCE(std::shared_ptr<esp_modem::DTE> dte_arg, const esp_modem_dce_config *config)
|
||||
: Module(std::move(dte_arg), config)
|
||||
{
|
||||
dce_list.push_back(this);
|
||||
}
|
||||
|
||||
// Destructor - remove this DCE instance from the static list
|
||||
DCE::~DCE()
|
||||
{
|
||||
auto it = std::find(dce_list.begin(), dce_list.end(), this);
|
||||
if (it != dce_list.end()) {
|
||||
dce_list.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool DCE::perform_sock()
|
||||
@@ -61,13 +85,26 @@ bool DCE::perform_sock()
|
||||
|
||||
void DCE::perform_at(uint8_t *data, size_t len)
|
||||
{
|
||||
ESP_LOG_BUFFER_HEXDUMP(TAG, data, len, ESP_LOG_VERBOSE);
|
||||
if (state != status::RECEIVING) {
|
||||
std::string_view resp_sv((char *)data, len);
|
||||
at.check_urc(state, resp_sv);
|
||||
if (state == status::IDLE) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Trace incoming AT bytes when handling a response; use DEBUG level
|
||||
ESP_LOG_BUFFER_HEXDUMP(TAG, data, len, ESP_LOG_DEBUG);
|
||||
switch (at.process_data(state, data, len)) {
|
||||
case Responder::ret::OK:
|
||||
// Release DTE access for this link after processing data
|
||||
ESP_LOGD(TAG, "GIVE data %d", at.link_id);
|
||||
xSemaphoreGive(at.s_dte_mutex);
|
||||
state = status::IDLE;
|
||||
signal.set(IDLE);
|
||||
return;
|
||||
case Responder::ret::FAIL:
|
||||
ESP_LOGD(TAG, "GIVE data %d", at.link_id);
|
||||
xSemaphoreGive(at.s_dte_mutex);
|
||||
state = status::FAILED;
|
||||
signal.set(IDLE);
|
||||
return;
|
||||
@@ -82,10 +119,14 @@ void DCE::perform_at(uint8_t *data, size_t len)
|
||||
std::string_view response((char *)data, len);
|
||||
switch (at.check_async_replies(state, response)) {
|
||||
case Responder::ret::OK:
|
||||
ESP_LOGD(TAG, "GIVE command %d", at.link_id);
|
||||
xSemaphoreGive(at.s_dte_mutex);
|
||||
state = status::IDLE;
|
||||
signal.set(IDLE);
|
||||
return;
|
||||
case Responder::ret::FAIL:
|
||||
ESP_LOGD(TAG, "GIVE command %d", at.link_id);
|
||||
xSemaphoreGive(at.s_dte_mutex);
|
||||
state = status::FAILED;
|
||||
signal.set(IDLE);
|
||||
return;
|
||||
@@ -121,7 +162,7 @@ bool DCE::at_to_sock()
|
||||
uint64_t data;
|
||||
read(data_ready_fd, &data, sizeof(data));
|
||||
ESP_LOGD(TAG, "select read: modem data available %" PRIu64, data);
|
||||
if (!signal.wait(IDLE, 1000)) {
|
||||
if (!signal.wait(IDLE, WAIT_TO_IDLE_TIMEOUT)) {
|
||||
ESP_LOGE(TAG, "Failed to get idle");
|
||||
close_sock();
|
||||
return false;
|
||||
@@ -131,6 +172,10 @@ bool DCE::at_to_sock()
|
||||
close_sock();
|
||||
return false;
|
||||
}
|
||||
// Take DTE mutex before issuing receive on this link
|
||||
ESP_LOGD(TAG, "TAKE RECV %d", at.link_id);
|
||||
xSemaphoreTake(at.s_dte_mutex, portMAX_DELAY);
|
||||
ESP_LOGD(TAG, "TAKEN RECV %d", at.link_id);
|
||||
state = status::RECEIVING;
|
||||
at.start_receiving(at.get_buf_len());
|
||||
return true;
|
||||
@@ -139,7 +184,7 @@ bool DCE::at_to_sock()
|
||||
bool DCE::sock_to_at()
|
||||
{
|
||||
ESP_LOGD(TAG, "socket read: data available");
|
||||
if (!signal.wait(IDLE, 1000)) {
|
||||
if (!signal.wait(IDLE, WAIT_TO_IDLE_TIMEOUT)) {
|
||||
ESP_LOGE(TAG, "Failed to get idle");
|
||||
close_sock();
|
||||
return false;
|
||||
@@ -149,6 +194,10 @@ bool DCE::sock_to_at()
|
||||
close_sock();
|
||||
return false;
|
||||
}
|
||||
// Take DTE mutex before issuing send on this link
|
||||
ESP_LOGD(TAG, "TAKE SEND %d", at.link_id);
|
||||
xSemaphoreTake(at.s_dte_mutex, portMAX_DELAY);
|
||||
ESP_LOGD(TAG, "TAKEN SEND %d", at.link_id);
|
||||
state = status::SENDING;
|
||||
int len = ::recv(sock, at.get_buf(), at.get_buf_len(), 0);
|
||||
if (len < 0) {
|
||||
@@ -201,7 +250,7 @@ void DCE::start_listening(int port)
|
||||
}
|
||||
int opt = 1;
|
||||
setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
|
||||
ESP_LOGI(TAG, "Socket created");
|
||||
ESP_LOGD(TAG, "Socket created");
|
||||
struct sockaddr_in addr = { };
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(port);
|
||||
@@ -213,7 +262,7 @@ void DCE::start_listening(int port)
|
||||
ESP_LOGE(TAG, "Socket unable to bind: errno %d", errno);
|
||||
return;
|
||||
}
|
||||
ESP_LOGI(TAG, "Socket bound, port %d", 1883);
|
||||
ESP_LOGD(TAG, "Socket bound, port %d", 1883);
|
||||
err = listen(listen_sock, 1);
|
||||
if (err != 0) {
|
||||
ESP_LOGE(TAG, "Error occurred during listen: errno %d", errno);
|
||||
@@ -224,12 +273,12 @@ void DCE::start_listening(int port)
|
||||
|
||||
bool DCE::connect(std::string host, int port)
|
||||
{
|
||||
dte->on_read(nullptr);
|
||||
tcp_close();
|
||||
dte->on_read([this](uint8_t *data, size_t len) {
|
||||
this->perform_at(data, len);
|
||||
return esp_modem::command_result::TIMEOUT;
|
||||
});
|
||||
data_ready_fd = eventfd(0, EFD_SUPPORT_ISR);
|
||||
assert(data_ready_fd > 0);
|
||||
// Take DTE mutex before starting connect for this link
|
||||
ESP_LOGD(TAG, "TAKE CONNECT %d", at.link_id);
|
||||
xSemaphoreTake(at.s_dte_mutex, portMAX_DELAY);
|
||||
ESP_LOGD(TAG, "TAKEN CONNECT %d", at.link_id);
|
||||
if (!at.start_connecting(host, port)) {
|
||||
ESP_LOGE(TAG, "Unable to start connecting");
|
||||
dte->on_read(nullptr);
|
||||
@@ -241,12 +290,15 @@ bool DCE::connect(std::string host, int port)
|
||||
|
||||
bool DCE::init()
|
||||
{
|
||||
if (network_init) {
|
||||
return true;
|
||||
}
|
||||
network_init = true;
|
||||
Responder::s_dte_mutex = xSemaphoreCreateBinary();
|
||||
xSemaphoreGive(at.s_dte_mutex);
|
||||
esp_vfs_eventfd_config_t config = ESP_VFS_EVENTD_CONFIG_DEFAULT();
|
||||
esp_vfs_eventfd_register(&config);
|
||||
|
||||
data_ready_fd = eventfd(0, EFD_SUPPORT_ISR);
|
||||
assert(data_ready_fd > 0);
|
||||
|
||||
dte->on_read(nullptr);
|
||||
const int retries = 5;
|
||||
int i = 0;
|
||||
@@ -287,6 +339,10 @@ bool DCE::init()
|
||||
esp_modem::Task::Delay(5000);
|
||||
}
|
||||
ESP_LOGI(TAG, "Got IP %s", ip_addr.c_str());
|
||||
dte->on_read([](uint8_t *data, size_t len) {
|
||||
read_callback(data, len);
|
||||
return esp_modem::command_result::TIMEOUT;
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "cxx_include/esp_modem_api.hpp"
|
||||
#include <cxx_include/esp_modem_dce_factory.hpp>
|
||||
#include "sock_commands.hpp"
|
||||
#include "sock_module.hpp"
|
||||
#include <sys/socket.h>
|
||||
|
||||
#pragma once
|
||||
@@ -33,6 +34,7 @@ public:
|
||||
sock(s), data_ready_fd(ready_fd), dte(dte_arg) {}
|
||||
ret process_data(status state, uint8_t *data, size_t len);
|
||||
ret check_async_replies(status state, std::string_view &response);
|
||||
ret check_urc(status state, std::string_view &response);
|
||||
|
||||
void start_sending(size_t len);
|
||||
void start_receiving(size_t len);
|
||||
@@ -62,13 +64,19 @@ public:
|
||||
return total_len;
|
||||
}
|
||||
|
||||
// Unique link identifier used to target multi-connection AT commands
|
||||
int link_id{s_link_id++};
|
||||
// Shared mutex guarding DTE access across concurrent DCE instances
|
||||
static SemaphoreHandle_t s_dte_mutex;
|
||||
private:
|
||||
static int s_link_id;
|
||||
static constexpr size_t buffer_size = 512;
|
||||
|
||||
bool on_read(char *data, size_t len)
|
||||
{
|
||||
#ifndef CONFIG_EXAMPLE_CUSTOM_TCP_TRANSPORT
|
||||
::send(sock, data, len, 0);
|
||||
printf("sending %d\n", len);
|
||||
#else
|
||||
::memcpy(&buffer[actual_read], data, len);
|
||||
actual_read += len;
|
||||
@@ -97,9 +105,11 @@ private:
|
||||
std::shared_ptr<esp_modem::DTE> &dte;
|
||||
};
|
||||
|
||||
class DCE : public ::esp_modem::GenericModule {
|
||||
using esp_modem::GenericModule::GenericModule;
|
||||
class DCE : public Module {
|
||||
using Module::Module;
|
||||
public:
|
||||
DCE(std::shared_ptr<esp_modem::DTE> dte_arg, const esp_modem_dce_config *config);
|
||||
~DCE();
|
||||
|
||||
/**
|
||||
* @brief Opens network in AT command mode
|
||||
@@ -162,6 +172,10 @@ public:
|
||||
return 0;
|
||||
}
|
||||
at.clear_offsets();
|
||||
// Take DTE mutex before issuing receive on this link
|
||||
ESP_LOGD("TAG", "TAKE RECV %d", at.link_id);
|
||||
xSemaphoreTake(at.s_dte_mutex, portMAX_DELAY);
|
||||
ESP_LOGD("TAG", "TAKEN RECV %d", at.link_id);
|
||||
state = status::RECEIVING;
|
||||
uint64_t data;
|
||||
read(data_ready_fd, &data, sizeof(data));
|
||||
@@ -183,6 +197,10 @@ public:
|
||||
if (!wait_to_idle(timeout_ms)) {
|
||||
return -1;
|
||||
}
|
||||
// Take DTE mutex before issuing send on this link
|
||||
ESP_LOGD("TAG", "TAKE SEND %d", at.link_id);
|
||||
xSemaphoreTake(at.s_dte_mutex, portMAX_DELAY);
|
||||
ESP_LOGD("TAG", "TAKEN SEND %d", at.link_id);
|
||||
state = status::SENDING;
|
||||
memcpy(at.get_buf(), buffer, len_to_send);
|
||||
ESP_LOG_BUFFER_HEXDUMP("dce", at.get_buf(), len, ESP_LOG_VERBOSE);
|
||||
@@ -223,6 +241,14 @@ public:
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
static std::vector<DCE *> dce_list;
|
||||
static bool network_init;
|
||||
static void read_callback(uint8_t *data, size_t len)
|
||||
{
|
||||
for (auto dce : dce_list) {
|
||||
dce->perform_at(data, len);
|
||||
}
|
||||
}
|
||||
private:
|
||||
esp_modem::SignalGroup signal;
|
||||
void close_sock();
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "esp_modem_config.h"
|
||||
#include "cxx_include/esp_modem_api.hpp"
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace sock_dce {
|
||||
|
||||
class Module: public esp_modem::GenericModule {
|
||||
using esp_modem::GenericModule::GenericModule;
|
||||
public:
|
||||
|
||||
esp_modem::command_result sync() override;
|
||||
esp_modem::command_result set_echo(bool on) override;
|
||||
esp_modem::command_result set_pdp_context(esp_modem::PdpContext &pdp) override;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <charconv>
|
||||
#include <sys/socket.h>
|
||||
#include "esp_vfs.h"
|
||||
@@ -14,6 +15,29 @@
|
||||
namespace sock_dce {
|
||||
|
||||
constexpr auto const *TAG = "sock_dce";
|
||||
constexpr auto WAIT_TO_IDLE_TIMEOUT = 5000;
|
||||
|
||||
// Definition of the static member variables
|
||||
std::vector<DCE*> DCE::dce_list{};
|
||||
bool DCE::network_init = false;
|
||||
int Responder::s_link_id = 0;
|
||||
SemaphoreHandle_t Responder::s_dte_mutex{};
|
||||
|
||||
// Constructor - add this DCE instance to the static list
|
||||
DCE::DCE(std::shared_ptr<esp_modem::DTE> dte_arg, const esp_modem_dce_config *config)
|
||||
: Module(std::move(dte_arg), config)
|
||||
{
|
||||
dce_list.push_back(this);
|
||||
}
|
||||
|
||||
// Destructor - remove this DCE instance from the static list
|
||||
DCE::~DCE()
|
||||
{
|
||||
auto it = std::find(dce_list.begin(), dce_list.end(), this);
|
||||
if (it != dce_list.end()) {
|
||||
dce_list.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool DCE::perform_sock()
|
||||
@@ -61,13 +85,26 @@ bool DCE::perform_sock()
|
||||
|
||||
void DCE::perform_at(uint8_t *data, size_t len)
|
||||
{
|
||||
ESP_LOG_BUFFER_HEXDUMP(TAG, data, len, ESP_LOG_VERBOSE);
|
||||
if (state != status::RECEIVING) {
|
||||
std::string_view resp_sv((char *)data, len);
|
||||
at.check_urc(state, resp_sv);
|
||||
if (state == status::IDLE) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Trace incoming AT bytes when handling a response; use DEBUG level
|
||||
ESP_LOG_BUFFER_HEXDUMP(TAG, data, len, ESP_LOG_DEBUG);
|
||||
switch (at.process_data(state, data, len)) {
|
||||
case Responder::ret::OK:
|
||||
// Release DTE access for this link after processing data
|
||||
ESP_LOGD(TAG, "GIVE data %d", at.link_id);
|
||||
xSemaphoreGive(at.s_dte_mutex);
|
||||
state = status::IDLE;
|
||||
signal.set(IDLE);
|
||||
return;
|
||||
case Responder::ret::FAIL:
|
||||
ESP_LOGD(TAG, "GIVE data %d", at.link_id);
|
||||
xSemaphoreGive(at.s_dte_mutex);
|
||||
state = status::FAILED;
|
||||
signal.set(IDLE);
|
||||
return;
|
||||
@@ -82,10 +119,14 @@ void DCE::perform_at(uint8_t *data, size_t len)
|
||||
std::string_view response((char *)data, len);
|
||||
switch (at.check_async_replies(state, response)) {
|
||||
case Responder::ret::OK:
|
||||
ESP_LOGD(TAG, "GIVE command %d", at.link_id);
|
||||
xSemaphoreGive(at.s_dte_mutex);
|
||||
state = status::IDLE;
|
||||
signal.set(IDLE);
|
||||
return;
|
||||
case Responder::ret::FAIL:
|
||||
ESP_LOGD(TAG, "GIVE command %d", at.link_id);
|
||||
xSemaphoreGive(at.s_dte_mutex);
|
||||
state = status::FAILED;
|
||||
signal.set(IDLE);
|
||||
return;
|
||||
@@ -121,7 +162,7 @@ bool DCE::at_to_sock()
|
||||
uint64_t data;
|
||||
read(data_ready_fd, &data, sizeof(data));
|
||||
ESP_LOGD(TAG, "select read: modem data available %" PRIu64, data);
|
||||
if (!signal.wait(IDLE, 1000)) {
|
||||
if (!signal.wait(IDLE, WAIT_TO_IDLE_TIMEOUT)) {
|
||||
ESP_LOGE(TAG, "Failed to get idle");
|
||||
close_sock();
|
||||
return false;
|
||||
@@ -131,6 +172,10 @@ bool DCE::at_to_sock()
|
||||
close_sock();
|
||||
return false;
|
||||
}
|
||||
// Take DTE mutex before issuing receive on this link
|
||||
ESP_LOGD(TAG, "TAKE RECV %d", at.link_id);
|
||||
xSemaphoreTake(at.s_dte_mutex, portMAX_DELAY);
|
||||
ESP_LOGD(TAG, "TAKEN RECV %d", at.link_id);
|
||||
state = status::RECEIVING;
|
||||
at.start_receiving(at.get_buf_len());
|
||||
return true;
|
||||
@@ -139,7 +184,7 @@ bool DCE::at_to_sock()
|
||||
bool DCE::sock_to_at()
|
||||
{
|
||||
ESP_LOGD(TAG, "socket read: data available");
|
||||
if (!signal.wait(IDLE, 1000)) {
|
||||
if (!signal.wait(IDLE, WAIT_TO_IDLE_TIMEOUT)) {
|
||||
ESP_LOGE(TAG, "Failed to get idle");
|
||||
close_sock();
|
||||
return false;
|
||||
@@ -149,6 +194,10 @@ bool DCE::sock_to_at()
|
||||
close_sock();
|
||||
return false;
|
||||
}
|
||||
// Take DTE mutex before issuing send on this link
|
||||
ESP_LOGD(TAG, "TAKE SEND %d", at.link_id);
|
||||
xSemaphoreTake(at.s_dte_mutex, portMAX_DELAY);
|
||||
ESP_LOGD(TAG, "TAKEN SEND %d", at.link_id);
|
||||
state = status::SENDING;
|
||||
int len = ::recv(sock, at.get_buf(), at.get_buf_len(), 0);
|
||||
if (len < 0) {
|
||||
@@ -201,7 +250,7 @@ void DCE::start_listening(int port)
|
||||
}
|
||||
int opt = 1;
|
||||
setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
|
||||
ESP_LOGI(TAG, "Socket created");
|
||||
ESP_LOGD(TAG, "Socket created");
|
||||
struct sockaddr_in addr = { };
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(port);
|
||||
@@ -213,7 +262,7 @@ void DCE::start_listening(int port)
|
||||
ESP_LOGE(TAG, "Socket unable to bind: errno %d", errno);
|
||||
return;
|
||||
}
|
||||
ESP_LOGI(TAG, "Socket bound, port %d", 1883);
|
||||
ESP_LOGD(TAG, "Socket bound, port %d", 1883);
|
||||
err = listen(listen_sock, 1);
|
||||
if (err != 0) {
|
||||
ESP_LOGE(TAG, "Error occurred during listen: errno %d", errno);
|
||||
@@ -224,12 +273,12 @@ void DCE::start_listening(int port)
|
||||
|
||||
bool DCE::connect(std::string host, int port)
|
||||
{
|
||||
dte->on_read(nullptr);
|
||||
tcp_close();
|
||||
dte->on_read([this](uint8_t *data, size_t len) {
|
||||
this->perform_at(data, len);
|
||||
return esp_modem::command_result::TIMEOUT;
|
||||
});
|
||||
data_ready_fd = eventfd(0, EFD_SUPPORT_ISR);
|
||||
assert(data_ready_fd > 0);
|
||||
// Take DTE mutex before starting connect for this link
|
||||
ESP_LOGD(TAG, "TAKE CONNECT %d", at.link_id);
|
||||
xSemaphoreTake(at.s_dte_mutex, portMAX_DELAY);
|
||||
ESP_LOGD(TAG, "TAKEN CONNECT %d", at.link_id);
|
||||
if (!at.start_connecting(host, port)) {
|
||||
ESP_LOGE(TAG, "Unable to start connecting");
|
||||
dte->on_read(nullptr);
|
||||
@@ -241,12 +290,15 @@ bool DCE::connect(std::string host, int port)
|
||||
|
||||
bool DCE::init()
|
||||
{
|
||||
if (network_init) {
|
||||
return true;
|
||||
}
|
||||
network_init = true;
|
||||
Responder::s_dte_mutex = xSemaphoreCreateBinary();
|
||||
xSemaphoreGive(at.s_dte_mutex);
|
||||
esp_vfs_eventfd_config_t config = ESP_VFS_EVENTD_CONFIG_DEFAULT();
|
||||
esp_vfs_eventfd_register(&config);
|
||||
|
||||
data_ready_fd = eventfd(0, EFD_SUPPORT_ISR);
|
||||
assert(data_ready_fd > 0);
|
||||
|
||||
dte->on_read(nullptr);
|
||||
const int retries = 5;
|
||||
int i = 0;
|
||||
@@ -287,6 +339,10 @@ bool DCE::init()
|
||||
esp_modem::Task::Delay(5000);
|
||||
}
|
||||
ESP_LOGI(TAG, "Got IP %s", ip_addr.c_str());
|
||||
dte->on_read([](uint8_t *data, size_t len) {
|
||||
read_callback(data, len);
|
||||
return esp_modem::command_result::TIMEOUT;
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "cxx_include/esp_modem_api.hpp"
|
||||
#include <cxx_include/esp_modem_dce_factory.hpp>
|
||||
#include "sock_commands.hpp"
|
||||
#include "sock_module.hpp"
|
||||
#include <sys/socket.h>
|
||||
|
||||
#pragma once
|
||||
@@ -33,6 +34,7 @@ public:
|
||||
sock(s), data_ready_fd(ready_fd), dte(dte_arg) {}
|
||||
ret process_data(status state, uint8_t *data, size_t len);
|
||||
ret check_async_replies(status state, std::string_view &response);
|
||||
ret check_urc(status state, std::string_view &response);
|
||||
|
||||
void start_sending(size_t len);
|
||||
void start_receiving(size_t len);
|
||||
@@ -62,13 +64,19 @@ public:
|
||||
return total_len;
|
||||
}
|
||||
|
||||
// Unique link identifier used to target multi-connection AT commands
|
||||
int link_id{s_link_id++};
|
||||
// Shared mutex guarding DTE access across concurrent DCE instances
|
||||
static SemaphoreHandle_t s_dte_mutex;
|
||||
private:
|
||||
static int s_link_id;
|
||||
static constexpr size_t buffer_size = 512;
|
||||
|
||||
bool on_read(char *data, size_t len)
|
||||
{
|
||||
#ifndef CONFIG_EXAMPLE_CUSTOM_TCP_TRANSPORT
|
||||
::send(sock, data, len, 0);
|
||||
printf("sending %d\n", len);
|
||||
#else
|
||||
::memcpy(&buffer[actual_read], data, len);
|
||||
actual_read += len;
|
||||
@@ -97,9 +105,11 @@ private:
|
||||
std::shared_ptr<esp_modem::DTE> &dte;
|
||||
};
|
||||
|
||||
class DCE : public ::esp_modem::GenericModule {
|
||||
using esp_modem::GenericModule::GenericModule;
|
||||
class DCE : public Module {
|
||||
using Module::Module;
|
||||
public:
|
||||
DCE(std::shared_ptr<esp_modem::DTE> dte_arg, const esp_modem_dce_config *config);
|
||||
~DCE();
|
||||
|
||||
// --- ESP-MODEM command module starts here ---
|
||||
#include "esp_modem_command_declare_helper.inc"
|
||||
@@ -140,6 +150,10 @@ esp_modem::return_type name(ESP_MODEM_COMMAND_PARAMS(__VA_ARGS__));
|
||||
return 0;
|
||||
}
|
||||
at.clear_offsets();
|
||||
// Take DTE mutex before issuing receive on this link
|
||||
ESP_LOGD("TAG", "TAKE RECV %d", at.link_id);
|
||||
xSemaphoreTake(at.s_dte_mutex, portMAX_DELAY);
|
||||
ESP_LOGD("TAG", "TAKEN RECV %d", at.link_id);
|
||||
state = status::RECEIVING;
|
||||
uint64_t data;
|
||||
read(data_ready_fd, &data, sizeof(data));
|
||||
@@ -162,6 +176,10 @@ esp_modem::return_type name(ESP_MODEM_COMMAND_PARAMS(__VA_ARGS__));
|
||||
if (!wait_to_idle(timeout_ms)) {
|
||||
return -1;
|
||||
}
|
||||
// Take DTE mutex before issuing send on this link
|
||||
ESP_LOGD("TAG", "TAKE SEND %d", at.link_id);
|
||||
xSemaphoreTake(at.s_dte_mutex, portMAX_DELAY);
|
||||
ESP_LOGD("TAG", "TAKEN SEND %d", at.link_id);
|
||||
state = status::SENDING;
|
||||
memcpy(at.get_buf(), buffer, len_to_send);
|
||||
ESP_LOG_BUFFER_HEXDUMP("dce", at.get_buf(), len, ESP_LOG_VERBOSE);
|
||||
@@ -203,6 +221,14 @@ esp_modem::return_type name(ESP_MODEM_COMMAND_PARAMS(__VA_ARGS__));
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
static std::vector<DCE*> dce_list;
|
||||
static bool network_init;
|
||||
static void read_callback(uint8_t *data, size_t len)
|
||||
{
|
||||
for (auto dce : dce_list) {
|
||||
dce->perform_at(data, len);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
esp_modem::SignalGroup signal;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user