mirror of
https://github.com/espressif/esp-protocols.git
synced 2025-07-03 21:56:40 +02:00
Compare commits
67 Commits
websocket-
...
websocket-
Author | SHA1 | Date | |
---|---|---|---|
1750a3fda9 | |||
2a3db45ef1 | |||
fcc61e0929 | |||
14763888ed | |||
a5954dda17 | |||
a65d81c954 | |||
2585565483 | |||
b9c675b0b1 | |||
d4e693e392 | |||
963b32e7b4 | |||
cffe26818b | |||
08a62ccc85 | |||
56fe53279e | |||
5baaf54291 | |||
38de23fb1c | |||
84390eb4d4 | |||
4e844936b7 | |||
21c84bfa8d | |||
438449f58f | |||
a23a0027fa | |||
3f74b4e8c0 | |||
46a6244c37 | |||
7be16bcc88 | |||
1fb02a9a60 | |||
b5be844c92 | |||
5b467cbf5c | |||
f8a776d8a5 | |||
a82c7922aa | |||
d31ad025c8 | |||
4977f96a61 | |||
dcdf31187a | |||
b6bbe47cae | |||
302b46f8e2 | |||
45b1597ac3 | |||
a06de6431b | |||
3b80181d30 | |||
9c54b72e1f | |||
16174470ee | |||
a363beea6f | |||
a8035c21a2 | |||
7eefcf084e | |||
18f845275f | |||
ad27414a64 | |||
a7610395ef | |||
9b7c8755e9 | |||
0d0630ed76 | |||
38a3631a27 | |||
96f4ebd994 | |||
247ca41bb7 | |||
891384cc53 | |||
38ef603296 | |||
312982e4aa | |||
d9d377133e | |||
110536ebb2 | |||
d85311880d | |||
27adbfeb3b | |||
5ba7cfab8e | |||
2f7c58259d | |||
2b092e0db4 | |||
f42c0adfc0 | |||
2782277f3f | |||
3225f40c22 | |||
68ce794098 | |||
1dc4299eb0 | |||
ce7daddc77 | |||
5000a9a20a | |||
2646dcd23a |
12
.github/workflows/asio__build-target-test.yml
vendored
12
.github/workflows/asio__build-target-test.yml
vendored
@ -16,13 +16,13 @@ jobs:
|
||||
idf_ver: ["latest", "release-v5.0", "release-v5.1"]
|
||||
idf_target: ["esp32", "esp32s2"]
|
||||
example: ["asio_chat", "async_request", "socks4", "ssl_client_server", "tcp_echo_server", "udp_echo_server"]
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
env:
|
||||
TEST_DIR: components/asio/examples
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
|
||||
@ -43,7 +43,7 @@ jobs:
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
esptool.py --chip ${{ matrix.idf_target }} merge_bin --fill-flash-size 4MB -o flash_image.bin @flash_args
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: examples_app_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.example }}
|
||||
path: |
|
||||
@ -76,8 +76,8 @@ jobs:
|
||||
steps:
|
||||
- name: Clear repository
|
||||
run: sudo rm -fr $GITHUB_WORKSPACE && mkdir $GITHUB_WORKSPACE
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/download-artifact@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: examples_app_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.example }}
|
||||
path: ${{ env.TEST_DIR }}/${{ matrix.example }}/build
|
||||
@ -93,7 +93,7 @@ jobs:
|
||||
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 }}
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: always()
|
||||
with:
|
||||
name: examples_results_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.example }}
|
||||
|
@ -16,11 +16,11 @@ jobs:
|
||||
idf_ver: ["latest", "release-v5.0"]
|
||||
idf_target: ["esp32"]
|
||||
test: [ { app: ifconfig-basic, path: "components/console_cmd_ifconfig/examples"}]
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Build ${{ matrix.test.app }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
|
||||
|
@ -16,11 +16,11 @@ jobs:
|
||||
idf_ver: ["latest", "release-v5.0"]
|
||||
idf_target: ["esp32"]
|
||||
test: [ { app: ping-basic, path: "components/console_cmd_ping/examples" }]
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Build ${{ matrix.test.app }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
|
||||
|
@ -16,11 +16,11 @@ jobs:
|
||||
idf_ver: ["latest", "release-v5.0"]
|
||||
idf_target: ["esp32"]
|
||||
test: [ { app: wifi-basic, path: "components/console_cmd_wifi/examples" }]
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Build ${{ matrix.test.app }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
|
||||
|
@ -16,11 +16,11 @@ jobs:
|
||||
idf_ver: ["latest", "release-v5.0"]
|
||||
idf_target: ["esp32"]
|
||||
test: [ { app: console_basic, path: "components/console_simple_init/examples" }]
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Build ${{ matrix.test.app }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
|
||||
|
28
.github/workflows/eppp__build.yml
vendored
Normal file
28
.github/workflows/eppp__build.yml
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
name: "eppp_link: build-tests"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, labeled]
|
||||
|
||||
jobs:
|
||||
build_eppp:
|
||||
if: contains(github.event.pull_request.labels.*.name, 'eppp') || github.event_name == 'push'
|
||||
name: Build
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest"]
|
||||
test: [ { app: host, path: "examples/host" }, { app: slave, path: "examples/slave" }, { app: test_app, path: "test/test_app" }]
|
||||
runs-on: ubuntu-20.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v3
|
||||
- name: Build ${{ matrix.test.app }} with IDF-${{ matrix.idf_ver }}
|
||||
shell: bash
|
||||
run: |
|
||||
${IDF_PATH}/install.sh --enable-pytest
|
||||
. ${IDF_PATH}/export.sh
|
||||
python ./ci/build_apps.py ./components/eppp_link/${{matrix.test.path}} -vv --preserve-all
|
@ -14,11 +14,11 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest", "release-v5.1"]
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
- name: Build with IDF-${{ matrix.idf_ver }}
|
||||
shell: bash
|
||||
run: |
|
||||
@ -33,11 +33,11 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest"]
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
- name: Build with IDF-${{ matrix.idf_ver }}
|
||||
shell: bash
|
||||
run: |
|
||||
|
14
.github/workflows/mdns__build-target-test.yml
vendored
14
.github/workflows/mdns__build-target-test.yml
vendored
@ -15,18 +15,18 @@ jobs:
|
||||
matrix:
|
||||
idf_ver: ["latest", "release-v5.0"]
|
||||
test: [ { app: example, path: "examples/query_advertise" }, { app: unit_test, path: "tests/unit_test" }, { app: test_app, path: "tests/test_apps" } ]
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
- name: Build ${{ matrix.test.app }} with IDF-${{ matrix.idf_ver }}
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
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 -m components/mdns/.build-test-rules.yml -d
|
||||
python ./ci/build_apps.py components/mdns/${{ matrix.test.path }} -r default -d
|
||||
# Build specific configs for test targets
|
||||
python ./ci/build_apps.py components/mdns/${{ matrix.test.path }}
|
||||
cd components/mdns/${{ matrix.test.path }}
|
||||
@ -34,7 +34,7 @@ jobs:
|
||||
$GITHUB_WORKSPACE/ci/clean_build_artifacts.sh `pwd`/$dir
|
||||
zip -qur artifacts.zip $dir
|
||||
done
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: mdns_bin_esp32_${{ matrix.idf_ver }}_${{ matrix.test.app }}
|
||||
path: components/mdns/${{ matrix.test.path }}/artifacts.zip
|
||||
@ -58,8 +58,8 @@ jobs:
|
||||
steps:
|
||||
- name: Clear repository
|
||||
run: sudo rm -fr $GITHUB_WORKSPACE && mkdir $GITHUB_WORKSPACE
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/download-artifact@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: mdns_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.test.app }}
|
||||
path: components/mdns/${{ matrix.test.path }}/ci/
|
||||
@ -77,7 +77,7 @@ jobs:
|
||||
mv $dir build
|
||||
python -m pytest --log-cli-level DEBUG --junit-xml=./results_${{ matrix.test.app }}_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${dir#"ci/build_"}.xml --target=${{ matrix.idf_target }}
|
||||
done
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: always()
|
||||
with:
|
||||
name: results_${{ matrix.test.app }}_${{ matrix.idf_target }}_${{ matrix.idf_ver }}.xml
|
||||
|
8
.github/workflows/mdns__host-tests.yml
vendored
8
.github/workflows/mdns__host-tests.yml
vendored
@ -11,12 +11,12 @@ jobs:
|
||||
host_test_mdns:
|
||||
if: contains(github.event.pull_request.labels.*.name, 'mdns') || github.event_name == 'push'
|
||||
name: Host test
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
container: espressif/idf:release-v5.1
|
||||
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@master
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: esp-protocols
|
||||
|
||||
@ -40,11 +40,11 @@ jobs:
|
||||
idf_ver: ["latest"]
|
||||
idf_target: ["esp32"]
|
||||
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@master
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: esp-protocols
|
||||
- name: Install Necessary Libs
|
||||
|
31
.github/workflows/modem__build-host-tests.yml
vendored
31
.github/workflows/modem__build-host-tests.yml
vendored
@ -27,13 +27,19 @@ jobs:
|
||||
example: "simple_cmux_client"
|
||||
warning: "Warning: The smallest app partition is nearly full"
|
||||
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
- name: Check out code (v3) # @v4 failed due to Node 20's requirement, incompatible with older IDF versions
|
||||
if: matrix.idf_ver != 'latest' && matrix.idf_ver < 'release-v5.0'
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
path: protocols
|
||||
- name: Check out code (v4)
|
||||
if: matrix.idf_ver == 'latest' || matrix.idf_ver >= 'release-v5.0'
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: protocols
|
||||
- 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 }}
|
||||
@ -54,11 +60,11 @@ jobs:
|
||||
idf_ver: ["release-v5.0", "release-v5.1", "latest"]
|
||||
test: ["target", "target_ota", "target_iperf"]
|
||||
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: protocols
|
||||
- name: Build ${{ matrix.test }} with IDF-${{ matrix.idf_ver }}
|
||||
@ -76,10 +82,25 @@ jobs:
|
||||
if: contains(github.event.pull_request.labels.*.name, 'modem') || github.event_name == 'push'
|
||||
uses: "./.github/workflows/run-host-tests.yml"
|
||||
with:
|
||||
idf_version: "release-v4.3"
|
||||
idf_version: "latest"
|
||||
app_name: "host_modem_test"
|
||||
app_path: "esp-protocols/components/esp_modem/test/host_test"
|
||||
component_path: "esp-protocols/components/esp_modem"
|
||||
upload_artifacts: true
|
||||
run_executable: true
|
||||
run_coverage: true
|
||||
pre_run_script: "esp-protocols/components/esp_modem/test/host_test/env.sh"
|
||||
publish_unit_test_result: true
|
||||
|
||||
build_linux_example:
|
||||
if: contains(github.event.pull_request.labels.*.name, 'modem') || github.event_name == 'push'
|
||||
uses: "./.github/workflows/run-host-tests.yml"
|
||||
with:
|
||||
idf_version: "latest"
|
||||
app_name: "linux_modem"
|
||||
app_path: "esp-protocols/components/esp_modem/examples/linux_modem"
|
||||
component_path: "esp-protocols/components/esp_modem"
|
||||
upload_artifacts: true
|
||||
run_executable: false
|
||||
run_coverage: false
|
||||
pre_run_script: "esp-protocols/components/esp_modem/test/host_test/env.sh"
|
||||
|
5
.github/workflows/modem__target-test.yml
vendored
5
.github/workflows/modem__target-test.yml
vendored
@ -20,13 +20,13 @@ jobs:
|
||||
- idf_ver: "latest"
|
||||
idf_target: "esp32s2"
|
||||
test: { app: usb_a7670_s2, path: examples/pppos_client }
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
env:
|
||||
TEST_DIR: components/esp_modem/${{ matrix.test.path }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Build esp-modem target tests with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
|
||||
@ -80,4 +80,5 @@ jobs:
|
||||
- name: Run Example Test on target
|
||||
working-directory: ${{ env.TEST_DIR }}
|
||||
run: |
|
||||
python -m pip install -r $GITHUB_WORKSPACE/ci/requirements.txt
|
||||
python -m pytest --log-cli-level DEBUG --target=${{ matrix.idf_target }}
|
||||
|
4
.github/workflows/mqtt_cxx__build.yml
vendored
4
.github/workflows/mqtt_cxx__build.yml
vendored
@ -16,11 +16,11 @@ jobs:
|
||||
idf_ver: ["latest", "release-v5.0"]
|
||||
idf_target: ["esp32"]
|
||||
test: [ { app: mqtt-basic, path: "components/esp_mqtt_cxx/examples" }]
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Build ${{ matrix.test.app }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
|
||||
|
2
.github/workflows/pre_commit_check.yml
vendored
2
.github/workflows/pre_commit_check.yml
vendored
@ -12,7 +12,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.base_ref }}
|
||||
fetch-depth: 20
|
||||
|
3
.github/workflows/publish-docs-component.yml
vendored
3
.github/workflows/publish-docs-component.yml
vendored
@ -20,7 +20,7 @@ jobs:
|
||||
if: github.repository == 'espressif/esp-protocols'
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
fetch-depth: 0
|
||||
@ -92,6 +92,7 @@ jobs:
|
||||
components/esp_modem;
|
||||
components/esp_mqtt_cxx;
|
||||
components/esp_websocket_client;
|
||||
components/eppp_link;
|
||||
components/mdns;
|
||||
components/console_simple_init;
|
||||
components/console_cmd_ping;
|
||||
|
24
.github/workflows/run-host-tests.yml
vendored
24
.github/workflows/run-host-tests.yml
vendored
@ -18,6 +18,12 @@ on:
|
||||
upload_artifacts:
|
||||
type: boolean
|
||||
required: true
|
||||
run_executable:
|
||||
type: boolean
|
||||
required: true
|
||||
run_coverage:
|
||||
type: boolean
|
||||
required: true
|
||||
pre_run_script:
|
||||
type: string
|
||||
required: false
|
||||
@ -28,14 +34,14 @@ on:
|
||||
jobs:
|
||||
build:
|
||||
name: Build App
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
permissions:
|
||||
checks: write
|
||||
contents: write
|
||||
container: espressif/idf:${{inputs.idf_version}}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: esp-protocols
|
||||
- name: Build ${{ inputs.app_name }} with IDF-${{ inputs.idf_version }}
|
||||
@ -51,7 +57,11 @@ jobs:
|
||||
# The sdkconfig.ci.linux specifies Linux as the build target with apropriate settings.
|
||||
cp sdkconfig.ci.linux sdkconfig.defaults
|
||||
idf.py build
|
||||
./build/${{inputs.app_name}}.elf -r junit -o junit.xml
|
||||
if [ "${{ inputs.run_executable}}" == "false" ]; then
|
||||
echo "Executeable wasn't run"
|
||||
exit 0
|
||||
fi
|
||||
./build/${{inputs.app_name}}.elf
|
||||
- name: Publish Unit Test Result
|
||||
uses: EnricoMi/publish-unit-test-result-action@v2
|
||||
if: ${{ inputs.publish_unit_test_result }}
|
||||
@ -59,6 +69,7 @@ jobs:
|
||||
files: ${{inputs.component_path}}/**/*junit.xml
|
||||
- name: Build with Coverage Enabled
|
||||
shell: bash
|
||||
if: ${{ inputs.run_coverage }}
|
||||
run: |
|
||||
component=$(basename ${{ inputs.component_path }})
|
||||
if [ -f "${{ inputs.pre_run_script }}" ]; then
|
||||
@ -74,6 +85,7 @@ jobs:
|
||||
./build/${{inputs.app_name}}.elf
|
||||
- name: Run Coverage
|
||||
shell: bash
|
||||
if: ${{ inputs.run_coverage }}
|
||||
run: |
|
||||
apt-get update && apt-get install -y python3-pip rsync
|
||||
python -m pip install gcovr
|
||||
@ -86,6 +98,7 @@ jobs:
|
||||
cp index.html ${{inputs.app_name}}_coverage_report
|
||||
cp -rf ${{inputs.app_name}}_coverage_report ${{inputs.app_name}}_coverage.xml $GITHUB_WORKSPACE
|
||||
- name: Code Coverage Summary Report
|
||||
if: ${{ inputs.run_coverage }}
|
||||
uses: irongut/CodeCoverageSummary@v1.3.0
|
||||
with:
|
||||
filename: esp-protocols/**/${{inputs.app_name}}_coverage.xml
|
||||
@ -99,9 +112,10 @@ jobs:
|
||||
thresholds: '60 80'
|
||||
- name: Write to Job Summary
|
||||
run: cat code-coverage-results.md >> $GITHUB_STEP_SUMMARY
|
||||
if: ${{ inputs.run_coverage }}
|
||||
- name: Upload files to artifacts for run-target job
|
||||
uses: actions/upload-artifact@v3
|
||||
if: ${{inputs.upload_artifacts}}
|
||||
uses: actions/upload-artifact@v4
|
||||
if: ${{ inputs.run_coverage }}
|
||||
with:
|
||||
name: ${{inputs.app_name}}_coverage_report
|
||||
path: |
|
||||
|
@ -17,4 +17,6 @@ jobs:
|
||||
app_name: "websocket"
|
||||
app_path: "esp-protocols/components/esp_websocket_client/examples/linux"
|
||||
component_path: "esp-protocols/components/esp_websocket_client"
|
||||
run_executable: true
|
||||
upload_artifacts: true
|
||||
run_coverage: true
|
||||
|
@ -15,13 +15,13 @@ jobs:
|
||||
matrix:
|
||||
idf_ver: ["release-v5.0", "release-v5.1", "latest"]
|
||||
test: [ { app: example, path: "examples/target" }, { app: unit_test, path: "test" } ]
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
env:
|
||||
TEST_DIR: components/esp_websocket_client/${{ matrix.test.path }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
|
||||
@ -35,7 +35,7 @@ jobs:
|
||||
$GITHUB_WORKSPACE/ci/clean_build_artifacts.sh `pwd`/$dir
|
||||
zip -qur artifacts.zip $dir
|
||||
done
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: websocket_bin_esp32_${{ matrix.idf_ver }}_${{ matrix.test.app }}
|
||||
path: ${{ env.TEST_DIR }}/artifacts.zip
|
||||
@ -60,8 +60,8 @@ jobs:
|
||||
env:
|
||||
TEST_DIR: components/esp_websocket_client/${{ matrix.test.path }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/download-artifact@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: websocket_bin_esp32_${{ matrix.idf_ver }}_${{ matrix.test.app }}
|
||||
path: ${{ env.TEST_DIR }}/ci/
|
||||
@ -79,7 +79,7 @@ jobs:
|
||||
mv $dir build
|
||||
python -m pytest --log-cli-level DEBUG --junit-xml=./results_${{ matrix.test.app }}_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${dir#"ci/build_"}.xml --target=${{ matrix.idf_target }}
|
||||
done
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: always()
|
||||
with:
|
||||
name: results_${{ matrix.test.app }}_${{ matrix.idf_target }}_${{ matrix.idf_ver }}.xml
|
||||
|
@ -61,8 +61,8 @@ repos:
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: commit message scopes
|
||||
name: "commit message must be scoped with: mdns, modem, websocket, asio, mqtt_cxx, console, common"
|
||||
entry: '\A(?!(feat|fix|ci|bump|test|docs)\((mdns|modem|common|console|websocket|asio|mqtt_cxx|examples)\)\:)'
|
||||
name: "commit message must be scoped with: mdns, modem, websocket, asio, mqtt_cxx, console, common, eppp"
|
||||
entry: '\A(?!(feat|fix|ci|bump|test|docs)\((mdns|modem|common|console|websocket|asio|mqtt_cxx|examples|eppp)\)\:)'
|
||||
language: pygrep
|
||||
args: [--multiline]
|
||||
stages: [commit-msg]
|
||||
|
@ -49,3 +49,7 @@ Please refer to instructions in [ESP-IDF](https://github.com/espressif/esp-idf)
|
||||
### console_cmd_wifi
|
||||
|
||||
* Brief introduction [README](components/console_cmd_wifi/README.md)
|
||||
|
||||
### ESP PPP Link (eppp)
|
||||
|
||||
* Brief introduction [README](components/eppp_link/README.md)
|
||||
|
8
components/eppp_link/.cz.yaml
Normal file
8
components/eppp_link/.cz.yaml
Normal file
@ -0,0 +1,8 @@
|
||||
---
|
||||
commitizen:
|
||||
bump_message: 'bump(eppp): $current_version -> $new_version'
|
||||
pre_bump_hooks: python ../../ci/changelog.py eppp_link
|
||||
tag_format: eppp-v$version
|
||||
version: 0.0.1
|
||||
version_files:
|
||||
- idf_component.yml
|
10
components/eppp_link/CHANGELOG.md
Normal file
10
components/eppp_link/CHANGELOG.md
Normal file
@ -0,0 +1,10 @@
|
||||
# Changelog
|
||||
|
||||
## [0.0.1](https://github.com/espressif/esp-protocols/commits/eppp-v0.0.1)
|
||||
|
||||
### Features
|
||||
|
||||
- Added CI job to build examples and tests ([8686977](https://github.com/espressif/esp-protocols/commit/8686977))
|
||||
- Added support for SPI transport ([18f8452](https://github.com/espressif/esp-protocols/commit/18f8452))
|
||||
- Added support for UART transport ([ad27414](https://github.com/espressif/esp-protocols/commit/ad27414))
|
||||
- Introduced ESP-PPP-Link component ([a761039](https://github.com/espressif/esp-protocols/commit/a761039))
|
3
components/eppp_link/CMakeLists.txt
Normal file
3
components/eppp_link/CMakeLists.txt
Normal file
@ -0,0 +1,3 @@
|
||||
idf_component_register(SRCS "eppp_link.c"
|
||||
INCLUDE_DIRS "include"
|
||||
PRIV_REQUIRES esp_netif esp_driver_spi esp_driver_gpio esp_timer driver)
|
35
components/eppp_link/Kconfig
Normal file
35
components/eppp_link/Kconfig
Normal file
@ -0,0 +1,35 @@
|
||||
menu "eppp_link"
|
||||
|
||||
choice EPPP_LINK_DEVICE
|
||||
prompt "Choose PPP device"
|
||||
default EPPP_LINK_DEVICE_UART
|
||||
help
|
||||
Select which peripheral to use for PPP link
|
||||
|
||||
config EPPP_LINK_DEVICE_UART
|
||||
bool "UART"
|
||||
help
|
||||
Use UART.
|
||||
|
||||
config EPPP_LINK_DEVICE_SPI
|
||||
bool "SPI"
|
||||
help
|
||||
Use SPI.
|
||||
endchoice
|
||||
|
||||
config EPPP_LINK_CONN_MAX_RETRY
|
||||
int "Maximum retry"
|
||||
default 6
|
||||
help
|
||||
Set the Maximum retry to infinitely avoid reconnecting
|
||||
This is used only with the simplified API (eppp_connect()
|
||||
and eppp_listen())
|
||||
|
||||
config EPPP_LINK_PACKET_QUEUE_SIZE
|
||||
int "Packet queue size"
|
||||
default 64
|
||||
help
|
||||
Size of the Tx packet queue.
|
||||
You can decrease the number for slower bit rates.
|
||||
|
||||
endmenu
|
202
components/eppp_link/LICENSE
Normal file
202
components/eppp_link/LICENSE
Normal file
@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
52
components/eppp_link/README.md
Normal file
52
components/eppp_link/README.md
Normal file
@ -0,0 +1,52 @@
|
||||
# ESP PPP Link component (eppp_link)
|
||||
|
||||
The component provides a general purpose connectivity engine between two microcontrollers, one acting as PPP server (slave), the other one as PPP client (host).
|
||||
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 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
|
||||
|
||||
## Typical application
|
||||
|
||||
Using this component we can construct a WiFi connectivity gateway on PPP channel. The below diagram depicts an application where
|
||||
PPP server is running on a WiFi capable chip with NAPT module translating packets between WiFi and PPPoS interface.
|
||||
We usually call this node a SLAVE microcontroller. The "HOST" microcontroller runs PPP client and connects only to the serial line,
|
||||
brings in the WiFi connectivity from the "SLAVE" microcontroller.
|
||||
|
||||
```
|
||||
SLAVE micro HOST micro
|
||||
\|/ +----------------+ +----------------+
|
||||
| | | serial line | |
|
||||
+---+ WiFi NAT PPPoS |======== UART / SPI =======| PPPoS client |
|
||||
| (server)| | |
|
||||
+----------------+ +----------------+
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### Client
|
||||
|
||||
* `eppp_connect()` -- Simplified API. Provides the initialization, starts the task and blocks until we're connected
|
||||
|
||||
### Server
|
||||
|
||||
* `eppp_listen()` -- Simplified API. Provides the initialization, starts the task and blocks until the client connects
|
||||
|
||||
### Manual actions
|
||||
|
||||
* `eppp_init()` -- Initializes one endpoint (client/server).
|
||||
* `eppp_deinit()` -- Destroys the endpoint
|
||||
* `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)
|
||||
|
||||
## Throughput
|
||||
|
||||
Tested with WiFi-NAPT example, no IRAM optimizations
|
||||
|
||||
### UART @ 3Mbauds
|
||||
|
||||
* TCP - 2Mbits/s
|
||||
* UDP - 2Mbits/s
|
||||
|
||||
### SPI @ 20MHz
|
||||
|
||||
* TCP - 6Mbits/s
|
||||
* UDP - 10Mbits/s
|
820
components/eppp_link/eppp_link.c
Normal file
820
components/eppp_link/eppp_link.c
Normal file
@ -0,0 +1,820 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_netif.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_netif_ppp.h"
|
||||
#include "eppp_link.h"
|
||||
|
||||
#if CONFIG_EPPP_LINK_DEVICE_SPI
|
||||
#include "driver/spi_master.h"
|
||||
#include "driver/spi_slave.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_timer.h"
|
||||
#include "esp_rom_crc.h"
|
||||
#elif CONFIG_EPPP_LINK_DEVICE_UART
|
||||
#include "driver/uart.h"
|
||||
#endif
|
||||
|
||||
static const int GOT_IPV4 = BIT0;
|
||||
static const int CONNECTION_FAILED = BIT1;
|
||||
#define CONNECT_BITS (GOT_IPV4|CONNECTION_FAILED)
|
||||
|
||||
static EventGroupHandle_t s_event_group = NULL;
|
||||
static const char *TAG = "eppp_link";
|
||||
static int s_retry_num = 0;
|
||||
static int s_eppp_netif_count = 0; // used as a suffix for the netif key
|
||||
|
||||
|
||||
struct packet {
|
||||
size_t len;
|
||||
uint8_t *data;
|
||||
};
|
||||
|
||||
#if CONFIG_EPPP_LINK_DEVICE_SPI
|
||||
#define MAX_PAYLOAD 1500
|
||||
#define MIN_TRIGGER_US 20
|
||||
#define SPI_HEADER_MAGIC 0x1234
|
||||
|
||||
static void timer_callback(void *arg);
|
||||
|
||||
struct header {
|
||||
uint16_t magic;
|
||||
uint16_t size;
|
||||
uint16_t next_size;
|
||||
uint16_t check;
|
||||
} __attribute__((packed));
|
||||
|
||||
enum blocked_status {
|
||||
NONE,
|
||||
MASTER_BLOCKED,
|
||||
MASTER_WANTS_READ,
|
||||
SLAVE_BLOCKED,
|
||||
SLAVE_WANTS_WRITE,
|
||||
};
|
||||
|
||||
#endif // CONFIG_EPPP_LINK_DEVICE_SPI
|
||||
|
||||
struct eppp_handle {
|
||||
#if CONFIG_EPPP_LINK_DEVICE_SPI
|
||||
QueueHandle_t out_queue;
|
||||
QueueHandle_t ready_semaphore;
|
||||
spi_device_handle_t spi_device;
|
||||
spi_host_device_t spi_host;
|
||||
int gpio_intr;
|
||||
uint16_t next_size;
|
||||
uint16_t transaction_size;
|
||||
struct packet outbound;
|
||||
enum blocked_status blocked;
|
||||
uint32_t slave_last_edge;
|
||||
esp_timer_handle_t timer;
|
||||
#elif CONFIG_EPPP_LINK_DEVICE_UART
|
||||
QueueHandle_t uart_event_queue;
|
||||
uart_port_t uart_port;
|
||||
#endif
|
||||
esp_netif_t *netif;
|
||||
eppp_type_t role;
|
||||
bool stop;
|
||||
bool exited;
|
||||
bool netif_stop;
|
||||
};
|
||||
|
||||
|
||||
static esp_err_t transmit(void *h, void *buffer, size_t len)
|
||||
{
|
||||
struct eppp_handle *handle = h;
|
||||
#if CONFIG_EPPP_LINK_DEVICE_SPI
|
||||
struct packet buf = { };
|
||||
uint8_t *current_buffer = buffer;
|
||||
size_t remaining = len;
|
||||
do { // TODO(IDF-9194): Refactor this loop to allocate only once and perform
|
||||
// fragmentation after receiving from the queue (applicable only if MTU > MAX_PAYLOAD)
|
||||
size_t batch = remaining > MAX_PAYLOAD ? MAX_PAYLOAD : remaining;
|
||||
buf.data = malloc(batch);
|
||||
if (buf.data == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to allocate packet");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
buf.len = batch;
|
||||
remaining -= batch;
|
||||
memcpy(buf.data, current_buffer, batch);
|
||||
current_buffer += batch;
|
||||
BaseType_t ret = xQueueSend(handle->out_queue, &buf, 0);
|
||||
if (ret != pdTRUE) {
|
||||
ESP_LOGE(TAG, "Failed to queue packet to slave!");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
} while (remaining > 0);
|
||||
|
||||
if (handle->role == EPPP_SERVER && handle->blocked == SLAVE_BLOCKED) {
|
||||
uint32_t now = esp_timer_get_time();
|
||||
uint32_t diff = now - handle->slave_last_edge;
|
||||
if (diff < MIN_TRIGGER_US) {
|
||||
esp_rom_delay_us(MIN_TRIGGER_US - diff);
|
||||
}
|
||||
gpio_set_level(handle->gpio_intr, 0);
|
||||
}
|
||||
|
||||
#elif CONFIG_EPPP_LINK_DEVICE_UART
|
||||
ESP_LOG_BUFFER_HEXDUMP("ppp_uart_send", buffer, len, ESP_LOG_VERBOSE);
|
||||
uart_write_bytes(handle->uart_port, buffer, len);
|
||||
#endif
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void netif_deinit(esp_netif_t *netif)
|
||||
{
|
||||
if (netif == NULL) {
|
||||
return;
|
||||
}
|
||||
struct eppp_handle *h = esp_netif_get_io_driver(netif);
|
||||
if (h == NULL) {
|
||||
return;
|
||||
}
|
||||
#if CONFIG_EPPP_LINK_DEVICE_SPI
|
||||
struct packet buf = { };
|
||||
while (xQueueReceive(h->out_queue, &buf, 0) == pdTRUE) {
|
||||
if (buf.len > 0) {
|
||||
free(buf.data);
|
||||
}
|
||||
}
|
||||
vQueueDelete(h->out_queue);
|
||||
if (h->role == EPPP_CLIENT) {
|
||||
vSemaphoreDelete(h->ready_semaphore);
|
||||
}
|
||||
#endif
|
||||
free(h);
|
||||
esp_netif_destroy(netif);
|
||||
if (s_eppp_netif_count > 0) {
|
||||
s_eppp_netif_count--;
|
||||
}
|
||||
}
|
||||
|
||||
static esp_netif_t *netif_init(eppp_type_t role)
|
||||
{
|
||||
if (s_eppp_netif_count > 9) { // Limit to max 10 netifs, since we use "EPPPx" as the unique key (where x is 0-9)
|
||||
ESP_LOGE(TAG, "Cannot create more than 10 instances");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Create the object first
|
||||
struct eppp_handle *h = calloc(1, sizeof(struct eppp_handle));
|
||||
if (!h) {
|
||||
ESP_LOGE(TAG, "Failed to allocate eppp_handle");
|
||||
return NULL;
|
||||
}
|
||||
h->role = role;
|
||||
#if CONFIG_EPPP_LINK_DEVICE_SPI
|
||||
h->out_queue = xQueueCreate(CONFIG_EPPP_LINK_PACKET_QUEUE_SIZE, sizeof(struct packet));
|
||||
if (!h->out_queue) {
|
||||
ESP_LOGE(TAG, "Failed to create the packet queue");
|
||||
free(h);
|
||||
return NULL;
|
||||
}
|
||||
if (role == EPPP_CLIENT) {
|
||||
h->ready_semaphore = xSemaphoreCreateBinary();
|
||||
if (!h->ready_semaphore) {
|
||||
ESP_LOGE(TAG, "Failed to create the packet queue");
|
||||
vQueueDelete(h->out_queue);
|
||||
free(h);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
h->transaction_size = 0;
|
||||
h->outbound.data = NULL;
|
||||
h->outbound.len = 0;
|
||||
if (role == EPPP_SERVER) {
|
||||
esp_timer_create_args_t args = {
|
||||
.callback = &timer_callback,
|
||||
.arg = h,
|
||||
.name = "timer"
|
||||
};
|
||||
if (esp_timer_create(&args, &h->timer) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to create the packet queue");
|
||||
vQueueDelete(h->out_queue);
|
||||
vSemaphoreDelete(h->ready_semaphore);
|
||||
free(h);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
esp_netif_driver_ifconfig_t driver_cfg = {
|
||||
.handle = h,
|
||||
.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();
|
||||
char if_key[] = "EPPP0"; // netif key needs to be unique
|
||||
if_key[sizeof(if_key) - 2 /* 2 = two chars before the terminator */ ] += s_eppp_netif_count++;
|
||||
base_netif_cfg.if_key = if_key;
|
||||
if (role == EPPP_CLIENT) {
|
||||
base_netif_cfg.if_desc = "pppos_client";
|
||||
} else {
|
||||
base_netif_cfg.if_desc = "pppos_server";
|
||||
}
|
||||
esp_netif_config_t netif_ppp_config = { .base = &base_netif_cfg,
|
||||
.driver = ppp_driver_cfg,
|
||||
.stack = ESP_NETIF_NETSTACK_DEFAULT_PPP
|
||||
};
|
||||
|
||||
esp_netif_t *netif = esp_netif_new(&netif_ppp_config);
|
||||
if (!netif) {
|
||||
ESP_LOGE(TAG, "Failed to create esp_netif");
|
||||
#if CONFIG_EPPP_LINK_DEVICE_SPI
|
||||
vQueueDelete(h->out_queue);
|
||||
if (h->ready_semaphore) {
|
||||
vSemaphoreDelete(h->ready_semaphore);
|
||||
}
|
||||
#endif
|
||||
free(h);
|
||||
return NULL;
|
||||
}
|
||||
return netif;
|
||||
|
||||
}
|
||||
|
||||
esp_err_t eppp_netif_stop(esp_netif_t *netif, int stop_timeout_ms)
|
||||
{
|
||||
esp_netif_action_disconnected(netif, 0, 0, 0);
|
||||
esp_netif_action_stop(netif, 0, 0, 0);
|
||||
struct eppp_handle *h = esp_netif_get_io_driver(netif);
|
||||
for (int wait = 0; wait < 100; wait++) {
|
||||
vTaskDelay(pdMS_TO_TICKS(stop_timeout_ms) / 100);
|
||||
if (h->netif_stop) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!h->netif_stop) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t eppp_netif_start(esp_netif_t *netif)
|
||||
{
|
||||
esp_netif_action_start(netif, 0, 0, 0);
|
||||
esp_netif_action_connected(netif, 0, 0, 0);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static int get_netif_num(esp_netif_t *netif)
|
||||
{
|
||||
if (netif == NULL) {
|
||||
return -1;
|
||||
}
|
||||
const char *ifkey = esp_netif_get_ifkey(netif);
|
||||
if (strstr(ifkey, "EPPP") == NULL) {
|
||||
return -1; // not our netif
|
||||
}
|
||||
int netif_cnt = ifkey[4] - '0';
|
||||
if (netif_cnt < 0 || netif_cnt > 9) {
|
||||
ESP_LOGE(TAG, "Unexpected netif key %s", ifkey);
|
||||
return -1;
|
||||
}
|
||||
return netif_cnt;
|
||||
}
|
||||
|
||||
static void on_ppp_event(void *arg, esp_event_base_t base, int32_t event_id, void *data)
|
||||
{
|
||||
esp_netif_t **netif = data;
|
||||
ESP_LOGD(TAG, "PPP status event: %" PRId32, event_id);
|
||||
if (base == NETIF_PPP_STATUS && event_id == NETIF_PPP_ERRORUSER) {
|
||||
ESP_LOGI(TAG, "Disconnected %d", get_netif_num(*netif));
|
||||
struct eppp_handle *h = esp_netif_get_io_driver(*netif);
|
||||
h->netif_stop = true;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
int netif_cnt = get_netif_num(netif);
|
||||
if (netif_cnt < 0) {
|
||||
return;
|
||||
}
|
||||
if (event_id == IP_EVENT_PPP_GOT_IP) {
|
||||
ESP_LOGI(TAG, "Got IPv4 event: Interface \"%s(%s)\" address: " IPSTR, esp_netif_get_desc(netif),
|
||||
esp_netif_get_ifkey(netif), IP2STR(&event->ip_info.ip));
|
||||
xEventGroupSetBits(s_event_group, GOT_IPV4 << (netif_cnt * 2));
|
||||
} else if (event_id == IP_EVENT_PPP_LOST_IP) {
|
||||
ESP_LOGI(TAG, "Disconnected");
|
||||
s_retry_num++;
|
||||
if (s_retry_num > CONFIG_EPPP_LINK_CONN_MAX_RETRY) {
|
||||
ESP_LOGE(TAG, "PPP Connection failed %d times, stop reconnecting.", s_retry_num);
|
||||
xEventGroupSetBits(s_event_group, CONNECTION_FAILED << (netif_cnt * 2));
|
||||
} else {
|
||||
ESP_LOGI(TAG, "PPP Connection failed %d times, try to reconnect.", s_retry_num);
|
||||
eppp_netif_start(netif);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if CONFIG_EPPP_LINK_DEVICE_SPI
|
||||
|
||||
#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 */
|
||||
|
||||
static void IRAM_ATTR timer_callback(void *arg)
|
||||
{
|
||||
struct eppp_handle *h = arg;
|
||||
if (h->blocked == SLAVE_WANTS_WRITE) {
|
||||
gpio_set_level(h->gpio_intr, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void IRAM_ATTR gpio_isr_handler(void *arg)
|
||||
{
|
||||
static uint32_t s_last_time;
|
||||
uint32_t now = esp_timer_get_time();
|
||||
uint32_t diff = now - s_last_time;
|
||||
if (diff < MIN_TRIGGER_US) { // debounce
|
||||
return;
|
||||
}
|
||||
s_last_time = now;
|
||||
struct eppp_handle *h = arg;
|
||||
BaseType_t yield = false;
|
||||
|
||||
// Positive edge means SPI slave prepared the data
|
||||
if (gpio_get_level(h->gpio_intr) == 1) {
|
||||
xSemaphoreGiveFromISR(h->ready_semaphore, &yield);
|
||||
if (yield) {
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Negative edge (when master blocked) means that slave wants to transmit
|
||||
if (h->blocked == MASTER_BLOCKED) {
|
||||
struct packet buf = { .data = NULL, .len = -1 };
|
||||
xQueueSendFromISR(h->out_queue, &buf, &yield);
|
||||
if (yield) {
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static esp_err_t deinit_master(esp_netif_t *netif)
|
||||
{
|
||||
struct eppp_handle *h = esp_netif_get_io_driver(netif);
|
||||
ESP_RETURN_ON_ERROR(spi_bus_remove_device(h->spi_device), TAG, "Failed to remove SPI bus");
|
||||
ESP_RETURN_ON_ERROR(spi_bus_free(h->spi_host), TAG, "Failed to free SPI bus");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t init_master(struct eppp_config_spi_s *config, esp_netif_t *netif)
|
||||
{
|
||||
struct eppp_handle *h = esp_netif_get_io_driver(netif);
|
||||
h->spi_host = config->host;
|
||||
h->gpio_intr = config->intr;
|
||||
spi_bus_config_t bus_cfg = {};
|
||||
bus_cfg.mosi_io_num = config->mosi;
|
||||
bus_cfg.miso_io_num = config->miso;
|
||||
bus_cfg.sclk_io_num = config->sclk;
|
||||
bus_cfg.quadwp_io_num = -1;
|
||||
bus_cfg.quadhd_io_num = -1;
|
||||
bus_cfg.max_transfer_sz = TRANSFER_SIZE;
|
||||
bus_cfg.flags = 0;
|
||||
bus_cfg.intr_flags = 0;
|
||||
|
||||
// TODO: Init and deinit SPI bus separately (per Kconfig?)
|
||||
if (spi_bus_initialize(config->host, &bus_cfg, SPI_DMA_CH_AUTO) != ESP_OK) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
spi_device_interface_config_t dev_cfg = {};
|
||||
dev_cfg.clock_speed_hz = config->freq;
|
||||
dev_cfg.mode = 0;
|
||||
dev_cfg.spics_io_num = config->cs;
|
||||
dev_cfg.cs_ena_pretrans = config->cs_ena_pretrans;
|
||||
dev_cfg.cs_ena_posttrans = config->cs_ena_posttrans;
|
||||
dev_cfg.duty_cycle_pos = 128;
|
||||
dev_cfg.input_delay_ns = config->input_delay_ns;
|
||||
dev_cfg.pre_cb = NULL;
|
||||
dev_cfg.post_cb = NULL;
|
||||
dev_cfg.queue_size = 3;
|
||||
|
||||
if (spi_bus_add_device(config->host, &dev_cfg, &h->spi_device) != ESP_OK) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
//GPIO config for the handshake line.
|
||||
gpio_config_t io_conf = {
|
||||
.intr_type = GPIO_INTR_ANYEDGE,
|
||||
.mode = GPIO_MODE_INPUT,
|
||||
.pull_up_en = 1,
|
||||
.pin_bit_mask = BIT64(config->intr),
|
||||
};
|
||||
|
||||
gpio_config(&io_conf);
|
||||
gpio_install_isr_service(0);
|
||||
gpio_set_intr_type(config->intr, GPIO_INTR_ANYEDGE);
|
||||
gpio_isr_handler_add(config->intr, gpio_isr_handler, esp_netif_get_io_driver(netif));
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void post_setup(spi_slave_transaction_t *trans)
|
||||
{
|
||||
struct eppp_handle *h = trans->user;
|
||||
h->slave_last_edge = esp_timer_get_time();
|
||||
gpio_set_level(h->gpio_intr, 1);
|
||||
if (h->transaction_size == 0) { // If no transaction planned:
|
||||
if (h->outbound.len == 0) { // we're blocked if we don't have any data
|
||||
h->blocked = SLAVE_BLOCKED;
|
||||
} else {
|
||||
h->blocked = SLAVE_WANTS_WRITE; // we notify the master that we want to write
|
||||
esp_timer_start_once(h->timer, MIN_TRIGGER_US);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void post_trans(spi_slave_transaction_t *trans)
|
||||
{
|
||||
struct eppp_handle *h = trans->user;
|
||||
h->blocked = NONE;
|
||||
gpio_set_level(h->gpio_intr, 0);
|
||||
}
|
||||
|
||||
static esp_err_t deinit_slave(esp_netif_t *netif)
|
||||
{
|
||||
struct eppp_handle *h = esp_netif_get_io_driver(netif);
|
||||
ESP_RETURN_ON_ERROR(spi_slave_free(h->spi_host), TAG, "Failed to free SPI slave host");
|
||||
ESP_RETURN_ON_ERROR(spi_bus_remove_device(h->spi_device), TAG, "Failed to remove SPI device");
|
||||
ESP_RETURN_ON_ERROR(spi_bus_free(h->spi_host), TAG, "Failed to free SPI bus");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t init_slave(struct eppp_config_spi_s *config, esp_netif_t *netif)
|
||||
{
|
||||
struct eppp_handle *h = esp_netif_get_io_driver(netif);
|
||||
h->spi_host = config->host;
|
||||
h->gpio_intr = config->intr;
|
||||
spi_bus_config_t bus_cfg = {};
|
||||
bus_cfg.mosi_io_num = config->mosi;
|
||||
bus_cfg.miso_io_num = config->miso;
|
||||
bus_cfg.sclk_io_num = config->sclk;
|
||||
bus_cfg.quadwp_io_num = -1;
|
||||
bus_cfg.quadhd_io_num = -1;
|
||||
bus_cfg.flags = 0;
|
||||
bus_cfg.intr_flags = 0;
|
||||
|
||||
//Configuration for the SPI slave interface
|
||||
spi_slave_interface_config_t slvcfg = {
|
||||
.mode = 0,
|
||||
.spics_io_num = config->cs,
|
||||
.queue_size = 3,
|
||||
.flags = 0,
|
||||
.post_setup_cb = post_setup,
|
||||
.post_trans_cb = post_trans,
|
||||
};
|
||||
|
||||
//Configuration for the handshake line
|
||||
gpio_config_t io_conf = {
|
||||
.intr_type = GPIO_INTR_DISABLE,
|
||||
.mode = GPIO_MODE_OUTPUT,
|
||||
.pin_bit_mask = BIT64(config->intr),
|
||||
};
|
||||
|
||||
gpio_config(&io_conf);
|
||||
gpio_set_pull_mode(config->mosi, GPIO_PULLUP_ONLY);
|
||||
gpio_set_pull_mode(config->sclk, GPIO_PULLUP_ONLY);
|
||||
gpio_set_pull_mode(config->cs, GPIO_PULLUP_ONLY);
|
||||
|
||||
//Initialize SPI slave interface
|
||||
if (spi_slave_initialize(config->host, &bus_cfg, &slvcfg, SPI_DMA_CH_AUTO) != ESP_OK) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
typedef esp_err_t (*perform_transaction_t)(struct eppp_handle *h, size_t len, const void *tx_buffer, void *rx_buffer);
|
||||
|
||||
static esp_err_t perform_transaction_master(struct eppp_handle *h, size_t len, const void *tx_buffer, void *rx_buffer)
|
||||
{
|
||||
spi_transaction_t t = {};
|
||||
t.length = len * 8;
|
||||
t.tx_buffer = tx_buffer;
|
||||
t.rx_buffer = rx_buffer;
|
||||
return spi_device_transmit(h->spi_device, &t);
|
||||
}
|
||||
|
||||
static esp_err_t perform_transaction_slave(struct eppp_handle *h, size_t len, const void *tx_buffer, void *rx_buffer)
|
||||
{
|
||||
spi_slave_transaction_t t = {};
|
||||
t.user = h;
|
||||
t.length = len * 8;
|
||||
t.tx_buffer = tx_buffer;
|
||||
t.rx_buffer = rx_buffer;
|
||||
return spi_slave_transmit(h->spi_host, &t, portMAX_DELAY);
|
||||
}
|
||||
|
||||
esp_err_t eppp_perform(esp_netif_t *netif)
|
||||
{
|
||||
static WORD_ALIGNED_ATTR uint8_t out_buf[TRANSFER_SIZE] = {};
|
||||
static WORD_ALIGNED_ATTR uint8_t in_buf[TRANSFER_SIZE] = {};
|
||||
|
||||
struct eppp_handle *h = esp_netif_get_io_driver(netif);
|
||||
|
||||
// Perform transaction for master and slave
|
||||
const perform_transaction_t perform_transaction = h->role == EPPP_CLIENT ? perform_transaction_master : perform_transaction_slave;
|
||||
|
||||
if (h->stop) {
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
|
||||
BaseType_t tx_queue_stat;
|
||||
bool allow_test_tx = false;
|
||||
uint16_t next_tx_size = 0;
|
||||
if (h->role == EPPP_CLIENT) {
|
||||
// SPI MASTER only code
|
||||
if (xSemaphoreTake(h->ready_semaphore, pdMS_TO_TICKS(1000)) != pdTRUE) {
|
||||
// slave might not be ready, but maybe we just missed an interrupt
|
||||
allow_test_tx = true;
|
||||
}
|
||||
if (h->outbound.len == 0 && h->transaction_size == 0 && h->blocked == NONE) {
|
||||
h->blocked = MASTER_BLOCKED;
|
||||
xQueueReceive(h->out_queue, &h->outbound, portMAX_DELAY);
|
||||
h->blocked = NONE;
|
||||
if (h->outbound.len == -1) {
|
||||
h->outbound.len = 0;
|
||||
h->blocked = MASTER_WANTS_READ;
|
||||
}
|
||||
} else if (h->blocked == MASTER_WANTS_READ) {
|
||||
h->blocked = NONE;
|
||||
}
|
||||
}
|
||||
struct header *head = (void *)out_buf;
|
||||
if (h->outbound.len <= h->transaction_size && allow_test_tx == false) {
|
||||
// sending outbound
|
||||
head->size = h->outbound.len;
|
||||
if (h->outbound.len > 0) {
|
||||
memcpy(out_buf + sizeof(struct header), h->outbound.data, h->outbound.len);
|
||||
free(h->outbound.data);
|
||||
ESP_LOG_BUFFER_HEXDUMP(TAG, out_buf + sizeof(struct header), head->size, ESP_LOG_VERBOSE);
|
||||
h->outbound.data = NULL;
|
||||
h->outbound.len = 0;
|
||||
}
|
||||
do {
|
||||
tx_queue_stat = xQueueReceive(h->out_queue, &h->outbound, 0);
|
||||
} while (tx_queue_stat == pdTRUE && h->outbound.len == -1);
|
||||
if (h->outbound.len == -1) { // used as a signal only, no actual data
|
||||
h->outbound.len = 0;
|
||||
}
|
||||
} else {
|
||||
// outbound is bigger, need to transmit in another transaction (keep this empty)
|
||||
head->size = 0;
|
||||
}
|
||||
next_tx_size = head->next_size = h->outbound.len;
|
||||
head->magic = SPI_HEADER_MAGIC;
|
||||
head->check = esp_rom_crc16_le(0, out_buf, sizeof(struct header) - sizeof(uint16_t));
|
||||
esp_err_t ret = perform_transaction(h, sizeof(struct header) + h->transaction_size, out_buf, in_buf);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "spi_device_transmit failed");
|
||||
h->transaction_size = 0; // need to start with HEADER only transaction
|
||||
return ESP_FAIL;
|
||||
}
|
||||
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) {
|
||||
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");
|
||||
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);
|
||||
}
|
||||
h->transaction_size = NEXT_TRANSACTION_SIZE(next_tx_size, head->next_size);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#elif CONFIG_EPPP_LINK_DEVICE_UART
|
||||
#define BUF_SIZE (1024)
|
||||
|
||||
static esp_err_t init_uart(struct eppp_handle *h, eppp_config_t *config)
|
||||
{
|
||||
h->uart_port = config->uart.port;
|
||||
uart_config_t uart_config = {};
|
||||
uart_config.baud_rate = config->uart.baud;
|
||||
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.source_clk = UART_SCLK_DEFAULT;
|
||||
|
||||
ESP_RETURN_ON_ERROR(uart_driver_install(h->uart_port, config->uart.rx_buffer_size, 0, config->uart.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->uart.tx_io, config->uart.rx_io, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE), 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;
|
||||
}
|
||||
|
||||
static void deinit_uart(struct eppp_handle *h)
|
||||
{
|
||||
uart_driver_delete(h->uart_port);
|
||||
}
|
||||
|
||||
esp_err_t eppp_perform(esp_netif_t *netif)
|
||||
{
|
||||
static uint8_t buffer[BUF_SIZE] = {};
|
||||
struct eppp_handle *h = esp_netif_get_io_driver(netif);
|
||||
uart_event_t event = {};
|
||||
if (h->stop) {
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
|
||||
if (xQueueReceive(h->uart_event_queue, &event, pdMS_TO_TICKS(100)) != pdTRUE) {
|
||||
return ESP_OK;
|
||||
}
|
||||
if (event.type == UART_DATA) {
|
||||
size_t len;
|
||||
uart_get_buffered_data_len(h->uart_port, &len);
|
||||
if (len) {
|
||||
len = uart_read_bytes(h->uart_port, buffer, BUF_SIZE, 0);
|
||||
ESP_LOG_BUFFER_HEXDUMP("ppp_uart_recv", buffer, len, ESP_LOG_VERBOSE);
|
||||
esp_netif_receive(netif, buffer, len, NULL);
|
||||
}
|
||||
} else {
|
||||
ESP_LOGW(TAG, "Received UART event: %d", event.type);
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#endif // CONFIG_EPPP_LINK_DEVICE_SPI / UART
|
||||
|
||||
static void ppp_task(void *args)
|
||||
{
|
||||
esp_netif_t *netif = args;
|
||||
while (eppp_perform(netif) != ESP_ERR_TIMEOUT) {}
|
||||
struct eppp_handle *h = esp_netif_get_io_driver(netif);
|
||||
h->exited = true;
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
static bool have_some_eppp_netif(esp_netif_t *netif, void *ctx)
|
||||
{
|
||||
return get_netif_num(netif) > 0;
|
||||
}
|
||||
|
||||
static void remove_handlers(void)
|
||||
{
|
||||
esp_netif_t *netif = esp_netif_find_if(have_some_eppp_netif, NULL);
|
||||
if (netif == NULL) {
|
||||
// if EPPP netif in the system, we cleanup the statics
|
||||
vEventGroupDelete(s_event_group);
|
||||
s_event_group = NULL;
|
||||
esp_event_handler_unregister(IP_EVENT, ESP_EVENT_ANY_ID, on_ip_event);
|
||||
esp_event_handler_unregister(NETIF_PPP_STATUS, ESP_EVENT_ANY_ID, on_ppp_event);
|
||||
}
|
||||
}
|
||||
|
||||
void eppp_deinit(esp_netif_t *netif)
|
||||
{
|
||||
if (netif == NULL) {
|
||||
return;
|
||||
}
|
||||
#if CONFIG_EPPP_LINK_DEVICE_SPI
|
||||
struct eppp_handle *h = esp_netif_get_io_driver(netif);
|
||||
if (h->role == EPPP_CLIENT) {
|
||||
deinit_master(netif);
|
||||
} else {
|
||||
deinit_slave(netif);
|
||||
}
|
||||
#elif CONFIG_EPPP_LINK_DEVICE_UART
|
||||
deinit_uart(esp_netif_get_io_driver(netif));
|
||||
#endif
|
||||
netif_deinit(netif);
|
||||
}
|
||||
|
||||
esp_netif_t *eppp_init(eppp_type_t role, eppp_config_t *config)
|
||||
{
|
||||
esp_netif_t *netif = netif_init(role);
|
||||
if (!netif) {
|
||||
ESP_LOGE(TAG, "Failed to initialize PPP netif");
|
||||
remove_handlers();
|
||||
return NULL;
|
||||
}
|
||||
esp_netif_ppp_config_t netif_params;
|
||||
ESP_ERROR_CHECK(esp_netif_ppp_get_params(netif, &netif_params));
|
||||
netif_params.ppp_our_ip4_addr = config->ppp.our_ip4_addr;
|
||||
netif_params.ppp_their_ip4_addr = config->ppp.their_ip4_addr;
|
||||
netif_params.ppp_error_event_enabled = true;
|
||||
ESP_ERROR_CHECK(esp_netif_ppp_set_params(netif, &netif_params));
|
||||
#if CONFIG_EPPP_LINK_DEVICE_SPI
|
||||
if (role == EPPP_CLIENT) {
|
||||
init_master(&config->spi, netif);
|
||||
} else {
|
||||
init_slave(&config->spi, netif);
|
||||
|
||||
}
|
||||
#elif CONFIG_EPPP_LINK_DEVICE_UART
|
||||
init_uart(esp_netif_get_io_driver(netif), config);
|
||||
#endif
|
||||
return netif;
|
||||
}
|
||||
|
||||
esp_netif_t *eppp_open(eppp_type_t role, eppp_config_t *config, int connect_timeout_ms)
|
||||
{
|
||||
#if CONFIG_EPPP_LINK_DEVICE_UART
|
||||
if (config->transport != EPPP_TRANSPORT_UART) {
|
||||
ESP_LOGE(TAG, "Invalid transport: UART device must be enabled in Kconfig");
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
#if CONFIG_EPPP_LINK_DEVICE_SPI
|
||||
if (config->transport != EPPP_TRANSPORT_SPI) {
|
||||
ESP_LOGE(TAG, "Invalid transport: SPI device must be enabled in Kconfig");
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (config->task.run_task == false) {
|
||||
ESP_LOGE(TAG, "task.run_task == false is invalid in this API. Please use eppp_init()");
|
||||
return NULL;
|
||||
}
|
||||
if (s_event_group == NULL) {
|
||||
s_event_group = xEventGroupCreate();
|
||||
if (esp_event_handler_register(IP_EVENT, ESP_EVENT_ANY_ID, on_ip_event, NULL) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to register IP event handler");
|
||||
remove_handlers();
|
||||
return NULL;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
esp_netif_t *netif = eppp_init(role, config);
|
||||
if (!netif) {
|
||||
remove_handlers();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
eppp_netif_start(netif);
|
||||
|
||||
if (xTaskCreate(ppp_task, "ppp connect", config->task.stack_size, netif, config->task.priority, NULL) != pdTRUE) {
|
||||
ESP_LOGE(TAG, "Failed to create a ppp connection task");
|
||||
eppp_deinit(netif);
|
||||
return NULL;
|
||||
}
|
||||
int netif_cnt = get_netif_num(netif);
|
||||
if (netif_cnt < 0) {
|
||||
eppp_close(netif);
|
||||
return NULL;
|
||||
}
|
||||
ESP_LOGI(TAG, "Waiting for IP address %d", netif_cnt);
|
||||
EventBits_t bits = xEventGroupWaitBits(s_event_group, CONNECT_BITS << (netif_cnt * 2), pdFALSE, pdFALSE, pdMS_TO_TICKS(connect_timeout_ms));
|
||||
if (bits & (CONNECTION_FAILED << (netif_cnt * 2))) {
|
||||
ESP_LOGE(TAG, "Connection failed!");
|
||||
eppp_close(netif);
|
||||
return NULL;
|
||||
}
|
||||
ESP_LOGI(TAG, "Connected! %d", netif_cnt);
|
||||
return netif;
|
||||
}
|
||||
|
||||
esp_netif_t *eppp_connect(eppp_config_t *config)
|
||||
{
|
||||
return eppp_open(EPPP_CLIENT, config, portMAX_DELAY);
|
||||
}
|
||||
|
||||
esp_netif_t *eppp_listen(eppp_config_t *config)
|
||||
{
|
||||
return eppp_open(EPPP_SERVER, config, portMAX_DELAY);
|
||||
}
|
||||
|
||||
void eppp_close(esp_netif_t *netif)
|
||||
{
|
||||
struct eppp_handle *h = esp_netif_get_io_driver(netif);
|
||||
if (eppp_netif_stop(netif, 60000) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Network didn't exit cleanly");
|
||||
}
|
||||
h->stop = true;
|
||||
for (int wait = 0; wait < 100; wait++) {
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
if (h->exited) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!h->exited) {
|
||||
ESP_LOGE(TAG, "Cannot stop ppp_task");
|
||||
}
|
||||
eppp_deinit(netif);
|
||||
remove_handlers();
|
||||
}
|
8
components/eppp_link/examples/host/CMakeLists.txt
Normal file
8
components/eppp_link/examples/host/CMakeLists.txt
Normal file
@ -0,0 +1,8 @@
|
||||
# The following four lines of boilerplate have to be in your project's CMakeLists
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/iperf)
|
||||
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(pppos_host)
|
9
components/eppp_link/examples/host/README.md
Normal file
9
components/eppp_link/examples/host/README.md
Normal file
@ -0,0 +1,9 @@
|
||||
|
||||
# Client side demo of ESP-PPP-Link
|
||||
|
||||
This is a basic demo of using esp-mqtt library, but connects to the internet using a PPPoS client. To run this example, you would need a PPP server that provides connectivity to the MQTT broker used in this example (by default a public broker accessible on the internet).
|
||||
|
||||
If configured, this example could also run a ping session and an iperf console.
|
||||
|
||||
|
||||
The PPP server could be a Linux computer with `pppd` service or an ESP32 acting like a connection gateway with PPPoS server (see the "slave" project).
|
2
components/eppp_link/examples/host/main/CMakeLists.txt
Normal file
2
components/eppp_link/examples/host/main/CMakeLists.txt
Normal file
@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS app_main.c register_iperf.c
|
||||
INCLUDE_DIRS ".")
|
53
components/eppp_link/examples/host/main/Kconfig.projbuild
Normal file
53
components/eppp_link/examples/host/main/Kconfig.projbuild
Normal file
@ -0,0 +1,53 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
config EXAMPLE_GLOBAL_DNS
|
||||
hex "Set global DNS server"
|
||||
range 0 0xFFFFFFFF
|
||||
default 0x08080808
|
||||
help
|
||||
Global DNS server address.
|
||||
|
||||
config EXAMPLE_MQTT
|
||||
bool "Run mqtt example"
|
||||
default y
|
||||
help
|
||||
Run MQTT client after startup.
|
||||
|
||||
config EXAMPLE_BROKER_URL
|
||||
string "Broker URL"
|
||||
depends on EXAMPLE_MQTT
|
||||
default "mqtt://mqtt.eclipseprojects.io"
|
||||
help
|
||||
URL of the broker to connect to.
|
||||
|
||||
config EXAMPLE_IPERF
|
||||
bool "Run iperf"
|
||||
default y
|
||||
help
|
||||
Init and run iperf console.
|
||||
|
||||
config EXAMPLE_UART_TX_PIN
|
||||
int "TXD Pin Number"
|
||||
depends on EPPP_LINK_DEVICE_UART
|
||||
default 10
|
||||
range 0 31
|
||||
help
|
||||
Pin number of UART TX.
|
||||
|
||||
config EXAMPLE_UART_RX_PIN
|
||||
int "RXD Pin Number"
|
||||
depends on EPPP_LINK_DEVICE_UART
|
||||
default 11
|
||||
range 0 31
|
||||
help
|
||||
Pin number of UART RX.
|
||||
|
||||
config EXAMPLE_UART_BAUDRATE
|
||||
int "Baudrate"
|
||||
depends on EPPP_LINK_DEVICE_UART
|
||||
default 2000000
|
||||
range 0 4000000
|
||||
help
|
||||
Baudrate used by the PPP over UART
|
||||
|
||||
endmenu
|
149
components/eppp_link/examples/host/main/app_main.c
Normal file
149
components/eppp_link/examples/host/main/app_main.c
Normal file
@ -0,0 +1,149 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include "esp_system.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_netif.h"
|
||||
#include "eppp_link.h"
|
||||
#include "esp_log.h"
|
||||
#include "mqtt_client.h"
|
||||
#include "console_ping.h"
|
||||
|
||||
void register_iperf(void);
|
||||
|
||||
static const char *TAG = "eppp_host_example";
|
||||
|
||||
#if CONFIG_EXAMPLE_MQTT
|
||||
static void mqtt_event_handler(void *args, esp_event_base_t base, int32_t event_id, void *event_data)
|
||||
{
|
||||
ESP_LOGD(TAG, "Event dispatched from event loop base=%s, event_id=%" PRIi32 "", base, event_id);
|
||||
esp_mqtt_event_handle_t event = event_data;
|
||||
esp_mqtt_client_handle_t client = event->client;
|
||||
int msg_id;
|
||||
switch ((esp_mqtt_event_id_t)event_id) {
|
||||
case MQTT_EVENT_CONNECTED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
|
||||
msg_id = esp_mqtt_client_publish(client, "/topic/qos1", "data_3", 0, 1, 0);
|
||||
ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);
|
||||
|
||||
msg_id = esp_mqtt_client_subscribe(client, "/topic/qos0", 0);
|
||||
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
|
||||
|
||||
msg_id = esp_mqtt_client_subscribe(client, "/topic/qos1", 1);
|
||||
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
|
||||
|
||||
msg_id = esp_mqtt_client_unsubscribe(client, "/topic/qos1");
|
||||
ESP_LOGI(TAG, "sent unsubscribe successful, msg_id=%d", msg_id);
|
||||
break;
|
||||
case MQTT_EVENT_DISCONNECTED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_SUBSCRIBED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id);
|
||||
msg_id = esp_mqtt_client_publish(client, "/topic/qos0", "data", 0, 0, 0);
|
||||
ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);
|
||||
break;
|
||||
case MQTT_EVENT_UNSUBSCRIBED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);
|
||||
break;
|
||||
case MQTT_EVENT_PUBLISHED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
|
||||
break;
|
||||
case MQTT_EVENT_DATA:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_DATA");
|
||||
printf("TOPIC=%.*s\r\n", event->topic_len, event->topic);
|
||||
printf("DATA=%.*s\r\n", event->data_len, event->data);
|
||||
break;
|
||||
case MQTT_EVENT_ERROR:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_ERROR");
|
||||
if (event->error_handle->error_type == MQTT_ERROR_TYPE_TCP_TRANSPORT) {
|
||||
ESP_LOGI(TAG, "Last errno string (%s)", strerror(event->error_handle->esp_transport_sock_errno));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ESP_LOGI(TAG, "Other event id:%d", event->event_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void mqtt_app_start(void)
|
||||
{
|
||||
esp_mqtt_client_config_t mqtt_cfg = {
|
||||
.broker.address.uri = "mqtt://mqtt.eclipseprojects.io",
|
||||
};
|
||||
|
||||
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);
|
||||
/* The last argument may be used to pass data to the event handler, in this example mqtt_event_handler */
|
||||
esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL);
|
||||
esp_mqtt_client_start(client);
|
||||
}
|
||||
#endif // MQTT
|
||||
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "[APP] Startup..");
|
||||
ESP_LOGI(TAG, "[APP] Free memory: %" PRIu32 " bytes", esp_get_free_heap_size());
|
||||
ESP_LOGI(TAG, "[APP] IDF version: %s", esp_get_idf_version());
|
||||
|
||||
ESP_ERROR_CHECK(nvs_flash_init());
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
|
||||
/* Sets up the default EPPP-connection
|
||||
*/
|
||||
eppp_config_t config = EPPP_DEFAULT_CLIENT_CONFIG();
|
||||
#if CONFIG_EPPP_LINK_DEVICE_SPI
|
||||
config.transport = EPPP_TRANSPORT_SPI;
|
||||
#else
|
||||
config.transport = EPPP_TRANSPORT_UART;
|
||||
config.uart.tx_io = CONFIG_EXAMPLE_UART_TX_PIN;
|
||||
config.uart.rx_io = CONFIG_EXAMPLE_UART_RX_PIN;
|
||||
config.uart.baud = CONFIG_EXAMPLE_UART_BAUDRATE;
|
||||
#endif
|
||||
esp_netif_t *eppp_netif = eppp_connect(&config);
|
||||
if (eppp_netif == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to connect");
|
||||
return ;
|
||||
}
|
||||
// Setup global DNS
|
||||
esp_netif_dns_info_t dns;
|
||||
dns.ip.u_addr.ip4.addr = esp_netif_htonl(CONFIG_EXAMPLE_GLOBAL_DNS);
|
||||
dns.ip.type = ESP_IPADDR_TYPE_V4;
|
||||
ESP_ERROR_CHECK(esp_netif_set_dns_info(eppp_netif, ESP_NETIF_DNS_MAIN, &dns));
|
||||
|
||||
// Initialize console REPL
|
||||
ESP_ERROR_CHECK(console_cmd_init());
|
||||
|
||||
#if CONFIG_EXAMPLE_IPERF
|
||||
register_iperf();
|
||||
|
||||
printf("\n =======================================================\n");
|
||||
printf(" | Steps to Test EPPP-host bandwidth |\n");
|
||||
printf(" | |\n");
|
||||
printf(" | 1. Wait for the ESP32 to get an IP |\n");
|
||||
printf(" | 2. Server: 'iperf -u -s -i 3' (on host) |\n");
|
||||
printf(" | 3. Client: 'iperf -u -c SERVER_IP -t 60 -i 3' |\n");
|
||||
printf(" | |\n");
|
||||
printf(" =======================================================\n\n");
|
||||
|
||||
#endif // CONFIG_EXAMPLE_IPERF
|
||||
|
||||
// Register the ping command
|
||||
ESP_ERROR_CHECK(console_cmd_ping_register());
|
||||
// start console REPL
|
||||
ESP_ERROR_CHECK(console_cmd_start());
|
||||
|
||||
#if CONFIG_EXAMPLE_MQTT
|
||||
mqtt_app_start();
|
||||
#endif
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
dependencies:
|
||||
espressif/eppp_link:
|
||||
version: "*"
|
||||
override_path: "../../.."
|
||||
console_cmd_ping:
|
||||
version: "*"
|
179
components/eppp_link/examples/host/main/register_iperf.c
Normal file
179
components/eppp_link/examples/host/main/register_iperf.c
Normal file
@ -0,0 +1,179 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "sys/socket.h" // for INADDR_ANY
|
||||
#include "esp_netif.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_netif.h"
|
||||
#include "esp_netif_ppp.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/event_groups.h"
|
||||
|
||||
#include "esp_console.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_bit_defs.h"
|
||||
#include "argtable3/argtable3.h"
|
||||
#include "iperf.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
/* "iperf" command */
|
||||
|
||||
static struct {
|
||||
struct arg_str *ip;
|
||||
struct arg_lit *server;
|
||||
struct arg_lit *udp;
|
||||
struct arg_lit *version;
|
||||
struct arg_int *port;
|
||||
struct arg_int *length;
|
||||
struct arg_int *interval;
|
||||
struct arg_int *time;
|
||||
struct arg_int *bw_limit;
|
||||
struct arg_lit *abort;
|
||||
struct arg_end *end;
|
||||
} iperf_args;
|
||||
|
||||
static int ppp_cmd_iperf(int argc, char **argv)
|
||||
{
|
||||
int nerrors = arg_parse(argc, argv, (void **)&iperf_args);
|
||||
// ethernet iperf only support IPV4 address
|
||||
iperf_cfg_t cfg = {.type = IPERF_IP_TYPE_IPV4};
|
||||
|
||||
if (nerrors != 0) {
|
||||
arg_print_errors(stderr, iperf_args.end, argv[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* iperf -a */
|
||||
if (iperf_args.abort->count != 0) {
|
||||
iperf_stop();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (((iperf_args.ip->count == 0) && (iperf_args.server->count == 0)) ||
|
||||
((iperf_args.ip->count != 0) && (iperf_args.server->count != 0))) {
|
||||
ESP_LOGE(__func__, "Wrong mode! ESP32 should run in client or server mode");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* iperf -s */
|
||||
if (iperf_args.ip->count == 0) {
|
||||
cfg.flag |= IPERF_FLAG_SERVER;
|
||||
}
|
||||
/* iperf -c SERVER_ADDRESS */
|
||||
else {
|
||||
cfg.destination_ip4 = esp_ip4addr_aton(iperf_args.ip->sval[0]);
|
||||
cfg.flag |= IPERF_FLAG_CLIENT;
|
||||
}
|
||||
|
||||
if (iperf_args.length->count == 0) {
|
||||
cfg.len_send_buf = 0;
|
||||
} else {
|
||||
cfg.len_send_buf = iperf_args.length->ival[0];
|
||||
}
|
||||
|
||||
cfg.source_ip4 = INADDR_ANY;
|
||||
|
||||
/* iperf -u */
|
||||
if (iperf_args.udp->count == 0) {
|
||||
cfg.flag |= IPERF_FLAG_TCP;
|
||||
} else {
|
||||
cfg.flag |= IPERF_FLAG_UDP;
|
||||
}
|
||||
|
||||
/* iperf -p */
|
||||
if (iperf_args.port->count == 0) {
|
||||
cfg.sport = IPERF_DEFAULT_PORT;
|
||||
cfg.dport = IPERF_DEFAULT_PORT;
|
||||
} else {
|
||||
if (cfg.flag & IPERF_FLAG_SERVER) {
|
||||
cfg.sport = iperf_args.port->ival[0];
|
||||
cfg.dport = IPERF_DEFAULT_PORT;
|
||||
} else {
|
||||
cfg.sport = IPERF_DEFAULT_PORT;
|
||||
cfg.dport = iperf_args.port->ival[0];
|
||||
}
|
||||
}
|
||||
|
||||
/* iperf -i */
|
||||
if (iperf_args.interval->count == 0) {
|
||||
cfg.interval = IPERF_DEFAULT_INTERVAL;
|
||||
} else {
|
||||
cfg.interval = iperf_args.interval->ival[0];
|
||||
if (cfg.interval <= 0) {
|
||||
cfg.interval = IPERF_DEFAULT_INTERVAL;
|
||||
}
|
||||
}
|
||||
|
||||
/* iperf -t */
|
||||
if (iperf_args.time->count == 0) {
|
||||
cfg.time = IPERF_DEFAULT_TIME;
|
||||
} else {
|
||||
cfg.time = iperf_args.time->ival[0];
|
||||
if (cfg.time <= cfg.interval) {
|
||||
cfg.time = cfg.interval;
|
||||
}
|
||||
}
|
||||
|
||||
/* iperf -b */
|
||||
if (iperf_args.bw_limit->count == 0) {
|
||||
cfg.bw_lim = IPERF_DEFAULT_NO_BW_LIMIT;
|
||||
} else {
|
||||
cfg.bw_lim = iperf_args.bw_limit->ival[0];
|
||||
if (cfg.bw_lim <= 0) {
|
||||
cfg.bw_lim = IPERF_DEFAULT_NO_BW_LIMIT;
|
||||
}
|
||||
}
|
||||
|
||||
printf("mode=%s-%s sip=" IPSTR ":%" PRIu16 ", dip=%" PRIu32 ".%" PRIu32 ".%" PRIu32 ".%" PRIu32 ":%" PRIu16 ", interval=%" PRIu32 ", time=%" PRIu32 "\r\n",
|
||||
cfg.flag & IPERF_FLAG_TCP ? "tcp" : "udp",
|
||||
cfg.flag & IPERF_FLAG_SERVER ? "server" : "client",
|
||||
(uint16_t) cfg.source_ip4 & 0xFF,
|
||||
(uint16_t) (cfg.source_ip4 >> 8) & 0xFF,
|
||||
(uint16_t) (cfg.source_ip4 >> 16) & 0xFF,
|
||||
(uint16_t) (cfg.source_ip4 >> 24) & 0xFF,
|
||||
cfg.sport,
|
||||
cfg.destination_ip4 & 0xFF, (cfg.destination_ip4 >> 8) & 0xFF,
|
||||
(cfg.destination_ip4 >> 16) & 0xFF, (cfg.destination_ip4 >> 24) & 0xFF, cfg.dport,
|
||||
cfg.interval, cfg.time);
|
||||
|
||||
iperf_start(&cfg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void register_iperf(void)
|
||||
{
|
||||
|
||||
iperf_args.ip = arg_str0("c", "client", "<ip>",
|
||||
"run in client mode, connecting to <host>");
|
||||
iperf_args.server = arg_lit0("s", "server", "run in server mode");
|
||||
iperf_args.udp = arg_lit0("u", "udp", "use UDP rather than TCP");
|
||||
iperf_args.version = arg_lit0("V", "ipv6_domain", "use IPV6 address rather than IPV4");
|
||||
iperf_args.port = arg_int0("p", "port", "<port>",
|
||||
"server port to listen on/connect to");
|
||||
iperf_args.length = arg_int0("l", "len", "<length>", "set read/write buffer size");
|
||||
iperf_args.interval = arg_int0("i", "interval", "<interval>",
|
||||
"seconds between periodic bandwidth reports");
|
||||
iperf_args.time = arg_int0("t", "time", "<time>", "time in seconds to transmit for (default 10 secs)");
|
||||
iperf_args.bw_limit = arg_int0("b", "bandwidth", "<bandwidth>", "bandwidth to send at in Mbits/sec");
|
||||
iperf_args.abort = arg_lit0("a", "abort", "abort running iperf");
|
||||
iperf_args.end = arg_end(1);
|
||||
const esp_console_cmd_t iperf_cmd = {
|
||||
.command = "iperf",
|
||||
.help = "iperf command",
|
||||
.hint = NULL,
|
||||
.func = &ppp_cmd_iperf,
|
||||
.argtable = &iperf_args
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&iperf_cmd));
|
||||
}
|
1
components/eppp_link/examples/host/sdkconfig.ci.spi
Normal file
1
components/eppp_link/examples/host/sdkconfig.ci.spi
Normal file
@ -0,0 +1 @@
|
||||
CONFIG_EPPP_LINK_DEVICE_SPI=y
|
1
components/eppp_link/examples/host/sdkconfig.ci.uart
Normal file
1
components/eppp_link/examples/host/sdkconfig.ci.uart
Normal file
@ -0,0 +1 @@
|
||||
CONFIG_EPPP_LINK_DEVICE_UART=y
|
4
components/eppp_link/examples/host/sdkconfig.defaults
Normal file
4
components/eppp_link/examples/host/sdkconfig.defaults
Normal file
@ -0,0 +1,4 @@
|
||||
CONFIG_LWIP_PPP_SUPPORT=y
|
||||
CONFIG_LWIP_PPP_SERVER_SUPPORT=y
|
||||
CONFIG_LWIP_PPP_VJ_HEADER_COMPRESSION=n
|
||||
CONFIG_LWIP_PPP_DEBUG_ON=y
|
6
components/eppp_link/examples/slave/CMakeLists.txt
Normal file
6
components/eppp_link/examples/slave/CMakeLists.txt
Normal file
@ -0,0 +1,6 @@
|
||||
# The following five lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(pppos_slave)
|
7
components/eppp_link/examples/slave/README.md
Normal file
7
components/eppp_link/examples/slave/README.md
Normal file
@ -0,0 +1,7 @@
|
||||
|
||||
# Wi-Fi station to PPPoS server
|
||||
|
||||
This example demonstrate using NAPT to bring connectivity from WiFi station to PPPoS server.
|
||||
|
||||
This example expect a PPPoS client to connect to the server and use the connectivity.
|
||||
The client could be a Linux computer with `pppd` service or another microcontroller with PPP client (or another ESP32 with not WiFi interface)
|
2
components/eppp_link/examples/slave/main/CMakeLists.txt
Normal file
2
components/eppp_link/examples/slave/main/CMakeLists.txt
Normal file
@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "eppp_slave.c"
|
||||
INCLUDE_DIRS ".")
|
45
components/eppp_link/examples/slave/main/Kconfig.projbuild
Normal file
45
components/eppp_link/examples/slave/main/Kconfig.projbuild
Normal file
@ -0,0 +1,45 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
config ESP_WIFI_SSID
|
||||
string "WiFi SSID"
|
||||
default "myssid"
|
||||
help
|
||||
SSID (network name) for the example to connect to.
|
||||
|
||||
config ESP_WIFI_PASSWORD
|
||||
string "WiFi Password"
|
||||
default "mypassword"
|
||||
help
|
||||
WiFi password (WPA or WPA2) for the example to use.
|
||||
|
||||
config ESP_MAXIMUM_RETRY
|
||||
int "Maximum retry"
|
||||
default 5
|
||||
help
|
||||
Set the Maximum retry to avoid station reconnecting to the AP unlimited when the AP is really inexistent.
|
||||
|
||||
config EXAMPLE_UART_TX_PIN
|
||||
int "TXD Pin Number"
|
||||
depends on EPPP_LINK_DEVICE_UART
|
||||
default 11
|
||||
range 0 31
|
||||
help
|
||||
Pin number of UART TX.
|
||||
|
||||
config EXAMPLE_UART_RX_PIN
|
||||
int "RXD Pin Number"
|
||||
depends on EPPP_LINK_DEVICE_UART
|
||||
default 10
|
||||
range 0 31
|
||||
help
|
||||
Pin number of UART RX.
|
||||
|
||||
config EXAMPLE_UART_BAUDRATE
|
||||
int "Baudrate"
|
||||
depends on EPPP_LINK_DEVICE_UART
|
||||
default 2000000
|
||||
range 0 4000000
|
||||
help
|
||||
Baudrate used by the PPP over UART
|
||||
|
||||
endmenu
|
147
components/eppp_link/examples/slave/main/eppp_slave.c
Normal file
147
components/eppp_link/examples/slave/main/eppp_slave.c
Normal file
@ -0,0 +1,147 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_wifi.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_log.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "eppp_link.h"
|
||||
|
||||
static const char *TAG = "eppp_slave";
|
||||
|
||||
#if CONFIG_SOC_WIFI_SUPPORTED
|
||||
|
||||
/* FreeRTOS event group to signal when we are connected*/
|
||||
static EventGroupHandle_t s_wifi_event_group;
|
||||
|
||||
/* The event group allows multiple bits for each event, but we only care about two events:
|
||||
* - we are connected to the AP with an IP
|
||||
* - we failed to connect after the maximum amount of retries */
|
||||
#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)
|
||||
{
|
||||
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
|
||||
esp_wifi_connect();
|
||||
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
|
||||
if (s_retry_num < CONFIG_ESP_MAXIMUM_RETRY) {
|
||||
esp_wifi_connect();
|
||||
s_retry_num++;
|
||||
ESP_LOGI(TAG, "retry to connect to the AP");
|
||||
} else {
|
||||
xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
|
||||
}
|
||||
ESP_LOGI(TAG, "connect to the AP fail");
|
||||
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
|
||||
ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data;
|
||||
ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
|
||||
s_retry_num = 0;
|
||||
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
|
||||
}
|
||||
}
|
||||
|
||||
void init_network_interface(void)
|
||||
{
|
||||
s_wifi_event_group = xEventGroupCreate();
|
||||
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
esp_netif_create_default_wifi_sta();
|
||||
|
||||
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||||
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
|
||||
|
||||
esp_event_handler_instance_t instance_any_id;
|
||||
esp_event_handler_instance_t instance_got_ip;
|
||||
ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
|
||||
ESP_EVENT_ANY_ID,
|
||||
&event_handler,
|
||||
NULL,
|
||||
&instance_any_id));
|
||||
ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
|
||||
IP_EVENT_STA_GOT_IP,
|
||||
&event_handler,
|
||||
NULL,
|
||||
&instance_got_ip));
|
||||
|
||||
wifi_config_t wifi_config = {
|
||||
.sta = {
|
||||
.ssid = 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) );
|
||||
ESP_ERROR_CHECK(esp_wifi_start() );
|
||||
|
||||
ESP_LOGI(TAG, "wifi_init_sta finished.");
|
||||
|
||||
/* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum
|
||||
* number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */
|
||||
EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
|
||||
WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
|
||||
pdFALSE,
|
||||
pdFALSE,
|
||||
portMAX_DELAY);
|
||||
|
||||
/* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually
|
||||
* happened. */
|
||||
if (bits & WIFI_CONNECTED_BIT) {
|
||||
ESP_LOGI(TAG, "connected to ap SSID:%s password:%s",
|
||||
CONFIG_ESP_WIFI_SSID, CONFIG_ESP_WIFI_PASSWORD);
|
||||
} else if (bits & WIFI_FAIL_BIT) {
|
||||
ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s",
|
||||
CONFIG_ESP_WIFI_SSID, CONFIG_ESP_WIFI_PASSWORD);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "UNEXPECTED EVENT");
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
||||
void init_network_interface(void)
|
||||
{
|
||||
// placeholder to initialize any other network interface if WiFi is not available
|
||||
}
|
||||
|
||||
#endif // SoC WiFi capable chip
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
//Initialize NVS
|
||||
esp_err_t ret = nvs_flash_init();
|
||||
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||
ret = nvs_flash_init();
|
||||
}
|
||||
ESP_ERROR_CHECK(ret);
|
||||
|
||||
init_network_interface(); // WiFi station if withing SoC capabilities (otherwise a placeholder)
|
||||
|
||||
eppp_config_t config = EPPP_DEFAULT_SERVER_CONFIG();
|
||||
#if CONFIG_EPPP_LINK_DEVICE_SPI
|
||||
config.transport = EPPP_TRANSPORT_SPI;
|
||||
#else
|
||||
config.transport = EPPP_TRANSPORT_UART;
|
||||
config.uart.tx_io = CONFIG_EXAMPLE_UART_TX_PIN;
|
||||
config.uart.rx_io = CONFIG_EXAMPLE_UART_RX_PIN;
|
||||
config.uart.baud = CONFIG_EXAMPLE_UART_BAUDRATE;
|
||||
#endif
|
||||
esp_netif_t *eppp_netif = eppp_listen(&config);
|
||||
if (eppp_netif == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to setup connection");
|
||||
return ;
|
||||
}
|
||||
ESP_ERROR_CHECK(esp_netif_napt_enable(eppp_netif));
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
dependencies:
|
||||
espressif/eppp_link:
|
||||
version: "*"
|
||||
override_path: "../../.."
|
1
components/eppp_link/examples/slave/sdkconfig.ci.spi
Normal file
1
components/eppp_link/examples/slave/sdkconfig.ci.spi
Normal file
@ -0,0 +1 @@
|
||||
CONFIG_EPPP_LINK_DEVICE_SPI=y
|
1
components/eppp_link/examples/slave/sdkconfig.ci.uart
Normal file
1
components/eppp_link/examples/slave/sdkconfig.ci.uart
Normal file
@ -0,0 +1 @@
|
||||
CONFIG_EPPP_LINK_DEVICE_UART=y
|
6
components/eppp_link/examples/slave/sdkconfig.defaults
Normal file
6
components/eppp_link/examples/slave/sdkconfig.defaults
Normal file
@ -0,0 +1,6 @@
|
||||
CONFIG_LWIP_IP_FORWARD=y
|
||||
CONFIG_LWIP_IPV4_NAPT=y
|
||||
CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=4096
|
||||
CONFIG_LWIP_PPP_SUPPORT=y
|
||||
CONFIG_LWIP_PPP_SERVER_SUPPORT=y
|
||||
CONFIG_LWIP_PPP_VJ_HEADER_COMPRESSION=n
|
6
components/eppp_link/idf_component.yml
Normal file
6
components/eppp_link/idf_component.yml
Normal file
@ -0,0 +1,6 @@
|
||||
version: 0.0.1
|
||||
url: https://github.com/espressif/esp-protocols/tree/master/components/eppp_link
|
||||
description: The component provides a general purpose PPP connectivity, typically used as WiFi-PPP router
|
||||
dependencies:
|
||||
idf:
|
||||
version: '>=5.2'
|
111
components/eppp_link/include/eppp_link.h
Normal file
111
components/eppp_link/include/eppp_link.h
Normal file
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define EPPP_DEFAULT_SERVER_IP() ESP_IP4TOADDR(192, 168, 11, 1)
|
||||
#define EPPP_DEFAULT_CLIENT_IP() ESP_IP4TOADDR(192, 168, 11, 2)
|
||||
|
||||
#define EPPP_DEFAULT_CONFIG(our_ip, their_ip) { \
|
||||
.transport = EPPP_TRANSPORT_UART, \
|
||||
.spi = { \
|
||||
.host = 1, \
|
||||
.mosi = 11, \
|
||||
.miso = 13, \
|
||||
.sclk = 12, \
|
||||
.cs = 10, \
|
||||
.intr = 2, \
|
||||
.freq = 16*1000*1000, \
|
||||
.input_delay_ns = 0, \
|
||||
.cs_ena_pretrans = 0, \
|
||||
.cs_ena_posttrans = 0, \
|
||||
}, \
|
||||
.uart = { \
|
||||
.port = 1, \
|
||||
.baud = 921600, \
|
||||
.tx_io = 25, \
|
||||
.rx_io = 26, \
|
||||
.queue_size = 16, \
|
||||
.rx_buffer_size = 1024, \
|
||||
}, \
|
||||
. task = { \
|
||||
.run_task = true, \
|
||||
.stack_size = 4096, \
|
||||
.priority = 8, \
|
||||
}, \
|
||||
. ppp = { \
|
||||
.our_ip4_addr.addr = our_ip, \
|
||||
.their_ip4_addr.addr = their_ip, \
|
||||
} \
|
||||
}
|
||||
|
||||
#define EPPP_DEFAULT_SERVER_CONFIG() EPPP_DEFAULT_CONFIG(EPPP_DEFAULT_SERVER_IP(), EPPP_DEFAULT_CLIENT_IP())
|
||||
#define EPPP_DEFAULT_CLIENT_CONFIG() EPPP_DEFAULT_CONFIG(EPPP_DEFAULT_CLIENT_IP(), EPPP_DEFAULT_SERVER_IP())
|
||||
|
||||
typedef enum eppp_type {
|
||||
EPPP_SERVER,
|
||||
EPPP_CLIENT,
|
||||
} eppp_type_t;
|
||||
|
||||
typedef enum eppp_transport {
|
||||
EPPP_TRANSPORT_UART,
|
||||
EPPP_TRANSPORT_SPI,
|
||||
} eppp_transport_t;
|
||||
|
||||
|
||||
typedef struct eppp_config_t {
|
||||
eppp_transport_t transport;
|
||||
|
||||
struct eppp_config_spi_s {
|
||||
int host;
|
||||
int mosi;
|
||||
int miso;
|
||||
int sclk;
|
||||
int cs;
|
||||
int intr;
|
||||
int freq;
|
||||
int input_delay_ns;
|
||||
int cs_ena_pretrans;
|
||||
int cs_ena_posttrans;
|
||||
} spi;
|
||||
|
||||
struct eppp_config_uart_s {
|
||||
int port;
|
||||
int baud;
|
||||
int tx_io;
|
||||
int rx_io;
|
||||
int queue_size;
|
||||
int rx_buffer_size;
|
||||
} uart;
|
||||
|
||||
struct eppp_config_task_s {
|
||||
bool run_task;
|
||||
int stack_size;
|
||||
int priority;
|
||||
} task;
|
||||
|
||||
struct eppp_config_pppos_s {
|
||||
esp_ip4_addr_t our_ip4_addr;
|
||||
esp_ip4_addr_t their_ip4_addr;
|
||||
} ppp;
|
||||
|
||||
} eppp_config_t;
|
||||
|
||||
esp_netif_t *eppp_connect(eppp_config_t *config);
|
||||
|
||||
esp_netif_t *eppp_listen(eppp_config_t *config);
|
||||
|
||||
void eppp_close(esp_netif_t *netif);
|
||||
|
||||
esp_netif_t *eppp_init(eppp_type_t role, eppp_config_t *config);
|
||||
|
||||
void eppp_deinit(esp_netif_t *netif);
|
||||
|
||||
esp_netif_t *eppp_open(eppp_type_t role, eppp_config_t *config, int connect_timeout_ms);
|
||||
|
||||
esp_err_t eppp_netif_stop(esp_netif_t *netif, int stop_timeout_ms);
|
||||
|
||||
esp_err_t eppp_netif_start(esp_netif_t *netif);
|
||||
|
||||
esp_err_t eppp_perform(esp_netif_t *netif);
|
7
components/eppp_link/test/test_app/CMakeLists.txt
Normal file
7
components/eppp_link/test/test_app/CMakeLists.txt
Normal file
@ -0,0 +1,7 @@
|
||||
# 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)
|
||||
project(test_app)
|
73
components/eppp_link/test/test_app/README.md
Normal file
73
components/eppp_link/test/test_app/README.md
Normal file
@ -0,0 +1,73 @@
|
||||
|
||||
# Test application running both server and client on the same device
|
||||
|
||||
Need to connect client's Tx to server's Rx and vice versa:
|
||||
GPIO25 - GPIO4
|
||||
GPIO26 - GPIO5
|
||||
|
||||
We wait for the connection and then we start pinging the client's address on server's netif.
|
||||
|
||||
## Example of output:
|
||||
|
||||
```
|
||||
I (393) eppp_test_app: [APP] Startup..
|
||||
I (393) eppp_test_app: [APP] Free memory: 296332 bytes
|
||||
I (393) eppp_test_app: [APP] IDF version: v5.3-dev-1154-gf14d9e7431-dirty
|
||||
I (423) uart: ESP_INTR_FLAG_IRAM flag not set while CONFIG_UART_ISR_IN_IRAM is enabled, flag updated
|
||||
I (423) uart: queue free spaces: 16
|
||||
I (433) eppp_link: Waiting for IP address
|
||||
I (433) uart: ESP_INTR_FLAG_IRAM flag not set while CONFIG_UART_ISR_IN_IRAM is enabled, flag updated
|
||||
I (443) uart: queue free spaces: 16
|
||||
I (443) eppp_link: Waiting for IP address
|
||||
I (6473) esp-netif_lwip-ppp: Connected
|
||||
I (6513) eppp_link: Got IPv4 event: Interface "pppos_client" address: 192.168.11.2
|
||||
I (6523) esp-netif_lwip-ppp: Connected
|
||||
I (6513) eppp_link: Connected!
|
||||
I (6523) eppp_link: Got IPv4 event: Interface "pppos_server" address: 192.168.11.1
|
||||
I (6553) main_task: Returned from app_main()
|
||||
64bytes from 192.168.11.2 icmp_seq=1 ttl=255 time=18 ms
|
||||
64bytes from 192.168.11.2 icmp_seq=2 ttl=255 time=19 ms
|
||||
64bytes from 192.168.11.2 icmp_seq=3 ttl=255 time=19 ms
|
||||
64bytes from 192.168.11.2 icmp_seq=4 ttl=255 time=20 ms
|
||||
64bytes from 192.168.11.2 icmp_seq=5 ttl=255 time=19 ms
|
||||
64bytes from 192.168.11.2 icmp_seq=6 ttl=255 time=19 ms
|
||||
64bytes from 192.168.11.2 icmp_seq=7 ttl=255 time=19 ms
|
||||
From 192.168.11.2 icmp_seq=8 timeout // <-- Disconnected Tx-Rx wires
|
||||
From 192.168.11.2 icmp_seq=9 timeout
|
||||
```
|
||||
## Test cases
|
||||
|
||||
This test app exercises these methods of setting up server-client connection:
|
||||
* simple blocking API (eppp_listen() <--> eppp_connect()): Uses network events internally and waits for connection
|
||||
* simplified non-blocking API (eppp_open(EPPP_SERVER, ...) <--> eppp_open(EPPP_SERVER, ...) ): Uses events internally, optionally waits for connecting
|
||||
* manual API (eppp_init(), eppp_netif_start(), eppp_perform()): User to manually drive Rx task
|
||||
- Note that the ping test for this test case takes longer, since we call perform for both server and client from one task, for example:
|
||||
|
||||
```
|
||||
TEST(eppp_test, open_close_taskless)I (28562) uart: ESP_INTR_FLAG_IRAM flag not set while CONFIG_UART_ISR_IN_IRAM is enabled, flag updated
|
||||
I (28572) uart: ESP_INTR_FLAG_IRAM flag not set while CONFIG_UART_ISR_IN_IRAM is enabled, flag updated
|
||||
Note: esp_netif_init() has been called. Until next reset, TCP/IP task will periodicially allocate memory and consume CPU time.
|
||||
I (28602) uart: ESP_INTR_FLAG_IRAM flag not set while CONFIG_UART_ISR_IN_IRAM is enabled, flag updated
|
||||
I (28612) uart: queue free spaces: 16
|
||||
I (28612) uart: ESP_INTR_FLAG_IRAM flag not set while CONFIG_UART_ISR_IN_IRAM is enabled, flag updated
|
||||
I (28622) uart: queue free spaces: 16
|
||||
I (28642) esp-netif_lwip-ppp: Connected
|
||||
I (28642) esp-netif_lwip-ppp: Connected
|
||||
I (28642) test: Got IPv4 event: Interface "pppos_server(EPPP0)" address: 192.168.11.1
|
||||
I (28642) esp-netif_lwip-ppp: Connected
|
||||
I (28652) test: Got IPv4 event: Interface "pppos_client(EPPP1)" address: 192.168.11.2
|
||||
I (28662) esp-netif_lwip-ppp: Connected
|
||||
64bytes from 192.168.11.2 icmp_seq=1 ttl=255 time=93 ms
|
||||
64bytes from 192.168.11.2 icmp_seq=2 ttl=255 time=98 ms
|
||||
64bytes from 192.168.11.2 icmp_seq=3 ttl=255 time=99 ms
|
||||
64bytes from 192.168.11.2 icmp_seq=4 ttl=255 time=99 ms
|
||||
64bytes from 192.168.11.2 icmp_seq=5 ttl=255 time=99 ms
|
||||
5 packets transmitted, 5 received, time 488ms
|
||||
I (29162) esp-netif_lwip-ppp: User interrupt
|
||||
I (29162) test: Disconnected interface "pppos_client(EPPP1)"
|
||||
I (29172) esp-netif_lwip-ppp: User interrupt
|
||||
I (29172) test: Disconnected interface "pppos_server(EPPP0)"
|
||||
MALLOC_CAP_8BIT usage: Free memory delta: 0 Leak threshold: -64
|
||||
MALLOC_CAP_32BIT usage: Free memory delta: 0 Leak threshold: -64
|
||||
PASS
|
||||
```
|
4
components/eppp_link/test/test_app/main/CMakeLists.txt
Normal file
4
components/eppp_link/test/test_app/main/CMakeLists.txt
Normal file
@ -0,0 +1,4 @@
|
||||
idf_component_register(SRCS app_main.c
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES test_utils
|
||||
PRIV_REQUIRES unity nvs_flash esp_netif driver esp_event)
|
344
components/eppp_link/test/test_app/main/app_main.c
Normal file
344
components/eppp_link/test/test_app/main/app_main.c
Normal file
@ -0,0 +1,344 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "esp_system.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_netif.h"
|
||||
#include "esp_netif_ppp.h"
|
||||
#include "eppp_link.h"
|
||||
#include "lwip/sockets.h"
|
||||
#include "esp_log.h"
|
||||
#include "ping/ping_sock.h"
|
||||
#include "driver/uart.h"
|
||||
#include "test_utils.h"
|
||||
#include "unity.h"
|
||||
#include "test_utils.h"
|
||||
#include "unity_fixture.h"
|
||||
#include "memory_checks.h"
|
||||
#include "lwip/sys.h"
|
||||
|
||||
#define CLIENT_INFO_CONNECTED BIT0
|
||||
#define CLIENT_INFO_DISCONNECT BIT1
|
||||
#define CLIENT_INFO_CLOSED BIT2
|
||||
#define PING_SUCCEEDED BIT3
|
||||
#define PING_FAILED BIT4
|
||||
#define STOP_WORKER_TASK BIT5
|
||||
#define WORKER_TASK_STOPPED BIT6
|
||||
|
||||
TEST_GROUP(eppp_test);
|
||||
TEST_SETUP(eppp_test)
|
||||
{
|
||||
// Perform some open/close operations to disregard lazy init one-time allocations
|
||||
// LWIP: core protection mutex
|
||||
sys_arch_protect();
|
||||
sys_arch_unprotect(0);
|
||||
// UART: install and delete both drivers to disregard potential leak in allocated interrupt slot
|
||||
TEST_ESP_OK(uart_driver_install(UART_NUM_1, 256, 0, 0, NULL, 0));
|
||||
TEST_ESP_OK(uart_driver_delete(UART_NUM_1));
|
||||
TEST_ESP_OK(uart_driver_install(UART_NUM_2, 256, 0, 0, NULL, 0));
|
||||
TEST_ESP_OK(uart_driver_delete(UART_NUM_2));
|
||||
// PING: used for timestamps
|
||||
struct timeval time;
|
||||
gettimeofday(&time, NULL);
|
||||
|
||||
test_utils_record_free_mem();
|
||||
TEST_ESP_OK(test_utils_set_leak_level(0, ESP_LEAK_TYPE_CRITICAL, ESP_COMP_LEAK_GENERAL));
|
||||
}
|
||||
|
||||
TEST_TEAR_DOWN(eppp_test)
|
||||
{
|
||||
test_utils_finish_and_evaluate_leaks(32, 64);
|
||||
}
|
||||
|
||||
static void test_on_ping_end(esp_ping_handle_t hdl, void *args)
|
||||
{
|
||||
EventGroupHandle_t event = args;
|
||||
uint32_t transmitted;
|
||||
uint32_t received;
|
||||
uint32_t total_time_ms;
|
||||
esp_ping_get_profile(hdl, ESP_PING_PROF_REQUEST, &transmitted, sizeof(transmitted));
|
||||
esp_ping_get_profile(hdl, ESP_PING_PROF_REPLY, &received, sizeof(received));
|
||||
esp_ping_get_profile(hdl, ESP_PING_PROF_DURATION, &total_time_ms, sizeof(total_time_ms));
|
||||
printf("%" PRId32 " packets transmitted, %" PRId32 " received, time %" PRId32 "ms\n", transmitted, received, total_time_ms);
|
||||
if (transmitted == received) {
|
||||
xEventGroupSetBits(event, PING_SUCCEEDED);
|
||||
} else {
|
||||
xEventGroupSetBits(event, PING_FAILED);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_on_ping_success(esp_ping_handle_t hdl, void *args)
|
||||
{
|
||||
uint8_t ttl;
|
||||
uint16_t seqno;
|
||||
uint32_t elapsed_time, recv_len;
|
||||
ip_addr_t target_addr;
|
||||
esp_ping_get_profile(hdl, ESP_PING_PROF_SEQNO, &seqno, sizeof(seqno));
|
||||
esp_ping_get_profile(hdl, ESP_PING_PROF_TTL, &ttl, sizeof(ttl));
|
||||
esp_ping_get_profile(hdl, ESP_PING_PROF_IPADDR, &target_addr, sizeof(target_addr));
|
||||
esp_ping_get_profile(hdl, ESP_PING_PROF_SIZE, &recv_len, sizeof(recv_len));
|
||||
esp_ping_get_profile(hdl, ESP_PING_PROF_TIMEGAP, &elapsed_time, sizeof(elapsed_time));
|
||||
printf("%" PRId32 "bytes from %s icmp_seq=%d ttl=%d time=%" PRId32 " ms\n",
|
||||
recv_len, inet_ntoa(target_addr.u_addr.ip4), seqno, ttl, elapsed_time);
|
||||
}
|
||||
|
||||
struct client_info {
|
||||
esp_netif_t *netif;
|
||||
EventGroupHandle_t event;
|
||||
};
|
||||
|
||||
static void open_client_task(void *ctx)
|
||||
{
|
||||
struct client_info *info = ctx;
|
||||
eppp_config_t config = EPPP_DEFAULT_CLIENT_CONFIG();
|
||||
config.uart.port = UART_NUM_2;
|
||||
config.uart.tx_io = 4;
|
||||
config.uart.rx_io = 5;
|
||||
|
||||
info->netif = eppp_connect(&config);
|
||||
xEventGroupSetBits(info->event, CLIENT_INFO_CONNECTED);
|
||||
|
||||
// wait for disconnection trigger
|
||||
EventBits_t bits = xEventGroupWaitBits(info->event, CLIENT_INFO_DISCONNECT, pdFALSE, pdFALSE, pdMS_TO_TICKS(50000));
|
||||
TEST_ASSERT_EQUAL(bits & CLIENT_INFO_DISCONNECT, CLIENT_INFO_DISCONNECT);
|
||||
eppp_close(info->netif);
|
||||
xEventGroupSetBits(info->event, CLIENT_INFO_CLOSED);
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
TEST(eppp_test, init_deinit)
|
||||
{
|
||||
// Init and deinit server size
|
||||
eppp_config_t config = EPPP_DEFAULT_CONFIG(0, 0);
|
||||
esp_netif_t *netif = eppp_init(EPPP_SERVER, &config);
|
||||
TEST_ASSERT_NOT_NULL(netif);
|
||||
eppp_deinit(netif);
|
||||
netif = NULL;
|
||||
// Init and deinit client size
|
||||
netif = eppp_init(EPPP_CLIENT, &config);
|
||||
TEST_ASSERT_NOT_NULL(netif);
|
||||
eppp_deinit(netif);
|
||||
}
|
||||
|
||||
static EventBits_t ping_test(uint32_t addr, esp_netif_t *netif, EventGroupHandle_t event)
|
||||
{
|
||||
ip_addr_t target_addr = { .type = IPADDR_TYPE_V4, .u_addr.ip4.addr = addr };
|
||||
esp_ping_config_t ping_config = ESP_PING_DEFAULT_CONFIG();
|
||||
ping_config.interval_ms = 100;
|
||||
ping_config.target_addr = target_addr;
|
||||
ping_config.interface = esp_netif_get_netif_impl_index(netif);
|
||||
esp_ping_callbacks_t cbs = { .cb_args = event, .on_ping_end = test_on_ping_end, .on_ping_success = test_on_ping_success };
|
||||
esp_ping_handle_t ping;
|
||||
esp_ping_new_session(&ping_config, &cbs, &ping);
|
||||
esp_ping_start(ping);
|
||||
// Wait for the client thread closure and delete locally created objects
|
||||
EventBits_t bits = xEventGroupWaitBits(event, PING_SUCCEEDED | PING_FAILED, pdFALSE, pdFALSE, pdMS_TO_TICKS(50000));
|
||||
TEST_ASSERT_EQUAL(bits & (PING_SUCCEEDED | PING_FAILED), PING_SUCCEEDED);
|
||||
esp_ping_stop(ping);
|
||||
esp_ping_delete_session(ping);
|
||||
return bits;
|
||||
}
|
||||
|
||||
TEST(eppp_test, open_close)
|
||||
{
|
||||
test_case_uses_tcpip();
|
||||
|
||||
eppp_config_t config = EPPP_DEFAULT_SERVER_CONFIG();
|
||||
struct client_info client = { .netif = NULL, .event = xEventGroupCreate()};
|
||||
|
||||
TEST_ESP_OK(esp_event_loop_create_default());
|
||||
|
||||
TEST_ASSERT_NOT_NULL(client.event);
|
||||
|
||||
// Need to connect the client in a separate thread, as the simplified API blocks until connection
|
||||
xTaskCreate(open_client_task, "client_task", 4096, &client, 5, NULL);
|
||||
|
||||
// Now start the server
|
||||
esp_netif_t *eppp_server = eppp_listen(&config);
|
||||
|
||||
// Wait for the client to connect
|
||||
EventBits_t bits = xEventGroupWaitBits(client.event, CLIENT_INFO_CONNECTED, pdFALSE, pdFALSE, pdMS_TO_TICKS(50000));
|
||||
TEST_ASSERT_EQUAL(bits & CLIENT_INFO_CONNECTED, CLIENT_INFO_CONNECTED);
|
||||
|
||||
// Check that both server and client are valid netif pointers
|
||||
TEST_ASSERT_NOT_NULL(eppp_server);
|
||||
TEST_ASSERT_NOT_NULL(client.netif);
|
||||
|
||||
// Now that we're connected, let's try to ping clients address
|
||||
bits = ping_test(config.ppp.their_ip4_addr.addr, eppp_server, client.event);
|
||||
TEST_ASSERT_EQUAL(bits & (PING_SUCCEEDED | PING_FAILED), PING_SUCCEEDED);
|
||||
|
||||
// Trigger client disconnection and close the server
|
||||
xEventGroupSetBits(client.event, CLIENT_INFO_DISCONNECT);
|
||||
eppp_close(eppp_server);
|
||||
|
||||
// Wait for the client thread closure and delete locally created objects
|
||||
bits = xEventGroupWaitBits(client.event, CLIENT_INFO_CLOSED, pdFALSE, pdFALSE, pdMS_TO_TICKS(50000));
|
||||
TEST_ASSERT_EQUAL(bits & CLIENT_INFO_CLOSED, CLIENT_INFO_CLOSED);
|
||||
|
||||
TEST_ESP_OK(esp_event_loop_delete_default());
|
||||
vEventGroupDelete(client.event);
|
||||
|
||||
// wait for the lwip sockets to close cleanly
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
}
|
||||
|
||||
static void on_event(void *arg, esp_event_base_t base, int32_t event_id, void *data)
|
||||
{
|
||||
EventGroupHandle_t event = arg;
|
||||
if (base == IP_EVENT && event_id == IP_EVENT_PPP_GOT_IP) {
|
||||
ip_event_got_ip_t *e = (ip_event_got_ip_t *)data;
|
||||
esp_netif_t *netif = e->esp_netif;
|
||||
ESP_LOGI("test", "Got IPv4 event: Interface \"%s(%s)\" address: " IPSTR, esp_netif_get_desc(netif),
|
||||
esp_netif_get_ifkey(netif), IP2STR(&e->ip_info.ip));
|
||||
if (strcmp("pppos_server", esp_netif_get_desc(netif)) == 0) {
|
||||
xEventGroupSetBits(event, 1 << EPPP_SERVER);
|
||||
} else if (strcmp("pppos_client", esp_netif_get_desc(netif)) == 0) {
|
||||
xEventGroupSetBits(event, 1 << EPPP_CLIENT);
|
||||
}
|
||||
} else if (base == NETIF_PPP_STATUS && event_id == NETIF_PPP_ERRORUSER) {
|
||||
esp_netif_t **netif = data;
|
||||
ESP_LOGI("test", "Disconnected interface \"%s(%s)\"", esp_netif_get_desc(*netif), esp_netif_get_ifkey(*netif));
|
||||
if (strcmp("pppos_server", esp_netif_get_desc(*netif)) == 0) {
|
||||
xEventGroupSetBits(event, 1 << EPPP_SERVER);
|
||||
} else if (strcmp("pppos_client", esp_netif_get_desc(*netif)) == 0) {
|
||||
xEventGroupSetBits(event, 1 << EPPP_CLIENT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(eppp_test, open_close_nonblocking)
|
||||
{
|
||||
test_case_uses_tcpip();
|
||||
EventGroupHandle_t event = xEventGroupCreate();
|
||||
|
||||
eppp_config_t server_config = EPPP_DEFAULT_SERVER_CONFIG();
|
||||
TEST_ESP_OK(esp_event_loop_create_default());
|
||||
|
||||
// Open the server size
|
||||
TEST_ESP_OK(esp_event_handler_register(IP_EVENT, ESP_EVENT_ANY_ID, on_event, event));
|
||||
esp_netif_t *eppp_server = eppp_open(EPPP_SERVER, &server_config, 0);
|
||||
TEST_ASSERT_NOT_NULL(eppp_server);
|
||||
// Open the client size
|
||||
eppp_config_t client_config = EPPP_DEFAULT_SERVER_CONFIG();
|
||||
client_config.uart.port = UART_NUM_2;
|
||||
client_config.uart.tx_io = 4;
|
||||
client_config.uart.rx_io = 5;
|
||||
esp_netif_t *eppp_client = eppp_open(EPPP_CLIENT, &client_config, 0);
|
||||
TEST_ASSERT_NOT_NULL(eppp_client);
|
||||
const EventBits_t wait_bits = (1 << EPPP_SERVER) | (1 << EPPP_CLIENT);
|
||||
EventBits_t bits = xEventGroupWaitBits(event, wait_bits, pdTRUE, pdTRUE, pdMS_TO_TICKS(50000));
|
||||
TEST_ASSERT_EQUAL(bits & wait_bits, wait_bits);
|
||||
|
||||
// Now that we're connected, let's try to ping clients address
|
||||
bits = ping_test(server_config.ppp.their_ip4_addr.addr, eppp_server, event);
|
||||
TEST_ASSERT_EQUAL(bits & (PING_SUCCEEDED | PING_FAILED), PING_SUCCEEDED);
|
||||
|
||||
// stop network for both client and server
|
||||
eppp_netif_stop(eppp_client, 0); // ignore result, since we're not waiting for clean close
|
||||
eppp_close(eppp_server);
|
||||
eppp_close(eppp_client); // finish client close
|
||||
TEST_ESP_OK(esp_event_loop_delete_default());
|
||||
vEventGroupDelete(event);
|
||||
|
||||
// wait for the lwip sockets to close cleanly
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
}
|
||||
|
||||
|
||||
struct worker {
|
||||
esp_netif_t *eppp_server;
|
||||
esp_netif_t *eppp_client;
|
||||
EventGroupHandle_t event;
|
||||
};
|
||||
|
||||
static void worker_task(void *ctx)
|
||||
{
|
||||
struct worker *info = ctx;
|
||||
while (1) {
|
||||
eppp_perform(info->eppp_server);
|
||||
eppp_perform(info->eppp_client);
|
||||
if (xEventGroupGetBits(info->event) & STOP_WORKER_TASK) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
xEventGroupSetBits(info->event, WORKER_TASK_STOPPED);
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
TEST(eppp_test, open_close_taskless)
|
||||
{
|
||||
test_case_uses_tcpip();
|
||||
struct worker info = { .event = xEventGroupCreate() };
|
||||
|
||||
TEST_ESP_OK(esp_event_loop_create_default());
|
||||
TEST_ESP_OK(esp_event_handler_register(IP_EVENT, ESP_EVENT_ANY_ID, on_event, info.event));
|
||||
TEST_ESP_OK(esp_event_handler_register(NETIF_PPP_STATUS, ESP_EVENT_ANY_ID, on_event, info.event));
|
||||
|
||||
// Create server
|
||||
eppp_config_t server_config = EPPP_DEFAULT_SERVER_CONFIG();
|
||||
info.eppp_server = eppp_init(EPPP_SERVER, &server_config);
|
||||
TEST_ASSERT_NOT_NULL(info.eppp_server);
|
||||
// Create client
|
||||
eppp_config_t client_config = EPPP_DEFAULT_CLIENT_CONFIG();
|
||||
client_config.uart.port = UART_NUM_2;
|
||||
client_config.uart.tx_io = 4;
|
||||
client_config.uart.rx_io = 5;
|
||||
info.eppp_client = eppp_init(EPPP_CLIENT, &client_config);
|
||||
TEST_ASSERT_NOT_NULL(info.eppp_client);
|
||||
// Start workers
|
||||
xTaskCreate(worker_task, "worker", 4096, &info, 5, NULL);
|
||||
// Start network
|
||||
TEST_ESP_OK(eppp_netif_start(info.eppp_server));
|
||||
TEST_ESP_OK(eppp_netif_start(info.eppp_client));
|
||||
|
||||
const EventBits_t wait_bits = (1 << EPPP_SERVER) | (1 << EPPP_CLIENT);
|
||||
EventBits_t bits = xEventGroupWaitBits(info.event, wait_bits, pdTRUE, pdTRUE, pdMS_TO_TICKS(50000));
|
||||
TEST_ASSERT_EQUAL(bits & wait_bits, wait_bits);
|
||||
xEventGroupClearBits(info.event, wait_bits);
|
||||
|
||||
// Now that we're connected, let's try to ping clients address
|
||||
bits = ping_test(server_config.ppp.their_ip4_addr.addr, info.eppp_server, info.event);
|
||||
TEST_ASSERT_EQUAL(bits & (PING_SUCCEEDED | PING_FAILED), PING_SUCCEEDED);
|
||||
|
||||
// stop network for both client and server, we won't wait for completion so expecting ESP_FAIL
|
||||
TEST_ASSERT_EQUAL(eppp_netif_stop(info.eppp_client, 0), ESP_FAIL);
|
||||
TEST_ASSERT_EQUAL(eppp_netif_stop(info.eppp_server, 0), ESP_FAIL);
|
||||
// and wait for completion
|
||||
bits = xEventGroupWaitBits(info.event, wait_bits, pdTRUE, pdTRUE, pdMS_TO_TICKS(50000));
|
||||
TEST_ASSERT_EQUAL(bits & wait_bits, wait_bits);
|
||||
|
||||
// now stop the worker
|
||||
xEventGroupSetBits(info.event, STOP_WORKER_TASK);
|
||||
bits = xEventGroupWaitBits(info.event, WORKER_TASK_STOPPED, pdTRUE, pdTRUE, pdMS_TO_TICKS(50000));
|
||||
TEST_ASSERT_EQUAL(bits & WORKER_TASK_STOPPED, WORKER_TASK_STOPPED);
|
||||
|
||||
// and destroy objects
|
||||
eppp_deinit(info.eppp_server);
|
||||
eppp_deinit(info.eppp_client);
|
||||
TEST_ESP_OK(esp_event_loop_delete_default());
|
||||
vEventGroupDelete(info.event);
|
||||
|
||||
// wait for the lwip sockets to close cleanly
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
}
|
||||
|
||||
|
||||
TEST_GROUP_RUNNER(eppp_test)
|
||||
{
|
||||
RUN_TEST_CASE(eppp_test, init_deinit)
|
||||
RUN_TEST_CASE(eppp_test, open_close)
|
||||
RUN_TEST_CASE(eppp_test, open_close_nonblocking)
|
||||
RUN_TEST_CASE(eppp_test, open_close_taskless)
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
UNITY_MAIN(eppp_test);
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
dependencies:
|
||||
espressif/eppp_link:
|
||||
version: "*"
|
||||
override_path: "../../.."
|
9
components/eppp_link/test/test_app/sdkconfig.defaults
Normal file
9
components/eppp_link/test/test_app/sdkconfig.defaults
Normal file
@ -0,0 +1,9 @@
|
||||
CONFIG_IDF_TARGET="esp32"
|
||||
CONFIG_UART_ISR_IN_IRAM=y
|
||||
CONFIG_ESP_NETIF_IP_LOST_TIMER_INTERVAL=0
|
||||
CONFIG_FREERTOS_UNICORE=y
|
||||
CONFIG_LWIP_PPP_SUPPORT=y
|
||||
CONFIG_LWIP_PPP_SERVER_SUPPORT=y
|
||||
CONFIG_LWIP_PPP_VJ_HEADER_COMPRESSION=n
|
||||
CONFIG_LWIP_PPP_DEBUG_ON=y
|
||||
CONFIG_UNITY_ENABLE_FIXTURE=y
|
@ -3,6 +3,6 @@ commitizen:
|
||||
bump_message: 'bump(modem): $current_version -> $new_version'
|
||||
pre_bump_hooks: python ../../ci/changelog.py esp_modem
|
||||
tag_format: modem-v$version
|
||||
version: 1.0.5
|
||||
version: 1.1.0
|
||||
version_files:
|
||||
- idf_component.yml
|
||||
|
@ -1,5 +1,28 @@
|
||||
# Changelog
|
||||
|
||||
## [1.1.0](https://github.com/espressif/esp-protocols/commits/modem-v1.1.0)
|
||||
|
||||
### Features
|
||||
|
||||
- Added support for at_raw() command ([ae38110](https://github.com/espressif/esp-protocols/commit/ae38110), [#471](https://github.com/espressif/esp-protocols/issues/471))
|
||||
- Added iperf test for PPP netifs ([976e98d](https://github.com/espressif/esp-protocols/commit/976e98d))
|
||||
- Added test that performs OTA to exercise modem layers ([f2223dd](https://github.com/espressif/esp-protocols/commit/f2223dd))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Fixed OTA test to gracefully fail with no verification ([1dc4299](https://github.com/espressif/esp-protocols/commit/1dc4299))
|
||||
- Added C-API to configure APN ([ce7dadd](https://github.com/espressif/esp-protocols/commit/ce7dadd), [#485](https://github.com/espressif/esp-protocols/issues/485))
|
||||
- Fixed AT commands to copy strings to prevent overrides ([741d166](https://github.com/espressif/esp-protocols/commit/741d166), [#463](https://github.com/espressif/esp-protocols/issues/463))
|
||||
- Fixed incorrect dial command format ([0998f3d](https://github.com/espressif/esp-protocols/commit/0998f3d), [#433](https://github.com/espressif/esp-protocols/issues/433))
|
||||
- Fixed documentation and example on creating custom device ([577de67](https://github.com/espressif/esp-protocols/commit/577de67), [#452](https://github.com/espressif/esp-protocols/issues/452))
|
||||
- Removed CI jobs for IDF v4.2 ([d88cd61](https://github.com/espressif/esp-protocols/commit/d88cd61))
|
||||
- Fixed OAT test to verify server cert and CN ([edc3e72](https://github.com/espressif/esp-protocols/commit/edc3e72))
|
||||
- Fixed set_pdp_context() command timeout ([1d80cbc](https://github.com/espressif/esp-protocols/commit/1d80cbc), [#455](https://github.com/espressif/esp-protocols/issues/455))
|
||||
|
||||
### Updated
|
||||
|
||||
- docs(modem): Added description of manual test procedure ([68ce794](https://github.com/espressif/esp-protocols/commit/68ce794))
|
||||
|
||||
## [1.0.5](https://github.com/espressif/esp-protocols/commits/modem-v1.0.5)
|
||||
|
||||
### Major changes
|
||||
|
@ -45,8 +45,3 @@ set_target_properties(${COMPONENT_LIB} PROPERTIES
|
||||
if(CONFIG_ESP_MODEM_ADD_CUSTOM_MODULE)
|
||||
idf_component_optional_requires(PUBLIC main)
|
||||
endif()
|
||||
|
||||
if(${target} STREQUAL "linux")
|
||||
# This is needed for ESP_LOGx() macros, as integer formats differ on ESP32(..) and x64
|
||||
set_target_properties(${COMPONENT_LIB} PROPERTIES COMPILE_FLAGS -Wno-format)
|
||||
endif()
|
||||
|
@ -22,8 +22,7 @@ using namespace esp_modem;
|
||||
|
||||
[[maybe_unused]] constexpr auto TAG = "linux_modem_main";
|
||||
|
||||
|
||||
int main()
|
||||
extern "C" void app_main(void)
|
||||
{
|
||||
// init the DTE
|
||||
esp_modem_dte_config_t dte_config = {
|
||||
|
@ -63,26 +63,6 @@ menu "Example Configuration"
|
||||
help
|
||||
Set APN (Access Point Name), a logical name to choose data network
|
||||
|
||||
config EXAMPLE_MODEM_PPP_AUTH_USERNAME
|
||||
string "Set username for authentication"
|
||||
default "espressif"
|
||||
depends on !EXAMPLE_MODEM_PPP_AUTH_NONE
|
||||
help
|
||||
Set username for PPP Authentication.
|
||||
|
||||
config EXAMPLE_MODEM_PPP_AUTH_PASSWORD
|
||||
string "Set password for authentication"
|
||||
default "esp32"
|
||||
depends on !EXAMPLE_MODEM_PPP_AUTH_NONE
|
||||
help
|
||||
Set password for PPP Authentication.
|
||||
|
||||
config EXAMPLE_MODEM_PPP_AUTH_NONE
|
||||
bool "Skip PPP authentication"
|
||||
default n
|
||||
help
|
||||
Set to true for the PPP client to skip authentication
|
||||
|
||||
config EXAMPLE_SEND_MSG
|
||||
bool "Short message (SMS)"
|
||||
default n
|
||||
|
@ -49,7 +49,7 @@ std::unique_ptr<DCE_gnss> create_SIM7070_GNSS_dce(const esp_modem::dce_config *c
|
||||
return gnss_factory::LocalFactory::create(config, std::move(dte), netif);
|
||||
}
|
||||
|
||||
esp_modem::command_result get_gnss_information_sim70xx_lib(esp_modem::CommandableIf *t, esp_modem_gps_t &gps)
|
||||
esp_modem::command_result get_gnss_information_sim70xx_lib(esp_modem::CommandableIf *t, sim70xx_gps_t &gps)
|
||||
{
|
||||
|
||||
ESP_LOGV(TAG, "%s", __func__ );
|
||||
@ -67,24 +67,26 @@ esp_modem::command_result get_gnss_information_sim70xx_lib(esp_modem::Commandabl
|
||||
}
|
||||
/**
|
||||
* Parsing +CGNSINF:
|
||||
* <GNSS run status>,
|
||||
* <Fix status>,
|
||||
* <UTC date & Time>,
|
||||
* <Latitude>,
|
||||
* <Longitude>,
|
||||
* <MSL Altitude>,
|
||||
* <Speed Over Ground>,
|
||||
* <Course Over Ground>,
|
||||
* <Fix Mode>,
|
||||
* <Reserved1>,
|
||||
* <HDOP>,
|
||||
* <PDOP>,
|
||||
* <VDOP>,
|
||||
* <Reserved2>,
|
||||
* <GNSS Satellites in View>,
|
||||
* <Reserved3>,
|
||||
* <HPA>,
|
||||
* <VPA>
|
||||
| **Index** | **Parameter** | **Unit** | **Range** | **Length** |
|
||||
|-----------|------------------------|--------------------|--------------------------------------------------------------------------------------|------------|
|
||||
| 1 | GNSS run status | -- | 0-1 | 1 |
|
||||
| 2 | Fix status | -- | 0-1 | 1 |
|
||||
| 3 | UTC date & Time | yyyyMMddhhmmss.sss | yyyy: [1980,2039] MM : [1,12] dd: [1,31] hh: [0,23] mm: [0,59] ss.sss:[0.000,60.999] | 18 |
|
||||
| 4 | Latitude | ±dd.dddddd | [-90.000000,90.000000] | 10 |
|
||||
| 5 | Longitude | ±dd.dddddd | -180.000000,180.000000] | 11 |
|
||||
| 6 | MSL Altitude | meters | [0,999.99] | 8 |
|
||||
| 7 | Speed Over Ground | Km/hour | [0,360.00] | 6 |
|
||||
| 8 | Course Over Ground | degrees | 0,1,2[1] | 6 |
|
||||
| 9 | Fix Mode | -- | | 1 |
|
||||
| 10 | Reserved1 | | | 0 |
|
||||
| 11 | HDOP | -- | [0,99.9] | 4 |
|
||||
| 12 | PDOP | -- | [0,99.9] | 4 |
|
||||
| 13 | VDOP | -- | [0,99.9] | 4 |
|
||||
| 14 | Reserved2 | | | 0 |
|
||||
| 15 | GPS Satellites in View | -- | -- [0,99] | 2 |
|
||||
| 16 | Reserved3 | | | 0 |
|
||||
| 17 | HPA[2] | meters | [0,9999.9] | 6 |
|
||||
| 18 | VPA[2] | meters | [0,9999.9] | 6 |
|
||||
*/
|
||||
out = out.substr(pattern.size());
|
||||
int pos = 0;
|
||||
@ -291,11 +293,11 @@ esp_modem::command_result get_gnss_information_sim70xx_lib(esp_modem::Commandabl
|
||||
{
|
||||
std::string_view sats_in_view = out.substr(0, pos);
|
||||
if (sats_in_view.length() > 1) {
|
||||
if (std::from_chars(out.data(), out.data() + pos, gps.sats_in_view).ec == std::errc::invalid_argument) {
|
||||
if (std::from_chars(out.data(), out.data() + pos, gps.sat.num).ec == std::errc::invalid_argument) {
|
||||
return esp_modem::command_result::FAIL;
|
||||
}
|
||||
} else {
|
||||
gps.sats_in_view = 0;
|
||||
gps.sat.num = 0;
|
||||
}
|
||||
} //clean up sats_in_view
|
||||
|
||||
@ -330,12 +332,12 @@ esp_modem::command_result get_gnss_information_sim70xx_lib(esp_modem::Commandabl
|
||||
return esp_modem::command_result::OK;
|
||||
}
|
||||
|
||||
esp_modem::command_result SIM7070_gnss::get_gnss_information_sim70xx(esp_modem_gps_t &gps)
|
||||
esp_modem::command_result SIM7070_gnss::get_gnss_information_sim70xx(sim70xx_gps_t &gps)
|
||||
{
|
||||
return get_gnss_information_sim70xx_lib(dte.get(), gps);
|
||||
}
|
||||
|
||||
esp_modem::command_result DCE_gnss::get_gnss_information_sim70xx(esp_modem_gps_t &gps)
|
||||
esp_modem::command_result DCE_gnss::get_gnss_information_sim70xx(sim70xx_gps_t &gps)
|
||||
{
|
||||
return device->get_gnss_information_sim70xx(gps);
|
||||
}
|
||||
|
@ -13,7 +13,7 @@
|
||||
|
||||
#include "cxx_include/esp_modem_dce_factory.hpp"
|
||||
#include "cxx_include/esp_modem_dce_module.hpp"
|
||||
#include "nmea_parser.h"
|
||||
#include "sim70xx_gps.h"
|
||||
|
||||
/**
|
||||
* @brief Definition of a custom SIM7070 class with GNSS capabilities.
|
||||
@ -23,7 +23,7 @@
|
||||
class SIM7070_gnss: public esp_modem::SIM7070 {
|
||||
using SIM7070::SIM7070;
|
||||
public:
|
||||
esp_modem::command_result get_gnss_information_sim70xx(esp_modem_gps_t &gps);
|
||||
esp_modem::command_result get_gnss_information_sim70xx(sim70xx_gps_t &gps);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -47,7 +47,7 @@ public:
|
||||
|
||||
#undef ESP_MODEM_DECLARE_DCE_COMMAND
|
||||
|
||||
esp_modem::command_result get_gnss_information_sim70xx(esp_modem_gps_t &gps);
|
||||
esp_modem::command_result get_gnss_information_sim70xx(sim70xx_gps_t &gps);
|
||||
|
||||
};
|
||||
|
||||
|
@ -17,7 +17,6 @@ extern "C" {
|
||||
#define GPS_MAX_SATELLITES_IN_VIEW (16)
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief GPS fix type
|
||||
*
|
||||
@ -53,9 +52,6 @@ typedef enum {
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t num; /*!< Satellite number */
|
||||
uint8_t elevation; /*!< Satellite elevation */
|
||||
uint16_t azimuth; /*!< Satellite azimuth */
|
||||
uint8_t snr; /*!< Satellite signal noise ratio */
|
||||
} gps_satellite_t;
|
||||
|
||||
/**
|
||||
@ -79,54 +75,31 @@ typedef struct {
|
||||
uint16_t year; /*!< Year (start from 2000) */
|
||||
} gps_date_t;
|
||||
|
||||
/**
|
||||
* @brief NMEA Statement
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
STATEMENT_UNKNOWN = 0, /*!< Unknown statement */
|
||||
STATEMENT_GGA, /*!< GGA */
|
||||
STATEMENT_GSA, /*!< GSA */
|
||||
STATEMENT_RMC, /*!< RMC */
|
||||
STATEMENT_GSV, /*!< GSV */
|
||||
STATEMENT_GLL, /*!< GLL */
|
||||
STATEMENT_VTG /*!< VTG */
|
||||
} nmea_statement_t;
|
||||
|
||||
/**
|
||||
* @brief GPS object
|
||||
*
|
||||
*/
|
||||
struct esp_modem_gps {
|
||||
struct sim70xx_gps {
|
||||
gps_run_t run; /*!< run status */
|
||||
gps_fix_t fix; /*!< Fix status */
|
||||
gps_date_t date; /*!< Fix date */
|
||||
gps_time_t tim; /*!< time in UTC */
|
||||
float latitude; /*!< Latitude (degrees) */
|
||||
float longitude; /*!< Longitude (degrees) */
|
||||
float altitude; /*!< Altitude (meters) */
|
||||
gps_run_t run; /*!< run status */
|
||||
gps_fix_t fix; /*!< Fix status */
|
||||
uint8_t sats_in_use; /*!< Number of satellites in use */
|
||||
gps_time_t tim; /*!< time in UTC */
|
||||
float speed; /*!< Ground speed, unit: m/s */
|
||||
float cog; /*!< Course over ground */
|
||||
gps_fix_mode_t fix_mode; /*!< Fix mode */
|
||||
float dop_h; /*!< Horizontal dilution of precision */
|
||||
float dop_p; /*!< Position dilution of precision */
|
||||
float dop_v; /*!< Vertical dilution of precision */
|
||||
uint8_t sats_in_view; /*!< Number of satellites in view */
|
||||
gps_date_t date; /*!< Fix date */
|
||||
float speed; /*!< Ground speed, unit: m/s */
|
||||
float cog; /*!< Course over ground */
|
||||
gps_satellite_t sat; /*!< Number of satellites in view */
|
||||
float hpa; /*!< Horizontal Position Accuracy */
|
||||
float vpa; /*!< Vertical Position Accuracy */
|
||||
};
|
||||
|
||||
typedef struct esp_modem_gps esp_modem_gps_t;
|
||||
typedef struct sim70xx_gps sim70xx_gps_t;
|
||||
|
||||
/**
|
||||
* @brief NMEA Parser Event ID
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
GPS_UPDATE, /*!< GPS information has been updated */
|
||||
GPS_UNKNOWN /*!< Unknown statements detected */
|
||||
} nmea_event_id_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
version: "1.0.5"
|
||||
version: "1.1.0"
|
||||
description: Library for communicating with cellular modems in command and data modes
|
||||
url: https://github.com/espressif/esp-protocols/tree/master/components/esp_modem
|
||||
issues: https://github.com/espressif/esp-protocols/issues
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -119,8 +119,27 @@ esp_err_t esp_modem_set_error_cb(esp_modem_dce_t *dce, esp_modem_terminal_error_
|
||||
*/
|
||||
esp_err_t esp_modem_set_mode(esp_modem_dce_t *dce, esp_modem_dce_mode_t mode);
|
||||
|
||||
/**
|
||||
* @brief Convenient function to run arbitrary commands from C-API
|
||||
*
|
||||
* @param dce Modem DCE handle
|
||||
* @param command Command to send
|
||||
* @param got_line_cb Callback function which is called whenever we receive a line
|
||||
* @param timeout_ms Command timeout
|
||||
* @return ESP_OK on success, ESP_FAIL on failure
|
||||
*/
|
||||
|
||||
esp_err_t esp_modem_command(esp_modem_dce_t *dce, const char *command, esp_err_t(*got_line_cb)(uint8_t *data, size_t len), uint32_t timeout_ms);
|
||||
|
||||
/**
|
||||
* @brief Sets the APN and configures it into the modem's PDP context
|
||||
*
|
||||
* @param dce Modem DCE handle
|
||||
* @param apn Access Point Name
|
||||
* @return ESP_OK on success
|
||||
*/
|
||||
esp_err_t esp_modem_set_apn(esp_modem_dce_t *dce, const char *apn);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
@ -448,3 +448,10 @@ extern "C" esp_err_t esp_modem_set_baud(esp_modem_dce_t *dce_wrap, int baud)
|
||||
{
|
||||
return command_response_to_esp_err(dce_wrap->dce->set_baud(baud));
|
||||
}
|
||||
|
||||
extern "C" esp_err_t esp_modem_set_apn(esp_modem_dce_t *dce_wrap, const char *apn)
|
||||
{
|
||||
auto new_pdp = std::unique_ptr<PdpContext>(new PdpContext(apn));
|
||||
dce_wrap->dce->get_module()->configure_pdp_context(std::move(new_pdp));
|
||||
return ESP_OK;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -13,6 +13,12 @@
|
||||
|
||||
using namespace esp_modem;
|
||||
|
||||
#ifdef CONFIG_IDF_TARGET_LINUX
|
||||
#define PRIsize_t "lu"
|
||||
#else
|
||||
#define PRIsize_t "u"
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ESP_MODEM_CMUX_DEFRAGMENT_PAYLOAD
|
||||
/**
|
||||
* @brief Define this to defragment partially received data of CMUX payload
|
||||
@ -245,7 +251,7 @@ bool CMux::on_header(CMuxFrame &frame)
|
||||
|
||||
bool CMux::on_payload(CMuxFrame &frame)
|
||||
{
|
||||
ESP_LOGD("CMUX", "Payload frame: dlci:%02x type:%02x payload:%d available:%d", dlci, type, payload_len, frame.len);
|
||||
ESP_LOGD("CMUX", "Payload frame: dlci:%02x type:%02x payload:%" PRIsize_t " available:%" PRIsize_t, dlci, type, payload_len, frame.len);
|
||||
if (frame.len < payload_len) { // payload
|
||||
state = cmux_state::PAYLOAD;
|
||||
if (!data_available(frame.ptr, frame.len)) { // partial read
|
||||
@ -312,7 +318,7 @@ bool CMux::on_cmux_data(uint8_t *data, size_t actual_len)
|
||||
auto data_end = buffer.get() + buffer.size;
|
||||
data_to_read = payload_len + 2; // 2 -- CMUX protocol footer
|
||||
if (data + data_to_read >= data_end) {
|
||||
ESP_LOGW("CUMX", "Failed to defragment longer payload (payload=%d)", payload_len);
|
||||
ESP_LOGW("CUMX", "Failed to defragment longer payload (payload=%" PRIsize_t ")", payload_len);
|
||||
// If you experience this error, your device uses longer payloads while
|
||||
// the configured buffer is too small to defragment the payload properly.
|
||||
// To resolve this issue you can:
|
||||
|
47
components/esp_modem/test/README.md
Normal file
47
components/esp_modem/test/README.md
Normal file
@ -0,0 +1,47 @@
|
||||
# ESP-Modem Testing
|
||||
|
||||
This folder contains automated and manual tests for esp-modem component. Beside these tests, some jobs are executed in CI to exercise standard examples (please refer to the CI definition and CI related sdkconfigs in examples).
|
||||
|
||||
List of test projects:
|
||||
|
||||
* `host_test` -- esp_modem is build on host (linux), modem's terminal in mocked using Loobpack class which creates simple responders to AT and CMUX mode. This test is executed in CI.
|
||||
* `target` -- test executed on target with no modem device, just a pppd running on the test runner. This test is executed in CI.
|
||||
* `target_ota` -- Manual test which perform OTA over PPP.
|
||||
* `target_iperf` -- Manual test to measure data throughput via PPP.
|
||||
|
||||
## Manual testing
|
||||
|
||||
Prior to every `esp_modem` release, these manual tests must be executed and pass
|
||||
(IDF-9074 to move the manual tests to CI)
|
||||
|
||||
### `target_ota`
|
||||
|
||||
Make sure that the UART ISR is not in IRAM, so the error messages are expected in the log, but the ESP32 should recover and continue with downloading the image.
|
||||
|
||||
Perform the test for these devices
|
||||
* SIM7600 (CMUX mode)
|
||||
* BG96 (CMUX mode)
|
||||
* SIM7000 (PPP mode)
|
||||
* A7672 (CMUX mode -- the only device with 2 byte CMUX payload), so the test is expected to fail more often if (`CONFIG_ESP_MODEM_CMUX_DEFRAGMENT_PAYLOAD=y` && `CONFIG_ESP_MODEM_USE_INFLATABLE_BUFFER_IF_NEEDED=n` && dte_buffer < device max payload)
|
||||
* NetworkDCE -- no modem device, pppd (PPP mode)
|
||||
|
||||
Perform the test with these configurations:
|
||||
* CONFIG_TEST_USE_VFS_TERM (y/n)
|
||||
* CONFIG_ESP_HTTP_CLIENT_ENABLE_CUSTOM_TRANSPORT (y/n)
|
||||
* CONFIG_ESP_MODEM_CMUX_DEFRAGMENT_PAYLOAD (y/n)
|
||||
* CONFIG_ESP_MODEM_USE_INFLATABLE_BUFFER_IF_NEEDED (y/n)
|
||||
|
||||
**Criteria for passing the test**
|
||||
|
||||
The test should complete the download with maximum 1 retry (50% of OTA failure)
|
||||
In case of CMUX mode, we're trying to exit CMUX at the end of the test. This step might also fail for some devices, as the CMUX-exit is not supported on certain devices (when the final error message appears that the device failed to exit CMUX, we just verify the new image by reseting the ESP32)
|
||||
|
||||
### `target_iperf`
|
||||
|
||||
Run these 4 `iperf` configurations (either manually or using `pytest`):
|
||||
* tcp_tx_throughput
|
||||
* tcp_rx_throughput
|
||||
* udp_tx_throughput
|
||||
* udp_rx_throughput
|
||||
|
||||
And verify in all four cases the value is about 0.70 Mbps
|
@ -3,19 +3,14 @@
|
||||
idf_version=$1
|
||||
component=$2
|
||||
|
||||
if [[ "$idf_version" == "release-v4.3" ]] && [[ "$component" == "esp_modem" ]]; then
|
||||
lwip=lwip-2.1.2
|
||||
lwip_uri=http://download.savannah.nongnu.org/releases/lwip
|
||||
lwip_contrib=contrib-2.1.0
|
||||
lwip=lwip-2.1.2
|
||||
lwip_uri=http://download.savannah.nongnu.org/releases/lwip
|
||||
lwip_contrib=contrib-2.1.0
|
||||
|
||||
wget --no-verbose ${lwip_uri}/${lwip}.zip
|
||||
unzip -oq ${lwip}.zip
|
||||
wget --no-verbose ${lwip_uri}/${lwip_contrib}.zip
|
||||
unzip -oq ${lwip_contrib}.zip
|
||||
wget --no-verbose ${lwip_uri}/${lwip}.zip
|
||||
unzip -oq ${lwip}.zip
|
||||
wget --no-verbose ${lwip_uri}/${lwip_contrib}.zip
|
||||
unzip -oq ${lwip_contrib}.zip
|
||||
|
||||
apt-get update && apt-get install -y gcc-8 g++-8
|
||||
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-8 800 --slave /usr/bin/g++ g++ /usr/bin/g++-8
|
||||
rm /usr/bin/gcov && ln -s /usr/bin/gcov-8 /usr/bin/gcov
|
||||
export LWIP_PATH=`pwd`/$lwip
|
||||
export LWIP_CONTRIB_PATH=`pwd`/$lwip_contrib
|
||||
fi
|
||||
export LWIP_PATH=`pwd`/$lwip
|
||||
export LWIP_CONTRIB_PATH=`pwd`/$lwip_contrib
|
||||
|
@ -1,11 +1,12 @@
|
||||
idf_component_register(SRCS "test_modem.cpp" "LoopbackTerm.cpp"
|
||||
INCLUDE_DIRS "$ENV{IDF_PATH}/tools/catch"
|
||||
REQUIRES esp_modem)
|
||||
REQUIRES esp_modem WHOLE_ARCHIVE)
|
||||
|
||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
find_package(Threads REQUIRED)
|
||||
target_link_libraries(${COMPONENT_LIB} PRIVATE Threads::Threads)
|
||||
|
||||
target_link_libraries(${COMPONENT_LIB} PRIVATE Catch2WithMain)
|
||||
|
||||
set_target_properties(${COMPONENT_LIB} PROPERTIES
|
||||
CXX_STANDARD 17
|
||||
CXX_STANDARD_REQUIRED ON
|
||||
|
@ -0,0 +1,5 @@
|
||||
dependencies:
|
||||
espressif/catch2:
|
||||
version: '*'
|
||||
idf:
|
||||
version: ">=5.0"
|
@ -1,14 +1,16 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
#define CATCH_CONFIG_MAIN // This tells the catch header to generate a main
|
||||
#include <memory>
|
||||
#include <future>
|
||||
#include "catch.hpp"
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/catch_session.hpp>
|
||||
#include "cxx_include/esp_modem_api.hpp"
|
||||
#include "LoopbackTerm.h"
|
||||
#include <iostream>
|
||||
|
||||
using namespace esp_modem;
|
||||
|
||||
@ -346,3 +348,25 @@ TEST_CASE("CMUX manual mode transitions", "[esp_modem][transitions]")
|
||||
CHECK(dce->set_mode(esp_modem::modem_mode::UNDEF) == true); // Succeeds from any state
|
||||
|
||||
}
|
||||
|
||||
#define CATCH_CONFIG_RUNNER
|
||||
extern "C" int app_main(void)
|
||||
{
|
||||
// Define the argument count and arguments for Catch2, including JUnit reporting
|
||||
int argc = 5;
|
||||
const char *argv[] = {"esp_modem", "-r", "junit", "-o", "junit.xml", nullptr};
|
||||
|
||||
// Run the Catch2 session and store the result
|
||||
int result = Catch::Session().run(argc, argv);
|
||||
|
||||
// Use more descriptive error handling
|
||||
if (result != 0) {
|
||||
printf("Test failed with result %d.\n", result);
|
||||
} else {
|
||||
printf("All tests passed successfully.\n");
|
||||
}
|
||||
|
||||
// Check for the junit.xml file in the current working directory
|
||||
// Exit the application with the test result as the status code
|
||||
std::exit(result);
|
||||
}
|
||||
|
@ -35,6 +35,10 @@ bool manual_ota::begin()
|
||||
esp_transport_handle_t tcp = esp_transport_tcp_init();
|
||||
ssl_ = esp_transport_batch_tls_init(tcp, max_buffer_size_);
|
||||
http_.config_.transport = ssl_;
|
||||
if (http_.config_.cert_pem == nullptr || common_name_ == nullptr) {
|
||||
ESP_LOGE(TAG, "TLS with no verification is not supported");
|
||||
return fail();
|
||||
}
|
||||
if (!esp_transport_batch_set_ca_cert(ssl_, http_.config_.cert_pem, 0)) {
|
||||
return fail();
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ public:
|
||||
/**
|
||||
* @brief Set common name of the server to verify
|
||||
*/
|
||||
const char *common_name_;
|
||||
const char *common_name_{};
|
||||
/**
|
||||
* @brief Wrapper around the http client -- Please set the http config
|
||||
*/
|
||||
|
@ -3,6 +3,6 @@ commitizen:
|
||||
bump_message: 'bump(websocket): $current_version -> $new_version'
|
||||
pre_bump_hooks: python ../../ci/changelog.py esp_websocket_client
|
||||
tag_format: websocket-v$version
|
||||
version: 1.2.2
|
||||
version: 1.2.3
|
||||
version_files:
|
||||
- idf_component.yml
|
||||
|
@ -1,5 +1,25 @@
|
||||
# Changelog
|
||||
|
||||
## [1.2.3](https://github.com/espressif/esp-protocols/commits/websocket-v1.2.3)
|
||||
|
||||
### Features
|
||||
|
||||
- Expanded example to demonstrate the transfer over TLS ([0d0630ed76](https://github.com/espressif/esp-protocols/commit/0d0630ed76))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- fix esp_event dependency management ([1fb02a9a60](https://github.com/espressif/esp-protocols/commit/1fb02a9a60))
|
||||
- Skip warn on zero timeout and auto reconnect is disabled ([5b467cbf5c](https://github.com/espressif/esp-protocols/commit/5b467cbf5c))
|
||||
- Fixed to use int return value in Tx functions ([9c54b72e1f](https://github.com/espressif/esp-protocols/commit/9c54b72e1f))
|
||||
- Fixed Tx functions with DYNAMIC_BUFFER ([16174470ee](https://github.com/espressif/esp-protocols/commit/16174470ee))
|
||||
- added dependency checks, sdkconfig.defaults and refined README.md ([312982e4aa](https://github.com/espressif/esp-protocols/commit/312982e4aa))
|
||||
- Close websocket and dispatch event if server does not close within a reasonable amount of time. ([d85311880d](https://github.com/espressif/esp-protocols/commit/d85311880d))
|
||||
- Continue waiting for TCP connection to be closed ([2b092e0db4](https://github.com/espressif/esp-protocols/commit/2b092e0db4))
|
||||
|
||||
### Updated
|
||||
|
||||
- docs(websocket): Added README for websocket host example ([2f7c58259d](https://github.com/espressif/esp-protocols/commit/2f7c58259d))
|
||||
|
||||
## [1.2.2](https://github.com/espressif/esp-protocols/commits/websocket-v1.2.2)
|
||||
|
||||
### Bug Fixes
|
||||
|
@ -16,6 +16,6 @@ if(${IDF_TARGET} STREQUAL "linux")
|
||||
else()
|
||||
idf_component_register(SRCS "esp_websocket_client.c"
|
||||
INCLUDE_DIRS "include"
|
||||
REQUIRES lwip esp-tls tcp_transport http_parser
|
||||
PRIV_REQUIRES esp_timer esp_event)
|
||||
REQUIRES lwip esp-tls tcp_transport http_parser esp_event
|
||||
PRIV_REQUIRES esp_timer)
|
||||
endif()
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -550,9 +550,13 @@ static int esp_websocket_client_send_with_exact_opcode(esp_websocket_client_hand
|
||||
int ret = -1;
|
||||
int need_write = len;
|
||||
int wlen = 0, widx = 0;
|
||||
|
||||
bool contained_fin = opcode & WS_TRANSPORT_OPCODES_FIN;
|
||||
|
||||
if (esp_websocket_new_buf(client, true) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to setup tx buffer");
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (widx < len || opcode) { // allow for sending "current_opcode" only message with len==0
|
||||
if (need_write > client->buffer_size) {
|
||||
need_write = client->buffer_size;
|
||||
@ -629,7 +633,7 @@ esp_websocket_client_handle_t esp_websocket_client_init(const esp_websocket_clie
|
||||
ESP_WS_CLIENT_MEM_CHECK(TAG, client->config->scheme, goto _websocket_init_fail);
|
||||
}
|
||||
|
||||
if (config->reconnect_timeout_ms <= 0) {
|
||||
if (!config->disable_auto_reconnect && config->reconnect_timeout_ms <= 0) {
|
||||
client->wait_timeout_ms = WEBSOCKET_RECONNECT_TIMEOUT_MS;
|
||||
ESP_LOGW(TAG, "`reconnect_timeout_ms` is not set, or it is less than or equal to zero, using default time out %d (milliseconds)", WEBSOCKET_RECONNECT_TIMEOUT_MS);
|
||||
} else {
|
||||
@ -1039,10 +1043,9 @@ static void esp_websocket_client_task(void *pv)
|
||||
ESP_LOGD(TAG, " Waiting for TCP connection to be closed by the server");
|
||||
int ret = esp_transport_ws_poll_connection_closed(client->transport, 1000);
|
||||
if (ret == 0) {
|
||||
// still waiting
|
||||
break;
|
||||
}
|
||||
if (ret < 0) {
|
||||
ESP_LOGW(TAG, "Did not get TCP close within expected delay");
|
||||
|
||||
} else if (ret < 0) {
|
||||
ESP_LOGW(TAG, "Connection terminated while waiting for clean TCP close");
|
||||
}
|
||||
client->run = false;
|
||||
@ -1205,33 +1208,27 @@ int esp_websocket_client_send_fin(esp_websocket_client_handle_t client, TickType
|
||||
|
||||
int esp_websocket_client_send_with_opcode(esp_websocket_client_handle_t client, ws_transport_opcodes_t opcode, const uint8_t *data, int len, TickType_t timeout)
|
||||
{
|
||||
int ret = ESP_OK;
|
||||
int ret = -1;
|
||||
if (client == NULL || len < 0 || (data == NULL && len > 0)) {
|
||||
ESP_LOGE(TAG, "Invalid arguments");
|
||||
return ESP_FAIL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (xSemaphoreTakeRecursive(client->lock, timeout) != pdPASS) {
|
||||
ESP_LOGE(TAG, "Could not lock ws-client within %" PRIu32 " timeout", timeout);
|
||||
return ESP_FAIL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!esp_websocket_client_is_connected(client)) {
|
||||
ESP_LOGE(TAG, "Websocket client is not connected");
|
||||
ret = ESP_FAIL;
|
||||
goto unlock_and_return;
|
||||
}
|
||||
|
||||
if (client->transport == NULL) {
|
||||
ESP_LOGE(TAG, "Invalid transport");
|
||||
ret = ESP_FAIL;
|
||||
goto unlock_and_return;
|
||||
}
|
||||
if (esp_websocket_new_buf(client, true) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to setup tx buffer");
|
||||
ret = ESP_FAIL;
|
||||
goto unlock_and_return;
|
||||
}
|
||||
|
||||
ret = esp_websocket_client_send_with_exact_opcode(client, opcode | WS_TRANSPORT_OPCODES_FIN, data, len, timeout);
|
||||
if (ret < 0) {
|
||||
ESP_LOGE(TAG, "Failed to send the buffer");
|
||||
|
@ -1,14 +1,15 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
set(COMPONENTS esp_websocket_client main)
|
||||
set(common_component_dir ../../../../common_components)
|
||||
set(EXTRA_COMPONENT_DIRS
|
||||
../../..
|
||||
"${common_component_dir}/linux_compat/esp_timer"
|
||||
"${common_component_dir}/linux_compat"
|
||||
"${common_component_dir}/linux_compat/freertos")
|
||||
|
||||
list(APPEND EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/protocols/linux_stubs/esp_stubs)
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
|
||||
set(common_component_dir ../../../../common_components)
|
||||
set(EXTRA_COMPONENT_DIRS
|
||||
../..
|
||||
"${common_component_dir}/linux_compat/esp_timer"
|
||||
"${common_component_dir}/linux_compat"
|
||||
"${common_component_dir}/linux_compat/freertos"
|
||||
$ENV{IDF_PATH}/examples/protocols/linux_stubs/esp_stubs
|
||||
$ENV{IDF_PATH}/examples/common_components/protocol_examples_common)
|
||||
|
||||
set(COMPONENTS main)
|
||||
project(websocket)
|
||||
|
35
components/esp_websocket_client/examples/linux/README.md
Normal file
35
components/esp_websocket_client/examples/linux/README.md
Normal file
@ -0,0 +1,35 @@
|
||||
# ESP Websocket Client - Host Example
|
||||
|
||||
This example demonstrates the ESP websocket client using the `linux` target. It allows for compilation and execution of the example directly within a Linux environment.
|
||||
|
||||
## Compilation and Execution
|
||||
|
||||
To compile and execute this example on Linux need to set target `linux`
|
||||
|
||||
```
|
||||
idf.py --preview set-target linux
|
||||
idf.py build
|
||||
./websocket.elf
|
||||
```
|
||||
|
||||
## Example Output
|
||||
|
||||
```
|
||||
I (164532) websocket: [APP] Startup..
|
||||
I (164532) websocket: [APP] Free memory: 4294967295 bytes
|
||||
I (164532) websocket: [APP] IDF version: v5.3-dev-1353-gb3f7e2c8a4
|
||||
I (164538) websocket: Connecting to ws://echo.websocket.events...
|
||||
W (164538) websocket_client: `reconnect_timeout_ms` is not set, or it is less than or equal to zero, using default time out 10000 (milliseconds)
|
||||
W (164538) websocket_client: `network_timeout_ms` is not set, or it is less than or equal to zero, using default time out 10000 (milliseconds)
|
||||
I (165103) websocket: WEBSOCKET_EVENT_CONNECTED
|
||||
I (165539) websocket: Sending hello 0000
|
||||
I (165627) websocket: WEBSOCKET_EVENT_DATA
|
||||
I (165627) websocket: Received opcode=1
|
||||
W (165627) websocket: Received=hello 0000
|
||||
W (165627) websocket: Total payload length=10, data_len=10, current payload offset=0
|
||||
|
||||
I (166539) websocket: Sending fragmented message
|
||||
```
|
||||
|
||||
## Coverage Reporting
|
||||
For generating a coverage report, it's necessary to enable `CONFIG_GCOV_ENABLED=y` option. Set the following configuration in your project's SDK configuration file (`sdkconfig.ci.coverage`, `sdkconfig.ci.linux` or via `menuconfig`):
|
@ -1,3 +0,0 @@
|
||||
dependencies:
|
||||
protocol_examples_common:
|
||||
path: ${IDF_PATH}/examples/common_components/protocol_examples_common
|
@ -4,5 +4,3 @@ CONFIG_IDF_TARGET_LINUX=y
|
||||
CONFIG_ESP_EVENT_POST_FROM_ISR=n
|
||||
CONFIG_ESP_EVENT_POST_FROM_IRAM_ISR=n
|
||||
CONFIG_WEBSOCKET_URI="ws://echo.websocket.events"
|
||||
CONFIG_WEBSOCKET_URI_FROM_STRING=y
|
||||
CONFIG_WEBSOCKET_URI_FROM_STDIN=n
|
||||
|
@ -3,6 +3,3 @@ CONFIG_IDF_TARGET_LINUX=y
|
||||
CONFIG_ESP_EVENT_POST_FROM_ISR=n
|
||||
CONFIG_ESP_EVENT_POST_FROM_IRAM_ISR=n
|
||||
CONFIG_WEBSOCKET_URI="ws://echo.websocket.events"
|
||||
CONFIG_WEBSOCKET_URI_FROM_STRING=y
|
||||
CONFIG_WEBSOCKET_URI_FROM_STDIN=n
|
||||
CONFIG_EXAMPLE_CONNECT_WIFI=n
|
||||
|
@ -0,0 +1,5 @@
|
||||
CONFIG_IDF_TARGET="linux"
|
||||
CONFIG_IDF_TARGET_LINUX=y
|
||||
CONFIG_ESP_EVENT_POST_FROM_ISR=n
|
||||
CONFIG_ESP_EVENT_POST_FROM_IRAM_ISR=n
|
||||
CONFIG_WEBSOCKET_URI="ws://echo.websocket.events"
|
@ -13,6 +13,55 @@ This example can be executed on any ESP32 board, the only required interface is
|
||||
* Open the project configuration menu (`idf.py menuconfig`)
|
||||
* Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu.
|
||||
* Configure the websocket endpoint URI under "Example Configuration", if "WEBSOCKET_URI_FROM_STDIN" is selected then the example application will connect to the URI it reads from stdin (used for testing)
|
||||
* To test a WebSocket client example over TLS, please enable one of the following configurations: `CONFIG_WS_OVER_TLS_MUTUAL_AUTH` or `CONFIG_WS_OVER_TLS_SERVER_AUTH`. See the sections below for more details.
|
||||
|
||||
### Server Certificate Verification
|
||||
|
||||
* Mutual Authentication: When `CONFIG_WS_OVER_TLS_MUTUAL_AUTH=y` is enabled, it's essential to provide valid certificates for both the server and client.
|
||||
This ensures a secure two-way verification process.
|
||||
* Server-Only Authentication: To perform verification of the server's certificate only (without requiring a client certificate), set `CONFIG_WS_OVER_TLS_SERVER_AUTH=y`.
|
||||
This method skips client certificate verification.
|
||||
* Example below demonstrates how to generate a new self signed certificates for the server and client using the OpenSSL command line tool
|
||||
|
||||
Please note: This example represents an extremely simplified approach to generating self-signed certificates/keys with a single common CA, devoid of CN checks, lacking password protection, and featuring hardcoded key sizes and types. It is intended solely for testing purposes.
|
||||
In the outlined steps, we are omitting the configuration of the CN (Common Name) field due to the context of a testing environment. However, it's important to recognize that the CN field is a critical element of SSL/TLS certificates, significantly influencing the security and efficacy of HTTPS communications. This field facilitates the verification of a website's identity, enhancing trust and security in web interactions. In practical deployments beyond testing scenarios, ensuring the CN field is accurately set is paramount for maintaining the integrity and reliability of secure communications
|
||||
|
||||
### Generating a self signed Certificates with OpenSSL
|
||||
* The example below outlines the process for creating new certificates for both the server and client using OpenSSL, a widely-used command line tool for implementing TLS protocol:
|
||||
|
||||
```
|
||||
Generate the CA's Private Key;
|
||||
openssl genrsa -out ca_key.pem 2048
|
||||
|
||||
Create the CA's Certificate
|
||||
openssl req -new -x509 -days 3650 -key ca_key.pem -out ca_cert.pem
|
||||
|
||||
Generate the Server's Private Key
|
||||
openssl genrsa -out server_key.pem 2048
|
||||
|
||||
Generate a Certificate Signing Request (CSR) for the Server
|
||||
openssl req -new -key server_key.pem -out server_csr.pem
|
||||
|
||||
Sign the Server's CSR with the CA's Certificate
|
||||
openssl x509 -req -days 3650 -in server_csr.pem -CA ca_cert.pem -CAkey ca_key.pem -CAcreateserial -out server_cert.pem
|
||||
|
||||
Generate the Client's Private Key
|
||||
openssl genrsa -out client_key.pem 2048
|
||||
|
||||
Generate a Certificate Signing Request (CSR) for the Client
|
||||
openssl req -new -key client_key.pem -out client_csr.pem
|
||||
|
||||
Sign the Client's CSR with the CA's Certificate
|
||||
openssl x509 -req -days 3650 -in client_csr.pem -CA ca_cert.pem -CAkey ca_key.pem -CAcreateserial -out client_cert.pem
|
||||
|
||||
```
|
||||
|
||||
Expiry time and metadata fields can be adjusted in the invocation.
|
||||
|
||||
Please see the openssl man pages (man openssl) for more details.
|
||||
|
||||
It is **strongly recommended** to not reuse the example certificate in your application;
|
||||
it is included only for demonstration.
|
||||
|
||||
### Build and Flash
|
||||
|
||||
|
@ -1,2 +1,22 @@
|
||||
idf_component_register(SRCS "websocket_example.c"
|
||||
INCLUDE_DIRS ".")
|
||||
set(SRC_FILES "websocket_example.c") # Define source files
|
||||
set(INCLUDE_DIRS ".") # Define include directories
|
||||
set(EMBED_FILES "") # Initialize an empty list for files to embed
|
||||
|
||||
# Conditionally append files to the list based on configuration
|
||||
#if(CONFIG_WS_OVER_TLS_MUTAL_AUTH)
|
||||
list(APPEND EMBED_FILES
|
||||
"certs/client_cert.pem"
|
||||
"certs/ca_cert.pem"
|
||||
"certs/client_key.pem")
|
||||
#endif()
|
||||
|
||||
# For testing purpose we are using CA of wss://echo.websocket.events
|
||||
#if(CONFIG_WS_OVER_TLS_SERVER_AUTH)
|
||||
list(APPEND EMBED_FILES
|
||||
"certs/ca_certificate_public_domain.pem")
|
||||
#endif()
|
||||
|
||||
# Register the component with source files, include dirs, and any conditionally added embedded files
|
||||
idf_component_register(SRCS "${SRC_FILES}"
|
||||
INCLUDE_DIRS "${INCLUDE_DIRS}"
|
||||
EMBED_TXTFILES "${EMBED_FILES}")
|
||||
|
@ -16,10 +16,30 @@ menu "Example Configuration"
|
||||
config WEBSOCKET_URI
|
||||
string "Websocket endpoint URI"
|
||||
depends on WEBSOCKET_URI_FROM_STRING
|
||||
default "ws://echo.websocket.events"
|
||||
default "wss://echo.websocket.events"
|
||||
help
|
||||
URL of websocket endpoint this example connects to and sends echo
|
||||
|
||||
config WS_OVER_TLS_SERVER_AUTH
|
||||
bool "Enable WebSocket over TLS with Server Certificate Verification Only"
|
||||
default y
|
||||
help
|
||||
Enables WebSocket connections over TLS (WSS) with server certificate verification.
|
||||
This setting mandates the client to verify the servers certificate, while the server
|
||||
does not require client certificate verification.
|
||||
|
||||
config WS_OVER_TLS_MUTUAL_AUTH
|
||||
bool "Enable WebSocket over TLS with Server Client Mutual Authentification"
|
||||
default n
|
||||
help
|
||||
Enables WebSocket connections over TLS (WSS) with server and client mutual certificate verification.
|
||||
|
||||
config WS_OVER_TLS_SKIP_COMMON_NAME_CHECK
|
||||
bool "Skip common name(CN) check during TLS authentification"
|
||||
default n
|
||||
help
|
||||
Skipping Common Name(CN) check during TLS(WSS) authentificatio
|
||||
|
||||
if CONFIG_IDF_TARGET = "linux"
|
||||
config GCOV_ENABLED
|
||||
bool "Coverage analyzer"
|
||||
|
@ -0,0 +1,21 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDazCCAlOgAwIBAgIUL04QhbSEt5oNbV4f7CeLLqTCw2gwDQYJKoZIhvcNAQEL
|
||||
BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
|
||||
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yNDAyMjMwODA2MjVaFw0zNDAy
|
||||
MjAwODA2MjVaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
|
||||
HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB
|
||||
AQUAA4IBDwAwggEKAoIBAQDjc78SuXAmJeBc0el2/m+2lwtk3J/VrNxHYkhjHa8K
|
||||
/ybU89VvKGuv9+L3IP67WMguFTaMgivJYUePjfMchtNJLJ+4cR9BkBKH4JnyXDae
|
||||
s0a5181LxRo8rqcaOw9hmJTgt9R4dIRTR3GN2/VLhlR+L9OTYA54RUtMyMMpyk5M
|
||||
YIJbcOwiwkVLsIYnexXDfgz9vQGl/2vBQ/RBtDBvbSyBiWox9SuzOrya1HUBzJkM
|
||||
Iu5L0bSa0LAeXHT3i3P1Y4WPt9ub70OhUNfJtHC+XbGFSEkkQG+lfbXU75XLoMWa
|
||||
iATMREOcb3Mq+pn1G8o1ZHVc6lBHUkfrNfxs5P/GQcSvAgMBAAGjUzBRMB0GA1Ud
|
||||
DgQWBBQGkdK2gR2HrQTnZnbuWO7I1+wdxDAfBgNVHSMEGDAWgBQGkdK2gR2HrQTn
|
||||
ZnbuWO7I1+wdxDAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBx
|
||||
G0hFtMwV/agIwC3ZaYC36ZWiijFzWkJSZG+fqAy32mSoVL2uQvOT8vEfF0ZnAcPc
|
||||
JI4oI059dBhAVlwqv6uLHyD4Gf2bF4oSLljdTz3X23llF+/wrTC2LLqMrm09aUC0
|
||||
ac74Q0FVwVJJcqH1HgemCMVjna5MkwNA6B+q7uR3eQ692VqXk6vjd4fRLBg1bBO1
|
||||
hXjasfNxA8A9quORF5+rjYrwyUZHuzcs0FfSClckIt4tHKtt4moLufOW6/PM4fRe
|
||||
AgdDfiTupxYLJFz4hFPhfgCh4TjQ+f9+uP4IAjW42dJmTVZjLEku/hm5lxCFObAq
|
||||
RgfaNwH8Ug1r1xswjSZG
|
||||
-----END CERTIFICATE-----
|
@ -0,0 +1,30 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFFjCCAv6gAwIBAgIRAJErCErPDBinU/bWLiWnX1owDQYJKoZIhvcNAQELBQAw
|
||||
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
|
||||
cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjAwOTA0MDAwMDAw
|
||||
WhcNMjUwOTE1MTYwMDAwWjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg
|
||||
RW5jcnlwdDELMAkGA1UEAxMCUjMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
|
||||
AoIBAQC7AhUozPaglNMPEuyNVZLD+ILxmaZ6QoinXSaqtSu5xUyxr45r+XXIo9cP
|
||||
R5QUVTVXjJ6oojkZ9YI8QqlObvU7wy7bjcCwXPNZOOftz2nwWgsbvsCUJCWH+jdx
|
||||
sxPnHKzhm+/b5DtFUkWWqcFTzjTIUu61ru2P3mBw4qVUq7ZtDpelQDRrK9O8Zutm
|
||||
NHz6a4uPVymZ+DAXXbpyb/uBxa3Shlg9F8fnCbvxK/eG3MHacV3URuPMrSXBiLxg
|
||||
Z3Vms/EY96Jc5lP/Ooi2R6X/ExjqmAl3P51T+c8B5fWmcBcUr2Ok/5mzk53cU6cG
|
||||
/kiFHaFpriV1uxPMUgP17VGhi9sVAgMBAAGjggEIMIIBBDAOBgNVHQ8BAf8EBAMC
|
||||
AYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMBIGA1UdEwEB/wQIMAYB
|
||||
Af8CAQAwHQYDVR0OBBYEFBQusxe3WFbLrlAJQOYfr52LFMLGMB8GA1UdIwQYMBaA
|
||||
FHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcw
|
||||
AoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzAnBgNVHR8EIDAeMBygGqAYhhZodHRw
|
||||
Oi8veDEuYy5sZW5jci5vcmcvMCIGA1UdIAQbMBkwCAYGZ4EMAQIBMA0GCysGAQQB
|
||||
gt8TAQEBMA0GCSqGSIb3DQEBCwUAA4ICAQCFyk5HPqP3hUSFvNVneLKYY611TR6W
|
||||
PTNlclQtgaDqw+34IL9fzLdwALduO/ZelN7kIJ+m74uyA+eitRY8kc607TkC53wl
|
||||
ikfmZW4/RvTZ8M6UK+5UzhK8jCdLuMGYL6KvzXGRSgi3yLgjewQtCPkIVz6D2QQz
|
||||
CkcheAmCJ8MqyJu5zlzyZMjAvnnAT45tRAxekrsu94sQ4egdRCnbWSDtY7kh+BIm
|
||||
lJNXoB1lBMEKIq4QDUOXoRgffuDghje1WrG9ML+Hbisq/yFOGwXD9RiX8F6sw6W4
|
||||
avAuvDszue5L3sz85K+EC4Y/wFVDNvZo4TYXao6Z0f+lQKc0t8DQYzk1OXVu8rp2
|
||||
yJMC6alLbBfODALZvYH7n7do1AZls4I9d1P4jnkDrQoxB3UqQ9hVl3LEKQ73xF1O
|
||||
yK5GhDDX8oVfGKF5u+decIsH4YaTw7mP3GFxJSqv3+0lUFJoi5Lc5da149p90Ids
|
||||
hCExroL1+7mryIkXPeFM5TgO9r0rvZaBFOvV2z0gp35Z0+L4WPlbuEjN/lxPFin+
|
||||
HlUjr8gRsI3qfJOQFy/9rKIJR0Y/8Omwt/8oTWgy1mdeHmmjk7j1nYsvC9JSQ6Zv
|
||||
MldlTTKB3zhThV1+XWYp6rjd5JW1zbVWEkLNxE7GJThEUG3szgBVGP7pSWTUTsqX
|
||||
nLRbwHOoq7hHwg==
|
||||
-----END CERTIFICATE-----
|
@ -0,0 +1,20 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDWjCCAkKgAwIBAgIUUPCOgMA2v09E29fCkogx3RUBRtEwDQYJKoZIhvcNAQEL
|
||||
BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
|
||||
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yNDAyMjMwODA3MzFaFw0zNDAy
|
||||
MjAwODA3MzFaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
|
||||
HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB
|
||||
AQUAA4IBDwAwggEKAoIBAQCrNeomxI2aoP+4iUy5SiA+41oHUDZDFeJOBjv5JCsK
|
||||
mlvFqxE9zynmPOVpuABErOJwzerPTa4NYKvuvs5CxVJUV5CXtWANuu9majioZNzj
|
||||
f877MDNX/GnZHK2gnkxVrZCPaDmx9yiMsFMXgmfdrDhwoUpXbdgSyeU/al9Ds2kF
|
||||
0hrHOH2LBWt/mVeLbONU5CC1HOdVVw+uRlhVlxnfhTPd/Nru3rJx7R0sN7qXcZpJ
|
||||
PL87WvrszLVOux24DeaOz9oiD2b7egFyUuq1BM25iCwi8s/Ths8xd0Ca1d8mEcHW
|
||||
FVd4w2+nUMXFE+IbP+wo6FXuiSaOBNri3rztpvCCMaWjAgMBAAGjQjBAMB0GA1Ud
|
||||
DgQWBBSOlA+9Vfbcfy8iS4HSd4V0KPtm4jAfBgNVHSMEGDAWgBQGkdK2gR2HrQTn
|
||||
ZnbuWO7I1+wdxDANBgkqhkiG9w0BAQsFAAOCAQEAOmzm/MwowKTrSpMSrmfA3MmW
|
||||
ULzsfa25WyAoTl90ATlg4653Y7pRaNfdvVvyi2V2LlPcmc7E0rfD53t1NxjDH1uM
|
||||
LgFMTNEaZ9nMRSW0kMiwaRpvmXS8Eb9PXfvIM/Mw0co/aMOtAQnfTGIqsgkQwKyk
|
||||
1GG7QKQq3p4QGu5ZaTnjnaoa79hODt+0xQDD1wp6C9xwBY0M4gndAi3wkOeFkGv+
|
||||
OmGPtaCBu5V9tJCZ9dfZvjkaK44NGwDw0urAcYRK2h7asnlflu7cnlGMBB0qY4kQ
|
||||
BX5WI8UjN6rECBHbtNRvEh06ogDdHbxYV+TibrqkkeDRw6HX1qqiEJ+iCgWEDQ==
|
||||
-----END CERTIFICATE-----
|
@ -0,0 +1,28 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCrNeomxI2aoP+4
|
||||
iUy5SiA+41oHUDZDFeJOBjv5JCsKmlvFqxE9zynmPOVpuABErOJwzerPTa4NYKvu
|
||||
vs5CxVJUV5CXtWANuu9majioZNzjf877MDNX/GnZHK2gnkxVrZCPaDmx9yiMsFMX
|
||||
gmfdrDhwoUpXbdgSyeU/al9Ds2kF0hrHOH2LBWt/mVeLbONU5CC1HOdVVw+uRlhV
|
||||
lxnfhTPd/Nru3rJx7R0sN7qXcZpJPL87WvrszLVOux24DeaOz9oiD2b7egFyUuq1
|
||||
BM25iCwi8s/Ths8xd0Ca1d8mEcHWFVd4w2+nUMXFE+IbP+wo6FXuiSaOBNri3rzt
|
||||
pvCCMaWjAgMBAAECggEAOTWjz16AXroLmRMv8v5E9h6sN6Ni7lnCrAXDRoYCZ+Ga
|
||||
Ztu5wCiYPJn+oqvcUxZd+Ammu6yeS1QRP468h20+DHbSFw+BUDU1x8gYtJQ3h0Fu
|
||||
3VqG3ZC3odfGYNRkd4CuvGy8Uq5e+1vz9/gYUuc4WNJccAiBWg3ir6UQviOWJV46
|
||||
LGfdEd9hVvIGl5pmArMBVYdpj9+JHunDtG4uQxiWla5pdLjlkC2mGexD18T9d718
|
||||
6I+o3YHv1Y9RPT1d4rNhYQWx6YdTTD2rmS7nTrzroj/4fXsblpXzR+/l7crlNERY
|
||||
67RMPwgDR1NiAbCAJKsSbMS66lRCNlhTM4YffGAN6QKBgQDkIdcNm9j49SK5Wbl5
|
||||
j8U6UbcVYPzPG+2ea+fDfUIafA0VQHIuX6FgA17Kp7BDX9ldKtSBpr0Z8vetVswr
|
||||
agmXVMR/7QdvnZ9NpL66YA/BRs67CvsryVu4AVAzThFGySmlcXGlPq47doWDQ3B9
|
||||
0BOEnVoeDXR3SabaNsEbhDYn1wKBgQDAIAUyhJcgz+LcgaAtBwdnEN57y66JlRVZ
|
||||
bsb6cEG/MNmnLjQYsplJjNbz4yrB5ukTChPTGRF/JQRqHoXh6DGQFHvobukwwA6x
|
||||
RAIIq0NLJ5HUipfOi+VpCbWUHdoUNhwjAB2qVtD4LXE2Lyn46C8ET5eRtRjUKpzV
|
||||
lpsq63KHFQKBgFB+cDbpCoGtXPcxZXQy+lA9jPAKLKmXHRyMzlX32F8n7iXVe3RJ
|
||||
YdNS3Rt8V4EuTK/G8PxeLNL/G80ZlyiqXX/79Ol+ZOVJJHBs9K8mPejgZwkwMrec
|
||||
cLRYIkg3/3iOehdaE9NOboOkqi9KmGKMDJb6PlXkQXflkO3l6/UdjU45AoGAen0v
|
||||
sxiTncjMU1eVfn+nuY8ouXaPbYoOFXmqBItDb5i+e3baohBj6F+Rv+ZKIVuNp6Ta
|
||||
JNErtYstOFcDdpbp2nkk0ni71WftNhkszsgZ3DV7JS3DQV0xwvj8ulUZ757b63is
|
||||
cShujHu0XR5OvTGSoEX6VVxHWyVb3lTp0sBPwU0CgYBe2Ieuya0X8mAbputFN64S
|
||||
Kv++dqktTUT8i+tp07sIrpDeYwO3D89x9kVSJj4ImlmhiBVGkxFWPkpGyBLotdse
|
||||
Ai/E6f5I7CDSZZC0ZucgcItNd4Yy459QY+dFwFtT3kIaD9ml8fnqQ83J9W8DWtv9
|
||||
6mY9FnUUufbJcpHxN58RTw==
|
||||
-----END PRIVATE KEY-----
|
@ -0,0 +1,20 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDWjCCAkKgAwIBAgIUUPCOgMA2v09E29fCkogx3RUBRtAwDQYJKoZIhvcNAQEL
|
||||
BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
|
||||
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yNDAyMjMwODA2NTlaFw0zNDAy
|
||||
MjAwODA2NTlaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
|
||||
HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB
|
||||
AQUAA4IBDwAwggEKAoIBAQC8WWbDxnLzTSfuQaO+kQnnzbwjhUHWn58s+BIEaO8M
|
||||
GG6bX+8r/SH9XjMfFS36qAN3qxgRun3YoRTaHc2QByiGjf5IL4EAPDnLN+NzUIL5
|
||||
7Gi2QPQP/GksAsOGKWk/nMRPk1vcMptkFVIWSp474SQ0A92Z9z0dUIqBpjRa34kr
|
||||
HsAIcT59/EG7YBBadMk0fQIxQVLh3Vosky85q+0waFihe47Ef5U2UftexoUx4Vcz
|
||||
6EtP60Wx+4qN+FLsr+n2B7Oz2ITqfwgqLzjNLZwm9bMjcLZ0fWm1A/W1C989MXwI
|
||||
w6DAPEZv7pbgp8r9phyrNieSDuuRaCvFsaXh6troAjLxAgMBAAGjQjBAMB0GA1Ud
|
||||
DgQWBBRJCYAQG2+1FN5P/wyAR1AsrAyb4DAfBgNVHSMEGDAWgBQGkdK2gR2HrQTn
|
||||
ZnbuWO7I1+wdxDANBgkqhkiG9w0BAQsFAAOCAQEAmllul/GIH7RVq85mM/SxP47J
|
||||
M7Z7T032KuR3n/Psyv2iq/uEV2CUje3XrKNwR2PaJL4Q6CtoWy7xgIP+9CBbjddR
|
||||
M7sdNQab8P2crAUtBKnkNOl/na/5KnXnjwi/PmWJJ9i2Cqt0PPkaykTWp/MLfYIw
|
||||
RPkY2Yo8f8gEiqXQd+0qTuMgumbgkPq3V8Lk1ocy62F5/qUhXxH+ifAXEoUQS6EG
|
||||
8DlgwdZlfUY+jeM6N56WzYmxD1syjNW7faPio+qXINfpYatROhqphaMQ5SA6TRj6
|
||||
jcnLa31TdDdWmWYDcYgZntAv6yGi3rh0MdYqeNS0FKlMKmaH81VHs7V1UUXwUQ==
|
||||
-----END CERTIFICATE-----
|
@ -0,0 +1,28 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC8WWbDxnLzTSfu
|
||||
QaO+kQnnzbwjhUHWn58s+BIEaO8MGG6bX+8r/SH9XjMfFS36qAN3qxgRun3YoRTa
|
||||
Hc2QByiGjf5IL4EAPDnLN+NzUIL57Gi2QPQP/GksAsOGKWk/nMRPk1vcMptkFVIW
|
||||
Sp474SQ0A92Z9z0dUIqBpjRa34krHsAIcT59/EG7YBBadMk0fQIxQVLh3Vosky85
|
||||
q+0waFihe47Ef5U2UftexoUx4Vcz6EtP60Wx+4qN+FLsr+n2B7Oz2ITqfwgqLzjN
|
||||
LZwm9bMjcLZ0fWm1A/W1C989MXwIw6DAPEZv7pbgp8r9phyrNieSDuuRaCvFsaXh
|
||||
6troAjLxAgMBAAECggEACNVCggTxCCMCr+RJKxs/NS1LWPkbZNbYjrHVmnpXV6Bf
|
||||
s460t0HoUasUx6zlGp+9heOyvcYat8maIj6KkOodBu5q0fTUXm/0n+ivlI1ejxz8
|
||||
ritupr9GKWe5xrVzd6XA+SBmivWenvt2/Y+jSxica4oQ3vMe3RyVWk4yn15jXu+9
|
||||
7B9lNyNeZtOBr6OozHGLYw4dwWcBNv2S6wevRKfHPwn/Ch5yTH1uAskgoMxUuyK2
|
||||
ynNVHWUhyS4pFU7Tex5ENDel15VYdbxV/2lQ2W6fHMLtC5GWKJXXbigCX7pfOpzC
|
||||
BFJEfZl7ze/qptE9AR7DkLFYyMtrS7OlebYbLDOM9wKBgQD+rTdwULZibpKwlI3a
|
||||
9Y22d4N/EDFvuu8LnuEiVQnXgwg9M+tlaa2liP18j1a7y/FCfoXf5sjUWCsdYR6d
|
||||
C0TuiOGI59hYGI94NvVLAmOutR+vJ/3jhbv5wyqEQLhJ42Yz9kWBrDCI+V3q3TdO
|
||||
H7wcH6suUIZpeLEJF4qHzY/1dwKBgQC9U/Pvswiww8sfysmd5shUNo4ofAZnTM1A
|
||||
ak6pWE3lSyiOkSm+3B2GqxYWLRoo1v+pTyhhXDtRRmxGtMNrKCsmlHef/o3c6kkG
|
||||
cuC2h/DiSmoITHy3BYKJoDeE54E8ubXUUKqHo41LYUs+D7M/IGxeiO13MUoIrEtF
|
||||
AwzVWPBU1wKBgH8barD2x6Bm+XWCHy6qIZlxGsMfDN1r2gTdvhWJhcj3D/Sj5heO
|
||||
X+lfbsxtKee+yOHcDesK3y8D9jjKkSHmTvgSfyX6OML3NxvTqidOwPugUHj2J8QX
|
||||
qhLk8mJhftj50reacWRf0TV76ADhecnXEuaic6hA7mTTpOAZzL0svm3PAoGBALWF
|
||||
r6VLX3KzVqZVtLb7FWmAoQ35093pCgXPpznAW3cTd4Axd/fxbTG4CUYb2i/760X2
|
||||
ij3Gw2yqe5fTKmYsLisgQA2bb4K28msHa6I2dmNQe5cXVp/X3Y98mJ6JpCSH3ekB
|
||||
qm7ABfGXCCApx28n9B8zY5JbJKNqJgS15vELA+ojAoGAAkaV2w46+3iQ6gJtQepr
|
||||
zGNybiYBx/Wo5fDdTS5u0xN+ZdC9fl2Zs0n7sMmUT8bWdDLcMnntHHO+oDIKyRHs
|
||||
TQh1n68vQ4JoegQv3Z9Z/TLEKqr9gyJC1Ao6M4bZpPhUWQwupfHColtsr2TskcnJ
|
||||
Nf2FpJZ7z6fQEShGlK1yTXM=
|
||||
-----END PRIVATE KEY-----
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
@ -91,7 +91,7 @@ static void websocket_event_handler(void *handler_args, esp_event_base_t base, i
|
||||
if (data->op_code == 0x08 && data->data_len == 2) {
|
||||
ESP_LOGW(TAG, "Received closed message with code=%d", 256 * data->data_ptr[0] + data->data_ptr[1]);
|
||||
} else {
|
||||
ESP_LOGW(TAG, "Received=%.*s", data->data_len, (char *)data->data_ptr);
|
||||
ESP_LOGW(TAG, "Received=%.*s\n\n", data->data_len, (char *)data->data_ptr);
|
||||
}
|
||||
|
||||
// If received data contains json structure it succeed to parse
|
||||
@ -143,6 +143,28 @@ static void websocket_app_start(void)
|
||||
websocket_cfg.uri = CONFIG_WEBSOCKET_URI;
|
||||
#endif /* CONFIG_WEBSOCKET_URI_FROM_STDIN */
|
||||
|
||||
#if CONFIG_WS_OVER_TLS_MUTUAL_AUTH
|
||||
/* Configuring client certificates for mutual authentification */
|
||||
extern const char cacert_start[] asm("_binary_ca_cert_pem_start"); // CA certificate
|
||||
extern const char cert_start[] asm("_binary_client_cert_pem_start"); // Client certificate
|
||||
extern const char cert_end[] asm("_binary_client_cert_pem_end");
|
||||
extern const char key_start[] asm("_binary_client_key_pem_start"); // Client private key
|
||||
extern const char key_end[] asm("_binary_client_key_pem_end");
|
||||
|
||||
websocket_cfg.cert_pem = cacert_start;
|
||||
websocket_cfg.client_cert = cert_start;
|
||||
websocket_cfg.client_cert_len = cert_end - cert_start;
|
||||
websocket_cfg.client_key = key_start;
|
||||
websocket_cfg.client_key_len = key_end - key_start;
|
||||
#elif CONFIG_WS_OVER_TLS_SERVER_AUTH
|
||||
extern const char cacert_start[] asm("_binary_ca_certificate_public_domain_pem_start"); // CA cert of wss://echo.websocket.event, modify it if using another server
|
||||
websocket_cfg.cert_pem = cacert_start;
|
||||
#endif
|
||||
|
||||
#if CONFIG_WS_OVER_TLS_SKIP_COMMON_NAME_CHECK
|
||||
websocket_cfg.skip_cert_common_name_check = true;
|
||||
#endif
|
||||
|
||||
ESP_LOGI(TAG, "Connecting to %s...", websocket_cfg.uri);
|
||||
|
||||
esp_websocket_client_handle_t client = esp_websocket_client_init(&websocket_cfg);
|
||||
|
@ -1,13 +1,16 @@
|
||||
# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
import json
|
||||
import random
|
||||
import re
|
||||
import socket
|
||||
import ssl
|
||||
import string
|
||||
import sys
|
||||
from threading import Event, Thread
|
||||
|
||||
from SimpleWebSocketServer import SimpleWebSocketServer, WebSocket
|
||||
from SimpleWebSocketServer import (SimpleSSLWebSocketServer,
|
||||
SimpleWebSocketServer, WebSocket)
|
||||
|
||||
|
||||
def get_my_ip():
|
||||
@ -27,7 +30,7 @@ class WebsocketTestEcho(WebSocket):
|
||||
|
||||
def handleMessage(self):
|
||||
self.sendMessage(self.data)
|
||||
print('Server sent: {}'.format(self.data))
|
||||
print('\n Server sent: {}\n'.format(self.data))
|
||||
|
||||
def handleConnected(self):
|
||||
print('Connection from: {}'.format(self.address))
|
||||
@ -44,12 +47,23 @@ class Websocket(object):
|
||||
conn.sendMessage(data)
|
||||
|
||||
def run(self):
|
||||
self.server = SimpleWebSocketServer('', self.port, WebsocketTestEcho)
|
||||
if self.use_tls is True:
|
||||
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
|
||||
ssl_context.load_cert_chain(certfile='main/certs/server_cert.pem', keyfile='main/certs/server_key.pem')
|
||||
if self.client_verify is True:
|
||||
ssl_context.load_verify_locations(cafile='main/certs/ca_cert.pem')
|
||||
ssl_context.verify = ssl.CERT_REQUIRED
|
||||
ssl_context.check_hostname = False
|
||||
self.server = SimpleSSLWebSocketServer('', self.port, WebsocketTestEcho, ssl_context=ssl_context)
|
||||
else:
|
||||
self.server = SimpleWebSocketServer('', self.port, WebsocketTestEcho)
|
||||
while not self.exit_event.is_set():
|
||||
self.server.serveonce()
|
||||
|
||||
def __init__(self, port):
|
||||
def __init__(self, port, use_tls, verify):
|
||||
self.port = port
|
||||
self.use_tls = use_tls
|
||||
self.client_verify = verify
|
||||
self.exit_event = Event()
|
||||
self.thread = Thread(target=self.run)
|
||||
self.thread.start()
|
||||
@ -77,6 +91,7 @@ def test_examples_protocol_websocket(dut):
|
||||
for i in range(0, 5):
|
||||
dut.expect(re.compile(b'Received=hello (\\d)'))
|
||||
print('All echos received')
|
||||
sys.stdout.flush()
|
||||
|
||||
def test_close(dut):
|
||||
code = dut.expect(
|
||||
@ -103,7 +118,8 @@ def test_examples_protocol_websocket(dut):
|
||||
match = dut.expect(
|
||||
re.compile(b'Json=({[a-zA-Z0-9]*).*}')).group(0).decode()[5:]
|
||||
if match == str(data[0]):
|
||||
print('Sent message and received message are equal')
|
||||
print('Sent message and received message are equal \n')
|
||||
sys.stdout.flush()
|
||||
else:
|
||||
raise ValueError(
|
||||
'DUT received string do not match sent string, \nexpected: {}\nwith length {}\
|
||||
@ -126,7 +142,8 @@ def test_examples_protocol_websocket(dut):
|
||||
recv_msg += match
|
||||
|
||||
if recv_msg == send_msg:
|
||||
print('Sent message and received message are equal')
|
||||
print('Sent message and received message are equal \n')
|
||||
sys.stdout.flush()
|
||||
else:
|
||||
raise ValueError(
|
||||
'DUT received string do not match sent string, \nexpected: {}\nwith length {}\
|
||||
@ -145,14 +162,24 @@ def test_examples_protocol_websocket(dut):
|
||||
uri = dut.app.sdkconfig['WEBSOCKET_URI']
|
||||
uri_from_stdin = False
|
||||
|
||||
if dut.app.sdkconfig.get('WS_OVER_TLS_MUTUAL_AUTH') is True:
|
||||
use_tls = True
|
||||
client_verify = True
|
||||
else:
|
||||
use_tls = False
|
||||
client_verify = False
|
||||
|
||||
except Exception:
|
||||
print('ENV_TEST_FAILURE: Cannot find uri settings in sdkconfig')
|
||||
raise
|
||||
|
||||
if uri_from_stdin:
|
||||
server_port = 8080
|
||||
with Websocket(server_port) as ws:
|
||||
uri = 'ws://{}:{}'.format(get_my_ip(), server_port)
|
||||
with Websocket(server_port, use_tls, client_verify) as ws:
|
||||
if use_tls is True:
|
||||
uri = 'wss://{}:{}'.format(get_my_ip(), server_port)
|
||||
else:
|
||||
uri = 'ws://{}:{}'.format(get_my_ip(), server_port)
|
||||
print('DUT connecting to {}'.format(uri))
|
||||
dut.expect('Please enter uri of websocket endpoint', timeout=30)
|
||||
dut.write(uri)
|
||||
|
@ -1,7 +1,7 @@
|
||||
CONFIG_IDF_TARGET="esp32"
|
||||
CONFIG_IDF_TARGET_LINUX=n
|
||||
CONFIG_WEBSOCKET_URI_FROM_STDIN=y
|
||||
CONFIG_WEBSOCKET_URI_FROM_STRING=n
|
||||
CONFIG_WEBSOCKET_URI_FROM_STDIN=n
|
||||
CONFIG_WEBSOCKET_URI_FROM_STRING=y
|
||||
CONFIG_EXAMPLE_CONNECT_ETHERNET=y
|
||||
CONFIG_EXAMPLE_CONNECT_WIFI=n
|
||||
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
|
||||
|
@ -0,0 +1,15 @@
|
||||
CONFIG_IDF_TARGET="esp32"
|
||||
CONFIG_IDF_TARGET_LINUX=n
|
||||
CONFIG_WEBSOCKET_URI_FROM_STDIN=y
|
||||
CONFIG_WEBSOCKET_URI_FROM_STRING=n
|
||||
CONFIG_EXAMPLE_CONNECT_ETHERNET=y
|
||||
CONFIG_EXAMPLE_CONNECT_WIFI=n
|
||||
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
|
||||
CONFIG_EXAMPLE_ETH_PHY_IP101=y
|
||||
CONFIG_EXAMPLE_ETH_MDC_GPIO=23
|
||||
CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
|
||||
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5
|
||||
CONFIG_EXAMPLE_ETH_PHY_ADDR=1
|
||||
CONFIG_EXAMPLE_CONNECT_IPV6=y
|
||||
CONFIG_WS_OVER_TLS_MUTUAL_AUTH=y
|
||||
CONFIG_WS_OVER_TLS_SKIP_COMMON_NAME_CHECK=y
|
@ -0,0 +1,15 @@
|
||||
CONFIG_IDF_TARGET="esp32"
|
||||
CONFIG_IDF_TARGET_LINUX=n
|
||||
CONFIG_WEBSOCKET_URI_FROM_STDIN=y
|
||||
CONFIG_WEBSOCKET_URI_FROM_STRING=n
|
||||
CONFIG_EXAMPLE_CONNECT_ETHERNET=y
|
||||
CONFIG_EXAMPLE_CONNECT_WIFI=n
|
||||
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
|
||||
CONFIG_EXAMPLE_ETH_PHY_IP101=y
|
||||
CONFIG_EXAMPLE_ETH_MDC_GPIO=23
|
||||
CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
|
||||
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5
|
||||
CONFIG_EXAMPLE_ETH_PHY_ADDR=1
|
||||
CONFIG_EXAMPLE_CONNECT_IPV6=y
|
||||
CONFIG_WS_OVER_TLS_MUTUAL_AUTH=n
|
||||
CONFIG_WS_OVER_TLS_SERVER_AUTH=n
|
@ -1,4 +1,4 @@
|
||||
version: "1.2.2"
|
||||
version: "1.2.3"
|
||||
description: WebSocket protocol client for ESP-IDF
|
||||
url: https://github.com/espressif/esp-protocols/tree/master/components/esp_websocket_client
|
||||
dependencies:
|
||||
|
@ -1,11 +0,0 @@
|
||||
components/mdns/examples:
|
||||
disable:
|
||||
- if: IDF_TARGET in ["esp32h2"]
|
||||
|
||||
components/mdns/tests/unit_test:
|
||||
disable:
|
||||
- if: IDF_TARGET in ["esp32h2"]
|
||||
|
||||
components/mdns/tests/test_apps:
|
||||
disable:
|
||||
- if: IDF_TARGET in ["esp32h2"]
|
@ -3,6 +3,6 @@ commitizen:
|
||||
bump_message: 'bump(mdns): $current_version -> $new_version'
|
||||
pre_bump_hooks: python ../../ci/changelog.py mdns
|
||||
tag_format: mdns-v$version
|
||||
version: 1.2.3
|
||||
version: 1.2.5
|
||||
version_files:
|
||||
- idf_component.yml
|
||||
|
@ -1,5 +1,20 @@
|
||||
# Changelog
|
||||
|
||||
## [1.2.5](https://github.com/espressif/esp-protocols/commits/mdns-v1.2.5)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Fixed build issues for targets without WiFi caps ([302b46f](https://github.com/espressif/esp-protocols/commit/302b46f))
|
||||
|
||||
## [1.2.4](https://github.com/espressif/esp-protocols/commits/mdns-v1.2.4)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Correction on 6d2c475 MDNS_PREDEF_NETIF_ETH fix ([fc59f87c4e](https://github.com/espressif/esp-protocols/commit/fc59f87c4e))
|
||||
- fix the logic of creating pcb for networking socket ([5000a9a20a](https://github.com/espressif/esp-protocols/commit/5000a9a20a))
|
||||
- fix compiling issue when disabling IPv4 ([2646dcd23a](https://github.com/espressif/esp-protocols/commit/2646dcd23a))
|
||||
- Fix compile error when MDNS_PREDEF_NETIF_ETH is defined, but ETH_ENABLED is not (#459) ([6d2c475c20](https://github.com/espressif/esp-protocols/commit/6d2c475c20))
|
||||
|
||||
## [1.2.3](https://github.com/espressif/esp-protocols/commits/mdns-v1.2.3)
|
||||
|
||||
### Bug Fixes
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user