mirror of
https://github.com/espressif/esp-protocols.git
synced 2025-07-26 00:37:31 +02:00
Compare commits
166 Commits
websocket-
...
mdns-v1.8.
Author | SHA1 | Date | |
---|---|---|---|
eb12d05bf3 | |||
520b8194fc | |||
40142cdcfd | |||
c7663cdef2 | |||
e01e67e7eb | |||
37f84ee5a4 | |||
95b56600ed | |||
a22c3da49e | |||
5d0fd5c1c5 | |||
7ea6879a19 | |||
2db11bbb8c | |||
cdb7bfd188 | |||
c679ceed85 | |||
c009892968 | |||
5f66f35f5f | |||
dea5f1c431 | |||
384d1c23ba | |||
88162d1f3a | |||
e65f22ab6c | |||
7d29b47676 | |||
f1a72ec42c | |||
ce160505dc | |||
87e96b4682 | |||
5b2077e373 | |||
b45fe143a4 | |||
ee2fbbbee7 | |||
cb061c9c38 | |||
0690eba3a8 | |||
eb4ab52487 | |||
8fcad10ccf | |||
936e43f9d8 | |||
64d818b2d3 | |||
cd07228f81 | |||
1c6580e22b | |||
87f835af0f | |||
85a8dac42d | |||
39866116f5 | |||
7740b591b6 | |||
b57979d967 | |||
42674b49f9 | |||
e069ae7762 | |||
44d476fc50 | |||
55385ec312 | |||
a3c2bbed9e | |||
84c47c37f1 | |||
e7273c46ec | |||
2e7d240abd | |||
d4a004b5b4 | |||
9046af8f8d | |||
eeeb9006eb | |||
b167aa315f | |||
72ba24470d | |||
7dc87d28b2 | |||
ac6a388cdd | |||
76aaea08d2 | |||
5db32cce30 | |||
9bdd429c7c | |||
6f7c52cc3f | |||
27435b7f34 | |||
813331f003 | |||
bd23c233a4 | |||
4eda7d472f | |||
163029c0b6 | |||
96eae25096 | |||
ebec8eff63 | |||
4451a8c5ad | |||
6d19aabb02 | |||
9162de1150 | |||
dbd164dd91 | |||
90d663ad01 | |||
a83f1b6787 | |||
84caca465d | |||
8f81478fff | |||
ae5a8ceeda | |||
774bab22ea | |||
265e38d684 | |||
93f772171c | |||
4ad88e297f | |||
196198ecc9 | |||
e838bf03f4 | |||
99b54ac384 | |||
f5be2f4115 | |||
9b74256b51 | |||
3d8835cfb9 | |||
24f55ce9b4 | |||
8f8516cc3f | |||
75a8e8640a | |||
907087c09b | |||
68a9e14898 | |||
827ea65fd5 | |||
9537721600 | |||
4394f845fc | |||
9b0ba6060f | |||
7c6a3098af | |||
f3f3e23bec | |||
9ed835ba3f | |||
f12a205657 | |||
5bd82c01a5 | |||
b4cb8f8a66 | |||
0499ed93df | |||
ade9448c01 | |||
4745fc8fe1 | |||
73e523e736 | |||
3cd0ed377b | |||
95294f5f89 | |||
5dcc33300f | |||
840a561de4 | |||
e6fb8aa078 | |||
3b2c614d86 | |||
cdeab8f517 | |||
6cce87e465 | |||
d57b8c5b29 | |||
9c11003449 | |||
85a7fc772c | |||
b090a3cb69 | |||
42cde46c97 | |||
beb6e57e5e | |||
15d3a01e11 | |||
e12ecb8e89 | |||
54271a1b96 | |||
886215032f | |||
269351f41c | |||
5e929902c7 | |||
f7c0b7564a | |||
c989c6adae | |||
18f196fa1e | |||
1db83cd1ca | |||
247f1681e8 | |||
32387f7e39 | |||
dbc3ea6809 | |||
8b6ea3311a | |||
8e55b93b59 | |||
0cb59ff80d | |||
1284f66d58 | |||
c5b49de2db | |||
2e9bb6ee45 | |||
1fcc5b1d56 | |||
849fe7b6cb | |||
5eadf1edee | |||
428fdbbd80 | |||
433a033fcc | |||
090b1ff845 | |||
295d99df96 | |||
b65cff3a0b | |||
e711f26670 | |||
4a1cb65c67 | |||
6c61dd39cf | |||
8821ea3a99 | |||
062b8dcacc | |||
7de57bb412 | |||
67191f3bb5 | |||
6d94ad646d | |||
685d47cd2f | |||
31f57ad067 | |||
32ac21b03c | |||
5b06a3b319 | |||
cc2741d4ad | |||
c5653ff204 | |||
77731c9b36 | |||
2442f6b553 | |||
0b5e362a7b | |||
5219c39d09 | |||
1a9eaf3e98 | |||
52598e5f03 | |||
2d9759265b | |||
8f1f935858 |
@ -13,7 +13,7 @@ jobs:
|
||||
name: Build
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest", "release-v5.0", "release-v5.1", "release-v5.2", "release-v5.3"]
|
||||
idf_ver: ["latest", "release-v5.0", "release-v5.1", "release-v5.2", "release-v5.3", "release-v5.4"]
|
||||
idf_target: ["esp32", "esp32s2"]
|
||||
example: ["asio_chat", "async_request", "socks4", "ssl_client_server", "tcp_echo_server", "udp_echo_server"]
|
||||
runs-on: ubuntu-22.04
|
||||
@ -64,7 +64,7 @@ jobs:
|
||||
name: Target tests
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest", "release-v5.0", "release-v5.2", "release-v5.3"]
|
||||
idf_ver: ["latest", "release-v5.1", "release-v5.2", "release-v5.3", "release-v5.4"]
|
||||
idf_target: ["esp32"]
|
||||
example: ["asio_chat", "tcp_echo_server", "udp_echo_server", "ssl_client_server"]
|
||||
needs: build_asio
|
||||
|
9
.github/workflows/clang-tidy.yml
vendored
9
.github/workflows/clang-tidy.yml
vendored
@ -9,10 +9,10 @@ on:
|
||||
jobs:
|
||||
build:
|
||||
name: Run clang-tidy
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
container: espressif/idf:latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: 'true'
|
||||
- name: Install esp-clang
|
||||
@ -24,6 +24,7 @@ jobs:
|
||||
chmod +x clang-tidy-sarif
|
||||
curl -sSL https://raw.githubusercontent.com/espressif/idf-extra-components/master/.github/filter_sarif.py -o filter_sarif.py
|
||||
- name: Install pyclang
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
pip install pyclang~=0.2.0
|
||||
@ -35,7 +36,7 @@ jobs:
|
||||
working-directory: test_app
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
idf.py clang-check --include-paths $GITHUB_WORKSPACE --exclude-paths $PWD --run-clang-tidy-py run-clang-tidy
|
||||
idf.py clang-check --include-paths $GITHUB_WORKSPACE --exclude-paths $PWD --run-clang-tidy-py run-clang-tidy --run-clang-tidy-options "-checks=-clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling"
|
||||
cp warnings.txt ../
|
||||
- name: Convert clang-tidy results into SARIF output
|
||||
run: |
|
||||
@ -49,7 +50,7 @@ jobs:
|
||||
results.sarif
|
||||
results.sarif.raw
|
||||
- name: Upload SARIF file
|
||||
uses: github/codeql-action/upload-sarif@v2
|
||||
uses: github/codeql-action/upload-sarif@v3
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
category: clang-tidy
|
||||
|
32
.github/workflows/console_cmd_mqtt__build.yml
vendored
Normal file
32
.github/workflows/console_cmd_mqtt__build.yml
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
name: "console_cmd_mqtt: build-tests"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, labeled]
|
||||
|
||||
jobs:
|
||||
build_console_cmd_mqtt:
|
||||
if: contains(github.event.pull_request.labels.*.name, 'console') || github.event_name == 'push'
|
||||
name: Build
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest", "release-v5.0", "release-v5.1", "release-v5.2", "release-v5.3"]
|
||||
idf_target: ["esp32"]
|
||||
test: [ { app: mqtt_ssl_auth_console, path: "components/console_cmd_mqtt/examples" }]
|
||||
runs-on: ubuntu-22.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Build ${{ matrix.test.app }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
|
||||
shell: bash
|
||||
working-directory: ${{matrix.test.path}}
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
pip install idf-component-manager idf-build-apps --upgrade
|
||||
python ../../../ci/build_apps.py ./${{ matrix.test.app }} --target ${{ matrix.idf_target }} -vv --preserve-all --pytest-app
|
50
.github/workflows/examples_build-host-test.yml
vendored
50
.github/workflows/examples_build-host-test.yml
vendored
@ -13,12 +13,15 @@ jobs:
|
||||
name: Build examples
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest", "release-v5.1", "release-v5.2", "release-v5.3"]
|
||||
idf_ver: ["latest", "release-v5.1", "release-v5.2", "release-v5.3", "release-v5.4"]
|
||||
include:
|
||||
- idf_ver: "latest"
|
||||
warning: "Warning: The smallest app partition is nearly full"
|
||||
runs-on: ubuntu-22.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
env:
|
||||
TARGET_TEST: examples/esp_netif/slip_custom_netif/
|
||||
TARGET_TEST_DIR: build_esp32c3_target
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v4
|
||||
@ -31,6 +34,16 @@ jobs:
|
||||
python -m pip install idf-build-apps
|
||||
# Build default configs for all targets
|
||||
python ./ci/build_apps.py examples -m examples/.build-test-rules.yml -d -c
|
||||
# Build target tests
|
||||
python ./ci/build_apps.py ${TARGET_TEST} -r sdkconfig.ci=target
|
||||
cd ${TARGET_TEST}
|
||||
${GITHUB_WORKSPACE}/ci/clean_build_artifacts.sh `pwd`/${TARGET_TEST_DIR}
|
||||
zip -qur artifacts.zip ${TARGET_TEST_DIR}
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: slip_target_${{ matrix.idf_ver }}
|
||||
path: ${{ env.TARGET_TEST }}/artifacts.zip
|
||||
if-no-files-found: error
|
||||
|
||||
build_and_run_on_host:
|
||||
if: contains(github.event.pull_request.labels.*.name, 'examples') || github.event_name == 'push'
|
||||
@ -51,3 +64,38 @@ jobs:
|
||||
python ./ci/build_apps.py examples/mqtt -l -t linux
|
||||
timeout 5 ./examples/mqtt/build_linux_default/esp_mqtt_demo.elf | tee test.log || true
|
||||
grep 'MQTT_EVENT_DATA' test.log
|
||||
|
||||
run_on_target:
|
||||
# Skip running on forks since it won't have access to secrets
|
||||
if: |
|
||||
github.repository == 'espressif/esp-protocols' &&
|
||||
( contains(github.event.pull_request.labels.*.name, 'examples') || github.event_name == 'push' )
|
||||
name: Slip example target test
|
||||
needs: build_all_examples
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["release-v5.4", "latest"]
|
||||
runs-on:
|
||||
- self-hosted
|
||||
- modem
|
||||
env:
|
||||
TARGET_TEST: examples/esp_netif/slip_custom_netif/
|
||||
TARGET_TEST_DIR: build_esp32c3_target
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: slip_target_${{ matrix.idf_ver }}
|
||||
path: ${{ env.TARGET_TEST }}/ci/
|
||||
- name: Run Test
|
||||
working-directory: ${{ env.TARGET_TEST }}
|
||||
run: |
|
||||
python -m venv .venv
|
||||
source .venv/bin/activate
|
||||
pip install --prefer-binary cryptography pytest-embedded pytest-embedded-serial-esp pytest-embedded-idf pytest-custom_exit_code esptool netifaces
|
||||
unzip ci/artifacts.zip -d ci
|
||||
for dir in `ls -d ci/build_*`; do
|
||||
rm -rf build sdkconfig.defaults
|
||||
mv $dir build
|
||||
python -m pytest --log-cli-level DEBUG --target=esp32c3
|
||||
done
|
||||
|
86
.github/workflows/lws_build.yml
vendored
Normal file
86
.github/workflows/lws_build.yml
vendored
Normal file
@ -0,0 +1,86 @@
|
||||
name: "lws: build-tests"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, labeled]
|
||||
|
||||
jobs:
|
||||
build_lws:
|
||||
if: contains(github.event.pull_request.labels.*.name, 'lws') || github.event_name == 'push'
|
||||
name: Libwebsockets build
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest", "release-v5.3", "release-v5.4"]
|
||||
test: [ { app: example, path: "examples/client" }]
|
||||
runs-on: ubuntu-22.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
env:
|
||||
TEST_DIR: components/libwebsockets/${{ matrix.test.path }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }}
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
python -m pip install idf-build-apps
|
||||
python ./ci/build_apps.py ${TEST_DIR}
|
||||
cd ${TEST_DIR}
|
||||
for dir in `ls -d build_esp32_*`; do
|
||||
$GITHUB_WORKSPACE/ci/clean_build_artifacts.sh `pwd`/$dir
|
||||
zip -qur artifacts.zip $dir
|
||||
done
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: lws_target_esp32_${{ matrix.idf_ver }}_${{ matrix.test.app }}
|
||||
path: ${{ env.TEST_DIR }}/artifacts.zip
|
||||
if-no-files-found: error
|
||||
|
||||
run-target-lws:
|
||||
# Skip running on forks since it won't have access to secrets
|
||||
if: |
|
||||
github.repository == 'espressif/esp-protocols' &&
|
||||
( contains(github.event.pull_request.labels.*.name, 'lws') || github.event_name == 'push' )
|
||||
name: Target test
|
||||
needs: build_lws
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
idf_ver: ["latest", "release-v5.3", "release-v5.4"]
|
||||
idf_target: ["esp32"]
|
||||
test: [ { app: example, path: "examples/client" }]
|
||||
runs-on:
|
||||
- self-hosted
|
||||
- ESP32-ETHERNET-KIT
|
||||
env:
|
||||
TEST_DIR: components/libwebsockets/${{ matrix.test.path }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: lws_target_esp32_${{ matrix.idf_ver }}_${{ matrix.test.app }}
|
||||
path: ${{ env.TEST_DIR }}/ci/
|
||||
- name: Install Python packages
|
||||
env:
|
||||
PIP_EXTRA_INDEX_URL: "https://www.piwheels.org/simple"
|
||||
run: |
|
||||
pip install --only-binary cryptography --extra-index-url https://dl.espressif.com/pypi/ -r $GITHUB_WORKSPACE/ci/requirements.txt
|
||||
- name: Run Example Test on target
|
||||
working-directory: ${{ env.TEST_DIR }}
|
||||
run: |
|
||||
unzip ci/artifacts.zip -d ci
|
||||
for dir in `ls -d ci/build_*`; do
|
||||
rm -rf build sdkconfig.defaults
|
||||
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@v4
|
||||
if: always()
|
||||
with:
|
||||
name: results_${{ matrix.test.app }}_${{ matrix.idf_target }}_${{ matrix.idf_ver }}.xml
|
||||
path: components/libwebsockets/${{ matrix.test.path }}/*.xml
|
24
.github/workflows/mdns__host-tests.yml
vendored
24
.github/workflows/mdns__host-tests.yml
vendored
@ -35,30 +35,36 @@ jobs:
|
||||
# Next we run the pytest (using the console app)
|
||||
pytest
|
||||
|
||||
build_afl_host_test_mdns:
|
||||
host_compat_checks:
|
||||
if: contains(github.event.pull_request.labels.*.name, 'mdns') || github.event_name == 'push'
|
||||
name: Build AFL host test
|
||||
name: Set of compatibility checks
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest"]
|
||||
idf_target: ["esp32"]
|
||||
|
||||
runs-on: ubuntu-22.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: esp-protocols
|
||||
- name: Install Necessary Libs
|
||||
run: |
|
||||
apt-get update -y
|
||||
apt-get install -y libbsd-dev
|
||||
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
|
||||
env:
|
||||
IDF_TARGET: ${{ matrix.idf_target }}
|
||||
- name: Test AFL compat build
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
cd $GITHUB_WORKSPACE/esp-protocols/components/mdns/tests/test_afl_fuzz_host/
|
||||
cd components/mdns/tests/test_afl_fuzz_host/
|
||||
make INSTR=off
|
||||
- name: Test no malloc functions
|
||||
shell: bash
|
||||
run: |
|
||||
cd components/mdns
|
||||
for file in $(ls *.c); do
|
||||
cp $file /tmp
|
||||
echo -n "Checking that $file does not call any std allocations directly..."
|
||||
python mem_prefix_script.py $file
|
||||
diff -q $file /tmp/$file || exit 1
|
||||
echo "OK"
|
||||
done
|
||||
|
15
.github/workflows/modem__build-host-tests.yml
vendored
15
.github/workflows/modem__build-host-tests.yml
vendored
@ -13,11 +13,8 @@ jobs:
|
||||
name: Build examples
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest", "release-v4.4", "release-v5.0", "release-v5.1", "release-v5.2", "release-v5.3"]
|
||||
idf_ver: ["latest", "release-v5.0", "release-v5.1", "release-v5.2", "release-v5.3", "release-v5.4"]
|
||||
example: ["pppos_client", "modem_console", "modem_tcp_client", "ap_to_pppos", "simple_cmux_client"]
|
||||
exclude:
|
||||
- idf_ver: "release-v4.4"
|
||||
example: modem_tcp_client
|
||||
include:
|
||||
- idf_ver: "release-v5.0"
|
||||
example: "simple_cmux_client"
|
||||
@ -26,13 +23,7 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- 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'
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: protocols
|
||||
@ -53,7 +44,7 @@ jobs:
|
||||
name: Build tests
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["release-v5.0", "release-v5.1", "release-v5.2", "release-v5.3", "latest"]
|
||||
idf_ver: ["release-v5.0", "release-v5.1", "release-v5.2", "release-v5.3", "release-v5.4", "latest"]
|
||||
test: ["target", "target_ota", "target_iperf"]
|
||||
|
||||
runs-on: ubuntu-22.04
|
||||
|
13
.github/workflows/modem__target-test.yml
vendored
13
.github/workflows/modem__target-test.yml
vendored
@ -42,7 +42,7 @@ jobs:
|
||||
idf.py set-target ${{ matrix.idf_target }}
|
||||
idf.py build
|
||||
$GITHUB_WORKSPACE/ci/clean_build_artifacts.sh ${GITHUB_WORKSPACE}/${TEST_DIR}/build
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: modem_target_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.test.app }}
|
||||
path: ${{ env.TEST_DIR }}/build
|
||||
@ -75,12 +75,17 @@ jobs:
|
||||
run: |
|
||||
sudo rm -fr $GITHUB_WORKSPACE && mkdir $GITHUB_WORKSPACE
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/download-artifact@v3
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: modem_target_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.test.app }}
|
||||
path: ${{ env.TEST_DIR }}/build
|
||||
- name: Run Example Test on target
|
||||
working-directory: ${{ env.TEST_DIR }}
|
||||
env:
|
||||
PIP_EXTRA_INDEX_URL: "https://dl.espressif.com/pypi/"
|
||||
run: |
|
||||
python -m pip install -r $GITHUB_WORKSPACE/ci/requirements.txt
|
||||
python -m venv .venv
|
||||
source .venv/bin/activate
|
||||
pip install --prefer-binary cryptography pytest-embedded pytest-embedded-serial-esp pytest-embedded-idf pytest-custom_exit_code esptool
|
||||
pip install -r $GITHUB_WORKSPACE/ci/requirements.txt
|
||||
cd ${{ env.TEST_DIR }}
|
||||
python -m pytest --log-cli-level DEBUG --target=${{ matrix.idf_target }}
|
||||
|
115
.github/workflows/mosq__build.yml
vendored
115
.github/workflows/mosq__build.yml
vendored
@ -17,7 +17,8 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
env:
|
||||
TEST_DIR: components/mosquitto/examples/broker
|
||||
TEST_DIR: components/mosquitto/examples
|
||||
TARGET_TEST: broker
|
||||
TARGET_TEST_DIR: build_esp32_default
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
@ -29,14 +30,15 @@ jobs:
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
pip install idf-component-manager idf-build-apps --upgrade
|
||||
python ci/build_apps.py ${TEST_DIR}
|
||||
cd ${TEST_DIR}
|
||||
python ci/build_apps.py -c ${TEST_DIR} -m components/mosquitto/.build-test-rules.yml
|
||||
# upload only the target test artifacts
|
||||
cd ${TEST_DIR}/${TARGET_TEST}
|
||||
${GITHUB_WORKSPACE}/ci/clean_build_artifacts.sh `pwd`/${TARGET_TEST_DIR}
|
||||
zip -qur artifacts.zip ${TARGET_TEST_DIR}
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: mosq_target_esp32_${{ matrix.idf_ver }}
|
||||
path: ${{ env.TEST_DIR }}/artifacts.zip
|
||||
path: ${{ env.TEST_DIR }}/${{ env.TARGET_TEST }}/artifacts.zip
|
||||
if-no-files-found: error
|
||||
|
||||
test_mosq:
|
||||
@ -71,3 +73,108 @@ jobs:
|
||||
mv $dir build
|
||||
python -m pytest --log-cli-level DEBUG --junit-xml=./results_esp32_${{ matrix.idf_ver }}_${dir#"ci/build_"}.xml --target=esp32
|
||||
done
|
||||
|
||||
check_consistency:
|
||||
if: contains(github.event.pull_request.labels.*.name, 'mosquitto') || github.event_name == 'push'
|
||||
name: Checks that API docs and versions are consistent
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Checks API Docs and versions
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install doxygen
|
||||
pip install esp-doxybook
|
||||
cd components/mosquitto
|
||||
cp api.md api_orig.md
|
||||
./generate_api_docs.sh
|
||||
diff -wB api.md api_orig.md
|
||||
# check version consistency
|
||||
CONFIG_VERSION=$(grep -Po '(?<=#define VERSION ")[^"]*' port/priv_include/config.h)
|
||||
CZ_VERSION=$(grep -Po '(?<=version: )[^"]*' .cz.yaml)
|
||||
COMP_VERSION=$(grep -Po '(?<=version: ")[^"]*' idf_component.yml)
|
||||
if [ "$CONFIG_VERSION" != "v$CZ_VERSION" ] || [ "$CONFIG_VERSION" != "v$COMP_VERSION" ]; then
|
||||
echo "Version mismatch detected:"
|
||||
echo "config.h: $CONFIG_VERSION"
|
||||
echo ".cz.yaml: $CZ_VERSION"
|
||||
echo "idf_component.yml: $COMP_VERSION"
|
||||
exit 1
|
||||
fi
|
||||
echo "Versions are consistent: $CONFIG_VERSION"
|
||||
|
||||
build_idf_tests_with_mosq:
|
||||
if: |
|
||||
github.repository == 'espressif/esp-protocols' &&
|
||||
( contains(github.event.pull_request.labels.*.name, 'mosquitto') || github.event_name == 'push' )
|
||||
name: Build IDF tests
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest"]
|
||||
idf_target: ["esp32"]
|
||||
test: [ { app: publish, path: "tools/test_apps/protocols/mqtt/publish_connect_test" }]
|
||||
runs-on: ubuntu-20.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
env:
|
||||
TARGET_TEST_DIR: build_esp32_local_broker
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Build ${{ matrix.test.app }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
pip install idf-component-manager idf-build-apps --upgrade
|
||||
export MOSQUITTO_PATH=`pwd`/components/mosquitto
|
||||
# to use the actual version of mosquitto
|
||||
sed -i '/espressif\/mosquitto:/a \ \ \ \ override_path: "${MOSQUITTO_PATH}"' ${IDF_PATH}/${{matrix.test.path}}/main/idf_component.yml
|
||||
export PEDANTIC_FLAGS="-DIDF_CI_BUILD -Werror -Werror=deprecated-declarations -Werror=unused-variable -Werror=unused-but-set-variable -Werror=unused-function"
|
||||
export EXTRA_CFLAGS="${PEDANTIC_FLAGS} -Wstrict-prototypes"
|
||||
export EXTRA_CXXFLAGS="${PEDANTIC_FLAGS}"
|
||||
cd ${IDF_PATH}/${{matrix.test.path}}
|
||||
idf-build-apps find --config sdkconfig.ci.local_broker -vv --target ${{ matrix.idf_target }} --build-dir=${TARGET_TEST_DIR}
|
||||
idf-build-apps build --config sdkconfig.ci.local_broker -vv --target ${{ matrix.idf_target }} --build-dir=${TARGET_TEST_DIR}
|
||||
${GITHUB_WORKSPACE}/ci/clean_build_artifacts.sh `pwd`/${TARGET_TEST_DIR}
|
||||
# to replace mqtt test configs with specific mosquitto markers
|
||||
python ${MOSQUITTO_PATH}/test/replace_decorators.py pytest_mqtt_publish_app.py ${TARGET_TEST_DIR}/pytest_mosquitto.py
|
||||
zip -qur ${GITHUB_WORKSPACE}/artifacts.zip ${TARGET_TEST_DIR}
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: mosq_publish_esp32_${{ matrix.idf_ver }}
|
||||
path: artifacts.zip
|
||||
if-no-files-found: error
|
||||
|
||||
test_idf_ci_with_mosq:
|
||||
# Skip running on forks since it won't have access to secrets
|
||||
if: |
|
||||
github.repository == 'espressif/esp-protocols' &&
|
||||
( contains(github.event.pull_request.labels.*.name, 'mosquitto') || github.event_name == 'push' )
|
||||
name: Mosquitto IDF target tests
|
||||
needs: build_idf_tests_with_mosq
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest"]
|
||||
runs-on:
|
||||
- self-hosted
|
||||
- ESP32-ETHERNET-KIT
|
||||
env:
|
||||
TEST_DIR: examples
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: mosq_publish_esp32_${{ matrix.idf_ver }}
|
||||
path: ${{ env.TEST_DIR }}/ci/
|
||||
- name: Run Test
|
||||
working-directory: ${{ env.TEST_DIR }}
|
||||
run: |
|
||||
python -m pip install pytest-embedded-serial-esp pytest-embedded-idf pytest-rerunfailures pytest-timeout pytest-ignore-test-results "paho-mqtt<2"
|
||||
unzip ci/artifacts.zip -d ci
|
||||
for dir in `ls -d ci/build_*`; do
|
||||
rm -rf build sdkconfig.defaults
|
||||
mv $dir build
|
||||
mv build/*.py .
|
||||
# Run only "test_mosquitto" marked tests
|
||||
python -m pytest --log-cli-level DEBUG --junit-xml=./results_esp32_${{ matrix.idf_ver }}_${dir#"ci/build_"}.xml --target=esp32 -m test_mosquitto
|
||||
done
|
||||
|
3
.github/workflows/publish-docs-component.yml
vendored
3
.github/workflows/publish-docs-component.yml
vendored
@ -98,7 +98,10 @@ jobs:
|
||||
components/console_cmd_ping;
|
||||
components/console_cmd_ifconfig;
|
||||
components/console_cmd_wifi;
|
||||
components/console_cmd_mqtt;
|
||||
components/mbedtls_cxx;
|
||||
components/mosquitto;
|
||||
components/sock_utils;
|
||||
components/libwebsockets;
|
||||
namespace: "espressif"
|
||||
api_token: ${{ secrets.IDF_COMPONENT_API_TOKEN }}
|
||||
|
95
.github/workflows/sockutls_build.yml
vendored
Normal file
95
.github/workflows/sockutls_build.yml
vendored
Normal file
@ -0,0 +1,95 @@
|
||||
name: "sock_utils: build-tests"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, labeled]
|
||||
|
||||
jobs:
|
||||
build_sock_utils:
|
||||
if: contains(github.event.pull_request.labels.*.name, 'sock_utils') || github.event_name == 'push'
|
||||
name: Socket helpers build
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest", "release-v5.3"]
|
||||
runs-on: ubuntu-22.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
env:
|
||||
TEST_DIR: components/sock_utils/examples/simple
|
||||
TARGET_TEST_DIR: build_esp32_default
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Build with IDF-${{ matrix.idf_ver }}
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
pip install idf-component-manager idf-build-apps --upgrade
|
||||
python ci/build_apps.py ${TEST_DIR}
|
||||
cd ${TEST_DIR}
|
||||
${GITHUB_WORKSPACE}/ci/clean_build_artifacts.sh `pwd`/${TARGET_TEST_DIR}
|
||||
zip -qur artifacts.zip ${TARGET_TEST_DIR}
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: sock_utils_target_esp32_${{ matrix.idf_ver }}
|
||||
path: ${{ env.TEST_DIR }}/artifacts.zip
|
||||
if-no-files-found: error
|
||||
host_test_sock_utils:
|
||||
if: contains(github.event.pull_request.labels.*.name, 'sock_utils') || github.event_name == 'push'
|
||||
name: Socket helpers host test
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest", "release-v5.3"]
|
||||
runs-on: ubuntu-22.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
env:
|
||||
TEST_DIR: components/sock_utils/test/host
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Build with IDF-${{ matrix.idf_ver }}
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
pip install idf-component-manager idf-build-apps --upgrade
|
||||
cd ${TEST_DIR}
|
||||
idf.py build
|
||||
./build/sock_utils_host_test.elf
|
||||
|
||||
test_sock_utils:
|
||||
# Skip running on forks since it won't have access to secrets
|
||||
if: |
|
||||
github.repository == 'espressif/esp-protocols' &&
|
||||
( contains(github.event.pull_request.labels.*.name, 'sock_utils') || github.event_name == 'push' )
|
||||
name: Socket helpers target test
|
||||
needs: build_sock_utils
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest", "release-v5.3"]
|
||||
runs-on:
|
||||
- self-hosted
|
||||
- ESP32-ETHERNET-KIT
|
||||
env:
|
||||
TEST_DIR: components/sock_utils/examples/simple
|
||||
TARGET_TEST_DIR: build_esp32_default
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: sock_utils_target_esp32_${{ matrix.idf_ver }}
|
||||
path: ${{ env.TEST_DIR }}/ci/
|
||||
- name: Run Test
|
||||
working-directory: ${{ env.TEST_DIR }}
|
||||
run: |
|
||||
unzip ci/artifacts.zip -d ci
|
||||
for dir in `ls -d ci/build_*`; do
|
||||
rm -rf build sdkconfig.defaults
|
||||
mv $dir build
|
||||
python -m pytest --log-cli-level DEBUG --junit-xml=./results_esp32_${{ matrix.idf_ver }}_${dir#"ci/build_"}.xml --target=esp32
|
||||
done
|
5
.gitmodules
vendored
5
.gitmodules
vendored
@ -1,6 +1,9 @@
|
||||
[submodule "components/asio/asio"]
|
||||
path = components/asio/asio
|
||||
url = https://github.com/espressif/asio
|
||||
url = https://github.com/chriskohlhoff/asio
|
||||
[submodule "components/mosquitto/mosquitto"]
|
||||
path = components/mosquitto/mosquitto
|
||||
url = https://github.com/eclipse/mosquitto
|
||||
[submodule "components/libwebsockets/libwebsockets"]
|
||||
path = components/libwebsockets/libwebsockets
|
||||
url = https://github.com/warmcat/libwebsockets.git
|
||||
|
@ -51,7 +51,7 @@ repos:
|
||||
rev: v1.0.5
|
||||
hooks:
|
||||
- id: astyle_py
|
||||
args: ['--style=otbs', '--attach-namespaces', '--attach-classes', '--indent=spaces=4', '--convert-tabs', '--align-pointer=name', '--align-reference=name', '--keep-one-line-statements', '--pad-header', '--pad-oper', '--exclude-list=ci/ignore_astyle.txt']
|
||||
args: ['--style=otbs', '--attach-namespaces', '--attach-classes', '--indent=spaces=4', '--convert-tabs', '--align-reference=name', '--keep-one-line-statements', '--pad-header', '--pad-oper', '--unpad-paren', '--max-continuation-indent=120', '--exclude-list=ci/ignore_astyle.txt']
|
||||
- repo: https://github.com/commitizen-tools/commitizen
|
||||
rev: v2.42.1
|
||||
hooks:
|
||||
@ -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, eppp, tls_cxx, mosq"
|
||||
entry: '\A(?!(feat|fix|ci|bump|test|docs|chore)\((mdns|modem|common|console|websocket|asio|mqtt_cxx|examples|eppp|tls_cxx|mosq)\)\:)'
|
||||
name: "commit message must be scoped with: mdns, modem, websocket, asio, mqtt_cxx, console, common, eppp, tls_cxx, mosq, sockutls, lws"
|
||||
entry: '\A(?!(feat|fix|ci|bump|test|docs|chore)\((mdns|modem|common|console|websocket|asio|mqtt_cxx|examples|eppp|tls_cxx|mosq|sockutls|lws)\)\:)'
|
||||
language: pygrep
|
||||
args: [--multiline]
|
||||
stages: [commit-msg]
|
||||
|
@ -62,3 +62,11 @@ Please refer to instructions in [ESP-IDF](https://github.com/espressif/esp-idf)
|
||||
|
||||
* Brief introduction [README](components/mosquitto/README.md)
|
||||
* API documentation [api.md](components/mosquitto/api.md)
|
||||
|
||||
### Socket helpers (sock-utils)
|
||||
|
||||
* Brief introduction [README](components/sock_utils/README.md)
|
||||
|
||||
### libwebsockets
|
||||
|
||||
* Brief introduction [README](components/libwebsockets/README.md)
|
||||
|
@ -0,0 +1 @@
|
||||
components/mosquitto/examples/serverless_mqtt/components/libjuice/port/juice_random.c
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -64,7 +64,7 @@ static struct generic_queue_handle *create_generic_queue(queue_type_t type, uint
|
||||
return h;
|
||||
}
|
||||
|
||||
QueueHandle_t xQueueCreate(uint32_t uxQueueLength, uint32_t uxItemSize )
|
||||
QueueHandle_t xQueueCreate(uint32_t uxQueueLength, uint32_t uxItemSize)
|
||||
{
|
||||
return (QueueHandle_t)create_generic_queue(QUEUE, uxQueueLength, uxItemSize);
|
||||
}
|
||||
@ -75,7 +75,7 @@ uint32_t xQueueSend(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t
|
||||
return osal_queue_send(h->q, (uint8_t *)pvItemToQueue, h->item_size) ? pdTRUE : pdFAIL;
|
||||
}
|
||||
|
||||
uint32_t xQueueSendToBack(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait )
|
||||
uint32_t xQueueSendToBack(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait)
|
||||
{
|
||||
return xQueueSend(xQueue, pvItemToQueue, xTicksToWait);
|
||||
}
|
||||
@ -86,7 +86,7 @@ uint32_t xQueueReceive(QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksTo
|
||||
return osal_queue_recv(h->q, (uint8_t *)pvBuffer, h->item_size, xTicksToWait) ? pdTRUE : pdFAIL;
|
||||
}
|
||||
|
||||
BaseType_t xSemaphoreGive( QueueHandle_t xQueue)
|
||||
BaseType_t xSemaphoreGive(QueueHandle_t xQueue)
|
||||
{
|
||||
struct generic_queue_handle *h = xQueue;
|
||||
if (h->type == MUTEX) {
|
||||
@ -96,7 +96,7 @@ BaseType_t xSemaphoreGive( QueueHandle_t xQueue)
|
||||
return xQueueSend(xQueue, &s_semaphore_data, portMAX_DELAY);
|
||||
}
|
||||
|
||||
BaseType_t xSemaphoreGiveRecursive( QueueHandle_t xQueue)
|
||||
BaseType_t xSemaphoreGiveRecursive(QueueHandle_t xQueue)
|
||||
{
|
||||
struct generic_queue_handle *h = xQueue;
|
||||
if (h->type == MUTEX_REC) {
|
||||
@ -106,7 +106,7 @@ BaseType_t xSemaphoreGiveRecursive( QueueHandle_t xQueue)
|
||||
return pdFALSE;
|
||||
}
|
||||
|
||||
BaseType_t xSemaphoreTake( QueueHandle_t xQueue, TickType_t pvTask )
|
||||
BaseType_t xSemaphoreTake(QueueHandle_t xQueue, TickType_t pvTask)
|
||||
{
|
||||
struct generic_queue_handle *h = xQueue;
|
||||
if (h->type == MUTEX) {
|
||||
@ -116,7 +116,7 @@ BaseType_t xSemaphoreTake( QueueHandle_t xQueue, TickType_t pvTask )
|
||||
return xQueueReceive(xQueue, &s_semaphore_data, portMAX_DELAY);
|
||||
}
|
||||
|
||||
BaseType_t xSemaphoreTakeRecursive( QueueHandle_t xQueue, TickType_t pvTask )
|
||||
BaseType_t xSemaphoreTakeRecursive(QueueHandle_t xQueue, TickType_t pvTask)
|
||||
{
|
||||
struct generic_queue_handle *h = xQueue;
|
||||
if (h->type == MUTEX_REC) {
|
||||
@ -126,7 +126,7 @@ BaseType_t xSemaphoreTakeRecursive( QueueHandle_t xQueue, TickType_t pvTask )
|
||||
return pdFALSE;
|
||||
}
|
||||
|
||||
void vQueueDelete( QueueHandle_t xQueue )
|
||||
void vQueueDelete(QueueHandle_t xQueue)
|
||||
{
|
||||
struct generic_queue_handle *h = xQueue;
|
||||
if (h->q) {
|
||||
@ -176,14 +176,14 @@ void vTaskSuspend(void *task)
|
||||
vTaskDelete(task);
|
||||
}
|
||||
|
||||
TickType_t xTaskGetTickCount( void )
|
||||
TickType_t xTaskGetTickCount(void)
|
||||
{
|
||||
struct timespec spec;
|
||||
clock_gettime(CLOCK_REALTIME, &spec);
|
||||
return spec.tv_nsec / 1000000 + spec.tv_sec * 1000;
|
||||
}
|
||||
|
||||
void vTaskDelay( const TickType_t xTicksToDelay )
|
||||
void vTaskDelay(const TickType_t xTicksToDelay)
|
||||
{
|
||||
usleep(xTicksToDelay * 1000);
|
||||
}
|
||||
@ -212,13 +212,27 @@ void *pthread_task(void *params)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BaseType_t xTaskCreatePinnedToCore( TaskFunction_t pvTaskCode,
|
||||
const char *const pcName,
|
||||
const uint32_t usStackDepth,
|
||||
void *const pvParameters,
|
||||
UBaseType_t uxPriority,
|
||||
TaskHandle_t *const pvCreatedTask,
|
||||
const BaseType_t xCoreID)
|
||||
TaskHandle_t xTaskCreateStaticPinnedToCore(TaskFunction_t pxTaskCode,
|
||||
const char *const pcName,
|
||||
const uint32_t ulStackDepth,
|
||||
void *const pvParameters,
|
||||
UBaseType_t uxPriority,
|
||||
StackType_t *const puxStackBuffer,
|
||||
StaticTask_t *const pxTaskBuffer,
|
||||
const BaseType_t xCoreID)
|
||||
{
|
||||
static TaskHandle_t pvCreatedTask;
|
||||
xTaskCreate(pxTaskCode, pcName, ulStackDepth, pvParameters, uxPriority, &pvCreatedTask);
|
||||
return pvCreatedTask;
|
||||
}
|
||||
|
||||
BaseType_t xTaskCreatePinnedToCore(TaskFunction_t pvTaskCode,
|
||||
const char *const pcName,
|
||||
const uint32_t usStackDepth,
|
||||
void *const pvParameters,
|
||||
UBaseType_t uxPriority,
|
||||
TaskHandle_t *const pvCreatedTask,
|
||||
const BaseType_t xCoreID)
|
||||
{
|
||||
xTaskCreate(pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pvCreatedTask);
|
||||
return pdTRUE;
|
||||
@ -266,7 +280,7 @@ void xTaskNotifyGive(TaskHandle_t task)
|
||||
}
|
||||
}
|
||||
|
||||
BaseType_t xTaskNotifyWait(uint32_t bits_entry_clear, uint32_t bits_exit_clear, uint32_t *value, TickType_t wait_time )
|
||||
BaseType_t xTaskNotifyWait(uint32_t bits_entry_clear, uint32_t bits_exit_clear, uint32_t *value, TickType_t wait_time)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -276,32 +290,32 @@ TaskHandle_t xTaskGetCurrentTaskHandle(void)
|
||||
return (TaskHandle_t)pthread_self();
|
||||
}
|
||||
|
||||
EventGroupHandle_t xEventGroupCreate( void )
|
||||
EventGroupHandle_t xEventGroupCreate(void)
|
||||
{
|
||||
return osal_signal_create();
|
||||
}
|
||||
|
||||
void vEventGroupDelete( EventGroupHandle_t xEventGroup )
|
||||
void vEventGroupDelete(EventGroupHandle_t xEventGroup)
|
||||
{
|
||||
osal_signal_delete(xEventGroup);
|
||||
}
|
||||
|
||||
EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear )
|
||||
EventBits_t xEventGroupClearBits(EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear)
|
||||
{
|
||||
return osal_signal_clear(xEventGroup, uxBitsToClear);
|
||||
}
|
||||
|
||||
EventBits_t xEventGroupGetBits( EventGroupHandle_t xEventGroup)
|
||||
EventBits_t xEventGroupGetBits(EventGroupHandle_t xEventGroup)
|
||||
{
|
||||
return osal_signal_get(xEventGroup);
|
||||
}
|
||||
|
||||
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet )
|
||||
EventBits_t xEventGroupSetBits(EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet)
|
||||
{
|
||||
return osal_signal_set(xEventGroup, uxBitsToSet);
|
||||
}
|
||||
|
||||
EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait )
|
||||
EventBits_t xEventGroupWaitBits(EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait)
|
||||
{
|
||||
return osal_signal_wait(xEventGroup, uxBitsToWaitFor, xWaitForAllBits, xTicksToWait);
|
||||
}
|
||||
|
@ -1,11 +1,12 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "esp_heap_caps.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -15,7 +16,10 @@ extern "C" {
|
||||
#define TaskHandle_t TaskHandle_t
|
||||
#define vSemaphoreDelete( xSemaphore ) vQueueDelete( ( QueueHandle_t ) ( xSemaphore ) )
|
||||
|
||||
void vTaskDelay( const TickType_t xTicksToDelay );
|
||||
typedef void *StackType_t;
|
||||
typedef void *StaticTask_t;
|
||||
|
||||
void vTaskDelay(const TickType_t xTicksToDelay);
|
||||
|
||||
void xTaskNotifyGive(TaskHandle_t task);
|
||||
|
||||
@ -23,39 +27,48 @@ void ulTaskNotifyTake(bool stuff, uint32_t timeout);
|
||||
|
||||
TaskHandle_t xTaskGetCurrentTaskHandle(void);
|
||||
|
||||
BaseType_t xTaskNotifyWait(uint32_t bits_entry_clear, uint32_t bits_exit_clear, uint32_t *value, TickType_t wait_time );
|
||||
BaseType_t xTaskNotifyWait(uint32_t bits_entry_clear, uint32_t bits_exit_clear, uint32_t *value, TickType_t wait_time);
|
||||
|
||||
BaseType_t xTaskCreatePinnedToCore( TaskFunction_t pvTaskCode,
|
||||
const char *const pcName,
|
||||
const uint32_t usStackDepth,
|
||||
void *const pvParameters,
|
||||
UBaseType_t uxPriority,
|
||||
TaskHandle_t *const pvCreatedTask,
|
||||
const BaseType_t xCoreID);
|
||||
TaskHandle_t xTaskCreateStaticPinnedToCore(TaskFunction_t pxTaskCode,
|
||||
const char *const pcName,
|
||||
const uint32_t ulStackDepth,
|
||||
void *const pvParameters,
|
||||
UBaseType_t uxPriority,
|
||||
StackType_t *const puxStackBuffer,
|
||||
StaticTask_t *const pxTaskBuffer,
|
||||
const BaseType_t xCoreID);
|
||||
|
||||
BaseType_t xTaskCreatePinnedToCore(TaskFunction_t pvTaskCode,
|
||||
const char *const pcName,
|
||||
const uint32_t usStackDepth,
|
||||
void *const pvParameters,
|
||||
UBaseType_t uxPriority,
|
||||
TaskHandle_t *const pvCreatedTask,
|
||||
const BaseType_t xCoreID);
|
||||
|
||||
BaseType_t xTaskCreate(TaskFunction_t pvTaskCode, const char *const pcName, const uint32_t usStackDepth, void *const pvParameters, UBaseType_t uxPriority, TaskHandle_t *const pvCreatedTask);
|
||||
|
||||
TickType_t xTaskGetTickCount( void );
|
||||
TickType_t xTaskGetTickCount(void);
|
||||
|
||||
void vQueueDelete( QueueHandle_t xQueue );
|
||||
void vQueueDelete(QueueHandle_t xQueue);
|
||||
|
||||
QueueHandle_t xSemaphoreCreateBinary(void);
|
||||
|
||||
QueueHandle_t xSemaphoreCreateMutex(void);
|
||||
QueueHandle_t xSemaphoreCreateRecursiveMutex(void);
|
||||
|
||||
BaseType_t xSemaphoreGive( QueueHandle_t xQueue);
|
||||
BaseType_t xSemaphoreGive(QueueHandle_t xQueue);
|
||||
|
||||
BaseType_t xSemaphoreTake( QueueHandle_t xQueue, TickType_t pvTask );
|
||||
BaseType_t xSemaphoreTake(QueueHandle_t xQueue, TickType_t pvTask);
|
||||
|
||||
BaseType_t xSemaphoreGiveRecursive( QueueHandle_t xQueue);
|
||||
BaseType_t xSemaphoreGiveRecursive(QueueHandle_t xQueue);
|
||||
|
||||
BaseType_t xSemaphoreTakeRecursive( QueueHandle_t xQueue, TickType_t pvTask );
|
||||
BaseType_t xSemaphoreTakeRecursive(QueueHandle_t xQueue, TickType_t pvTask);
|
||||
|
||||
void vTaskDelete(TaskHandle_t *task);
|
||||
|
||||
QueueHandle_t xQueueCreate( uint32_t uxQueueLength,
|
||||
uint32_t uxItemSize );
|
||||
QueueHandle_t xQueueCreate(uint32_t uxQueueLength,
|
||||
uint32_t uxItemSize);
|
||||
|
||||
uint32_t xQueueSend(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait);
|
||||
|
||||
@ -63,23 +76,26 @@ uint32_t xQueueReceive(QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksTo
|
||||
|
||||
void vTaskSuspend(void *task);
|
||||
|
||||
EventGroupHandle_t xEventGroupCreate( void );
|
||||
void vEventGroupDelete( EventGroupHandle_t xEventGroup );
|
||||
EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup,
|
||||
const EventBits_t uxBitsToClear );
|
||||
EventGroupHandle_t xEventGroupCreate(void);
|
||||
void vEventGroupDelete(EventGroupHandle_t xEventGroup);
|
||||
EventBits_t xEventGroupClearBits(EventGroupHandle_t xEventGroup,
|
||||
const EventBits_t uxBitsToClear);
|
||||
|
||||
EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup,
|
||||
const EventBits_t uxBitsToWaitFor,
|
||||
const BaseType_t xClearOnExit,
|
||||
const BaseType_t xWaitForAllBits,
|
||||
TickType_t xTicksToWait );
|
||||
EventBits_t xEventGroupWaitBits(EventGroupHandle_t xEventGroup,
|
||||
const EventBits_t uxBitsToWaitFor,
|
||||
const BaseType_t xClearOnExit,
|
||||
const BaseType_t xWaitForAllBits,
|
||||
TickType_t xTicksToWait);
|
||||
|
||||
EventBits_t xEventGroupGetBits( EventGroupHandle_t xEventGroup);
|
||||
EventBits_t xEventGroupGetBits(EventGroupHandle_t xEventGroup);
|
||||
|
||||
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup,
|
||||
const EventBits_t uxBitsToSet );
|
||||
EventBits_t xEventGroupSetBits(EventGroupHandle_t xEventGroup,
|
||||
const EventBits_t uxBitsToSet);
|
||||
|
||||
uint32_t xQueueSendToBack(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait );
|
||||
uint32_t xQueueSendToBack(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait);
|
||||
|
||||
void *heap_caps_malloc(size_t size, uint32_t caps);
|
||||
void heap_caps_free(void *ptr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -1,7 +1,8 @@
|
||||
---
|
||||
commitizen:
|
||||
bump_message: 'bump(asio): $current_version -> $new_version'
|
||||
pre_bump_hooks: python ../../ci/changelog.py asio
|
||||
tag_format: asio-v$version
|
||||
version: 1.28.0~0
|
||||
version: 1.32.0
|
||||
version_files:
|
||||
- idf_component.yml
|
||||
|
@ -1,5 +1,26 @@
|
||||
# Changelog
|
||||
|
||||
## [1.32.0](https://github.com/espressif/esp-protocols/commits/asio-v1.32.0)
|
||||
|
||||
### Features
|
||||
|
||||
- Upgrade asio to 1.32 ([9bdd429c](https://github.com/espressif/esp-protocols/commit/9bdd429c))
|
||||
- Drop esp/asio patches in favor of sock-utils ([27435b7f](https://github.com/espressif/esp-protocols/commit/27435b7f))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Fix chat example to print only the message body ([76aaea08](https://github.com/espressif/esp-protocols/commit/76aaea08))
|
||||
- Make asio enable if_nametoindex to fix linking ([5db32cce](https://github.com/espressif/esp-protocols/commit/5db32cce))
|
||||
- Re-applie refs to common comps idf_component.yml ([9fe44a45](https://github.com/espressif/esp-protocols/commit/9fe44a45))
|
||||
- Reference common component from IDF ([74fc228c](https://github.com/espressif/esp-protocols/commit/74fc228c))
|
||||
- Revert referencing protocol_examples_common from IDF ([f9e0281a](https://github.com/espressif/esp-protocols/commit/f9e0281a))
|
||||
- reference protocol_examples_common from IDF ([09abb18b](https://github.com/espressif/esp-protocols/commit/09abb18b))
|
||||
- specify override_path in example manifest files ([1d8923cf](https://github.com/espressif/esp-protocols/commit/1d8923cf))
|
||||
|
||||
### Updated
|
||||
|
||||
- docs(asio): Updates asio docs ([ce9337d3](https://github.com/espressif/esp-protocols/commit/ce9337d3))
|
||||
|
||||
## [1.28.2~0](https://github.com/espressif/esp-protocols/commits/asio-1.28.2_0)
|
||||
|
||||
### Bug Fixes
|
||||
|
@ -6,8 +6,8 @@ if(NOT CONFIG_LWIP_IPV6 AND NOT CMAKE_BUILD_EARLY_EXPANSION)
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(asio_sources "asio/asio/src/asio.cpp")
|
||||
set(asio_requires lwip)
|
||||
set(asio_sources "asio/asio/src/asio.cpp" "port/src/asio_stub.cpp")
|
||||
set(asio_requires lwip sock_utils)
|
||||
|
||||
if(CONFIG_ASIO_SSL_SUPPORT)
|
||||
list(APPEND asio_sources
|
||||
@ -18,7 +18,7 @@ if(CONFIG_ASIO_SSL_SUPPORT)
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS ${asio_sources}
|
||||
INCLUDE_DIRS "asio/asio/include" "port/include"
|
||||
INCLUDE_DIRS "port/include" "asio/asio/include"
|
||||
PRIV_INCLUDE_DIRS ${asio_priv_includes}
|
||||
PRIV_REQUIRES ${asio_requires})
|
||||
|
||||
@ -30,6 +30,7 @@ target_compile_definitions(${COMPONENT_LIB} PUBLIC SA_RESTART=0x01
|
||||
ASIO_STANDALONE
|
||||
ASIO_HAS_PTHREADS
|
||||
OPENSSL_NO_ENGINE
|
||||
ASIO_DETAIL_IMPL_POSIX_EVENT_IPP # this replaces asio's posix_event constructor
|
||||
)
|
||||
|
||||
if(NOT CONFIG_COMPILER_CXX_EXCEPTIONS)
|
||||
|
@ -1,6 +1,15 @@
|
||||
menu "ESP-ASIO"
|
||||
visible if LWIP_IPV6
|
||||
|
||||
config ASIO_IS_ENABLED
|
||||
# Invisible option that is enabled if ASIO is added to the IDF components.
|
||||
# This is used to "select" LWIP_NETIF_API option
|
||||
# which enables if_indextoname() and if_nametoindex() functions
|
||||
# (these are optionally used in asio)
|
||||
bool
|
||||
default "y"
|
||||
select LWIP_NETIF_API
|
||||
|
||||
config ASIO_SSL_SUPPORT
|
||||
bool "Enable SSL/TLS support of ASIO"
|
||||
default n
|
||||
|
Submodule components/asio/asio updated: a2e0f70d61...03ae834edb
@ -120,7 +120,7 @@ private:
|
||||
asio::buffer(read_msg_.body(), read_msg_.body_length()),
|
||||
[this, self](std::error_code ec, std::size_t /*length*/) {
|
||||
if (!ec) {
|
||||
ESP_LOGD("asio-chat:", "%s", read_msg_.body());
|
||||
ESP_LOGD("asio-chat", "%.*s", read_msg_.body_length(), read_msg_.body());
|
||||
room_.deliver(read_msg_);
|
||||
do_read_header();
|
||||
} else {
|
||||
|
@ -1,4 +1,4 @@
|
||||
version: "1.28.2~0"
|
||||
version: "1.32.0"
|
||||
description: Cross-platform C++ library for network and I/O programming
|
||||
url: https://github.com/espressif/esp-protocols/tree/master/components/asio
|
||||
issues: https://github.com/espressif/esp-protocols/issues
|
||||
@ -7,3 +7,5 @@ repository: https://github.com/espressif/esp-protocols.git
|
||||
dependencies:
|
||||
idf:
|
||||
version: ">=5.0"
|
||||
espressif/sock_utils:
|
||||
version: "^0.1"
|
||||
|
11
components/asio/port/include/asio/detail/config.hpp
Normal file
11
components/asio/port/include/asio/detail/config.hpp
Normal file
@ -0,0 +1,11 @@
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "sys/socket.h"
|
||||
#include "socketpair.h"
|
||||
|
||||
#include_next "asio/detail/config.hpp"
|
@ -1,12 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2018-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef _ESP_ASIO_CONFIG_H_
|
||||
#define _ESP_ASIO_CONFIG_H_
|
||||
|
||||
#define ASIO_SSL_DETAIL_OPENSSL_TYPES_HPP
|
||||
#include "openssl_stub.hpp"
|
||||
|
||||
#endif // _ESP_ASIO_CONFIG_H_
|
@ -8,7 +8,7 @@
|
||||
//
|
||||
|
||||
#include "asio/detail/config.hpp"
|
||||
#include "openssl_stub.hpp"
|
||||
#include "asio/ssl/detail/openssl_types.hpp"
|
||||
#include <cstring>
|
||||
#include "asio/detail/throw_error.hpp"
|
||||
#include "asio/error.hpp"
|
||||
|
@ -7,7 +7,7 @@
|
||||
//
|
||||
|
||||
#include "asio/detail/config.hpp"
|
||||
#include "openssl_stub.hpp"
|
||||
#include "asio/ssl/detail/openssl_types.hpp"
|
||||
#include "asio/detail/throw_error.hpp"
|
||||
#include "asio/error.hpp"
|
||||
#include "asio/ssl/detail/engine.hpp"
|
||||
|
36
components/asio/port/src/asio_stub.cpp
Normal file
36
components/asio/port/src/asio_stub.cpp
Normal file
@ -0,0 +1,36 @@
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
// SPDX-FileContributor: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
//
|
||||
#include "asio/detail/posix_event.hpp"
|
||||
#include "asio/detail/throw_error.hpp"
|
||||
#include "asio/error.hpp"
|
||||
#include "asio/detail/push_options.hpp"
|
||||
#include <unistd.h>
|
||||
#include <climits>
|
||||
|
||||
namespace asio::detail {
|
||||
// This replaces asio's posix_event constructor
|
||||
// since the default POSIX version uses pthread_condattr_t operations (init, setclock, destroy),
|
||||
// which are not available on all IDF versions (some are defined in compilers' headers, others in
|
||||
// pthread library, but they typically return `ENOSYS` which causes trouble in the event wrapper)
|
||||
// IMPORTANT: Check implementation of posix_event() when upgrading upstream asio in order not to
|
||||
// miss any initialization step.
|
||||
posix_event::posix_event()
|
||||
: state_(0)
|
||||
{
|
||||
int error = ::pthread_cond_init(&cond_, nullptr);
|
||||
asio::error_code ec(error, asio::error::get_system_category());
|
||||
asio::detail::throw_error(ec, "event");
|
||||
}
|
||||
} // namespace asio::detail
|
||||
|
||||
extern "C" int pause (void)
|
||||
{
|
||||
while (true) {
|
||||
::sleep(UINT_MAX);
|
||||
}
|
||||
}
|
8
components/console_cmd_mqtt/.cz.yaml
Normal file
8
components/console_cmd_mqtt/.cz.yaml
Normal file
@ -0,0 +1,8 @@
|
||||
---
|
||||
commitizen:
|
||||
bump_message: 'bump(console): $current_version -> $new_version'
|
||||
pre_bump_hooks: python ../../ci/changelog.py console_cmd_mqtt
|
||||
tag_format: console_cmd_mqtt-v$version
|
||||
version: 1.0.0
|
||||
version_files:
|
||||
- idf_component.yml
|
7
components/console_cmd_mqtt/CHANGELOG.md
Normal file
7
components/console_cmd_mqtt/CHANGELOG.md
Normal file
@ -0,0 +1,7 @@
|
||||
# Changelog
|
||||
|
||||
## [1.0.0](https://github.com/espressif/esp-protocols/commits/console_cmd_mqtt-v1.0.0)
|
||||
|
||||
### Features
|
||||
|
||||
- Added component with mqtt command ([1fcc5b1d](https://github.com/espressif/esp-protocols/commit/1fcc5b1d))
|
7
components/console_cmd_mqtt/CMakeLists.txt
Normal file
7
components/console_cmd_mqtt/CMakeLists.txt
Normal file
@ -0,0 +1,7 @@
|
||||
idf_component_register(SRCS "console_mqtt.c"
|
||||
INCLUDE_DIRS "."
|
||||
PRIV_REQUIRES esp_netif console mqtt)
|
||||
|
||||
if(CONFIG_MQTT_CMD_AUTO_REGISTRATION)
|
||||
target_link_libraries(${COMPONENT_LIB} PRIVATE "-u console_cmd_mqtt_register")
|
||||
endif()
|
15
components/console_cmd_mqtt/Kconfig.projbuild
Normal file
15
components/console_cmd_mqtt/Kconfig.projbuild
Normal file
@ -0,0 +1,15 @@
|
||||
menu "MQTT Configuration"
|
||||
|
||||
config MQTT_CMD_AUTO_REGISTRATION
|
||||
bool "Enable Console command mqtt Auto-registration"
|
||||
default y
|
||||
help
|
||||
Enabling this allows for the autoregistration of the wifi command.
|
||||
|
||||
config MQTT_BROKER_URL
|
||||
string "Broker URL or IP address"
|
||||
default "mqtt://mqtt.eclipseprojects.io"
|
||||
help
|
||||
URL or IP address of the broker to connect to
|
||||
|
||||
endmenu
|
87
components/console_cmd_mqtt/README.md
Normal file
87
components/console_cmd_mqtt/README.md
Normal file
@ -0,0 +1,87 @@
|
||||
# Console command mqtt
|
||||
The component provides a console where mqtt commands can be executed.
|
||||
|
||||
|
||||
## MQTT Configuration:
|
||||
1. Broker: Use menuconfig **"MQTT Configuration"** to configure the broker url.
|
||||
|
||||
|
||||
## API
|
||||
|
||||
### Steps to enable console in an example code:
|
||||
1. Add this component to your project using ```idf.py add-dependency``` command.
|
||||
2. In the main file of the example, add the following line:
|
||||
```c
|
||||
#include "console_mqtt.h"
|
||||
```
|
||||
3. Ensure esp-netif is initialized and default event loop is created in your app_main():
|
||||
```c
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
```
|
||||
4. In your app_main() function, add the following line as the last line:
|
||||
```c
|
||||
ESP_ERROR_CHECK(console_cmd_init()); // Initialize console
|
||||
|
||||
// Register all plugin command added to your project
|
||||
ESP_ERROR_CHECK(console_cmd_all_register());
|
||||
|
||||
// To register only mqtt command skip calling console_cmd_all_register()
|
||||
ESP_ERROR_CHECK(console_cmd_mqtt_register());
|
||||
|
||||
ESP_ERROR_CHECK(console_cmd_start()); // Start console
|
||||
```
|
||||
|
||||
Note: Auto-registration of a specific plugin command can be disabled from menuconfig.
|
||||
|
||||
### Certificate Integration for Mutual Authentication
|
||||
To enhance security and enable secure communication over MQTT, three functions have been added to the API, allowing users to set client certificates, client keys, and broker certificates separately.
|
||||
|
||||
Setting the client certificate:
|
||||
```c
|
||||
set_mqtt_client_cert(client_cert_pem_start, client_cert_pem_end);
|
||||
```
|
||||
Setting the client key:
|
||||
```c
|
||||
set_mqtt_client_key(client_key_pem_start, client_key_pem_end);
|
||||
```
|
||||
Setting the broker certificate:
|
||||
```c
|
||||
set_mqtt_broker_certs(broker_cert_pem_start, broker_cert_pem_end);
|
||||
```
|
||||
Each function takes pointers to the start and end of the respective PEM-encoded data, allowing users to specify the necessary certificate and key information independently. For a complete secure MQTT setup, users should call all three functions in their application code.
|
||||
|
||||
To utilize these certificates, users need to include additional arguments when establishing MQTT connections using the library. Specifically, users should provide the `--cert`, `--key`, and `--cafile` options along with the MQTT connection command.
|
||||
|
||||
### Adding a plugin command or component:
|
||||
To add a plugin command or any component from IDF component manager into your project, simply include an entry within the `idf_component.yml` file.
|
||||
|
||||
For more details refer [IDF Component Manager](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/tools/idf-component-manager.html)
|
||||
|
||||
## Suported command:
|
||||
|
||||
### mqtt:
|
||||
```
|
||||
mqtt [-CsD] [-h <host>] [-u <username>] [-P <password>] [--cert] [--key] [--cafile]
|
||||
mqtt command
|
||||
-C, --connect Connect to a broker (flag, no argument)
|
||||
-h, --host=<host> Specify the host uri to connect to
|
||||
-s, --status Displays the status of the mqtt client (flag, no argument)
|
||||
-u, --username=<username> Provide a username to be used for authenticating with the broker
|
||||
-P, --password=<password> Provide a password to be used for authenticating with the broker
|
||||
--cert Define the PEM encoded certificate for this client, if required by the broker (flag, no argument)
|
||||
--key Define the PEM encoded private key for this client, if required by the broker (flag, no argument)
|
||||
--cafile Define the PEM encoded CA certificates that are trusted (flag, no argument)
|
||||
--use-internal-bundle Use the internal certificate bundle for TLS (flag, no argument)
|
||||
-D, --disconnect Disconnect from the broker (flag, no argument)
|
||||
|
||||
mqtt_pub [-t <topic>] [-m <message>]
|
||||
mqtt publish command
|
||||
-t, --topic=<topic> Topic to Subscribe/Publish
|
||||
-m, --message=<message> Message to Publish
|
||||
|
||||
mqtt_sub [-U] [-t <topic>]
|
||||
mqtt subscribe command
|
||||
-t, --topic=<topic> Topic to Subscribe/Publish
|
||||
-U, --unsubscribe Unsubscribe from a topic
|
||||
```
|
475
components/console_cmd_mqtt/console_mqtt.c
Normal file
475
components/console_cmd_mqtt/console_mqtt.c
Normal file
@ -0,0 +1,475 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_console.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_log.h"
|
||||
#include "argtable3/argtable3.h"
|
||||
#include "console_mqtt.h"
|
||||
#include "mqtt_client.h"
|
||||
#if defined(CONFIG_MBEDTLS_CERTIFICATE_BUNDLE)
|
||||
#include "esp_crt_bundle.h"
|
||||
#endif
|
||||
|
||||
static const char *TAG = "console_mqtt";
|
||||
|
||||
#define CONNECT_HELP_MSG "mqtt -C -h <host uri> -u <username> -P <password> --cert --key --cafile\n"
|
||||
#define PUBLISH_HELP_MSG "Usage: mqtt -P -t <topic> -d <data>\n"
|
||||
#define SUBSCRIBE_HELP_MSG "Usage: mqtt -S -t <topic>\n"
|
||||
#define UNSUBSCRIBE_HELP_MSG "Usage: mqtt -U\n"
|
||||
#define DISCONNECT_HELP_MSG "Usage: mqtt -D\n"
|
||||
|
||||
#if CONFIG_MQTT_CMD_AUTO_REGISTRATION
|
||||
/**
|
||||
* Static registration of this plugin is achieved by defining the plugin description
|
||||
* structure and placing it into .console_cmd_desc section.
|
||||
* The name of the section and its placement is determined by linker.lf file in 'plugins' component.
|
||||
*/
|
||||
static const console_cmd_plugin_desc_t __attribute__((section(".console_cmd_desc"), used)) PLUGIN = {
|
||||
.name = "console_cmd_mqtt",
|
||||
.plugin_regd_fn = &console_cmd_mqtt_register
|
||||
};
|
||||
#endif
|
||||
|
||||
static struct {
|
||||
struct arg_lit *connect;
|
||||
struct arg_str *uri;
|
||||
struct arg_lit *status;
|
||||
struct arg_str *username;
|
||||
struct arg_str *password;
|
||||
struct arg_lit *cert;
|
||||
struct arg_lit *key;
|
||||
struct arg_lit *cafile;
|
||||
#if defined(CONFIG_MBEDTLS_CERTIFICATE_BUNDLE)
|
||||
struct arg_lit *use_internal_bundle;
|
||||
#endif
|
||||
struct arg_lit *disconnect;
|
||||
|
||||
struct arg_end *end;
|
||||
} mqtt_args;
|
||||
|
||||
static struct {
|
||||
struct arg_str *topic;
|
||||
struct arg_lit *unsubscribe;
|
||||
|
||||
struct arg_end *end;
|
||||
} mqtt_sub_args;
|
||||
|
||||
static struct {
|
||||
struct arg_str *topic;
|
||||
struct arg_str *message;
|
||||
|
||||
struct arg_end *end;
|
||||
} mqtt_pub_args;
|
||||
|
||||
typedef enum {
|
||||
MQTT_STATE_INIT = 0,
|
||||
MQTT_STATE_DISCONNECTED,
|
||||
MQTT_STATE_CONNECTED,
|
||||
MQTT_STATE_ERROR,
|
||||
MQTT_STATE_STOPPED,
|
||||
} mqtt_client_state_t;
|
||||
|
||||
mqtt_client_state_t client_status = MQTT_STATE_INIT;
|
||||
|
||||
static esp_mqtt_client_handle_t client_handle = NULL;
|
||||
|
||||
static const uint8_t *s_own_cert_pem_start = NULL;
|
||||
static const uint8_t *s_own_cert_pem_end = NULL;
|
||||
static const uint8_t *s_own_key_pem_start = NULL;
|
||||
static const uint8_t *s_own_key_pem_end = NULL;
|
||||
static const uint8_t *s_ca_cert_pem_start = NULL;
|
||||
static const uint8_t *s_ca_cert_pem_end = NULL;
|
||||
|
||||
static void log_error_if_nonzero(const char *message, int error_code)
|
||||
{
|
||||
if (error_code != 0) {
|
||||
ESP_LOGE(TAG, "Last error %s: 0x%x", message, error_code);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Event handler registered to receive MQTT events
|
||||
*
|
||||
* This function is called by the MQTT client event loop.
|
||||
*
|
||||
* @param handler_args user data registered to the event.
|
||||
* @param base Event base for the handler(always MQTT Base in this example).
|
||||
* @param event_id The id for the received event.
|
||||
* @param event_data The data for the event, esp_mqtt_event_handle_t.
|
||||
*/
|
||||
static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
|
||||
{
|
||||
ESP_LOGD(TAG, "Event dispatched from event loop base=%s, event_id=%" PRIi32, base, event_id);
|
||||
esp_mqtt_event_handle_t event = event_data;
|
||||
switch ((esp_mqtt_event_id_t)event_id) {
|
||||
case MQTT_EVENT_BEFORE_CONNECT:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_BEFORE_CONNECT");
|
||||
break;
|
||||
case MQTT_EVENT_CONNECTED:
|
||||
client_status = MQTT_STATE_CONNECTED;
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
|
||||
break;
|
||||
case MQTT_EVENT_DISCONNECTED:
|
||||
client_status = MQTT_STATE_DISCONNECTED;
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
|
||||
break;
|
||||
case MQTT_EVENT_SUBSCRIBED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->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");
|
||||
ESP_LOGI(TAG, "TOPIC=%.*s\r\n", event->topic_len, event->topic);
|
||||
ESP_LOGI(TAG, "DATA=%.*s\r\n", event->data_len, event->data);
|
||||
break;
|
||||
case MQTT_EVENT_ERROR:
|
||||
client_status = MQTT_STATE_ERROR;
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_ERROR");
|
||||
if (event->error_handle->error_type == MQTT_ERROR_TYPE_TCP_TRANSPORT) {
|
||||
log_error_if_nonzero("reported from esp-tls", event->error_handle->esp_tls_last_esp_err);
|
||||
log_error_if_nonzero("reported from tls stack", event->error_handle->esp_tls_stack_err);
|
||||
log_error_if_nonzero("captured as transport's socket errno", event->error_handle->esp_transport_sock_errno);
|
||||
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 const char *mqtt_state_to_string(mqtt_client_state_t state)
|
||||
{
|
||||
switch (state) {
|
||||
case MQTT_STATE_INIT:
|
||||
return "Initializing";
|
||||
case MQTT_STATE_DISCONNECTED:
|
||||
return "Disconnected";
|
||||
case MQTT_STATE_CONNECTED:
|
||||
return "Connected";
|
||||
case MQTT_STATE_ERROR:
|
||||
return "Error";
|
||||
case MQTT_STATE_STOPPED:
|
||||
return "Disconnected and Stopped";
|
||||
default:
|
||||
return "Unknown State";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int do_mqtt_cmd(int argc, char **argv)
|
||||
{
|
||||
int nerrors = arg_parse(argc, argv, (void **)&mqtt_args);
|
||||
if (nerrors != 0) {
|
||||
arg_print_errors(stderr, mqtt_args.end, argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (mqtt_args.status->count > 0) {
|
||||
ESP_LOGI(TAG, "MQTT Client Status: %s\n", mqtt_state_to_string(client_status));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mqtt_args.connect->count > 0) {
|
||||
|
||||
if (client_handle != NULL) {
|
||||
ESP_LOGW(TAG, "mqtt client already connected");
|
||||
ESP_LOGI(TAG, "Try: %s", DISCONNECT_HELP_MSG);
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *uri = CONFIG_MQTT_BROKER_URL;
|
||||
if (mqtt_args.uri->count > 0) {
|
||||
uri = (char *)mqtt_args.uri->sval[0];
|
||||
}
|
||||
|
||||
esp_mqtt_client_config_t mqtt_cfg = {
|
||||
.broker.address.uri = uri,
|
||||
};
|
||||
|
||||
if ((mqtt_args.username->count > 0) && (mqtt_args.password->count > 0)) {
|
||||
mqtt_cfg.credentials.username = mqtt_args.username->sval[0];
|
||||
mqtt_cfg.credentials.authentication.password = mqtt_args.password->sval[0];
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "broker: %s", mqtt_cfg.broker.address.uri);
|
||||
|
||||
#if defined(CONFIG_MBEDTLS_CERTIFICATE_BUNDLE)
|
||||
/* Ensure --use_internal_bundle and --cafile are mutually exclusive */
|
||||
if ((mqtt_args.use_internal_bundle->count > 0) && (mqtt_args.cafile->count > 0)) {
|
||||
ESP_LOGE(TAG, "Error: Options can't be used together. Use either --use-internal-bundle or --cafile. \n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (mqtt_args.use_internal_bundle->count > 0) {
|
||||
mqtt_cfg.broker.verification.crt_bundle_attach = esp_crt_bundle_attach;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (mqtt_args.cafile->count > 0) {
|
||||
if (s_ca_cert_pem_start && s_ca_cert_pem_end) {
|
||||
mqtt_cfg.broker.verification.certificate = (const char *)s_ca_cert_pem_start;
|
||||
} else {
|
||||
ESP_LOGW(TAG, "cafile not provided");
|
||||
}
|
||||
}
|
||||
|
||||
if (mqtt_args.cert->count > 0) {
|
||||
if (s_own_cert_pem_start && s_own_cert_pem_end) {
|
||||
mqtt_cfg.credentials.authentication.certificate = (const char *)s_own_cert_pem_start;
|
||||
} else {
|
||||
ESP_LOGW(TAG, "cert not provided");
|
||||
}
|
||||
|
||||
if (mqtt_args.key->count > 0) {
|
||||
if (s_own_key_pem_start && s_own_key_pem_end) {
|
||||
mqtt_cfg.credentials.authentication.key = (const char *)s_own_key_pem_start;
|
||||
} else {
|
||||
ESP_LOGW(TAG, "key not provided");
|
||||
}
|
||||
} else {
|
||||
mqtt_cfg.credentials.authentication.key = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
client_handle = esp_mqtt_client_init(&mqtt_cfg);
|
||||
if (client_handle == NULL) {
|
||||
ESP_LOGE(TAG, "ERROR: Client init");
|
||||
ESP_LOGI(TAG, "Try: %s", DISCONNECT_HELP_MSG);
|
||||
ESP_LOGE(TAG, CONNECT_HELP_MSG);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* 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_handle, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL);
|
||||
esp_mqtt_client_start(client_handle);
|
||||
|
||||
} else if (mqtt_args.disconnect->count > 0) {
|
||||
ESP_LOGD(TAG, "Disconnect command received:");
|
||||
|
||||
if (client_handle == NULL) {
|
||||
ESP_LOGE(TAG, "mqtt client not connected");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (esp_mqtt_client_stop(client_handle) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to stop mqtt client task");
|
||||
return 1;
|
||||
}
|
||||
|
||||
client_handle = NULL;
|
||||
client_status = MQTT_STATE_STOPPED;
|
||||
ESP_LOGI(TAG, "mqtt client disconnected and stopped");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
esp_err_t set_mqtt_client_cert(const uint8_t *client_cert_pem_start_i, const uint8_t *client_cert_pem_end_i)
|
||||
{
|
||||
if (!client_cert_pem_start_i || !client_cert_pem_end_i ||
|
||||
(client_cert_pem_start_i > client_cert_pem_end_i)) {
|
||||
ESP_LOGE(TAG, "Invalid mqtt Client certs(%d)\n", __LINE__);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
s_own_cert_pem_start = client_cert_pem_start_i;
|
||||
s_own_cert_pem_end = client_cert_pem_end_i;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
||||
esp_err_t set_mqtt_client_key(const uint8_t *client_key_pem_start_i, const uint8_t *client_key_pem_end_i)
|
||||
{
|
||||
if (client_key_pem_start_i && client_key_pem_end_i &&
|
||||
(client_key_pem_start_i >= client_key_pem_end_i)) {
|
||||
ESP_LOGE(TAG, "Invalid mqtt Client key(%d)\n", __LINE__);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
s_own_key_pem_start = client_key_pem_start_i;
|
||||
s_own_key_pem_end = client_key_pem_end_i;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
||||
esp_err_t set_mqtt_broker_certs(const uint8_t *ca_cert_pem_start_i, const uint8_t *ca_cert_pem_end_i)
|
||||
{
|
||||
if (!ca_cert_pem_start_i || !ca_cert_pem_end_i ||
|
||||
(ca_cert_pem_start_i > ca_cert_pem_end_i)) {
|
||||
ESP_LOGE(TAG, "Invalid mqtt ca cert(%d)\n", __LINE__);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
s_ca_cert_pem_start = ca_cert_pem_start_i;
|
||||
s_ca_cert_pem_end = ca_cert_pem_end_i;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
||||
static int do_mqtt_sub_cmd(int argc, char **argv)
|
||||
{
|
||||
int msg_id;
|
||||
int nerrors = arg_parse(argc, argv, (void **)&mqtt_sub_args);
|
||||
if (nerrors != 0) {
|
||||
arg_print_errors(stderr, mqtt_sub_args.end, argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (client_handle == NULL) {
|
||||
ESP_LOGE(TAG, "mqtt client not connected");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mqtt_sub_args.unsubscribe->count > 0) {
|
||||
if (mqtt_sub_args.topic->count <= 0) {
|
||||
ESP_LOGE(TAG, UNSUBSCRIBE_HELP_MSG);
|
||||
return 0;
|
||||
}
|
||||
char *topic = (char *)mqtt_sub_args.topic->sval[0];
|
||||
|
||||
msg_id = esp_mqtt_client_unsubscribe(client_handle, mqtt_sub_args.topic->sval[0]);
|
||||
ESP_LOGI(TAG, "Unsubscribe successful, msg_id=%d, topic=%s", msg_id, topic);
|
||||
|
||||
} else {
|
||||
if (mqtt_sub_args.topic->count <= 0) {
|
||||
ESP_LOGE(TAG, SUBSCRIBE_HELP_MSG);
|
||||
return 0;
|
||||
}
|
||||
char *topic = (char *)mqtt_sub_args.topic->sval[0];
|
||||
|
||||
msg_id = esp_mqtt_client_subscribe(client_handle, topic, 0);
|
||||
ESP_LOGI(TAG, "Subscribe successful, msg_id=%d, topic=%s", msg_id, topic);
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int do_mqtt_pub_cmd(int argc, char **argv)
|
||||
{
|
||||
int msg_id;
|
||||
int nerrors = arg_parse(argc, argv, (void **)&mqtt_pub_args);
|
||||
if (nerrors != 0) {
|
||||
arg_print_errors(stderr, mqtt_pub_args.end, argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (client_handle == NULL) {
|
||||
ESP_LOGE(TAG, "mqtt client not connected");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((mqtt_pub_args.topic->count <= 0) || (mqtt_pub_args.message->count <= 0)) {
|
||||
ESP_LOGE(TAG, PUBLISH_HELP_MSG);
|
||||
}
|
||||
|
||||
msg_id = esp_mqtt_client_publish(client_handle,
|
||||
mqtt_pub_args.topic->sval[0],
|
||||
mqtt_pub_args.message->sval[0],
|
||||
0, 1, 0);
|
||||
if (msg_id == -1) {
|
||||
ESP_LOGE(TAG, "mqtt client not connected");
|
||||
return 0;
|
||||
}
|
||||
ESP_LOGI(TAG, "Publish successful, msg_id=%d, topic=%s, data=%s",
|
||||
msg_id, mqtt_pub_args.topic->sval[0], mqtt_pub_args.message->sval[0]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Registers the mqtt commands.
|
||||
*
|
||||
* @return
|
||||
* - esp_err_t
|
||||
*/
|
||||
esp_err_t console_cmd_mqtt_register(void)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
/* Register mqtt */
|
||||
mqtt_args.connect = arg_lit0("C", "connect", "Connect to a broker (flag, no argument)");
|
||||
mqtt_args.uri = arg_str0("h", "host", "<host>", "Specify the host uri to connect to");
|
||||
mqtt_args.status = arg_lit0("s", "status", "Displays the status of the mqtt client (flag, no argument)");
|
||||
mqtt_args.username = arg_str0("u", "username", "<username>", "Provide a username to be used for authenticating with the broker");
|
||||
mqtt_args.password = arg_str0("P", "password", "<password>", "Provide a password to be used for authenticating with the broker");
|
||||
mqtt_args.cert = arg_lit0(NULL, "cert", "Define the PEM encoded certificate for this client, if required by the broker (flag, no argument)");
|
||||
mqtt_args.key = arg_lit0(NULL, "key", "Define the PEM encoded private key for this client, if required by the broker (flag, no argument)");
|
||||
mqtt_args.cafile = arg_lit0(NULL, "cafile", "Define the PEM encoded CA certificates that are trusted (flag, no argument)");
|
||||
#if defined(CONFIG_MBEDTLS_CERTIFICATE_BUNDLE)
|
||||
mqtt_args.use_internal_bundle = arg_lit0(NULL, "use-internal-bundle", "Use the internal certificate bundle for TLS (flag, no argument)");
|
||||
#endif
|
||||
mqtt_args.disconnect = arg_lit0("D", "disconnect", "Disconnect from the broker (flag, no argument)");
|
||||
mqtt_args.end = arg_end(1);
|
||||
|
||||
const esp_console_cmd_t mqtt_cmd = {
|
||||
.command = "mqtt",
|
||||
.help = "mqtt command",
|
||||
.hint = NULL,
|
||||
.func = &do_mqtt_cmd,
|
||||
.argtable = &mqtt_args
|
||||
};
|
||||
|
||||
ret = esp_console_cmd_register(&mqtt_cmd);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Unable to register mqtt");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Register mqtt_pub */
|
||||
mqtt_pub_args.topic = arg_str0("t", "topic", "<topic>", "Topic to Subscribe/Publish");
|
||||
mqtt_pub_args.message = arg_str0("m", "message", "<message>", "Message to Publish");
|
||||
mqtt_pub_args.end = arg_end(1);
|
||||
|
||||
const esp_console_cmd_t mqtt_pub_cmd = {
|
||||
.command = "mqtt_pub",
|
||||
.help = "mqtt publish command",
|
||||
.hint = NULL,
|
||||
.func = &do_mqtt_pub_cmd,
|
||||
.argtable = &mqtt_pub_args
|
||||
};
|
||||
|
||||
ret = esp_console_cmd_register(&mqtt_pub_cmd);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Unable to register mqtt_pub");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Register mqtt_sub */
|
||||
mqtt_sub_args.topic = arg_str0("t", "topic", "<topic>", "Topic to Subscribe/Publish");
|
||||
mqtt_sub_args.unsubscribe = arg_lit0("U", "unsubscribe", "Unsubscribe from a topic");
|
||||
mqtt_sub_args.end = arg_end(1);
|
||||
|
||||
const esp_console_cmd_t mqtt_sub_cmd = {
|
||||
.command = "mqtt_sub",
|
||||
.help = "mqtt subscribe command",
|
||||
.hint = NULL,
|
||||
.func = &do_mqtt_sub_cmd,
|
||||
.argtable = &mqtt_sub_args
|
||||
};
|
||||
|
||||
ret = esp_console_cmd_register(&mqtt_sub_cmd);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Unable to register mqtt_sub");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
73
components/console_cmd_mqtt/console_mqtt.h
Normal file
73
components/console_cmd_mqtt/console_mqtt.h
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "console_simple_init.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Registers the mqtt command.
|
||||
*
|
||||
* @return
|
||||
* - esp_err_t
|
||||
*/
|
||||
esp_err_t console_cmd_mqtt_register(void);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set MQTT client certificate
|
||||
*
|
||||
* This function sets the MQTT client certificate for secure communication.
|
||||
* The function takes the PEM(Privacy Enhanced Mail) encoded certificate arguments.
|
||||
*
|
||||
* @param client_cert_pem_start_i Pointer to the beginning of the client certificate PEM data.
|
||||
* @param client_cert_pem_end_i Pointer to the end of the client certificate PEM data.
|
||||
*
|
||||
* @return
|
||||
* ESP_OK on success
|
||||
* ESP_ERR_INVALID_ARG on invalid arguments
|
||||
*/
|
||||
esp_err_t set_mqtt_client_cert(const uint8_t *client_cert_pem_start_i, const uint8_t *client_cert_pem_end_i);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set MQTT client key
|
||||
*
|
||||
* This function sets the MQTT client key for secure communication.
|
||||
* The function takes the PEM(Privacy Enhanced Mail) encoded key arguments.
|
||||
*
|
||||
* @param client_key_pem_start_i Pointer to the beginning of the client key PEM data.
|
||||
* @param client_key_pem_end_i Pointer to the end of the client key PEM data.
|
||||
*
|
||||
* @return
|
||||
* ESP_OK on success
|
||||
* ESP_ERR_INVALID_ARG on invalid arguments
|
||||
*/
|
||||
esp_err_t set_mqtt_client_key(const uint8_t *client_key_pem_start_i, const uint8_t *client_key_pem_end_i);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set MQTT broker certificate
|
||||
*
|
||||
* This function sets the MQTT broker certificate for secure communication.
|
||||
* The function takes the PEM(Privacy Enhanced Mail) encoded broker certificate arguments.
|
||||
*
|
||||
* @param broker_cert_pem_start_i Pointer to the beginning of the broker certificate PEM data.
|
||||
* @param broker_cert_pem_end_i Pointer to the end of the broker certificate PEM data.
|
||||
*
|
||||
* @return
|
||||
* ESP_OK on success
|
||||
* ESP_ERR_INVALID_ARG on invalid arguments
|
||||
*/
|
||||
esp_err_t set_mqtt_broker_certs(const uint8_t *broker_cert_pem_start_i, const uint8_t *broker_cert_pem_end_i);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -0,0 +1,11 @@
|
||||
# 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(mqtt_ssl_auth_console)
|
||||
|
||||
# Certs for mqtts://test.mosquitto.org:8884
|
||||
target_add_binary_data(${CMAKE_PROJECT_NAME}.elf "certs/client.crt" TEXT)
|
||||
target_add_binary_data(${CMAKE_PROJECT_NAME}.elf "certs/client.key" TEXT)
|
||||
target_add_binary_data(${CMAKE_PROJECT_NAME}.elf "certs/mosquitto.org.pem" TEXT)
|
@ -0,0 +1,174 @@
|
||||
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- |
|
||||
|
||||
# ESP-MQTT SSL Authentication Console
|
||||
|
||||
This example demonstrates the use of the MQTT command-line component to connect to both secured and unsecured MQTT brokers. It provides multiple modes of connection, including:
|
||||
|
||||
* Unsecured transport: Connect to a broker without encryption.
|
||||
* SSL/TLS transport: Securely connect using SSL/TLS with options for:
|
||||
* Validating the broker using a provided CA certificate.
|
||||
* Validating the broker using the internal certificate bundle.
|
||||
* Performing SSL mutual authentication using client and broker certificates.
|
||||
|
||||
Additionally, the example allows subscribing to topics, unsubscribing from topics, and publishing messages to a specified topic through commands. Connections to the broker at test.mosquitto.org are used to demonstrate these features.
|
||||
(Please note that the public broker is maintained by the community so may not be always available, for details please visit http://test.mosquitto.org)
|
||||
|
||||
It uses ESP-MQTT library which implements mqtt client to connect to mqtt broker.
|
||||
|
||||
## How to use example
|
||||
|
||||
### Hardware Required
|
||||
|
||||
This example can be executed on any ESP32 board, the only required interface is WiFi and connection to internet.
|
||||
|
||||
### Configure the project
|
||||
|
||||
* Open the project configuration menu (`idf.py menuconfig`)
|
||||
* Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details.
|
||||
|
||||
* Generate your client keys and certificate (specific to testing with Mosquitto broker)
|
||||
|
||||
Note: The following steps are for testing with the Mosquitto broker. If you're using a different broker, you may need to adapt the steps to meet your broker's certificate and key requirements.
|
||||
|
||||
#### Steps for SSL Mutual authentication:
|
||||
Navigate to the certs directory
|
||||
|
||||
```
|
||||
cd certs
|
||||
```
|
||||
|
||||
Generate a client key and a CSR. When you are generating the CSR, do not use the default values. At a minimum, the CSR must include the Country, Organisation and Common Name fields.
|
||||
|
||||
```
|
||||
openssl genrsa -out client.key
|
||||
openssl req -out client.csr -key client.key -new
|
||||
```
|
||||
|
||||
Paste the generated CSR in the [Mosquitto test certificate signer](https://test.mosquitto.org/ssl/index.php), click Submit and copy the downloaded `client.crt` in the `main` directory.
|
||||
|
||||
Please note, that the supplied files `client.crt` and `client.key` in the `main` directory are only placeholders for your client certificate and key (i.e. the example "as is" would compile but would not connect to the broker)
|
||||
|
||||
The broker certificate `mosquitto.org.pem` can be downloaded in pem format from [mosquitto.org.crt](https://test.mosquitto.org/ssl/mosquitto.org.crt). Convert it to `mosquitto.org.pem` simply by renaming it.
|
||||
|
||||
Note: If your certificate and key file names differ, update the root `CMakeLists.txt` file and main/`mqtt_ssl_auth_console.c` accordingly.
|
||||
|
||||
### Build and Flash
|
||||
|
||||
Build the project and flash it to the board, then run monitor tool to view serial output:
|
||||
|
||||
```
|
||||
idf.py -p PORT flash monitor
|
||||
```
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
Warning: This example might need a bigger app partition size if you're compiling it for debug. To ensere this issue doesn't happen "optimize for size is enabled in menuconfig.
|
||||
|
||||
### Command Usage:
|
||||
```
|
||||
esp> help
|
||||
help [<string>]
|
||||
Print the summary of all registered commands if no arguments are given,
|
||||
otherwise print summary of given command.
|
||||
<string> Name of command
|
||||
|
||||
mqtt [-CsD] [-h <host>] [-u <username>] [-P <password>] [--cert] [--key] [--cafile]
|
||||
mqtt command
|
||||
-C, --connect Connect to a broker (flag, no argument)
|
||||
-h, --host=<host> Specify the host uri to connect to
|
||||
-s, --status Displays the status of the mqtt client (flag, no argument)
|
||||
-u, --username=<username> Provide a username to be used for authenticating with the broker
|
||||
-P, --password=<password> Provide a password to be used for authenticating with the broker
|
||||
--cert Define the PEM encoded certificate for this client, if required by the broker (flag, no argument)
|
||||
--key Define the PEM encoded private key for this client, if required by the broker (flag, no argument)
|
||||
--cafile Define the PEM encoded CA certificates that are trusted (flag, no argument)
|
||||
--use-internal-bundle Use the internal certificate bundle for TLS (flag, no argument)
|
||||
-D, --disconnect Disconnect from the broker (flag, no argument)
|
||||
|
||||
mqtt_pub [-t <topic>] [-m <message>]
|
||||
mqtt publish command
|
||||
-t, --topic=<topic> Topic to Subscribe/Publish
|
||||
-m, --message=<message> Message to Publish
|
||||
|
||||
mqtt_sub [-U] [-t <topic>]
|
||||
mqtt subscribe command
|
||||
-t, --topic=<topic> Topic to Subscribe/Publish
|
||||
-U, --unsubscribe Unsubscribe from a topic
|
||||
```
|
||||
|
||||
### Connection:
|
||||
|
||||
#### Connect without Validating the Broker:
|
||||
This option connects to the broker without validating its certificate. It is not secure.
|
||||
```
|
||||
mqtt -h mqtts://test.mosquitto.org -C
|
||||
```
|
||||
or
|
||||
```
|
||||
mqtt -h mqtts://mqtt.eclipseprojects.io -C
|
||||
```
|
||||
|
||||
#### Validate the Broker using the Internal Certificate Bundle:
|
||||
This option uses the ESP-IDF's built-in certificate bundle to verify the broker's identity.
|
||||
```
|
||||
mqtt -h mqtts://mqtt.eclipseprojects.io -C --use-internal-bundle
|
||||
```
|
||||
or
|
||||
```
|
||||
mqtt -h mqtts://test.mosquitto.org -C --use-internal-bundle
|
||||
```
|
||||
|
||||
#### Validate the Broker using a Provided CA Certificate:
|
||||
This option requires you to provide the broker's CA certificate for validation.
|
||||
```
|
||||
mqtt -h mqtts://test.mosquitto.org -C --cafile
|
||||
```
|
||||
|
||||
|
||||
#### SSL Mutual Authentication(encrypted, client certificate required):
|
||||
This option performs client authentication in addition to broker validation. It requires the client certificate, private key, and broker CA certificate.
|
||||
```
|
||||
mqtt -h mqtts://test.mosquitto.org:8884 -C --cert --key --cafile
|
||||
```
|
||||
or
|
||||
```
|
||||
mqtt -h mqtts://test.mosquitto.org:8884 -C --cert --key --use-internal-bundle
|
||||
```
|
||||
|
||||
Note: In this example, the broker's certificate is included in the certificate bundle (refer to sdkconfig.default).
|
||||
|
||||
### Disconnect:
|
||||
```
|
||||
esp> mqtt -D
|
||||
I (1189949) console_mqtt: mqtt client disconnected
|
||||
```
|
||||
|
||||
### Subscribe/Unsubscribe:
|
||||
```
|
||||
esp> mqtt_sub -t test0
|
||||
I (897289) console_mqtt: Subscribe successful, msg_id=57425, topic=test0
|
||||
esp> I (897799) console_mqtt: MQTT_EVENT_SUBSCRIBED, msg_id=57425
|
||||
esp>
|
||||
esp> mqtt_sub -U -t test0
|
||||
I (902009) console_mqtt: Unsubscribe successful, msg_id=27663, topic=test0
|
||||
esp> I (902509) console_mqtt: MQTT_EVENT_UNSUBSCRIBED, msg_id=27663
|
||||
```
|
||||
|
||||
### Publish:
|
||||
```
|
||||
esp> mqtt_pub -t test0 -m "Hello, Testing 123"
|
||||
I (999469) console_mqtt: Publish successful, msg_id=55776, topic=test0, data=Hello, Testing 123
|
||||
I (1000009) console_mqtt: MQTT_EVENT_PUBLISHED, msg_id=55776
|
||||
esp>
|
||||
```
|
||||
|
||||
### Receiving data event:
|
||||
```
|
||||
esp> I (999999) console_mqtt: MQTT_EVENT_DATA
|
||||
I (999999) console_mqtt: TOPIC=test0
|
||||
|
||||
I (999999) console_mqtt: DATA=Hello, Testing 123
|
||||
```
|
@ -0,0 +1,24 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEAzCCAuugAwIBAgIUBY1hlCGvdj4NhBXkZ/uLUZNILAwwDQYJKoZIhvcNAQEL
|
||||
BQAwgZAxCzAJBgNVBAYTAkdCMRcwFQYDVQQIDA5Vbml0ZWQgS2luZ2RvbTEOMAwG
|
||||
A1UEBwwFRGVyYnkxEjAQBgNVBAoMCU1vc3F1aXR0bzELMAkGA1UECwwCQ0ExFjAU
|
||||
BgNVBAMMDW1vc3F1aXR0by5vcmcxHzAdBgkqhkiG9w0BCQEWEHJvZ2VyQGF0Y2hv
|
||||
by5vcmcwHhcNMjAwNjA5MTEwNjM5WhcNMzAwNjA3MTEwNjM5WjCBkDELMAkGA1UE
|
||||
BhMCR0IxFzAVBgNVBAgMDlVuaXRlZCBLaW5nZG9tMQ4wDAYDVQQHDAVEZXJieTES
|
||||
MBAGA1UECgwJTW9zcXVpdHRvMQswCQYDVQQLDAJDQTEWMBQGA1UEAwwNbW9zcXVp
|
||||
dHRvLm9yZzEfMB0GCSqGSIb3DQEJARYQcm9nZXJAYXRjaG9vLm9yZzCCASIwDQYJ
|
||||
KoZIhvcNAQEBBQADggEPADCCAQoCggEBAME0HKmIzfTOwkKLT3THHe+ObdizamPg
|
||||
UZmD64Tf3zJdNeYGYn4CEXbyP6fy3tWc8S2boW6dzrH8SdFf9uo320GJA9B7U1FW
|
||||
Te3xda/Lm3JFfaHjkWw7jBwcauQZjpGINHapHRlpiCZsquAthOgxW9SgDgYlGzEA
|
||||
s06pkEFiMw+qDfLo/sxFKB6vQlFekMeCymjLCbNwPJyqyhFmPWwio/PDMruBTzPH
|
||||
3cioBnrJWKXc3OjXdLGFJOfj7pP0j/dr2LH72eSvv3PQQFl90CZPFhrCUcRHSSxo
|
||||
E6yjGOdnz7f6PveLIB574kQORwt8ePn0yidrTC1ictikED3nHYhMUOUCAwEAAaNT
|
||||
MFEwHQYDVR0OBBYEFPVV6xBUFPiGKDyo5V3+Hbh4N9YSMB8GA1UdIwQYMBaAFPVV
|
||||
6xBUFPiGKDyo5V3+Hbh4N9YSMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL
|
||||
BQADggEBAGa9kS21N70ThM6/Hj9D7mbVxKLBjVWe2TPsGfbl3rEDfZ+OKRZ2j6AC
|
||||
6r7jb4TZO3dzF2p6dgbrlU71Y/4K0TdzIjRj3cQ3KSm41JvUQ0hZ/c04iGDg/xWf
|
||||
+pp58nfPAYwuerruPNWmlStWAXf0UTqRtg4hQDWBuUFDJTuWuuBvEXudz74eh/wK
|
||||
sMwfu1HFvjy5Z0iMDU8PUDepjVolOCue9ashlS4EB5IECdSR2TItnAIiIwimx839
|
||||
LdUdRudafMu5T5Xma182OC0/u/xRlEm+tvKGGmfFcN0piqVl8OrSPBgIlb+1IKJE
|
||||
m/XriWr/Cq4h/JfB7NTsezVslgkBaoU=
|
||||
-----END CERTIFICATE-----
|
@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "mqtt_ssl_auth_console.c"
|
||||
INCLUDE_DIRS ".")
|
@ -0,0 +1,8 @@
|
||||
dependencies:
|
||||
idf:
|
||||
version: ">=5.0"
|
||||
protocol_examples_common:
|
||||
path: ${IDF_PATH}/examples/common_components/protocol_examples_common
|
||||
console_cmd_mqtt:
|
||||
version: "*"
|
||||
override_path: '../../../'
|
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include "nvs_flash.h"
|
||||
#include "esp_netif.h"
|
||||
#include "esp_event.h"
|
||||
#include <netdb.h>
|
||||
#include "console_mqtt.h"
|
||||
#include "protocol_examples_common.h"
|
||||
|
||||
// Certs for mqtts://test.mosquitto.org:8884
|
||||
extern const uint8_t g_client_cert_pem_start[] asm("_binary_client_crt_start");
|
||||
extern const uint8_t g_client_cert_pem_end[] asm("_binary_client_crt_end");
|
||||
extern const uint8_t g_client_key_pem_start[] asm("_binary_client_key_start");
|
||||
extern const uint8_t g_client_key_pem_end[] asm("_binary_client_key_end");
|
||||
extern const uint8_t g_broker_cert_pem_start[] asm("_binary_mosquitto_org_pem_start");
|
||||
extern const uint8_t g_broker_cert_pem_end[] asm("_binary_mosquitto_org_pem_end");
|
||||
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
esp_err_t ret = nvs_flash_init(); //Initialize NVS
|
||||
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);
|
||||
|
||||
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
|
||||
* Read "Establishing Wi-Fi or Ethernet Connection" section in
|
||||
* ${IDF_PATH}/examples/protocols/README.md for more information about this function.
|
||||
*/
|
||||
ESP_ERROR_CHECK(example_connect());
|
||||
|
||||
// Initialize console REPL
|
||||
ESP_ERROR_CHECK(console_cmd_init());
|
||||
ESP_ERROR_CHECK(console_cmd_all_register());
|
||||
|
||||
set_mqtt_client_cert(g_client_cert_pem_start, g_client_cert_pem_end);
|
||||
set_mqtt_client_key(g_client_key_pem_start, g_client_key_pem_end);
|
||||
set_mqtt_broker_certs(g_broker_cert_pem_start, g_broker_cert_pem_end);
|
||||
|
||||
// start console REPL
|
||||
ESP_ERROR_CHECK(console_cmd_start());
|
||||
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
# SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.esp32
|
||||
def test_examples_ifconfig_command(dut):
|
||||
dut.expect('esp>', timeout=30)
|
||||
dut.write('help mqtt')
|
||||
dut.expect(r'mqtt \[-CsD\] \[-h <host>\] \[-u <username>\] \[-P <password>\] \[--cert\] \[--key\] \[--cafile\]', timeout=30)
|
||||
|
||||
dut.write('help mqtt_pub')
|
||||
dut.expect(r'mqtt_pub \[-t <topic>\] \[-m <message>\]', timeout=30)
|
||||
|
||||
dut.write('help mqtt_sub')
|
||||
dut.expect(r'mqtt_sub \[-U\] \[-t <topic>\]', timeout=30)
|
@ -0,0 +1,7 @@
|
||||
# This file was generated using idf.py save-defconfig. It can be edited manually.
|
||||
# Espressif IoT Development Framework (ESP-IDF) 5.5.0 Project Minimal Configuration
|
||||
#
|
||||
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
|
||||
CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_CMN=y
|
||||
CONFIG_MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE=y
|
||||
CONFIG_MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE_PATH="certs/mosquitto.org.pem"
|
11
components/console_cmd_mqtt/idf_component.yml
Normal file
11
components/console_cmd_mqtt/idf_component.yml
Normal file
@ -0,0 +1,11 @@
|
||||
version: 1.0.0
|
||||
url: https://github.com/espressif/esp-protocols/tree/master/components/console_cmd_mqtt
|
||||
description: The component provides a console where the 'mqtt' command can be executed.
|
||||
license: Apache-2.0
|
||||
dependencies:
|
||||
idf:
|
||||
version: '>=5.0'
|
||||
espressif/console_simple_init:
|
||||
version: '>=1.1.0'
|
||||
override_path: '../console_simple_init'
|
||||
public: true
|
@ -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.1.0
|
||||
version: 1.3.0
|
||||
version_files:
|
||||
- idf_component.yml
|
||||
|
@ -1,5 +1,63 @@
|
||||
# Changelog
|
||||
|
||||
## [1.3.0](https://github.com/espressif/esp-protocols/commits/modem-v1.3.0)
|
||||
|
||||
### Features
|
||||
|
||||
- Add mode detection to the example ([18f196fa](https://github.com/espressif/esp-protocols/commit/18f196fa))
|
||||
- Support for pausing network in C-API ([1db83cd1](https://github.com/espressif/esp-protocols/commit/1db83cd1))
|
||||
- Add support for pausing netif ([247f1681](https://github.com/espressif/esp-protocols/commit/247f1681), [#699](https://github.com/espressif/esp-protocols/issues/699))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Minor cleanup of pppos example ([5e929902](https://github.com/espressif/esp-protocols/commit/5e929902))
|
||||
- Fix PPP mode detection to accept LCP/conf ([c989c6ad](https://github.com/espressif/esp-protocols/commit/c989c6ad))
|
||||
- Refine mode switch data->command ([8b6ea331](https://github.com/espressif/esp-protocols/commit/8b6ea331), [#692](https://github.com/espressif/esp-protocols/issues/692))
|
||||
- Detect serial ports properly ([0cb59ff8](https://github.com/espressif/esp-protocols/commit/0cb59ff8))
|
||||
- Fix CMUX enter to ignore URC before transition ([1284f66d](https://github.com/espressif/esp-protocols/commit/1284f66d), [#669](https://github.com/espressif/esp-protocols/issues/669))
|
||||
|
||||
## [1.2.1](https://github.com/espressif/esp-protocols/commits/modem-v1.2.1)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Use higher GPIO range to support new chips ([428fdbbd](https://github.com/espressif/esp-protocols/commit/428fdbbd), [#558](https://github.com/espressif/esp-protocols/issues/558))
|
||||
- Remove tests and support for IDFv4.4, added IDFv5.4 ([433a033f](https://github.com/espressif/esp-protocols/commit/433a033f))
|
||||
- Fix typo GENETIC -> GENERIC in mode types ([090b1ff8](https://github.com/espressif/esp-protocols/commit/090b1ff8), [#667](https://github.com/espressif/esp-protocols/issues/667))
|
||||
- Add support for URC handler into C-API ([295d99df](https://github.com/espressif/esp-protocols/commit/295d99df), [#180](https://github.com/espressif/esp-protocols/issues/180))
|
||||
|
||||
## [1.2.0](https://github.com/espressif/esp-protocols/commits/modem-v1.2.0)
|
||||
|
||||
### Features
|
||||
|
||||
- Add support for guessing mode ([52598e5f](https://github.com/espressif/esp-protocols/commit/52598e5f))
|
||||
- Delete CMUX internal implementation even if terminal exit fails ([0e0cbd6b](https://github.com/espressif/esp-protocols/commit/0e0cbd6b))
|
||||
- Add support for handling URC ([1b6a3b3b](https://github.com/espressif/esp-protocols/commit/1b6a3b3b), [#180](https://github.com/espressif/esp-protocols/issues/180))
|
||||
- add ability to change ESP_MODEM_C_API_STR_MAX from Kconfig ([17909892](https://github.com/espressif/esp-protocols/commit/17909892))
|
||||
- Added target test config with CHAP authentication ([f8ae7def](https://github.com/espressif/esp-protocols/commit/f8ae7def))
|
||||
- example add esp32p4 usb support ([adafeae5](https://github.com/espressif/esp-protocols/commit/adafeae5))
|
||||
- Publish mbedtls component ([0140455f](https://github.com/espressif/esp-protocols/commit/0140455f))
|
||||
- host test support of the latest ESP-IDF release ([3f74b4e8](https://github.com/espressif/esp-protocols/commit/3f74b4e8))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Fix console example to use urc/detect features ([1a9eaf3e](https://github.com/espressif/esp-protocols/commit/1a9eaf3e))
|
||||
- Update target test builds to use external Catch2 ([554f022c](https://github.com/espressif/esp-protocols/commit/554f022c))
|
||||
- Fix arguments names when spawn esp_modem_xxx declarations ([b6792c52](https://github.com/espressif/esp-protocols/commit/b6792c52))
|
||||
- Remove catch dependency ([c3480768](https://github.com/espressif/esp-protocols/commit/c3480768))
|
||||
- Examples: use local configs for MQTT topic/data ([f5c13b92](https://github.com/espressif/esp-protocols/commit/f5c13b92))
|
||||
- Fixed clang-tidy warnings ([70fa3af7](https://github.com/espressif/esp-protocols/commit/70fa3af7))
|
||||
- Fix CI build per IDFv5.3 ([d0c17ef0](https://github.com/espressif/esp-protocols/commit/d0c17ef0))
|
||||
- Fixed UART task to check for buffered data periodically ([4bdd90cc](https://github.com/espressif/esp-protocols/commit/4bdd90cc), [#536](https://github.com/espressif/esp-protocols/issues/536))
|
||||
- Cleanup unused configs from PPPoS example ([08a62ccc](https://github.com/espressif/esp-protocols/commit/08a62ccc))
|
||||
- Update CMUX example with SIM7070_gnss cleaned-up ([56fe5327](https://github.com/espressif/esp-protocols/commit/56fe5327))
|
||||
- Update console example with SIM7070_gnss format comments ([5baaf542](https://github.com/espressif/esp-protocols/commit/5baaf542))
|
||||
- Fix remaining print format warnings ([3b80181d](https://github.com/espressif/esp-protocols/commit/3b80181d))
|
||||
|
||||
### Updated
|
||||
|
||||
- docs(modem): Fix esp_modem_at_raw() description (C-API) ([492a6a00](https://github.com/espressif/esp-protocols/commit/492a6a00))
|
||||
- ci(common): updated github actions(checkout, upload, download) v3 to 4, Ubuntu 20.04 to v22.04 ([a23a0027](https://github.com/espressif/esp-protocols/commit/a23a0027))
|
||||
|
||||
## [1.1.0](https://github.com/espressif/esp-protocols/commits/modem-v1.1.0)
|
||||
|
||||
### Features
|
||||
|
@ -76,4 +76,20 @@ menu "esp-modem"
|
||||
help
|
||||
If enabled, APIs to add URC handler are available
|
||||
|
||||
config ESP_MODEM_PPP_ESCAPE_BEFORE_EXIT
|
||||
bool "Send escape sequence when switching PPP -> CMD"
|
||||
default n
|
||||
help
|
||||
If enabled, the library sends a PPP escape ("+++" command)
|
||||
to switch to command mode. This make switching from PPP to CMD
|
||||
mode more robust for some devices (e.g. Quectel), but might cause
|
||||
trouble for other devices (e.g. SIMCOM).
|
||||
|
||||
config ESP_MODEM_ADD_DEBUG_LOGS
|
||||
bool "Add UART Tx/Rx logs"
|
||||
default n
|
||||
help
|
||||
If enabled, the library dumps all transmitted and received data.
|
||||
This option is only used for debugging.
|
||||
|
||||
endmenu
|
||||
|
@ -15,7 +15,3 @@ By default, this example simply connects to the PPP server using a supported dev
|
||||
This example however, doesn't rely on sending specific AT commands, just the bare minimum to setup the cellular network.
|
||||
Thus, if the `EXAMPLE_USE_MINIMAL_DCE` option is enabled, we directly inherit from the `ModuleIf` and implement only the basic commands.
|
||||
Also, to demonstrate the dce_factory functionality, a new `NetDCE_Factory` is implemented for creating the network module and the DCE.
|
||||
|
||||
### Supported IDF versions
|
||||
|
||||
This example is only supported from `v4.2`, since is uses NAPT feature.
|
||||
|
@ -17,7 +17,3 @@ over PPPoS, i.e. over the modem serial line.
|
||||
* Experiment with the network, after getting the IP from the modem device
|
||||
- directly in the code
|
||||
- in the system (need to set `tun` interface IP, dns servers, and routing the desired traffic over the tun interface)
|
||||
|
||||
### Supported IDF versions
|
||||
|
||||
This example (using the default CMake IDF build system) is only supported from `v4.4`, since is uses `idf.py`'s linux target.
|
||||
|
@ -25,9 +25,3 @@ USB example uses Quactel BG96 modem device. BG96 needs a positive pulse on its P
|
||||
This example supports USB modem hot-plugging and reconnection. There is one limitation coming from esp_console component:
|
||||
When esp_console REPL is being destroyed (after USB mode disconnection or after `exit` command), it will block on UART read.
|
||||
You must send a character to it (via idf.py monitor), so it unblocks and properly exits.
|
||||
|
||||
### Supported IDF versions
|
||||
|
||||
This example is only supported from `v4.2`, due to support of the console repl mode.
|
||||
|
||||
USB example is supported from `v4.4`.
|
||||
|
@ -108,28 +108,28 @@ menu "Example Configuration"
|
||||
config EXAMPLE_MODEM_UART_TX_PIN
|
||||
int "TXD Pin Number"
|
||||
default 25
|
||||
range 0 31
|
||||
range 0 56
|
||||
help
|
||||
Pin number of UART TX.
|
||||
|
||||
config EXAMPLE_MODEM_UART_RX_PIN
|
||||
int "RXD Pin Number"
|
||||
default 26
|
||||
range 0 31
|
||||
range 0 56
|
||||
help
|
||||
Pin number of UART RX.
|
||||
|
||||
config EXAMPLE_MODEM_UART_RTS_PIN
|
||||
int "RTS Pin Number"
|
||||
default 27
|
||||
range 0 31
|
||||
range 0 56
|
||||
help
|
||||
Pin number of UART RTS.
|
||||
|
||||
config EXAMPLE_MODEM_UART_CTS_PIN
|
||||
int "CTS Pin Number"
|
||||
default 23
|
||||
range 0 31
|
||||
range 0 56
|
||||
help
|
||||
Pin number of UART CTS.
|
||||
|
||||
@ -179,7 +179,7 @@ menu "Example Configuration"
|
||||
config EXAMPLE_MODEM_PWRKEY_PIN
|
||||
int "PWRKEY Pin Number"
|
||||
default 18
|
||||
range 0 31
|
||||
range 0 56
|
||||
help
|
||||
Pin number connected to modem's power key pin.
|
||||
endmenu
|
||||
|
@ -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
|
||||
*/
|
||||
@ -89,7 +89,7 @@ void wakeup_modem(void)
|
||||
vTaskDelay(pdMS_TO_TICKS(2000));
|
||||
}
|
||||
|
||||
#ifdef CONFIG_EXAMPLE_MODEM_DEVICE_SHINY
|
||||
#ifdef CONFIG_ESP_MODEM_URC_HANDLER
|
||||
command_result handle_urc(uint8_t *data, size_t len)
|
||||
{
|
||||
ESP_LOG_BUFFER_HEXDUMP("on_read", data, len, ESP_LOG_INFO);
|
||||
@ -238,7 +238,9 @@ extern "C" void app_main(void)
|
||||
if (c->get_count_of(&SetModeArgs::mode)) {
|
||||
auto mode = c->get_string_of(&SetModeArgs::mode);
|
||||
modem_mode dev_mode;
|
||||
if (mode == "UNDEF") {
|
||||
if (mode == "AUTO") {
|
||||
dev_mode = esp_modem::modem_mode::AUTODETECT;
|
||||
} else if (mode == "UNDEF") {
|
||||
dev_mode = esp_modem::modem_mode::UNDEF;
|
||||
} else if (mode == "CMUX1") {
|
||||
dev_mode = esp_modem::modem_mode::CMUX_MANUAL_MODE;
|
||||
@ -370,19 +372,30 @@ extern "C" void app_main(void)
|
||||
ESP_LOGI(TAG, "Resetting the module...");
|
||||
CHECK_ERR(dce->reset(), ESP_LOGI(TAG, "OK"));
|
||||
});
|
||||
#ifdef CONFIG_EXAMPLE_MODEM_DEVICE_SHINY
|
||||
#ifdef CONFIG_ESP_MODEM_URC_HANDLER
|
||||
const ConsoleCommand HandleURC("urc", "toggle urc handling", no_args, [&](ConsoleCommand * c) {
|
||||
static int cnt = 0;
|
||||
if (++cnt % 2) {
|
||||
ESP_LOGI(TAG, "Adding URC handler");
|
||||
dce->set_on_read(handle_urc);
|
||||
dce->set_urc(handle_urc);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "URC removed");
|
||||
dce->set_on_read(nullptr);
|
||||
dce->set_urc(nullptr);
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
#endif
|
||||
const ConsoleCommand PauseNetwork("pause_net", "toggle network pause", no_args, [&](ConsoleCommand * c) {
|
||||
static int cnt = 0;
|
||||
if (++cnt % 2) {
|
||||
ESP_LOGI(TAG, "Pausing netif");
|
||||
dce->pause_netif(true);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "Unpausing netif");
|
||||
dce->pause_netif(false);
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
|
||||
const struct SetApn {
|
||||
SetApn(): apn(STR1, nullptr, nullptr, "<apn>", "APN (Access Point Name)") {}
|
||||
|
@ -20,14 +20,14 @@ menu "Example Configuration"
|
||||
config EXAMPLE_MODEM_UART_TX_PIN
|
||||
int "TXD Pin Number"
|
||||
default 4
|
||||
range 0 31
|
||||
range 0 56
|
||||
help
|
||||
Pin number of UART TX.
|
||||
|
||||
config EXAMPLE_MODEM_UART_RX_PIN
|
||||
int "RXD Pin Number"
|
||||
default 5
|
||||
range 0 31
|
||||
range 0 56
|
||||
help
|
||||
Pin number of UART RX.
|
||||
|
||||
@ -70,14 +70,14 @@ menu "Example Configuration"
|
||||
config EXAMPLE_MODEM_PWRKEY_PIN
|
||||
int "PWRKEY Pin Number"
|
||||
default 18
|
||||
range 0 31
|
||||
range 0 56
|
||||
help
|
||||
Pin number connected to modem's power key pin.
|
||||
|
||||
config EXAMPLE_MODEM_STATUS_PIN
|
||||
int "STATUS Pin Number"
|
||||
default 19
|
||||
range 0 31
|
||||
range 0 56
|
||||
help
|
||||
Pin number connected to modem's status pin.
|
||||
|
||||
|
@ -22,7 +22,3 @@ To enable this mode, please set `EXAMPLE_CUSTOM_TCP_TRANSPORT=y`
|
||||
This configuration could be used with any network library, which is connecting to a localhost endpoint instead of remote one. This example creates a localhost listener which basically mimics the remote endpoint by forwarding the traffic between the library and the TCP/socket layer of the modem (which is already secure if the TLS is used in the network library)
|
||||
|
||||

|
||||
|
||||
### Supported IDF versions
|
||||
|
||||
This example is supported from IDF `v5.0`.
|
||||
|
@ -30,28 +30,28 @@ menu "Example Configuration"
|
||||
config EXAMPLE_MODEM_UART_TX_PIN
|
||||
int "TXD Pin Number"
|
||||
default 25
|
||||
range 0 31
|
||||
range 0 56
|
||||
help
|
||||
Pin number of UART TX.
|
||||
|
||||
config EXAMPLE_MODEM_UART_RX_PIN
|
||||
int "RXD Pin Number"
|
||||
default 26
|
||||
range 0 31
|
||||
range 0 56
|
||||
help
|
||||
Pin number of UART RX.
|
||||
|
||||
config EXAMPLE_MODEM_UART_RTS_PIN
|
||||
int "RTS Pin Number"
|
||||
default 27
|
||||
range 0 31
|
||||
range 0 56
|
||||
help
|
||||
Pin number of UART RTS.
|
||||
|
||||
config EXAMPLE_MODEM_UART_CTS_PIN
|
||||
int "CTS Pin Number"
|
||||
default 23
|
||||
range 0 31
|
||||
range 0 56
|
||||
help
|
||||
Pin number of UART CTS.
|
||||
|
||||
|
@ -18,9 +18,3 @@ For USB enabled targets (ESP32-S2, ESP32-S3, or ESP32-P4), it is possible to con
|
||||
USB example uses Quactel BG96 modem device. BG96 needs a positive pulse on its PWK pin to boot-up.
|
||||
|
||||
This example supports USB modem hot-plugging and reconnection.
|
||||
|
||||
### Supported IDF versions
|
||||
|
||||
This example is only supported from `v4.1`, as this is the default dependency of `esp-modem` component.
|
||||
|
||||
USB example is supported from `v4.4`.
|
||||
|
@ -100,28 +100,28 @@ menu "Example Configuration"
|
||||
config EXAMPLE_MODEM_UART_TX_PIN
|
||||
int "TXD Pin Number"
|
||||
default 25
|
||||
range 0 31
|
||||
range 0 56
|
||||
help
|
||||
Pin number of UART TX.
|
||||
|
||||
config EXAMPLE_MODEM_UART_RX_PIN
|
||||
int "RXD Pin Number"
|
||||
default 26
|
||||
range 0 31
|
||||
range 0 56
|
||||
help
|
||||
Pin number of UART RX.
|
||||
|
||||
config EXAMPLE_MODEM_UART_RTS_PIN
|
||||
int "RTS Pin Number"
|
||||
default 27
|
||||
range 0 31
|
||||
range 0 56
|
||||
help
|
||||
Pin number of UART RTS.
|
||||
|
||||
config EXAMPLE_MODEM_UART_CTS_PIN
|
||||
int "CTS Pin Number"
|
||||
default 23
|
||||
range 0 31
|
||||
range 0 56
|
||||
help
|
||||
Pin number of UART CTS.
|
||||
|
||||
@ -201,4 +201,23 @@ menu "Example Configuration"
|
||||
help
|
||||
MQTT data message, which we publish and expect to receive.
|
||||
|
||||
config EXAMPLE_PAUSE_NETIF_TO_CHECK_SIGNAL
|
||||
bool "Demonstrate netif pause"
|
||||
default n
|
||||
help
|
||||
Set this to true to demonstrate network pausing.
|
||||
If enabled, the example waits for an MQTT data, then temporarily
|
||||
drops network to check signal quality, resumes networking and
|
||||
publishes another MQTT message.
|
||||
Connection to the MQTT broker should be kept.
|
||||
|
||||
config EXAMPLE_DETECT_MODE_BEFORE_CONNECT
|
||||
bool "Detect mode before connect"
|
||||
default n
|
||||
help
|
||||
Set this to true to demonstrate mode auto-detection.
|
||||
If enabled, the example tries to recognize the actual mode.
|
||||
If mode is detected correctly and it is not a command mode,
|
||||
then the example switches to command mode.
|
||||
|
||||
endmenu
|
||||
|
@ -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
|
||||
*/
|
||||
@ -34,6 +34,7 @@
|
||||
static const char *TAG = "pppos_example";
|
||||
static EventGroupHandle_t event_group = NULL;
|
||||
static const int CONNECT_BIT = BIT0;
|
||||
static const int DISCONNECT_BIT = BIT1;
|
||||
static const int GOT_DATA_BIT = BIT2;
|
||||
static const int USB_DISCONNECTED_BIT = BIT3; // Used only with USB DTE but we define it unconditionally, to avoid too many #ifdefs in the code
|
||||
|
||||
@ -55,6 +56,7 @@ static void usb_terminal_error_handler(esp_modem_terminal_error_t err)
|
||||
}
|
||||
#define CHECK_USB_DISCONNECTION(event_group) \
|
||||
if ((xEventGroupGetBits(event_group) & USB_DISCONNECTED_BIT) == USB_DISCONNECTED_BIT) { \
|
||||
ESP_LOGE(TAG, "USB_DISCONNECTED_BIT destroying modem dce"); \
|
||||
esp_modem_destroy(dce); \
|
||||
continue; \
|
||||
}
|
||||
@ -140,6 +142,7 @@ static void on_ip_event(void *arg, esp_event_base_t event_base,
|
||||
ESP_LOGI(TAG, "GOT ip event!!!");
|
||||
} else if (event_id == IP_EVENT_PPP_LOST_IP) {
|
||||
ESP_LOGI(TAG, "Modem Disconnect from PPP Server");
|
||||
xEventGroupSetBits(event_group, DISCONNECT_BIT);
|
||||
} else if (event_id == IP_EVENT_GOT_IP6) {
|
||||
ESP_LOGI(TAG, "GOT IPv6 event!");
|
||||
|
||||
@ -158,6 +161,7 @@ void app_main(void)
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(NETIF_PPP_STATUS, ESP_EVENT_ANY_ID, &on_ppp_changed, NULL));
|
||||
|
||||
/* Configure the PPP netif */
|
||||
esp_err_t err;
|
||||
esp_modem_dce_config_t dce_config = ESP_MODEM_DCE_DEFAULT_CONFIG(CONFIG_EXAMPLE_MODEM_PPP_APN);
|
||||
esp_netif_config_t netif_ppp_config = ESP_NETIF_DEFAULT_PPP();
|
||||
esp_netif_t *esp_netif = esp_netif_new(&netif_ppp_config);
|
||||
@ -205,7 +209,7 @@ void app_main(void)
|
||||
#endif
|
||||
assert(dce);
|
||||
if (dte_config.uart_config.flow_control == ESP_MODEM_FLOW_CONTROL_HW) {
|
||||
esp_err_t err = esp_modem_set_flow_control(dce, 2, 2); //2/2 means HW Flow Control.
|
||||
err = esp_modem_set_flow_control(dce, 2, 2); //2/2 means HW Flow Control.
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to set the set_flow_control mode");
|
||||
return;
|
||||
@ -246,7 +250,27 @@ void app_main(void)
|
||||
#error Invalid serial connection to modem.
|
||||
#endif
|
||||
|
||||
xEventGroupClearBits(event_group, CONNECT_BIT | GOT_DATA_BIT | USB_DISCONNECTED_BIT);
|
||||
#if CONFIG_EXAMPLE_DETECT_MODE_BEFORE_CONNECT
|
||||
xEventGroupClearBits(event_group, CONNECT_BIT | GOT_DATA_BIT | USB_DISCONNECTED_BIT | DISCONNECT_BIT);
|
||||
|
||||
err = esp_modem_set_mode(dce, ESP_MODEM_MODE_DETECT);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "esp_modem_set_mode(ESP_MODEM_MODE_DETECT) failed with %d", err);
|
||||
return;
|
||||
}
|
||||
esp_modem_dce_mode_t mode = esp_modem_get_mode(dce);
|
||||
ESP_LOGI(TAG, "Mode detection completed: current mode is: %d", mode);
|
||||
if (mode == ESP_MODEM_MODE_DATA) { // set back to command mode
|
||||
err = esp_modem_set_mode(dce, ESP_MODEM_MODE_COMMAND);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "esp_modem_set_mode(ESP_MODEM_MODE_COMMAND) failed with %d", err);
|
||||
return;
|
||||
}
|
||||
ESP_LOGI(TAG, "Command mode restored");
|
||||
}
|
||||
#endif // CONFIG_EXAMPLE_DETECT_MODE_BEFORE_CONNECT
|
||||
|
||||
xEventGroupClearBits(event_group, CONNECT_BIT | GOT_DATA_BIT | USB_DISCONNECTED_BIT | DISCONNECT_BIT);
|
||||
|
||||
/* Run the modem demo app */
|
||||
#if CONFIG_EXAMPLE_NEED_SIM_PIN == 1
|
||||
@ -262,7 +286,7 @@ void app_main(void)
|
||||
#endif
|
||||
|
||||
int rssi, ber;
|
||||
esp_err_t err = esp_modem_get_signal_quality(dce, &rssi, &ber);
|
||||
err = esp_modem_get_signal_quality(dce, &rssi, &ber);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "esp_modem_get_signal_quality failed with %d %s", err, esp_err_to_name(err));
|
||||
return;
|
||||
@ -301,22 +325,41 @@ void app_main(void)
|
||||
}
|
||||
/* Wait for IP address */
|
||||
ESP_LOGI(TAG, "Waiting for IP address");
|
||||
xEventGroupWaitBits(event_group, CONNECT_BIT | USB_DISCONNECTED_BIT, pdFALSE, pdFALSE, portMAX_DELAY);
|
||||
xEventGroupWaitBits(event_group, CONNECT_BIT | USB_DISCONNECTED_BIT | DISCONNECT_BIT, pdFALSE, pdFALSE,
|
||||
pdMS_TO_TICKS(60000));
|
||||
CHECK_USB_DISCONNECTION(event_group);
|
||||
if ((xEventGroupGetBits(event_group) & CONNECT_BIT) != CONNECT_BIT) {
|
||||
ESP_LOGW(TAG, "Modem not connected, switching back to the command mode");
|
||||
err = esp_modem_set_mode(dce, ESP_MODEM_MODE_COMMAND);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "esp_modem_set_mode(ESP_MODEM_MODE_COMMAND) failed with %d", err);
|
||||
return;
|
||||
}
|
||||
ESP_LOGI(TAG, "Command mode restored");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Config MQTT */
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
|
||||
esp_mqtt_client_config_t mqtt_config = {
|
||||
.broker.address.uri = CONFIG_EXAMPLE_MQTT_BROKER_URI,
|
||||
};
|
||||
#else
|
||||
esp_mqtt_client_config_t mqtt_config = {
|
||||
.uri = CONFIG_EXAMPLE_MQTT_BROKER_URI,
|
||||
};
|
||||
#endif
|
||||
esp_mqtt_client_handle_t mqtt_client = esp_mqtt_client_init(&mqtt_config);
|
||||
esp_mqtt_client_register_event(mqtt_client, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL);
|
||||
esp_mqtt_client_start(mqtt_client);
|
||||
|
||||
#if CONFIG_EXAMPLE_PAUSE_NETIF_TO_CHECK_SIGNAL
|
||||
xEventGroupWaitBits(event_group, GOT_DATA_BIT, pdTRUE, pdFALSE, portMAX_DELAY);
|
||||
esp_modem_pause_net(dce, true);
|
||||
err = esp_modem_get_signal_quality(dce, &rssi, &ber);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "esp_modem_get_signal_quality failed with %d", err);
|
||||
return;
|
||||
}
|
||||
ESP_LOGI(TAG, "Signal quality: rssi=%d, ber=%d", rssi, ber);
|
||||
esp_modem_pause_net(dce, false);
|
||||
esp_mqtt_client_publish(mqtt_client, CONFIG_EXAMPLE_MQTT_TEST_TOPIC, CONFIG_EXAMPLE_MQTT_TEST_DATA, 0, 0, 0);
|
||||
#endif // CONFIG_EXAMPLE_PAUSE_NETIF_TO_CHECK_SIGNAL
|
||||
|
||||
ESP_LOGI(TAG, "Waiting for MQTT data");
|
||||
xEventGroupWaitBits(event_group, GOT_DATA_BIT | USB_DISCONNECTED_BIT, pdFALSE, pdFALSE, portMAX_DELAY);
|
||||
CHECK_USB_DISCONNECTION(event_group);
|
||||
|
@ -12,7 +12,7 @@ def test_pppos_connect(dut):
|
||||
4. checks that the client cleanly disconnects
|
||||
"""
|
||||
# Check the sequence of connecting, publishing, disconnecting
|
||||
dut.expect('Modem Connect to PPP Server')
|
||||
dut.expect('Modem Connect to PPP Server', timeout=90)
|
||||
# Check for MQTT connection and the data event
|
||||
dut.expect('MQTT_EVENT_CONNECTED')
|
||||
dut.expect('MQTT_EVENT_DATA')
|
||||
|
@ -11,5 +11,7 @@ CONFIG_EXAMPLE_MODEM_DEVICE_SIM800=y
|
||||
CONFIG_EXAMPLE_MODEM_DEVICE_BG96=n
|
||||
CONFIG_EXAMPLE_MODEM_PPP_APN="lpwa.vodafone.com"
|
||||
CONFIG_EXAMPLE_MQTT_TEST_TOPIC="/ci/esp-modem/pppos-client"
|
||||
CONFIG_EXAMPLE_PAUSE_NETIF_TO_CHECK_SIGNAL=y
|
||||
CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT=y
|
||||
CONFIG_ESP32_PANIC_PRINT_HALT=y
|
||||
CONFIG_EXAMPLE_DETECT_MODE_BEFORE_CONNECT=y
|
||||
|
@ -11,11 +11,3 @@ The example uses the following configuration options to demonstrate basic esp-mo
|
||||
* `EXAMPLE_NEED_SIM_PIN`: To unlock the SIM card with a PIN code if needed
|
||||
* `EXAMPLE_PERFORM_OTA`: To start simple OTA at the end of the example to exercise basic CMUX/modem networking. Please note that the option `CONFIG_UART_ISR_IN_IRAM` is not enabled automatically, so that buffer overflows are expected and CMUX/PPP and networking should recover.
|
||||
* `EXAMPLE_USE_VFS_TERM`: To demonstrate using an abstract file descriptor to talk to the device (instead of the UART driver directly). This option could be used when implementing a custom VFS driver.
|
||||
|
||||
## About the esp_modem
|
||||
|
||||
Please check the component [README](../../README.md)
|
||||
|
||||
### Supported IDF versions
|
||||
|
||||
This example is only supported from `v4.3`, since is uses an experimental `esp_event_cxx` component.
|
||||
|
@ -69,28 +69,28 @@ menu "Example Configuration"
|
||||
config EXAMPLE_MODEM_UART_TX_PIN
|
||||
int "TXD Pin Number"
|
||||
default 25
|
||||
range 0 31
|
||||
range 0 56
|
||||
help
|
||||
Pin number of UART TX.
|
||||
|
||||
config EXAMPLE_MODEM_UART_RX_PIN
|
||||
int "RXD Pin Number"
|
||||
default 26
|
||||
range 0 31
|
||||
range 0 56
|
||||
help
|
||||
Pin number of UART RX.
|
||||
|
||||
config EXAMPLE_MODEM_UART_RTS_PIN
|
||||
int "RTS Pin Number"
|
||||
default 27
|
||||
range 0 31
|
||||
range 0 56
|
||||
help
|
||||
Pin number of UART RTS.
|
||||
|
||||
config EXAMPLE_MODEM_UART_CTS_PIN
|
||||
int "CTS Pin Number"
|
||||
default 23
|
||||
range 0 31
|
||||
range 0 56
|
||||
help
|
||||
Pin number of UART CTS.
|
||||
endmenu
|
||||
|
@ -16,3 +16,4 @@ CONFIG_COMPILER_CXX_EXCEPTIONS=y
|
||||
CONFIG_ESP_MAIN_TASK_STACK_SIZE=8192
|
||||
CONFIG_EXAMPLE_CLOSE_CMUX_AT_END=y
|
||||
CONFIG_EXAMPLE_MQTT_TEST_TOPIC="/ci/esp-modem/pppos-client"
|
||||
CONFIG_BROKER_URI="mqtt://mqtt.eclipseprojects.io"
|
||||
|
@ -1,4 +1,4 @@
|
||||
version: "1.1.0"
|
||||
version: "1.3.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
|
||||
|
@ -30,9 +30,11 @@ public:
|
||||
~DCE_Mode() = default;
|
||||
bool set(DTE *dte, ModuleIf *module, Netif &netif, modem_mode m);
|
||||
modem_mode get();
|
||||
modem_mode guess(DTE *dte, bool with_cmux = false);
|
||||
|
||||
private:
|
||||
bool set_unsafe(DTE *dte, ModuleIf *module, Netif &netif, modem_mode m);
|
||||
modem_mode guess_unsafe(DTE *dte, bool with_cmux);
|
||||
modem_mode mode;
|
||||
|
||||
};
|
||||
@ -79,11 +81,21 @@ public:
|
||||
return dte->command(command, std::move(got_line), time_ms);
|
||||
}
|
||||
|
||||
modem_mode guess_mode(bool with_cmux = false)
|
||||
{
|
||||
return mode.guess(dte.get(), with_cmux);
|
||||
}
|
||||
|
||||
bool set_mode(modem_mode m)
|
||||
{
|
||||
return mode.set(dte.get(), device.get(), netif, m);
|
||||
}
|
||||
|
||||
modem_mode get_mode()
|
||||
{
|
||||
return mode.get();
|
||||
}
|
||||
|
||||
bool recover()
|
||||
{
|
||||
return dte->recover();
|
||||
@ -96,6 +108,29 @@ public:
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Pauses/Unpauses network temporarily
|
||||
* @param do_pause true to pause, false to unpause
|
||||
* @param force true to ignore command failures and continue
|
||||
* @return command_result of the underlying commands
|
||||
*/
|
||||
command_result pause_netif(bool do_pause, bool force = false, int delay = 1000)
|
||||
{
|
||||
command_result result;
|
||||
if (do_pause) {
|
||||
netif.pause();
|
||||
Task::Delay(delay); // Mandatory 1s pause before
|
||||
dte->set_command_callbacks();
|
||||
result = device->set_command_mode();
|
||||
} else {
|
||||
result = device->resume_data_mode();
|
||||
if (result == command_result::OK || force) {
|
||||
netif.resume();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected:
|
||||
std::shared_ptr<DTE> dte;
|
||||
std::shared_ptr<SpecificModule> device;
|
||||
|
@ -77,7 +77,9 @@ public:
|
||||
if (set_command_mode() == command_result::OK) {
|
||||
return true;
|
||||
}
|
||||
Task::Delay(1000); // Mandatory 1s pause after escape
|
||||
// send a newline to delimit the escape from the upcoming sync command
|
||||
uint8_t delim = '\n';
|
||||
dte->write(&delim, 1);
|
||||
if (sync() == command_result::OK) {
|
||||
return true;
|
||||
}
|
||||
|
@ -65,6 +65,18 @@ public:
|
||||
|
||||
int write(DTE_Command command);
|
||||
|
||||
/**
|
||||
* @brief send data to the selected terminal, by default (without term_id argument)
|
||||
* this API works the same as write: sends data to the secondary terminal, which is
|
||||
* typically used as data terminal (for networking).
|
||||
*
|
||||
* @param data Data pointer to write
|
||||
* @param len Data len to write
|
||||
* @param term_id Terminal id: Primary if id==0, Secondary if id==1
|
||||
* @return number of bytes written
|
||||
*/
|
||||
int send(uint8_t *data, size_t len, int term_id = 1);
|
||||
|
||||
/**
|
||||
* @brief Reading from the underlying terminal
|
||||
* @param d Returning the data pointer of the received payload
|
||||
@ -133,6 +145,12 @@ public:
|
||||
*/
|
||||
bool recover();
|
||||
|
||||
/**
|
||||
* @brief Set internal command callbacks to the underlying terminal.
|
||||
* Here we capture command replies to be processed by supplied command callbacks in struct command_cb.
|
||||
*/
|
||||
void set_command_callbacks();
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Allows for locking the DTE
|
||||
@ -192,12 +210,6 @@ private:
|
||||
} inflatable;
|
||||
#endif // CONFIG_ESP_MODEM_USE_INFLATABLE_BUFFER_IF_NEEDED
|
||||
|
||||
/**
|
||||
* @brief Set internal command callbacks to the underlying terminal.
|
||||
* Here we capture command replies to be processed by supplied command callbacks in struct command_cb.
|
||||
*/
|
||||
void set_command_callbacks();
|
||||
|
||||
/**
|
||||
* @brief This abstracts command callback processing and implements its locking, signaling of completion and timeouts.
|
||||
*/
|
||||
|
@ -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
|
||||
*/
|
||||
@ -54,6 +54,16 @@ public:
|
||||
*/
|
||||
void stop();
|
||||
|
||||
/**
|
||||
* @brief Pause the network interface
|
||||
*/
|
||||
void pause();
|
||||
|
||||
/**
|
||||
* @brief Resume the network interface
|
||||
*/
|
||||
void resume();
|
||||
|
||||
void receive(uint8_t *data, size_t len);
|
||||
|
||||
private:
|
||||
|
@ -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
|
||||
*/
|
||||
@ -37,6 +37,17 @@ enum class modem_mode {
|
||||
CMUX_MANUAL_DATA, /*!< Sets the primary terminal to DATA mode in manual CMUX */
|
||||
CMUX_MANUAL_COMMAND, /*!< Sets the primary terminal to COMMAND mode in manual CMUX */
|
||||
CMUX_MANUAL_SWAP, /*!< Swaps virtual terminals in manual CMUX mode (primary <-> secondary) */
|
||||
RESUME_DATA_MODE, /*!< This is used when the device is already in DATA mode and we need the modem lib to
|
||||
* enter the mode without switching. On success, we would end up in DATA-mode, UNDEF otherwise */
|
||||
RESUME_COMMAND_MODE, /*!< This is used when the device is already in COMMAND mode and we want to resume it
|
||||
* On success, we would end up in DATA-mode, UNDEF otherwise */
|
||||
RESUME_CMUX_MANUAL_MODE, /*!< This is used when the device is already in CMUX mode and we need the modem lib to
|
||||
* enter it without switching. On success, we would end up in CMUX_MANUAL-mode, UNDEF otherwise */
|
||||
RESUME_CMUX_MANUAL_DATA, /*!< This is used when the device is already in CMUX-DATA mode and we need the modem lib to
|
||||
* enter it without switching. On success, we would end up in CMUX_MANUAL-DATA mode, UNDEF otherwise */
|
||||
AUTODETECT, /*!< Auto-detection command: It tries to send a few packets in order to recognize which mode the
|
||||
* the device currently is and update the modem library mode. On success the modem is updated,
|
||||
* otherwise it's set to UNDEF */
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -13,6 +13,10 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Compatibility macro to be removed in v2.0
|
||||
*/
|
||||
#define ESP_MODEM_DCE_GENETIC ESP_MODEM_DCE_GENERIC
|
||||
|
||||
typedef struct esp_modem_dce_wrap esp_modem_dce_t;
|
||||
|
||||
typedef struct esp_modem_PdpContext_t {
|
||||
@ -41,13 +45,15 @@ typedef enum esp_modem_dce_mode {
|
||||
ESP_MODEM_MODE_CMUX_MANUAL_SWAP, /**< Swap terminals in CMUX manual mode */
|
||||
ESP_MODEM_MODE_CMUX_MANUAL_DATA, /**< Set DATA mode in CMUX manual mode */
|
||||
ESP_MODEM_MODE_CMUX_MANUAL_COMMAND, /**< Set COMMAND mode in CMUX manual mode */
|
||||
ESP_MODEM_MODE_DETECT, /**< Detect the mode and resume it (if sucessfully detected) */
|
||||
ESP_MODEM_MODE_UNDEF,
|
||||
} esp_modem_dce_mode_t;
|
||||
|
||||
/**
|
||||
* @brief DCE devices: Enum list of supported devices
|
||||
*/
|
||||
typedef enum esp_modem_dce_device {
|
||||
ESP_MODEM_DCE_GENETIC, /**< The most generic device */
|
||||
ESP_MODEM_DCE_GENERIC, /**< The most generic device */
|
||||
ESP_MODEM_DCE_SIM7600,
|
||||
ESP_MODEM_DCE_SIM7070,
|
||||
ESP_MODEM_DCE_SIM7000,
|
||||
@ -141,6 +147,33 @@ esp_err_t esp_modem_command(esp_modem_dce_t *dce, const char *command, esp_err_t
|
||||
*/
|
||||
esp_err_t esp_modem_set_apn(esp_modem_dce_t *dce, const char *apn);
|
||||
|
||||
#ifdef CONFIG_ESP_MODEM_URC_HANDLER
|
||||
/**
|
||||
* @brief Sets a handler for unsolicited result codes (URCs) from the modem
|
||||
*
|
||||
* This function registers a callback that is triggered whenever an unsolicited
|
||||
* result code (URC) is received from the modem. URCs are typically sent by the
|
||||
* modem without a prior command to notify the host about certain events or status changes.
|
||||
*
|
||||
* @param dce Modem DCE handle
|
||||
* @param got_line_cb Callback function which is called whenever a URC line is received
|
||||
* @return ESP_OK on success, ESP_FAIL on failure
|
||||
*/
|
||||
esp_err_t esp_modem_set_urc(esp_modem_dce_t *dce, esp_err_t(*got_line_cb)(uint8_t *data, size_t len));
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief This API provides support for temporarily pausing networking in order
|
||||
* to send/receive AT commands and resume networking afterwards.
|
||||
* @note This function does not switch modes, the modem is still in data mode.
|
||||
*
|
||||
* @param dce Modem DCE handle
|
||||
* @param pause true to pause the network interface, false to resume networking
|
||||
* @return ESP_OK on success
|
||||
*/
|
||||
esp_err_t esp_modem_pause_net(esp_modem_dce_t *dce, bool pause);
|
||||
|
||||
esp_modem_dce_mode_t esp_modem_get_mode(esp_modem_dce_t *dce);
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
@ -44,7 +44,7 @@ inline dce_factory::ModemType convert_modem_enum(esp_modem_dce_device_t module)
|
||||
case ESP_MODEM_DCE_SIM800:
|
||||
return esp_modem::dce_factory::ModemType::SIM800;
|
||||
default:
|
||||
case ESP_MODEM_DCE_GENETIC:
|
||||
case ESP_MODEM_DCE_GENERIC:
|
||||
return esp_modem::dce_factory::ModemType::GenericModule;
|
||||
}
|
||||
}
|
||||
|
@ -60,7 +60,7 @@ extern "C" esp_modem_dce_t *esp_modem_new_dev(esp_modem_dce_device_t module, con
|
||||
|
||||
extern "C" esp_modem_dce_t *esp_modem_new(const esp_modem_dte_config_t *dte_config, const esp_modem_dce_config_t *dce_config, esp_netif_t *netif)
|
||||
{
|
||||
return esp_modem_new_dev(ESP_MODEM_DCE_GENETIC, dte_config, dce_config, netif);
|
||||
return esp_modem_new_dev(ESP_MODEM_DCE_GENERIC, dte_config, dce_config, netif);
|
||||
}
|
||||
|
||||
extern "C" void esp_modem_destroy(esp_modem_dce_t *dce_wrap)
|
||||
@ -95,12 +95,43 @@ extern "C" esp_err_t esp_modem_sync(esp_modem_dce_t *dce_wrap)
|
||||
return command_response_to_esp_err(dce_wrap->dce->sync());
|
||||
}
|
||||
|
||||
extern "C" esp_modem_dce_mode_t esp_modem_get_mode(esp_modem_dce_t *dce_wrap)
|
||||
{
|
||||
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
|
||||
return ESP_MODEM_MODE_UNDEF;
|
||||
}
|
||||
auto mode = dce_wrap->dce->get_mode();
|
||||
switch (mode) {
|
||||
default:
|
||||
case modem_mode::UNDEF:
|
||||
return ESP_MODEM_MODE_UNDEF;
|
||||
case modem_mode::COMMAND_MODE:
|
||||
return ESP_MODEM_MODE_COMMAND;
|
||||
case modem_mode::DATA_MODE:
|
||||
return ESP_MODEM_MODE_DATA;
|
||||
case modem_mode::CMUX_MODE:
|
||||
return ESP_MODEM_MODE_CMUX;
|
||||
case modem_mode::CMUX_MANUAL_MODE:
|
||||
return ESP_MODEM_MODE_CMUX_MANUAL;
|
||||
case modem_mode::CMUX_MANUAL_EXIT:
|
||||
return ESP_MODEM_MODE_CMUX_MANUAL_EXIT;
|
||||
case modem_mode::CMUX_MANUAL_DATA:
|
||||
return ESP_MODEM_MODE_CMUX_MANUAL_DATA;
|
||||
case modem_mode::CMUX_MANUAL_COMMAND:
|
||||
return ESP_MODEM_MODE_CMUX_MANUAL_COMMAND;
|
||||
case modem_mode::CMUX_MANUAL_SWAP:
|
||||
return ESP_MODEM_MODE_CMUX_MANUAL_SWAP;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" esp_err_t esp_modem_set_mode(esp_modem_dce_t *dce_wrap, esp_modem_dce_mode_t mode)
|
||||
{
|
||||
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
switch (mode) {
|
||||
case ESP_MODEM_MODE_UNDEF:
|
||||
return dce_wrap->dce->set_mode(modem_mode::UNDEF) ? ESP_OK : ESP_FAIL;
|
||||
case ESP_MODEM_MODE_DATA:
|
||||
return dce_wrap->dce->set_mode(modem_mode::DATA_MODE) ? ESP_OK : ESP_FAIL;
|
||||
case ESP_MODEM_MODE_COMMAND:
|
||||
@ -117,6 +148,8 @@ extern "C" esp_err_t esp_modem_set_mode(esp_modem_dce_t *dce_wrap, esp_modem_dce
|
||||
return dce_wrap->dce->set_mode(modem_mode::CMUX_MANUAL_DATA) ? ESP_OK : ESP_FAIL;
|
||||
case ESP_MODEM_MODE_CMUX_MANUAL_COMMAND:
|
||||
return dce_wrap->dce->set_mode(modem_mode::CMUX_MANUAL_COMMAND) ? ESP_OK : ESP_FAIL;
|
||||
case ESP_MODEM_MODE_DETECT:
|
||||
return dce_wrap->dce->set_mode(modem_mode::AUTODETECT) ? ESP_OK : ESP_FAIL;
|
||||
}
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
@ -451,3 +484,43 @@ extern "C" esp_err_t esp_modem_set_apn(esp_modem_dce_t *dce_wrap, const char *ap
|
||||
dce_wrap->dce->get_module()->configure_pdp_context(std::move(new_pdp));
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ESP_MODEM_URC_HANDLER
|
||||
extern "C" esp_err_t esp_modem_set_urc(esp_modem_dce_t *dce_wrap, esp_err_t(*got_line_fn)(uint8_t *data, size_t len))
|
||||
{
|
||||
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (got_line_fn == nullptr) {
|
||||
dce_wrap->dce->set_urc(nullptr);
|
||||
return ESP_OK;
|
||||
}
|
||||
dce_wrap->dce->set_urc([got_line_fn](uint8_t *data, size_t len) {
|
||||
switch (got_line_fn(data, len)) {
|
||||
case ESP_OK:
|
||||
return command_result::OK;
|
||||
case ESP_FAIL:
|
||||
return command_result::FAIL;
|
||||
default:
|
||||
return command_result::TIMEOUT;
|
||||
}
|
||||
});
|
||||
return ESP_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
extern "C" esp_err_t esp_modem_pause_net(esp_modem_dce_t *dce_wrap, bool pause)
|
||||
{
|
||||
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
return command_response_to_esp_err(dce_wrap->dce->pause_netif(pause));
|
||||
}
|
||||
|
||||
extern "C" esp_err_t esp_modem_hang_up(esp_modem_dce_t *dce_wrap)
|
||||
{
|
||||
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
return command_response_to_esp_err(dce_wrap->dce->hang_up());
|
||||
}
|
||||
|
@ -123,7 +123,12 @@ bool CMux::data_available(uint8_t *data, size_t len)
|
||||
{
|
||||
if (data && (type & FT_UIH) == FT_UIH && len > 0 && dlci > 0) { // valid payload on a virtual term
|
||||
int virtual_term = dlci - 1;
|
||||
if (virtual_term < MAX_TERMINALS_NUM && read_cb[virtual_term]) {
|
||||
if (virtual_term < MAX_TERMINALS_NUM) {
|
||||
if (read_cb[virtual_term] == nullptr) {
|
||||
// ignore all virtual terminal's data before we completely establish CMUX
|
||||
ESP_LOG_BUFFER_HEXDUMP("CMUX Rx before init", data, len, ESP_LOG_DEBUG);
|
||||
return true;
|
||||
}
|
||||
// Post partial data (or defragment to post on CMUX footer)
|
||||
#ifdef DEFRAGMENT_CMUX_PAYLOAD
|
||||
if (payload_start == nullptr) {
|
||||
@ -142,7 +147,11 @@ bool CMux::data_available(uint8_t *data, size_t len)
|
||||
sabm_ack = dlci;
|
||||
} else if (data == nullptr && dlci > 0) {
|
||||
int virtual_term = dlci - 1;
|
||||
if (virtual_term < MAX_TERMINALS_NUM && read_cb[virtual_term]) {
|
||||
if (virtual_term < MAX_TERMINALS_NUM) {
|
||||
if (read_cb[virtual_term] == nullptr) {
|
||||
// silently ignore this CMUX frame (not finished entering CMUX, yet)
|
||||
return true;
|
||||
}
|
||||
#ifdef DEFRAGMENT_CMUX_PAYLOAD
|
||||
read_cb[virtual_term](payload_start, total_payload_size);
|
||||
#endif
|
||||
|
@ -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
|
||||
*/
|
||||
@ -18,7 +18,6 @@ namespace transitions {
|
||||
|
||||
static bool exit_data(DTE &dte, ModuleIf &device, Netif &netif)
|
||||
{
|
||||
netif.stop();
|
||||
auto signal = std::make_shared<SignalGroup>();
|
||||
std::weak_ptr<SignalGroup> weak_signal = signal;
|
||||
dte.set_read_cb([&netif, weak_signal](uint8_t *data, size_t len) -> bool {
|
||||
@ -32,7 +31,7 @@ static bool exit_data(DTE &dte, ModuleIf &device, Netif &netif)
|
||||
if (memchr(data, '\n', len))
|
||||
{
|
||||
ESP_LOG_BUFFER_HEXDUMP("esp-modem: debug_data (CMD)", data, len, ESP_LOG_DEBUG);
|
||||
const auto pass = std::list<std::string_view>({"NO CARRIER", "DISCONNECTED"});
|
||||
const auto pass = std::list<std::string_view>({"NO CARRIER", "DISCONNECTED", "OK"});
|
||||
std::string_view response((char *) data, len);
|
||||
for (auto &it : pass)
|
||||
if (response.find(it) != std::string::npos) {
|
||||
@ -44,8 +43,14 @@ static bool exit_data(DTE &dte, ModuleIf &device, Netif &netif)
|
||||
}
|
||||
return false;
|
||||
});
|
||||
netif.stop();
|
||||
netif.wait_until_ppp_exits();
|
||||
if (!signal->wait(1, 2000)) {
|
||||
#ifdef ESP_MODEM_PPP_ESCAPE_BEFORE_EXIT
|
||||
std::array<uint8_t, 3> ppp_escape = {'+', '+', '+'};
|
||||
dte.write(ppp_escape.data(), ppp_escape.size());
|
||||
#endif
|
||||
if (!signal->wait(1, 2000)) { // wait for any of the disconnection messages
|
||||
// if no reply -> set device to command mode
|
||||
dte.set_read_cb(nullptr);
|
||||
if (!device.set_mode(modem_mode::COMMAND_MODE)) {
|
||||
return false;
|
||||
@ -103,6 +108,51 @@ bool DCE_Mode::set_unsafe(DTE *dte, ModuleIf *device, Netif &netif, modem_mode m
|
||||
return true;
|
||||
case modem_mode::DUAL_MODE: // Only DTE can be in Dual mode
|
||||
break;
|
||||
case modem_mode::AUTODETECT: {
|
||||
auto guessed = guess_unsafe(dte, true);
|
||||
if (guessed == modem_mode::UNDEF) {
|
||||
return false;
|
||||
}
|
||||
// prepare the undefined mode before to allow all possible transitions
|
||||
if (!dte->set_mode(modem_mode::UNDEF)) {
|
||||
return false;
|
||||
}
|
||||
mode = modem_mode::UNDEF;
|
||||
ESP_LOGD("DCE mode", "Detected mode: %d", static_cast<int>(guessed));
|
||||
if (guessed == modem_mode::DATA_MODE) {
|
||||
return set_unsafe(dte, device, netif, esp_modem::modem_mode::RESUME_DATA_MODE);
|
||||
} else if (guessed == esp_modem::modem_mode::COMMAND_MODE) {
|
||||
return set_unsafe(dte, device, netif, esp_modem::modem_mode::RESUME_COMMAND_MODE);
|
||||
} else if (guessed == esp_modem::modem_mode::CMUX_MODE) {
|
||||
if (!set_unsafe(dte, device, netif, esp_modem::modem_mode::RESUME_CMUX_MANUAL_MODE)) {
|
||||
return false;
|
||||
}
|
||||
// now we guess the mode for each terminal
|
||||
guessed = guess_unsafe(dte, false);
|
||||
ESP_LOGD("DCE mode", "Detected mode on primary term: %d", static_cast<int>(guessed));
|
||||
// now we need to access the second terminal, so we could simply send a SWAP command
|
||||
// (switching to data mode does the swapping internally, so we only swap if we're in CMD mode)
|
||||
if (guessed == modem_mode::DATA_MODE) {
|
||||
// switch to DATA on the primary terminal and swap terminals
|
||||
if (!set_unsafe(dte, device, netif, esp_modem::modem_mode::RESUME_CMUX_MANUAL_DATA)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// swap terminals
|
||||
if (!set_unsafe(dte, device, netif, esp_modem::modem_mode::CMUX_MANUAL_SWAP)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
guessed = guess_unsafe(dte, false);
|
||||
ESP_LOGD("DCE mode", "Detected mode on secondary term: %d", static_cast<int>(guessed));
|
||||
if (guessed == modem_mode::DATA_MODE) {
|
||||
if (!set_unsafe(dte, device, netif, esp_modem::modem_mode::RESUME_CMUX_MANUAL_DATA)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case modem_mode::COMMAND_MODE:
|
||||
if (mode == modem_mode::COMMAND_MODE || mode >= modem_mode::CMUX_MANUAL_MODE) {
|
||||
return false;
|
||||
@ -122,6 +172,32 @@ bool DCE_Mode::set_unsafe(DTE *dte, ModuleIf *device, Netif &netif, modem_mode m
|
||||
}
|
||||
mode = m;
|
||||
return true;
|
||||
case modem_mode::RESUME_DATA_MODE:
|
||||
if (!dte->set_mode(modem_mode::DATA_MODE)) {
|
||||
return false;
|
||||
}
|
||||
netif.start();
|
||||
mode = modem_mode::DATA_MODE;
|
||||
return true;
|
||||
case modem_mode::RESUME_COMMAND_MODE:
|
||||
if (!dte->set_mode(modem_mode::COMMAND_MODE)) {
|
||||
return false;
|
||||
}
|
||||
mode = modem_mode::COMMAND_MODE;
|
||||
return true;
|
||||
case modem_mode::RESUME_CMUX_MANUAL_MODE:
|
||||
if (!dte->set_mode(modem_mode::CMUX_MANUAL_MODE)) {
|
||||
return false;
|
||||
}
|
||||
mode = modem_mode::CMUX_MANUAL_MODE;
|
||||
return true;
|
||||
case modem_mode::RESUME_CMUX_MANUAL_DATA:
|
||||
if (!dte->set_mode(modem_mode::CMUX_MANUAL_SWAP)) {
|
||||
return false;
|
||||
}
|
||||
netif.start();
|
||||
mode = modem_mode::CMUX_MANUAL_MODE;
|
||||
return true;
|
||||
case modem_mode::DATA_MODE:
|
||||
if (mode == modem_mode::DATA_MODE || mode == modem_mode::CMUX_MODE || mode >= modem_mode::CMUX_MANUAL_MODE) {
|
||||
return false;
|
||||
@ -191,4 +267,121 @@ modem_mode DCE_Mode::get()
|
||||
return mode;
|
||||
}
|
||||
|
||||
modem_mode DCE_Mode::guess(DTE *dte, bool with_cmux)
|
||||
{
|
||||
Scoped<DTE> lock(*dte);
|
||||
return guess_unsafe(dte, with_cmux);
|
||||
}
|
||||
|
||||
/**
|
||||
* This namespace contains probe packets and expected replies on 3 different protocols,
|
||||
* the modem device could use (as well as timeouts and mode ids for synchronisation)
|
||||
*/
|
||||
namespace probe {
|
||||
|
||||
namespace ppp {
|
||||
// Test that we're in the PPP mode by sending an LCP protocol echo request and expecting LCP echo reply
|
||||
constexpr std::array<uint8_t, 16> lcp_echo_request = {0x7e, 0xff, 0x03, 0xc0, 0x21, 0x09, 0x01, 0x00, 0x08, 0x99, 0xd1, 0x35, 0xc1, 0x8e, 0x2c, 0x7e };
|
||||
constexpr std::array<uint8_t, 5> lcp_echo_reply_head = {0x7e, 0xff, 0x7d, 0x23, 0xc0};
|
||||
const size_t mode = 1 << 0;
|
||||
const int timeout = 200;
|
||||
}
|
||||
|
||||
namespace cmd {
|
||||
// For command mode, we just send a simple AT command
|
||||
const char at[] = "\r\nAT\r\n";
|
||||
const size_t max_at_reply = 16; // account for some whitespaces and/or CMUX encapsulation
|
||||
const char reply[] = { 'O', 'K' };
|
||||
const int mode = 1 << 1;
|
||||
const int timeout = 500;
|
||||
}
|
||||
|
||||
namespace cmux {
|
||||
// For CMUX mode, we send an SABM on control terminal (0)
|
||||
const uint8_t sabm0_reqest[] = {0xf9, 0x03, 0x3f, 0x01, 0x1c, 0xf9};
|
||||
const uint8_t sabm0_reply[] = {0xf9, 0x03, 0x73, 0x01};
|
||||
const int mode = 1 << 0;
|
||||
const int timeout = 200;
|
||||
}
|
||||
};
|
||||
|
||||
modem_mode DCE_Mode::guess_unsafe(DTE *dte, bool with_cmux)
|
||||
{
|
||||
// placeholder for reply and its size, since it could come in pieces, and we have to cache
|
||||
// this is captured by the lambda by reference.
|
||||
// must make sure the lambda is cleared before exiting this function (done by dte->on_read(nullptr))
|
||||
uint8_t reply[std::max(probe::cmd::max_at_reply, std::max(sizeof(probe::ppp::lcp_echo_request), sizeof(probe::cmux::sabm0_reply)))];
|
||||
size_t reply_pos = 0;
|
||||
auto signal = std::make_shared<SignalGroup>();
|
||||
std::weak_ptr<SignalGroup> weak_signal = signal;
|
||||
dte->on_read([weak_signal, with_cmux, &reply, &reply_pos](uint8_t *data, size_t len) {
|
||||
// storing the response in the `reply` array and de-fragmenting
|
||||
if (reply_pos >= sizeof(reply)) {
|
||||
return command_result::TIMEOUT;
|
||||
}
|
||||
auto reply_size = std::min((size_t)sizeof(reply) - reply_pos, len);
|
||||
::memcpy(reply + reply_pos, data, reply_size);
|
||||
reply_pos += reply_size;
|
||||
ESP_LOG_BUFFER_HEXDUMP("esp-modem: guess mode data:", reply, reply_pos, ESP_LOG_DEBUG);
|
||||
|
||||
// Check whether the response resembles the "golden" reply (for these 3 protocols)
|
||||
if (reply_pos >= sizeof(probe::ppp::lcp_echo_reply_head)) {
|
||||
// check for initial 2 bytes
|
||||
auto *ptr = static_cast<uint8_t *>(memmem(reply, reply_pos, probe::ppp::lcp_echo_reply_head.data(), 2));
|
||||
// and check the other two bytes for protocol ID:
|
||||
// * either LCP reply
|
||||
if (ptr && ptr[3] == probe::ppp::lcp_echo_reply_head[3] && ptr[4] == probe::ppp::lcp_echo_reply_head[4]) {
|
||||
if (auto signal = weak_signal.lock()) {
|
||||
signal->set(probe::ppp::mode);
|
||||
}
|
||||
}
|
||||
// * or LCP conf request
|
||||
if (ptr && ptr[3] == probe::ppp::lcp_echo_request[3] && ptr[4] == probe::ppp::lcp_echo_request[4]) {
|
||||
if (auto signal = weak_signal.lock()) {
|
||||
signal->set(probe::ppp::mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (reply_pos >= 4 && memmem(reply, reply_pos, probe::cmd::reply, sizeof(probe::cmd::reply))) {
|
||||
if (reply[0] != 0xf9) { // double check that the reply is not wrapped in CMUX headers
|
||||
if (auto signal = weak_signal.lock()) {
|
||||
signal->set(probe::cmd::mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (with_cmux && reply_pos >= sizeof(probe::cmux::sabm0_reply)) {
|
||||
// checking the initial 3 bytes
|
||||
auto *ptr = static_cast<uint8_t *>(memmem(reply, reply_pos, probe::cmux::sabm0_reply, 3));
|
||||
// and checking that DLCI is 0 (control frame)
|
||||
if (ptr && (ptr[3] >> 2) == 0) {
|
||||
if (auto signal = weak_signal.lock()) {
|
||||
signal->set(probe::cmux::mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
return command_result::TIMEOUT;
|
||||
});
|
||||
auto guessed = modem_mode::UNDEF;
|
||||
// Check the PPP mode fist by sending LCP echo request
|
||||
dte->send((uint8_t *)probe::ppp::lcp_echo_request.data(), sizeof(probe::ppp::lcp_echo_request), 0);
|
||||
if (signal->wait(probe::ppp::mode, probe::ppp::timeout)) {
|
||||
guessed = modem_mode::DATA_MODE;
|
||||
} else { // LCP echo timeout
|
||||
// now check for AT mode
|
||||
reply_pos = 0;
|
||||
dte->send((uint8_t *)probe::cmd::at, sizeof(probe::cmd::at), 0);
|
||||
if (signal->wait(probe::cmd::mode, probe::cmd::timeout)) {
|
||||
guessed = modem_mode::COMMAND_MODE;
|
||||
} else if (with_cmux) { // no AT reply, check for CMUX mode (if requested)
|
||||
reply_pos = 0;
|
||||
dte->send((uint8_t *) probe::cmux::sabm0_reqest, sizeof(probe::cmux::sabm0_reqest), 0);
|
||||
if (signal->wait(probe::cmux::mode, probe::cmux::timeout)) {
|
||||
guessed = modem_mode::CMUX_MODE;
|
||||
}
|
||||
}
|
||||
}
|
||||
dte->on_read(nullptr);
|
||||
return guessed;
|
||||
}
|
||||
|
||||
} // esp_modem
|
||||
|
@ -14,38 +14,53 @@ using namespace esp_modem;
|
||||
|
||||
static const size_t dte_default_buffer_size = 1000;
|
||||
|
||||
DTE::DTE(const esp_modem_dte_config *config, std::unique_ptr<Terminal> terminal):
|
||||
buffer(config->dte_buffer_size),
|
||||
cmux_term(nullptr), primary_term(std::move(terminal)), secondary_term(primary_term),
|
||||
mode(modem_mode::UNDEF)
|
||||
DTE::DTE(const esp_modem_dte_config *config, std::unique_ptr<Terminal> terminal)
|
||||
: buffer(config->dte_buffer_size),
|
||||
cmux_term(nullptr),
|
||||
primary_term(std::move(terminal)),
|
||||
secondary_term(primary_term),
|
||||
mode(modem_mode::UNDEF)
|
||||
{
|
||||
ESP_MODEM_THROW_IF_FALSE(primary_term != nullptr, "Invalid argument: terminal cannot be null");
|
||||
set_command_callbacks();
|
||||
}
|
||||
|
||||
DTE::DTE(std::unique_ptr<Terminal> terminal):
|
||||
buffer(dte_default_buffer_size),
|
||||
cmux_term(nullptr), primary_term(std::move(terminal)), secondary_term(primary_term),
|
||||
mode(modem_mode::UNDEF)
|
||||
DTE::DTE(std::unique_ptr<Terminal> terminal)
|
||||
: buffer(dte_default_buffer_size),
|
||||
cmux_term(nullptr),
|
||||
primary_term(std::move(terminal)),
|
||||
secondary_term(primary_term),
|
||||
mode(modem_mode::UNDEF)
|
||||
{
|
||||
ESP_MODEM_THROW_IF_FALSE(primary_term != nullptr, "Invalid argument: terminal cannot be null");
|
||||
set_command_callbacks();
|
||||
}
|
||||
|
||||
DTE::DTE(const esp_modem_dte_config *config, std::unique_ptr<Terminal> t, std::unique_ptr<Terminal> s):
|
||||
buffer(config->dte_buffer_size),
|
||||
cmux_term(nullptr), primary_term(std::move(t)), secondary_term(std::move(s)),
|
||||
mode(modem_mode::DUAL_MODE)
|
||||
DTE::DTE(const esp_modem_dte_config *config, std::unique_ptr<Terminal> t, std::unique_ptr<Terminal> s)
|
||||
: buffer(config->dte_buffer_size),
|
||||
cmux_term(nullptr),
|
||||
primary_term(std::move(t)),
|
||||
secondary_term(std::move(s)),
|
||||
mode(modem_mode::DUAL_MODE)
|
||||
{
|
||||
ESP_MODEM_THROW_IF_FALSE(primary_term != nullptr, "Invalid argument: primary terminal cannot be null");
|
||||
ESP_MODEM_THROW_IF_FALSE(secondary_term != nullptr, "Invalid argument: secondary terminal cannot be null");
|
||||
set_command_callbacks();
|
||||
}
|
||||
|
||||
DTE::DTE(std::unique_ptr<Terminal> t, std::unique_ptr<Terminal> s):
|
||||
buffer(dte_default_buffer_size),
|
||||
cmux_term(nullptr), primary_term(std::move(t)), secondary_term(std::move(s)),
|
||||
mode(modem_mode::DUAL_MODE)
|
||||
DTE::DTE(std::unique_ptr<Terminal> t, std::unique_ptr<Terminal> s)
|
||||
: buffer(dte_default_buffer_size),
|
||||
cmux_term(nullptr),
|
||||
primary_term(std::move(t)),
|
||||
secondary_term(std::move(s)),
|
||||
mode(modem_mode::DUAL_MODE)
|
||||
{
|
||||
ESP_MODEM_THROW_IF_FALSE(primary_term != nullptr, "Invalid argument: primary terminal cannot be null");
|
||||
ESP_MODEM_THROW_IF_FALSE(secondary_term != nullptr, "Invalid argument: secondary terminal cannot be null");
|
||||
set_command_callbacks();
|
||||
}
|
||||
|
||||
|
||||
void DTE::set_command_callbacks()
|
||||
{
|
||||
primary_term->set_read_cb([this](uint8_t *data, size_t len) {
|
||||
@ -223,13 +238,13 @@ bool DTE::set_mode(modem_mode m)
|
||||
}
|
||||
}
|
||||
// transitions (COMMAND|DUAL|CMUX|UNDEF) -> DATA
|
||||
if (m == modem_mode::DATA_MODE) {
|
||||
if (m == modem_mode::DATA_MODE || m == modem_mode::RESUME_DATA_MODE) {
|
||||
if (mode == modem_mode::CMUX_MODE || mode == modem_mode::CMUX_MANUAL_MODE || mode == modem_mode::DUAL_MODE) {
|
||||
// mode stays the same, but need to swap terminals (as command has been switched)
|
||||
secondary_term.swap(primary_term);
|
||||
set_command_callbacks();
|
||||
} else {
|
||||
mode = m;
|
||||
mode = modem_mode::DATA_MODE;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -316,6 +331,12 @@ int DTE::write(uint8_t *data, size_t len)
|
||||
return secondary_term->write(data, len);
|
||||
}
|
||||
|
||||
int DTE::send(uint8_t *data, size_t len, int term_id)
|
||||
{
|
||||
Terminal *term = term_id == 0 ? primary_term.get() : secondary_term.get();
|
||||
return term->write(data, len);
|
||||
}
|
||||
|
||||
int DTE::write(DTE_Command command)
|
||||
{
|
||||
return primary_term->write(command.data, command.len);
|
||||
|
@ -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
|
||||
*/
|
||||
@ -87,8 +87,10 @@ void Netif::start()
|
||||
receive(data, len);
|
||||
return true;
|
||||
});
|
||||
signal.set(PPP_STARTED);
|
||||
esp_netif_action_start(driver.base.netif, nullptr, 0, nullptr);
|
||||
if (!signal.is_any(PPP_STARTED)) {
|
||||
signal.set(PPP_STARTED);
|
||||
esp_netif_action_start(driver.base.netif, nullptr, 0, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void Netif::stop()
|
||||
@ -97,6 +99,20 @@ void Netif::stop()
|
||||
signal.clear(PPP_STARTED);
|
||||
}
|
||||
|
||||
void Netif::resume()
|
||||
{
|
||||
ppp_dte->set_read_cb([this](uint8_t *data, size_t len) -> bool {
|
||||
receive(data, len);
|
||||
return true;
|
||||
});
|
||||
signal.set(PPP_STARTED);
|
||||
}
|
||||
|
||||
void Netif::pause()
|
||||
{
|
||||
signal.clear(PPP_STARTED);
|
||||
}
|
||||
|
||||
Netif::~Netif()
|
||||
{
|
||||
if (signal.is_any(PPP_STARTED)) {
|
||||
|
@ -52,7 +52,6 @@ void Netif::start()
|
||||
|
||||
void Netif::stop()
|
||||
{
|
||||
ppp_dte->set_read_cb(nullptr);
|
||||
signal.clear(PPP_STARTED);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
*/
|
||||
@ -72,6 +72,7 @@ private:
|
||||
{
|
||||
auto t = static_cast<UartTerminal *>(task_param);
|
||||
t->task();
|
||||
t->task_handle.task_handle = nullptr;
|
||||
vTaskDelete(nullptr);
|
||||
}
|
||||
|
||||
@ -175,13 +176,20 @@ int UartTerminal::read(uint8_t *data, size_t len)
|
||||
uart_get_buffered_data_len(uart.port, &length);
|
||||
length = std::min(len, length);
|
||||
if (length > 0) {
|
||||
return uart_read_bytes(uart.port, data, length, portMAX_DELAY);
|
||||
int read_len = uart_read_bytes(uart.port, data, length, portMAX_DELAY);
|
||||
#if CONFIG_ESP_MODEM_ADD_DEBUG_LOGS
|
||||
ESP_LOG_BUFFER_HEXDUMP("uart-rx", data, read_len, ESP_LOG_DEBUG);
|
||||
#endif
|
||||
return read_len;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int UartTerminal::write(uint8_t *data, size_t len)
|
||||
{
|
||||
#if CONFIG_ESP_MODEM_ADD_DEBUG_LOGS
|
||||
ESP_LOG_BUFFER_HEXDUMP("uart-tx", data, len, ESP_LOG_DEBUG);
|
||||
#endif
|
||||
return uart_write_bytes_compat(uart.port, data, len);
|
||||
}
|
||||
|
||||
|
@ -16,14 +16,14 @@ menu "Test App Configuration"
|
||||
config TEST_APP_UART_TX_PIN
|
||||
int "TXD Pin Number"
|
||||
default 6
|
||||
range 0 31
|
||||
range 0 56
|
||||
help
|
||||
Pin number of UART TX.
|
||||
|
||||
config TEST_APP_UART_RX_PIN
|
||||
int "RXD Pin Number"
|
||||
default 7
|
||||
range 0 31
|
||||
range 0 56
|
||||
help
|
||||
Pin number of UART RX.
|
||||
|
||||
|
@ -9,6 +9,20 @@ from threading import Event, Thread
|
||||
import netifaces
|
||||
|
||||
|
||||
def is_esp32(port):
|
||||
"""
|
||||
Check if the given port is connected to an ESP32 using esptool.
|
||||
"""
|
||||
try:
|
||||
result = subprocess.run(
|
||||
['esptool.py', '--port', port, 'chip_id'],
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True, text=True
|
||||
)
|
||||
return 'ESP32' in result.stdout
|
||||
except subprocess.CalledProcessError:
|
||||
return False
|
||||
|
||||
|
||||
def run_server(server_stop, port, server_ip, client_ip, auth, auth_user, auth_password):
|
||||
print('Starting PPP server on port: {}'.format(port))
|
||||
try:
|
||||
@ -66,13 +80,27 @@ def test_examples_protocol_pppos_connect(dut):
|
||||
)
|
||||
raise
|
||||
|
||||
# the PPP test env uses two ttyUSB's: one for ESP32 board, another one for ppp server
|
||||
# use the other port for PPP server than the DUT/ESP
|
||||
port = '/dev/ttyUSB0' if dut.serial.port == '/dev/ttyUSB1' else '/dev/ttyUSB1'
|
||||
# the PPP test env uses three ttyUSB's: two for ESP32 board and another one for the ppp server
|
||||
# we need to detect the server_port (for PPPD)
|
||||
server_port = None
|
||||
for i in ['/dev/ttyUSB0', '/dev/ttyUSB1', '/dev/ttyUSB2']:
|
||||
if i == dut.serial.port:
|
||||
print(f'DUT port: {i}')
|
||||
elif is_esp32(i):
|
||||
print(f'Some other ESP32: {i}')
|
||||
else:
|
||||
print(f'Port for PPPD: {i}')
|
||||
server_port = i
|
||||
if server_port is None:
|
||||
print(
|
||||
'ENV_TEST_FAILURE: Cannot locate PPPD port'
|
||||
)
|
||||
raise
|
||||
|
||||
# Start the PPP server
|
||||
server_stop = Event()
|
||||
t = Thread(target=run_server,
|
||||
args=(server_stop, port, server_ip, client_ip, auth, auth_user, auth_password))
|
||||
args=(server_stop, server_port, server_ip, client_ip, auth, auth_user, auth_password))
|
||||
t.start()
|
||||
try:
|
||||
ppp_server_timeout = time.time() + 30
|
||||
|
@ -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.3.0
|
||||
version: 1.4.0
|
||||
version_files:
|
||||
- idf_component.yml
|
||||
|
@ -1,5 +1,23 @@
|
||||
# Changelog
|
||||
|
||||
## [1.4.0](https://github.com/espressif/esp-protocols/commits/websocket-v1.4.0)
|
||||
|
||||
### Features
|
||||
|
||||
- Support DS peripheral for mutual TLS ([55385ec3](https://github.com/espressif/esp-protocols/commit/55385ec3))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- wait for task on destroy ([42674b49](https://github.com/espressif/esp-protocols/commit/42674b49))
|
||||
- Fix pytest to verify client correctly ([9046af8f](https://github.com/espressif/esp-protocols/commit/9046af8f))
|
||||
- propagate error type ([eeeb9006](https://github.com/espressif/esp-protocols/commit/eeeb9006))
|
||||
- fix example buffer leak ([5219c39d](https://github.com/espressif/esp-protocols/commit/5219c39d))
|
||||
|
||||
### Updated
|
||||
|
||||
- chore(websocket): align structure members ([beb6e57e](https://github.com/espressif/esp-protocols/commit/beb6e57e))
|
||||
- chore(websocket): remove unused client variable ([15d3a01e](https://github.com/espressif/esp-protocols/commit/15d3a01e))
|
||||
|
||||
## [1.3.0](https://github.com/espressif/esp-protocols/commits/websocket-v1.3.0)
|
||||
|
||||
### Features
|
||||
|
@ -93,10 +93,13 @@ typedef struct {
|
||||
size_t client_cert_len;
|
||||
const char *client_key;
|
||||
size_t client_key_len;
|
||||
#if CONFIG_ESP_TLS_USE_DS_PERIPHERAL
|
||||
void *client_ds_data;
|
||||
#endif
|
||||
bool use_global_ca_store;
|
||||
bool skip_cert_common_name_check;
|
||||
const char *cert_common_name;
|
||||
esp_err_t (*crt_bundle_attach)(void *conf);
|
||||
esp_err_t (*crt_bundle_attach)(void *conf);
|
||||
esp_transport_handle_t ext_transport;
|
||||
} websocket_config_storage_t;
|
||||
|
||||
@ -122,12 +125,11 @@ struct esp_websocket_client {
|
||||
uint64_t ping_tick_ms;
|
||||
uint64_t pingpong_tick_ms;
|
||||
int wait_timeout_ms;
|
||||
int auto_reconnect;
|
||||
bool run;
|
||||
bool wait_for_pong_resp;
|
||||
bool selected_for_destroying;
|
||||
EventGroupHandle_t status_bits;
|
||||
SemaphoreHandle_t lock;
|
||||
SemaphoreHandle_t lock;
|
||||
size_t errormsg_size;
|
||||
char *errormsg_buffer;
|
||||
char *rx_buffer;
|
||||
@ -186,9 +188,9 @@ static void esp_websocket_free_buf(esp_websocket_client_handle_t client, bool is
|
||||
}
|
||||
|
||||
static esp_err_t esp_websocket_client_dispatch_event(esp_websocket_client_handle_t client,
|
||||
esp_websocket_event_id_t event,
|
||||
const char *data,
|
||||
int data_len)
|
||||
esp_websocket_event_id_t event,
|
||||
const char *data,
|
||||
int data_len)
|
||||
{
|
||||
esp_err_t err;
|
||||
esp_websocket_event_data_t event_data;
|
||||
@ -204,8 +206,8 @@ static esp_err_t esp_websocket_client_dispatch_event(esp_websocket_client_handle
|
||||
|
||||
if (client->error_handle.error_type == WEBSOCKET_ERROR_TYPE_TCP_TRANSPORT) {
|
||||
event_data.error_handle.esp_tls_last_esp_err = esp_tls_get_and_clear_last_error(esp_transport_get_error_handle(client->transport),
|
||||
&client->error_handle.esp_tls_stack_err,
|
||||
&client->error_handle.esp_tls_cert_verify_flags);
|
||||
&client->error_handle.esp_tls_stack_err,
|
||||
&client->error_handle.esp_tls_cert_verify_flags);
|
||||
event_data.error_handle.esp_tls_stack_err = client->error_handle.esp_tls_stack_err;
|
||||
event_data.error_handle.esp_tls_cert_verify_flags = client->error_handle.esp_tls_cert_verify_flags;
|
||||
event_data.error_handle.esp_transport_sock_errno = esp_transport_get_errno(client->transport);
|
||||
@ -235,14 +237,14 @@ static esp_err_t esp_websocket_client_abort_connection(esp_websocket_client_hand
|
||||
} else {
|
||||
client->reconnect_tick_ms = _tick_get_ms();
|
||||
ESP_LOGI(TAG, "Reconnect after %d ms", client->wait_timeout_ms);
|
||||
client->error_handle.error_type = error_type;
|
||||
client->state = WEBSOCKET_STATE_WAIT_TIMEOUT;
|
||||
}
|
||||
client->error_handle.error_type = error_type;
|
||||
esp_websocket_client_dispatch_event(client, WEBSOCKET_EVENT_DISCONNECTED, NULL, 0);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t esp_websocket_client_error(esp_websocket_client_handle_t client, const char *format, ...) __attribute__ ((format (printf, 2, 3)));
|
||||
static esp_err_t esp_websocket_client_error(esp_websocket_client_handle_t client, const char *format, ...) __attribute__((format(printf, 2, 3)));
|
||||
static esp_err_t esp_websocket_client_error(esp_websocket_client_handle_t client, const char *format, ...)
|
||||
{
|
||||
va_list myargs;
|
||||
@ -447,6 +449,21 @@ static void destroy_and_free_resources(esp_websocket_client_handle_t client)
|
||||
client = NULL;
|
||||
}
|
||||
|
||||
static esp_err_t stop_wait_task(esp_websocket_client_handle_t client)
|
||||
{
|
||||
/* A running client cannot be stopped from the websocket task/event handler */
|
||||
TaskHandle_t running_task = xTaskGetCurrentTaskHandle();
|
||||
if (running_task == client->task_handle) {
|
||||
ESP_LOGE(TAG, "Client cannot be stopped from websocket task");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
client->run = false;
|
||||
xEventGroupWaitBits(client->status_bits, STOPPED_BIT, false, true, portMAX_DELAY);
|
||||
client->state = WEBSOCKET_STATE_UNKNOW;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t set_websocket_transport_optional_settings(esp_websocket_client_handle_t client, const char *scheme)
|
||||
{
|
||||
esp_transport_handle_t trans = esp_transport_list_get_transport(client->transport_list, scheme);
|
||||
@ -532,6 +549,10 @@ static esp_err_t esp_websocket_client_create_transport(esp_websocket_client_hand
|
||||
} else {
|
||||
esp_transport_ssl_set_client_key_data_der(ssl, client->config->client_key, client->config->client_key_len);
|
||||
}
|
||||
#if CONFIG_ESP_TLS_USE_DS_PERIPHERAL
|
||||
} else if (client->config->client_ds_data) {
|
||||
esp_transport_ssl_set_ds_data(ssl, client->config->client_ds_data);
|
||||
#endif
|
||||
}
|
||||
if (client->config->crt_bundle_attach) {
|
||||
#ifdef CONFIG_MBEDTLS_CERTIFICATE_BUNDLE
|
||||
@ -654,7 +675,7 @@ esp_websocket_client_handle_t esp_websocket_client_init(const esp_websocket_clie
|
||||
client->keep_alive_cfg.keep_alive_enable = true;
|
||||
client->keep_alive_cfg.keep_alive_idle = (config->keep_alive_idle == 0) ? WEBSOCKET_KEEP_ALIVE_IDLE : config->keep_alive_idle;
|
||||
client->keep_alive_cfg.keep_alive_interval = (config->keep_alive_interval == 0) ? WEBSOCKET_KEEP_ALIVE_INTERVAL : config->keep_alive_interval;
|
||||
client->keep_alive_cfg.keep_alive_count = (config->keep_alive_count == 0) ? WEBSOCKET_KEEP_ALIVE_COUNT : config->keep_alive_count;
|
||||
client->keep_alive_cfg.keep_alive_count = (config->keep_alive_count == 0) ? WEBSOCKET_KEEP_ALIVE_COUNT : config->keep_alive_count;
|
||||
}
|
||||
|
||||
if (config->if_name) {
|
||||
@ -697,6 +718,9 @@ esp_websocket_client_handle_t esp_websocket_client_init(const esp_websocket_clie
|
||||
client->config->client_cert_len = config->client_cert_len;
|
||||
client->config->client_key = config->client_key;
|
||||
client->config->client_key_len = config->client_key_len;
|
||||
#if CONFIG_ESP_TLS_USE_DS_PERIPHERAL
|
||||
client->config->client_ds_data = config->client_ds_data;
|
||||
#endif
|
||||
client->config->skip_cert_common_name_check = config->skip_cert_common_name_check;
|
||||
client->config->cert_common_name = config->cert_common_name;
|
||||
client->config->crt_bundle_attach = config->crt_bundle_attach;
|
||||
@ -745,6 +769,7 @@ esp_websocket_client_handle_t esp_websocket_client_init(const esp_websocket_clie
|
||||
ESP_WS_CLIENT_MEM_CHECK(TAG, client->status_bits, {
|
||||
goto _websocket_init_fail;
|
||||
});
|
||||
xEventGroupSetBits(client->status_bits, STOPPED_BIT);
|
||||
|
||||
client->buffer_size = buffer_size;
|
||||
return client;
|
||||
@ -759,9 +784,11 @@ esp_err_t esp_websocket_client_destroy(esp_websocket_client_handle_t client)
|
||||
if (client == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (client->run) {
|
||||
esp_websocket_client_stop(client);
|
||||
|
||||
if (client->status_bits && (STOPPED_BIT & xEventGroupGetBits(client->status_bits)) == 0) {
|
||||
stop_wait_task(client);
|
||||
}
|
||||
|
||||
destroy_and_free_resources(client);
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -923,7 +950,7 @@ static esp_err_t esp_websocket_client_recv(esp_websocket_client_handle_t client)
|
||||
client->last_fin = esp_transport_ws_get_fin_flag(client->transport);
|
||||
client->last_opcode = esp_transport_ws_get_read_opcode(client->transport);
|
||||
|
||||
if (rlen == 0 && client->last_opcode == WS_TRANSPORT_OPCODES_NONE ) {
|
||||
if (rlen == 0 && client->last_opcode == WS_TRANSPORT_OPCODES_NONE) {
|
||||
ESP_LOGV(TAG, "esp_transport_read timeouts");
|
||||
esp_websocket_free_buf(client, false);
|
||||
return ESP_OK;
|
||||
@ -1029,7 +1056,7 @@ static void esp_websocket_client_task(void *pv)
|
||||
}
|
||||
}
|
||||
|
||||
if ( _tick_get_ms() - client->pingpong_tick_ms > client->config->pingpong_timeout_sec * 1000 ) {
|
||||
if (_tick_get_ms() - client->pingpong_tick_ms > client->config->pingpong_timeout_sec * 1000) {
|
||||
if (client->wait_for_pong_resp) {
|
||||
esp_websocket_client_error(client, "Error, no PONG received for more than %d seconds after PING", client->config->pingpong_timeout_sec);
|
||||
esp_websocket_client_abort_connection(client, WEBSOCKET_ERROR_TYPE_PONG_TIMEOUT);
|
||||
@ -1150,23 +1177,13 @@ esp_err_t esp_websocket_client_stop(esp_websocket_client_handle_t client)
|
||||
if (client == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (!client->run) {
|
||||
|
||||
if (xEventGroupGetBits(client->status_bits) & STOPPED_BIT) {
|
||||
ESP_LOGW(TAG, "Client was not started");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
/* A running client cannot be stopped from the websocket task/event handler */
|
||||
TaskHandle_t running_task = xTaskGetCurrentTaskHandle();
|
||||
if (running_task == client->task_handle) {
|
||||
ESP_LOGE(TAG, "Client cannot be stopped from websocket task");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
|
||||
client->run = false;
|
||||
xEventGroupWaitBits(client->status_bits, STOPPED_BIT, false, true, portMAX_DELAY);
|
||||
client->state = WEBSOCKET_STATE_UNKNOW;
|
||||
return ESP_OK;
|
||||
return stop_wait_task(client);
|
||||
}
|
||||
|
||||
static int esp_websocket_client_send_close(esp_websocket_client_handle_t client, int code, const char *additional_data, int total_len, TickType_t timeout)
|
||||
@ -1356,3 +1373,13 @@ esp_err_t esp_websocket_register_events(esp_websocket_client_handle_t client,
|
||||
}
|
||||
return esp_event_handler_register_with(client->event_handle, WEBSOCKET_EVENTS, event, event_handler, event_handler_arg);
|
||||
}
|
||||
|
||||
esp_err_t esp_websocket_unregister_events(esp_websocket_client_handle_t client,
|
||||
esp_websocket_event_id_t event,
|
||||
esp_event_handler_t event_handler)
|
||||
{
|
||||
if (client == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
return esp_event_handler_unregister_with(client->event_handle, WEBSOCKET_EVENTS, event, event_handler);
|
||||
}
|
||||
|
@ -222,10 +222,12 @@ static void websocket_app_start(void)
|
||||
char *long_data = malloc(size);
|
||||
memset(long_data, 'a', size);
|
||||
esp_websocket_client_send_text(client, long_data, size, portMAX_DELAY);
|
||||
free(long_data);
|
||||
|
||||
xSemaphoreTake(shutdown_sema, portMAX_DELAY);
|
||||
esp_websocket_client_close(client, portMAX_DELAY);
|
||||
ESP_LOGI(TAG, "Websocket Stopped");
|
||||
esp_websocket_unregister_events(client, WEBSOCKET_EVENT_ANY, websocket_event_handler);
|
||||
esp_websocket_client_destroy(client);
|
||||
}
|
||||
|
||||
|
@ -55,7 +55,7 @@ class Websocket(object):
|
||||
ssl_context.load_cert_chain(certfile='main/certs/server/server_cert.pem', keyfile='main/certs/server/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.verify_mode = ssl.CERT_REQUIRED
|
||||
ssl_context.check_hostname = False
|
||||
self.server = SimpleSSLWebSocketServer('', self.port, WebsocketTestEcho, ssl_context=ssl_context)
|
||||
else:
|
||||
|
@ -1,4 +1,4 @@
|
||||
version: "1.3.0"
|
||||
version: "1.4.0"
|
||||
description: WebSocket protocol client for ESP-IDF
|
||||
url: https://github.com/espressif/esp-protocols/tree/master/components/esp_websocket_client
|
||||
dependencies:
|
||||
|
@ -108,10 +108,13 @@ typedef struct {
|
||||
int buffer_size; /*!< Websocket buffer size */
|
||||
const char *cert_pem; /*!< Pointer to certificate data in PEM or DER format for server verify (with SSL), default is NULL, not required to verify the server. PEM-format must have a terminating NULL-character. DER-format requires the length to be passed in cert_len. */
|
||||
size_t cert_len; /*!< Length of the buffer pointed to by cert_pem. May be 0 for null-terminated pem */
|
||||
const char *client_cert; /*!< Pointer to certificate data in PEM or DER format for SSL mutual authentication, default is NULL, not required if mutual authentication is not needed. If it is not NULL, also `client_key` has to be provided. PEM-format must have a terminating NULL-character. DER-format requires the length to be passed in client_cert_len. */
|
||||
const char *client_cert; /*!< Pointer to certificate data in PEM or DER format for SSL mutual authentication, default is NULL, not required if mutual authentication is not needed. If it is not NULL, also `client_key` or `client_ds_data` (if supported) has to be provided. PEM-format must have a terminating NULL-character. DER-format requires the length to be passed in client_cert_len. */
|
||||
size_t client_cert_len; /*!< Length of the buffer pointed to by client_cert. May be 0 for null-terminated pem */
|
||||
const char *client_key; /*!< Pointer to private key data in PEM or DER format for SSL mutual authentication, default is NULL, not required if mutual authentication is not needed. If it is not NULL, also `client_cert` has to be provided. PEM-format must have a terminating NULL-character. DER-format requires the length to be passed in client_key_len */
|
||||
const char *client_key; /*!< Pointer to private key data in PEM or DER format for SSL mutual authentication, default is NULL, not required if mutual authentication is not needed. If it is not NULL, also `client_cert` has to be provided and `client_ds_data` (if supported) gets ignored. PEM-format must have a terminating NULL-character. DER-format requires the length to be passed in client_key_len */
|
||||
size_t client_key_len; /*!< Length of the buffer pointed to by client_key_pem. May be 0 for null-terminated pem */
|
||||
#if CONFIG_ESP_TLS_USE_DS_PERIPHERAL
|
||||
void *client_ds_data; /*!< Pointer to the encrypted private key data for SSL mutual authentication using the DS peripheral, default is NULL, not required if mutual authentication is not needed. If it is not NULL, also `client_cert` has to be provided. It is ignored if `client_key` is provided */
|
||||
#endif
|
||||
esp_websocket_transport_t transport; /*!< Websocket transport type, see `esp_websocket_transport_t */
|
||||
const char *subprotocol; /*!< Websocket subprotocol */
|
||||
const char *user_agent; /*!< Websocket user-agent */
|
||||
@ -457,6 +460,18 @@ esp_err_t esp_websocket_register_events(esp_websocket_client_handle_t client,
|
||||
esp_event_handler_t event_handler,
|
||||
void *event_handler_arg);
|
||||
|
||||
/**
|
||||
* @brief Unegister the Websocket Events
|
||||
*
|
||||
* @param client The client handle
|
||||
* @param event The event id
|
||||
* @param event_handler The callback function
|
||||
* @return esp_err_t
|
||||
*/
|
||||
esp_err_t esp_websocket_unregister_events(esp_websocket_client_handle_t client,
|
||||
esp_websocket_event_id_t event,
|
||||
esp_event_handler_t event_handler);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
8
components/libwebsockets/.cz.yaml
Normal file
8
components/libwebsockets/.cz.yaml
Normal file
@ -0,0 +1,8 @@
|
||||
---
|
||||
commitizen:
|
||||
bump_message: 'bump(lws): $current_version -> $new_version'
|
||||
pre_bump_hooks: python ../../ci/changelog.py libwebsockets
|
||||
tag_format: lws-v$version
|
||||
version: 4.3.3
|
||||
version_files:
|
||||
- idf_component.yml
|
7
components/libwebsockets/CHANGELOG.md
Normal file
7
components/libwebsockets/CHANGELOG.md
Normal file
@ -0,0 +1,7 @@
|
||||
# Changelog
|
||||
|
||||
## [4.3.3](https://github.com/espressif/esp-protocols/commits/lws-v4.3.3)
|
||||
|
||||
### Features
|
||||
|
||||
- Add initial support libwebsockets component ([ef3443d](https://github.com/espressif/esp-protocols/commit/ef3443d))
|
20
components/libwebsockets/CMakeLists.txt
Normal file
20
components/libwebsockets/CMakeLists.txt
Normal file
@ -0,0 +1,20 @@
|
||||
idf_component_register(REQUIRES mbedtls)
|
||||
|
||||
set(LWS_WITH_EXPORT_LWSTARGETS OFF CACHE BOOL "Export libwebsockets CMake targets. Disable if they conflict with an outer cmake project.")
|
||||
set(LWS_WITH_MBEDTLS ON CACHE BOOL "Use mbedTLS (>=2.0) replacement for OpenSSL.")
|
||||
set(LWS_WITH_JPEG OFF CACHE BOOL "Enable stateful JPEG stream decoder")
|
||||
|
||||
|
||||
set(WRAP_FUNCTIONS mbedtls_ssl_handshake_step
|
||||
lws_adopt_descriptor_vhost)
|
||||
|
||||
foreach(wrap ${WRAP_FUNCTIONS})
|
||||
target_link_libraries(${COMPONENT_LIB} INTERFACE "-Wl,--wrap=${wrap}")
|
||||
endforeach()
|
||||
|
||||
target_link_libraries(${COMPONENT_LIB} INTERFACE websockets)
|
||||
|
||||
target_sources(${COMPONENT_LIB} INTERFACE "port/lws_port.c")
|
||||
|
||||
|
||||
add_subdirectory(libwebsockets)
|
9
components/libwebsockets/LICENSE.txt
Normal file
9
components/libwebsockets/LICENSE.txt
Normal file
@ -0,0 +1,9 @@
|
||||
Libwebsockets and included programs are provided under the terms of the
|
||||
MIT license, with the exception that some sources are under
|
||||
a similar permissive license like BSD, or are explicitly CC0 / public
|
||||
domain to remove any obstacles from basing differently-licensed code on
|
||||
them.
|
||||
Please refer to the LWS LICENSE for more details.
|
||||
|
||||
Espressif port files are licensed under Apache-2.0 license.
|
||||
Espressif examples and tests are distributed under Unlicense/CC0.
|
24
components/libwebsockets/README.md
Normal file
24
components/libwebsockets/README.md
Normal file
@ -0,0 +1,24 @@
|
||||
# ESP32 libwebsockets Port
|
||||
|
||||
This is a lightweight port of the libwebsockets library designed to run on the ESP32. It provides WebSocket client functionalities.
|
||||
|
||||
## Supported Options
|
||||
|
||||
The ESP-IDF port of libwebsockets supports a set of common WebSocket configurations for clients. These options can be configured through a structure passed to the `lws_create_context()` function.
|
||||
|
||||
Key features supported:
|
||||
- WebSocket with optional SSL/TLS
|
||||
- HTTP/1.1 client support
|
||||
|
||||
## Memory Footprint Considerations
|
||||
|
||||
The memory consumption primarily depends on the number of concurrent connections and the selected options for WebSocket frames, protocol handling, and SSL/TLS features. It consumes approximately 300 kB of program memory.
|
||||
|
||||
### Client:
|
||||
The values bellow were extracted from the client example (./examples/client/main/lws-client.c)
|
||||
- **Initial Memory Usage**: ~8 kB of heap on startup
|
||||
- **Connected Memory Usage Over TLS**: ~35.3 kB of heap after connected to a server
|
||||
- **Connected Memory Usage Over TCP (Plain)**: ~4.5 kB of heap after connected to a server
|
||||
|
||||
#### When configuring a WebSocket client, ensure that you have enough heap space to handle the desired number of concurrent client connections.
|
||||
#### SSL/TLS configurations may require additional memory overhead, depending on the certificate size and cryptographic settings.
|
6
components/libwebsockets/examples/client/CMakeLists.txt
Normal file
6
components/libwebsockets/examples/client/CMakeLists.txt
Normal file
@ -0,0 +1,6 @@
|
||||
# The following lines of boilerplate have to be in your project's CMakeLists
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(client_example)
|
311
components/libwebsockets/examples/client/LICENSE
Normal file
311
components/libwebsockets/examples/client/LICENSE
Normal file
@ -0,0 +1,311 @@
|
||||
Libwebsockets and included programs are provided under the terms of the
|
||||
MIT license shown below, with the exception that some sources are under
|
||||
a similar permissive license like BSD, or are explicitly CC0 / public
|
||||
domain to remove any obstacles from basing differently-licensed code on
|
||||
them.
|
||||
|
||||
Original liberal license retained:
|
||||
|
||||
- lib/misc/sha-1.c - 3-clause BSD license retained, link to original [BSD3]
|
||||
- win32port/zlib
|
||||
- lib/drivers/display/upng.* - ZLIB license (see zlib.h) [ZLIB]
|
||||
- lib/tls/mbedtls/wrapper - Apache 2.0 (only built if linked against mbedtls) [APACHE2]
|
||||
- lib/tls/mbedtls/mbedtls-extensions.c
|
||||
- lib/misc/base64-decode.c - already MIT
|
||||
- contrib/mcufont/encoder
|
||||
- lib/misc/ieeehalfprecision.c - 2-clause BSD license retained [BSD2]
|
||||
- contrib/mcufont/fonts - Open Font License [OFL]
|
||||
|
||||
Relicensed to MIT:
|
||||
|
||||
- lib/misc/daemonize.c - relicensed from Public Domain to MIT,
|
||||
link to original Public Domain version
|
||||
- lib/plat/windows/windows-resolv.c - relicensed from "Beerware v42" to MIT
|
||||
|
||||
Public Domain (CC-zero) to simplify reuse:
|
||||
|
||||
- test-apps/*.c
|
||||
- test-apps/*.h
|
||||
- minimal-examples/*
|
||||
- lwsws/*
|
||||
|
||||
Although libwebsockets is available under a permissive license, it does not
|
||||
change the reality of dealing with large lumps of external code... if your
|
||||
copy diverges it is guaranteed to contain security problems after a while
|
||||
and can be very painful to pick backports (especially since historically,
|
||||
we are very hot on cleaning and refactoring the codebase). The least
|
||||
painful and lowest risk way remains sending your changes and fixes upstream
|
||||
to us so you can easily use later releases and fixes.
|
||||
|
||||
## MIT License applied to libwebsockets
|
||||
|
||||
https://opensource.org/licenses/MIT
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to
|
||||
deal in the Software without restriction, including without limitation the
|
||||
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
IN THE SOFTWARE.
|
||||
|
||||
## BSD2
|
||||
|
||||
```
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the distribution
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
```
|
||||
|
||||
## BSD3
|
||||
|
||||
For convenience, a copy of the license on `./lib/misc/sha-1.c`. In binary
|
||||
distribution, this applies to builds with ws support enabled, and without
|
||||
`LWS_WITHOUT_BUILTIN_SHA1` at cmake.
|
||||
|
||||
```
|
||||
/*
|
||||
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the project nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH
|
||||
```
|
||||
|
||||
## ZLIB
|
||||
|
||||
For convenience, a copy of the license on zlib. In binary distribution,
|
||||
this applies for win32 builds with internal zlib only. You can avoid
|
||||
building any zlib usage or copy at all with `-DLWS_WITH_ZLIB=0` (the
|
||||
default), and so avoid needing to observe the license for binary
|
||||
distribution that doesn't include the related code.
|
||||
|
||||
```
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
Jean-loup Gailly Mark Adler
|
||||
jloup@gzip.org madler@alumni.caltech.edu
|
||||
```
|
||||
|
||||
|
||||
## APACHE2
|
||||
|
||||
For convenience, a copy of the license on the mbedtls wrapper part. In binary
|
||||
distribution, this applies only when building lws against mbedtls.
|
||||
|
||||
The canonical license application to source files uses the URL reference, so the
|
||||
whole is not reproduced here.
|
||||
|
||||
```
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// 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.
|
||||
```
|
||||
|
||||
## CC0
|
||||
|
||||
For convenience,the full text of CC0 dedication found on the lws examples.
|
||||
The intention of this is to dedicate the examples to the public domain, so
|
||||
users can build off and modify them without any constraint.
|
||||
|
||||
```
|
||||
Statement of Purpose
|
||||
|
||||
The laws of most jurisdictions throughout the world automatically confer exclusive Copyright and Related Rights (defined below) upon the creator and subsequent owner(s) (each and all, an "owner") of an original work of authorship and/or a database (each, a "Work").
|
||||
|
||||
Certain owners wish to permanently relinquish those rights to a Work for the purpose of contributing to a commons of creative, cultural and scientific works ("Commons") that the public can reliably and without fear of later claims of infringement build upon, modify, incorporate in other works, reuse and redistribute as freely as possible in any form whatsoever and for any purposes, including without limitation commercial purposes. These owners may contribute to the Commons to promote the ideal of a free culture and the further production of creative, cultural and scientific works, or to gain reputation or greater distribution for their Work in part through the use and efforts of others.
|
||||
|
||||
For these and/or other purposes and motivations, and without any expectation of additional consideration or compensation, the person associating CC0 with a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and publicly distribute the Work under its terms, with knowledge of his or her Copyright and Related Rights in the Work and the meaning and intended legal effect of CC0 on those rights.
|
||||
|
||||
1. Copyright and Related Rights. A Work made available under CC0 may be protected by copyright and related or neighboring rights ("Copyright and Related Rights"). Copyright and Related Rights include, but are not limited to, the following:
|
||||
|
||||
the right to reproduce, adapt, distribute, perform, display, communicate, and translate a Work;
|
||||
moral rights retained by the original author(s) and/or performer(s);
|
||||
publicity and privacy rights pertaining to a person's image or likeness depicted in a Work;
|
||||
rights protecting against unfair competition in regards to a Work, subject to the limitations in paragraph 4(a), below;
|
||||
rights protecting the extraction, dissemination, use and reuse of data in a Work;
|
||||
database rights (such as those arising under Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, and under any national implementation thereof, including any amended or successor version of such directive); and
|
||||
other similar, equivalent or corresponding rights throughout the world based on applicable law or treaty, and any national implementations thereof.
|
||||
|
||||
2. Waiver. To the greatest extent permitted by, but not in contravention of, applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and unconditionally waives, abandons, and surrenders all of Affirmer's Copyright and Related Rights and associated claims and causes of action, whether now known or unknown (including existing as well as future claims and causes of action), in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each member of the public at large and to the detriment of Affirmer's heirs and successors, fully intending that such Waiver shall not be subject to revocation, rescission, cancellation, termination, or any other legal or equitable action to disrupt the quiet enjoyment of the Work by the public as contemplated by Affirmer's express Statement of Purpose.
|
||||
|
||||
3. Public License Fallback. Should any part of the Waiver for any reason be judged legally invalid or ineffective under applicable law, then the Waiver shall be preserved to the maximum extent permitted taking into account Affirmer's express Statement of Purpose. In addition, to the extent the Waiver is so judged Affirmer hereby grants to each affected person a royalty-free, non transferable, non sublicensable, non exclusive, irrevocable and unconditional license to exercise Affirmer's Copyright and Related Rights in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "License"). The License shall be deemed effective as of the date CC0 was applied by Affirmer to the Work. Should any part of the License for any reason be judged legally invalid or ineffective under applicable law, such partial invalidity or ineffectiveness shall not invalidate the remainder of the License, and in such case Affirmer hereby affirms that he or she will not (i) exercise any of his or her remaining Copyright and Related Rights in the Work or (ii) assert any associated claims and causes of action with respect to the Work, in either case contrary to Affirmer's express Statement of Purpose.
|
||||
|
||||
4. Limitations and Disclaimers.
|
||||
|
||||
No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, licensed or otherwise affected by this document.
|
||||
Affirmer offers the Work as-is and makes no representations or warranties of any kind concerning the Work, express, implied, statutory or otherwise, including without limitation warranties of title, merchantability, fitness for a particular purpose, non infringement, or the absence of latent or other defects, accuracy, or the present or absence of errors, whether or not discoverable, all to the greatest extent permissible under applicable law.
|
||||
Affirmer disclaims responsibility for clearing rights of other persons that may apply to the Work or any use thereof, including without limitation any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims responsibility for obtaining any necessary consents, permissions or other rights required for any use of the Work.
|
||||
Affirmer understands and acknowledges that Creative Commons is not a party to this document and has no duty or obligation with respect to this CC0 or use of the Work.
|
||||
```
|
||||
|
||||
## OFL: Open Font License
|
||||
|
||||
```
|
||||
Copyright (c) 2012-2015, The Mozilla Foundation and Telefonica S.A.
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
```
|
87
components/libwebsockets/examples/client/README.md
Normal file
87
components/libwebsockets/examples/client/README.md
Normal file
@ -0,0 +1,87 @@
|
||||
# Websocket LWS client example
|
||||
|
||||
This example will shows how to set up and communicate over a websocket.
|
||||
|
||||
## How to Use Example
|
||||
|
||||
### Hardware Required
|
||||
|
||||
This example can be executed on any ESP32 board, the only required interface is WiFi and connection to internet or a local server.
|
||||
|
||||
### Configure the project
|
||||
|
||||
* 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"
|
||||
|
||||
### 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
|
||||
|
||||
It is **strongly recommended** to not reuse the example certificate in your application;
|
||||
it is included only for demonstration.
|
||||
|
||||
|
||||
### Build and Flash
|
||||
|
||||
Build the project and flash it to the board, then run monitor tool to view serial output:
|
||||
|
||||
```
|
||||
idf.py -p PORT flash monitor
|
||||
```
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
## Example Output
|
||||
|
||||
```
|
||||
I (18208) lws-client: LWS minimal ws client echo
|
||||
|
||||
219868: lws_create_context: LWS: 4.3.99-v4.3.0-424-ga74362ff, MbedTLS-3.6.2 NET CLI SRV H1 H2 WS SS-JSON-POL ConMon IPv6-absent
|
||||
219576: mem: platform fd map: 20 bytes
|
||||
217880: __lws_lc_tag: ++ [wsi|0|pipe] (1)
|
||||
216516: __lws_lc_tag: ++ [vh|0|default||-1] (1)
|
||||
I (18248) lws-client: connect_cb: connecting
|
||||
|
||||
210112: __lws_lc_tag: ++ [wsicli|0|WS/h1/default/echo.websocket.events] (1)
|
||||
204800: [wsicli|0|WS/h1/default/echo.websocket.events]: lws_client_connect_3_connect: trying 13.248.241.119
|
||||
180776: lws_ssl_client_bio_create: allowing selfsigned
|
||||
I (19998) wifi:<ba-add>idx:0 (ifx:0, b4:89:01:63:9d:08), tid:0, ssn:321, winSize:64
|
||||
I (20768) lws-client: WEBSOCKET_EVENT_CONNECTED
|
||||
I (20768) lws-client: Sending hello 0000
|
||||
I (20778) lws-client: WEBSOCKET_EVENT_DATA
|
||||
W (20778) lws-client: Received=echo.websocket.events sponsored by Lob.com
|
||||
|
||||
|
||||
I (20968) lws-client: WEBSOCKET_EVENT_DATA
|
||||
W (20968) lws-client: Received=hello 0000
|
||||
|
||||
|
||||
I (22978) lws-client: Sending hello 0001
|
||||
I (23118) lws-client: WEBSOCKET_EVENT_DATA
|
||||
W (23118) lws-client: Received=hello 0001
|
||||
|
||||
|
||||
I (23778) lws-client: Sending hello 0002
|
||||
I (23938) lws-client: WEBSOCKET_EVENT_DATA
|
||||
W (23938) lws-client: Received=hello 0002
|
||||
|
||||
|
||||
I (25948) lws-client: Sending hello 0003
|
||||
I (26088) lws-client: WEBSOCKET_EVENT_DATA
|
||||
W (26088) lws-client: Received=hello 0003
|
||||
|
||||
|
||||
I (26948) lws-client: Sending hello 0004
|
||||
I (27118) lws-client: WEBSOCKET_EVENT_DATA
|
||||
W (27118) lws-client: Received=hello 0004
|
||||
```
|
12
components/libwebsockets/examples/client/main/CMakeLists.txt
Normal file
12
components/libwebsockets/examples/client/main/CMakeLists.txt
Normal file
@ -0,0 +1,12 @@
|
||||
set(SRC_FILES "lws-client.c") # Define source files
|
||||
set(INCLUDE_DIRS ".") # Define include directories
|
||||
set(EMBED_FILES "") # Initialize an empty list for files to embed
|
||||
|
||||
list(APPEND EMBED_FILES
|
||||
"certs/client_cert.pem"
|
||||
"certs/ca_cert.pem"
|
||||
"certs/client_key.pem")
|
||||
|
||||
idf_component_register(SRCS "${SRC_FILES}"
|
||||
INCLUDE_DIRS "${INCLUDE_DIRS}"
|
||||
EMBED_TXTFILES "${EMBED_FILES}")
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user