mirror of
https://github.com/espressif/esp-protocols.git
synced 2025-07-26 08:47:27 +02:00
Compare commits
127 Commits
asio-v1.0.
...
asio-v1.14
Author | SHA1 | Date | |
---|---|---|---|
f148c98b13 | |||
06103e4bb4 | |||
c6fc267e5f | |||
52b7f001a2 | |||
cf504ec900 | |||
ab2e08f96c | |||
511ed541b8 | |||
8d0e2aab6b | |||
a02bf05eed | |||
85a2e25093 | |||
a9b5e66d0f | |||
988b3f9905 | |||
53b59332dc | |||
bf84ae940a | |||
a89a0ab7a3 | |||
fe536e476c | |||
afafcb7c24 | |||
55b4775ca8 | |||
1c6c610f20 | |||
9d9d0db1ee | |||
b704aaa33b | |||
7a21db23ad | |||
fcd6f0bb14 | |||
52d7458b99 | |||
56cb58ced7 | |||
77a7538a02 | |||
c8d0a13f0e | |||
582f5b5ff6 | |||
06dd536d52 | |||
e66b19c414 | |||
0ad6cad8b2 | |||
ffa13e4b90 | |||
0fc1fc6b23 | |||
f1d1d79daf | |||
36d0d32b35 | |||
3bf488eb86 | |||
061885ad23 | |||
ab70791625 | |||
62cb235aa9 | |||
04c711f757 | |||
467fec5c9b | |||
5193ebc6ea | |||
3498e86d8b | |||
07a347f907 | |||
d9c9681094 | |||
7310a7a0bc | |||
accf9244ca | |||
290197c210 | |||
b8d1e58778 | |||
cc4d33d871 | |||
ef0e48a678 | |||
187ef7676e | |||
a8714730fb | |||
d2f519f9e5 | |||
a045c1c885 | |||
543521a220 | |||
85be67e708 | |||
5b1b2cce75 | |||
1029078541 | |||
0015e5411c | |||
65b64e1fc1 | |||
d07237b2ce | |||
3c65fde2a7 | |||
35833d2730 | |||
bbb4b7e686 | |||
64e31dae48 | |||
63ce3a5d59 | |||
5dd138c883 | |||
088f7ac3f8 | |||
e079f8ba98 | |||
ff2b0734ea | |||
330332a0fb | |||
48c157bc46 | |||
98bf3efeb6 | |||
ae8479c77e | |||
444fae9066 | |||
bb4c002841 | |||
656ab21c9b | |||
2099434b3f | |||
8f00fc182a | |||
d74c296182 | |||
c4e85bd099 | |||
85ba60e405 | |||
89e1bd27b3 | |||
341fcb0f40 | |||
469f953b28 | |||
381eb314dc | |||
1ffc20c8e3 | |||
5c245dbdb5 | |||
134a9a9eee | |||
010f98ca80 | |||
6e4e4fab1d | |||
b6852a0588 | |||
415e04a55f | |||
3456781494 | |||
d1129f3d19 | |||
973837dd66 | |||
36de9afe0c | |||
0d5081b841 | |||
85c7282641 | |||
57afa38f49 | |||
238ee96783 | |||
10e6348e09 | |||
a286634359 | |||
4cdfc857ad | |||
371a32d4ae | |||
dc4e54e99a | |||
d66f9dc158 | |||
4980ac85b7 | |||
626eb52d04 | |||
82b1aa9280 | |||
e8145fcede | |||
9c3e24b6cf | |||
b4d85d6aae | |||
0b102f6286 | |||
06e7baf2c2 | |||
3662c149fb | |||
a243d7e878 | |||
ef1bae5cdd | |||
4cefcd3606 | |||
a177b3d024 | |||
b7e73d25a7 | |||
9b403d477f | |||
d723fb7a5a | |||
9905fe4cf6 | |||
8dc3e5835c | |||
0cf08fb676 |
36
.github/workflows/build.yml
vendored
36
.github/workflows/build.yml
vendored
@ -1,36 +0,0 @@
|
||||
name: Build
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest", "release-v4.1", "release-v4.2", "release-v4.3", "release-v4.4"]
|
||||
example: ["pppos_client", "modem_console", "ap_to_pppos", "simple_cmux_client"]
|
||||
idf_target: ["esp32"]
|
||||
exclude:
|
||||
- idf_ver: "release-v4.1"
|
||||
example: modem_console
|
||||
- idf_ver: "release-v4.1"
|
||||
example: ap_to_pppos
|
||||
- idf_ver: "release-v4.1"
|
||||
example: simple_cmux_client
|
||||
- idf_ver: "release-v4.2"
|
||||
example: simple_cmux_client
|
||||
|
||||
runs-on: ubuntu-20.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@master
|
||||
with:
|
||||
path: esp-protocols
|
||||
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
|
||||
env:
|
||||
IDF_TARGET: ${{ matrix.idf_target }}
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
cd $GITHUB_WORKSPACE/esp-protocols/components/esp_modem/examples/${{ matrix.example }}
|
||||
idf.py build
|
@ -1,38 +0,0 @@
|
||||
name: Build mDNS
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest"]
|
||||
idf_target: ["esp32", "esp32s2", "esp32c3"]
|
||||
|
||||
runs-on: ubuntu-20.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
path: esp-protocols
|
||||
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
|
||||
env:
|
||||
IDF_TARGET: ${{ matrix.idf_target }}
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
cd $GITHUB_WORKSPACE/esp-protocols/components/mdns/examples/
|
||||
idf.py set-target ${{ matrix.idf_target }}
|
||||
cat sdkconfig.ci.eth_def >> sdkconfig.defaults
|
||||
idf.py build
|
||||
rm sdkconfig.defaults
|
||||
cat sdkconfig.ci.eth_custom_netif >> sdkconfig.defaults
|
||||
idf.py build
|
||||
rm sdkconfig.defaults
|
||||
cat sdkconfig.ci.eth_socket >> sdkconfig.defaults
|
||||
idf.py build
|
||||
cd $GITHUB_WORKSPACE/esp-protocols/components/mdns/tests/test_apps/
|
||||
idf.py set-target ${{ matrix.idf_target }}
|
||||
idf.py build
|
@ -1,78 +0,0 @@
|
||||
name: Build Websockets
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest"]
|
||||
idf_target: ["esp32"]
|
||||
|
||||
runs-on: ubuntu-20.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
|
||||
env:
|
||||
IDF_TARGET: ${{ matrix.idf_target }}
|
||||
shell: bash
|
||||
working-directory: components/esp_websocket_client/examples/
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
cat sdkconfig.ci >> sdkconfig.defaults
|
||||
idf.py build
|
||||
- name: Merge binaries
|
||||
working-directory: components/esp_websocket_client/examples/build
|
||||
env:
|
||||
IDF_TARGET: ${{ matrix.idf_target }}
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
esptool.py --chip ${{ matrix.idf_target }} merge_bin --fill-flash-size 4MB -o flash_image.bin @flash_args
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: examples_app_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}
|
||||
path: components/esp_websocket_client/examples/build/
|
||||
if-no-files-found: error
|
||||
|
||||
run-target:
|
||||
name: Run Example Test on target
|
||||
needs: build
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
idf_ver: ["latest"]
|
||||
idf_target: ["esp32"]
|
||||
runs-on:
|
||||
- self-hosted
|
||||
- ESP32-ETHERNET-KIT
|
||||
container:
|
||||
image: python:3.7-buster
|
||||
options: --privileged # Privileged mode has access to serial ports
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: examples_app_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}
|
||||
path: components/esp_websocket_client/examples/build/
|
||||
- name: Install Python packages
|
||||
env:
|
||||
PIP_EXTRA_INDEX_URL: "https://www.piwheels.org/simple"
|
||||
run: |
|
||||
pip install -r $GITHUB_WORKSPACE/components/esp_websocket_client/examples/requirements.txt
|
||||
- name: Download Example Test to target
|
||||
run: python -m esptool --chip ${{ matrix.idf_target }} write_flash 0x0 components/esp_websocket_client/examples/build/flash_image.bin
|
||||
- name: Run Example Test on target
|
||||
working-directory: components/esp_websocket_client/examples
|
||||
run: |
|
||||
cp sdkconfig.ci sdkconfig.defaults
|
||||
pytest --log-cli-level DEBUG --junit-xml=./test_app_results_${{ matrix.idf_target }}_${{ matrix.idf_ver }}.xml --target=${{ matrix.idf_target }}
|
||||
- uses: actions/upload-artifact@v2
|
||||
if: always()
|
||||
with:
|
||||
name: examples_results_${{ matrix.idf_target }}_${{ matrix.idf_ver }}
|
||||
path: examples/*.xml
|
28
.github/workflows/build_asio.yml
vendored
28
.github/workflows/build_asio.yml
vendored
@ -1,28 +0,0 @@
|
||||
name: Build ASIO
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest"]
|
||||
idf_target: ["esp32", "esp32s2"]
|
||||
example: ["asio_chat", "async_request", "socks4", "ssl_client_server", "tcp_echo_server", "udp_echo_server"]
|
||||
|
||||
runs-on: ubuntu-20.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
path: esp-protocols
|
||||
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
|
||||
env:
|
||||
IDF_TARGET: ${{ matrix.idf_target }}
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
cd $GITHUB_WORKSPACE/esp-protocols/components/asio/examples/${{ matrix.example }}
|
||||
idf.py set-target ${{ matrix.idf_target }}
|
||||
idf.py build
|
2
.github/workflows/host-test.yml
vendored
2
.github/workflows/host-test.yml
vendored
@ -4,7 +4,7 @@ on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
host_test:
|
||||
name: Build and test
|
||||
name: Build and Test on Host
|
||||
runs-on: ubuntu-20.04
|
||||
container: espressif/idf:release-v4.3
|
||||
env:
|
||||
|
3
.github/workflows/publish-docs-component.yml
vendored
3
.github/workflows/publish-docs-component.yml
vendored
@ -9,6 +9,8 @@ jobs:
|
||||
docs_build:
|
||||
name: Docs-Build-And-Upload
|
||||
runs-on: ubuntu-latest
|
||||
# Skip running on forks since it won't have access to secrets
|
||||
if: github.repository == 'espressif/esp-protocols'
|
||||
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
@ -16,6 +18,7 @@ jobs:
|
||||
with:
|
||||
persist-credentials: false
|
||||
fetch-depth: 0
|
||||
submodules: recursive
|
||||
|
||||
- name: Generate docs
|
||||
run: |
|
||||
|
316
.github/workflows/target-test.yml
vendored
Normal file
316
.github/workflows/target-test.yml
vendored
Normal file
@ -0,0 +1,316 @@
|
||||
name: Build and Run Target tests
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build_esp_modem:
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest", "release-v4.1", "release-v4.2", "release-v4.3", "release-v4.4"]
|
||||
example: ["pppos_client", "modem_console", "ap_to_pppos", "simple_cmux_client"]
|
||||
idf_target: ["esp32"]
|
||||
exclude:
|
||||
- idf_ver: "release-v4.1"
|
||||
example: modem_console
|
||||
- idf_ver: "release-v4.1"
|
||||
example: ap_to_pppos
|
||||
- idf_ver: "release-v4.1"
|
||||
example: simple_cmux_client
|
||||
- idf_ver: "release-v4.2"
|
||||
example: simple_cmux_client
|
||||
|
||||
runs-on: ubuntu-20.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@master
|
||||
with:
|
||||
path: esp-protocols
|
||||
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
|
||||
env:
|
||||
IDF_TARGET: ${{ matrix.idf_target }}
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
cd $GITHUB_WORKSPACE/esp-protocols/components/esp_modem/examples/${{ matrix.example }}
|
||||
idf.py build
|
||||
|
||||
build_esp_modem_usb:
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest", "release-v4.4", "release-v5.0"]
|
||||
example: ["modem_console", "pppos_client"]
|
||||
idf_target: ["esp32s2", "esp32s3"]
|
||||
|
||||
runs-on: ubuntu-20.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v3
|
||||
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
|
||||
working-directory: components/esp_modem/examples/${{ matrix.example }}
|
||||
env:
|
||||
IDF_TARGET: ${{ matrix.idf_target }}
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
cat sdkconfig.ci.usb >> sdkconfig.defaults
|
||||
idf.py build
|
||||
|
||||
build_mdns:
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest"]
|
||||
idf_target: ["esp32", "esp32s2", "esp32c3"]
|
||||
config: ["eth_custom_netif", "eth_def", "eth_no_ipv6", "eth_socket"]
|
||||
runs-on: ubuntu-20.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }} for ${{ matrix.config }}
|
||||
env:
|
||||
IDF_TARGET: ${{ matrix.idf_target }}
|
||||
shell: bash
|
||||
working-directory: components/mdns/examples/
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
rm -rf sdkconfig sdkconfig.defaults build build_${{ matrix.config }}
|
||||
cat sdkconfig.ci.${{ matrix.config }} >> sdkconfig.defaults
|
||||
idf.py set-target ${{ matrix.idf_target }}
|
||||
idf.py build
|
||||
mv build build_${{ matrix.config }}
|
||||
- name: Merge binaries with IDF-${{ matrix.idf_ver }} for ${{ matrix.config }}
|
||||
working-directory: components/mdns/examples
|
||||
env:
|
||||
IDF_TARGET: ${{ matrix.idf_target }}
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
cd build_${{ matrix.config }}
|
||||
esptool.py --chip ${{ matrix.idf_target }} merge_bin --fill-flash-size 4MB -o flash_image.bin @flash_args
|
||||
cd ../
|
||||
cat build_${{ matrix.config }}/config/sdkconfig.json
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: examples_app_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.config }}
|
||||
path: |
|
||||
components/mdns/examples/build_${{ matrix.config }}/bootloader/bootloader.bin
|
||||
components/mdns/examples/build_${{ matrix.config }}/partition_table/partition-table.bin
|
||||
components/mdns/examples/build_${{ matrix.config }}/*.bin
|
||||
components/mdns/examples/build_${{ matrix.config }}/*.elf
|
||||
components/mdns/examples/build_${{ matrix.config }}/flasher_args.json
|
||||
components/mdns/examples/build_${{ matrix.config }}/config/sdkconfig.h
|
||||
components/mdns/examples/build_${{ matrix.config }}/config/sdkconfig.json
|
||||
if-no-files-found: error
|
||||
|
||||
build_asio:
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest"]
|
||||
idf_target: ["esp32", "esp32s2"]
|
||||
example: ["asio_chat", "async_request", "socks4", "ssl_client_server", "tcp_echo_server", "udp_echo_server"]
|
||||
runs-on: ubuntu-20.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
|
||||
working-directory: components/asio/examples/${{ matrix.example }}
|
||||
env:
|
||||
IDF_TARGET: ${{ matrix.idf_target }}
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
test -f sdkconfig.ci && cat sdkconfig.ci >> sdkconfig.defaults || echo "No sdkconfig.ci"
|
||||
idf.py set-target ${{ matrix.idf_target }}
|
||||
idf.py build
|
||||
- name: Merge binaries with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }} for ${{ matrix.example }}
|
||||
working-directory: components/asio/examples/${{ matrix.example }}/build
|
||||
env:
|
||||
IDF_TARGET: ${{ matrix.idf_target }}
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
esptool.py --chip ${{ matrix.idf_target }} merge_bin --fill-flash-size 4MB -o flash_image.bin @flash_args
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: examples_app_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.example }}
|
||||
path: |
|
||||
components/asio/examples/${{ matrix.example }}/build/bootloader/bootloader.bin
|
||||
components/asio/examples/${{ matrix.example }}/build//partition_table/partition-table.bin
|
||||
components/asio/examples/${{ matrix.example }}/build/*.bin
|
||||
components/asio/examples/${{ matrix.example }}/build/*.elf
|
||||
components/asio/examples/${{ matrix.example }}/build/flasher_args.json
|
||||
components/asio/examples/${{ matrix.example }}/build/config/sdkconfig.h
|
||||
components/asio/examples/${{ matrix.example }}/build/config/sdkconfig.json
|
||||
if-no-files-found: error
|
||||
|
||||
|
||||
build_websocket:
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest"]
|
||||
idf_target: ["esp32"]
|
||||
runs-on: ubuntu-20.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
|
||||
env:
|
||||
IDF_TARGET: ${{ matrix.idf_target }}
|
||||
shell: bash
|
||||
working-directory: components/esp_websocket_client/examples/
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
cat sdkconfig.ci >> sdkconfig.defaults
|
||||
idf.py build
|
||||
- name: Merge binaries
|
||||
working-directory: components/esp_websocket_client/examples/build
|
||||
env:
|
||||
IDF_TARGET: ${{ matrix.idf_target }}
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
esptool.py --chip ${{ matrix.idf_target }} merge_bin --fill-flash-size 4MB -o flash_image.bin @flash_args
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: examples_app_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}
|
||||
path: |
|
||||
components/esp_websocket_client/examples/build/bootloader/bootloader.bin
|
||||
components/esp_websocket_client/examples/build/partition_table/partition-table.bin
|
||||
components/esp_websocket_client/examples/build/*.bin
|
||||
components/esp_websocket_client/examples/build/*.elf
|
||||
components/esp_websocket_client/examples/build/flasher_args.json
|
||||
components/esp_websocket_client/examples/build/config/sdkconfig.h
|
||||
components/esp_websocket_client/examples/build/config/sdkconfig.json
|
||||
if-no-files-found: error
|
||||
|
||||
run-target:
|
||||
name: Run Websocket Example Test on target
|
||||
needs: build_websocket
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
idf_ver: ["latest"]
|
||||
idf_target: ["esp32"]
|
||||
runs-on:
|
||||
- self-hosted
|
||||
- ESP32-ETHERNET-KIT
|
||||
# Skip running on forks since it won't have access to secrets
|
||||
if: github.repository == 'espressif/esp-protocols'
|
||||
container:
|
||||
image: python:3.7-buster
|
||||
options: --privileged # Privileged mode has access to serial ports
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: examples_app_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}
|
||||
path: components/esp_websocket_client/examples/build/
|
||||
- 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/components/esp_websocket_client/examples/requirements.txt
|
||||
- name: Download Example Test to target
|
||||
run: python -m esptool --chip ${{ matrix.idf_target }} write_flash 0x0 components/esp_websocket_client/examples/build/flash_image.bin
|
||||
- name: Run Example Test on target
|
||||
working-directory: components/esp_websocket_client/examples
|
||||
run: |
|
||||
cp sdkconfig.ci sdkconfig.defaults
|
||||
pytest --log-cli-level DEBUG --junit-xml=./examples_results_${{ matrix.idf_target }}_${{ matrix.idf_ver }}.xml --target=${{ matrix.idf_target }}
|
||||
- uses: actions/upload-artifact@v2
|
||||
if: always()
|
||||
with:
|
||||
name: examples_results_${{ matrix.idf_target }}_${{ matrix.idf_ver }}
|
||||
path: components/esp_websocket_client/examples/*.xml
|
||||
|
||||
run-target-mdns:
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest"]
|
||||
idf_target: ["esp32"]
|
||||
config: ["eth_custom_netif", "eth_def", "eth_no_ipv6", "eth_socket"]
|
||||
name: Run mDNS Example Test on target
|
||||
needs: build_mdns
|
||||
runs-on:
|
||||
- self-hosted
|
||||
- ESP32-ETHERNET-KIT
|
||||
# Skip running on forks since it won't have access to secrets
|
||||
if: github.repository == 'espressif/esp-protocols'
|
||||
steps:
|
||||
- name: Clear repository
|
||||
run: sudo rm -fr $GITHUB_WORKSPACE && mkdir $GITHUB_WORKSPACE
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: examples_app_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.config }}
|
||||
path: components/mdns/examples/build_${{ matrix.config }}
|
||||
- name: Install Python packages
|
||||
env:
|
||||
PIP_EXTRA_INDEX_URL: "https://www.piwheels.org/simple"
|
||||
run: |
|
||||
sudo apt-get install -y dnsutils
|
||||
- name: Download Example Test to target ${{ matrix.config }}
|
||||
run: |
|
||||
python -m esptool --chip ${{ matrix.idf_target }} write_flash 0x0 components/mdns/examples/build_${{ matrix.config }}/flash_image.bin
|
||||
- name: Run Example Test on target ${{ matrix.config }}
|
||||
working-directory: components/mdns/examples
|
||||
run: |
|
||||
rm -rf build
|
||||
mv build_${{ matrix.config }} build
|
||||
cat sdkconfig.ci.${{ matrix.config }} >> sdkconfig.defaults
|
||||
python -m pytest --log-cli-level DEBUG --junit-xml=./examples_results_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.config }}.xml --target=${{ matrix.idf_target }}
|
||||
rm -rf build sdkconfig.defaults
|
||||
- uses: actions/upload-artifact@v2
|
||||
if: always()
|
||||
with:
|
||||
name: examples_results_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.config }}
|
||||
path: components/mdns/examples/*.xml
|
||||
|
||||
run-target-asio:
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest"]
|
||||
idf_target: ["esp32"]
|
||||
example: ["asio_chat", "tcp_echo_server", "udp_echo_server", "ssl_client_server"]
|
||||
name: Run ASIO Example Test on target
|
||||
needs: build_asio
|
||||
runs-on:
|
||||
- self-hosted
|
||||
- ESP32-ETHERNET-KIT
|
||||
# Skip running on forks since it won't have access to secrets
|
||||
if: github.repository == 'espressif/esp-protocols'
|
||||
steps:
|
||||
- name: Clear repository
|
||||
run: sudo rm -fr $GITHUB_WORKSPACE && mkdir $GITHUB_WORKSPACE
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: examples_app_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.example }}
|
||||
path: components/asio/examples/${{ matrix.example }}/build
|
||||
- name: Install Python packages
|
||||
env:
|
||||
PIP_EXTRA_INDEX_URL: "https://www.piwheels.org/simple"
|
||||
run: |
|
||||
sudo apt-get install -y dnsutils
|
||||
- name: Download Example Test to target ${{ matrix.config }}
|
||||
run: |
|
||||
python -m esptool --chip ${{ matrix.idf_target }} write_flash 0x0 components/asio/examples/${{ matrix.example }}/build/flash_image.bin
|
||||
- name: Run Example Test ${{ matrix.example }} on target
|
||||
working-directory: components/asio/examples/${{ matrix.example }}
|
||||
run: |
|
||||
python -m pytest --log-cli-level DEBUG --junit-xml=./examples_results_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.config }}.xml --target=${{ matrix.idf_target }}
|
||||
- uses: actions/upload-artifact@v2
|
||||
if: always()
|
||||
with:
|
||||
name: examples_results_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.example }}
|
||||
path: components/asio/examples/${{ matrix.example }}/*.xml
|
@ -1,4 +1,4 @@
|
||||
idf_component_register(SRCS "connect.c" "stdin_out.c" "addr_from_stdin.c"
|
||||
INCLUDE_DIRS "include"
|
||||
PRIV_REQUIRES esp_netif driver esp_eth
|
||||
PRIV_REQUIRES esp_netif driver esp_eth esp_wifi vfs
|
||||
)
|
||||
|
@ -396,7 +396,9 @@ static esp_netif_t *eth_start(void)
|
||||
#endif
|
||||
#elif CONFIG_EXAMPLE_USE_SPI_ETHERNET
|
||||
gpio_install_isr_service(0);
|
||||
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
|
||||
spi_device_handle_t spi_handle = NULL;
|
||||
#endif
|
||||
spi_bus_config_t buscfg = {
|
||||
.miso_io_num = CONFIG_EXAMPLE_ETH_SPI_MISO_GPIO,
|
||||
.mosi_io_num = CONFIG_EXAMPLE_ETH_SPI_MOSI_GPIO,
|
||||
@ -414,9 +416,14 @@ static esp_netif_t *eth_start(void)
|
||||
.spics_io_num = CONFIG_EXAMPLE_ETH_SPI_CS_GPIO,
|
||||
.queue_size = 20
|
||||
};
|
||||
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
|
||||
ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_EXAMPLE_ETH_SPI_HOST, &devcfg, &spi_handle));
|
||||
/* dm9051 ethernet driver is based on spi driver */
|
||||
eth_dm9051_config_t dm9051_config = ETH_DM9051_DEFAULT_CONFIG(spi_handle);
|
||||
#else
|
||||
eth_dm9051_config_t dm9051_config = ETH_DM9051_DEFAULT_CONFIG(CONFIG_EXAMPLE_ETH_SPI_HOST, &devcfg);
|
||||
#endif // ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
|
||||
|
||||
dm9051_config.int_gpio_num = CONFIG_EXAMPLE_ETH_SPI_INT_GPIO;
|
||||
s_mac = esp_eth_mac_new_dm9051(&dm9051_config, &mac_config);
|
||||
s_phy = esp_eth_phy_new_dm9051(&phy_config);
|
||||
@ -429,9 +436,13 @@ static esp_netif_t *eth_start(void)
|
||||
.spics_io_num = CONFIG_EXAMPLE_ETH_SPI_CS_GPIO,
|
||||
.queue_size = 20
|
||||
};
|
||||
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
|
||||
ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_EXAMPLE_ETH_SPI_HOST, &devcfg, &spi_handle));
|
||||
/* w5500 ethernet driver is based on spi driver */
|
||||
eth_w5500_config_t w5500_config = ETH_W5500_DEFAULT_CONFIG(spi_handle);
|
||||
#else
|
||||
eth_w5500_config_t w5500_config = ETH_W5500_DEFAULT_CONFIG(CONFIG_EXAMPLE_ETH_SPI_HOST, &devcfg);
|
||||
#endif // ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
|
||||
w5500_config.int_gpio_num = CONFIG_EXAMPLE_ETH_SPI_INT_GPIO;
|
||||
s_mac = esp_eth_mac_new_w5500(&w5500_config, &mac_config);
|
||||
s_phy = esp_eth_phy_new_w5500(&phy_config);
|
||||
|
@ -27,6 +27,7 @@ idf_component_register(SRCS ${asio_sources}
|
||||
INCLUDE_DIRS "asio/asio/include" "port/include"
|
||||
PRIV_INCLUDE_DIRS ${asio_priv_includes}
|
||||
REQUIRES lwip)
|
||||
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")
|
||||
|
||||
if(CONFIG_ASIO_SSL_SUPPORT)
|
||||
if(CONFIG_ASIO_USE_ESP_WOLFSSL)
|
||||
|
@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
# (Not part of the boilerplate)
|
||||
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
|
||||
set(EXTRA_COMPONENT_DIRS ../../../../common_components/protocol_examples_common)
|
||||
set(EXTRA_COMPONENT_DIRS ../.. ../../../../common_components/protocol_examples_common)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(asio_chat)
|
||||
|
@ -1,29 +0,0 @@
|
||||
# This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
# Unless required by applicable law or agreed to in writing, this
|
||||
# software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
# CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from __future__ import print_function, unicode_literals
|
||||
|
||||
import re
|
||||
|
||||
import ttfw_idf
|
||||
|
||||
|
||||
@ttfw_idf.idf_example_test(env_tag='Example_GENERIC')
|
||||
def test_examples_asio_chat(env, _): # type: (ttfw_idf.TinyFW.Env, None) -> None
|
||||
msg = 'asio-chat: received hi'
|
||||
dut = env.get_dut('asio_chat', 'examples/protocols/asio/asio_chat')
|
||||
# start the test and expect the client to receive back it's original data
|
||||
dut.start_app()
|
||||
dut.expect(re.compile(r'{}'.format('Waiting for input')), timeout=30)
|
||||
dut.write(msg)
|
||||
dut.write('exit')
|
||||
dut.expect(re.compile(r'{}'.format(msg)), timeout=30)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_examples_asio_chat()
|
24
components/asio/examples/asio_chat/pytest.ini
Normal file
24
components/asio/examples/asio_chat/pytest.ini
Normal file
@ -0,0 +1,24 @@
|
||||
[pytest]
|
||||
# only the files with prefix `pytest_` would be recognized as pytest test scripts.
|
||||
python_files = pytest_*.py
|
||||
|
||||
addopts =
|
||||
-s
|
||||
--embedded-services esp,idf
|
||||
-W ignore::_pytest.warning_types.PytestExperimentalApiWarning
|
||||
--tb short
|
||||
|
||||
# ignore DeprecationWarning
|
||||
filterwarnings =
|
||||
ignore:Call to deprecated create function (.*)\(\):DeprecationWarning
|
||||
|
||||
# log related
|
||||
log_cli = True
|
||||
log_cli_level = INFO
|
||||
log_cli_format = %(asctime)s %(levelname)s %(message)s
|
||||
log_cli_date_format = %Y-%m-%d %H:%M:%S
|
||||
|
||||
log_file = test.log
|
||||
log_file_level = INFO
|
||||
log_file_format = %(asctime)s %(levelname)s %(message)s
|
||||
log_file_date_format = %Y-%m-%d %H:%M:%S
|
21
components/asio/examples/asio_chat/pytest_example_test.py
Normal file
21
components/asio/examples/asio_chat/pytest_example_test.py
Normal file
@ -0,0 +1,21 @@
|
||||
# This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
# Unless required by applicable law or agreed to in writing, this
|
||||
# software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
# CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import re
|
||||
import pytest
|
||||
from pytest_embedded import Dut
|
||||
|
||||
|
||||
def test_examples_asio_chat(dut):
|
||||
msg = 'asio-chat: received hi'
|
||||
# start the test and expect the client to receive back it's original data
|
||||
dut.expect(re.compile(b'Waiting for input'), timeout=30)
|
||||
dut.write(msg)
|
||||
dut.write('exit')
|
||||
msg = bytes(msg, encoding='utf8')
|
||||
dut.expect(re.compile(msg), timeout=30)
|
@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
# (Not part of the boilerplate)
|
||||
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
|
||||
set(EXTRA_COMPONENT_DIRS ../../../../common_components/protocol_examples_common)
|
||||
set(EXTRA_COMPONENT_DIRS ../../ ../../../../common_components/protocol_examples_common)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(async_http_request)
|
||||
|
@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
# (Not part of the boilerplate)
|
||||
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
|
||||
set(EXTRA_COMPONENT_DIRS ../../../../common_components/protocol_examples_common)
|
||||
set(EXTRA_COMPONENT_DIRS ../.. ../../../../common_components/protocol_examples_common)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(asio_sock4)
|
||||
|
@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
# (Not part of the boilerplate)
|
||||
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
|
||||
set(EXTRA_COMPONENT_DIRS ../../../../common_components/protocol_examples_common)
|
||||
set(EXTRA_COMPONENT_DIRS ../.. ../../../../common_components/protocol_examples_common)
|
||||
set(EXCLUDE_COMPONENTS openssl)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
|
@ -1,16 +0,0 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import ttfw_idf
|
||||
|
||||
|
||||
@ttfw_idf.idf_example_test(env_tag='Example_GENERIC', target=['esp32', 'esp32c3'])
|
||||
def test_examples_asio_ssl(env, extra_data):
|
||||
|
||||
dut = env.get_dut('asio_ssl_client_server', 'examples/protocols/asio/ssl_client_server')
|
||||
dut.start_app()
|
||||
|
||||
dut.expect('Reply: GET / HTTP/1.1')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_examples_asio_ssl()
|
24
components/asio/examples/ssl_client_server/pytest.ini
Normal file
24
components/asio/examples/ssl_client_server/pytest.ini
Normal file
@ -0,0 +1,24 @@
|
||||
[pytest]
|
||||
# only the files with prefix `pytest_` would be recognized as pytest test scripts.
|
||||
python_files = pytest_*.py
|
||||
|
||||
addopts =
|
||||
-s
|
||||
--embedded-services esp,idf
|
||||
-W ignore::_pytest.warning_types.PytestExperimentalApiWarning
|
||||
--tb short
|
||||
|
||||
# ignore DeprecationWarning
|
||||
filterwarnings =
|
||||
ignore:Call to deprecated create function (.*)\(\):DeprecationWarning
|
||||
|
||||
# log related
|
||||
log_cli = True
|
||||
log_cli_level = INFO
|
||||
log_cli_format = %(asctime)s %(levelname)s %(message)s
|
||||
log_cli_date_format = %Y-%m-%d %H:%M:%S
|
||||
|
||||
log_file = test.log
|
||||
log_file_level = INFO
|
||||
log_file_format = %(asctime)s %(levelname)s %(message)s
|
||||
log_file_date_format = %Y-%m-%d %H:%M:%S
|
@ -0,0 +1,8 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import pytest
|
||||
from pytest_embedded import Dut
|
||||
|
||||
|
||||
def test_examples_asio_ssl(dut):
|
||||
dut.expect('Reply: GET / HTTP/1.1')
|
@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
# (Not part of the boilerplate)
|
||||
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
|
||||
set(EXTRA_COMPONENT_DIRS ../../../../common_components/protocol_examples_common)
|
||||
set(EXTRA_COMPONENT_DIRS ../.. ../../../../common_components/protocol_examples_common)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(asio_tcp_echo_server)
|
||||
|
24
components/asio/examples/tcp_echo_server/pytest.ini
Normal file
24
components/asio/examples/tcp_echo_server/pytest.ini
Normal file
@ -0,0 +1,24 @@
|
||||
[pytest]
|
||||
# only the files with prefix `pytest_` would be recognized as pytest test scripts.
|
||||
python_files = pytest_*.py
|
||||
|
||||
addopts =
|
||||
-s
|
||||
--embedded-services esp,idf
|
||||
-W ignore::_pytest.warning_types.PytestExperimentalApiWarning
|
||||
--tb short
|
||||
|
||||
# ignore DeprecationWarning
|
||||
filterwarnings =
|
||||
ignore:Call to deprecated create function (.*)\(\):DeprecationWarning
|
||||
|
||||
# log related
|
||||
log_cli = True
|
||||
log_cli_level = INFO
|
||||
log_cli_format = %(asctime)s %(levelname)s %(message)s
|
||||
log_cli_date_format = %Y-%m-%d %H:%M:%S
|
||||
|
||||
log_file = test.log
|
||||
log_file_level = INFO
|
||||
log_file_format = %(asctime)s %(levelname)s %(message)s
|
||||
log_file_date_format = %Y-%m-%d %H:%M:%S
|
@ -1,12 +1,10 @@
|
||||
import os
|
||||
import re
|
||||
import socket
|
||||
|
||||
import ttfw_idf
|
||||
from pytest_embedded import Dut
|
||||
|
||||
|
||||
@ttfw_idf.idf_example_test(env_tag='Example_WIFI_Protocols')
|
||||
def test_examples_protocol_asio_tcp_server(env, extra_data):
|
||||
def test_examples_protocol_asio_tcp_server(dut):
|
||||
"""
|
||||
steps: |
|
||||
1. join AP
|
||||
@ -16,20 +14,13 @@ def test_examples_protocol_asio_tcp_server(env, extra_data):
|
||||
5. Test evaluates received test message on server stdout
|
||||
"""
|
||||
test_msg = b'echo message from client to server'
|
||||
dut1 = env.get_dut('tcp_echo_server', 'examples/protocols/asio/tcp_echo_server', dut_class=ttfw_idf.ESP32DUT)
|
||||
# check and log bin size
|
||||
binary_file = os.path.join(dut1.app.binary_path, 'asio_tcp_echo_server.bin')
|
||||
bin_size = os.path.getsize(binary_file)
|
||||
ttfw_idf.log_performance('asio_tcp_echo_server_bin_size', '{}KB'.format(bin_size // 1024))
|
||||
# 1. start test
|
||||
dut1.start_app()
|
||||
# 2. get the server IP address
|
||||
data = dut1.expect(re.compile(r' IPv4 address: ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)'), timeout=30)
|
||||
data = dut.expect(re.compile(b' IPv4 address: ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)'), timeout=30).group(1).decode()
|
||||
# 3. create tcp client and connect to server
|
||||
dut1.expect('ASIO engine is up and running', timeout=1)
|
||||
dut.expect('ASIO engine is up and running', timeout=1)
|
||||
cli = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
cli.settimeout(30)
|
||||
cli.connect((data[0], 2222))
|
||||
cli.connect((data, 2222))
|
||||
cli.send(test_msg)
|
||||
data = cli.recv(1024)
|
||||
# 4. check the message received back from the server
|
||||
@ -40,8 +31,5 @@ def test_examples_protocol_asio_tcp_server(env, extra_data):
|
||||
print('Failure!')
|
||||
raise ValueError('Wrong data received from asi tcp server: {} (expected:{})'.format(data, test_msg))
|
||||
# 5. check the client message appears also on server terminal
|
||||
dut1.expect(test_msg.decode())
|
||||
dut.expect(test_msg.decode())
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_examples_protocol_asio_tcp_server()
|
2
components/asio/examples/tcp_echo_server/sdkconfig.ci
Normal file
2
components/asio/examples/tcp_echo_server/sdkconfig.ci
Normal file
@ -0,0 +1,2 @@
|
||||
CONFIG_EXAMPLE_CONNECT_WIFI=n
|
||||
CONFIG_EXAMPLE_CONNECT_ETHERNET=y
|
@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
# (Not part of the boilerplate)
|
||||
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
|
||||
set(EXTRA_COMPONENT_DIRS ../../../../common_components/protocol_examples_common)
|
||||
set(EXTRA_COMPONENT_DIRS ../../ ../../../../common_components/protocol_examples_common)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(asio_udp_echo_server)
|
||||
|
@ -1,47 +0,0 @@
|
||||
import os
|
||||
import re
|
||||
import socket
|
||||
|
||||
import ttfw_idf
|
||||
|
||||
|
||||
@ttfw_idf.idf_example_test(env_tag='Example_WIFI_Protocols')
|
||||
def test_examples_protocol_asio_udp_server(env, extra_data):
|
||||
"""
|
||||
steps: |
|
||||
1. join AP
|
||||
2. Start server
|
||||
3. Test connects to server and sends a test message
|
||||
4. Test evaluates received test message from server
|
||||
5. Test evaluates received test message on server stdout
|
||||
"""
|
||||
test_msg = b'echo message from client to server'
|
||||
dut1 = env.get_dut('udp_echo_server', 'examples/protocols/asio/udp_echo_server', dut_class=ttfw_idf.ESP32DUT)
|
||||
# check and log bin size
|
||||
binary_file = os.path.join(dut1.app.binary_path, 'asio_udp_echo_server.bin')
|
||||
bin_size = os.path.getsize(binary_file)
|
||||
ttfw_idf.log_performance('asio_udp_echo_server_bin_size', '{}KB'.format(bin_size // 1024))
|
||||
# 1. start test
|
||||
dut1.start_app()
|
||||
# 2. get the server IP address
|
||||
data = dut1.expect(re.compile(r' IPv4 address: ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)'), timeout=30)
|
||||
# 3. create tcp client and connect to server
|
||||
dut1.expect('ASIO engine is up and running', timeout=1)
|
||||
cli = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
cli.settimeout(30)
|
||||
cli.connect((data[0], 2222))
|
||||
cli.send(test_msg)
|
||||
data = cli.recv(1024)
|
||||
# 4. check the message received back from the server
|
||||
if (data == test_msg):
|
||||
print('PASS: Received correct message')
|
||||
pass
|
||||
else:
|
||||
print('Failure!')
|
||||
raise ValueError('Wrong data received from asio udp server: {} (expected:{})'.format(data, test_msg))
|
||||
# 5. check the client message appears also on server terminal
|
||||
dut1.expect(test_msg.decode())
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_examples_protocol_asio_udp_server()
|
24
components/asio/examples/udp_echo_server/pytest.ini
Normal file
24
components/asio/examples/udp_echo_server/pytest.ini
Normal file
@ -0,0 +1,24 @@
|
||||
[pytest]
|
||||
# only the files with prefix `pytest_` would be recognized as pytest test scripts.
|
||||
python_files = pytest_*.py
|
||||
|
||||
addopts =
|
||||
-s
|
||||
--embedded-services esp,idf
|
||||
-W ignore::_pytest.warning_types.PytestExperimentalApiWarning
|
||||
--tb short
|
||||
|
||||
# ignore DeprecationWarning
|
||||
filterwarnings =
|
||||
ignore:Call to deprecated create function (.*)\(\):DeprecationWarning
|
||||
|
||||
# log related
|
||||
log_cli = True
|
||||
log_cli_level = INFO
|
||||
log_cli_format = %(asctime)s %(levelname)s %(message)s
|
||||
log_cli_date_format = %Y-%m-%d %H:%M:%S
|
||||
|
||||
log_file = test.log
|
||||
log_file_level = INFO
|
||||
log_file_format = %(asctime)s %(levelname)s %(message)s
|
||||
log_file_date_format = %Y-%m-%d %H:%M:%S
|
@ -0,0 +1,33 @@
|
||||
import os
|
||||
import re
|
||||
import socket
|
||||
|
||||
import pytest
|
||||
from pytest_embedded import Dut
|
||||
|
||||
def test_examples_protocol_asio_udp_server(dut):
|
||||
"""
|
||||
steps: |
|
||||
1. join AP
|
||||
2. Start server
|
||||
3. Test connects to server and sends a test message
|
||||
4. Test evaluates received test message from server
|
||||
5. Test evaluates received test message on server stdout
|
||||
"""
|
||||
test_msg = b'echo message from client to server'
|
||||
data = dut.expect(re.compile(b' IPv4 address: ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)'), timeout=30).group(1).decode()
|
||||
dut.expect('ASIO engine is up and running', timeout=1)
|
||||
cli = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
cli.settimeout(30)
|
||||
cli.connect((data, 2222))
|
||||
cli.send(test_msg)
|
||||
data = cli.recv(1024)
|
||||
# 4. check the message received back from the server
|
||||
if (data == test_msg):
|
||||
print('PASS: Received correct message')
|
||||
pass
|
||||
else:
|
||||
print('Failure!')
|
||||
raise ValueError('Wrong data received from asio udp server: {} (expected:{})'.format(data, test_msg))
|
||||
# 5. check the client message appears also on server terminal
|
||||
dut.expect(test_msg.decode())
|
2
components/asio/examples/udp_echo_server/sdkconfig.ci
Normal file
2
components/asio/examples/udp_echo_server/sdkconfig.ci
Normal file
@ -0,0 +1,2 @@
|
||||
CONFIG_EXAMPLE_CONNECT_WIFI=n
|
||||
CONFIG_EXAMPLE_CONNECT_ETHERNET=y
|
@ -1,4 +1,4 @@
|
||||
version: "1.0.1"
|
||||
version: "1.14.1~3"
|
||||
description: ASIO
|
||||
dependencies:
|
||||
idf:
|
||||
|
5
components/esp_modem/.gitignore
vendored
5
components/esp_modem/.gitignore
vendored
@ -90,4 +90,7 @@ build
|
||||
dependencies.lock
|
||||
|
||||
# ignore generated docs
|
||||
docs/html
|
||||
docs/html
|
||||
|
||||
# esp-idf managed components
|
||||
**/managed_components/**
|
@ -11,9 +11,10 @@ else()
|
||||
src/esp_modem_uart.cpp
|
||||
src/esp_modem_term_uart.cpp
|
||||
src/esp_modem_netif.cpp)
|
||||
set(dependencies driver)
|
||||
set(dependencies driver esp_event esp_netif)
|
||||
endif()
|
||||
|
||||
|
||||
set(srcs ${platform_srcs}
|
||||
"src/esp_modem_dte.cpp"
|
||||
"src/esp_modem_dce.cpp"
|
||||
@ -34,12 +35,14 @@ idf_component_register(SRCS "${srcs}"
|
||||
PRIV_INCLUDE_DIRS private_include
|
||||
REQUIRES ${dependencies})
|
||||
|
||||
|
||||
set_target_properties(${COMPONENT_LIB} PROPERTIES
|
||||
CXX_STANDARD 17
|
||||
CXX_STANDARD_REQUIRED ON
|
||||
CXX_EXTENSIONS ON
|
||||
)
|
||||
|
||||
|
||||
if(${target} STREQUAL "linux")
|
||||
# This is needed for ESP_LOGx() macros, as integer formats differ on ESP32(..) and x64
|
||||
set_target_properties(${COMPONENT_LIB} PROPERTIES COMPILE_FLAGS -Wno-format)
|
||||
|
@ -7,3 +7,4 @@ endif()
|
||||
idf_component_register(SRCS "ap_to_pppos.c"
|
||||
${NETWORK_DCE}
|
||||
INCLUDE_DIRS ".")
|
||||
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")
|
||||
|
@ -11,12 +11,13 @@
|
||||
#include "esp_wifi.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_idf_version.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "lwip/lwip_napt.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "network_dce.h"
|
||||
#if ESP_IDF_VERSION_MAJOR >= 5
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
|
||||
#include "esp_mac.h"
|
||||
#include "dhcpserver/dhcpserver.h"
|
||||
#endif
|
||||
@ -124,6 +125,38 @@ void wifi_init_softap(void)
|
||||
EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS, EXAMPLE_ESP_WIFI_CHANNEL);
|
||||
}
|
||||
|
||||
void start_network(void)
|
||||
{
|
||||
EventBits_t bits = 0;
|
||||
while ((bits & CONNECT_BIT) == 0) {
|
||||
if (!modem_check_sync()) {
|
||||
ESP_LOGE(TAG, "Modem does not respond, maybe in DATA mode? ...exiting network mode");
|
||||
modem_stop_network();
|
||||
if (!modem_check_sync()) {
|
||||
ESP_LOGE(TAG, "Modem does not respond to AT ...restarting");
|
||||
modem_reset();
|
||||
ESP_LOGI(TAG, "Restarted");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (!modem_check_signal()) {
|
||||
ESP_LOGI(TAG, "Poor signal ...will check after 5s");
|
||||
vTaskDelay(pdMS_TO_TICKS(5000));
|
||||
continue;
|
||||
}
|
||||
if (!modem_start_network()) {
|
||||
ESP_LOGE(TAG, "Modem could not enter network mode ...will retry after 10s");
|
||||
vTaskDelay(pdMS_TO_TICKS(10000));
|
||||
continue;
|
||||
}
|
||||
bits = xEventGroupWaitBits(event_group, (DISCONNECT_BIT | CONNECT_BIT), pdTRUE, pdFALSE, pdMS_TO_TICKS(30000));
|
||||
if (bits & DISCONNECT_BIT) {
|
||||
ESP_LOGE(TAG, "Modem got disconnected ...retrying");
|
||||
modem_stop_network();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
// Initialize NVS
|
||||
@ -149,16 +182,7 @@ void app_main(void)
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, ESP_EVENT_ANY_ID, on_ip_event, NULL));
|
||||
|
||||
// Start the PPP network and wait for connection
|
||||
modem_start_network();
|
||||
EventBits_t bits;
|
||||
do {
|
||||
bits = xEventGroupWaitBits(event_group, (CONNECT_BIT | DISCONNECT_BIT), pdTRUE, pdFALSE, portMAX_DELAY);
|
||||
if (bits & DISCONNECT_BIT) {
|
||||
ESP_LOGW(TAG, "Modem got disconnected from the PPP server: retrying...");
|
||||
modem_stop_network();
|
||||
modem_start_network();
|
||||
}
|
||||
} while ((bits & CONNECT_BIT) == 0);
|
||||
start_network();
|
||||
|
||||
// Initialize the AP and setup the NAT
|
||||
esp_netif_t *ap_netif = esp_netif_create_default_wifi_ap();
|
||||
@ -172,11 +196,10 @@ void app_main(void)
|
||||
|
||||
// Provide a recovery if disconnection of some kind registered
|
||||
while (true) {
|
||||
bits = xEventGroupWaitBits(event_group, DISCONNECT_BIT, pdTRUE, pdFALSE, portMAX_DELAY);
|
||||
EventBits_t bits = xEventGroupWaitBits(event_group, DISCONNECT_BIT, pdTRUE, pdFALSE, portMAX_DELAY);
|
||||
if (bits & DISCONNECT_BIT) {
|
||||
ESP_LOGW(TAG, "Modem got disconnected from the PPP server: restarting the network...");
|
||||
modem_stop_network();
|
||||
modem_start_network();
|
||||
start_network();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -47,12 +47,31 @@ void modem_deinit_network(void)
|
||||
}
|
||||
}
|
||||
|
||||
void modem_start_network()
|
||||
bool modem_start_network()
|
||||
{
|
||||
esp_modem_set_mode(dce, ESP_MODEM_MODE_DATA);
|
||||
return esp_modem_set_mode(dce, ESP_MODEM_MODE_DATA) == ESP_OK;
|
||||
}
|
||||
|
||||
void modem_stop_network()
|
||||
bool modem_stop_network()
|
||||
{
|
||||
esp_modem_set_mode(dce, ESP_MODEM_MODE_COMMAND);
|
||||
return esp_modem_set_mode(dce, ESP_MODEM_MODE_COMMAND);
|
||||
}
|
||||
|
||||
bool modem_check_sync()
|
||||
{
|
||||
return esp_modem_sync(dce) == ESP_OK;
|
||||
}
|
||||
|
||||
void modem_reset()
|
||||
{
|
||||
esp_modem_reset(dce);
|
||||
}
|
||||
|
||||
bool modem_check_signal()
|
||||
{
|
||||
int rssi, ber;
|
||||
if (esp_modem_get_signal_quality(dce, &rssi, &ber) == ESP_OK) {
|
||||
return rssi != 99 && rssi > 5;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -79,6 +79,24 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
bool sync()
|
||||
{
|
||||
return dce_commands::sync(dte.get()) == command_result::OK;
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
dce_commands::reset(dte.get());
|
||||
}
|
||||
|
||||
bool check_signal()
|
||||
{
|
||||
int rssi, ber;
|
||||
if (dce_commands::get_signal_quality(dte.get(), rssi, ber) != command_result::OK)
|
||||
return false;
|
||||
return rssi != 99 && rssi > 5;
|
||||
}
|
||||
|
||||
[[maybe_unused]] bool init_sim(const std::string &pin)
|
||||
{
|
||||
// switch to command mode (in case we were in PPP mode)
|
||||
@ -166,14 +184,14 @@ extern "C" esp_err_t modem_init_network(esp_netif_t *netif)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
extern "C" void modem_start_network()
|
||||
extern "C" bool modem_start_network()
|
||||
{
|
||||
dce->set_mode(esp_modem::modem_mode::DATA_MODE);
|
||||
return dce->set_mode(esp_modem::modem_mode::DATA_MODE);
|
||||
}
|
||||
|
||||
extern "C" void modem_stop_network()
|
||||
extern "C" bool modem_stop_network()
|
||||
{
|
||||
dce->set_mode(esp_modem::modem_mode::COMMAND_MODE);
|
||||
return dce->set_mode(esp_modem::modem_mode::COMMAND_MODE);
|
||||
}
|
||||
|
||||
extern "C" void modem_deinit_network()
|
||||
@ -182,4 +200,19 @@ extern "C" void modem_deinit_network()
|
||||
dce = nullptr;
|
||||
}
|
||||
|
||||
extern "C" bool modem_check_sync()
|
||||
{
|
||||
return dce->get_module()->sync();
|
||||
}
|
||||
|
||||
extern "C" void modem_reset()
|
||||
{
|
||||
dce->get_module()->reset();
|
||||
}
|
||||
|
||||
extern "C" bool modem_check_signal()
|
||||
{
|
||||
return dce->get_module()->check_signal();
|
||||
}
|
||||
|
||||
}
|
@ -31,13 +31,18 @@ void modem_deinit_network();
|
||||
/**
|
||||
* @brief Starts the PPP network
|
||||
*/
|
||||
void modem_start_network();
|
||||
bool modem_start_network();
|
||||
|
||||
/**
|
||||
* @brief Stops the PPP network
|
||||
*/
|
||||
void modem_stop_network();
|
||||
bool modem_stop_network();
|
||||
|
||||
bool modem_check_sync();
|
||||
|
||||
void modem_reset();
|
||||
|
||||
bool modem_check_signal();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ int main()
|
||||
|
||||
bool pin_ok = true;
|
||||
if (dce->read_pin(pin_ok) == command_result::OK && !pin_ok) {
|
||||
throw_if_false(dce->set_pin(CONFIG_EXAMPLE_SIM_PIN) == command_result::OK, "Cannot set PIN!");
|
||||
ESP_MODEM_THROW_IF_FALSE(dce->set_pin(CONFIG_EXAMPLE_SIM_PIN) == command_result::OK, "Cannot set PIN!");
|
||||
usleep(1000000);
|
||||
}
|
||||
std::string str;
|
||||
|
@ -2,15 +2,5 @@
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
set(EXTRA_COMPONENT_DIRS "../..")
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/version.cmake)
|
||||
|
||||
if("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_GREATER_EQUAL "4.4")
|
||||
if(("${IDF_TARGET}" STREQUAL "esp32s2") OR ("${IDF_TARGET}" STREQUAL "esp32s3"))
|
||||
list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/examples/peripherals/usb/host/cdc/common")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(modem-console)
|
||||
|
@ -20,7 +20,11 @@ For USB enabled targets (ESP32-S2 and ESP32-S3), it is possible to connect to th
|
||||
1. In menuconfig, navigate to `Example Configuration->Type of serial connection to the modem` and choose `USB`.
|
||||
2. Connect the modem USB signals to pin 19 (DATA-) and 20 (DATA+) on your ESP chip.
|
||||
|
||||
USB example uses Quactel BG96 modem device.
|
||||
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. 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
|
||||
|
||||
|
@ -1,19 +0,0 @@
|
||||
include($ENV{IDF_PATH}/tools/cmake/version.cmake)
|
||||
idf_build_get_property(target IDF_TARGET)
|
||||
|
||||
# USB is supported on S2 and S3 targets and IDF version >= 4.4
|
||||
if("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_GREATER_EQUAL "4.4")
|
||||
if(("${target}" STREQUAL "esp32s2") OR ("${target}" STREQUAL "esp32s3"))
|
||||
|
||||
idf_component_register(SRCS "esp_modem_usb.cpp" "esp_modem_usb_api_target.cpp"
|
||||
REQUIRES cdc_acm_host esp_modem
|
||||
REQUIRED_IDF_TARGETS esp32s2 esp32s3
|
||||
PRIV_INCLUDE_DIRS "private_include"
|
||||
INCLUDE_DIRS "include")
|
||||
|
||||
set_target_properties(${COMPONENT_LIB} PROPERTIES
|
||||
CXX_STANDARD 17
|
||||
)
|
||||
|
||||
endif()
|
||||
endif()
|
@ -1,191 +0,0 @@
|
||||
// Copyright 2021 Espressif Systems (Shanghai) CO 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.
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_modem_config.h"
|
||||
#include "esp_modem_usb_config.h"
|
||||
#include "cxx_include/esp_modem_dte.hpp"
|
||||
#include "usb/usb_host.h"
|
||||
#include "usb/cdc_acm_host.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "usb_terminal.hpp"
|
||||
|
||||
static const char *TAG = "usb_terminal";
|
||||
|
||||
/**
|
||||
* @brief USB Host task
|
||||
*
|
||||
* This task is created only if install_usb_host is set to true in DTE configuration.
|
||||
* In case the user doesn't want in install USB Host driver here, he must install it before creating UsbTerminal object.
|
||||
*
|
||||
* @param arg Unused
|
||||
*/
|
||||
void usb_host_task(void *arg)
|
||||
{
|
||||
while (1) {
|
||||
// Start handling system events
|
||||
uint32_t event_flags;
|
||||
usb_host_lib_handle_events(portMAX_DELAY, &event_flags);
|
||||
if (event_flags & USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS) {
|
||||
ESP_LOGD(TAG, "No more clients: clean up\n");
|
||||
usb_host_device_free_all();
|
||||
}
|
||||
if (event_flags & USB_HOST_LIB_EVENT_FLAGS_ALL_FREE) {
|
||||
ESP_LOGD(TAG, "All free: uninstall USB lib\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up USB Host
|
||||
vTaskDelay(10); // Short delay to allow clients clean-up
|
||||
usb_host_lib_handle_events(0, NULL); // Make sure there are now pending events
|
||||
usb_host_uninstall();
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
namespace esp_modem {
|
||||
class UsbTerminal : public Terminal, private CdcAcmDevice {
|
||||
public:
|
||||
explicit UsbTerminal(const esp_modem_dte_config *config)
|
||||
{
|
||||
const struct esp_modem_usb_term_config* usb_config = (struct esp_modem_usb_term_config*)(config->extension_config);
|
||||
|
||||
// Install USB Host driver
|
||||
if (usb_config->install_usb_host) {
|
||||
const usb_host_config_t host_config = {
|
||||
.skip_phy_setup = false,
|
||||
.intr_flags = ESP_INTR_FLAG_LEVEL1,
|
||||
};
|
||||
throw_if_esp_fail(usb_host_install(&host_config), "USB Host install failed");
|
||||
ESP_LOGD(TAG, "USB Host installed");
|
||||
throw_if_false(pdTRUE == xTaskCreatePinnedToCore(usb_host_task, "usb_host", 4096, NULL, config->task_priority + 1, NULL, usb_config->xCoreID), "USB host task failed");
|
||||
}
|
||||
|
||||
// Install CDC-ACM driver
|
||||
const cdc_acm_host_driver_config_t esp_modem_cdc_acm_driver_config = {
|
||||
.driver_task_stack_size = config->task_stack_size,
|
||||
.driver_task_priority = config->task_priority,
|
||||
.xCoreID = (BaseType_t)usb_config->xCoreID
|
||||
};
|
||||
|
||||
// Silently continue of error: CDC-ACM driver might be already installed
|
||||
cdc_acm_host_install(&esp_modem_cdc_acm_driver_config);
|
||||
|
||||
// Open CDC-ACM device
|
||||
const cdc_acm_host_device_config_t esp_modem_cdc_acm_device_config = {
|
||||
.connection_timeout_ms = usb_config->timeout_ms,
|
||||
.out_buffer_size = config->dte_buffer_size,
|
||||
.event_cb = handle_notif,
|
||||
.data_cb = handle_rx,
|
||||
.user_arg = this
|
||||
};
|
||||
|
||||
if (usb_config->cdc_compliant) {
|
||||
throw_if_esp_fail(this->CdcAcmDevice::open(usb_config->vid, usb_config->pid,
|
||||
usb_config->interface_idx, &esp_modem_cdc_acm_device_config),
|
||||
"USB Device open failed");
|
||||
} else {
|
||||
throw_if_esp_fail(this->CdcAcmDevice::open_vendor_specific(usb_config->vid, usb_config->pid,
|
||||
usb_config->interface_idx, &esp_modem_cdc_acm_device_config),
|
||||
"USB Device open failed");
|
||||
}
|
||||
};
|
||||
|
||||
~UsbTerminal()
|
||||
{
|
||||
this->CdcAcmDevice::close();
|
||||
};
|
||||
|
||||
void start() override
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void stop() override
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int write(uint8_t *data, size_t len) override
|
||||
{
|
||||
ESP_LOG_BUFFER_HEXDUMP(TAG, data, len, ESP_LOG_DEBUG);
|
||||
if (this->CdcAcmDevice::tx_blocking(data, len) != ESP_OK) {
|
||||
return -1;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
int read(uint8_t *data, size_t len) override
|
||||
{
|
||||
// This function should never be called. UsbTerminal provides data through Terminal::on_read callback
|
||||
ESP_LOGW(TAG, "Unexpected call to UsbTerminal::read function");
|
||||
return -1;
|
||||
}
|
||||
|
||||
private:
|
||||
UsbTerminal() = delete;
|
||||
UsbTerminal(const UsbTerminal ©) = delete;
|
||||
UsbTerminal &operator=(const UsbTerminal ©) = delete;
|
||||
bool operator== (const UsbTerminal ¶m) const = delete;
|
||||
bool operator!= (const UsbTerminal ¶m) const = delete;
|
||||
|
||||
static void handle_rx(uint8_t *data, size_t data_len, void *user_arg)
|
||||
{
|
||||
ESP_LOG_BUFFER_HEXDUMP(TAG, data, data_len, ESP_LOG_DEBUG);
|
||||
UsbTerminal *this_terminal = static_cast<UsbTerminal *>(user_arg);
|
||||
if (data_len > 0 && this_terminal->on_read) {
|
||||
this_terminal->on_read(data, data_len);
|
||||
} else {
|
||||
ESP_LOGD(TAG, "Unhandled RX data");
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_notif(cdc_acm_dev_hdl_t cdc_hdl, const cdc_acm_host_dev_event_data_t *event, void *user_ctx)
|
||||
{
|
||||
UsbTerminal *this_terminal = static_cast<UsbTerminal *>(user_ctx);
|
||||
|
||||
switch (event->type) {
|
||||
// Notifications like Ring, Rx Carrier indication or Network connection indication are not relevant for USB terminal
|
||||
case CDC_ACM_HOST_NETWORK_CONNECTION:
|
||||
case CDC_ACM_HOST_SERIAL_STATE:
|
||||
break;
|
||||
case CDC_ACM_HOST_DEVICE_DISCONNECTED:
|
||||
ESP_LOGW(TAG, "USB terminal disconnected");
|
||||
cdc_acm_host_close(cdc_hdl);
|
||||
if (this_terminal->on_error) {
|
||||
this_terminal->on_error(terminal_error::UNEXPECTED_CONTROL_FLOW);
|
||||
}
|
||||
break;
|
||||
case CDC_ACM_HOST_ERROR:
|
||||
ESP_LOGE(TAG, "Unexpected CDC-ACM error: %d.", event->data.error);
|
||||
if (this_terminal->on_error) {
|
||||
this_terminal->on_error(terminal_error::UNEXPECTED_CONTROL_FLOW);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
std::unique_ptr<Terminal> create_usb_terminal(const esp_modem_dte_config *config)
|
||||
{
|
||||
TRY_CATCH_RET_NULL(
|
||||
return std::make_unique<UsbTerminal>(config);
|
||||
)
|
||||
}
|
||||
} // namespace esp_modem
|
@ -1,32 +0,0 @@
|
||||
// Copyright 2021-2022 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.
|
||||
|
||||
|
||||
#include "usb_terminal.hpp"
|
||||
#include "cxx_include/esp_modem_api.hpp"
|
||||
#include "cxx_include/esp_modem_netif.hpp"
|
||||
|
||||
#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
|
||||
static const char *TAG = "modem_usb_api_target";
|
||||
#endif
|
||||
|
||||
namespace esp_modem {
|
||||
std::shared_ptr<DTE> create_usb_dte(const dte_config *config)
|
||||
{
|
||||
TRY_CATCH_RET_NULL(
|
||||
auto term = create_usb_terminal(config);
|
||||
return std::make_shared<DTE>(config, std::move(term));
|
||||
)
|
||||
}
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
// Copyright 2021-2022 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.
|
||||
|
||||
#pragma once
|
||||
#include "cxx_include/esp_modem_dce.hpp"
|
||||
#include "cxx_include/esp_modem_dce_module.hpp"
|
||||
|
||||
namespace esp_modem {
|
||||
/**
|
||||
* @brief Create USB DTE
|
||||
*
|
||||
* @param config DTE configuration
|
||||
* @return shared ptr to DTE on success
|
||||
* nullptr on failure (either due to insufficient memory or wrong dte configuration)
|
||||
* if exceptions are disabled the API abort()'s on error
|
||||
*/
|
||||
std::shared_ptr<DTE> create_usb_dte(const dte_config *config);
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
// Copyright 2021-2022 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.
|
||||
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/**
|
||||
* @brief USB configuration structure
|
||||
* @see USB host CDC-ACM driver documentation for details about interfaces settings
|
||||
*/
|
||||
struct esp_modem_usb_term_config {
|
||||
uint16_t vid; /*!< Vendor ID of the USB device */
|
||||
uint16_t pid; /*!< Product ID of the USB device */
|
||||
int interface_idx; /*!< USB Interface index that will be used */
|
||||
uint32_t timeout_ms; /*!< Time for a USB modem to connect to USB host. 0 means wait forever. */
|
||||
int xCoreID; /*!< Core affinity of created tasks: CDC-ACM driver task and optional USB Host task */
|
||||
bool cdc_compliant; /*!< Treat the USB device as CDC-compliant. Read CDC-ACM driver documentation for more details */
|
||||
bool install_usb_host; /*!< Flag whether USB Host driver should be installed */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief ESP Mode USB DTE Default Configuration
|
||||
*
|
||||
* @param[in] _usb_config esp_modem_usb_term_config configuration structure. Can be obtained by ESP_MODEM_DEFAULT_USB_CONFIG
|
||||
*
|
||||
*/
|
||||
#define ESP_MODEM_DTE_DEFAULT_USB_CONFIG(_usb_config) \
|
||||
{ \
|
||||
.dte_buffer_size = 512, \
|
||||
.task_stack_size = 4096, \
|
||||
.task_priority = 5, \
|
||||
.extension_config = &_usb_config \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief ESP Modem USB Default Configuration
|
||||
*
|
||||
* @param[in] _vid USB Vendor ID
|
||||
* @param[in] _pid USB Product ID
|
||||
* @see USB host CDC-ACM driver documentation for details about interfaces settings
|
||||
*/
|
||||
#define ESP_MODEM_DEFAULT_USB_CONFIG(_vid, _pid) \
|
||||
{ \
|
||||
.vid = _vid, \
|
||||
.pid = _pid, \
|
||||
.interface_idx = 0, \
|
||||
.timeout_ms = 0, \
|
||||
.xCoreID = 0, \
|
||||
.cdc_compliant = false, \
|
||||
.install_usb_host = true \
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
// Copyright 2021 Espressif Systems (Shanghai) CO 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.
|
||||
|
||||
#pragma once
|
||||
#include "cxx_include/esp_modem_dte.hpp"
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
struct esp_modem_dte_config;
|
||||
|
||||
// Copy-pasted from esp_modem/private_include/exception_stub.hpp
|
||||
#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
|
||||
#define TRY_CATCH_OR_DO(block, action) \
|
||||
try { block \
|
||||
} catch (std::bad_alloc& e) { \
|
||||
ESP_LOGE(TAG, "Out of memory"); \
|
||||
action; \
|
||||
} catch (::esp_modem::esp_err_exception& e) { \
|
||||
esp_err_t err = e.get_err_t(); \
|
||||
ESP_LOGE(TAG, "%s: Exception caught with ESP err_code=%d", __func__, err); \
|
||||
ESP_LOGE(TAG, "%s", e.what()); \
|
||||
action; \
|
||||
}
|
||||
|
||||
#define TRY_CATCH_RET_NULL(block) TRY_CATCH_OR_DO(block, return nullptr)
|
||||
#else
|
||||
|
||||
#define TRY_CATCH_OR_DO(block, action) \
|
||||
block
|
||||
|
||||
#define TRY_CATCH_RET_NULL(block) \
|
||||
block
|
||||
|
||||
#endif
|
||||
|
||||
namespace esp_modem {
|
||||
|
||||
std::unique_ptr<Terminal> create_usb_terminal(const esp_modem_dte_config *config);
|
||||
|
||||
} // namespace esp_modem
|
@ -2,5 +2,6 @@ idf_component_register(SRCS "modem_console_main.cpp"
|
||||
"console_helper.cpp"
|
||||
"httpget_handle.c"
|
||||
"ping_handle.c"
|
||||
REQUIRES console esp_http_client nvs_flash esp_modem esp_modem_usb_dte
|
||||
REQUIRES console esp_http_client nvs_flash
|
||||
INCLUDE_DIRS ".")
|
||||
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")
|
||||
|
@ -1,17 +1,172 @@
|
||||
|
||||
menu "Example Configuration"
|
||||
|
||||
choice EXAMPLE_SERIAL_CONFIG
|
||||
prompt "Type of serial connection to the modem"
|
||||
default EXAMPLE_SERIAL_CONFIG_UART
|
||||
config EXAMPLE_SERIAL_CONFIG_UART
|
||||
bool "UART"
|
||||
help
|
||||
Connect to modem via UART.
|
||||
config EXAMPLE_SERIAL_CONFIG_USB
|
||||
bool "USB"
|
||||
depends on IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
|
||||
help
|
||||
Connect to modem via USB (CDC-ACM class). For IDF version >= 4.4.
|
||||
endchoice
|
||||
endmenu
|
||||
|
||||
menu "Example Configuration"
|
||||
|
||||
choice EXAMPLE_SERIAL_CONFIG
|
||||
prompt "Type of serial connection to the modem"
|
||||
default EXAMPLE_SERIAL_CONFIG_UART
|
||||
config EXAMPLE_SERIAL_CONFIG_UART
|
||||
bool "UART"
|
||||
help
|
||||
Connect to modem via UART.
|
||||
config EXAMPLE_SERIAL_CONFIG_USB
|
||||
bool "USB"
|
||||
depends on IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
|
||||
help
|
||||
Connect to modem via USB (CDC-ACM class). For IDF version >= 4.4.
|
||||
endchoice
|
||||
|
||||
choice EXAMPLE_MODEM_DEVICE
|
||||
depends on EXAMPLE_SERIAL_CONFIG_UART
|
||||
prompt "Choose supported modem device (DCE)"
|
||||
default EXAMPLE_MODEM_DEVICE_BG96
|
||||
help
|
||||
Select modem device connected to the ESP DTE.
|
||||
config EXAMPLE_MODEM_DEVICE_SHINY
|
||||
bool "SHINY"
|
||||
help
|
||||
SHINY is a GSM/GPRS module.
|
||||
It supports SHINY.
|
||||
config EXAMPLE_MODEM_DEVICE_SIM800
|
||||
bool "SIM800"
|
||||
help
|
||||
SIMCom SIM800L is a GSM/GPRS module.
|
||||
It supports Quad-band 850/900/1800/1900MHz.
|
||||
config EXAMPLE_MODEM_DEVICE_BG96
|
||||
bool "BG96"
|
||||
help
|
||||
Quectel BG96 is a series of LTE Cat M1/Cat NB1/EGPRS module.
|
||||
config EXAMPLE_MODEM_DEVICE_SIM7000
|
||||
bool "SIM7000"
|
||||
help
|
||||
SIM7000 is a Multi-Band LTE-FDD and GSM/GPRS/EDGE module.
|
||||
config EXAMPLE_MODEM_DEVICE_SIM7070
|
||||
bool "SIM7070"
|
||||
help
|
||||
SIM7070 is Multi-Band CAT M and NB IoT module.
|
||||
config EXAMPLE_MODEM_DEVICE_SIM7600
|
||||
bool "SIM7600"
|
||||
help
|
||||
SIM7600 is a Multi-Band LTE-TDD/LTE-FDD/HSPA+ and GSM/GPRS/EDGE module.
|
||||
endchoice
|
||||
|
||||
config EXAMPLE_MODEM_PPP_APN
|
||||
string "Set MODEM APN"
|
||||
default "internet"
|
||||
help
|
||||
Set APN (Access Point Name), a logical name to choose data network
|
||||
|
||||
config EXAMPLE_MODEM_PPP_AUTH_USERNAME
|
||||
string "Set username for authentication"
|
||||
default "espressif"
|
||||
depends on !EXAMPLE_MODEM_PPP_AUTH_NONE
|
||||
help
|
||||
Set username for PPP Authentication.
|
||||
|
||||
config EXAMPLE_MODEM_PPP_AUTH_PASSWORD
|
||||
string "Set password for authentication"
|
||||
default "esp32"
|
||||
depends on !EXAMPLE_MODEM_PPP_AUTH_NONE
|
||||
help
|
||||
Set password for PPP Authentication.
|
||||
|
||||
config EXAMPLE_MODEM_PPP_AUTH_NONE
|
||||
bool "Skip PPP authentication"
|
||||
default n
|
||||
help
|
||||
Set to true for the PPP client to skip authentication
|
||||
|
||||
menu "UART Configuration"
|
||||
depends on EXAMPLE_SERIAL_CONFIG_UART
|
||||
|
||||
choice EXAMPLE_FLOW_CONTROL
|
||||
bool "Set preferred modem control flow"
|
||||
default EXAMPLE_FLOW_CONTROL_NONE
|
||||
help
|
||||
Set the modem's preferred control flow
|
||||
|
||||
config EXAMPLE_FLOW_CONTROL_NONE
|
||||
bool "No control flow"
|
||||
config EXAMPLE_FLOW_CONTROL_SW
|
||||
bool "SW control flow"
|
||||
config EXAMPLE_FLOW_CONTROL_HW
|
||||
bool "HW control flow"
|
||||
endchoice
|
||||
|
||||
config EXAMPLE_MODEM_UART_TX_PIN
|
||||
int "TXD Pin Number"
|
||||
default 25
|
||||
range 0 31
|
||||
help
|
||||
Pin number of UART TX.
|
||||
|
||||
config EXAMPLE_MODEM_UART_RX_PIN
|
||||
int "RXD Pin Number"
|
||||
default 26
|
||||
range 0 31
|
||||
help
|
||||
Pin number of UART RX.
|
||||
|
||||
config EXAMPLE_MODEM_UART_RTS_PIN
|
||||
int "RTS Pin Number"
|
||||
default 27
|
||||
range 0 31
|
||||
help
|
||||
Pin number of UART RTS.
|
||||
|
||||
config EXAMPLE_MODEM_UART_CTS_PIN
|
||||
int "CTS Pin Number"
|
||||
default 23
|
||||
range 0 31
|
||||
help
|
||||
Pin number of UART CTS.
|
||||
|
||||
config EXAMPLE_MODEM_UART_EVENT_TASK_STACK_SIZE
|
||||
int "UART Event Task Stack Size"
|
||||
range 2000 6000
|
||||
default 4096
|
||||
help
|
||||
Stack size of UART event task.
|
||||
|
||||
config EXAMPLE_MODEM_UART_EVENT_TASK_PRIORITY
|
||||
int "UART Event Task Priority"
|
||||
range 3 22
|
||||
default 5
|
||||
help
|
||||
Priority of UART event task.
|
||||
|
||||
config EXAMPLE_MODEM_UART_EVENT_QUEUE_SIZE
|
||||
int "UART Event Queue Size"
|
||||
range 10 40
|
||||
default 30
|
||||
help
|
||||
Length of UART event queue.
|
||||
|
||||
config EXAMPLE_MODEM_UART_PATTERN_QUEUE_SIZE
|
||||
int "UART Pattern Queue Size"
|
||||
range 10 40
|
||||
default 20
|
||||
help
|
||||
Length of UART pattern queue.
|
||||
|
||||
config EXAMPLE_MODEM_UART_TX_BUFFER_SIZE
|
||||
int "UART TX Buffer Size"
|
||||
range 256 2048
|
||||
default 512
|
||||
help
|
||||
Buffer size of UART TX buffer.
|
||||
|
||||
config EXAMPLE_MODEM_UART_RX_BUFFER_SIZE
|
||||
int "UART RX Buffer Size"
|
||||
range 256 2048
|
||||
default 1024
|
||||
help
|
||||
Buffer size of UART RX buffer.
|
||||
endmenu
|
||||
|
||||
config EXAMPLE_MODEM_PWRKEY_PIN
|
||||
int "PWRKEY Pin Number"
|
||||
default 18
|
||||
range 0 31
|
||||
help
|
||||
Pin number connected to modem's power key pin.
|
||||
endmenu
|
||||
|
@ -18,6 +18,16 @@ ConsoleCommand::ConsoleCommand(const char *command, const char *help, const std:
|
||||
RegisterCommand(command, help, args);
|
||||
}
|
||||
|
||||
ConsoleCommand::~ConsoleCommand()
|
||||
{
|
||||
// Find this command in static list of commands and remove it
|
||||
auto cmd = std::find(console_commands.begin(), console_commands.end(), this);
|
||||
if (cmd != console_commands.end()) {
|
||||
console_commands.erase(cmd);
|
||||
last_command--;
|
||||
}
|
||||
}
|
||||
|
||||
void ConsoleCommand::RegisterCommand(const char *command, const char *help, const std::vector<CommandArgs> &args)
|
||||
{
|
||||
assert(last_command <= MAX_REPEAT_NR);
|
||||
|
@ -92,6 +92,11 @@ public:
|
||||
*/
|
||||
explicit ConsoleCommand(const char *command, const char *help, const std::vector<CommandArgs> &args, std::function<bool(ConsoleCommand *)> f);
|
||||
|
||||
/**
|
||||
* @brief Destructor of ConsoleCommand
|
||||
*/
|
||||
~ConsoleCommand();
|
||||
|
||||
/**
|
||||
* @brief Utility getters of various params from the argument list
|
||||
*/
|
||||
|
@ -0,0 +1,12 @@
|
||||
## IDF Component Manager Manifest File
|
||||
dependencies:
|
||||
## Required IDF version
|
||||
idf: ">=4.1.0"
|
||||
espressif/esp_modem:
|
||||
version: "^0.1.20"
|
||||
override_path: "../../../"
|
||||
espressif/esp_modem_usb_dte:
|
||||
version: "^1.0.0"
|
||||
rules:
|
||||
- if: "idf_version >=4.4"
|
||||
- if: "target in [esp32s2, esp32s3]"
|
@ -15,10 +15,12 @@
|
||||
#include "esp_console.h"
|
||||
#include "esp_event.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "esp_sleep.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "cxx_include/esp_modem_dte.hpp"
|
||||
#include "esp_modem_config.h"
|
||||
#include "cxx_include/esp_modem_api.hpp"
|
||||
#if defined(CONFIG_USB_OTG_SUPPORTED)
|
||||
#if defined(CONFIG_EXAMPLE_SERIAL_CONFIG_USB)
|
||||
#include "esp_modem_usb_config.h"
|
||||
#include "cxx_include/esp_modem_usb_api.hpp"
|
||||
#endif
|
||||
@ -26,6 +28,14 @@
|
||||
#include "console_helper.hpp"
|
||||
#include "my_module_dce.hpp"
|
||||
|
||||
#if defined(CONFIG_EXAMPLE_FLOW_CONTROL_NONE)
|
||||
#define EXAMPLE_FLOW_CONTROL ESP_MODEM_FLOW_CONTROL_NONE
|
||||
#elif defined(CONFIG_EXAMPLE_FLOW_CONTROL_SW)
|
||||
#define EXAMPLE_FLOW_CONTROL ESP_MODEM_FLOW_CONTROL_SW
|
||||
#elif defined(CONFIG_EXAMPLE_FLOW_CONTROL_HW)
|
||||
#define EXAMPLE_FLOW_CONTROL ESP_MODEM_FLOW_CONTROL_HW
|
||||
#endif
|
||||
|
||||
#define CHECK_ERR(cmd, success_action) do { \
|
||||
auto err = cmd; \
|
||||
if (err == command_result::OK) { \
|
||||
@ -33,7 +43,7 @@
|
||||
return 0; \
|
||||
} else { \
|
||||
ESP_LOGE(TAG, "Failed with %s", err == command_result::TIMEOUT ? "TIMEOUT":"ERROR"); \
|
||||
return 1; \
|
||||
return 1; \
|
||||
} } while (0)
|
||||
|
||||
/**
|
||||
@ -41,6 +51,9 @@
|
||||
*/
|
||||
#define DEFAULT_APN "my_apn"
|
||||
|
||||
#define GPIO_OUTPUT_PWRKEY (gpio_num_t)CONFIG_EXAMPLE_MODEM_PWRKEY_PIN
|
||||
#define GPIO_OUTPUT_PIN_SEL (1ULL<<GPIO_OUTPUT_PWRKEY)
|
||||
|
||||
extern "C" void modem_console_register_http(void);
|
||||
extern "C" void modem_console_register_ping(void);
|
||||
|
||||
@ -48,10 +61,40 @@ static const char *TAG = "modem_console";
|
||||
static esp_console_repl_t *s_repl = nullptr;
|
||||
|
||||
using namespace esp_modem;
|
||||
static SignalGroup exit_signal;
|
||||
|
||||
|
||||
void config_gpio(void)
|
||||
{
|
||||
gpio_config_t io_conf = {}; //zero-initialize the config structure.
|
||||
|
||||
io_conf.intr_type = GPIO_INTR_DISABLE; //disable interrupt
|
||||
io_conf.mode = GPIO_MODE_OUTPUT; //set as output mode
|
||||
io_conf.pin_bit_mask = GPIO_OUTPUT_PIN_SEL; //bit mask of the pins that you want to set,e.g.GPIO18/19
|
||||
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE; //disable pull-down mode
|
||||
io_conf.pull_up_en = GPIO_PULLUP_DISABLE; //disable pull-up mode
|
||||
|
||||
gpio_config(&io_conf); //configure GPIO with the given settings
|
||||
}
|
||||
|
||||
void wakeup_modem(void)
|
||||
{
|
||||
/* Power on the modem */
|
||||
ESP_LOGI(TAG, "Power on the modem");
|
||||
gpio_set_level(GPIO_OUTPUT_PWRKEY, 1);
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
gpio_set_level(GPIO_OUTPUT_PWRKEY, 0);
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(2000));
|
||||
}
|
||||
|
||||
extern "C" void app_main(void)
|
||||
{
|
||||
static RTC_RODATA_ATTR char apn_rtc[20] = DEFAULT_APN;
|
||||
static RTC_DATA_ATTR modem_mode mode_rtc = esp_modem::modem_mode::COMMAND_MODE;
|
||||
|
||||
config_gpio();
|
||||
|
||||
ESP_ERROR_CHECK(nvs_flash_init());
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
@ -64,29 +107,98 @@ extern "C" void app_main(void)
|
||||
|
||||
#if defined(CONFIG_EXAMPLE_SERIAL_CONFIG_UART)
|
||||
esp_modem_dte_config_t dte_config = ESP_MODEM_DTE_DEFAULT_CONFIG();
|
||||
/* setup UART specific configuration based on kconfig options */
|
||||
dte_config.uart_config.tx_io_num = CONFIG_EXAMPLE_MODEM_UART_TX_PIN;
|
||||
dte_config.uart_config.rx_io_num = CONFIG_EXAMPLE_MODEM_UART_RX_PIN;
|
||||
dte_config.uart_config.rts_io_num = CONFIG_EXAMPLE_MODEM_UART_RTS_PIN;
|
||||
dte_config.uart_config.cts_io_num = CONFIG_EXAMPLE_MODEM_UART_CTS_PIN;
|
||||
dte_config.uart_config.flow_control = EXAMPLE_FLOW_CONTROL;
|
||||
dte_config.uart_config.rx_buffer_size = CONFIG_EXAMPLE_MODEM_UART_RX_BUFFER_SIZE;
|
||||
dte_config.uart_config.tx_buffer_size = CONFIG_EXAMPLE_MODEM_UART_TX_BUFFER_SIZE;
|
||||
dte_config.uart_config.event_queue_size = CONFIG_EXAMPLE_MODEM_UART_EVENT_QUEUE_SIZE;
|
||||
dte_config.task_stack_size = CONFIG_EXAMPLE_MODEM_UART_EVENT_TASK_STACK_SIZE;
|
||||
dte_config.task_priority = CONFIG_EXAMPLE_MODEM_UART_EVENT_TASK_PRIORITY;
|
||||
dte_config.dte_buffer_size = CONFIG_EXAMPLE_MODEM_UART_RX_BUFFER_SIZE / 2;
|
||||
auto uart_dte = create_uart_dte(&dte_config);
|
||||
|
||||
#if CONFIG_EXAMPLE_MODEM_DEVICE_SHINY == 1
|
||||
ESP_LOGI(TAG, "Initializing esp_modem for the SHINY module...");
|
||||
auto dce = create_shiny_dce(&dce_config, uart_dte, esp_netif);
|
||||
#elif CONFIG_EXAMPLE_MODEM_DEVICE_BG96 == 1
|
||||
ESP_LOGI(TAG, "Initializing esp_modem for the BG96 module...");
|
||||
auto dce = create_BG96_dce(&dce_config, uart_dte, esp_netif);
|
||||
#elif CONFIG_EXAMPLE_MODEM_DEVICE_SIM800 == 1
|
||||
ESP_LOGI(TAG, "Initializing esp_modem for the SIM800 module...");
|
||||
auto dce = create_SIM800_dce(&dce_config, uart_dte, esp_netif);
|
||||
#elif CONFIG_EXAMPLE_MODEM_DEVICE_SIM7000 == 1
|
||||
ESP_LOGI(TAG, "Initializing esp_modem for the SIM7000 module...");
|
||||
auto dce = create_SIM7000_dce(&dce_config, uart_dte, esp_netif);
|
||||
#elif CONFIG_EXAMPLE_MODEM_DEVICE_SIM7070 == 1
|
||||
ESP_LOGI(TAG, "Initializing esp_modem for the SIM7070 module...");
|
||||
auto dce = create_SIM7070_dce(&dce_config, uart_dte, esp_netif);
|
||||
#elif CONFIG_EXAMPLE_MODEM_DEVICE_SIM7600 == 1
|
||||
ESP_LOGI(TAG, "Initializing esp_modem for the SIM7600 module...");
|
||||
auto dce = create_SIM7600_dce(&dce_config, uart_dte, esp_netif);
|
||||
#else
|
||||
ESP_LOGI(TAG, "Initializing esp_modem for a generic module...");
|
||||
auto dce = create_generic_dce(&dce_config, uart_dte, esp_netif);
|
||||
#endif
|
||||
|
||||
|
||||
#elif defined(CONFIG_EXAMPLE_SERIAL_CONFIG_USB)
|
||||
struct esp_modem_usb_term_config usb_config = ESP_MODEM_DEFAULT_USB_CONFIG(0x2C7C, 0x0296); // VID and PID of BG96 modem
|
||||
// BG96 modem implements Vendor Specific class, that is CDC-ACM like. Interface for AT commands has index no. 2.
|
||||
usb_config.interface_idx = 2;
|
||||
esp_modem_dte_config_t dte_config = ESP_MODEM_DTE_DEFAULT_USB_CONFIG(usb_config);
|
||||
ESP_LOGI(TAG, "Waiting for USB device connection...");
|
||||
auto dte = create_usb_dte(&dte_config);
|
||||
std::unique_ptr<DCE> dce = create_BG96_dce(&dce_config, dte, esp_netif);
|
||||
while (1) {
|
||||
exit_signal.clear(1);
|
||||
struct esp_modem_usb_term_config usb_config = ESP_MODEM_DEFAULT_USB_CONFIG(0x2C7C, 0x0296, 2); // VID, PID and interface num of BG96 modem
|
||||
const esp_modem_dte_config_t dte_config = ESP_MODEM_DTE_DEFAULT_USB_CONFIG(usb_config);
|
||||
ESP_LOGI(TAG, "Waiting for USB device connection...");
|
||||
auto dte = create_usb_dte(&dte_config);
|
||||
dte->set_error_cb([&](terminal_error err) {
|
||||
ESP_LOGI(TAG, "error handler %d", err);
|
||||
if (err == terminal_error::DEVICE_GONE) {
|
||||
exit_signal.set(1);
|
||||
}
|
||||
});
|
||||
std::unique_ptr<DCE> dce = create_BG96_dce(&dce_config, dte, esp_netif);
|
||||
|
||||
#else
|
||||
#error Invalid serial connection to modem.
|
||||
#endif
|
||||
|
||||
|
||||
assert(dce != nullptr);
|
||||
|
||||
if (dte_config.uart_config.flow_control == ESP_MODEM_FLOW_CONTROL_HW) {
|
||||
if (command_result::OK != dce->set_flow_control(2, 2)) {
|
||||
ESP_LOGE(TAG, "Failed to set the set_flow_control mode");
|
||||
return;
|
||||
}
|
||||
ESP_LOGI(TAG, "set_flow_control OK");
|
||||
}
|
||||
|
||||
// init console REPL environment
|
||||
esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT();
|
||||
esp_console_dev_uart_config_t uart_config = ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT();
|
||||
ESP_ERROR_CHECK(esp_console_new_repl_uart(&uart_config, &repl_config, &s_repl));
|
||||
|
||||
switch (esp_sleep_get_wakeup_cause()) {
|
||||
case ESP_SLEEP_WAKEUP_TIMER:
|
||||
if (esp_modem::modem_mode::CMUX_MODE == mode_rtc) {
|
||||
ESP_LOGI(TAG, "Deep sleep reset\n");
|
||||
|
||||
/* Set APN */
|
||||
auto new_pdp = std::unique_ptr<PdpContext>(new PdpContext(apn_rtc));
|
||||
dce->get_module()->configure_pdp_context(std::move(new_pdp));
|
||||
|
||||
/* Set CMUX mode */
|
||||
if (!dce->set_mode(mode_rtc)) {
|
||||
ESP_LOGE(TAG, "Failed to set the desired mode");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ESP_SLEEP_WAKEUP_UNDEFINED:
|
||||
default:
|
||||
ESP_LOGD(TAG, "Not a deep sleep reset\n");
|
||||
}
|
||||
|
||||
modem_console_register_http();
|
||||
modem_console_register_ping();
|
||||
const struct SetModeArgs {
|
||||
@ -102,7 +214,10 @@ extern "C" void app_main(void)
|
||||
} else if (mode == "PPP") {
|
||||
dev_mode = esp_modem::modem_mode::DATA_MODE;
|
||||
} else if (mode == "CMUX") {
|
||||
/* Even if switching to CMUX fails, we make the DTE multiplex terminal.
|
||||
(This is potentially a bug and might be fixed eventually) */
|
||||
dev_mode = esp_modem::modem_mode::CMUX_MODE;
|
||||
mode_rtc = dev_mode;
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Unsupported mode: %s", mode.c_str());
|
||||
return 1;
|
||||
@ -112,6 +227,8 @@ extern "C" void app_main(void)
|
||||
ESP_LOGE(TAG, "Failed to set the desired mode");
|
||||
return 1;
|
||||
}
|
||||
mode_rtc = dev_mode;
|
||||
|
||||
ESP_LOGI(TAG, "OK");
|
||||
}
|
||||
return 0;
|
||||
@ -219,6 +336,7 @@ extern "C" void app_main(void)
|
||||
if (c->get_count_of(&SetApn::apn)) {
|
||||
auto apn = c->get_string_of(&SetApn::apn);
|
||||
ESP_LOGI(TAG, "Setting the APN=%s...", apn.c_str());
|
||||
strcpy(apn_rtc, apn.c_str());
|
||||
auto new_pdp = std::unique_ptr<PdpContext>(new PdpContext(apn));
|
||||
dce->get_module()->configure_pdp_context(std::move(new_pdp));
|
||||
ESP_LOGI(TAG, "OK");
|
||||
@ -226,16 +344,96 @@ extern "C" void app_main(void)
|
||||
return 0;
|
||||
});
|
||||
|
||||
SignalGroup exit_signal;
|
||||
const ConsoleCommand ExitConsole("exit", "exit the console application", no_args, [&](ConsoleCommand * c) {
|
||||
ESP_LOGI(TAG, "Exiting...");
|
||||
exit_signal.set(1);
|
||||
s_repl->del(s_repl);
|
||||
return 0;
|
||||
});
|
||||
|
||||
/* Put the esp32 into deep sleep */
|
||||
const struct DeepSleepArgs {
|
||||
DeepSleepArgs(): timeout(INT1, nullptr, nullptr, "<tout>", "TIMEOUT") {}
|
||||
CommandArgs timeout;
|
||||
} deep_sleep_args;
|
||||
const ConsoleCommand SetDeepSleep("set_deep_sleep", "Put esp32 to deep sleep", &deep_sleep_args, sizeof(deep_sleep_args), [&](ConsoleCommand * c) {
|
||||
int tout = c->get_int_of(&DeepSleepArgs::timeout);
|
||||
ESP_LOGI(TAG, "Entering deep sleep for %d sec", tout);
|
||||
ESP_LOGI(TAG, "Wakeup Cause: %d ", esp_sleep_get_wakeup_cause());
|
||||
esp_deep_sleep(tout * 1000000);
|
||||
return 0;
|
||||
});
|
||||
|
||||
/* Wake up modem */
|
||||
const ConsoleCommand WakeupModem("wakeup_modem", "Wakes up the modem from PSM", no_args, [&](ConsoleCommand * c) {
|
||||
wakeup_modem();
|
||||
ESP_LOGI(TAG, "OK");
|
||||
return 0;
|
||||
});
|
||||
|
||||
/* Enable PSM modem */
|
||||
const ConsoleCommand EnablePSM("enable_psm", "Enables PSM on the modem", no_args, [&](ConsoleCommand * c) {
|
||||
std::string out;
|
||||
CHECK_ERR(dce->at("AT+CPSMS=1", out, 500), ESP_LOGI(TAG, "OK. %s", out.c_str()));
|
||||
return 0;
|
||||
});
|
||||
|
||||
/* Disable PSM modem */
|
||||
const ConsoleCommand DisablePSM("disable_psm", "Disables PSM on the modem", no_args, [&](ConsoleCommand * c) {
|
||||
std::string out;
|
||||
CHECK_ERR(dce->at("AT+CPSMS=0", out, 500), ESP_LOGI(TAG, "OK. %s", out.c_str()));
|
||||
return 0;
|
||||
});
|
||||
|
||||
/* Get modem PSM cfg */
|
||||
const ConsoleCommand GetModemCfg("get_psm_cfg", "Get PSM config", no_args, [&](ConsoleCommand * c) {
|
||||
std::string out;
|
||||
CHECK_ERR(dce->at("AT+CPSMS?", out, 500), ESP_LOGI(TAG, "OK. %s", out.c_str()));
|
||||
return 0;
|
||||
});
|
||||
|
||||
/* Set modem PSM config */
|
||||
const struct SetPsmCfgArgs {
|
||||
SetPsmCfgArgs():
|
||||
periodic_tau(STR1, nullptr, nullptr, "<Requested_Periodic-TAU>", "T3412 Timer in 8-bit format"),
|
||||
active_time(STR0, nullptr, nullptr, "<Requested_Active-Time>", "T3324 Timer in 8-bit format") {}
|
||||
CommandArgs periodic_tau;
|
||||
CommandArgs active_time;
|
||||
} set_psm_cfg_args;
|
||||
const ConsoleCommand SetPsmCfg("set_psm_cfg", "Set PSM config", &set_psm_cfg_args, sizeof(set_psm_cfg_args), [&](ConsoleCommand * c) {
|
||||
std::string out;
|
||||
auto periodic_tau = c->get_string_of(&SetPsmCfgArgs::periodic_tau);
|
||||
auto active_time = c->get_string_of(&SetPsmCfgArgs::active_time);
|
||||
|
||||
/* Validate input */
|
||||
if ((strlen(periodic_tau.c_str()) != strlen("00000000")) ||
|
||||
(strlen(active_time.c_str()) != strlen("00000000"))) {
|
||||
ESP_LOGE(TAG, "Failed with ERROR: Invalid argument length");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Get PSM config */
|
||||
dce->at("AT+CPSMS?", out, 500);
|
||||
|
||||
/* Update PSM config */
|
||||
if (out.size() > 8) {
|
||||
std::string set_cmd = "AT+CPSMS=" + std::to_string(out.c_str()[8] - '0') + ",,,\"" + periodic_tau.c_str() + "\",\"" + active_time.c_str() + "\"";
|
||||
CHECK_ERR(dce->at(set_cmd, out, 500), ESP_LOGI(TAG, "OK. %s", out.c_str()));
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Failed with ERROR: Invalid AT+CPSMS? return length");
|
||||
}
|
||||
|
||||
return 0;
|
||||
});
|
||||
|
||||
|
||||
// start console REPL
|
||||
ESP_ERROR_CHECK(esp_console_start_repl(s_repl));
|
||||
// wait for exit
|
||||
exit_signal.wait_any(1, UINT32_MAX);
|
||||
s_repl->del(s_repl);
|
||||
ESP_LOGI(TAG, "Exiting...%d", esp_get_free_heap_size());
|
||||
#if defined(CONFIG_EXAMPLE_SERIAL_CONFIG_USB)
|
||||
// USB example runs in a loop to demonstrate hot-plugging and sudden disconnection features.
|
||||
} // while (1)
|
||||
#endif
|
||||
}
|
||||
|
@ -0,0 +1 @@
|
||||
CONFIG_EXAMPLE_SERIAL_CONFIG_USB=y
|
@ -1,8 +1,7 @@
|
||||
# Override some defaults to enable PPP
|
||||
# This file was generated using idf.py save-defconfig. It can be edited manually.
|
||||
# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration
|
||||
#
|
||||
CONFIG_ESP_MAIN_TASK_STACK_SIZE=7168
|
||||
CONFIG_LWIP_PPP_SUPPORT=y
|
||||
# CONFIG_LWIP_PPP_ENABLE_IPV6 is not set
|
||||
CONFIG_LWIP_PPP_PAP_SUPPORT=y
|
||||
CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=4096
|
||||
# Do not enable IPV6 in dte<->dce link local
|
||||
CONFIG_LWIP_PPP_ENABLE_IPV6=n
|
||||
# Disable legacy API
|
||||
CONFIG_MODEM_LEGACY_API=n
|
||||
|
@ -9,6 +9,18 @@ This example shows how to act as a MQTT client after the PPPoS channel created b
|
||||
|
||||
See the README.md file in the upper level `pppos` directory for more information about the PPPoS examples.
|
||||
|
||||
### USB DTE support
|
||||
|
||||
For USB enabled targets (ESP32-S2 and ESP32-S3), it is possible to connect to the modem device via USB.
|
||||
1. In menuconfig, navigate to `Example Configuration->Type of serial connection to the modem` and choose `USB`.
|
||||
2. Connect the modem USB signals to pin 19 (DATA-) and 20 (DATA+) on your ESP chip.
|
||||
|
||||
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.
|
||||
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`.
|
@ -1,2 +1,3 @@
|
||||
idf_component_register(SRCS "pppos_client_main.c"
|
||||
INCLUDE_DIRS ".")
|
||||
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")
|
||||
|
@ -1,6 +1,21 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
choice EXAMPLE_SERIAL_CONFIG
|
||||
prompt "Type of serial connection to the modem"
|
||||
default EXAMPLE_SERIAL_CONFIG_UART
|
||||
config EXAMPLE_SERIAL_CONFIG_UART
|
||||
bool "UART"
|
||||
help
|
||||
Connect to modem via UART.
|
||||
config EXAMPLE_SERIAL_CONFIG_USB
|
||||
bool "USB"
|
||||
depends on IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
|
||||
help
|
||||
Connect to modem via USB (CDC-ACM class). For IDF version >= 4.4.
|
||||
endchoice
|
||||
|
||||
choice EXAMPLE_MODEM_DEVICE
|
||||
depends on EXAMPLE_SERIAL_CONFIG_UART
|
||||
prompt "Choose supported modem device (DCE)"
|
||||
default EXAMPLE_MODEM_DEVICE_BG96
|
||||
help
|
||||
@ -74,6 +89,7 @@ menu "Example Configuration"
|
||||
Pin to unlock the SIM
|
||||
|
||||
menu "UART Configuration"
|
||||
depends on EXAMPLE_SERIAL_CONFIG_UART
|
||||
config EXAMPLE_MODEM_UART_TX_PIN
|
||||
int "TXD Pin Number"
|
||||
default 25
|
||||
|
@ -0,0 +1,12 @@
|
||||
## IDF Component Manager Manifest File
|
||||
dependencies:
|
||||
## Required IDF version
|
||||
idf: ">=4.1.0"
|
||||
espressif/esp_modem:
|
||||
version: "^0.1.23"
|
||||
override_path: "../../../"
|
||||
espressif/esp_modem_usb_dte:
|
||||
version: "^1.0.0"
|
||||
rules:
|
||||
- if: "idf_version >=4.4"
|
||||
- if: "target in [esp32s2, esp32s3]"
|
@ -14,6 +14,7 @@
|
||||
#include "mqtt_client.h"
|
||||
#include "esp_modem_api.h"
|
||||
#include "esp_log.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#define BROKER_URL "mqtt://mqtt.eclipseprojects.io"
|
||||
|
||||
@ -21,12 +22,36 @@ static const char *TAG = "pppos_example";
|
||||
static EventGroupHandle_t event_group = NULL;
|
||||
static const int CONNECT_BIT = BIT0;
|
||||
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
|
||||
|
||||
static esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t event)
|
||||
#if defined(CONFIG_EXAMPLE_SERIAL_CONFIG_USB)
|
||||
#include "esp_modem_usb_c_api.h"
|
||||
#include "esp_modem_usb_config.h"
|
||||
#include "freertos/task.h"
|
||||
static void usb_terminal_error_handler(esp_modem_terminal_error_t err)
|
||||
{
|
||||
if (err == ESP_MODEM_TERMINAL_DEVICE_GONE) {
|
||||
ESP_LOGI(TAG, "USB modem disconnected");
|
||||
assert(event_group);
|
||||
xEventGroupSetBits(event_group, USB_DISCONNECTED_BIT);
|
||||
}
|
||||
}
|
||||
#define CHECK_USB_DISCONNECTION(event_group) \
|
||||
if ((xEventGroupGetBits(event_group) & USB_DISCONNECTED_BIT) == USB_DISCONNECTED_BIT) { \
|
||||
esp_modem_destroy(dce); \
|
||||
continue; \
|
||||
}
|
||||
#else
|
||||
#define CHECK_USB_DISCONNECTION(event_group)
|
||||
#endif
|
||||
|
||||
static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
|
||||
{
|
||||
ESP_LOGD(TAG, "Event dispatched from event loop base=%s, event_id=%d", base, event_id);
|
||||
esp_mqtt_event_handle_t event = event_data;
|
||||
esp_mqtt_client_handle_t client = event->client;
|
||||
int msg_id;
|
||||
switch (event->event_id) {
|
||||
switch ((esp_mqtt_event_id_t)event_id) {
|
||||
case MQTT_EVENT_CONNECTED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
|
||||
msg_id = esp_mqtt_client_subscribe(client, "/topic/esp-pppos", 0);
|
||||
@ -59,7 +84,6 @@ static esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t event)
|
||||
ESP_LOGI(TAG, "MQTT other event id: %d", event->event_id);
|
||||
break;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void on_ppp_changed(void *arg, esp_event_base_t event_base,
|
||||
@ -110,16 +134,22 @@ static void on_ip_event(void *arg, esp_event_base_t event_base,
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
|
||||
/* Init and register system/core components */
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, ESP_EVENT_ANY_ID, &on_ip_event, NULL));
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(NETIF_PPP_STATUS, ESP_EVENT_ANY_ID, &on_ppp_changed, NULL));
|
||||
|
||||
/* Configure the PPP netif */
|
||||
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);
|
||||
assert(esp_netif);
|
||||
|
||||
event_group = xEventGroupCreate();
|
||||
|
||||
/* Configure the DTE */
|
||||
#if defined(CONFIG_EXAMPLE_SERIAL_CONFIG_UART)
|
||||
esp_modem_dte_config_t dte_config = ESP_MODEM_DTE_DEFAULT_CONFIG();
|
||||
/* setup UART specific configuration based on kconfig options */
|
||||
dte_config.uart_config.tx_io_num = CONFIG_EXAMPLE_MODEM_UART_TX_PIN;
|
||||
@ -133,17 +163,6 @@ void app_main(void)
|
||||
dte_config.task_priority = CONFIG_EXAMPLE_MODEM_UART_EVENT_TASK_PRIORITY;
|
||||
dte_config.dte_buffer_size = CONFIG_EXAMPLE_MODEM_UART_RX_BUFFER_SIZE / 2;
|
||||
|
||||
/* Configure the DCE */
|
||||
esp_modem_dce_config_t dce_config = ESP_MODEM_DCE_DEFAULT_CONFIG(CONFIG_EXAMPLE_MODEM_PPP_APN);
|
||||
|
||||
/* Configure the PPP netif */
|
||||
esp_netif_config_t netif_ppp_config = ESP_NETIF_DEFAULT_PPP();
|
||||
|
||||
/* Run the modem demo app */
|
||||
// Init netif object
|
||||
esp_netif_t *esp_netif = esp_netif_new(&netif_ppp_config);
|
||||
assert(esp_netif);
|
||||
|
||||
#if CONFIG_EXAMPLE_MODEM_DEVICE_BG96 == 1
|
||||
ESP_LOGI(TAG, "Initializing esp_modem for the BG96 module...");
|
||||
esp_modem_dce_t *dce = esp_modem_new_dev(ESP_MODEM_DCE_BG96, &dte_config, &dce_config, esp_netif);
|
||||
@ -157,8 +176,24 @@ void app_main(void)
|
||||
ESP_LOGI(TAG, "Initializing esp_modem for a generic module...");
|
||||
esp_modem_dce_t *dce = esp_modem_new(&dte_config, &dce_config, esp_netif);
|
||||
#endif
|
||||
assert(dce);
|
||||
|
||||
#elif defined(CONFIG_EXAMPLE_SERIAL_CONFIG_USB)
|
||||
while (1) {
|
||||
ESP_LOGI(TAG, "Initializing esp_modem for the BG96 module...");
|
||||
struct esp_modem_usb_term_config usb_config = ESP_MODEM_DEFAULT_USB_CONFIG(0x2C7C, 0x0296, 2); // VID, PID and interface num of BG96 modem
|
||||
const esp_modem_dte_config_t dte_usb_config = ESP_MODEM_DTE_DEFAULT_USB_CONFIG(usb_config);
|
||||
ESP_LOGI(TAG, "Waiting for USB device connection...");
|
||||
esp_modem_dce_t *dce = esp_modem_new_dev_usb(ESP_MODEM_DCE_BG96, &dte_usb_config, &dce_config, esp_netif);
|
||||
esp_modem_set_error_cb(dce, usb_terminal_error_handler);
|
||||
vTaskDelay(pdMS_TO_TICKS(1000)); // Although the DTE should be ready after USB enumeration, sometimes it fails to respond without this delay
|
||||
|
||||
#else
|
||||
#error Invalid serial connection to modem.
|
||||
#endif
|
||||
assert(dce);
|
||||
xEventGroupClearBits(event_group, CONNECT_BIT | GOT_DATA_BIT | USB_DISCONNECTED_BIT);
|
||||
|
||||
/* Run the modem demo app */
|
||||
#if CONFIG_EXAMPLE_NEED_SIM_PIN == 1
|
||||
// check if PIN needed
|
||||
bool pin_ok = false;
|
||||
@ -198,15 +233,27 @@ void app_main(void)
|
||||
return;
|
||||
}
|
||||
/* Wait for IP address */
|
||||
xEventGroupWaitBits(event_group, CONNECT_BIT, pdTRUE, pdTRUE, portMAX_DELAY);
|
||||
ESP_LOGI(TAG, "Waiting for IP address");
|
||||
xEventGroupWaitBits(event_group, CONNECT_BIT | USB_DISCONNECTED_BIT, pdFALSE, pdFALSE, portMAX_DELAY);
|
||||
CHECK_USB_DISCONNECTION(event_group);
|
||||
|
||||
/* Config MQTT */
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
|
||||
esp_mqtt_client_config_t mqtt_config = {
|
||||
.broker.address.uri = BROKER_URL,
|
||||
};
|
||||
#else
|
||||
esp_mqtt_client_config_t mqtt_config = {
|
||||
.uri = BROKER_URL,
|
||||
.event_handle = mqtt_event_handler,
|
||||
};
|
||||
#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);
|
||||
xEventGroupWaitBits(event_group, GOT_DATA_BIT, pdTRUE, pdTRUE, portMAX_DELAY);
|
||||
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);
|
||||
|
||||
esp_mqtt_client_destroy(mqtt_client);
|
||||
err = esp_modem_set_mode(dce, ESP_MODEM_MODE_COMMAND);
|
||||
if (err != ESP_OK) {
|
||||
@ -221,6 +268,15 @@ void app_main(void)
|
||||
}
|
||||
ESP_LOGI(TAG, "IMSI=%s", imsi);
|
||||
|
||||
#if defined(CONFIG_EXAMPLE_SERIAL_CONFIG_USB)
|
||||
// USB example runs in a loop to demonstrate hot-plugging and sudden disconnection features.
|
||||
ESP_LOGI(TAG, "USB demo finished. Disconnect and connect the modem to run it again");
|
||||
xEventGroupWaitBits(event_group, USB_DISCONNECTED_BIT, pdFALSE, pdFALSE, portMAX_DELAY);
|
||||
CHECK_USB_DISCONNECTION(event_group); // dce will be destroyed here
|
||||
} // while (1)
|
||||
#else
|
||||
// UART DTE clean-up
|
||||
esp_modem_destroy(dce);
|
||||
esp_netif_destroy(esp_netif);
|
||||
#endif
|
||||
}
|
||||
|
@ -0,0 +1 @@
|
||||
CONFIG_EXAMPLE_SERIAL_CONFIG_USB=y
|
@ -14,6 +14,14 @@ menu "Example Configuration"
|
||||
bool "BG96"
|
||||
help
|
||||
Quectel BG96 is a series of LTE Cat M1/Cat NB1/EGPRS module.
|
||||
config EXAMPLE_MODEM_DEVICE_SIM7000
|
||||
bool "SIM7000"
|
||||
help
|
||||
SIM7000 is a Multi-Band LTE-FDD and GSM/GPRS/EDGE module.
|
||||
config EXAMPLE_MODEM_DEVICE_SIM7070
|
||||
bool "SIM7070"
|
||||
help
|
||||
SIM7070 is Multi-Band CAT M and NB IoT module.
|
||||
config EXAMPLE_MODEM_DEVICE_SIM7600
|
||||
bool "SIM7600"
|
||||
help
|
||||
@ -39,6 +47,50 @@ menu "Example Configuration"
|
||||
help
|
||||
Pin to unlock the SIM
|
||||
|
||||
choice EXAMPLE_FLOW_CONTROL
|
||||
bool "Set preferred modem control flow"
|
||||
default EXAMPLE_FLOW_CONTROL_NONE
|
||||
help
|
||||
Set the modem's preferred control flow
|
||||
|
||||
config EXAMPLE_FLOW_CONTROL_NONE
|
||||
bool "No control flow"
|
||||
config EXAMPLE_FLOW_CONTROL_SW
|
||||
bool "SW control flow"
|
||||
config EXAMPLE_FLOW_CONTROL_HW
|
||||
bool "HW control flow"
|
||||
endchoice
|
||||
|
||||
menu "UART Configuration"
|
||||
config EXAMPLE_MODEM_UART_TX_PIN
|
||||
int "TXD Pin Number"
|
||||
default 25
|
||||
range 0 31
|
||||
help
|
||||
Pin number of UART TX.
|
||||
|
||||
config EXAMPLE_MODEM_UART_RX_PIN
|
||||
int "RXD Pin Number"
|
||||
default 26
|
||||
range 0 31
|
||||
help
|
||||
Pin number of UART RX.
|
||||
|
||||
config EXAMPLE_MODEM_UART_RTS_PIN
|
||||
int "RTS Pin Number"
|
||||
default 27
|
||||
range 0 31
|
||||
help
|
||||
Pin number of UART RTS.
|
||||
|
||||
config EXAMPLE_MODEM_UART_CTS_PIN
|
||||
int "CTS Pin Number"
|
||||
default 23
|
||||
range 0 31
|
||||
help
|
||||
Pin number of UART CTS.
|
||||
endmenu
|
||||
|
||||
config EXAMPLE_USE_VFS_TERM
|
||||
bool "Use VFS terminal"
|
||||
default n
|
||||
@ -61,4 +113,10 @@ menu "Example Configuration"
|
||||
help
|
||||
HTTPS address of the update binary.
|
||||
|
||||
config EXAMPLE_CLOSE_CMUX_AT_END
|
||||
bool "Close multiplexed mode at the end of the example"
|
||||
default n
|
||||
help
|
||||
Close the multiplexed mode at the end of the example and rollback to command mode.
|
||||
|
||||
endmenu
|
||||
|
@ -21,6 +21,14 @@
|
||||
#include "esp_https_ota.h" // For potential OTA configuration
|
||||
#include "vfs_resource/vfs_create.hpp"
|
||||
|
||||
#if defined(CONFIG_EXAMPLE_FLOW_CONTROL_NONE)
|
||||
#define EXAMPLE_FLOW_CONTROL ESP_MODEM_FLOW_CONTROL_NONE
|
||||
#elif defined(CONFIG_EXAMPLE_FLOW_CONTROL_SW)
|
||||
#define EXAMPLE_FLOW_CONTROL ESP_MODEM_FLOW_CONTROL_SW
|
||||
#elif defined(CONFIG_EXAMPLE_FLOW_CONTROL_HW)
|
||||
#define EXAMPLE_FLOW_CONTROL ESP_MODEM_FLOW_CONTROL_HW
|
||||
#endif
|
||||
|
||||
#define BROKER_URL "mqtt://mqtt.eclipseprojects.io"
|
||||
|
||||
|
||||
@ -39,6 +47,12 @@ extern "C" void app_main(void)
|
||||
|
||||
/* Configure and create the DTE */
|
||||
esp_modem_dte_config_t dte_config = ESP_MODEM_DTE_DEFAULT_CONFIG();
|
||||
/* setup UART specific configuration based on kconfig options */
|
||||
dte_config.uart_config.tx_io_num = CONFIG_EXAMPLE_MODEM_UART_TX_PIN;
|
||||
dte_config.uart_config.rx_io_num = CONFIG_EXAMPLE_MODEM_UART_RX_PIN;
|
||||
dte_config.uart_config.rts_io_num = CONFIG_EXAMPLE_MODEM_UART_RTS_PIN;
|
||||
dte_config.uart_config.cts_io_num = CONFIG_EXAMPLE_MODEM_UART_CTS_PIN;
|
||||
dte_config.uart_config.flow_control = EXAMPLE_FLOW_CONTROL;
|
||||
#if CONFIG_EXAMPLE_USE_VFS_TERM == 1
|
||||
/* The VFS terminal is just a demonstration of using an abstract file descriptor
|
||||
* which implements non-block reads, writes and selects to communicate with esp-modem.
|
||||
@ -71,6 +85,10 @@ extern "C" void app_main(void)
|
||||
std::unique_ptr<DCE> dce = create_BG96_dce(&dce_config, dte, esp_netif);
|
||||
#elif CONFIG_EXAMPLE_MODEM_DEVICE_SIM800 == 1
|
||||
std::unique_ptr<DCE> dce = create_SIM800_dce(&dce_config, dte, esp_netif);
|
||||
#elif CONFIG_EXAMPLE_MODEM_DEVICE_SIM7000 == 1
|
||||
std::unique_ptr<DCE> dce = create_SIM7000_dce(&dce_config, dte, esp_netif);
|
||||
#elif CONFIG_EXAMPLE_MODEM_DEVICE_SIM7070 == 1
|
||||
std::unique_ptr<DCE> dce = create_SIM7070_dce(&dce_config, dte, esp_netif);
|
||||
#elif CONFIG_EXAMPLE_MODEM_DEVICE_SIM7600 == 1
|
||||
std::unique_ptr<DCE> dce = create_SIM7600_dce(&dce_config, dte, esp_netif);
|
||||
#else
|
||||
@ -78,11 +96,22 @@ extern "C" void app_main(void)
|
||||
#endif
|
||||
assert(dce);
|
||||
|
||||
if(dte_config.uart_config.flow_control == ESP_MODEM_FLOW_CONTROL_HW)
|
||||
{
|
||||
if (command_result::OK != dce->set_flow_control(2, 2)) {
|
||||
ESP_LOGE(TAG, "Failed to set the set_flow_control mode");
|
||||
return;
|
||||
}
|
||||
ESP_LOGI(TAG, "set_flow_control OK");
|
||||
} else {
|
||||
ESP_LOGI(TAG, "not set_flow_control, because 2-wire mode active.");
|
||||
}
|
||||
|
||||
/* Setup basic operation mode for the DCE (pin if used, CMUX mode) */
|
||||
#if CONFIG_EXAMPLE_NEED_SIM_PIN == 1
|
||||
bool pin_ok = true;
|
||||
if (dce->read_pin(pin_ok) == command_result::OK && !pin_ok) {
|
||||
throw_if_false(dce->set_pin(CONFIG_EXAMPLE_SIM_PIN) == command_result::OK, "Cannot set PIN!");
|
||||
ESP_MODEM_THROW_IF_FALSE(dce->set_pin(CONFIG_EXAMPLE_SIM_PIN) == command_result::OK, "Cannot set PIN!");
|
||||
vTaskDelay(pdMS_TO_TICKS(1000)); // Need to wait for some time after unlocking the SIM
|
||||
}
|
||||
#endif
|
||||
@ -164,4 +193,14 @@ extern "C" void app_main(void)
|
||||
return;
|
||||
}
|
||||
#endif // CONFIG_EXAMPLE_PERFORM_OTA
|
||||
|
||||
/* Close multiplexed command/data mode */
|
||||
#if CONFIG_EXAMPLE_CLOSE_CMUX_AT_END == 1
|
||||
if (dce->set_mode(esp_modem::modem_mode::COMMAND_MODE)) {
|
||||
std::cout << "Modem has correctly entered command mode" << std::endl;
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Failed to configure desired mode... exiting");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -26,7 +26,11 @@ struct MqttClientHandle {
|
||||
explicit MqttClientHandle(const std::string &uri)
|
||||
{
|
||||
esp_mqtt_client_config_t config = { };
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
|
||||
config.broker.address.uri = uri.c_str();
|
||||
#else
|
||||
config.uri = uri.c_str();
|
||||
#endif
|
||||
client = esp_mqtt_client_init(&config);
|
||||
esp_mqtt_client_register_event(client, MQTT_EVENT_ANY, mqtt_event_handler, this);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
version: "0.1.17"
|
||||
version: "0.1.23"
|
||||
description: esp modem
|
||||
url: https://github.com/espressif/esp-protocols/tree/master/components/esp_modem
|
||||
dependencies:
|
||||
|
@ -69,12 +69,12 @@ class Creator {
|
||||
public:
|
||||
Creator(std::shared_ptr<DTE> dte, esp_netif_t *esp_netif): dte(std::move(dte)), device(nullptr), netif(esp_netif)
|
||||
{
|
||||
throw_if_false(netif != nullptr, "Null netif");
|
||||
ESP_MODEM_THROW_IF_FALSE(netif != nullptr, "Null netif");
|
||||
}
|
||||
|
||||
Creator(std::shared_ptr<DTE> dte, esp_netif_t *esp_netif, std::shared_ptr<T_Module> dev): dte(std::move(dte)), device(std::move(dev)), netif(esp_netif)
|
||||
{
|
||||
throw_if_false(netif != nullptr, "Null netif");
|
||||
ESP_MODEM_THROW_IF_FALSE(netif != nullptr, "Null netif");
|
||||
}
|
||||
|
||||
~Creator()
|
||||
|
@ -104,6 +104,15 @@ public:
|
||||
pdp = std::move(new_pdp);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Simplified version of operator name (without the ACT, which is included in the command library)
|
||||
*/
|
||||
command_result get_operator_name(std::string& name)
|
||||
{
|
||||
int dummy_act;
|
||||
return get_operator_name(name, dummy_act);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Common DCE commands generated from the API AT list
|
||||
*/
|
||||
|
@ -75,6 +75,12 @@ public:
|
||||
*/
|
||||
void set_read_cb(std::function<bool(uint8_t *data, size_t len)> f);
|
||||
|
||||
/**
|
||||
* @brief Sets DTE error callback
|
||||
* @param f Function to be called on DTE error
|
||||
*/
|
||||
void set_error_cb(std::function<void(terminal_error err)> f);
|
||||
|
||||
/**
|
||||
* @brief Sets the DTE to desired mode (Command/Data/Cmux)
|
||||
* @param m Desired operation mode
|
||||
@ -116,6 +122,7 @@ private:
|
||||
std::shared_ptr<Terminal> data_term; /*!< Secondary terminal for this DTE */
|
||||
modem_mode mode; /*!< DTE operation mode */
|
||||
SignalGroup signal; /*!< Event group used to signal request-response operations */
|
||||
command_result result; /*!< Command result of the currently exectuted command */
|
||||
std::function<bool(uint8_t *data, size_t len)> on_data; /*!< on data callback for current terminal */
|
||||
};
|
||||
|
||||
|
@ -16,14 +16,21 @@
|
||||
|
||||
#include <string>
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#ifndef __FILENAME__
|
||||
#define __FILENAME__ __FILE__
|
||||
#endif
|
||||
#define ESP_MODEM_THROW_IF_FALSE(...) esp_modem::throw_if_false(__FILENAME__, __LINE__, __VA_ARGS__)
|
||||
#define ESP_MODEM_THROW_IF_ERROR(...) esp_modem::throw_if_error(__FILENAME__, __LINE__, __VA_ARGS__)
|
||||
|
||||
namespace esp_modem {
|
||||
|
||||
#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
|
||||
#define THROW(exception) throw(exception)
|
||||
#define ESP_MODEM_THROW(exception) throw(exception)
|
||||
|
||||
class esp_err_exception: virtual public std::exception {
|
||||
public:
|
||||
explicit esp_err_exception(esp_err_t err): esp_err(err) {}
|
||||
explicit esp_err_exception(std::string msg): esp_err(ESP_FAIL), message(std::move(msg)) {}
|
||||
explicit esp_err_exception(std::string msg, esp_err_t err): esp_err(err), message(std::move(msg)) {}
|
||||
virtual esp_err_t get_err_t()
|
||||
@ -31,7 +38,7 @@ public:
|
||||
return esp_err;
|
||||
}
|
||||
~esp_err_exception() noexcept override = default;
|
||||
virtual const char *what() const noexcept
|
||||
[[nodiscard]] const char *what() const noexcept override
|
||||
{
|
||||
return message.c_str();
|
||||
}
|
||||
@ -39,28 +46,43 @@ private:
|
||||
esp_err_t esp_err;
|
||||
std::string message;
|
||||
};
|
||||
|
||||
#else
|
||||
#define THROW(exception) abort()
|
||||
#define ESP_MODEM_THROW(exception) do { exception; abort(); } while(0)
|
||||
|
||||
class esp_err_exception {
|
||||
void print(std::string msg) { ESP_LOGE("ESP_MODEM_THROW", "%s\n", msg.c_str()); }
|
||||
public:
|
||||
explicit esp_err_exception(std::string msg) { print(std::move(msg)); }
|
||||
explicit esp_err_exception(std::string msg, esp_err_t err) { print(std::move(msg)); }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
static inline void throw_if_false(bool condition, std::string message)
|
||||
static inline std::string make_message(const std::string& filename, int line, const std::string& message = "ERROR")
|
||||
{
|
||||
std::string text = filename + ":" + std::to_string(line) + " " + message;
|
||||
return text;
|
||||
}
|
||||
|
||||
static inline void throw_if_false(const std::string& filename, int line, bool condition, const std::string& message)
|
||||
{
|
||||
if (!condition) {
|
||||
THROW(esp_err_exception(std::move(message)));
|
||||
ESP_MODEM_THROW(esp_err_exception(make_message(filename, line, message)));
|
||||
}
|
||||
}
|
||||
|
||||
static inline void throw_if_esp_fail(esp_err_t err, std::string message)
|
||||
static inline void throw_if_error(const std::string& filename, int line, esp_err_t err, const std::string& message)
|
||||
{
|
||||
if (err != ESP_OK) {
|
||||
THROW(esp_err_exception(std::move(message), err));
|
||||
ESP_MODEM_THROW(esp_err_exception(make_message(filename, line, message), err));
|
||||
}
|
||||
}
|
||||
|
||||
static inline void throw_if_esp_fail(esp_err_t err)
|
||||
static inline void throw_if_error(const std::string& filename, int line, esp_err_t err)
|
||||
{
|
||||
if (err != ESP_OK) {
|
||||
THROW(esp_err_exception(err));
|
||||
ESP_MODEM_THROW(esp_err_exception(make_message(filename, line), err));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,6 +41,7 @@ enum class terminal_error {
|
||||
BUFFER_OVERFLOW,
|
||||
CHECKSUM_ERROR,
|
||||
UNEXPECTED_CONTROL_FLOW,
|
||||
DEVICE_GONE,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -15,6 +15,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "esp_modem_config.h"
|
||||
#include "esp_netif.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -22,7 +23,11 @@ extern "C" {
|
||||
|
||||
typedef struct esp_modem_dce_wrap esp_modem_dce_t;
|
||||
|
||||
struct PdpContext;
|
||||
typedef struct esp_modem_PdpContext_t {
|
||||
size_t context_id;
|
||||
const char *protocol_type;
|
||||
const char *apn;
|
||||
} esp_modem_PdpContext_t;
|
||||
|
||||
/**
|
||||
* @defgroup ESP_MODEM_C_API ESP_MODEM C API
|
||||
@ -55,6 +60,23 @@ typedef enum esp_modem_dce_device
|
||||
ESP_MODEM_DCE_SIM800,
|
||||
} esp_modem_dce_device_t;
|
||||
|
||||
/**
|
||||
* @brief Terminal errors
|
||||
*/
|
||||
typedef enum esp_modem_terminal_error
|
||||
{
|
||||
ESP_MODEM_TERMINAL_BUFFER_OVERFLOW,
|
||||
ESP_MODEM_TERMINAL_CHECKSUM_ERROR,
|
||||
ESP_MODEM_TERMINAL_UNEXPECTED_CONTROL_FLOW,
|
||||
ESP_MODEM_TERMINAL_DEVICE_GONE,
|
||||
ESP_MODEM_TERMINAL_UNKNOWN_ERROR,
|
||||
} esp_modem_terminal_error_t;
|
||||
|
||||
/**
|
||||
* @brief Terminal error callback
|
||||
*/
|
||||
typedef void (*esp_modem_terminal_error_cbt)(esp_modem_terminal_error_t);
|
||||
|
||||
/**
|
||||
* @brief Create a generic DCE handle for new modem API
|
||||
*
|
||||
@ -85,6 +107,15 @@ esp_modem_dce_t *esp_modem_new_dev(esp_modem_dce_device_t module, const esp_mode
|
||||
*/
|
||||
void esp_modem_destroy(esp_modem_dce_t * dce);
|
||||
|
||||
/**
|
||||
* @brief Set DTE's error callback
|
||||
*
|
||||
* @param dce Modem DCE handle
|
||||
* @param[in] err_cb Error callback
|
||||
* @return ESP_OK on success, ESP_FAIL on failure
|
||||
*/
|
||||
esp_err_t esp_modem_set_error_cb(esp_modem_dce_t * dce, esp_modem_terminal_error_cbt err_cb);
|
||||
|
||||
/**
|
||||
* @brief Set operation mode for this DCE
|
||||
* @param dce Modem DCE handle
|
||||
|
@ -50,7 +50,8 @@ struct esp_modem_uart_term_config {
|
||||
uart_stop_bits_t stop_bits; /*!< Stop bits of UART */
|
||||
uart_parity_t parity; /*!< Parity type */
|
||||
esp_modem_flow_ctrl_t flow_control; /*!< Flow control type */
|
||||
int baud_rate; /*!< Communication baud rate */
|
||||
uart_sclk_t source_clk; /*!< UART source clock selection */
|
||||
int baud_rate; /*!< Communication baud rate */
|
||||
int tx_io_num; /*!< TXD Pin Number */
|
||||
int rx_io_num; /*!< RXD Pin Number */
|
||||
int rts_io_num; /*!< RTS Pin Number */
|
||||
@ -107,6 +108,7 @@ struct esp_modem_dte_config {
|
||||
.stop_bits = UART_STOP_BITS_1, \
|
||||
.parity = UART_PARITY_DISABLE, \
|
||||
.flow_control = ESP_MODEM_FLOW_CONTROL_NONE,\
|
||||
.source_clk = UART_SCLK_APB, \
|
||||
.baud_rate = 115200, \
|
||||
.tx_io_num = 25, \
|
||||
.rx_io_num = 26, \
|
||||
|
87
components/esp_modem/include/esp_private/c_api_wrapper.hpp
Normal file
87
components/esp_modem/include/esp_private/c_api_wrapper.hpp
Normal file
@ -0,0 +1,87 @@
|
||||
// Copyright 2022 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.
|
||||
|
||||
/**
|
||||
* @file c_api_wrapper.hpp
|
||||
* @brief Collection of C API wrappers
|
||||
*
|
||||
* This file is located in include/esp_private because it is not intended for users,
|
||||
* but rather for esp_modem C extension developers.
|
||||
*
|
||||
* The C extension API must provide a 'factory function' that returns initialized pointer to esp_modem_dce_wrap.
|
||||
* Helper functions provided below, can be used for conversion between C++ enum classes and standard C enums.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cxx_include/esp_modem_dce_factory.hpp"
|
||||
#include "esp_modem_c_api_types.h"
|
||||
|
||||
using namespace esp_modem;
|
||||
|
||||
struct esp_modem_dce_wrap { // need to mimic the polymorphic dispatch as CPP uses templated dispatch
|
||||
enum class modem_wrap_dte_type { UART, VFS, USB } dte_type;
|
||||
dce_factory::ModemType modem_type;
|
||||
DCE *dce;
|
||||
std::shared_ptr<DTE> dte;
|
||||
esp_modem_dce_wrap() : dce(nullptr), dte(nullptr) {}
|
||||
};
|
||||
|
||||
inline dce_factory::ModemType convert_modem_enum(esp_modem_dce_device_t module)
|
||||
{
|
||||
switch (module) {
|
||||
case ESP_MODEM_DCE_SIM7600:
|
||||
return esp_modem::dce_factory::ModemType::SIM7600;
|
||||
case ESP_MODEM_DCE_SIM7070:
|
||||
return esp_modem::dce_factory::ModemType::SIM7070;
|
||||
case ESP_MODEM_DCE_SIM7000:
|
||||
return esp_modem::dce_factory::ModemType::SIM7000;
|
||||
case ESP_MODEM_DCE_BG96:
|
||||
return esp_modem::dce_factory::ModemType::BG96;
|
||||
case ESP_MODEM_DCE_SIM800:
|
||||
return esp_modem::dce_factory::ModemType::SIM800;
|
||||
default:
|
||||
case ESP_MODEM_DCE_GENETIC:
|
||||
return esp_modem::dce_factory::ModemType::GenericModule;
|
||||
}
|
||||
}
|
||||
|
||||
inline esp_modem_terminal_error_t convert_terminal_error_enum(terminal_error err)
|
||||
{
|
||||
switch (err) {
|
||||
case terminal_error::BUFFER_OVERFLOW:
|
||||
return ESP_MODEM_TERMINAL_BUFFER_OVERFLOW;
|
||||
case terminal_error::CHECKSUM_ERROR:
|
||||
return ESP_MODEM_TERMINAL_CHECKSUM_ERROR;
|
||||
case terminal_error::UNEXPECTED_CONTROL_FLOW:
|
||||
return ESP_MODEM_TERMINAL_UNEXPECTED_CONTROL_FLOW;
|
||||
case terminal_error::DEVICE_GONE:
|
||||
return ESP_MODEM_TERMINAL_DEVICE_GONE;
|
||||
default:
|
||||
return ESP_MODEM_TERMINAL_UNKNOWN_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
inline esp_err_t command_response_to_esp_err(command_result res)
|
||||
{
|
||||
switch (res) {
|
||||
case command_result::OK:
|
||||
return ESP_OK;
|
||||
case command_result::FAIL:
|
||||
return ESP_FAIL;
|
||||
case command_result::TIMEOUT:
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
@ -38,7 +38,7 @@
|
||||
#define BOOL_OUT(param, name) bool* _ARG(param, name)
|
||||
#define INT_OUT(param, name) int* _ARG(param, name)
|
||||
#define INTEGER_LIST_IN(param, name) const int* _ARG(param, name)
|
||||
#define STRUCT_OUT(struct_name, p1) struct struct_name* p1
|
||||
#define STRUCT_OUT(struct_name, p1) esp_modem_ ## struct_name ## _t* p1
|
||||
#endif
|
||||
|
||||
#define DECLARE_ALL_COMMAND_APIS(...) \
|
||||
@ -47,12 +47,14 @@
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ \
|
||||
ESP_MODEM_DECLARE_DCE_COMMAND(sync, command_result, 0) \
|
||||
\
|
||||
/**
|
||||
* @brief Reads the operator name
|
||||
* @param[out] operator name
|
||||
* @param[out] access technology
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ \
|
||||
ESP_MODEM_DECLARE_DCE_COMMAND(get_operator_name, command_result, 1, STRING_OUT(p1, name)) \
|
||||
ESP_MODEM_DECLARE_DCE_COMMAND(get_operator_name, command_result, 2, STRING_OUT(p1, name), INT_OUT(p2, act)) \
|
||||
\
|
||||
/**
|
||||
* @brief Stores current user profile
|
||||
@ -65,7 +67,16 @@ ESP_MODEM_DECLARE_DCE_COMMAND(store_profile, command_result, 0) \
|
||||
* @param[in] pin Pin
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/\
|
||||
ESP_MODEM_DECLARE_DCE_COMMAND(set_pin, command_result, 1, STRING_IN(p1, pin)) \
|
||||
ESP_MODEM_DECLARE_DCE_COMMAND(set_pin, command_result, 1, STRING_IN(p1, pin)) \
|
||||
\
|
||||
/**
|
||||
* @brief Execute the supplied AT command
|
||||
* @param[in] at AT command
|
||||
* @param[out] out Command output string
|
||||
* @param[in] timeout AT command timeout in milliseconds
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/\
|
||||
ESP_MODEM_DECLARE_DCE_COMMAND(at, command_result, 3, STRING_IN(p1, cmd), STRING_OUT(p2, out), INT_IN(p3, timeout)) \
|
||||
\
|
||||
/**
|
||||
* @brief Checks if the SIM needs a PIN
|
||||
@ -89,7 +100,7 @@ ESP_MODEM_DECLARE_DCE_COMMAND(set_echo, command_result, 1, BOOL_IN(p1, echo_on))
|
||||
ESP_MODEM_DECLARE_DCE_COMMAND(sms_txt_mode, command_result, 1, BOOL_IN(p1, txt)) \
|
||||
\
|
||||
/**
|
||||
* @brief Sets the default (GSM) charater set
|
||||
* @brief Sets the default (GSM) character set
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ \
|
||||
ESP_MODEM_DECLARE_DCE_COMMAND(sms_character_set, command_result, 0) \
|
||||
@ -103,7 +114,7 @@ ESP_MODEM_DECLARE_DCE_COMMAND(sms_character_set, command_result, 0) \
|
||||
ESP_MODEM_DECLARE_DCE_COMMAND(send_sms, command_result, 2, STRING_IN(p1, number), STRING_IN(p2, message)) \
|
||||
\
|
||||
/**
|
||||
* @brief Resumes data mode (Switches back to th data mode, which was temporarily suspended)
|
||||
* @brief Resumes data mode (Switches back to the data mode, which was temporarily suspended)
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ \
|
||||
ESP_MODEM_DECLARE_DCE_COMMAND(resume_data_mode, command_result, 0) \
|
||||
@ -284,6 +295,13 @@ ESP_MODEM_DECLARE_DCE_COMMAND(get_network_system_mode, command_result, 1, INT_OU
|
||||
*/ \
|
||||
ESP_MODEM_DECLARE_DCE_COMMAND(set_gnss_power_mode, command_result, 1, INT_IN(p1, mode)) \
|
||||
\
|
||||
/**
|
||||
* @brief GNSS power control
|
||||
* @param[out] mode power mode (0 - off, 1 - on)
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ \
|
||||
ESP_MODEM_DECLARE_DCE_COMMAND(get_gnss_power_mode, command_result, 1, INT_OUT(p1, mode)) \
|
||||
\
|
||||
|
||||
|
||||
#ifdef GENERATE_DOCS
|
||||
|
@ -22,6 +22,7 @@
|
||||
.stop_bits = UART_STOP_BITS_1, \
|
||||
.parity = UART_PARITY_DISABLE, \
|
||||
.flow_control = ESP_MODEM_FLOW_CONTROL_NONE,\
|
||||
.source_clk = UART_SCLK_APB, \
|
||||
.baud_rate = 115200, \
|
||||
.tx_io_num = 25, \
|
||||
.rx_io_num = 26, \
|
||||
|
@ -1,2 +1,3 @@
|
||||
idf_component_register(INCLUDE_DIRS include
|
||||
idf_component_register(SRCS "esp_err_to_name.c"
|
||||
INCLUDE_DIRS include
|
||||
REQUIRES esp_netif_linux esp_event_mock)
|
||||
|
@ -0,0 +1,14 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: Franz Hoepfinger
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
|
||||
|
||||
static const char esp_unknown_msg[] = "ERROR";
|
||||
|
||||
const char *esp_err_to_name(int code)
|
||||
{
|
||||
return esp_unknown_msg;
|
||||
}
|
@ -17,4 +17,5 @@
|
||||
typedef int uart_port_t;
|
||||
typedef int uart_word_length_t;
|
||||
typedef int uart_stop_bits_t;
|
||||
typedef int uart_parity_t;
|
||||
typedef int uart_parity_t;
|
||||
typedef int uart_sclk_t;
|
||||
|
@ -25,3 +25,11 @@ typedef int esp_err_t;
|
||||
#define ESP_ERR_NOT_FOUND 0x105
|
||||
#define ESP_ERR_NOT_SUPPORTED 0x106
|
||||
#define ESP_ERR_TIMEOUT 0x107
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
const char *esp_err_to_name(int code);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -22,7 +22,7 @@
|
||||
action; \
|
||||
} catch (::esp_modem::esp_err_exception& e) { \
|
||||
esp_err_t err = e.get_err_t(); \
|
||||
ESP_LOGE(TAG, "%s: Exception caught with ESP err_code=%d", __func__, err); \
|
||||
ESP_LOGE(TAG, "%s: Exception caught with ESP err_code=%d %s", __func__, err, esp_err_to_name(err)); \
|
||||
ESP_LOGE(TAG, "%s", e.what()); \
|
||||
action; \
|
||||
}
|
||||
|
@ -15,6 +15,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "esp_idf_version.h"
|
||||
#include "driver/uart.h"
|
||||
|
||||
/**
|
||||
@ -23,7 +24,7 @@
|
||||
*/
|
||||
static inline int uart_write_bytes_compat(uart_port_t uart_num, const void* src, size_t size)
|
||||
{
|
||||
#if ESP_IDF_VERSION_MAJOR >= 4 && ESP_IDF_VERSION_MINOR >= 3
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 3, 0)
|
||||
const void *data = src;
|
||||
#else
|
||||
auto *data = reinterpret_cast<const char*>(src);
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "esp_modem_c_api_types.h"
|
||||
#include "esp_modem_config.h"
|
||||
#include "exception_stub.hpp"
|
||||
#include "esp_private/c_api_wrapper.hpp"
|
||||
#include "cstring"
|
||||
|
||||
#ifndef ESP_MODEM_C_API_STR_MAX
|
||||
@ -35,44 +36,6 @@ size_t strlcpy(char *dest, const char *src, size_t len);
|
||||
// C API definitions
|
||||
using namespace esp_modem;
|
||||
|
||||
struct esp_modem_dce_wrap { // need to mimic the polymorphic dispatch as CPP uses templated dispatch
|
||||
enum class modem_wrap_dte_type { UART, } dte_type;
|
||||
dce_factory::ModemType modem_type;
|
||||
DCE *dce;
|
||||
};
|
||||
|
||||
static inline esp_err_t command_response_to_esp_err(command_result res)
|
||||
{
|
||||
switch (res) {
|
||||
case command_result::OK:
|
||||
return ESP_OK;
|
||||
case command_result::FAIL:
|
||||
return ESP_FAIL;
|
||||
case command_result::TIMEOUT:
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
static inline dce_factory::ModemType convert_modem_enum(esp_modem_dce_device_t module)
|
||||
{
|
||||
switch (module) {
|
||||
case ESP_MODEM_DCE_SIM7600:
|
||||
return esp_modem::dce_factory::ModemType::SIM7600;
|
||||
case ESP_MODEM_DCE_SIM7070:
|
||||
return esp_modem::dce_factory::ModemType::SIM7070;
|
||||
case ESP_MODEM_DCE_SIM7000:
|
||||
return esp_modem::dce_factory::ModemType::SIM7000;
|
||||
case ESP_MODEM_DCE_BG96:
|
||||
return esp_modem::dce_factory::ModemType::BG96;
|
||||
case ESP_MODEM_DCE_SIM800:
|
||||
return esp_modem::dce_factory::ModemType::SIM800;
|
||||
default:
|
||||
case ESP_MODEM_DCE_GENETIC:
|
||||
return esp_modem::dce_factory::ModemType::GenericModule;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" esp_modem_dce_t *esp_modem_new_dev(esp_modem_dce_device_t module, const esp_modem_dte_config_t *dte_config, const esp_modem_dce_config_t *dce_config, esp_netif_t *netif)
|
||||
{
|
||||
auto dce_wrap = new (std::nothrow) esp_modem_dce_wrap;
|
||||
@ -84,6 +47,7 @@ extern "C" esp_modem_dce_t *esp_modem_new_dev(esp_modem_dce_device_t module, con
|
||||
delete dce_wrap;
|
||||
return nullptr;
|
||||
}
|
||||
dce_wrap->dte = dte;
|
||||
dce_factory::Factory f(convert_modem_enum(module));
|
||||
dce_wrap->dce = f.build(dce_config, std::move(dte), netif);
|
||||
if (dce_wrap->dce == nullptr) {
|
||||
@ -108,6 +72,22 @@ extern "C" void esp_modem_destroy(esp_modem_dce_t *dce_wrap)
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" esp_err_t esp_modem_set_error_cb(esp_modem_dce_t * dce_wrap, esp_modem_terminal_error_cbt err_cb)
|
||||
{
|
||||
if (dce_wrap == nullptr || dce_wrap->dce == nullptr || dce_wrap->dte == nullptr) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (err_cb) {
|
||||
dce_wrap->dte->set_error_cb([err_cb](terminal_error err) {
|
||||
err_cb(convert_terminal_error_enum(err));
|
||||
});
|
||||
} else {
|
||||
dce_wrap->dte->set_error_cb(nullptr);
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
extern "C" esp_err_t esp_modem_sync(esp_modem_dce_t *dce_wrap)
|
||||
{
|
||||
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
|
||||
@ -122,20 +102,15 @@ extern "C" esp_err_t esp_modem_set_mode(esp_modem_dce_t *dce_wrap, esp_modem_dce
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (mode == ESP_MODEM_MODE_DATA) {
|
||||
dce_wrap->dce->set_data();
|
||||
} else if (mode == ESP_MODEM_MODE_COMMAND) {
|
||||
dce_wrap->dce->exit_data();
|
||||
} else if (mode == ESP_MODEM_MODE_CMUX) {
|
||||
if (dce_wrap->dce->set_mode(modem_mode::CMUX_MODE) &&
|
||||
// automatically switch to data mode for the primary terminal
|
||||
dce_wrap->dce->set_mode(modem_mode::DATA_MODE)) {
|
||||
return ESP_OK;
|
||||
}
|
||||
return ESP_FAIL;
|
||||
} else {
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
return dce_wrap->dce->set_mode(modem_mode::DATA_MODE) ? ESP_OK : ESP_FAIL;
|
||||
}
|
||||
return ESP_OK;
|
||||
if (mode == ESP_MODEM_MODE_COMMAND) {
|
||||
return dce_wrap->dce->set_mode(modem_mode::COMMAND_MODE) ? ESP_OK : ESP_FAIL;
|
||||
}
|
||||
if (mode == ESP_MODEM_MODE_CMUX) {
|
||||
return dce_wrap->dce->set_mode(modem_mode::CMUX_MODE) ? ESP_OK : ESP_FAIL;
|
||||
}
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
extern "C" esp_err_t esp_modem_read_pin(esp_modem_dce_t *dce_wrap, bool *pin)
|
||||
@ -184,6 +159,20 @@ extern "C" esp_err_t esp_modem_set_pin(esp_modem_dce_t *dce_wrap, const char *pi
|
||||
return command_response_to_esp_err(dce_wrap->dce->set_pin(pin_str));
|
||||
}
|
||||
|
||||
extern "C" esp_err_t esp_modem_at(esp_modem_dce_t *dce_wrap, const char *at, char *p_out, int timeout)
|
||||
{
|
||||
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
std::string out;
|
||||
std::string at_str(at);
|
||||
auto ret = command_response_to_esp_err(dce_wrap->dce->at(at_str, out, timeout));
|
||||
if ((p_out != NULL) && (!out.empty())) {
|
||||
strlcpy(p_out, out.c_str(), ESP_MODEM_C_API_STR_MAX);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
extern "C" esp_err_t esp_modem_get_signal_quality(esp_modem_dce_t *dce_wrap, int *rssi, int *ber)
|
||||
{
|
||||
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
|
||||
@ -234,15 +223,17 @@ extern "C" esp_err_t esp_modem_get_imei(esp_modem_dce_t *dce_wrap, char *p_imei)
|
||||
return ret;
|
||||
}
|
||||
|
||||
extern "C" esp_err_t esp_modem_get_operator_name(esp_modem_dce_t *dce_wrap, char *p_name)
|
||||
extern "C" esp_err_t esp_modem_get_operator_name(esp_modem_dce_t *dce_wrap, char *p_name, int *p_act)
|
||||
{
|
||||
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
|
||||
if (dce_wrap == nullptr || dce_wrap->dce == nullptr || p_name == nullptr || p_act == nullptr) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
std::string name;
|
||||
auto ret = command_response_to_esp_err(dce_wrap->dce->get_operator_name(name));
|
||||
int act;
|
||||
auto ret = command_response_to_esp_err(dce_wrap->dce->get_operator_name(name, act));
|
||||
if (ret == ESP_OK && !name.empty()) {
|
||||
strlcpy(p_name, name.c_str(), ESP_MODEM_C_API_STR_MAX);
|
||||
*p_act = act;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@ -379,3 +370,32 @@ extern "C" esp_err_t esp_modem_set_gnss_power_mode(esp_modem_dce_t *dce_wrap, in
|
||||
}
|
||||
return command_response_to_esp_err(dce_wrap->dce->set_gnss_power_mode(mode));
|
||||
}
|
||||
|
||||
extern "C" esp_err_t esp_modem_get_gnss_power_mode(esp_modem_dce_t *dce_wrap, int *p_mode)
|
||||
{
|
||||
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
int mode;
|
||||
auto ret = command_response_to_esp_err(dce_wrap->dce->get_gnss_power_mode(mode));
|
||||
if (ret == ESP_OK) {
|
||||
*p_mode = mode;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
extern "C" esp_err_t esp_modem_reset(esp_modem_dce_t *dce_wrap)
|
||||
{
|
||||
return command_response_to_esp_err(dce_wrap->dce->reset());
|
||||
}
|
||||
|
||||
extern "C" esp_err_t esp_modem_set_pdp_context(esp_modem_dce_t *dce_wrap, esp_modem_PdpContext_t *c_api_pdp)
|
||||
{
|
||||
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
esp_modem::PdpContext pdp{c_api_pdp->apn};
|
||||
pdp.context_id = c_api_pdp->context_id;
|
||||
pdp.protocol_type = c_api_pdp->protocol_type;
|
||||
return command_response_to_esp_err(dce_wrap->dce->set_pdp_context(pdp));
|
||||
}
|
||||
|
@ -82,7 +82,7 @@ void CMux::send_disconnect(size_t i)
|
||||
{
|
||||
if (i == 0) { // control terminal
|
||||
uint8_t frame[] = {
|
||||
SOF_MARKER, 0x3, 0xFF, 0x5, 0xC3, 0x1, 0xE7, SOF_MARKER };
|
||||
SOF_MARKER, 0x3, 0xEF, 0x5, 0xC3, 0x1, 0xF2, SOF_MARKER };
|
||||
term->write(frame, 8);
|
||||
} else { // separate virtual terminal
|
||||
uint8_t frame[] = {
|
||||
@ -142,7 +142,7 @@ void CMux::data_available(uint8_t *data, size_t len)
|
||||
read_cb[virtual_term](payload_start, total_payload_size);
|
||||
#endif
|
||||
}
|
||||
} else if (type == 0xFF && dlci == 0) { // notify the internal DISC command
|
||||
} else if ((type&FT_UIH) == FT_UIH && dlci == 0) { // notify the internal DISC command
|
||||
Scoped<Lock> l(lock);
|
||||
sabm_ack = dlci;
|
||||
}
|
||||
@ -325,11 +325,12 @@ bool CMux::on_cmux_data(uint8_t *data, size_t actual_len)
|
||||
|
||||
bool CMux::deinit()
|
||||
{
|
||||
int timeout = 0;
|
||||
int timeout;
|
||||
sabm_ack = -1;
|
||||
// First disconnect all (2) virtual terminals
|
||||
for (size_t i = 1; i < 3; i++) {
|
||||
send_disconnect(i);
|
||||
timeout = 0;
|
||||
while (true) {
|
||||
usleep(10'000);
|
||||
Scoped<Lock> l(lock);
|
||||
@ -345,6 +346,7 @@ bool CMux::deinit()
|
||||
sabm_ack = -1;
|
||||
// Then disconnect the control terminal
|
||||
send_disconnect(0);
|
||||
timeout = 0;
|
||||
while (true) {
|
||||
usleep(10'000);
|
||||
Scoped<Lock> l(lock);
|
||||
|
@ -228,7 +228,7 @@ command_result set_flow_control(CommandableIf *t, int dce_flow, int dte_flow)
|
||||
return generic_command_common(t, "AT+IFC=" + std::to_string(dce_flow) + ", " + std::to_string(dte_flow) + "\r");
|
||||
}
|
||||
|
||||
command_result get_operator_name(CommandableIf *t, std::string &operator_name)
|
||||
command_result get_operator_name(CommandableIf *t, std::string &operator_name, int &act)
|
||||
{
|
||||
ESP_LOGV(TAG, "%s", __func__ );
|
||||
std::string_view out;
|
||||
@ -239,9 +239,19 @@ command_result get_operator_name(CommandableIf *t, std::string &operator_name)
|
||||
auto pos = out.find("+COPS");
|
||||
auto property = 0;
|
||||
while (pos != std::string::npos) {
|
||||
// Looking for: +COPS: <mode>[, <format>[, <oper>]]
|
||||
// Looking for: +COPS: <mode>[, <format>[, <oper>[, <act>]]]
|
||||
if (property++ == 2) { // operator name is after second comma (as a 3rd property of COPS string)
|
||||
operator_name = out.substr(++pos);
|
||||
auto additional_comma = operator_name.find(','); // check for the optional ACT
|
||||
if (additional_comma != std::string::npos && std::from_chars(operator_name.data() + additional_comma + 1,operator_name.data() + operator_name.length(), act).ec != std::errc::invalid_argument) {
|
||||
operator_name = operator_name.substr(0, additional_comma);
|
||||
}
|
||||
// and strip quotes if present
|
||||
auto quote1 = operator_name.find('"');
|
||||
auto quote2 = operator_name.rfind('"');
|
||||
if (quote1 != std::string::npos && quote2 != std::string::npos) {
|
||||
operator_name = operator_name.substr(quote1+1, quote2-1);
|
||||
}
|
||||
return command_result::OK;
|
||||
}
|
||||
pos = out.find(',', ++pos);
|
||||
@ -263,7 +273,7 @@ command_result set_pdp_context(CommandableIf *t, PdpContext &pdp)
|
||||
ESP_LOGV(TAG, "%s", __func__ );
|
||||
std::string pdp_command = "AT+CGDCONT=" + std::to_string(pdp.context_id) +
|
||||
",\"" + pdp.protocol_type + "\",\"" + pdp.apn + "\"\r";
|
||||
return generic_command_common(t, pdp_command);
|
||||
return generic_command_common(t, pdp_command, 150000);
|
||||
}
|
||||
|
||||
command_result set_data_mode(CommandableIf *t)
|
||||
@ -379,6 +389,13 @@ command_result set_pin(CommandableIf *t, const std::string &pin)
|
||||
return generic_command_common(t, set_pin_command);
|
||||
}
|
||||
|
||||
command_result at(CommandableIf *t, const std::string &cmd, std::string &out, int timeout = 500)
|
||||
{
|
||||
ESP_LOGV(TAG, "%s", __func__ );
|
||||
std::string at_command = cmd + "\r";
|
||||
return generic_get_string(t, at_command, out, timeout);
|
||||
}
|
||||
|
||||
command_result get_signal_quality(CommandableIf *t, int &rssi, int &ber)
|
||||
{
|
||||
ESP_LOGV(TAG, "%s", __func__ );
|
||||
@ -441,7 +458,7 @@ command_result get_network_attachment_state(CommandableIf *t, int &state)
|
||||
command_result set_radio_state(CommandableIf *t, int state)
|
||||
{
|
||||
ESP_LOGV(TAG, "%s", __func__ );
|
||||
return generic_command_common(t, "AT+CFUN=" + std::to_string(state) + "\r");
|
||||
return generic_command_common(t, "AT+CFUN=" + std::to_string(state) + "\r", 15000);
|
||||
}
|
||||
|
||||
command_result get_radio_state(CommandableIf *t, int &state)
|
||||
@ -537,10 +554,31 @@ command_result set_gnss_power_mode(CommandableIf *t, int mode)
|
||||
return generic_command_common(t, "AT+CGNSPWR=" + std::to_string(mode) + "\r");
|
||||
}
|
||||
|
||||
command_result get_gnss_power_mode(CommandableIf *t, int &mode)
|
||||
{
|
||||
ESP_LOGV(TAG, "%s", __func__ );
|
||||
std::string_view out;
|
||||
auto ret = generic_get_string(t, "AT+CGNSPWR?\r", out);
|
||||
if (ret != command_result::OK) {
|
||||
return ret;
|
||||
}
|
||||
constexpr std::string_view pattern = "+CGNSPWR: ";
|
||||
constexpr int pos = pattern.size();
|
||||
if (out.find(pattern) == std::string::npos) {
|
||||
return command_result::FAIL;
|
||||
}
|
||||
|
||||
if (std::from_chars(out.data() + pos, out.data() + out.size(), mode).ec == std::errc::invalid_argument) {
|
||||
return command_result::FAIL;
|
||||
}
|
||||
|
||||
return command_result::OK;
|
||||
}
|
||||
|
||||
command_result set_gnss_power_mode_sim76xx(CommandableIf *t, int mode)
|
||||
{
|
||||
ESP_LOGV(TAG, "%s", __func__ );
|
||||
return generic_command_common(t, "AT+CGPS=" + std::to_string(mode) + "\r");
|
||||
}
|
||||
|
||||
} // esp_modem::dce_commands
|
||||
} // esp_modem::dce_commands
|
||||
|
@ -35,8 +35,9 @@ DTE::DTE(std::unique_ptr<Terminal> terminal):
|
||||
command_result DTE::command(const std::string &command, got_line_cb got_line, uint32_t time_ms, const char separator)
|
||||
{
|
||||
Scoped<Lock> l(internal_lock);
|
||||
command_result res = command_result::TIMEOUT;
|
||||
command_term->set_read_cb([&](uint8_t *data, size_t len) {
|
||||
result = command_result::TIMEOUT;
|
||||
signal.clear(GOT_LINE);
|
||||
command_term->set_read_cb([this, got_line, separator](uint8_t *data, size_t len) {
|
||||
if (!data) {
|
||||
data = buffer.get();
|
||||
len = command_term->read(data + buffer.consumed, buffer.size - buffer.consumed);
|
||||
@ -44,8 +45,8 @@ command_result DTE::command(const std::string &command, got_line_cb got_line, ui
|
||||
buffer.consumed = 0; // if the underlying terminal contains data, we cannot fragment
|
||||
}
|
||||
if (memchr(data + buffer.consumed, separator, len)) {
|
||||
res = got_line(data, buffer.consumed + len);
|
||||
if (res == command_result::OK || res == command_result::FAIL) {
|
||||
result = got_line(data, buffer.consumed + len);
|
||||
if (result == command_result::OK || result == command_result::FAIL) {
|
||||
signal.set(GOT_LINE);
|
||||
return true;
|
||||
}
|
||||
@ -55,12 +56,12 @@ command_result DTE::command(const std::string &command, got_line_cb got_line, ui
|
||||
});
|
||||
command_term->write((uint8_t *)command.c_str(), command.length());
|
||||
auto got_lf = signal.wait(GOT_LINE, time_ms);
|
||||
if (got_lf && res == command_result::TIMEOUT) {
|
||||
throw_if_esp_fail(ESP_ERR_INVALID_STATE);
|
||||
if (got_lf && result == command_result::TIMEOUT) {
|
||||
ESP_MODEM_THROW_IF_ERROR(ESP_ERR_INVALID_STATE);
|
||||
}
|
||||
buffer.consumed = 0;
|
||||
command_term->set_read_cb(nullptr);
|
||||
return res;
|
||||
return result;
|
||||
}
|
||||
|
||||
command_result DTE::command(const std::string &cmd, got_line_cb got_line, uint32_t time_ms)
|
||||
@ -155,6 +156,12 @@ void DTE::set_read_cb(std::function<bool(uint8_t *, size_t)> f)
|
||||
});
|
||||
}
|
||||
|
||||
void DTE::set_error_cb(std::function<void(terminal_error err)> f)
|
||||
{
|
||||
data_term->set_error_cb(f);
|
||||
command_term->set_error_cb(f);
|
||||
}
|
||||
|
||||
int DTE::read(uint8_t **d, size_t len)
|
||||
{
|
||||
auto data_to_read = std::min(len, buffer.size);
|
||||
|
@ -14,8 +14,10 @@
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <inttypes.h>
|
||||
#include <esp_log.h>
|
||||
#include <esp_event.h>
|
||||
#include "esp_idf_version.h"
|
||||
#include "cxx_include/esp_modem_netif.hpp"
|
||||
#include "cxx_include/esp_modem_dte.hpp"
|
||||
#include "esp_netif_ppp.h"
|
||||
@ -28,7 +30,7 @@ void Netif::on_ppp_changed(void *arg, esp_event_base_t event_base,
|
||||
{
|
||||
auto *ppp = static_cast<Netif *>(arg);
|
||||
if (event_id < NETIF_PP_PHASE_OFFSET) {
|
||||
ESP_LOGI("esp_modem_netif", "PPP state changed event %d", event_id);
|
||||
ESP_LOGI("esp_modem_netif", "PPP state changed event %" PRId32, event_id);
|
||||
// only notify the modem on state/error events, ignoring phase transitions
|
||||
ppp->signal.set(PPP_EXIT);
|
||||
}
|
||||
@ -58,7 +60,7 @@ esp_err_t Netif::esp_modem_post_attach(esp_netif_t *esp_netif, void *args)
|
||||
esp_netif_ppp_config_t ppp_config = { .ppp_phase_event_enabled = true, // assuming phase enabled, as earlier IDFs
|
||||
.ppp_error_event_enabled = false
|
||||
}; // don't provide cfg getters so we enable both events
|
||||
#if ESP_IDF_VERSION_MAJOR >= 4 && ESP_IDF_VERSION_MINOR >= 4
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0)
|
||||
esp_netif_ppp_get_params(esp_netif, &ppp_config);
|
||||
#endif // ESP-IDF >= v4.4
|
||||
if (!ppp_config.ppp_error_event_enabled) {
|
||||
@ -82,11 +84,11 @@ Netif::Netif(std::shared_ptr<DTE> e, esp_netif_t *ppp_netif) :
|
||||
driver.base.netif = ppp_netif;
|
||||
driver.ppp = this;
|
||||
driver.base.post_attach = esp_modem_post_attach;
|
||||
throw_if_esp_fail(esp_event_handler_register(NETIF_PPP_STATUS, ESP_EVENT_ANY_ID, &on_ppp_changed, (void *) this));
|
||||
throw_if_esp_fail(esp_event_handler_register(IP_EVENT, IP_EVENT_PPP_GOT_IP, esp_netif_action_connected, ppp_netif));
|
||||
throw_if_esp_fail(
|
||||
ESP_MODEM_THROW_IF_ERROR(esp_event_handler_register(NETIF_PPP_STATUS, ESP_EVENT_ANY_ID, &on_ppp_changed, (void *) this));
|
||||
ESP_MODEM_THROW_IF_ERROR(esp_event_handler_register(IP_EVENT, IP_EVENT_PPP_GOT_IP, esp_netif_action_connected, ppp_netif));
|
||||
ESP_MODEM_THROW_IF_ERROR(
|
||||
esp_event_handler_register(IP_EVENT, IP_EVENT_PPP_LOST_IP, esp_netif_action_disconnected, ppp_netif));
|
||||
throw_if_esp_fail(esp_netif_attach(ppp_netif, &driver));
|
||||
ESP_MODEM_THROW_IF_ERROR(esp_netif_attach(ppp_netif, &driver));
|
||||
}
|
||||
|
||||
void Netif::start()
|
||||
|
@ -28,7 +28,7 @@ void Lock::unlock()
|
||||
Lock::Lock(): m(nullptr)
|
||||
{
|
||||
m = xSemaphoreCreateRecursiveMutex();
|
||||
throw_if_false(m != nullptr, "create signal event group failed");
|
||||
ESP_MODEM_THROW_IF_FALSE(m != nullptr, "create signal event group failed");
|
||||
}
|
||||
|
||||
Lock::~Lock()
|
||||
@ -45,7 +45,7 @@ void Lock::lock()
|
||||
SignalGroup::SignalGroup(): event_group(nullptr)
|
||||
{
|
||||
event_group = xEventGroupCreate();
|
||||
throw_if_false(event_group != nullptr, "create signal event group failed");
|
||||
ESP_MODEM_THROW_IF_FALSE(event_group != nullptr, "create signal event group failed");
|
||||
}
|
||||
|
||||
void SignalGroup::set(uint32_t bits)
|
||||
@ -86,7 +86,7 @@ Task::Task(size_t stack_size, size_t priority, void *task_param, TaskFunction_t
|
||||
: task_handle(nullptr)
|
||||
{
|
||||
BaseType_t ret = xTaskCreate(task_function, "vfs_task", stack_size, task_param, priority, &task_handle);
|
||||
throw_if_false(ret == pdTRUE, "create vfs task failed");
|
||||
ESP_MODEM_THROW_IF_FALSE(ret == pdTRUE, "create vfs task failed");
|
||||
}
|
||||
|
||||
Task::~Task()
|
||||
|
@ -38,9 +38,9 @@ uart_resource::uart_resource(const esp_modem_uart_term_config *config, QueueHand
|
||||
uart_config.stop_bits = config->stop_bits;
|
||||
uart_config.flow_ctrl = (config->flow_control == ESP_MODEM_FLOW_CONTROL_HW) ? UART_HW_FLOWCTRL_CTS_RTS
|
||||
: UART_HW_FLOWCTRL_DISABLE;
|
||||
uart_config.source_clk = UART_SCLK_APB;
|
||||
uart_config.source_clk = config->source_clk;
|
||||
|
||||
throw_if_esp_fail(uart_param_config(config->port_num, &uart_config), "config uart parameter failed");
|
||||
ESP_MODEM_THROW_IF_ERROR(uart_param_config(config->port_num, &uart_config), "config uart parameter failed");
|
||||
|
||||
if (config->flow_control == ESP_MODEM_FLOW_CONTROL_HW) {
|
||||
res = uart_set_pin(config->port_num, config->tx_io_num, config->rx_io_num,
|
||||
@ -49,24 +49,24 @@ uart_resource::uart_resource(const esp_modem_uart_term_config *config, QueueHand
|
||||
res = uart_set_pin(config->port_num, config->tx_io_num, config->rx_io_num,
|
||||
UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
|
||||
}
|
||||
throw_if_esp_fail(res, "config uart gpio failed");
|
||||
ESP_MODEM_THROW_IF_ERROR(res, "config uart gpio failed");
|
||||
/* Set flow control threshold */
|
||||
if (config->flow_control == ESP_MODEM_FLOW_CONTROL_HW) {
|
||||
res = uart_set_hw_flow_ctrl(config->port_num, UART_HW_FLOWCTRL_CTS_RTS, UART_FIFO_LEN - 8);
|
||||
} else if (config->flow_control == ESP_MODEM_FLOW_CONTROL_SW) {
|
||||
res = uart_set_sw_flow_ctrl(config->port_num, true, 8, UART_FIFO_LEN - 8);
|
||||
}
|
||||
throw_if_esp_fail(res, "config uart flow control failed");
|
||||
ESP_MODEM_THROW_IF_ERROR(res, "config uart flow control failed");
|
||||
|
||||
/* Install UART driver and get event queue used inside driver */
|
||||
res = uart_driver_install(config->port_num,
|
||||
config->rx_buffer_size, config->tx_buffer_size,
|
||||
config->event_queue_size, config->event_queue_size ? event_queue : nullptr,
|
||||
0);
|
||||
throw_if_esp_fail(res, "install uart driver failed");
|
||||
throw_if_esp_fail(uart_set_rx_timeout(config->port_num, 1), "set rx timeout failed");
|
||||
ESP_MODEM_THROW_IF_ERROR(res, "install uart driver failed");
|
||||
ESP_MODEM_THROW_IF_ERROR(uart_set_rx_timeout(config->port_num, 1), "set rx timeout failed");
|
||||
|
||||
throw_if_esp_fail(uart_set_rx_full_threshold(config->port_num, 64), "config rx full threshold failed");
|
||||
ESP_MODEM_THROW_IF_ERROR(uart_set_rx_full_threshold(config->port_num, 64), "config rx full threshold failed");
|
||||
|
||||
/* mark UART as initialized */
|
||||
port = config->port_num;
|
||||
|
@ -33,7 +33,7 @@ struct uart_task {
|
||||
task_handle(nullptr)
|
||||
{
|
||||
BaseType_t ret = xTaskCreate(task_function, "uart_task", stack_size, task_param, priority, &task_handle);
|
||||
throw_if_false(ret == pdTRUE, "create uart event task failed");
|
||||
ESP_MODEM_THROW_IF_FALSE(ret == pdTRUE, "create uart event task failed");
|
||||
}
|
||||
|
||||
~uart_task()
|
||||
@ -72,8 +72,8 @@ public:
|
||||
|
||||
void set_read_cb(std::function<bool(uint8_t *data, size_t len)> f) override
|
||||
{
|
||||
ESP_MODEM_THROW_IF_FALSE(signal.wait(TASK_PARAMS, 1000), "Failed to set UART task params");
|
||||
on_read = std::move(f);
|
||||
signal.set(TASK_PARAMS);
|
||||
}
|
||||
|
||||
private:
|
||||
@ -118,7 +118,6 @@ std::unique_ptr<Terminal> create_uart_terminal(const esp_modem_dte_config *confi
|
||||
|
||||
void UartTerminal::task()
|
||||
{
|
||||
std::function<bool(uint8_t *data, size_t len)> on_read_priv = nullptr;
|
||||
uart_event_t event;
|
||||
size_t len;
|
||||
signal.set(TASK_INIT);
|
||||
@ -127,17 +126,15 @@ void UartTerminal::task()
|
||||
return; // exits to the static method where the task gets deleted
|
||||
}
|
||||
while (signal.is_any(TASK_START)) {
|
||||
signal.set(TASK_PARAMS);
|
||||
if (get_event(event, 100)) {
|
||||
if (signal.is_any(TASK_PARAMS)) {
|
||||
on_read_priv = on_read;
|
||||
signal.clear(TASK_PARAMS);
|
||||
}
|
||||
signal.clear(TASK_PARAMS);
|
||||
switch (event.type) {
|
||||
case UART_DATA:
|
||||
uart_get_buffered_data_len(uart.port, &len);
|
||||
if (len && on_read_priv) {
|
||||
if (on_read_priv(nullptr, len)) {
|
||||
on_read_priv = nullptr;
|
||||
if (len && on_read) {
|
||||
if (on_read(nullptr, len)) {
|
||||
on_read = nullptr;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -27,7 +27,7 @@ uart_resource::uart_resource(const esp_modem_uart_term_config *config, QueueHand
|
||||
{
|
||||
ESP_LOGD(TAG, "Creating uart resource" );
|
||||
struct termios tty = {};
|
||||
throw_if_false(tcgetattr(fd, &tty) == 0, "Failed to tcgetattr()");
|
||||
ESP_MODEM_THROW_IF_FALSE(tcgetattr(fd, &tty) == 0, "Failed to tcgetattr()");
|
||||
|
||||
tty.c_cflag &= ~PARENB;
|
||||
tty.c_cflag &= ~CSTOPB;
|
||||
|
@ -91,7 +91,7 @@ bool vfs_create_socket(struct esp_modem_vfs_socket_creator *config, struct esp_m
|
||||
}
|
||||
TRY_CATCH_OR_DO(
|
||||
int fd = -1;
|
||||
esp_modem::throw_if_esp_fail(hostname_to_fd(config->host_name, config->port, &fd));
|
||||
ESP_MODEM_THROW_IF_ERROR(hostname_to_fd(config->host_name, config->port, &fd));
|
||||
|
||||
// Set the FD to non-blocking mode
|
||||
int flags = fcntl(fd, F_GETFL, nullptr) | O_NONBLOCK;
|
||||
|
@ -48,7 +48,7 @@ bool vfs_create_uart(struct esp_modem_vfs_uart_creator *config, struct esp_modem
|
||||
}
|
||||
TRY_CATCH_OR_DO(
|
||||
int fd = open(config->dev_name, O_RDWR);
|
||||
esp_modem::throw_if_false(fd >= 0, "Cannot open the fd");
|
||||
ESP_MODEM_THROW_IF_FALSE(fd >= 0, "Cannot open the fd");
|
||||
|
||||
created_config->resource = new esp_modem_vfs_resource(&config->uart, fd);
|
||||
created_config->fd = fd;
|
||||
|
@ -17,6 +17,7 @@ int LoopbackTerm::write(uint8_t *data, size_t len)
|
||||
{
|
||||
if (inject_by) { // injection test: ignore what we write, but respond with injected data
|
||||
auto ret = std::async(&LoopbackTerm::batch_read, this);
|
||||
async_results.push_back(std::move(ret));
|
||||
return len;
|
||||
}
|
||||
if (len > 2 && (data[len - 1] == '\r' || data[len - 1] == '+') ) { // Simple AT responder
|
||||
@ -34,6 +35,8 @@ int LoopbackTerm::write(uint8_t *data, size_t len)
|
||||
response = "+CSQ: 123,456\n\r\nOK\r\n";
|
||||
} else if (command.find("AT+CGMM\r") != std::string::npos) {
|
||||
response = "0G Dummy Model\n\r\nOK\r\n";
|
||||
} else if (command.find("AT+COPS?\r") != std::string::npos) {
|
||||
response = "+COPS: 0,0,\"OperatorName\",5\n\r\nOK\r\n";
|
||||
} else if (command.find("AT+CBC\r") != std::string::npos) {
|
||||
response = is_bg96 ? "+CBC: 1,20,123456\r\r\n\r\nOK\r\n\n\r\n" :
|
||||
"+CBC: 123.456V\r\r\n\r\nOK\r\n\n\r\n";
|
||||
@ -97,7 +100,7 @@ LoopbackTerm::LoopbackTerm(bool is_bg96): loopback_data(), data_len(0), pin_ok(f
|
||||
|
||||
LoopbackTerm::LoopbackTerm(): loopback_data(), data_len(0), pin_ok(false), is_bg96(false), inject_by(0) {}
|
||||
|
||||
int LoopbackTerm::inject(uint8_t *data, size_t len, size_t injected_by)
|
||||
int LoopbackTerm::inject(uint8_t *data, size_t len, size_t injected_by, size_t delay_before, size_t delay_after)
|
||||
{
|
||||
if (data == nullptr) {
|
||||
inject_by = 0;
|
||||
@ -108,14 +111,20 @@ int LoopbackTerm::inject(uint8_t *data, size_t len, size_t injected_by)
|
||||
memcpy(&loopback_data[0], data, len);
|
||||
data_len = len;
|
||||
inject_by = injected_by;
|
||||
delay_after_inject = delay_after;
|
||||
delay_before_inject = delay_before;
|
||||
return len;
|
||||
}
|
||||
|
||||
void LoopbackTerm::batch_read()
|
||||
{
|
||||
while (data_len > 0) {
|
||||
on_read(nullptr, std::min(inject_by, data_len));
|
||||
Task::Delay(1);
|
||||
Task::Delay(delay_before_inject);
|
||||
{
|
||||
Scoped<Lock> lock(on_read_guard);
|
||||
on_read(nullptr, std::min(inject_by, data_len));
|
||||
}
|
||||
Task::Delay(delay_after_inject);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,7 @@ public:
|
||||
* inject_by defines batch sizes: the read callback is called multiple times
|
||||
* with partial data of `inject_by` size
|
||||
*/
|
||||
int inject(uint8_t *data, size_t len, size_t inject_by);
|
||||
int inject(uint8_t *data, size_t len, size_t inject_by,size_t delay_before=0, size_t delay_after=1);
|
||||
|
||||
void start() override;
|
||||
void stop() override;
|
||||
@ -26,6 +26,12 @@ public:
|
||||
|
||||
int read(uint8_t *data, size_t len) override;
|
||||
|
||||
void set_read_cb(std::function<bool(uint8_t *data, size_t len)> f) override
|
||||
{
|
||||
Scoped<Lock> lock(on_read_guard);
|
||||
on_read = std::move(f);
|
||||
}
|
||||
|
||||
private:
|
||||
enum class status_t {
|
||||
STARTED,
|
||||
@ -39,4 +45,9 @@ private:
|
||||
bool pin_ok;
|
||||
bool is_bg96;
|
||||
size_t inject_by;
|
||||
size_t delay_before_inject;
|
||||
size_t delay_after_inject;
|
||||
std::vector<std::future<void>> async_results;
|
||||
Lock on_read_guard;
|
||||
|
||||
};
|
||||
|
@ -7,6 +7,28 @@
|
||||
|
||||
using namespace esp_modem;
|
||||
|
||||
TEST_CASE("DTE command races", "[esp_modem]") {
|
||||
auto term = std::make_unique<LoopbackTerm>(true);
|
||||
auto loopback = term.get();
|
||||
auto dte = std::make_shared<DTE>(std::move(term));
|
||||
CHECK(term == nullptr);
|
||||
esp_modem_dce_config_t dce_config = ESP_MODEM_DCE_DEFAULT_CONFIG("APN");
|
||||
esp_netif_t netif{};
|
||||
auto dce = create_BG96_dce(&dce_config, dte, &netif);
|
||||
CHECK(dce != nullptr);
|
||||
uint8_t resp[] = {'O', 'K', '\n'};
|
||||
// run many commands in succession with the timeout set exactly to the timespan of injected reply
|
||||
// (checks for potential exception, data races, recycled local variables, etc.)
|
||||
for (int i=0; i<1000; ++i) {
|
||||
loopback->inject(&resp[0], sizeof(resp), sizeof(resp), /* 1ms before injecting reply */1, 0);
|
||||
auto ret = dce->command("AT\n", [&](uint8_t *data, size_t len) {
|
||||
return command_result::OK;
|
||||
}, 1);
|
||||
// this command should either timeout or finish successfully
|
||||
CHECK((ret == command_result::TIMEOUT || ret == command_result::OK));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Test polymorphic delete for custom device/dte", "[esp_modem]")
|
||||
{
|
||||
auto term = std::make_unique<LoopbackTerm>(true);
|
||||
@ -56,6 +78,14 @@ TEST_CASE("DCE AT parser", "[esp_modem]")
|
||||
std::string model;
|
||||
CHECK(dce->get_module_name(model) == command_result::OK);
|
||||
CHECK(model == "0G Dummy Model");
|
||||
|
||||
std::string operator_name;
|
||||
int act = 99;
|
||||
CHECK(dce->get_operator_name(operator_name) == command_result::OK);
|
||||
CHECK(operator_name == "OperatorName");
|
||||
CHECK(dce->get_operator_name(operator_name, act) == command_result::OK);
|
||||
CHECK(operator_name == "OperatorName");
|
||||
CHECK(act == 5);
|
||||
}
|
||||
|
||||
|
||||
|
@ -87,7 +87,7 @@ esp_err_t modem_init_network(esp_netif_t *netif)
|
||||
return NetModule::init(netif);
|
||||
}
|
||||
|
||||
void modem_start_network()
|
||||
esp_err_t modem_start_network()
|
||||
{
|
||||
NetModule::start();
|
||||
}
|
||||
|
@ -9,4 +9,5 @@ endif()
|
||||
idf_component_register(SRCS "esp_websocket_client.c"
|
||||
INCLUDE_DIRS "include"
|
||||
REQUIRES lwip esp-tls tcp_transport http_parser
|
||||
PRIV_REQUIRES esp_timer)
|
||||
PRIV_REQUIRES esp_timer esp_event)
|
||||
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")
|
||||
|
10
components/esp_websocket_client/Kconfig
Normal file
10
components/esp_websocket_client/Kconfig
Normal file
@ -0,0 +1,10 @@
|
||||
menu "ESP WebSocket client"
|
||||
|
||||
config ESP_WS_CLIENT_ENABLE_DYNAMIC_BUFFER
|
||||
bool "Enable websocket client dynamic buffer for send and receive data"
|
||||
default n
|
||||
help
|
||||
Enable this option will reallocated buffer when send or receive data and free them when end of use.
|
||||
This can save about 2 KB memory when no websocket data send and receive.
|
||||
|
||||
endmenu
|
@ -54,6 +54,9 @@ static const char *TAG = "WEBSOCKET_CLIENT";
|
||||
action; \
|
||||
}
|
||||
|
||||
#define WS_OVER_TCP_SCHEME "ws"
|
||||
#define WS_OVER_TLS_SCHEME "wss"
|
||||
|
||||
const static int STOPPED_BIT = BIT0;
|
||||
const static int CLOSE_FRAME_SENT_BIT = BIT1; // Indicates that a close frame was sent by the client
|
||||
// and we are waiting for the server to continue with clean close
|
||||
@ -78,6 +81,15 @@ typedef struct {
|
||||
char *headers;
|
||||
int pingpong_timeout_sec;
|
||||
size_t ping_interval_sec;
|
||||
const char *cert;
|
||||
size_t cert_len;
|
||||
const char *client_cert;
|
||||
size_t client_cert_len;
|
||||
const char *client_key;
|
||||
size_t client_key_len;
|
||||
bool use_global_ca_store;
|
||||
bool skip_cert_common_name_check;
|
||||
esp_err_t (*crt_bundle_attach)(void *conf);
|
||||
} websocket_config_storage_t;
|
||||
|
||||
typedef enum {
|
||||
@ -122,6 +134,45 @@ static uint64_t _tick_get_ms(void)
|
||||
return esp_timer_get_time()/1000;
|
||||
}
|
||||
|
||||
static esp_err_t esp_websocket_new_buf(esp_websocket_client_handle_t client, bool is_tx)
|
||||
{
|
||||
#ifdef CONFIG_ESP_WS_CLIENT_ENABLE_DYNAMIC_BUFFER
|
||||
if (is_tx) {
|
||||
if (client->tx_buffer) {
|
||||
free(client->tx_buffer);
|
||||
}
|
||||
|
||||
client->tx_buffer = calloc(1, client->buffer_size);
|
||||
ESP_WS_CLIENT_MEM_CHECK(TAG, client->tx_buffer, return ESP_ERR_NO_MEM);
|
||||
} else {
|
||||
if (client->rx_buffer) {
|
||||
free(client->rx_buffer);
|
||||
}
|
||||
|
||||
client->rx_buffer = calloc(1, client->buffer_size);
|
||||
ESP_WS_CLIENT_MEM_CHECK(TAG, client->rx_buffer, return ESP_ERR_NO_MEM);
|
||||
}
|
||||
#endif
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void esp_websocket_free_buf(esp_websocket_client_handle_t client, bool is_tx)
|
||||
{
|
||||
#ifdef CONFIG_ESP_WS_CLIENT_ENABLE_DYNAMIC_BUFFER
|
||||
if (is_tx) {
|
||||
if (client->tx_buffer) {
|
||||
free(client->tx_buffer);
|
||||
client->tx_buffer = NULL;
|
||||
}
|
||||
} else {
|
||||
if (client->rx_buffer) {
|
||||
free(client->rx_buffer);
|
||||
client->rx_buffer = NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static esp_err_t esp_websocket_client_dispatch_event(esp_websocket_client_handle_t client,
|
||||
esp_websocket_event_id_t event,
|
||||
const char *data,
|
||||
@ -308,6 +359,93 @@ static esp_err_t set_websocket_transport_optional_settings(esp_websocket_client_
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
static esp_err_t esp_websocket_client_create_transport(esp_websocket_client_handle_t client)
|
||||
{
|
||||
if (!client->config->scheme) {
|
||||
ESP_LOGE(TAG, "No scheme found");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
if (client->transport_list) {
|
||||
esp_transport_list_destroy(client->transport_list);
|
||||
client->transport_list = NULL;
|
||||
}
|
||||
|
||||
client->transport_list = esp_transport_list_init();
|
||||
ESP_WS_CLIENT_MEM_CHECK(TAG, client->transport_list, return ESP_ERR_NO_MEM);
|
||||
if (strcasecmp(client->config->scheme, WS_OVER_TCP_SCHEME) == 0) {
|
||||
esp_transport_handle_t tcp = esp_transport_tcp_init();
|
||||
ESP_WS_CLIENT_MEM_CHECK(TAG, tcp, return ESP_ERR_NO_MEM);
|
||||
|
||||
esp_transport_set_default_port(tcp, WEBSOCKET_TCP_DEFAULT_PORT);
|
||||
esp_transport_list_add(client->transport_list, tcp, "_tcp"); // need to save to transport list, for cleanup
|
||||
if (client->keep_alive_cfg.keep_alive_enable) {
|
||||
esp_transport_tcp_set_keep_alive(tcp, &client->keep_alive_cfg);
|
||||
}
|
||||
if (client->if_name) {
|
||||
esp_transport_tcp_set_interface_name(tcp, client->if_name);
|
||||
}
|
||||
|
||||
esp_transport_handle_t ws = esp_transport_ws_init(tcp);
|
||||
ESP_WS_CLIENT_MEM_CHECK(TAG, ws, return ESP_ERR_NO_MEM);
|
||||
|
||||
esp_transport_set_default_port(ws, WEBSOCKET_TCP_DEFAULT_PORT);
|
||||
esp_transport_list_add(client->transport_list, ws, WS_OVER_TCP_SCHEME);
|
||||
ESP_WS_CLIENT_ERR_OK_CHECK(TAG, set_websocket_transport_optional_settings(client, WS_OVER_TCP_SCHEME), return ESP_FAIL;)
|
||||
} else if (strcasecmp(client->config->scheme, WS_OVER_TLS_SCHEME) == 0) {
|
||||
esp_transport_handle_t ssl = esp_transport_ssl_init();
|
||||
ESP_WS_CLIENT_MEM_CHECK(TAG, ssl, return ESP_ERR_NO_MEM);
|
||||
|
||||
esp_transport_set_default_port(ssl, WEBSOCKET_SSL_DEFAULT_PORT);
|
||||
esp_transport_list_add(client->transport_list, ssl, "_ssl"); // need to save to transport list, for cleanup
|
||||
if (client->config->use_global_ca_store == true) {
|
||||
esp_transport_ssl_enable_global_ca_store(ssl);
|
||||
} else if (client->config->cert) {
|
||||
if (!client->config->cert_len) {
|
||||
esp_transport_ssl_set_cert_data(ssl, client->config->cert, strlen(client->config->cert));
|
||||
} else {
|
||||
esp_transport_ssl_set_cert_data_der(ssl, client->config->cert, client->config->cert_len);
|
||||
}
|
||||
}
|
||||
if (client->config->client_cert) {
|
||||
if (!client->config->client_cert_len) {
|
||||
esp_transport_ssl_set_client_cert_data(ssl, client->config->client_cert, strlen(client->config->client_cert));
|
||||
} else {
|
||||
esp_transport_ssl_set_client_cert_data_der(ssl, client->config->client_cert, client->config->client_cert_len);
|
||||
}
|
||||
}
|
||||
if (client->config->client_key) {
|
||||
if (!client->config->client_key_len) {
|
||||
esp_transport_ssl_set_client_key_data(ssl, client->config->client_key, strlen(client->config->client_key));
|
||||
} else {
|
||||
esp_transport_ssl_set_client_key_data_der(ssl, client->config->client_key, client->config->client_key_len);
|
||||
}
|
||||
}
|
||||
if (client->config->crt_bundle_attach) {
|
||||
#ifdef CONFIG_MBEDTLS_CERTIFICATE_BUNDLE
|
||||
esp_transport_ssl_crt_bundle_attach(ssl, client->config->crt_bundle_attach);
|
||||
#else //CONFIG_MBEDTLS_CERTIFICATE_BUNDLE
|
||||
ESP_LOGE(TAG, "crt_bundle_attach configured but not enabled in menuconfig: Please enable MBEDTLS_CERTIFICATE_BUNDLE option");
|
||||
#endif
|
||||
}
|
||||
if (client->config->skip_cert_common_name_check) {
|
||||
esp_transport_ssl_skip_common_name_check(ssl);
|
||||
}
|
||||
|
||||
esp_transport_handle_t wss = esp_transport_ws_init(ssl);
|
||||
ESP_WS_CLIENT_MEM_CHECK(TAG, wss, return ESP_ERR_NO_MEM);
|
||||
|
||||
esp_transport_set_default_port(wss, WEBSOCKET_SSL_DEFAULT_PORT);
|
||||
|
||||
esp_transport_list_add(client->transport_list, wss, WS_OVER_TLS_SCHEME);
|
||||
ESP_WS_CLIENT_ERR_OK_CHECK(TAG, set_websocket_transport_optional_settings(client, WS_OVER_TLS_SCHEME), return ESP_FAIL;)
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Not support this websocket scheme %s, only support %s and %s", client->config->scheme, WS_OVER_TCP_SCHEME, WS_OVER_TLS_SCHEME);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_websocket_client_handle_t esp_websocket_client_init(const esp_websocket_client_config_t *config)
|
||||
{
|
||||
esp_websocket_client_handle_t client = calloc(1, sizeof(struct esp_websocket_client));
|
||||
@ -343,83 +481,31 @@ esp_websocket_client_handle_t esp_websocket_client_init(const esp_websocket_clie
|
||||
client->config = calloc(1, sizeof(websocket_config_storage_t));
|
||||
ESP_WS_CLIENT_MEM_CHECK(TAG, client->config, goto _websocket_init_fail);
|
||||
|
||||
client->transport_list = esp_transport_list_init();
|
||||
ESP_WS_CLIENT_MEM_CHECK(TAG, client->transport_list, goto _websocket_init_fail);
|
||||
|
||||
esp_transport_handle_t tcp = esp_transport_tcp_init();
|
||||
ESP_WS_CLIENT_MEM_CHECK(TAG, tcp, goto _websocket_init_fail);
|
||||
|
||||
esp_transport_set_default_port(tcp, WEBSOCKET_TCP_DEFAULT_PORT);
|
||||
esp_transport_list_add(client->transport_list, tcp, "_tcp"); // need to save to transport list, for cleanup
|
||||
esp_transport_tcp_set_keep_alive(tcp, &client->keep_alive_cfg);
|
||||
esp_transport_tcp_set_interface_name(tcp, client->if_name);
|
||||
|
||||
esp_transport_handle_t ws = esp_transport_ws_init(tcp);
|
||||
ESP_WS_CLIENT_MEM_CHECK(TAG, ws, goto _websocket_init_fail);
|
||||
|
||||
esp_transport_set_default_port(ws, WEBSOCKET_TCP_DEFAULT_PORT);
|
||||
esp_transport_list_add(client->transport_list, ws, "ws");
|
||||
if (config->transport == WEBSOCKET_TRANSPORT_OVER_TCP) {
|
||||
asprintf(&client->config->scheme, "ws");
|
||||
asprintf(&client->config->scheme, WS_OVER_TCP_SCHEME);
|
||||
ESP_WS_CLIENT_MEM_CHECK(TAG, client->config->scheme, goto _websocket_init_fail);
|
||||
} else if (config->transport == WEBSOCKET_TRANSPORT_OVER_SSL) {
|
||||
asprintf(&client->config->scheme, WS_OVER_TLS_SCHEME);
|
||||
ESP_WS_CLIENT_MEM_CHECK(TAG, client->config->scheme, goto _websocket_init_fail);
|
||||
}
|
||||
|
||||
esp_transport_handle_t ssl = esp_transport_ssl_init();
|
||||
ESP_WS_CLIENT_MEM_CHECK(TAG, ssl, goto _websocket_init_fail);
|
||||
|
||||
esp_transport_set_default_port(ssl, WEBSOCKET_SSL_DEFAULT_PORT);
|
||||
esp_transport_list_add(client->transport_list, ssl, "_ssl"); // need to save to transport list, for cleanup
|
||||
if (config->use_global_ca_store == true) {
|
||||
esp_transport_ssl_enable_global_ca_store(ssl);
|
||||
} else if (config->cert_pem) {
|
||||
if (!config->cert_len) {
|
||||
esp_transport_ssl_set_cert_data(ssl, config->cert_pem, strlen(config->cert_pem));
|
||||
} else {
|
||||
esp_transport_ssl_set_cert_data_der(ssl, config->cert_pem, config->cert_len);
|
||||
}
|
||||
}
|
||||
if (config->client_cert) {
|
||||
if (!config->client_cert_len) {
|
||||
esp_transport_ssl_set_client_cert_data(ssl, config->client_cert, strlen(config->client_cert));
|
||||
} else {
|
||||
esp_transport_ssl_set_client_cert_data_der(ssl, config->client_cert, config->client_cert_len);
|
||||
}
|
||||
}
|
||||
if (config->client_key) {
|
||||
if (!config->client_key_len) {
|
||||
esp_transport_ssl_set_client_key_data(ssl, config->client_key, strlen(config->client_key));
|
||||
} else {
|
||||
esp_transport_ssl_set_client_key_data_der(ssl, config->client_key, config->client_key_len);
|
||||
}
|
||||
}
|
||||
|
||||
if (config->crt_bundle_attach) {
|
||||
#ifdef CONFIG_MBEDTLS_CERTIFICATE_BUNDLE
|
||||
esp_transport_ssl_crt_bundle_attach(ssl, config->crt_bundle_attach);
|
||||
#else //CONFIG_MBEDTLS_CERTIFICATE_BUNDLE
|
||||
ESP_LOGE(TAG, "crt_bundle_attach configured but not enabled in menuconfig: Please enable MBEDTLS_CERTIFICATE_BUNDLE option");
|
||||
#endif
|
||||
}
|
||||
|
||||
if (config->skip_cert_common_name_check) {
|
||||
esp_transport_ssl_skip_common_name_check(ssl);
|
||||
}
|
||||
if (config->reconnect_timeout_ms <= 0) {
|
||||
client->wait_timeout_ms = WEBSOCKET_RECONNECT_TIMEOUT_MS;
|
||||
ESP_LOGW(TAG, "`reconnect_timeout_ms` is not set, or it is less than or equal to zero, using default time out %d (milliseconds)", WEBSOCKET_RECONNECT_TIMEOUT_MS);
|
||||
} else {
|
||||
client->wait_timeout_ms = config->reconnect_timeout_ms;
|
||||
}
|
||||
esp_transport_handle_t wss = esp_transport_ws_init(ssl);
|
||||
ESP_WS_CLIENT_MEM_CHECK(TAG, wss, goto _websocket_init_fail);
|
||||
|
||||
esp_transport_set_default_port(wss, WEBSOCKET_SSL_DEFAULT_PORT);
|
||||
|
||||
esp_transport_list_add(client->transport_list, wss, "wss");
|
||||
if (config->transport == WEBSOCKET_TRANSPORT_OVER_SSL) {
|
||||
asprintf(&client->config->scheme, "wss");
|
||||
ESP_WS_CLIENT_MEM_CHECK(TAG, client->config->scheme, goto _websocket_init_fail);
|
||||
}
|
||||
// configure ssl related parameters
|
||||
client->config->use_global_ca_store = config->use_global_ca_store;
|
||||
client->config->cert = config->cert_pem;
|
||||
client->config->cert_len = config->cert_len;
|
||||
client->config->client_cert = config->client_cert;
|
||||
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;
|
||||
client->config->skip_cert_common_name_check = config->skip_cert_common_name_check;
|
||||
client->config->crt_bundle_attach = config->crt_bundle_attach;
|
||||
|
||||
if (config->uri) {
|
||||
if (esp_websocket_client_set_uri(client, config->uri) != ESP_OK) {
|
||||
@ -434,13 +520,10 @@ esp_websocket_client_handle_t esp_websocket_client_init(const esp_websocket_clie
|
||||
}
|
||||
|
||||
if (client->config->scheme == NULL) {
|
||||
asprintf(&client->config->scheme, "ws");
|
||||
asprintf(&client->config->scheme, WS_OVER_TCP_SCHEME);
|
||||
ESP_WS_CLIENT_MEM_CHECK(TAG, client->config->scheme, goto _websocket_init_fail);
|
||||
}
|
||||
|
||||
ESP_WS_CLIENT_ERR_OK_CHECK(TAG, set_websocket_transport_optional_settings(client, "ws"), goto _websocket_init_fail;)
|
||||
ESP_WS_CLIENT_ERR_OK_CHECK(TAG, set_websocket_transport_optional_settings(client, "wss"), goto _websocket_init_fail;)
|
||||
|
||||
client->keepalive_tick_ms = _tick_get_ms();
|
||||
client->reconnect_tick_ms = _tick_get_ms();
|
||||
client->ping_tick_ms = _tick_get_ms();
|
||||
@ -450,6 +533,7 @@ esp_websocket_client_handle_t esp_websocket_client_init(const esp_websocket_clie
|
||||
if (buffer_size <= 0) {
|
||||
buffer_size = WEBSOCKET_BUFFER_SIZE_BYTE;
|
||||
}
|
||||
#ifndef CONFIG_ESP_WS_CLIENT_ENABLE_DYNAMIC_BUFFER
|
||||
client->rx_buffer = malloc(buffer_size);
|
||||
ESP_WS_CLIENT_MEM_CHECK(TAG, client->rx_buffer, {
|
||||
goto _websocket_init_fail;
|
||||
@ -458,6 +542,7 @@ esp_websocket_client_handle_t esp_websocket_client_init(const esp_websocket_clie
|
||||
ESP_WS_CLIENT_MEM_CHECK(TAG, client->tx_buffer, {
|
||||
goto _websocket_init_fail;
|
||||
});
|
||||
#endif
|
||||
client->status_bits = xEventGroupCreate();
|
||||
ESP_WS_CLIENT_MEM_CHECK(TAG, client->status_bits, {
|
||||
goto _websocket_init_fail;
|
||||
@ -566,10 +651,15 @@ static esp_err_t esp_websocket_client_recv(esp_websocket_client_handle_t client)
|
||||
{
|
||||
int rlen;
|
||||
client->payload_offset = 0;
|
||||
if (esp_websocket_new_buf(client, false) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to setup rx buffer");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
do {
|
||||
rlen = esp_transport_read(client->transport, client->rx_buffer, client->buffer_size, client->config->network_timeout_ms);
|
||||
if (rlen < 0) {
|
||||
ESP_LOGE(TAG, "Error read data");
|
||||
esp_websocket_free_buf(client, false);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
client->payload_len = esp_transport_ws_get_read_payload_len(client->transport);
|
||||
@ -578,6 +668,7 @@ static esp_err_t esp_websocket_client_recv(esp_websocket_client_handle_t client)
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -598,7 +689,7 @@ static esp_err_t esp_websocket_client_recv(esp_websocket_client_handle_t client)
|
||||
ESP_LOGD(TAG, "Received close frame");
|
||||
client->state = WEBSOCKET_STATE_CLOSING;
|
||||
}
|
||||
|
||||
esp_websocket_free_buf(client, false);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@ -757,6 +848,11 @@ esp_err_t esp_websocket_client_start(esp_websocket_client_handle_t client)
|
||||
ESP_LOGE(TAG, "The client has started");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
if (esp_websocket_client_create_transport(client) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to create websocket transport");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
if (xTaskCreate(esp_websocket_client_task, "websocket_task", client->config->task_stack, client, client->config->task_prio, &client->task_handle) != pdTRUE) {
|
||||
ESP_LOGE(TAG, "Error create websocket task");
|
||||
return ESP_FAIL;
|
||||
@ -890,6 +986,10 @@ static int esp_websocket_client_send_with_opcode(esp_websocket_client_handle_t c
|
||||
ESP_LOGE(TAG, "Invalid transport");
|
||||
goto unlock_and_return;
|
||||
}
|
||||
if (esp_websocket_new_buf(client, true) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to setup tx buffer");
|
||||
goto unlock_and_return;
|
||||
}
|
||||
uint32_t current_opcode = opcode;
|
||||
while (widx < len || current_opcode) { // allow for sending "current_opcode" only message with len==0
|
||||
if (need_write > client->buffer_size) {
|
||||
@ -904,6 +1004,7 @@ static int esp_websocket_client_send_with_opcode(esp_websocket_client_handle_t c
|
||||
if (wlen < 0 || (wlen == 0 && need_write != 0)) {
|
||||
ret = wlen;
|
||||
ESP_LOGE(TAG, "Network error: esp_transport_write() returned %d, errno=%d", ret, errno);
|
||||
esp_websocket_free_buf(client, true);
|
||||
esp_websocket_client_abort_connection(client);
|
||||
goto unlock_and_return;
|
||||
}
|
||||
@ -913,6 +1014,7 @@ static int esp_websocket_client_send_with_opcode(esp_websocket_client_handle_t c
|
||||
|
||||
}
|
||||
ret = widx;
|
||||
esp_websocket_free_buf(client, true);
|
||||
unlock_and_return:
|
||||
xSemaphoreGiveRecursive(client->lock);
|
||||
return ret;
|
||||
|
@ -1,2 +1,3 @@
|
||||
idf_component_register(SRCS "websocket_example.c"
|
||||
INCLUDE_DIRS ".")
|
||||
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "esp_log.h"
|
||||
#include "esp_websocket_client.h"
|
||||
#include "esp_event.h"
|
||||
#include <cJSON.h>
|
||||
|
||||
#define NO_DATA_TIMEOUT_SEC 5
|
||||
|
||||
@ -74,6 +75,19 @@ static void websocket_event_handler(void *handler_args, esp_event_base_t base, i
|
||||
} else {
|
||||
ESP_LOGW(TAG, "Received=%.*s", data->data_len, (char *)data->data_ptr);
|
||||
}
|
||||
|
||||
// If received data contains json structure it succeed to parse
|
||||
cJSON *root = cJSON_Parse(data->data_ptr);
|
||||
if (root) {
|
||||
for (int i = 0 ; i < cJSON_GetArraySize(root) ; i++) {
|
||||
cJSON *elem = cJSON_GetArrayItem(root, i);
|
||||
cJSON *id = cJSON_GetObjectItem(elem, "id");
|
||||
cJSON *name = cJSON_GetObjectItem(elem, "name");
|
||||
ESP_LOGW(TAG, "Json={'id': '%s', 'name': '%s'}", id->valuestring, name->valuestring);
|
||||
}
|
||||
cJSON_Delete(root);
|
||||
}
|
||||
|
||||
ESP_LOGW(TAG, "Total payload length=%d, data_len=%d, current payload offset=%d\r\n", data->payload_len, data->data_len, data->payload_offset);
|
||||
|
||||
xTimerReset(shutdown_signal_timer, portMAX_DELAY);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user