forked from espressif/esp-protocols
Compare commits
121 Commits
mdns-v1.5.
...
fixes
Author | SHA1 | Date | |
---|---|---|---|
e11e1136e1 | |||
1c2ee55459 | |||
3be87562ad | |||
a6fe9525e1 | |||
bd6bf6df26 | |||
5187d3f94e | |||
1d49013fc6 | |||
b8cdd373f4 | |||
66a5ac0190 | |||
40cce5e926 | |||
1b1ede435d | |||
c6f08ee961 | |||
a21ce883ef | |||
79d6fa2607 | |||
ad90558420 | |||
8541753443 | |||
6660f71d03 | |||
57cd60807e | |||
03dd8006b2 | |||
3863c26b79 | |||
1d1ff365c2 | |||
ef3870573c | |||
ad94cc9502 | |||
4885d28294 | |||
df00a03084 | |||
e2fa11103c | |||
d2e94e5db2 | |||
bc8ac4c684 | |||
b710dbd2ad | |||
5eeb29cb94 | |||
a00117fbdb | |||
6ed672da7b | |||
1b4baaed0e | |||
74b7d85d4a | |||
317faf89ff | |||
b97dfc08b8 | |||
e9d7350219 | |||
61da30b013 | |||
8fd2c99f15 | |||
8560f02191 | |||
703c49297f | |||
2fe8345fa5 | |||
3fc26a5e5c | |||
5db6be7422 | |||
8ca45f34fa | |||
2e28774228 | |||
e14e21ab32 | |||
6f00c369fc | |||
905b84fb97 | |||
d7f5322a39 | |||
eb12d05bf3 | |||
520b8194fc | |||
40142cdcfd | |||
c7663cdef2 | |||
e01e67e7eb | |||
37f84ee5a4 | |||
95b56600ed | |||
a22c3da49e | |||
5d0fd5c1c5 | |||
7ea6879a19 | |||
2db11bbb8c | |||
cdb7bfd188 | |||
c679ceed85 | |||
c009892968 | |||
5f66f35f5f | |||
dea5f1c431 | |||
384d1c23ba | |||
88162d1f3a | |||
e65f22ab6c | |||
7d29b47676 | |||
f1a72ec42c | |||
ce160505dc | |||
87e96b4682 | |||
5b2077e373 | |||
030cb75ece | |||
b45fe143a4 | |||
ee2fbbbee7 | |||
cb061c9c38 | |||
0690eba3a8 | |||
eb4ab52487 | |||
8fcad10ccf | |||
936e43f9d8 | |||
64d818b2d3 | |||
cd07228f81 | |||
1c6580e22b | |||
87f835af0f | |||
85a8dac42d | |||
39866116f5 | |||
7740b591b6 | |||
b57979d967 | |||
42674b49f9 | |||
e069ae7762 | |||
44d476fc50 | |||
55385ec312 | |||
a3c2bbed9e | |||
84c47c37f1 | |||
e7273c46ec | |||
2e7d240abd | |||
d4a004b5b4 | |||
9046af8f8d | |||
eeeb9006eb | |||
b167aa315f | |||
72ba24470d | |||
7dc87d28b2 | |||
ac6a388cdd | |||
76aaea08d2 | |||
5db32cce30 | |||
9bdd429c7c | |||
6f7c52cc3f | |||
27435b7f34 | |||
813331f003 | |||
bd23c233a4 | |||
4eda7d472f | |||
163029c0b6 | |||
96eae25096 | |||
ebec8eff63 | |||
4451a8c5ad | |||
6d19aabb02 | |||
9162de1150 | |||
dbd164dd91 | |||
90d663ad01 |
@ -13,7 +13,7 @@ jobs:
|
||||
name: Build
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest", "release-v5.0", "release-v5.1", "release-v5.2", "release-v5.3"]
|
||||
idf_ver: ["latest", "release-v5.0", "release-v5.1", "release-v5.2", "release-v5.3", "release-v5.4"]
|
||||
idf_target: ["esp32", "esp32s2"]
|
||||
example: ["asio_chat", "async_request", "socks4", "ssl_client_server", "tcp_echo_server", "udp_echo_server"]
|
||||
runs-on: ubuntu-22.04
|
||||
@ -64,7 +64,7 @@ jobs:
|
||||
name: Target tests
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest", "release-v5.0", "release-v5.2", "release-v5.3"]
|
||||
idf_ver: ["latest", "release-v5.1", "release-v5.2", "release-v5.3", "release-v5.4"]
|
||||
idf_target: ["esp32"]
|
||||
example: ["asio_chat", "tcp_echo_server", "udp_echo_server", "ssl_client_server"]
|
||||
needs: build_asio
|
||||
|
8
.github/workflows/clang-tidy.yml
vendored
8
.github/workflows/clang-tidy.yml
vendored
@ -9,12 +9,12 @@ on:
|
||||
jobs:
|
||||
build:
|
||||
name: Run clang-tidy
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
container: espressif/idf:latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: 'true'
|
||||
submodules: recursive
|
||||
- name: Install esp-clang
|
||||
run: |
|
||||
${IDF_PATH}/tools/idf_tools.py --non-interactive install esp-clang
|
||||
@ -50,7 +50,7 @@ jobs:
|
||||
results.sarif
|
||||
results.sarif.raw
|
||||
- name: Upload SARIF file
|
||||
uses: github/codeql-action/upload-sarif@v2
|
||||
uses: github/codeql-action/upload-sarif@v3
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
category: clang-tidy
|
||||
|
2
.github/workflows/eppp__build.yml
vendored
2
.github/workflows/eppp__build.yml
vendored
@ -15,7 +15,7 @@ jobs:
|
||||
matrix:
|
||||
idf_ver: ["latest", "release-v5.3"]
|
||||
test: [ { app: host, path: "examples/host" }, { app: slave, path: "examples/slave" }, { app: test_app, path: "test/test_app" }]
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
|
38
.github/workflows/esp_dns__build.yml
vendored
Normal file
38
.github/workflows/esp_dns__build.yml
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
name: "esp_dns: build-tests"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, labeled]
|
||||
|
||||
jobs:
|
||||
build_esp_dns:
|
||||
if: contains(github.event.pull_request.labels.*.name, 'dns') || github.event_name == 'push'
|
||||
name: Build
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest", "release-v5.1", "release-v5.2", "release-v5.3", "release-v5.4"]
|
||||
idf_target: ["esp32"]
|
||||
test: [ { app: esp_dns_basic, path: "components/esp_dns/examples"}]
|
||||
include:
|
||||
- idf_ver: "latest"
|
||||
warning: "the choice symbol ETHERNET_PHY_LAN867X\nis deprecated: Please use smi_gpio instead"
|
||||
|
||||
runs-on: ubuntu-22.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Build ${{ matrix.test.app }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
|
||||
env:
|
||||
EXPECTED_WARNING: ${{ matrix.warning }}
|
||||
shell: bash
|
||||
working-directory: ${{matrix.test.path}}
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
pip install idf-component-manager idf-build-apps --upgrade
|
||||
python ../../../ci/build_apps.py ./${{ matrix.test.app }} --target ${{ matrix.idf_target }} -vv --preserve-all --pytest-app
|
50
.github/workflows/examples_build-host-test.yml
vendored
50
.github/workflows/examples_build-host-test.yml
vendored
@ -13,12 +13,15 @@ jobs:
|
||||
name: Build examples
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest", "release-v5.1", "release-v5.2", "release-v5.3"]
|
||||
idf_ver: ["latest", "release-v5.1", "release-v5.2", "release-v5.3", "release-v5.4"]
|
||||
include:
|
||||
- idf_ver: "latest"
|
||||
warning: "Warning: The smallest app partition is nearly full"
|
||||
runs-on: ubuntu-22.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
env:
|
||||
TARGET_TEST: examples/esp_netif/slip_custom_netif/
|
||||
TARGET_TEST_DIR: build_esp32c3_target
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v4
|
||||
@ -31,6 +34,16 @@ jobs:
|
||||
python -m pip install idf-build-apps
|
||||
# Build default configs for all targets
|
||||
python ./ci/build_apps.py examples -m examples/.build-test-rules.yml -d -c
|
||||
# Build target tests
|
||||
python ./ci/build_apps.py ${TARGET_TEST} -r sdkconfig.ci=target
|
||||
cd ${TARGET_TEST}
|
||||
${GITHUB_WORKSPACE}/ci/clean_build_artifacts.sh `pwd`/${TARGET_TEST_DIR}
|
||||
zip -qur artifacts.zip ${TARGET_TEST_DIR}
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: slip_target_${{ matrix.idf_ver }}
|
||||
path: ${{ env.TARGET_TEST }}/artifacts.zip
|
||||
if-no-files-found: error
|
||||
|
||||
build_and_run_on_host:
|
||||
if: contains(github.event.pull_request.labels.*.name, 'examples') || github.event_name == 'push'
|
||||
@ -51,3 +64,38 @@ jobs:
|
||||
python ./ci/build_apps.py examples/mqtt -l -t linux
|
||||
timeout 5 ./examples/mqtt/build_linux_default/esp_mqtt_demo.elf | tee test.log || true
|
||||
grep 'MQTT_EVENT_DATA' test.log
|
||||
|
||||
run_on_target:
|
||||
# Skip running on forks since it won't have access to secrets
|
||||
if: |
|
||||
github.repository == 'espressif/esp-protocols' &&
|
||||
( contains(github.event.pull_request.labels.*.name, 'examples') || github.event_name == 'push' )
|
||||
name: Slip example target test
|
||||
needs: build_all_examples
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["release-v5.4", "latest"]
|
||||
runs-on:
|
||||
- self-hosted
|
||||
- modem
|
||||
env:
|
||||
TARGET_TEST: examples/esp_netif/slip_custom_netif/
|
||||
TARGET_TEST_DIR: build_esp32c3_target
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: slip_target_${{ matrix.idf_ver }}
|
||||
path: ${{ env.TARGET_TEST }}/ci/
|
||||
- name: Run Test
|
||||
working-directory: ${{ env.TARGET_TEST }}
|
||||
run: |
|
||||
python -m venv .venv
|
||||
source .venv/bin/activate
|
||||
pip install --prefer-binary cryptography pytest-embedded pytest-embedded-serial-esp pytest-embedded-idf pytest-custom_exit_code esptool netifaces
|
||||
unzip ci/artifacts.zip -d ci
|
||||
for dir in `ls -d ci/build_*`; do
|
||||
rm -rf build sdkconfig.defaults
|
||||
mv $dir build
|
||||
python -m pytest --log-cli-level DEBUG --target=esp32c3
|
||||
done
|
||||
|
86
.github/workflows/lws_build.yml
vendored
Normal file
86
.github/workflows/lws_build.yml
vendored
Normal file
@ -0,0 +1,86 @@
|
||||
name: "lws: build-tests"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, labeled]
|
||||
|
||||
jobs:
|
||||
build_lws:
|
||||
if: contains(github.event.pull_request.labels.*.name, 'lws') || github.event_name == 'push'
|
||||
name: Libwebsockets build
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest", "release-v5.3", "release-v5.4"]
|
||||
test: [ { app: example, path: "examples/client" }]
|
||||
runs-on: ubuntu-22.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
env:
|
||||
TEST_DIR: components/libwebsockets/${{ matrix.test.path }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }}
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
python -m pip install idf-build-apps
|
||||
python ./ci/build_apps.py ${TEST_DIR}
|
||||
cd ${TEST_DIR}
|
||||
for dir in `ls -d build_esp32_*`; do
|
||||
$GITHUB_WORKSPACE/ci/clean_build_artifacts.sh `pwd`/$dir
|
||||
zip -qur artifacts.zip $dir
|
||||
done
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: lws_target_esp32_${{ matrix.idf_ver }}_${{ matrix.test.app }}
|
||||
path: ${{ env.TEST_DIR }}/artifacts.zip
|
||||
if-no-files-found: error
|
||||
|
||||
run-target-lws:
|
||||
# Skip running on forks since it won't have access to secrets
|
||||
if: |
|
||||
github.repository == 'espressif/esp-protocols' &&
|
||||
( contains(github.event.pull_request.labels.*.name, 'lws') || github.event_name == 'push' )
|
||||
name: Target test
|
||||
needs: build_lws
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
idf_ver: ["latest", "release-v5.3", "release-v5.4"]
|
||||
idf_target: ["esp32"]
|
||||
test: [ { app: example, path: "examples/client" }]
|
||||
runs-on:
|
||||
- self-hosted
|
||||
- ESP32-ETHERNET-KIT
|
||||
env:
|
||||
TEST_DIR: components/libwebsockets/${{ matrix.test.path }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: lws_target_esp32_${{ matrix.idf_ver }}_${{ matrix.test.app }}
|
||||
path: ${{ env.TEST_DIR }}/ci/
|
||||
- name: Install Python packages
|
||||
env:
|
||||
PIP_EXTRA_INDEX_URL: "https://www.piwheels.org/simple"
|
||||
run: |
|
||||
pip install --only-binary cryptography --extra-index-url https://dl.espressif.com/pypi/ -r $GITHUB_WORKSPACE/ci/requirements.txt
|
||||
- name: Run Example Test on target
|
||||
working-directory: ${{ env.TEST_DIR }}
|
||||
run: |
|
||||
unzip ci/artifacts.zip -d ci
|
||||
for dir in `ls -d ci/build_*`; do
|
||||
rm -rf build sdkconfig.defaults
|
||||
mv $dir build
|
||||
python -m pytest --log-cli-level DEBUG --junit-xml=./results_${{ matrix.test.app }}_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${dir#"ci/build_"}.xml --target=${{ matrix.idf_target }}
|
||||
done
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: always()
|
||||
with:
|
||||
name: results_${{ matrix.test.app }}_${{ matrix.idf_target }}_${{ matrix.idf_ver }}.xml
|
||||
path: components/libwebsockets/${{ matrix.test.path }}/*.xml
|
24
.github/workflows/mdns__host-tests.yml
vendored
24
.github/workflows/mdns__host-tests.yml
vendored
@ -35,30 +35,36 @@ jobs:
|
||||
# Next we run the pytest (using the console app)
|
||||
pytest
|
||||
|
||||
build_afl_host_test_mdns:
|
||||
host_compat_checks:
|
||||
if: contains(github.event.pull_request.labels.*.name, 'mdns') || github.event_name == 'push'
|
||||
name: Build AFL host test
|
||||
name: Set of compatibility checks
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest"]
|
||||
idf_target: ["esp32"]
|
||||
|
||||
runs-on: ubuntu-22.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: esp-protocols
|
||||
- name: Install Necessary Libs
|
||||
run: |
|
||||
apt-get update -y
|
||||
apt-get install -y libbsd-dev
|
||||
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
|
||||
env:
|
||||
IDF_TARGET: ${{ matrix.idf_target }}
|
||||
- name: Test AFL compat build
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
cd $GITHUB_WORKSPACE/esp-protocols/components/mdns/tests/test_afl_fuzz_host/
|
||||
cd components/mdns/tests/test_afl_fuzz_host/
|
||||
make INSTR=off
|
||||
- name: Test no malloc functions
|
||||
shell: bash
|
||||
run: |
|
||||
cd components/mdns
|
||||
for file in $(ls *.c); do
|
||||
cp $file /tmp
|
||||
echo -n "Checking that $file does not call any std allocations directly..."
|
||||
python mem_prefix_script.py $file
|
||||
diff -q $file /tmp/$file || exit 1
|
||||
echo "OK"
|
||||
done
|
||||
|
18
.github/workflows/modem__build-host-tests.yml
vendored
18
.github/workflows/modem__build-host-tests.yml
vendored
@ -91,3 +91,21 @@ jobs:
|
||||
run_executable: false
|
||||
run_coverage: false
|
||||
pre_run_script: "esp-protocols/components/esp_modem/test/host_test/env.sh"
|
||||
|
||||
esp_modem_generated_commands:
|
||||
if: contains(github.event.pull_request.labels.*.name, 'modem') || github.event_name == 'push'
|
||||
name: Generated commands compatibility
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v4
|
||||
- name: Compat check
|
||||
shell: bash
|
||||
run: |
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y astyle
|
||||
cd components/esp_modem
|
||||
find examples/ -type f -regex '.*/generate/.*\.\(hpp\|cpp\)' -exec ./scripts/generate.sh {} \;
|
||||
./scripts/generate.sh
|
||||
git diff --name-only
|
||||
git diff --quiet
|
||||
|
4
.github/workflows/modem__target-test.yml
vendored
4
.github/workflows/modem__target-test.yml
vendored
@ -42,7 +42,7 @@ jobs:
|
||||
idf.py set-target ${{ matrix.idf_target }}
|
||||
idf.py build
|
||||
$GITHUB_WORKSPACE/ci/clean_build_artifacts.sh ${GITHUB_WORKSPACE}/${TEST_DIR}/build
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: modem_target_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.test.app }}
|
||||
path: ${{ env.TEST_DIR }}/build
|
||||
@ -75,7 +75,7 @@ jobs:
|
||||
run: |
|
||||
sudo rm -fr $GITHUB_WORKSPACE && mkdir $GITHUB_WORKSPACE
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/download-artifact@v3
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: modem_target_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.test.app }}
|
||||
path: ${{ env.TEST_DIR }}/build
|
||||
|
77
.github/workflows/mosq__build.yml
vendored
77
.github/workflows/mosq__build.yml
vendored
@ -101,3 +101,80 @@ jobs:
|
||||
exit 1
|
||||
fi
|
||||
echo "Versions are consistent: $CONFIG_VERSION"
|
||||
|
||||
build_idf_tests_with_mosq:
|
||||
if: |
|
||||
github.repository == 'espressif/esp-protocols' &&
|
||||
( contains(github.event.pull_request.labels.*.name, 'mosquitto') || github.event_name == 'push' )
|
||||
name: Build IDF tests
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest"]
|
||||
idf_target: ["esp32"]
|
||||
test: [ { app: publish, path: "tools/test_apps/protocols/mqtt/publish_connect_test" }]
|
||||
runs-on: ubuntu-22.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
env:
|
||||
TARGET_TEST_DIR: build_esp32_local_broker
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Build ${{ matrix.test.app }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
pip install idf-component-manager idf-build-apps --upgrade
|
||||
export MOSQUITTO_PATH=`pwd`/components/mosquitto
|
||||
# to use the actual version of mosquitto
|
||||
sed -i '/espressif\/mosquitto:/a \ \ \ \ override_path: "${MOSQUITTO_PATH}"' ${IDF_PATH}/${{matrix.test.path}}/main/idf_component.yml
|
||||
export PEDANTIC_FLAGS="-DIDF_CI_BUILD -Werror -Werror=deprecated-declarations -Werror=unused-variable -Werror=unused-but-set-variable -Werror=unused-function"
|
||||
export EXTRA_CFLAGS="${PEDANTIC_FLAGS} -Wstrict-prototypes"
|
||||
export EXTRA_CXXFLAGS="${PEDANTIC_FLAGS}"
|
||||
cd ${IDF_PATH}/${{matrix.test.path}}
|
||||
idf-build-apps find --config sdkconfig.ci.local_broker -vv --target ${{ matrix.idf_target }} --build-dir=${TARGET_TEST_DIR}
|
||||
idf-build-apps build --config sdkconfig.ci.local_broker -vv --target ${{ matrix.idf_target }} --build-dir=${TARGET_TEST_DIR}
|
||||
${GITHUB_WORKSPACE}/ci/clean_build_artifacts.sh `pwd`/${TARGET_TEST_DIR}
|
||||
# to replace mqtt test configs with specific mosquitto markers
|
||||
python ${MOSQUITTO_PATH}/test/replace_decorators.py pytest_mqtt_publish_app.py ${TARGET_TEST_DIR}/pytest_mosquitto.py
|
||||
zip -qur ${GITHUB_WORKSPACE}/artifacts.zip ${TARGET_TEST_DIR}
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: mosq_publish_esp32_${{ matrix.idf_ver }}
|
||||
path: artifacts.zip
|
||||
if-no-files-found: error
|
||||
|
||||
test_idf_ci_with_mosq:
|
||||
# Skip running on forks since it won't have access to secrets
|
||||
if: |
|
||||
github.repository == 'espressif/esp-protocols' &&
|
||||
( contains(github.event.pull_request.labels.*.name, 'mosquitto') || github.event_name == 'push' )
|
||||
name: Mosquitto IDF target tests
|
||||
needs: build_idf_tests_with_mosq
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest"]
|
||||
runs-on:
|
||||
- self-hosted
|
||||
- ESP32-ETHERNET-KIT
|
||||
env:
|
||||
TEST_DIR: examples
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: mosq_publish_esp32_${{ matrix.idf_ver }}
|
||||
path: ${{ env.TEST_DIR }}/ci/
|
||||
- name: Run Test
|
||||
working-directory: ${{ env.TEST_DIR }}
|
||||
run: |
|
||||
python -m pip install pytest-embedded-serial-esp pytest-embedded-idf pytest-rerunfailures pytest-timeout pytest-ignore-test-results "paho-mqtt<2" --upgrade
|
||||
unzip ci/artifacts.zip -d ci
|
||||
for dir in `ls -d ci/build_*`; do
|
||||
rm -rf build sdkconfig.defaults
|
||||
mv $dir build
|
||||
mv build/*.py .
|
||||
# Run only "test_mosquitto" marked tests
|
||||
python -m pytest --log-cli-level DEBUG --junit-xml=./results_esp32_${{ matrix.idf_ver }}_${dir#"ci/build_"}.xml --target=esp32 -m test_mosquitto
|
||||
done
|
||||
|
2
.github/workflows/publish-docs-component.yml
vendored
2
.github/workflows/publish-docs-component.yml
vendored
@ -102,5 +102,7 @@ jobs:
|
||||
components/mbedtls_cxx;
|
||||
components/mosquitto;
|
||||
components/sock_utils;
|
||||
components/libwebsockets;
|
||||
components/esp_dns;
|
||||
namespace: "espressif"
|
||||
api_token: ${{ secrets.IDF_COMPONENT_API_TOKEN }}
|
||||
|
2
.github/workflows/tls_cxx__build.yml
vendored
2
.github/workflows/tls_cxx__build.yml
vendored
@ -15,7 +15,7 @@ jobs:
|
||||
matrix:
|
||||
idf_ver: ["latest", "release-v5.3", "release-v5.2", "release-v5.1"]
|
||||
test: [ { app: client, path: "examples/tls_client" }, { app: udp, path: "examples/udp_mutual_auth" }, { app: test, path: "tests/uart_mutual_auth" } ]
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
|
5
.gitmodules
vendored
5
.gitmodules
vendored
@ -1,6 +1,9 @@
|
||||
[submodule "components/asio/asio"]
|
||||
path = components/asio/asio
|
||||
url = https://github.com/espressif/asio
|
||||
url = https://github.com/chriskohlhoff/asio
|
||||
[submodule "components/mosquitto/mosquitto"]
|
||||
path = components/mosquitto/mosquitto
|
||||
url = https://github.com/eclipse/mosquitto
|
||||
[submodule "components/libwebsockets/libwebsockets"]
|
||||
path = components/libwebsockets/libwebsockets
|
||||
url = https://github.com/warmcat/libwebsockets.git
|
||||
|
@ -51,7 +51,7 @@ repos:
|
||||
rev: v1.0.5
|
||||
hooks:
|
||||
- id: astyle_py
|
||||
args: ['--style=otbs', '--attach-namespaces', '--attach-classes', '--indent=spaces=4', '--convert-tabs', '--align-pointer=name', '--align-reference=name', '--keep-one-line-statements', '--pad-header', '--pad-oper', '--exclude-list=ci/ignore_astyle.txt']
|
||||
args: ['--style=otbs', '--attach-namespaces', '--attach-classes', '--indent=spaces=4', '--convert-tabs', '--align-reference=name', '--keep-one-line-statements', '--pad-header', '--pad-oper', '--unpad-paren', '--max-continuation-indent=120', '--exclude-list=ci/ignore_astyle.txt']
|
||||
- repo: https://github.com/commitizen-tools/commitizen
|
||||
rev: v2.42.1
|
||||
hooks:
|
||||
@ -61,8 +61,8 @@ repos:
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: commit message scopes
|
||||
name: "commit message must be scoped with: mdns, modem, websocket, asio, mqtt_cxx, console, common, eppp, tls_cxx, mosq, sockutls"
|
||||
entry: '\A(?!(feat|fix|ci|bump|test|docs|chore)\((mdns|modem|common|console|websocket|asio|mqtt_cxx|examples|eppp|tls_cxx|mosq|sockutls)\)\:)'
|
||||
name: "commit message must be scoped with: mdns, dns, modem, websocket, asio, mqtt_cxx, console, common, eppp, tls_cxx, mosq, sockutls, lws"
|
||||
entry: '\A(?!(feat|fix|ci|bump|test|docs|chore)\((mdns|dns|modem|common|console|websocket|asio|mqtt_cxx|examples|eppp|tls_cxx|mosq|sockutls|lws)\)\:)'
|
||||
language: pygrep
|
||||
args: [--multiline]
|
||||
stages: [commit-msg]
|
||||
|
12
README.md
12
README.md
@ -66,3 +66,15 @@ Please refer to instructions in [ESP-IDF](https://github.com/espressif/esp-idf)
|
||||
### Socket helpers (sock-utils)
|
||||
|
||||
* Brief introduction [README](components/sock_utils/README.md)
|
||||
|
||||
### libwebsockets
|
||||
|
||||
* Brief introduction [README](components/libwebsockets/README.md)
|
||||
|
||||
### console_cmd_mqtt
|
||||
|
||||
* Brief introduction [README](components/console_cmd_mqtt/README.md)
|
||||
|
||||
### esp_dns
|
||||
|
||||
* Brief introduction [README](components/esp_dns/README.md)
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -64,7 +64,7 @@ static struct generic_queue_handle *create_generic_queue(queue_type_t type, uint
|
||||
return h;
|
||||
}
|
||||
|
||||
QueueHandle_t xQueueCreate(uint32_t uxQueueLength, uint32_t uxItemSize )
|
||||
QueueHandle_t xQueueCreate(uint32_t uxQueueLength, uint32_t uxItemSize)
|
||||
{
|
||||
return (QueueHandle_t)create_generic_queue(QUEUE, uxQueueLength, uxItemSize);
|
||||
}
|
||||
@ -75,7 +75,7 @@ uint32_t xQueueSend(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t
|
||||
return osal_queue_send(h->q, (uint8_t *)pvItemToQueue, h->item_size) ? pdTRUE : pdFAIL;
|
||||
}
|
||||
|
||||
uint32_t xQueueSendToBack(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait )
|
||||
uint32_t xQueueSendToBack(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait)
|
||||
{
|
||||
return xQueueSend(xQueue, pvItemToQueue, xTicksToWait);
|
||||
}
|
||||
@ -86,7 +86,7 @@ uint32_t xQueueReceive(QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksTo
|
||||
return osal_queue_recv(h->q, (uint8_t *)pvBuffer, h->item_size, xTicksToWait) ? pdTRUE : pdFAIL;
|
||||
}
|
||||
|
||||
BaseType_t xSemaphoreGive( QueueHandle_t xQueue)
|
||||
BaseType_t xSemaphoreGive(QueueHandle_t xQueue)
|
||||
{
|
||||
struct generic_queue_handle *h = xQueue;
|
||||
if (h->type == MUTEX) {
|
||||
@ -96,7 +96,7 @@ BaseType_t xSemaphoreGive( QueueHandle_t xQueue)
|
||||
return xQueueSend(xQueue, &s_semaphore_data, portMAX_DELAY);
|
||||
}
|
||||
|
||||
BaseType_t xSemaphoreGiveRecursive( QueueHandle_t xQueue)
|
||||
BaseType_t xSemaphoreGiveRecursive(QueueHandle_t xQueue)
|
||||
{
|
||||
struct generic_queue_handle *h = xQueue;
|
||||
if (h->type == MUTEX_REC) {
|
||||
@ -106,7 +106,7 @@ BaseType_t xSemaphoreGiveRecursive( QueueHandle_t xQueue)
|
||||
return pdFALSE;
|
||||
}
|
||||
|
||||
BaseType_t xSemaphoreTake( QueueHandle_t xQueue, TickType_t pvTask )
|
||||
BaseType_t xSemaphoreTake(QueueHandle_t xQueue, TickType_t pvTask)
|
||||
{
|
||||
struct generic_queue_handle *h = xQueue;
|
||||
if (h->type == MUTEX) {
|
||||
@ -116,7 +116,7 @@ BaseType_t xSemaphoreTake( QueueHandle_t xQueue, TickType_t pvTask )
|
||||
return xQueueReceive(xQueue, &s_semaphore_data, portMAX_DELAY);
|
||||
}
|
||||
|
||||
BaseType_t xSemaphoreTakeRecursive( QueueHandle_t xQueue, TickType_t pvTask )
|
||||
BaseType_t xSemaphoreTakeRecursive(QueueHandle_t xQueue, TickType_t pvTask)
|
||||
{
|
||||
struct generic_queue_handle *h = xQueue;
|
||||
if (h->type == MUTEX_REC) {
|
||||
@ -126,7 +126,7 @@ BaseType_t xSemaphoreTakeRecursive( QueueHandle_t xQueue, TickType_t pvTask )
|
||||
return pdFALSE;
|
||||
}
|
||||
|
||||
void vQueueDelete( QueueHandle_t xQueue )
|
||||
void vQueueDelete(QueueHandle_t xQueue)
|
||||
{
|
||||
struct generic_queue_handle *h = xQueue;
|
||||
if (h->q) {
|
||||
@ -166,6 +166,8 @@ void vTaskDelete(TaskHandle_t *task)
|
||||
|
||||
if (task == NULL) {
|
||||
pthread_exit(0);
|
||||
} else {
|
||||
pthread_cancel((pthread_t)task);
|
||||
}
|
||||
void *thread_rval = NULL;
|
||||
pthread_join((pthread_t)task, &thread_rval);
|
||||
@ -176,14 +178,14 @@ void vTaskSuspend(void *task)
|
||||
vTaskDelete(task);
|
||||
}
|
||||
|
||||
TickType_t xTaskGetTickCount( void )
|
||||
TickType_t xTaskGetTickCount(void)
|
||||
{
|
||||
struct timespec spec;
|
||||
clock_gettime(CLOCK_REALTIME, &spec);
|
||||
return spec.tv_nsec / 1000000 + spec.tv_sec * 1000;
|
||||
}
|
||||
|
||||
void vTaskDelay( const TickType_t xTicksToDelay )
|
||||
void vTaskDelay(const TickType_t xTicksToDelay)
|
||||
{
|
||||
usleep(xTicksToDelay * 1000);
|
||||
}
|
||||
@ -212,13 +214,27 @@ void *pthread_task(void *params)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BaseType_t xTaskCreatePinnedToCore( TaskFunction_t pvTaskCode,
|
||||
const char *const pcName,
|
||||
const uint32_t usStackDepth,
|
||||
void *const pvParameters,
|
||||
UBaseType_t uxPriority,
|
||||
TaskHandle_t *const pvCreatedTask,
|
||||
const BaseType_t xCoreID)
|
||||
TaskHandle_t xTaskCreateStaticPinnedToCore(TaskFunction_t pxTaskCode,
|
||||
const char *const pcName,
|
||||
const uint32_t ulStackDepth,
|
||||
void *const pvParameters,
|
||||
UBaseType_t uxPriority,
|
||||
StackType_t *const puxStackBuffer,
|
||||
StaticTask_t *const pxTaskBuffer,
|
||||
const BaseType_t xCoreID)
|
||||
{
|
||||
static TaskHandle_t pvCreatedTask;
|
||||
xTaskCreate(pxTaskCode, pcName, ulStackDepth, pvParameters, uxPriority, &pvCreatedTask);
|
||||
return pvCreatedTask;
|
||||
}
|
||||
|
||||
BaseType_t xTaskCreatePinnedToCore(TaskFunction_t pvTaskCode,
|
||||
const char *const pcName,
|
||||
const uint32_t usStackDepth,
|
||||
void *const pvParameters,
|
||||
UBaseType_t uxPriority,
|
||||
TaskHandle_t *const pvCreatedTask,
|
||||
const BaseType_t xCoreID)
|
||||
{
|
||||
xTaskCreate(pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pvCreatedTask);
|
||||
return pdTRUE;
|
||||
@ -266,7 +282,7 @@ void xTaskNotifyGive(TaskHandle_t task)
|
||||
}
|
||||
}
|
||||
|
||||
BaseType_t xTaskNotifyWait(uint32_t bits_entry_clear, uint32_t bits_exit_clear, uint32_t *value, TickType_t wait_time )
|
||||
BaseType_t xTaskNotifyWait(uint32_t bits_entry_clear, uint32_t bits_exit_clear, uint32_t *value, TickType_t wait_time)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -276,32 +292,32 @@ TaskHandle_t xTaskGetCurrentTaskHandle(void)
|
||||
return (TaskHandle_t)pthread_self();
|
||||
}
|
||||
|
||||
EventGroupHandle_t xEventGroupCreate( void )
|
||||
EventGroupHandle_t xEventGroupCreate(void)
|
||||
{
|
||||
return osal_signal_create();
|
||||
}
|
||||
|
||||
void vEventGroupDelete( EventGroupHandle_t xEventGroup )
|
||||
void vEventGroupDelete(EventGroupHandle_t xEventGroup)
|
||||
{
|
||||
osal_signal_delete(xEventGroup);
|
||||
}
|
||||
|
||||
EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear )
|
||||
EventBits_t xEventGroupClearBits(EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear)
|
||||
{
|
||||
return osal_signal_clear(xEventGroup, uxBitsToClear);
|
||||
}
|
||||
|
||||
EventBits_t xEventGroupGetBits( EventGroupHandle_t xEventGroup)
|
||||
EventBits_t xEventGroupGetBits(EventGroupHandle_t xEventGroup)
|
||||
{
|
||||
return osal_signal_get(xEventGroup);
|
||||
}
|
||||
|
||||
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet )
|
||||
EventBits_t xEventGroupSetBits(EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet)
|
||||
{
|
||||
return osal_signal_set(xEventGroup, uxBitsToSet);
|
||||
}
|
||||
|
||||
EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait )
|
||||
EventBits_t xEventGroupWaitBits(EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait)
|
||||
{
|
||||
return osal_signal_wait(xEventGroup, uxBitsToWaitFor, xWaitForAllBits, xTicksToWait);
|
||||
}
|
||||
|
@ -1,11 +1,12 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "esp_heap_caps.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -15,7 +16,10 @@ extern "C" {
|
||||
#define TaskHandle_t TaskHandle_t
|
||||
#define vSemaphoreDelete( xSemaphore ) vQueueDelete( ( QueueHandle_t ) ( xSemaphore ) )
|
||||
|
||||
void vTaskDelay( const TickType_t xTicksToDelay );
|
||||
typedef void *StackType_t;
|
||||
typedef void *StaticTask_t;
|
||||
|
||||
void vTaskDelay(const TickType_t xTicksToDelay);
|
||||
|
||||
void xTaskNotifyGive(TaskHandle_t task);
|
||||
|
||||
@ -23,39 +27,48 @@ void ulTaskNotifyTake(bool stuff, uint32_t timeout);
|
||||
|
||||
TaskHandle_t xTaskGetCurrentTaskHandle(void);
|
||||
|
||||
BaseType_t xTaskNotifyWait(uint32_t bits_entry_clear, uint32_t bits_exit_clear, uint32_t *value, TickType_t wait_time );
|
||||
BaseType_t xTaskNotifyWait(uint32_t bits_entry_clear, uint32_t bits_exit_clear, uint32_t *value, TickType_t wait_time);
|
||||
|
||||
BaseType_t xTaskCreatePinnedToCore( TaskFunction_t pvTaskCode,
|
||||
const char *const pcName,
|
||||
const uint32_t usStackDepth,
|
||||
void *const pvParameters,
|
||||
UBaseType_t uxPriority,
|
||||
TaskHandle_t *const pvCreatedTask,
|
||||
const BaseType_t xCoreID);
|
||||
TaskHandle_t xTaskCreateStaticPinnedToCore(TaskFunction_t pxTaskCode,
|
||||
const char *const pcName,
|
||||
const uint32_t ulStackDepth,
|
||||
void *const pvParameters,
|
||||
UBaseType_t uxPriority,
|
||||
StackType_t *const puxStackBuffer,
|
||||
StaticTask_t *const pxTaskBuffer,
|
||||
const BaseType_t xCoreID);
|
||||
|
||||
BaseType_t xTaskCreatePinnedToCore(TaskFunction_t pvTaskCode,
|
||||
const char *const pcName,
|
||||
const uint32_t usStackDepth,
|
||||
void *const pvParameters,
|
||||
UBaseType_t uxPriority,
|
||||
TaskHandle_t *const pvCreatedTask,
|
||||
const BaseType_t xCoreID);
|
||||
|
||||
BaseType_t xTaskCreate(TaskFunction_t pvTaskCode, const char *const pcName, const uint32_t usStackDepth, void *const pvParameters, UBaseType_t uxPriority, TaskHandle_t *const pvCreatedTask);
|
||||
|
||||
TickType_t xTaskGetTickCount( void );
|
||||
TickType_t xTaskGetTickCount(void);
|
||||
|
||||
void vQueueDelete( QueueHandle_t xQueue );
|
||||
void vQueueDelete(QueueHandle_t xQueue);
|
||||
|
||||
QueueHandle_t xSemaphoreCreateBinary(void);
|
||||
|
||||
QueueHandle_t xSemaphoreCreateMutex(void);
|
||||
QueueHandle_t xSemaphoreCreateRecursiveMutex(void);
|
||||
|
||||
BaseType_t xSemaphoreGive( QueueHandle_t xQueue);
|
||||
BaseType_t xSemaphoreGive(QueueHandle_t xQueue);
|
||||
|
||||
BaseType_t xSemaphoreTake( QueueHandle_t xQueue, TickType_t pvTask );
|
||||
BaseType_t xSemaphoreTake(QueueHandle_t xQueue, TickType_t pvTask);
|
||||
|
||||
BaseType_t xSemaphoreGiveRecursive( QueueHandle_t xQueue);
|
||||
BaseType_t xSemaphoreGiveRecursive(QueueHandle_t xQueue);
|
||||
|
||||
BaseType_t xSemaphoreTakeRecursive( QueueHandle_t xQueue, TickType_t pvTask );
|
||||
BaseType_t xSemaphoreTakeRecursive(QueueHandle_t xQueue, TickType_t pvTask);
|
||||
|
||||
void vTaskDelete(TaskHandle_t *task);
|
||||
|
||||
QueueHandle_t xQueueCreate( uint32_t uxQueueLength,
|
||||
uint32_t uxItemSize );
|
||||
QueueHandle_t xQueueCreate(uint32_t uxQueueLength,
|
||||
uint32_t uxItemSize);
|
||||
|
||||
uint32_t xQueueSend(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait);
|
||||
|
||||
@ -63,23 +76,26 @@ uint32_t xQueueReceive(QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksTo
|
||||
|
||||
void vTaskSuspend(void *task);
|
||||
|
||||
EventGroupHandle_t xEventGroupCreate( void );
|
||||
void vEventGroupDelete( EventGroupHandle_t xEventGroup );
|
||||
EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup,
|
||||
const EventBits_t uxBitsToClear );
|
||||
EventGroupHandle_t xEventGroupCreate(void);
|
||||
void vEventGroupDelete(EventGroupHandle_t xEventGroup);
|
||||
EventBits_t xEventGroupClearBits(EventGroupHandle_t xEventGroup,
|
||||
const EventBits_t uxBitsToClear);
|
||||
|
||||
EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup,
|
||||
const EventBits_t uxBitsToWaitFor,
|
||||
const BaseType_t xClearOnExit,
|
||||
const BaseType_t xWaitForAllBits,
|
||||
TickType_t xTicksToWait );
|
||||
EventBits_t xEventGroupWaitBits(EventGroupHandle_t xEventGroup,
|
||||
const EventBits_t uxBitsToWaitFor,
|
||||
const BaseType_t xClearOnExit,
|
||||
const BaseType_t xWaitForAllBits,
|
||||
TickType_t xTicksToWait);
|
||||
|
||||
EventBits_t xEventGroupGetBits( EventGroupHandle_t xEventGroup);
|
||||
EventBits_t xEventGroupGetBits(EventGroupHandle_t xEventGroup);
|
||||
|
||||
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup,
|
||||
const EventBits_t uxBitsToSet );
|
||||
EventBits_t xEventGroupSetBits(EventGroupHandle_t xEventGroup,
|
||||
const EventBits_t uxBitsToSet);
|
||||
|
||||
uint32_t xQueueSendToBack(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait );
|
||||
uint32_t xQueueSendToBack(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait);
|
||||
|
||||
void *heap_caps_malloc(size_t size, uint32_t caps);
|
||||
void heap_caps_free(void *ptr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -1,7 +1,8 @@
|
||||
---
|
||||
commitizen:
|
||||
bump_message: 'bump(asio): $current_version -> $new_version'
|
||||
pre_bump_hooks: python ../../ci/changelog.py asio
|
||||
tag_format: asio-v$version
|
||||
version: 1.28.0~0
|
||||
version: 1.32.0
|
||||
version_files:
|
||||
- idf_component.yml
|
||||
|
@ -1,5 +1,26 @@
|
||||
# Changelog
|
||||
|
||||
## [1.32.0](https://github.com/espressif/esp-protocols/commits/asio-v1.32.0)
|
||||
|
||||
### Features
|
||||
|
||||
- Upgrade asio to 1.32 ([9bdd429c](https://github.com/espressif/esp-protocols/commit/9bdd429c))
|
||||
- Drop esp/asio patches in favor of sock-utils ([27435b7f](https://github.com/espressif/esp-protocols/commit/27435b7f))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Fix chat example to print only the message body ([76aaea08](https://github.com/espressif/esp-protocols/commit/76aaea08))
|
||||
- Make asio enable if_nametoindex to fix linking ([5db32cce](https://github.com/espressif/esp-protocols/commit/5db32cce))
|
||||
- Re-applie refs to common comps idf_component.yml ([9fe44a45](https://github.com/espressif/esp-protocols/commit/9fe44a45))
|
||||
- Reference common component from IDF ([74fc228c](https://github.com/espressif/esp-protocols/commit/74fc228c))
|
||||
- Revert referencing protocol_examples_common from IDF ([f9e0281a](https://github.com/espressif/esp-protocols/commit/f9e0281a))
|
||||
- reference protocol_examples_common from IDF ([09abb18b](https://github.com/espressif/esp-protocols/commit/09abb18b))
|
||||
- specify override_path in example manifest files ([1d8923cf](https://github.com/espressif/esp-protocols/commit/1d8923cf))
|
||||
|
||||
### Updated
|
||||
|
||||
- docs(asio): Updates asio docs ([ce9337d3](https://github.com/espressif/esp-protocols/commit/ce9337d3))
|
||||
|
||||
## [1.28.2~0](https://github.com/espressif/esp-protocols/commits/asio-1.28.2_0)
|
||||
|
||||
### Bug Fixes
|
||||
|
@ -6,8 +6,8 @@ if(NOT CONFIG_LWIP_IPV6 AND NOT CMAKE_BUILD_EARLY_EXPANSION)
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(asio_sources "asio/asio/src/asio.cpp")
|
||||
set(asio_requires lwip)
|
||||
set(asio_sources "asio/asio/src/asio.cpp" "port/src/asio_stub.cpp")
|
||||
set(asio_requires lwip sock_utils)
|
||||
|
||||
if(CONFIG_ASIO_SSL_SUPPORT)
|
||||
list(APPEND asio_sources
|
||||
@ -18,7 +18,7 @@ if(CONFIG_ASIO_SSL_SUPPORT)
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS ${asio_sources}
|
||||
INCLUDE_DIRS "asio/asio/include" "port/include"
|
||||
INCLUDE_DIRS "port/include" "asio/asio/include"
|
||||
PRIV_INCLUDE_DIRS ${asio_priv_includes}
|
||||
PRIV_REQUIRES ${asio_requires})
|
||||
|
||||
@ -30,6 +30,7 @@ target_compile_definitions(${COMPONENT_LIB} PUBLIC SA_RESTART=0x01
|
||||
ASIO_STANDALONE
|
||||
ASIO_HAS_PTHREADS
|
||||
OPENSSL_NO_ENGINE
|
||||
ASIO_DETAIL_IMPL_POSIX_EVENT_IPP # this replaces asio's posix_event constructor
|
||||
)
|
||||
|
||||
if(NOT CONFIG_COMPILER_CXX_EXCEPTIONS)
|
||||
|
@ -1,6 +1,15 @@
|
||||
menu "ESP-ASIO"
|
||||
visible if LWIP_IPV6
|
||||
|
||||
config ASIO_IS_ENABLED
|
||||
# Invisible option that is enabled if ASIO is added to the IDF components.
|
||||
# This is used to "select" LWIP_NETIF_API option
|
||||
# which enables if_indextoname() and if_nametoindex() functions
|
||||
# (these are optionally used in asio)
|
||||
bool
|
||||
default "y"
|
||||
select LWIP_NETIF_API
|
||||
|
||||
config ASIO_SSL_SUPPORT
|
||||
bool "Enable SSL/TLS support of ASIO"
|
||||
default n
|
||||
|
Submodule components/asio/asio updated: a2e0f70d61...03ae834edb
@ -120,7 +120,7 @@ private:
|
||||
asio::buffer(read_msg_.body(), read_msg_.body_length()),
|
||||
[this, self](std::error_code ec, std::size_t /*length*/) {
|
||||
if (!ec) {
|
||||
ESP_LOGD("asio-chat:", "%s", read_msg_.body());
|
||||
ESP_LOGD("asio-chat", "%.*s", read_msg_.body_length(), read_msg_.body());
|
||||
room_.deliver(read_msg_);
|
||||
do_read_header();
|
||||
} else {
|
||||
|
@ -17,6 +17,8 @@
|
||||
#include "asio/ssl.hpp"
|
||||
#include "asio/buffer.hpp"
|
||||
#include "esp_pthread.h"
|
||||
// allows for direct access to mbedtls specifics
|
||||
#include "asio/ssl/mbedtls_specific.hpp"
|
||||
|
||||
extern const unsigned char server_pem_start[] asm("_binary_srv_crt_start");
|
||||
extern const unsigned char server_pem_end[] asm("_binary_srv_crt_end");
|
||||
@ -217,6 +219,7 @@ void ssl_server_thread()
|
||||
io_context.run();
|
||||
}
|
||||
|
||||
|
||||
void ssl_client_thread()
|
||||
{
|
||||
asio::io_context io_context;
|
||||
@ -229,6 +232,11 @@ void ssl_client_thread()
|
||||
asio::ssl::context ctx(asio::ssl::context::tls_client);
|
||||
#if CONFIG_EXAMPLE_CLIENT_VERIFY_PEER
|
||||
ctx.add_certificate_authority(cert_chain);
|
||||
// mbedtls (from 3.6.3) requires hostname to be set when performing TLS handshake with verify-peer option
|
||||
// asio::ssl allows for name verification using verification callback, i.e. socket_.set_verify_callback(asio::ssl::host_name_verification()),
|
||||
// - which is not supported in Espressif ASIO port yet.
|
||||
// Therefore we provide a way to directly use mbedtls API and here we just configure the expected hostname to verify
|
||||
asio::ssl::mbedtls::set_hostname(ctx.native_handle(), server_ip);
|
||||
#endif // CONFIG_EXAMPLE_CLIENT_VERIFY_PEER
|
||||
|
||||
Client c(io_context, ctx, endpoints);
|
||||
|
@ -1,22 +1,22 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDkzCCAnugAwIBAgIUNI5wldYysh6rtCzYmda6H414aRswDQYJKoZIhvcNAQEL
|
||||
MIIDkzCCAnugAwIBAgIUb25LYOLubieEbKPQDiM+8T5p4yUwDQYJKoZIhvcNAQEL
|
||||
BQAwWTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
|
||||
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDESMBAGA1UEAwwJRXNwcmVzc2lmMB4X
|
||||
DTIwMDEyMTA5MDk0NloXDTI1MDEyMDA5MDk0NlowWTELMAkGA1UEBhMCQVUxEzAR
|
||||
DTI1MDQwNzA5NDkzOFoXDTQ1MDQwMjA5NDkzOFowWTELMAkGA1UEBhMCQVUxEzAR
|
||||
BgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5
|
||||
IEx0ZDESMBAGA1UEAwwJRXNwcmVzc2lmMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
|
||||
MIIBCgKCAQEAyadSpRnIQBVbEAsbpkrKrOMlBOMIUmA8AfNyOYPLfv0Oa5lBiMAV
|
||||
3OQDu5tYyFYKwkCUqq65iAm50fPbSH71w1tkja6nZ1yAIM+TvpMlM/WiFGrhY+Tc
|
||||
kAcLcKUJyPxrv/glzoVslbqUgIhuhCSKA8uk1+ILcn3nWzPcbcowLx31+AHeZj8h
|
||||
bIAdj6vjqxMCFStp4IcA+ikmCk75LCN4vkkifdkebb/ZDNYCZZhpCBnCHyFAjPc4
|
||||
7C+FDVGT3/UUeeTy+Mtn+MqUAhB+W0sPDm1n2h59D4Z/MFm0hl6GQCAKeMJPzssU
|
||||
BBsRm6zoyPQ4VTqG0uwfNNbORyIfKONMUwIDAQABo1MwUTAdBgNVHQ4EFgQUGYLV
|
||||
EkgWzxjpltE6texha7zZVxowHwYDVR0jBBgwFoAUGYLVEkgWzxjpltE6texha7zZ
|
||||
VxowDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAb2EF4Zg2XWNb
|
||||
eZHnzupCDd9jAhwPqkt7F1OXvxJa/RFUSB9+2izGvikGGhuKY4f0iLuqF+bhExD9
|
||||
sapDcdFO2Suh4J3onbwEvmKvsv56K3xhapYg8WwPofpkVirnkwFjpQXGzrYxPujg
|
||||
BPmSy3psQrhvOr/WH7SefJv2qr4ikaugfE+3enY4PL+C1dSQAuNo1QGgWsZIu0c8
|
||||
TZybNZ13vNVMA+tgj2CM8FR3Etaabwtu3TTcAnO7aoBTix/bLBTuZoczhN8/MhG3
|
||||
GylmDzFI8a6aKxQL3Fi4PsM82hRKWu3gfs39sR1Ci4V22v8uO5EWBPK0QZvDSc1a
|
||||
KwwxI4zA0w==
|
||||
MIIBCgKCAQEArJsjwSNjPOBpTCRW+pIag9gJgRaNIjscea/ilRYRwAnqWKLNssNw
|
||||
Kye79KmQ5TxnOEvBIYjesArst1l7MghPLaELscCKo96jzCkSmgPLbxPs+5/E4daO
|
||||
9ItxOSH2mjOgG5yFQLEb8xOvsvWWrJAUBj6RBjhzgSYLYRbesWKAyVi9fxSuzfZm
|
||||
ROV0B2NsO1PlUDzweo9RYSuvpyNR3kddNnc6lJLXtZhf6IHczjFDFd5/PQuzLIO/
|
||||
Dbg+5AMpQykbMFhcQI/Y49GlMMXFDIaWjP+XfE/yUJ4GyYd2EzpDFDFMisnkuR9d
|
||||
LQgSXZNwygO8SIfYnnm1pwcGuG/fCQZYpQIDAQABo1MwUTAdBgNVHQ4EFgQUMTUG
|
||||
OZ7ujyz7oXSuhDgbpoPRo1cwHwYDVR0jBBgwFoAUMTUGOZ7ujyz7oXSuhDgbpoPR
|
||||
o1cwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAD5JwzRVEvnTK
|
||||
R2bfMNy60FmFNTOEEYP+XYoNGBiXVY3MRrWlfbY5Pbs4Nq7sCfzEWMj2UsjFmjZE
|
||||
DU6FdsaL6rhnps03MR5yiuE5w2aPiH/ijgzVfZtdLe6nKcnrv1YInjEKk+Y3qGu6
|
||||
2ZC+MEINPBfRiuN6gCAdxGiK81J4FPLlZImLO/g/0fSrIXCzBUzjoYRYjsy5AP60
|
||||
0kbaoGA/SshP0aeNvWB0wUab40idGXBFJ3vnEfMbLIMdc/uCqnzRpqK0m1DacwrI
|
||||
nTUMl0bI302Oa/gym+Ma0nJ1nVADcLKoZ1syWjyzIcl6zr+ITY5S+pbeO/geQgKh
|
||||
NSUkahX6MQ==
|
||||
-----END CERTIFICATE-----
|
||||
|
22
components/asio/examples/ssl_client_server/main/regenerate_test_certs.sh
Executable file
22
components/asio/examples/ssl_client_server/main/regenerate_test_certs.sh
Executable file
@ -0,0 +1,22 @@
|
||||
#!/bin/bash
|
||||
# This script generates self-signed certificates for testing purposes only.
|
||||
# DO NOT use these certificates in production environments.
|
||||
# These certificates are meant for development and testing of SSL/TLS functionality.
|
||||
|
||||
# 1. Generate CA private key
|
||||
openssl genrsa -out ca.key 2048
|
||||
|
||||
# 2. Generate CA certificate (validity: 20 years, CN=Espressif)
|
||||
openssl req -x509 -new -nodes -key ca.key -sha256 -days 7300 -out ca.crt -subj "/C=AU/ST=Some-State/O=Internet Widgits Pty Ltd/CN=Espressif"
|
||||
|
||||
# 3. Generate server private key
|
||||
openssl genrsa -out server.key 2048
|
||||
|
||||
# 4. Generate server Certificate Signing Request (CSR)
|
||||
openssl req -new -key server.key -out server.csr -subj "/CN=localhost"
|
||||
|
||||
# 5. Generate server certificate signed by CA (validity: 20 years)
|
||||
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out srv.crt -days 7300 -sha256
|
||||
|
||||
# 6. Clean up intermediate files
|
||||
rm server.csr ca.srl
|
@ -1,27 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEogIBAAKCAQEAlUCywNhVv4RO2y9h/XGKZ1azzk3jzHpSBzIGO9LoiA8trC/p
|
||||
1ykGaUfYPJllYK4HMhC4fUyE3J7tVL2Eskzl26LNPLbEoaBWZM9NhV3iA1/1EtOu
|
||||
p6umLx+y3sDfvK35YAOUbjdAlBfhnJ4r8h7oTsxl3J5jZ18zgjJnJi2NEFq/yTpO
|
||||
MiwHLWPjy25fDFixfV9UzSvbgt1JaGPmC7c4QkhHzjyp0+ikuvRIw0p9BBNeqBV2
|
||||
da3qBMB5FtodUJTAz6o6OKWbTalLjQi6C1H6z9TnY7IrJBUOy/FWkQH/sEsLdscD
|
||||
hHa1Dz2oT203QjhzyOSfnNF95D/1MdNcMt6l0wIDAQABAoIBAC1JJTOoMFRc48RT
|
||||
myrYQYNbZlEphv3q+2qdfhC2zMFDwbrmCtCy7PQSzYSNkpoEE8DYG/JAvmtmeWJl
|
||||
4pZrCK9ctWM/nWfhC3WpBL97nfEiM20T94F+bn0L5Cz8XqaULv839th+QUTt/hGU
|
||||
WIctY5VNJXcMQ+MAmtNdUbjex1d3iuxiKHUo4nDoZ8digKFNdtdP5B5nlMq5chCL
|
||||
mxNRcsGsx2dDAxbGUapdTVPWHPJKpLOBoSkluDsfd2KZADFU2R1SJpAX9+RYh3HM
|
||||
5FTUdHTUaISxbKkgeDKlEM0lqk2TtGUwCyEj098ewi7Wzsu9w60IplPPUJx5FRG6
|
||||
jp3wzLkCgYEAxKp5T20rf/7ysX7x053I7VCjDXUxAaWOEj1uS3AhOkl0NaZg7Di+
|
||||
y53fWNkcHdkt2n2LqMt/43UgMYq3TVVcq2eunPNF11e1bJw8CjDafwDs4omwwyVn
|
||||
lYhPuB4dK2OAib+vU5Zqpp0kZMoxk2MZVgon8z+s8DW/zmB6aFqAWeUCgYEAwkhC
|
||||
OgmXKMdjOCVy5t2f5UbY8Y9rV3w8eUATuJ47MMwLr4pGYnKoEn9JB4ltWrHv/u5S
|
||||
fOv3tIrrCEvnCoCbOILwCsY5LqTNXgqova8FB6RpMUQCzhDd8LHuvdHv0WMnMzX1
|
||||
3PKuqwh8JS55m4WqZRhzr5BFKG4fHPVs4IcaJVcCgYAzzCaJSdqUKqTnJOUydDNQ
|
||||
ddWMHNqccWs62J0tF0pZHLGT089hSAzQejMyJnSmU+Ykzr4y5e44DUg+ZCelIZ93
|
||||
saYmxlgVwI8THQ8fLADQRIEfpV4996MRmkZM2vmZzOo03Zyi6lIKsga82Rg3lnk8
|
||||
1Q3ynknBNpbfF0AGLhfyFQKBgBYlxJ73HutAJ5hr9HhLBYJOnEaVUehMOlycKGNg
|
||||
bmD2sdJWEgYBChXpurqIORYguLo4EuE4ySkkuPxeIr14wbkkfBbOWBBwKxUwY+IT
|
||||
xKAFZxR9q1AwbgyVTCEJgKw/AGX/HcMNS0omEnjunmBTUYRq0C1QZgHg490aQUor
|
||||
PJjLAoGAevzdTpFlVeuKeYh1oDubGO1LinyXpBv7fPFjl+zu4AVbjojcU6yC4OO6
|
||||
QvqopE6SyAECKy8kAOFcESPsGc9Lta2XUvI203z7pIVlNVEcJ0+90mQh3Mn1U46l
|
||||
sZ49PdRvNwNb5wvkh1UqNsMlGFbRlzMbIk45ou4311kCobowZek=
|
||||
MIIEpAIBAAKCAQEA1zQFgwUxyIteLl5SiciuRBZbn/3KWRmsVpyo5JiYCK9NM3Q8
|
||||
dDur/dyQ4y2Mq0RVuM7uZL7VraRA4F9+Tm8D2BJ8q4Ai3nRDiGQkFEfbvX0Wic6P
|
||||
P6q7lKm65fnYMvbWHqhMOglr8e4b7dMOFpZdNLRZVcoP4/43+/9dOgOj7TXczTFs
|
||||
jnlLJBijOnwABf/xlTpTR7ZbQ3uOlckc0TK/Lqxex+NUq4dXQKa96a/wpA6smW38
|
||||
0XU5hvVBmhA9YNK86CIpAVOny9gNM1Wxv+aAdVZigNNi6Hht75neC0DhFqGbfpMi
|
||||
nLhW8qGwVtY3T1pM8HrpdAu5plkdvmcDm8tUAwIDAQABAoIBADHwOHc29V58ONa5
|
||||
vJ2MnCPgrFJsKlCSzJMst2SUpHMfeuK9zmmKj1bRoC2XnFUB/oJsQpXOUveAbi2i
|
||||
+0RoLpQtdhC2I2FLyYAU/OpX4n4OUPSZolQ74luVJ3HGkI0DCp0CoO220f3KK2D8
|
||||
4QAM1IQudayavyVBEOzBTXjw71FUCXmg0viBtd7JRSug9FR69PPLWP14uzo1viBA
|
||||
dtRsLePDyTatW+bfKkPwDG8hhJoummw+fYRPZbM05aWLmVvTiZ/eQtRq1jkwUNSH
|
||||
zXsJiCQbHLqwoXISiEsdagQM8hNW2bw5B+ijCQhWNj2ZZBZPJIRtI75sXiXGy2eC
|
||||
kDaP0cECgYEA8GpoGOyVZ+KMm7PVNcNbdLJrjpoNhdVXdGwR+yd3u6EoQ3MMD5tr
|
||||
4F7pFtN3IxwLoCSM/dnobysNFdKdQRnOB+o3uLADiPn9REM7ebuGUwUP3BWwkb7S
|
||||
orDVPUMA82A1p0T4Dwi+OAPpS5bUoI7S/6ZwheWTdoGZYjCrtsqkeEUCgYEA5Sc5
|
||||
sgLFWIqvYUQF/+aLAwjHR/bBD9NkvHgdW8GmgXdnEd0DIKHDpJ2yEK3BbQxVp/Kk
|
||||
O2KG1NGyJ9UqA9QQ3q5UgpZNHQBWxz2GUl0jHsy8enhgsZr4K2+wvuw5F5bCdXPe
|
||||
m/dyFIGnUJ7ic+DtvDGjXdcwAR8Cgc97m5Pg06cCgYEAgyjqBb78e6KDJ2biyOP9
|
||||
fxrfxvqQqhUMEz3qSWTs03ZGaxXW3KTkI5JkA8n2Uzc3uHR4Xv2E6zFHgEJY/G1B
|
||||
k9vZ7m5IX3BTFezAA9eknqJCVsWWgMzkSVHD5Bor6JryaoEb+8e/TvwDSPPOqJGC
|
||||
12pMNSBcZOirb4AyDhVbySkCgYB3Lu2dHj/SC1+oMR8Ft7y5eUlcroQ/XO1Z8Qck
|
||||
ABY/5ABhlBfaUwhUiAhjEFw4AWBTl6m/kUEbU21btkzB7PxRNU6TFOVKnjCENAW2
|
||||
tOZdUJL/B7kS5s0ImnDM/EO9dxXwzLENYaed7sk870ZMisJbTV3wosk+7Af7yBQ8
|
||||
GK+opQKBgQCdZy3KX2FT8S/K2SjDuRM8uDzJ+IcaqScDhgbJFMlrbWmTSML69oRD
|
||||
Ic6xVe5hWkkPIs521gwrQSD5E3dbb2dFmjhUZpZkHdv0u/AUupFN0EaCFb/I2A0P
|
||||
fRebd9oKoZjlUrEPeID0kjzbmnPGbtG+gFZYmkRb5iLdcCVAn0O1AQ==
|
||||
-----END RSA PRIVATE KEY-----
|
||||
|
@ -1,18 +1,18 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIC9DCCAdwCFA1lSIcHwYKdB2UqOrZxZnVgPObTMA0GCSqGSIb3DQEBCwUAMFkx
|
||||
MIIC9DCCAdwCFHNjaiCN2RT7W7NHXho8HlgxdAygMA0GCSqGSIb3DQEBCwUAMFkx
|
||||
CzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRl
|
||||
cm5ldCBXaWRnaXRzIFB0eSBMdGQxEjAQBgNVBAMMCUVzcHJlc3NpZjAeFw0yMDA2
|
||||
MTIwNjA0MTNaFw0yMjA2MDIwNjA0MTNaMBQxEjAQBgNVBAMMCWxvY2FsaG9zdDCC
|
||||
ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJVAssDYVb+ETtsvYf1ximdW
|
||||
s85N48x6UgcyBjvS6IgPLawv6dcpBmlH2DyZZWCuBzIQuH1MhNye7VS9hLJM5dui
|
||||
zTy2xKGgVmTPTYVd4gNf9RLTrqerpi8fst7A37yt+WADlG43QJQX4ZyeK/Ie6E7M
|
||||
ZdyeY2dfM4IyZyYtjRBav8k6TjIsBy1j48tuXwxYsX1fVM0r24LdSWhj5gu3OEJI
|
||||
R848qdPopLr0SMNKfQQTXqgVdnWt6gTAeRbaHVCUwM+qOjilm02pS40IugtR+s/U
|
||||
52OyKyQVDsvxVpEB/7BLC3bHA4R2tQ89qE9tN0I4c8jkn5zRfeQ/9THTXDLepdMC
|
||||
AwEAATANBgkqhkiG9w0BAQsFAAOCAQEAnMYGW+idt37bEE4WPgrRorKWuplR+zHD
|
||||
wJFz53DQzyIZJHmJ2hR5U0jNcHy/nMq7tbdz9LZPrVF4lZJ3TJhnmkOKjMFPCQE8
|
||||
YcmsP3il6eXgtGqg53InOi/uJqEQ9TfM54cbpp6xKbnmpwk4uprISBRQt7u2ZLk2
|
||||
40ED6zgjFPDTYmSjSpb2AN6KUB6PflgVs+4p9ViHNq4U3AlYV/BM0+3G4aMX2wNl
|
||||
ZIpQfOyuaYD5MU50mY+O+gDiiypkpYf6a6S4YJ1sMbavDsP7bW5UMnP0jKYR549q
|
||||
5hF1fdkXq52DfJ9ya2kl3mANFkKssQV+1KCBMxGoeqfakmJfa03xXA==
|
||||
cm5ldCBXaWRnaXRzIFB0eSBMdGQxEjAQBgNVBAMMCUVzcHJlc3NpZjAeFw0yNTA0
|
||||
MDcwOTQ5MzhaFw00NTA0MDIwOTQ5MzhaMBQxEjAQBgNVBAMMCWxvY2FsaG9zdDCC
|
||||
ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANc0BYMFMciLXi5eUonIrkQW
|
||||
W5/9ylkZrFacqOSYmAivTTN0PHQ7q/3ckOMtjKtEVbjO7mS+1a2kQOBffk5vA9gS
|
||||
fKuAIt50Q4hkJBRH2719FonOjz+qu5SpuuX52DL21h6oTDoJa/HuG+3TDhaWXTS0
|
||||
WVXKD+P+N/v/XToDo+013M0xbI55SyQYozp8AAX/8ZU6U0e2W0N7jpXJHNEyvy6s
|
||||
XsfjVKuHV0Cmvemv8KQOrJlt/NF1OYb1QZoQPWDSvOgiKQFTp8vYDTNVsb/mgHVW
|
||||
YoDTYuh4be+Z3gtA4Rahm36TIpy4VvKhsFbWN09aTPB66XQLuaZZHb5nA5vLVAMC
|
||||
AwEAATANBgkqhkiG9w0BAQsFAAOCAQEAoiuycWVVjmS9IMS1n9ll8UlIqq8dl7vs
|
||||
Y5ckGMrdSGR8BPgloTrB6ual4vRPgbn2rGBGAvGusdcmhc1vkVbYsI3JRpTTDDoE
|
||||
PvQqHWXwV2RDRU5kG6ZOsU+o01Ir4b3w3qfP2LT20FCuuAMIMh23PsSmoc7ziFZ8
|
||||
76+ox6FjhJMPMF2aftiDmP44/fFg16C1t2PFH/Bk4sm4qRdpXVcWeiaHaSF9JkHa
|
||||
XwW3TuDSxJwlFFU7ffTRgYYkQ61q8B0LjWV4FF1dBBqflAiXEhWcVhljqfsWn7rq
|
||||
NBJ/QzZ3GhgQO9GOCokh/ckcp/ZMOm9tv9lV2huGz8Akk8/UYhMUEg==
|
||||
-----END CERTIFICATE-----
|
||||
|
@ -1,4 +1,4 @@
|
||||
version: "1.28.2~0"
|
||||
version: "1.32.0"
|
||||
description: Cross-platform C++ library for network and I/O programming
|
||||
url: https://github.com/espressif/esp-protocols/tree/master/components/asio
|
||||
issues: https://github.com/espressif/esp-protocols/issues
|
||||
@ -7,3 +7,5 @@ repository: https://github.com/espressif/esp-protocols.git
|
||||
dependencies:
|
||||
idf:
|
||||
version: ">=5.0"
|
||||
espressif/sock_utils:
|
||||
version: "^0.1"
|
||||
|
11
components/asio/port/include/asio/detail/config.hpp
Normal file
11
components/asio/port/include/asio/detail/config.hpp
Normal file
@ -0,0 +1,11 @@
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "sys/socket.h"
|
||||
#include "socketpair.h"
|
||||
|
||||
#include_next "asio/detail/config.hpp"
|
29
components/asio/port/include/asio/ssl/mbedtls_specific.hpp
Normal file
29
components/asio/port/include/asio/ssl/mbedtls_specific.hpp
Normal file
@ -0,0 +1,29 @@
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "asio/ssl/context_base.hpp"
|
||||
#include "asio/ssl/context.hpp"
|
||||
#include "asio/ssl/detail/openssl_types.hpp"
|
||||
|
||||
namespace asio {
|
||||
namespace ssl {
|
||||
namespace mbedtls {
|
||||
|
||||
/**
|
||||
* @brief Configures specific hostname to be used in peer verification
|
||||
*
|
||||
* @param handle asio::ssl context handle type
|
||||
* @param name hostname to be verified (std::string ownership will be moved to ssl::context)
|
||||
*
|
||||
* @return true on success
|
||||
*/
|
||||
bool set_hostname(asio::ssl::context::native_handle_type handle, std::string name);
|
||||
|
||||
};
|
||||
};
|
||||
} // namespace asio::ssl::mbedtls
|
@ -1,12 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2018-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef _ESP_ASIO_CONFIG_H_
|
||||
#define _ESP_ASIO_CONFIG_H_
|
||||
|
||||
#define ASIO_SSL_DETAIL_OPENSSL_TYPES_HPP
|
||||
#include "openssl_stub.hpp"
|
||||
|
||||
#endif // _ESP_ASIO_CONFIG_H_
|
@ -1,5 +1,5 @@
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
// SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
@ -52,6 +52,12 @@ public:
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool set_hostname(std::string hostname)
|
||||
{
|
||||
hostname_ = std::move(hostname);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::size_t size(container c) const
|
||||
{
|
||||
switch (c) {
|
||||
@ -70,6 +76,7 @@ public:
|
||||
const_buffer cert_chain_;
|
||||
const_buffer private_key_;
|
||||
const_buffer ca_cert_;
|
||||
std::string hostname_;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1,5 +1,5 @@
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
// SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
@ -16,6 +16,11 @@ namespace asio {
|
||||
namespace ssl {
|
||||
namespace mbedtls {
|
||||
|
||||
bool set_hostname(asio::ssl::context::native_handle_type handle, std::string name)
|
||||
{
|
||||
return handle->get()->set_hostname(std::move(name));
|
||||
}
|
||||
|
||||
const char *error_message(int error_code)
|
||||
{
|
||||
static char error_buf[100];
|
||||
@ -25,7 +30,7 @@ const char *error_message(int error_code)
|
||||
|
||||
void throw_alloc_failure(const char *location)
|
||||
{
|
||||
asio::error_code ec( MBEDTLS_ERR_SSL_ALLOC_FAILED, asio::error::get_mbedtls_category());
|
||||
asio::error_code ec(MBEDTLS_ERR_SSL_ALLOC_FAILED, asio::error::get_mbedtls_category());
|
||||
asio::detail::throw_error(ec, location);
|
||||
}
|
||||
|
||||
@ -269,6 +274,16 @@ private:
|
||||
} else {
|
||||
mbedtls_ssl_conf_ca_chain(&conf_, nullptr, nullptr);
|
||||
}
|
||||
|
||||
// Configure hostname before handshake if users pre-configured any
|
||||
// use NULL if not set (to preserve the default behaviour of mbedtls < v3.6.3)
|
||||
const char* hostname = !ctx->hostname_.empty() ? ctx->hostname_.c_str() : NULL;
|
||||
ret = mbedtls_ssl_set_hostname(&ssl_, hostname);
|
||||
if (ret < 0) {
|
||||
print_error("mbedtls_ssl_set_hostname", ret);
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = mbedtls_ssl_setup(&ssl_, &conf_);
|
||||
if (ret) {
|
||||
print_error("mbedtls_ssl_setup", ret);
|
||||
|
@ -8,7 +8,7 @@
|
||||
//
|
||||
|
||||
#include "asio/detail/config.hpp"
|
||||
#include "openssl_stub.hpp"
|
||||
#include "asio/ssl/detail/openssl_types.hpp"
|
||||
#include <cstring>
|
||||
#include "asio/detail/throw_error.hpp"
|
||||
#include "asio/error.hpp"
|
||||
|
@ -7,7 +7,7 @@
|
||||
//
|
||||
|
||||
#include "asio/detail/config.hpp"
|
||||
#include "openssl_stub.hpp"
|
||||
#include "asio/ssl/detail/openssl_types.hpp"
|
||||
#include "asio/detail/throw_error.hpp"
|
||||
#include "asio/error.hpp"
|
||||
#include "asio/ssl/detail/engine.hpp"
|
||||
|
36
components/asio/port/src/asio_stub.cpp
Normal file
36
components/asio/port/src/asio_stub.cpp
Normal file
@ -0,0 +1,36 @@
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
// SPDX-FileContributor: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
//
|
||||
#include "asio/detail/posix_event.hpp"
|
||||
#include "asio/detail/throw_error.hpp"
|
||||
#include "asio/error.hpp"
|
||||
#include "asio/detail/push_options.hpp"
|
||||
#include <unistd.h>
|
||||
#include <climits>
|
||||
|
||||
namespace asio::detail {
|
||||
// This replaces asio's posix_event constructor
|
||||
// since the default POSIX version uses pthread_condattr_t operations (init, setclock, destroy),
|
||||
// which are not available on all IDF versions (some are defined in compilers' headers, others in
|
||||
// pthread library, but they typically return `ENOSYS` which causes trouble in the event wrapper)
|
||||
// IMPORTANT: Check implementation of posix_event() when upgrading upstream asio in order not to
|
||||
// miss any initialization step.
|
||||
posix_event::posix_event()
|
||||
: state_(0)
|
||||
{
|
||||
int error = ::pthread_cond_init(&cond_, nullptr);
|
||||
asio::error_code ec(error, asio::error::get_system_category());
|
||||
asio::detail::throw_error(ec, "event");
|
||||
}
|
||||
} // namespace asio::detail
|
||||
|
||||
extern "C" int pause (void)
|
||||
{
|
||||
while (true) {
|
||||
::sleep(UINT_MAX);
|
||||
}
|
||||
}
|
@ -1,3 +1,22 @@
|
||||
idf_component_register(SRCS eppp_link.c eppp_sdio_slave.c eppp_sdio_host.c
|
||||
if("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_GREATER "5.3")
|
||||
set(driver_deps esp_driver_gpio esp_driver_spi)
|
||||
else()
|
||||
set(driver_deps driver)
|
||||
endif()
|
||||
|
||||
if(CONFIG_EPPP_LINK_DEVICE_ETH)
|
||||
set(transport_src eppp_eth.c)
|
||||
endif()
|
||||
|
||||
if(CONFIG_EPPP_LINK_DEVICE_SDIO)
|
||||
set(transport_src eppp_sdio_slave.c eppp_sdio_host.c)
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS eppp_link.c ${transport_src}
|
||||
INCLUDE_DIRS "include"
|
||||
PRIV_REQUIRES esp_netif esp_driver_spi esp_driver_gpio esp_timer driver)
|
||||
PRIV_REQUIRES esp_netif esp_timer esp_eth ${driver_deps})
|
||||
|
||||
if(CONFIG_EPPP_LINK_DEVICE_ETH)
|
||||
idf_component_get_property(ethernet_init espressif__ethernet_init COMPONENT_LIB)
|
||||
target_link_libraries(${COMPONENT_LIB} PRIVATE ${ethernet_init})
|
||||
endif()
|
||||
|
@ -28,6 +28,16 @@ menu "eppp_link"
|
||||
help
|
||||
Use SDIO.
|
||||
|
||||
config EPPP_LINK_DEVICE_ETH
|
||||
bool "Ethernet"
|
||||
depends on SOC_EMAC_SUPPORTED
|
||||
help
|
||||
Use Ethernet.
|
||||
This transport could employ a full fledged Ethernet connection
|
||||
between two EPPP nodes via standard Ethernet cable.
|
||||
It could be also effectively connected directly on PCB, EMAC to EMAC,
|
||||
without any Ethernet PHY chips (using eth_dummy_phy driver).
|
||||
|
||||
endchoice
|
||||
|
||||
config EPPP_LINK_CONN_MAX_RETRY
|
||||
@ -67,4 +77,14 @@ menu "eppp_link"
|
||||
|
||||
endchoice
|
||||
|
||||
config EPPP_LINK_ETHERNET_OUR_ADDRESS
|
||||
string "MAC address our local node"
|
||||
default "06:00:00:00:00:01"
|
||||
depends on EPPP_LINK_DEVICE_ETH
|
||||
|
||||
config EPPP_LINK_ETHERNET_THEIR_ADDRESS
|
||||
string "MAC address the remote node"
|
||||
default "06:00:00:00:00:02"
|
||||
depends on EPPP_LINK_DEVICE_ETH
|
||||
|
||||
endmenu
|
||||
|
@ -11,12 +11,12 @@ We usually call this node a SLAVE microcontroller. The "HOST" microcontroller ru
|
||||
brings in the WiFi connectivity from the "SLAVE" microcontroller.
|
||||
|
||||
```
|
||||
SLAVE micro HOST micro
|
||||
\|/ +----------------+ +----------------+
|
||||
| | | serial line | |
|
||||
+---+ WiFi NAT PPPoS |=== UART / SPI / SDIO =====| PPPoS client |
|
||||
| (server)| | |
|
||||
+----------------+ +----------------+
|
||||
SLAVE micro HOST micro
|
||||
\|/ +----------------+ +----------------+
|
||||
| | | (serial) line | |
|
||||
+---+ WiFi NAT PPPoS |=== UART / SPI / SDIO / ETH ===| PPPoS client |
|
||||
| (server)| | |
|
||||
+----------------+ +----------------+
|
||||
```
|
||||
|
||||
## API
|
||||
@ -55,3 +55,9 @@ Tested with WiFi-NAPT example
|
||||
|
||||
* TCP - 9Mbits/s
|
||||
* UDP - 11Mbits/s
|
||||
|
||||
### Ethernet
|
||||
|
||||
- Internal EMAC with real PHY chip
|
||||
* TCP - 5Mbits/s
|
||||
* UDP - 8Mbits/s
|
||||
|
119
components/eppp_link/eppp_eth.c
Normal file
119
components/eppp_link/eppp_eth.c
Normal file
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
#include "esp_log.h"
|
||||
#include "esp_netif.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_mac.h"
|
||||
#include "eppp_link.h"
|
||||
#include "eppp_transport.h"
|
||||
#include "esp_eth_driver.h"
|
||||
#include "ethernet_init.h"
|
||||
#include "esp_eth_spec.h"
|
||||
|
||||
typedef struct header {
|
||||
uint8_t dst[ETH_ADDR_LEN];
|
||||
uint8_t src[ETH_ADDR_LEN];
|
||||
uint16_t len;
|
||||
} __attribute__((packed)) header_t;
|
||||
|
||||
static const char *TAG = "eppp_ethernet";
|
||||
static bool s_is_connected = false;
|
||||
static esp_eth_handle_t *s_eth_handles = NULL;
|
||||
static uint8_t s_out_buffer[ETH_MAX_PACKET_SIZE];
|
||||
static uint8_t s_their_mac[ETH_ADDR_LEN];
|
||||
static uint8_t s_our_mac[ETH_ADDR_LEN];
|
||||
|
||||
static void event_handler(void *arg, esp_event_base_t event_base,
|
||||
int32_t event_id, void *event_data)
|
||||
{
|
||||
switch (event_id) {
|
||||
case ETHERNET_EVENT_CONNECTED:
|
||||
ESP_LOGI(TAG, "Ethernet Link Up");
|
||||
s_is_connected = true;
|
||||
break;
|
||||
case ETHERNET_EVENT_DISCONNECTED:
|
||||
ESP_LOGI(TAG, "Ethernet Link Down");
|
||||
s_is_connected = false;
|
||||
break;
|
||||
case ETHERNET_EVENT_START:
|
||||
ESP_LOGI(TAG, "Ethernet Started");
|
||||
break;
|
||||
case ETHERNET_EVENT_STOP:
|
||||
ESP_LOGI(TAG, "Ethernet Stopped");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static esp_err_t receive(esp_eth_handle_t h, uint8_t *buffer, uint32_t len, void *netif)
|
||||
{
|
||||
header_t *head = (header_t *)buffer;
|
||||
size_t packet_len = head->len;
|
||||
if (len >= packet_len) {
|
||||
esp_err_t ret = esp_netif_receive(netif, buffer + ETH_HEADER_LEN, packet_len, NULL);
|
||||
free(buffer);
|
||||
return ret;
|
||||
}
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
__attribute__((weak)) esp_err_t eppp_transport_ethernet_init(esp_eth_handle_t *handle_array[])
|
||||
{
|
||||
uint8_t eth_port_cnt = 0;
|
||||
ESP_RETURN_ON_ERROR(ethernet_init_all(handle_array, ð_port_cnt), TAG, "Failed to init common eth drivers");
|
||||
ESP_RETURN_ON_FALSE(eth_port_cnt == 1, ESP_ERR_INVALID_ARG, TAG, "multiple Ethernet devices detected, please init only one");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
__attribute__((weak)) void eppp_transport_ethernet_deinit(esp_eth_handle_t *handle_array)
|
||||
{
|
||||
ethernet_deinit_all(s_eth_handles);
|
||||
}
|
||||
|
||||
|
||||
esp_err_t eppp_transport_init(eppp_config_t *config, esp_netif_t *esp_netif)
|
||||
{
|
||||
ESP_RETURN_ON_ERROR(eppp_transport_ethernet_init(&s_eth_handles), TAG, "Failed to initialize Ethernet driver");
|
||||
ESP_RETURN_ON_ERROR(esp_eth_update_input_path(s_eth_handles[0], receive, esp_netif), TAG, "Failed to set Ethernet Rx callback");
|
||||
sscanf(CONFIG_EPPP_LINK_ETHERNET_OUR_ADDRESS, "%2" PRIu8 ":%2" PRIu8 ":%2" PRIi8 ":%2" PRIu8 ":%2" PRIu8 ":%2" PRIu8,
|
||||
&s_our_mac[0], &s_our_mac[1], &s_our_mac[2], &s_our_mac[3], &s_our_mac[4], &s_our_mac[5]);
|
||||
|
||||
sscanf(CONFIG_EPPP_LINK_ETHERNET_THEIR_ADDRESS, "%2" PRIu8 ":%2" PRIu8 ":%2" PRIi8 ":%2" PRIu8 ":%2" PRIu8 ":%2" PRIu8,
|
||||
&s_their_mac[0], &s_their_mac[1], &s_their_mac[2], &s_their_mac[3], &s_their_mac[4], &s_their_mac[5]);
|
||||
esp_eth_ioctl(s_eth_handles[0], ETH_CMD_S_MAC_ADDR, s_our_mac);
|
||||
ESP_RETURN_ON_ERROR(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, event_handler, NULL), TAG, "Failed to register Ethernet handlers");
|
||||
ESP_RETURN_ON_ERROR(esp_eth_start(s_eth_handles[0]), TAG, "Failed to start Ethernet driver");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void eppp_transport_deinit(void)
|
||||
{
|
||||
esp_eth_stop(s_eth_handles[0]);
|
||||
eppp_transport_ethernet_deinit(s_eth_handles);
|
||||
}
|
||||
|
||||
esp_err_t eppp_transport_tx(void *h, void *buffer, size_t len)
|
||||
{
|
||||
if (!s_is_connected) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
// setup Ethernet header
|
||||
header_t *head = (header_t *)s_out_buffer;
|
||||
memcpy(head->dst, s_their_mac, ETH_ADDR_LEN);
|
||||
memcpy(head->src, s_our_mac, ETH_ADDR_LEN);
|
||||
head->len = len;
|
||||
// support only payloads with len <= ETH_MAX_PAYLOAD_LEN
|
||||
if (len > ETH_MAX_PAYLOAD_LEN) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
memcpy(s_out_buffer + ETH_HEADER_LEN, buffer, len);
|
||||
return esp_eth_transmit(s_eth_handles[0], s_out_buffer, len + ETH_HEADER_LEN);
|
||||
}
|
@ -12,7 +12,7 @@
|
||||
#include "esp_event.h"
|
||||
#include "esp_netif_ppp.h"
|
||||
#include "eppp_link.h"
|
||||
#include "esp_serial_slave_link/essl_sdio.h"
|
||||
#include "eppp_transport.h"
|
||||
|
||||
#if CONFIG_EPPP_LINK_DEVICE_SPI
|
||||
#include "driver/spi_master.h"
|
||||
@ -24,6 +24,12 @@
|
||||
#include "driver/uart.h"
|
||||
#endif
|
||||
|
||||
#if CONFIG_EPPP_LINK_DEVICE_ETH
|
||||
#define EPPP_NEEDS_TASK 0
|
||||
#else
|
||||
#define EPPP_NEEDS_TASK 1
|
||||
#endif
|
||||
|
||||
static const int GOT_IPV4 = BIT0;
|
||||
static const int CONNECTION_FAILED = BIT1;
|
||||
#define CONNECT_BITS (GOT_IPV4|CONNECTION_FAILED)
|
||||
@ -98,6 +104,8 @@ esp_err_t eppp_sdio_host_init(struct eppp_config_sdio_s *config);
|
||||
esp_err_t eppp_sdio_slave_init(void);
|
||||
void eppp_sdio_slave_deinit(void);
|
||||
void eppp_sdio_host_deinit(void);
|
||||
#elif CONFIG_EPPP_LINK_DEVICE_ETH
|
||||
|
||||
#else
|
||||
static esp_err_t transmit(void *h, void *buffer, size_t len)
|
||||
{
|
||||
@ -224,6 +232,8 @@ static esp_netif_t *netif_init(eppp_type_t role, eppp_config_t *eppp_config)
|
||||
.handle = h,
|
||||
#if CONFIG_EPPP_LINK_DEVICE_SDIO
|
||||
.transmit = role == EPPP_CLIENT ? eppp_sdio_host_tx : eppp_sdio_slave_tx,
|
||||
#elif CONFIG_EPPP_LINK_DEVICE_ETH
|
||||
.transmit = eppp_transport_tx,
|
||||
#else
|
||||
.transmit = transmit,
|
||||
#endif
|
||||
@ -691,6 +701,7 @@ esp_err_t eppp_perform(esp_netif_t *netif)
|
||||
|
||||
#endif // CONFIG_EPPP_LINK_DEVICE_SPI / UART
|
||||
|
||||
#if EPPP_NEEDS_TASK
|
||||
static void ppp_task(void *args)
|
||||
{
|
||||
esp_netif_t *netif = args;
|
||||
@ -699,6 +710,7 @@ static void ppp_task(void *args)
|
||||
h->exited = true;
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool have_some_eppp_netif(esp_netif_t *netif, void *ctx)
|
||||
{
|
||||
@ -738,6 +750,8 @@ void eppp_deinit(esp_netif_t *netif)
|
||||
} else {
|
||||
eppp_sdio_slave_deinit();
|
||||
}
|
||||
#elif CONFIG_EPPP_LINK_DEVICE_ETH
|
||||
eppp_transport_deinit();
|
||||
#endif
|
||||
netif_deinit(netif);
|
||||
}
|
||||
@ -781,6 +795,13 @@ esp_netif_t *eppp_init(eppp_type_t role, eppp_config_t *config)
|
||||
ESP_LOGE(TAG, "Failed to initialize SDIO %d", ret);
|
||||
return NULL;
|
||||
}
|
||||
#elif CONFIG_EPPP_LINK_DEVICE_ETH
|
||||
esp_err_t ret = eppp_transport_init(config, netif);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to initialize SDIO %d", ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
return netif;
|
||||
}
|
||||
@ -834,12 +855,13 @@ esp_netif_t *eppp_open(eppp_type_t role, eppp_config_t *config, int connect_time
|
||||
}
|
||||
|
||||
eppp_netif_start(netif);
|
||||
|
||||
#if EPPP_NEEDS_TASK
|
||||
if (xTaskCreate(ppp_task, "ppp connect", config->task.stack_size, netif, config->task.priority, NULL) != pdTRUE) {
|
||||
ESP_LOGE(TAG, "Failed to create a ppp connection task");
|
||||
eppp_deinit(netif);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
int netif_cnt = get_netif_num(netif);
|
||||
if (netif_cnt < 0) {
|
||||
eppp_close(netif);
|
||||
|
14
components/eppp_link/eppp_transport.h
Normal file
14
components/eppp_link/eppp_transport.h
Normal file
@ -0,0 +1,14 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
esp_err_t eppp_transport_init(eppp_config_t *config, esp_netif_t *esp_netif);
|
||||
|
||||
esp_err_t eppp_transport_tx(void *h, void *buffer, size_t len);
|
||||
|
||||
esp_err_t eppp_transport_rx(esp_netif_t *netif);
|
||||
|
||||
void eppp_transport_deinit(void);
|
2
components/eppp_link/examples/host/sdkconfig.ci.eth
Normal file
2
components/eppp_link/examples/host/sdkconfig.ci.eth
Normal file
@ -0,0 +1,2 @@
|
||||
CONFIG_IDF_TARGET="esp32"
|
||||
CONFIG_EPPP_LINK_DEVICE_ETH=y
|
2
components/eppp_link/examples/host/sdkconfig.ci.sdio
Normal file
2
components/eppp_link/examples/host/sdkconfig.ci.sdio
Normal file
@ -0,0 +1,2 @@
|
||||
CONFIG_IDF_TARGET="esp32p4"
|
||||
CONFIG_EPPP_LINK_DEVICE_SDIO=y
|
2
components/eppp_link/examples/slave/sdkconfig.ci.eth
Normal file
2
components/eppp_link/examples/slave/sdkconfig.ci.eth
Normal file
@ -0,0 +1,2 @@
|
||||
CONFIG_IDF_TARGET="esp32"
|
||||
CONFIG_EPPP_LINK_DEVICE_ETH=y
|
2
components/eppp_link/examples/slave/sdkconfig.ci.sdio
Normal file
2
components/eppp_link/examples/slave/sdkconfig.ci.sdio
Normal file
@ -0,0 +1,2 @@
|
||||
CONFIG_IDF_TARGET="esp32c6"
|
||||
CONFIG_EPPP_LINK_DEVICE_SDIO=y
|
@ -4,3 +4,4 @@ description: The component provides a general purpose PPP connectivity, typicall
|
||||
dependencies:
|
||||
idf: '>=5.2'
|
||||
espressif/esp_serial_slave_link: "^1.1.0"
|
||||
espressif/ethernet_init: '>=0.0.7'
|
||||
|
@ -63,6 +63,7 @@ typedef enum eppp_transport {
|
||||
EPPP_TRANSPORT_UART,
|
||||
EPPP_TRANSPORT_SPI,
|
||||
EPPP_TRANSPORT_SDIO,
|
||||
EPPP_TRANSPORT_ETHERNET,
|
||||
} eppp_transport_t;
|
||||
|
||||
|
||||
|
8
components/esp_dns/.cz.yaml
Normal file
8
components/esp_dns/.cz.yaml
Normal file
@ -0,0 +1,8 @@
|
||||
---
|
||||
commitizen:
|
||||
bump_message: 'bump(dns): $current_version -> $new_version'
|
||||
pre_bump_hooks: python ../../ci/changelog.py esp_dns
|
||||
tag_format: esp_dns-v$version
|
||||
version: 1.0.0
|
||||
version_files:
|
||||
- idf_component.yml
|
7
components/esp_dns/CHANGELOG.md
Normal file
7
components/esp_dns/CHANGELOG.md
Normal file
@ -0,0 +1,7 @@
|
||||
# Changelog
|
||||
|
||||
## [1.0.0](https://github.com/espressif/esp-protocols/commits/esp_dns-v1.0.0)
|
||||
|
||||
### Features
|
||||
|
||||
- Add ESP DNS module with support for UDP, TCP, DoT, and DoH protocols ([57cd6080](https://github.com/espressif/esp-protocols/commit/57cd6080))
|
15
components/esp_dns/CMakeLists.txt
Normal file
15
components/esp_dns/CMakeLists.txt
Normal file
@ -0,0 +1,15 @@
|
||||
idf_component_register(SRCS
|
||||
"esp_dns_udp.c"
|
||||
"esp_dns_tcp.c"
|
||||
"esp_dns_dot.c"
|
||||
"esp_dns_doh.c"
|
||||
"esp_dns.c"
|
||||
"esp_dns_lwip.c"
|
||||
"esp_dns_utils.c"
|
||||
INCLUDE_DIRS "include"
|
||||
PRIV_INCLUDE_DIRS "."
|
||||
PRIV_REQUIRES nvs_flash lwip esp_event esp-tls esp_http_client esp-tls tcp_transport)
|
||||
|
||||
if(CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_CUSTOM)
|
||||
target_link_libraries(${COMPONENT_LIB} "-u lwip_hook_netconn_external_resolve")
|
||||
endif()
|
201
components/esp_dns/LICENSE
Normal file
201
components/esp_dns/LICENSE
Normal file
@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
223
components/esp_dns/README.md
Normal file
223
components/esp_dns/README.md
Normal file
@ -0,0 +1,223 @@
|
||||
# ESP DNS Component
|
||||
|
||||
This component provides a flexible DNS resolution system for ESP32 devices with support for multiple DNS protocols. It allows applications to resolve domain names using various transport methods, including standard UDP/TCP DNS, and securely resolve them using DNS over TLS (DoT) and DNS over HTTPS (DoH).
|
||||
|
||||
## Table of Contents
|
||||
- [Features](#features)
|
||||
- [Requirements](#requirements)
|
||||
- [How to Use](#how-to-use)
|
||||
- [Configuration](#configuration)
|
||||
- [Certificate Options](#certificate-options)
|
||||
- [Limitations](#limitations)
|
||||
- [Performance Considerations](#performance-considerations)
|
||||
- [How It Works](#how-it-works)
|
||||
- [Troubleshooting](#troubleshooting)
|
||||
|
||||
## Features
|
||||
|
||||
- **Multiple Protocol Support** Choose from various DNS protocols:
|
||||
- Standard UDP DNS (Port 53)
|
||||
- TCP DNS (Port 53)
|
||||
- DNS over TLS (DoT) (Port 853)
|
||||
- DNS over HTTPS (DoH) (Port 443)
|
||||
|
||||
- **Secure DNS Resolution**: Supports encrypted DNS queries using TLS and HTTPS to protect privacy and prevent DNS spoofing.
|
||||
|
||||
- **Flexible Configuration**: Easily configure DNS servers, ports, timeouts, and protocol-specific options.
|
||||
|
||||
- **LWIP Integration**: Seamlessly integrates with the ESP-IDF networking stack through LWIP hooks.
|
||||
|
||||
- **Standard getaddrinfo() Interface**: Use the standard `getaddrinfo()` function to resolve domain names.
|
||||
|
||||
|
||||
## Requirements
|
||||
|
||||
- ESP-IDF v5.0 or newer
|
||||
- Network connectivity (Wi-Fi or Ethernet)
|
||||
- For DoT/DoH: Sufficient RAM for TLS operations
|
||||
|
||||
|
||||
## How to Use
|
||||
|
||||
### 1. Enable custom DNS resolution
|
||||
|
||||
To enable custom DNS resolution, configure the `CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_CUSTOM` setting either through menuconfig or by adding `CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_CUSTOM=y` to your `sdkconfig.defaults` file to pre-set the configuration during the build process.
|
||||
|
||||
### 2. Configure DNS Settings
|
||||
|
||||
Initialize the DNS component with your preferred configuration:
|
||||
```C
|
||||
#include "esp_dns.h"
|
||||
|
||||
/* Configure DNS over HTTPS */
|
||||
esp_dns_config_t dns_config = {
|
||||
.dns_server = "dns.google", /* DNS server hostname or IP address */
|
||||
.port = ESP_DNS_DEFAULT_DOH_PORT, /* Optional: Server port (443 is default for HTTPS) */
|
||||
.timeout_ms = ESP_DNS_DEFAULT_TIMEOUT_MS, /* Optional: Request timeout in milliseconds (10000ms default) */
|
||||
.tls_config = {
|
||||
/* Optional: Use ESP-IDF certificate bundle for validating popular DNS providers */
|
||||
.crt_bundle_attach = esp_crt_bundle_attach,
|
||||
|
||||
/* Or provide a custom certificate in PEM format (string) for your DNS server */
|
||||
/* Note: Only PEM format is supported; DER format certificates are not supported yet */
|
||||
.cert_pem = server_root_cert_pem_start,
|
||||
|
||||
/* Note: If both crt_bundle_attach and cert_pem are provided,
|
||||
crt_bundle_attach is preferred over cert_pem */
|
||||
},
|
||||
.protocol_config.doh_config = {
|
||||
.url_path = "/dns-query", /* Optional: DoH endpoint path on the server ("/dns-query" default) */
|
||||
}
|
||||
};
|
||||
|
||||
/* Initialize DNS component based on protocol */
|
||||
esp_dns_handle_t dns_handle = NULL;
|
||||
|
||||
/* Call esp_dns_init_doh() to use DNS over HTTPS */
|
||||
dns_handle = esp_dns_init_doh(&dns_config);
|
||||
|
||||
/* or Call esp_dns_init_dot() to use DNS over TLS */
|
||||
dns_handle = esp_dns_init_dot(&dns_config);
|
||||
|
||||
/* or Call esp_dns_init_tcp() to use DNS over TCP */
|
||||
dns_handle = esp_dns_init_tcp(&dns_config);
|
||||
|
||||
/* or Call esp_dns_init_udp() to use DNS over UDP */
|
||||
dns_handle = esp_dns_init_udp(&dns_config);
|
||||
|
||||
if (dns_handle == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to initialize DNS");
|
||||
return;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### 3. Resolve Domain Names
|
||||
|
||||
Once initialized, the component automatically handles DNS resolution through the standard `getaddrinfo()` function:
|
||||
|
||||
```C
|
||||
struct addrinfo hints = {
|
||||
.ai_family = AF_UNSPEC,
|
||||
.ai_socktype = SOCK_STREAM,
|
||||
};
|
||||
struct addrinfo res;
|
||||
int err = getaddrinfo("www.example.com", "80", &hints, &res);
|
||||
if (err != 0) {
|
||||
ESP_LOGE(TAG, "DNS lookup failed: %d", err);
|
||||
return;
|
||||
}
|
||||
/* Use the resolved addresses */
|
||||
/* ... */
|
||||
|
||||
/* Free the address info when done */
|
||||
freeaddrinfo(res);
|
||||
```
|
||||
|
||||
### 4. Cleanup
|
||||
|
||||
When you're done using the DNS component, clean up resources based on the protocol used:
|
||||
|
||||
```C
|
||||
int ret = 0;
|
||||
/* Call esp_dns_cleanup_doh() to cleanup DNS over HTTPS */
|
||||
ret = esp_dns_cleanup_doh(dns_handle);
|
||||
|
||||
/* or Call esp_dns_cleanup_dot() to cleanup DNS over TLS */
|
||||
ret = esp_dns_cleanup_dot(dns_handle);
|
||||
|
||||
/* or Call esp_dns_cleanup_tcp() to cleanup DNS over TCP */
|
||||
ret = esp_dns_cleanup_tcp(dns_handle);
|
||||
|
||||
/* or Call esp_dns_cleanup_udp() to cleanup DNS over UDP */
|
||||
ret = esp_dns_cleanup_udp(dns_handle);
|
||||
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "Failed to cleanup DNS");
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Configuration
|
||||
|
||||
### Setting Up the ESP DNS Component
|
||||
|
||||
1. Navigate to your project directory.
|
||||
2. Execute `idf.py menuconfig`.
|
||||
3. Locate the **Component config -> LWIP -> Hooks -> Netconn external resolve Hook** section.
|
||||
4. Change the setting to `Custom implementation`.
|
||||
|
||||
### Common Settings
|
||||
|
||||
| Parameter | Description | Default Value |
|
||||
|-----------|-------------|---------------|
|
||||
| `dns_server` | IP address or hostname of DNS server | `"8.8.8.8"` (Google DNS) |
|
||||
| `port` | Server port number | Protocol-dependent (53, 853, or 443) |
|
||||
| `timeout_ms` | Query timeout in milliseconds | `10000` (10 seconds) |
|
||||
|
||||
### TLS Configuration (for DoT and DoH)
|
||||
|
||||
| Parameter | Description |
|
||||
|-----------|-------------|
|
||||
| `crt_bundle_attach` | Function pointer to attach certificate bundle |
|
||||
| `server_cert` | SSL server certificate in PEM format |
|
||||
| `alpn_protos` | ALPN protocols for DoH (typically `"h2"`) |
|
||||
|
||||
### Protocol-Specific Options
|
||||
|
||||
#### DoH Options
|
||||
- **URL Path**: URL path for DoH service (e.g., "/dns-query")
|
||||
|
||||
|
||||
## Certificate Options
|
||||
|
||||
When using secure DNS protocols (DoT and DoH), you have two certificate options:
|
||||
|
||||
1. **Certificate Bundle**: Use ESP-IDF's certificate bundle for validating connections to popular DNS providers.
|
||||
2. **Custom Certificate**: Provide your own certificate in PEM format for custom DNS servers.
|
||||
|
||||
|
||||
## Limitations
|
||||
|
||||
- The UDP DNS protocol implementation relies on the native LWIP DNS resolver.
|
||||
- Transport protocol selection must be configured through `esp_dns_init_xxx()` rather than `getaddrinfo()` parameters due to LWIP resolver hook limitations.
|
||||
- Maximum response size is limited by the buffer size (default: 512 bytes) for DNS over TLS (DOT) and TCP protocols.
|
||||
- Only one DNS protocol can be active at a time.
|
||||
|
||||
- **Resolution Speed**:
|
||||
- UDP DNS is fastest but least secure
|
||||
- DoH typically has the highest latency but offers the best security
|
||||
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
- **Memory Usage**: DoH and DoT require more memory due to TLS overhead:
|
||||
|
||||
TBD: Fill in the memory usage for each protocol
|
||||
|
||||
|
||||
## How It Works
|
||||
This component utilizes the `CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_CUSTOM` hook to override the core DNS functionality of LWIP and implement custom DNS over HTTPS resolution. To enable this, ensure that the configuration option `Component config → LWIP → Hooks → Netconn external resolve Hook` is set to `Custom implementation`.
|
||||
|
||||
Once you add this component to your project, it will replace the default LWIP DNS resolution automatically.
|
||||
|
||||
**⚠️ Warning:** This component cannot work alongside other components that use the `CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_CUSTOM` hook.
|
||||
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **Connection Issues**:
|
||||
- Ensure network connectivity and correct DNS server configuration
|
||||
- Verify that your network allows the required ports (53, 853, or 443)
|
||||
|
||||
- **Certificate Errors**:
|
||||
- Verify that the correct certificate is provided for secure protocols
|
||||
- For public DNS servers, use the certificate bundle approach
|
||||
|
||||
- **Timeout Errors**:
|
||||
- Increase the timeout value for slow network connections
|
||||
- Try a different DNS server that might be geographically closer
|
||||
|
||||
- **Memory Issues**:
|
||||
- If you encounter memory errors, consider increasing the task stack size
|
||||
- For memory-constrained devices, prefer UDP DNS.
|
157
components/esp_dns/esp_dns.c
Normal file
157
components/esp_dns/esp_dns.c
Normal file
@ -0,0 +1,157 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file esp_dns.c
|
||||
* @brief Custom DNS module for ESP32 with multiple protocol support
|
||||
*
|
||||
* This module provides DNS resolution capabilities with support for various protocols:
|
||||
* - Standard UDP/TCP DNS (Port 53)
|
||||
* - DNS over TLS (DoT) (Port 853)
|
||||
* - DNS over HTTPS (DoH) (Port 443)
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "esp_dns_priv.h"
|
||||
#include "esp_dns.h"
|
||||
|
||||
#define TAG "ESP_DNS"
|
||||
|
||||
/* Global DNS handle instance */
|
||||
esp_dns_handle_t g_dns_handle = NULL;
|
||||
|
||||
/* Mutex for protecting global handle access */
|
||||
static SemaphoreHandle_t s_dns_global_mutex = NULL;
|
||||
|
||||
/**
|
||||
* @brief Creates or returns a singleton DNS handle instance
|
||||
*
|
||||
* This function implements a singleton pattern for the DNS handle. It creates
|
||||
* a static instance of the dns_handle structure on first call and initializes
|
||||
* it to zeros. On subsequent calls, it returns a pointer to the same instance.
|
||||
*
|
||||
* The function ensures that only one DNS handle exists throughout the application
|
||||
* lifecycle, which helps manage resources efficiently.
|
||||
*
|
||||
* @return Pointer to the singleton DNS handle instance
|
||||
*/
|
||||
static esp_dns_handle_t esp_dns_create_handle(void)
|
||||
{
|
||||
static struct esp_dns_handle instance;
|
||||
static bool initialized = false;
|
||||
|
||||
if (!initialized) {
|
||||
memset(&instance, 0, sizeof(instance));
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
return &instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize the DNS module with provided configuration
|
||||
*
|
||||
* @param config DNS configuration parameters
|
||||
*
|
||||
* @return On success, returns a handle to the initialized DNS module
|
||||
* On failure, returns NULL
|
||||
*/
|
||||
esp_dns_handle_t esp_dns_init(const esp_dns_config_t *config)
|
||||
{
|
||||
/* Create global mutex if it doesn't exist */
|
||||
if (s_dns_global_mutex == NULL) {
|
||||
s_dns_global_mutex = xSemaphoreCreateMutex();
|
||||
if (s_dns_global_mutex == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to create global mutex");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Take the global mutex */
|
||||
if (xSemaphoreTake(s_dns_global_mutex, portMAX_DELAY) != pdTRUE) {
|
||||
ESP_LOGE(TAG, "Failed to take global mutex");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Check if we need to clean up an existing handle */
|
||||
if (g_dns_handle != NULL) {
|
||||
ESP_LOGE(TAG, "DNS handle already initialized. Call esp_dns_cleanup() before reinitializing");
|
||||
xSemaphoreGive(s_dns_global_mutex);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Allocate memory for the new handle */
|
||||
esp_dns_handle_t handle = esp_dns_create_handle();
|
||||
if (handle == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to allocate memory for DNS handle");
|
||||
xSemaphoreGive(s_dns_global_mutex);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Copy configuration */
|
||||
memcpy(&handle->config, config, sizeof(esp_dns_config_t));
|
||||
|
||||
/* Create mutex for this handle */
|
||||
handle->lock = xSemaphoreCreateMutex();
|
||||
if (handle->lock == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to create handle mutex");
|
||||
free(handle);
|
||||
xSemaphoreGive(s_dns_global_mutex);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Set global handle */
|
||||
g_dns_handle = handle;
|
||||
handle->initialized = true;
|
||||
|
||||
/* Release global mutex */
|
||||
xSemaphoreGive(s_dns_global_mutex);
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Cleanup and release resources associated with a DNS module handle
|
||||
*
|
||||
* @param handle DNS module handle previously obtained from esp_dns_init()
|
||||
*
|
||||
* @return 0 on success, non-zero error code on failure
|
||||
*/
|
||||
int esp_dns_cleanup(esp_dns_handle_t handle)
|
||||
{
|
||||
/* Take the handle mutex */
|
||||
if (xSemaphoreTake(handle->lock, portMAX_DELAY) != pdTRUE) {
|
||||
ESP_LOGE(TAG, "Failed to take handle mutex during cleanup");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Release and delete mutex */
|
||||
xSemaphoreGive(handle->lock);
|
||||
vSemaphoreDelete(handle->lock);
|
||||
|
||||
/* Take global mutex before modifying global handle */
|
||||
if (s_dns_global_mutex != NULL && xSemaphoreTake(s_dns_global_mutex, portMAX_DELAY) == pdTRUE) {
|
||||
/* Clear global handle if it matches this one */
|
||||
if (g_dns_handle == handle) {
|
||||
g_dns_handle = NULL;
|
||||
}
|
||||
|
||||
xSemaphoreGive(s_dns_global_mutex);
|
||||
}
|
||||
|
||||
/* Mark as uninitialized */
|
||||
handle->initialized = false;
|
||||
|
||||
return 0;
|
||||
}
|
309
components/esp_dns/esp_dns_doh.c
Normal file
309
components/esp_dns/esp_dns_doh.c
Normal file
@ -0,0 +1,309 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "esp_event.h"
|
||||
#include "esp_log.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_http_client.h"
|
||||
#include "esp_dns_utils.h"
|
||||
#include "esp_dns_priv.h"
|
||||
#include "esp_dns.h"
|
||||
|
||||
#define TAG "ESP_DNS_DOH"
|
||||
|
||||
#define SERVER_URL_MAX_SZ 256
|
||||
|
||||
/**
|
||||
* @brief Initializes the DNS over HTTPS (DoH) module
|
||||
*
|
||||
* Sets up the DoH service using the provided configuration. Validates the parameters,
|
||||
* sets the protocol, and initializes the DNS module. Returns a handle for further use.
|
||||
*
|
||||
* @param config Pointer to the DNS configuration structure, which must be initialized
|
||||
*
|
||||
* @return On success, returns a handle to the initialized DoH module; returns NULL on failure
|
||||
*/
|
||||
esp_dns_handle_t esp_dns_init_doh(esp_dns_config_t *config)
|
||||
{
|
||||
ESP_LOGD(TAG, "Initializing DNS over HTTPS");
|
||||
|
||||
/* Validate parameters */
|
||||
if (config == NULL) {
|
||||
ESP_LOGE(TAG, "Invalid configuration (NULL)");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
config->protocol = ESP_DNS_PROTOCOL_DOH;
|
||||
|
||||
esp_dns_handle_t handle = esp_dns_init(config);
|
||||
if (handle == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to initialize DNS");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "DNS module initialized successfully with protocol DNS Over HTTPS(%d)", config->protocol);
|
||||
return handle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Cleans up the DNS over HTTPS (DoH) module
|
||||
*
|
||||
* Releases resources allocated for the DoH service. Validates the parameters,
|
||||
* checks the protocol, and cleans up the DNS module.
|
||||
*
|
||||
* @param handle Pointer to the DNS handle to be cleaned up
|
||||
*
|
||||
* @return 0 on success, or -1 on failure
|
||||
*/
|
||||
int esp_dns_cleanup_doh(esp_dns_handle_t handle)
|
||||
{
|
||||
ESP_LOGD(TAG, "Cleaning up DNS over HTTPS");
|
||||
|
||||
/* Validate parameters */
|
||||
if (handle == NULL) {
|
||||
ESP_LOGE(TAG, "Invalid handle (NULL)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (handle->config.protocol != ESP_DNS_PROTOCOL_DOH) {
|
||||
ESP_LOGW(TAG, "Unknown protocol during cleanup: %d", handle->config.protocol);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ret = esp_dns_cleanup(handle);
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "Failed to cleanup DNS");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Empty the handle */
|
||||
memset(handle, 0, sizeof(*handle));
|
||||
|
||||
ESP_LOGD(TAG, "DNS module cleaned up DNS Over HTTPS successfully");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief HTTP event handler for DNS over HTTPS requests
|
||||
*
|
||||
* Handles HTTP events during DNS over HTTPS communication, including data reception,
|
||||
* connection status, and error conditions.
|
||||
*
|
||||
* @param evt Pointer to the HTTP client event structure
|
||||
*
|
||||
* @return ESP_OK on success, or an error code on failure
|
||||
*/
|
||||
esp_err_t esp_dns_http_event_handler(esp_http_client_event_t *evt)
|
||||
{
|
||||
char *temp_buff = NULL;
|
||||
size_t temp_buff_len = 0;
|
||||
esp_dns_handle_t handle = (esp_dns_handle_t)evt->user_data;
|
||||
|
||||
switch (evt->event_id) {
|
||||
case HTTP_EVENT_ERROR:
|
||||
ESP_LOGD(TAG, "HTTP_EVENT_ERROR");
|
||||
break;
|
||||
case HTTP_EVENT_ON_CONNECTED:
|
||||
ESP_LOGD(TAG, "HTTP_EVENT_ON_CONNECTED");
|
||||
break;
|
||||
case HTTP_EVENT_HEADER_SENT:
|
||||
ESP_LOGD(TAG, "HTTP_EVENT_HEADER_SENT");
|
||||
break;
|
||||
case HTTP_EVENT_ON_HEADER:
|
||||
ESP_LOGD(TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value);
|
||||
break;
|
||||
case HTTP_EVENT_ON_DATA:
|
||||
ESP_LOGD(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
|
||||
/* Check if buffer is null, if yes, initialize it */
|
||||
if (handle->response_buffer.buffer == NULL) {
|
||||
if (evt->data_len == 0) {
|
||||
ESP_LOGW(TAG, "Received empty HTTP data");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
temp_buff = malloc(evt->data_len);
|
||||
if (temp_buff) {
|
||||
handle->response_buffer.buffer = temp_buff;
|
||||
handle->response_buffer.length = evt->data_len;
|
||||
memcpy(handle->response_buffer.buffer, evt->data, evt->data_len);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Buffer allocation error");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
} else {
|
||||
/* Reallocate buffer to hold the new data chunk */
|
||||
int new_len = handle->response_buffer.length + evt->data_len;
|
||||
if (new_len == 0) {
|
||||
ESP_LOGW(TAG, "New data length is zero after receiving HTTP data");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
temp_buff = realloc(handle->response_buffer.buffer, new_len);
|
||||
if (temp_buff) {
|
||||
handle->response_buffer.buffer = temp_buff;
|
||||
memcpy(handle->response_buffer.buffer + handle->response_buffer.length, evt->data, evt->data_len);
|
||||
handle->response_buffer.length = new_len;
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Buffer allocation error");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case HTTP_EVENT_ON_FINISH:
|
||||
ESP_LOGD(TAG, "HTTP_EVENT_ON_FINISH");
|
||||
/* Entire response received, process it here */
|
||||
ESP_LOGD(TAG, "Received full response, length: %d", handle->response_buffer.length);
|
||||
|
||||
/* Check if the buffer indicates an HTTP error response */
|
||||
if (HttpStatus_Ok == esp_http_client_get_status_code(evt->client)) {
|
||||
/* Parse the DNS response */
|
||||
esp_dns_parse_response((uint8_t *)handle->response_buffer.buffer,
|
||||
handle->response_buffer.length,
|
||||
&handle->response_buffer.dns_response);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "HTTP Error: %d", esp_http_client_get_status_code(evt->client));
|
||||
temp_buff_len = handle->response_buffer.length > ESP_DNS_BUFFER_SIZE ? ESP_DNS_BUFFER_SIZE : handle->response_buffer.length;
|
||||
ESP_LOG_BUFFER_HEXDUMP(TAG, handle->response_buffer.buffer, temp_buff_len, ESP_LOG_ERROR);
|
||||
handle->response_buffer.dns_response.status_code = ERR_VAL; /* TBD: Not handled properly yet */
|
||||
}
|
||||
|
||||
free(handle->response_buffer.buffer);
|
||||
handle->response_buffer.buffer = NULL;
|
||||
handle->response_buffer.length = 0;
|
||||
break;
|
||||
case HTTP_EVENT_DISCONNECTED:
|
||||
ESP_LOGD(TAG, "HTTP_EVENT_DISCONNECTED");
|
||||
break;
|
||||
case HTTP_EVENT_REDIRECT:
|
||||
ESP_LOGE(TAG, "HTTP_EVENT_REDIRECT: Not supported(%d)", esp_http_client_get_status_code(evt->client));
|
||||
break;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Resolves a hostname using DNS over HTTPS
|
||||
*
|
||||
* This function generates a DNS request, sends it via HTTPS, and processes
|
||||
* the response to extract IP addresses.
|
||||
*
|
||||
* @param handle Pointer to the DNS handle
|
||||
* @param name The hostname to resolve
|
||||
* @param addr Pointer to store the resolved IP addresses
|
||||
* @param rrtype The address RR type (A or AAAA)
|
||||
*
|
||||
* @return ERR_OK on success, or an error code on failure
|
||||
*/
|
||||
err_t dns_resolve_doh(const esp_dns_handle_t handle, const char *name, ip_addr_t *addr, u8_t rrtype)
|
||||
{
|
||||
uint8_t buffer_qry[ESP_DNS_BUFFER_SIZE];
|
||||
|
||||
/* Initialize error status */
|
||||
err_t err = ERR_OK;
|
||||
const char *prefix = "https://";
|
||||
|
||||
/* Set default values for DoH configuration if not specified */
|
||||
const char *url_path = handle->config.protocol_config.doh_config.url_path ?
|
||||
handle->config.protocol_config.doh_config.url_path : "dns-query";
|
||||
int port = handle->config.port ?
|
||||
handle->config.port : ESP_DNS_DEFAULT_DOH_PORT;
|
||||
|
||||
/* Calculate required URL length: https:// + server + / + path + null terminator */
|
||||
size_t url_len = strlen(prefix) + \
|
||||
strlen(handle->config.dns_server) + 1 + \
|
||||
strlen(url_path) + 1; /* 1 for '/' and 1 for '\0' */
|
||||
|
||||
/* Allocate memory for the full server URL */
|
||||
char *dns_server_url = malloc(url_len);
|
||||
if (dns_server_url == NULL) {
|
||||
ESP_LOGE(TAG, "Memory allocation failed");
|
||||
return ERR_MEM;
|
||||
}
|
||||
|
||||
/* Construct the complete server URL by combining prefix, server and path */
|
||||
snprintf(dns_server_url, url_len, "%s%s/%s", prefix,
|
||||
handle->config.dns_server,
|
||||
url_path);
|
||||
|
||||
/* Configure the HTTP client with base settings */
|
||||
esp_http_client_config_t config = {
|
||||
.url = dns_server_url,
|
||||
.event_handler = esp_dns_http_event_handler,
|
||||
.method = HTTP_METHOD_POST,
|
||||
.user_data = handle,
|
||||
.port = port,
|
||||
};
|
||||
|
||||
/* Configure TLS certificate settings - either using bundle or PEM cert */
|
||||
if (handle->config.tls_config.crt_bundle_attach) {
|
||||
config.crt_bundle_attach = handle->config.tls_config.crt_bundle_attach;
|
||||
} else {
|
||||
config.cert_pem = handle->config.tls_config.cert_pem; /* Use the root certificate for dns.google if needed */
|
||||
}
|
||||
|
||||
/* Clear the response buffer to ensure no residual data remains */
|
||||
memset(&handle->response_buffer, 0, sizeof(response_buffer_t));
|
||||
|
||||
/* Create DNS query in wire format */
|
||||
size_t query_size = esp_dns_create_query(buffer_qry, sizeof(buffer_qry), name, rrtype, &handle->response_buffer.dns_response.id);
|
||||
if (query_size == -1) {
|
||||
ESP_LOGE(TAG, "Error: Hostname too big");
|
||||
err = ERR_MEM;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Initialize HTTP client with the configuration */
|
||||
esp_http_client_handle_t client = esp_http_client_init(&config);
|
||||
if (client == NULL) {
|
||||
ESP_LOGE(TAG, "Error initializing HTTP client");
|
||||
err = ERR_VAL;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Set Content-Type header for DNS-over-HTTPS */
|
||||
esp_err_t ret = esp_http_client_set_header(client, "Content-Type", "application/dns-message");
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Error setting HTTP header: %s", esp_err_to_name(ret));
|
||||
err = ERR_VAL;
|
||||
goto client_cleanup;
|
||||
}
|
||||
|
||||
/* Set the DNS query as POST data */
|
||||
ret = esp_http_client_set_post_field(client, (const char *)buffer_qry, query_size);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Error setting POST field: %s", esp_err_to_name(ret));
|
||||
err = ERR_VAL;
|
||||
goto client_cleanup;
|
||||
}
|
||||
|
||||
/* Execute the HTTP request */
|
||||
ret = esp_http_client_perform(client);
|
||||
if (ret == ESP_OK) {
|
||||
ESP_LOGD(TAG, "HTTP POST Status = %d, content_length = %lld",
|
||||
esp_http_client_get_status_code(client),
|
||||
esp_http_client_get_content_length(client));
|
||||
|
||||
/* Verify HTTP status code and DNS response status */
|
||||
if ((HttpStatus_Ok != esp_http_client_get_status_code(client)) ||
|
||||
(handle->response_buffer.dns_response.status_code != ERR_OK)) {
|
||||
err = ERR_ARG;
|
||||
goto client_cleanup;
|
||||
}
|
||||
|
||||
/* Extract IP addresses from DNS response */
|
||||
err = esp_dns_extract_ip_addresses_from_response(&handle->response_buffer.dns_response, addr);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "HTTP POST request failed: %s", esp_err_to_name(ret));
|
||||
err = ERR_VAL;
|
||||
}
|
||||
|
||||
/* Clean up HTTP client */
|
||||
client_cleanup:
|
||||
esp_http_client_cleanup(client);
|
||||
|
||||
/* Free allocated memory */
|
||||
cleanup:
|
||||
free(dns_server_url);
|
||||
|
||||
return err;
|
||||
}
|
205
components/esp_dns/esp_dns_dot.c
Normal file
205
components/esp_dns/esp_dns_dot.c
Normal file
@ -0,0 +1,205 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "esp_transport.h"
|
||||
#include "esp_transport_ssl.h"
|
||||
#include "esp_dns_priv.h"
|
||||
#include "esp_dns.h"
|
||||
|
||||
|
||||
#define TAG "ESP_DNS_DOT"
|
||||
|
||||
|
||||
/**
|
||||
* @brief Initializes the DNS over TLS (DoT) module
|
||||
*
|
||||
* Sets up the DoT service using the provided configuration. Validates the parameters,
|
||||
* sets the protocol, and initializes the DNS module. Returns a handle for further use.
|
||||
*
|
||||
* @param config Pointer to the DNS configuration structure, which must be initialized
|
||||
*
|
||||
* @return On success, returns a handle to the initialized DoT module; returns NULL on failure
|
||||
*/
|
||||
esp_dns_handle_t esp_dns_init_dot(esp_dns_config_t *config)
|
||||
{
|
||||
ESP_LOGD(TAG, "Initializing DNS over TLS");
|
||||
|
||||
/* Validate parameters */
|
||||
if (config == NULL) {
|
||||
ESP_LOGE(TAG, "Invalid configuration (NULL)");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
config->protocol = ESP_DNS_PROTOCOL_DOT;
|
||||
|
||||
esp_dns_handle_t handle = esp_dns_init(config);
|
||||
if (handle == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to initialize DNS");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "DNS module initialized successfully with protocol DNS Over TLS(%d)", config->protocol);
|
||||
return handle;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Cleans up the DNS over TLS (DoT) module
|
||||
*
|
||||
* Releases resources allocated for the DoT service. Validates the parameters,
|
||||
* checks the protocol, and cleans up the DNS module.
|
||||
*
|
||||
* @param handle Pointer to the DNS handle to be cleaned up
|
||||
*
|
||||
* @return 0 on success, or -1 on failure
|
||||
*/
|
||||
int esp_dns_cleanup_dot(esp_dns_handle_t handle)
|
||||
{
|
||||
ESP_LOGD(TAG, "Cleaning up DNS over TLS");
|
||||
|
||||
/* Validate parameters */
|
||||
if (handle == NULL) {
|
||||
ESP_LOGE(TAG, "Invalid handle (NULL)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (handle->config.protocol != ESP_DNS_PROTOCOL_DOT) {
|
||||
ESP_LOGW(TAG, "Unknown protocol during cleanup: %d", handle->config.protocol);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ret = esp_dns_cleanup(handle);
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "Failed to cleanup DNS");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Empty the handle */
|
||||
memset(handle, 0, sizeof(*handle));
|
||||
|
||||
ESP_LOGD(TAG, "DNS module cleaned up DNS Over TLS successfully");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Resolves a hostname using DNS over TLS (DoT)
|
||||
*
|
||||
* Performs DNS resolution over a TLS-encrypted connection. Creates a DNS query,
|
||||
* establishes a TLS connection, sends the query, and processes the response.
|
||||
*
|
||||
* @param handle Pointer to the DNS handle
|
||||
* @param name Hostname to resolve
|
||||
* @param addr Pointer to store the resolved IP address
|
||||
* @param rrtype DNS record type to query
|
||||
*
|
||||
* @return ERR_OK on success, or an error code on failure
|
||||
*/
|
||||
err_t dns_resolve_dot(const esp_dns_handle_t handle, const char *name, ip_addr_t *addr, u8_t rrtype)
|
||||
{
|
||||
int err = ERR_OK;
|
||||
esp_transport_handle_t transport = NULL;
|
||||
int len = 0;
|
||||
char dot_buffer[ESP_DNS_BUFFER_SIZE];
|
||||
size_t query_size;
|
||||
int timeout_ms;
|
||||
int dot_port;
|
||||
|
||||
if (addr == NULL) {
|
||||
return ERR_ARG;
|
||||
}
|
||||
|
||||
/* Set timeout and port values, using defaults if not specified in config */
|
||||
timeout_ms = handle->config.timeout_ms ? : ESP_DNS_DEFAULT_TIMEOUT_MS;
|
||||
dot_port = handle->config.port ? : ESP_DNS_DEFAULT_DOT_PORT;
|
||||
|
||||
/* Clear the response buffer to ensure no residual data remains */
|
||||
memset(&handle->response_buffer, 0, sizeof(response_buffer_t));
|
||||
|
||||
/* Create DNS query in wire format, leaving 2 bytes at start for length prefix as required by RFC 7858 */
|
||||
memset(dot_buffer, 0, ESP_DNS_BUFFER_SIZE);
|
||||
query_size = esp_dns_create_query((uint8_t *)(dot_buffer + 2), sizeof(dot_buffer) - 2,
|
||||
name, rrtype, &handle->response_buffer.dns_response.id);
|
||||
if (query_size == -1) {
|
||||
ESP_LOGE(TAG, "Error: Hostname too big");
|
||||
return ERR_MEM;
|
||||
}
|
||||
|
||||
/* Prepends the 2-byte length field to DNS messages as required by RFC 7858 */
|
||||
dot_buffer[0] = (query_size >> 8) & 0xFF;
|
||||
dot_buffer[1] = query_size & 0xFF;
|
||||
|
||||
transport = esp_transport_ssl_init();
|
||||
if (!transport) {
|
||||
ESP_LOGE(TAG, "Failed to initialize transport");
|
||||
return ERR_MEM;
|
||||
}
|
||||
|
||||
/* Configure TLS certificate settings - either using bundle or PEM cert */
|
||||
if (handle->config.tls_config.crt_bundle_attach) {
|
||||
esp_transport_ssl_crt_bundle_attach(transport, handle->config.tls_config.crt_bundle_attach);
|
||||
} else {
|
||||
if (handle->config.tls_config.cert_pem == NULL) {
|
||||
ESP_LOGE(TAG, "Certificate PEM data is null");
|
||||
err = ERR_VAL;
|
||||
goto cleanup;
|
||||
}
|
||||
esp_transport_ssl_set_cert_data(transport,
|
||||
handle->config.tls_config.cert_pem,
|
||||
strlen(handle->config.tls_config.cert_pem));
|
||||
}
|
||||
|
||||
if (esp_transport_connect(transport, handle->config.dns_server, dot_port, timeout_ms) < 0) {
|
||||
ESP_LOGE(TAG, "TLS connection failed");
|
||||
err = ERR_CONN;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Send DNS query */
|
||||
len = esp_transport_write(transport,
|
||||
dot_buffer,
|
||||
query_size + 2,
|
||||
timeout_ms);
|
||||
if (len < 0) {
|
||||
ESP_LOGE(TAG, "Failed to send DNS query");
|
||||
err = ERR_ABRT;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Read response */
|
||||
memset(dot_buffer, 0, ESP_DNS_BUFFER_SIZE);
|
||||
len = esp_transport_read(transport,
|
||||
dot_buffer,
|
||||
sizeof(dot_buffer),
|
||||
timeout_ms);
|
||||
if (len > 0) {
|
||||
/* Skip the 2-byte length field that prepends DNS messages as required by RFC 7858 */
|
||||
handle->response_buffer.buffer = dot_buffer + 2;
|
||||
handle->response_buffer.length = len - 2;
|
||||
|
||||
/* Parse the DNS response */
|
||||
esp_dns_parse_response((uint8_t *)handle->response_buffer.buffer,
|
||||
handle->response_buffer.length,
|
||||
&handle->response_buffer.dns_response);
|
||||
|
||||
/* Extract IP addresses from DNS response */
|
||||
err = esp_dns_extract_ip_addresses_from_response(&handle->response_buffer.dns_response, addr);
|
||||
if (err != ERR_OK) {
|
||||
ESP_LOGE(TAG, "Failed to extract IP address from DNS response");
|
||||
goto cleanup;
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Failed to receive response");
|
||||
err = ERR_ABRT;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if (transport) {
|
||||
esp_transport_close(transport);
|
||||
esp_transport_destroy(transport);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
111
components/esp_dns/esp_dns_lwip.c
Normal file
111
components/esp_dns/esp_dns_lwip.c
Normal file
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file esp_dns_lwip.c
|
||||
* @brief Custom DNS module for ESP32 with multiple protocol support
|
||||
*
|
||||
* Provides DNS resolution capabilities with support for various protocols:
|
||||
* - Standard UDP/TCP DNS (Port 53)
|
||||
* - DNS over TLS (DoT) (Port 853)
|
||||
* - DNS over HTTPS (DoH) (Port 443)
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "esp_dns.h"
|
||||
#include "esp_dns_priv.h"
|
||||
|
||||
#define TAG "ESP_DNS_LWIP"
|
||||
|
||||
/* Global DNS handle instance */
|
||||
extern esp_dns_handle_t g_dns_handle;
|
||||
|
||||
/* ========================= LWIP HOOK FUNCTIONS ========================= */
|
||||
|
||||
#if defined(CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_CUSTOM)
|
||||
/**
|
||||
* @brief Custom DNS resolution hook for lwIP network connections
|
||||
*
|
||||
* @param name Hostname to resolve
|
||||
* @param addr Pointer to store resolved IP address
|
||||
* @param addrtype Type of address to resolve (IPv4/IPv6)
|
||||
* @param err Pointer to store error code
|
||||
*
|
||||
* @return int 0 if resolution should be handled by lwIP, 1 if handled by this module
|
||||
*/
|
||||
int lwip_hook_netconn_external_resolve(const char *name, ip_addr_t *addr, u8_t addrtype, err_t *err)
|
||||
{
|
||||
if (g_dns_handle == NULL) {
|
||||
ESP_LOGD(TAG, "ESP_DNS module not initialized, resolving through native DNS");
|
||||
*err = ERR_OK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (name == NULL || addr == NULL || err == NULL) {
|
||||
if (err) {
|
||||
*err = ERR_ARG;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Check if name is already an IP address */
|
||||
if (ipaddr_aton(name, addr)) {
|
||||
*err = ERR_OK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check if DNS server name matches or if it's localhost */
|
||||
if ((strcmp(name, g_dns_handle->config.dns_server) == 0) ||
|
||||
#if LWIP_HAVE_LOOPIF
|
||||
(strcmp(name, "localhost") == 0) ||
|
||||
#endif
|
||||
ipaddr_aton(name, addr)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
u8_t rrtype;
|
||||
if ((addrtype == NETCONN_DNS_IPV4) || (addrtype == NETCONN_DNS_IPV4_IPV6)) {
|
||||
rrtype = DNS_RRTYPE_A;
|
||||
} else if ((addrtype == NETCONN_DNS_IPV6) || (addrtype == NETCONN_DNS_IPV6_IPV4)) {
|
||||
rrtype = DNS_RRTYPE_AAAA;
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Invalid address type");
|
||||
*err = ERR_VAL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Resolve based on configured transport type */
|
||||
switch (g_dns_handle->config.protocol) {
|
||||
case ESP_DNS_PROTOCOL_UDP:
|
||||
/* Return zero as lwIP DNS can handle UDP DNS */
|
||||
return 0;
|
||||
case ESP_DNS_PROTOCOL_TCP:
|
||||
*err = dns_resolve_tcp(g_dns_handle, name, addr, rrtype);
|
||||
break;
|
||||
case ESP_DNS_PROTOCOL_DOT:
|
||||
*err = dns_resolve_dot(g_dns_handle, name, addr, rrtype);
|
||||
break;
|
||||
case ESP_DNS_PROTOCOL_DOH:
|
||||
*err = dns_resolve_doh(g_dns_handle, name, addr, rrtype);
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE(TAG, "Invalid transport type");
|
||||
*err = ERR_VAL;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
#else
|
||||
#error "CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_CUSTOM is not defined. Please enable it in your menuconfig"
|
||||
#endif /* CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_CUSTOM */
|
116
components/esp_dns/esp_dns_priv.h
Normal file
116
components/esp_dns/esp_dns_priv.h
Normal file
@ -0,0 +1,116 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* @file esp_dns_priv.h
|
||||
* @brief Private header for ESP DNS module
|
||||
*
|
||||
* This module provides DNS resolution capabilities with support for various protocols:
|
||||
* - Standard UDP/TCP DNS (Port 53)
|
||||
* - DNS over TLS (DoT)
|
||||
* - DNS over HTTPS (DoH)
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/task.h"
|
||||
#include "lwip/prot/dns.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/err.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "esp_dns.h"
|
||||
#include "esp_dns_utils.h"
|
||||
|
||||
/**
|
||||
* @brief Opaque handle type for DNS module instances
|
||||
*/
|
||||
struct esp_dns_handle {
|
||||
/* Configuration */
|
||||
esp_dns_config_t config; /* Copy of user configuration */
|
||||
|
||||
/* Connection state */
|
||||
bool initialized; /* Flag indicating successful initialization */
|
||||
|
||||
response_buffer_t response_buffer; /* Buffer for storing DNS response data during processing */
|
||||
|
||||
/* Thread safety */
|
||||
SemaphoreHandle_t lock; /* Mutex for synchronization */
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Initialize DNS module with configuration
|
||||
*
|
||||
* @param config DNS configuration parameters
|
||||
*
|
||||
* @return esp_dns_handle_t Handle to DNS module instance
|
||||
*/
|
||||
esp_dns_handle_t esp_dns_init(const esp_dns_config_t *config);
|
||||
|
||||
/**
|
||||
* @brief Clean up DNS module resources
|
||||
*
|
||||
* @param handle DNS module handle
|
||||
*
|
||||
* @return int 0 on success, negative error code on failure
|
||||
*/
|
||||
int esp_dns_cleanup(esp_dns_handle_t handle);
|
||||
|
||||
/**
|
||||
* @brief Resolve hostname using DNS over HTTPS
|
||||
*
|
||||
* @param handle DNS module handle
|
||||
* @param name Hostname to resolve
|
||||
* @param addr Pointer to store resolved IP address
|
||||
* @param rrtype Record type (A or AAAA)
|
||||
*
|
||||
* @return err_t Error code
|
||||
*/
|
||||
err_t dns_resolve_doh(const esp_dns_handle_t handle, const char *name, ip_addr_t *addr, u8_t rrtype);
|
||||
|
||||
/**
|
||||
* @brief Resolve hostname using DNS over TLS
|
||||
*
|
||||
* @param handle DNS module handle
|
||||
* @param name Hostname to resolve
|
||||
* @param addr Pointer to store resolved IP address
|
||||
* @param rrtype Record type (A or AAAA)
|
||||
*
|
||||
* @return err_t Error code
|
||||
*/
|
||||
err_t dns_resolve_dot(const esp_dns_handle_t handle, const char *name, ip_addr_t *addr, u8_t rrtype);
|
||||
|
||||
/**
|
||||
* @brief Resolve hostname using TCP DNS
|
||||
*
|
||||
* @param handle DNS module handle
|
||||
* @param name Hostname to resolve
|
||||
* @param addr Pointer to store resolved IP address
|
||||
* @param rrtype Record type (A or AAAA)
|
||||
*
|
||||
* @return err_t Error code
|
||||
*/
|
||||
err_t dns_resolve_tcp(const esp_dns_handle_t handle, const char *name, ip_addr_t *addr, u8_t rrtype);
|
||||
|
||||
/**
|
||||
* @brief Resolve hostname using UDP DNS
|
||||
*
|
||||
* @param handle DNS module handle
|
||||
* @param name Hostname to resolve
|
||||
* @param addr Pointer to store resolved IP address
|
||||
* @param rrtype Record type (A or AAAA)
|
||||
*
|
||||
* @return err_t Error code
|
||||
*/
|
||||
err_t dns_resolve_udp(const esp_dns_handle_t handle, const char *name, ip_addr_t *addr, u8_t rrtype);
|
188
components/esp_dns/esp_dns_tcp.c
Normal file
188
components/esp_dns/esp_dns_tcp.c
Normal file
@ -0,0 +1,188 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "esp_transport.h"
|
||||
#include "esp_transport_tcp.h"
|
||||
#include "esp_dns_priv.h"
|
||||
#include "esp_dns.h"
|
||||
|
||||
#define TAG "ESP_DNS_TCP"
|
||||
|
||||
/**
|
||||
* @brief Initializes the TCP DNS module
|
||||
*
|
||||
* Sets up the TCP DNS service using the provided configuration. Validates the parameters,
|
||||
* sets the protocol, and initializes the DNS module.
|
||||
*
|
||||
* @param config Pointer to the DNS configuration structure
|
||||
*
|
||||
* @return Handle to the initialized TCP module on success, NULL on failure
|
||||
*/
|
||||
esp_dns_handle_t esp_dns_init_tcp(esp_dns_config_t *config)
|
||||
{
|
||||
ESP_LOGD(TAG, "Initializing TCP DNS");
|
||||
|
||||
/* Validate parameters */
|
||||
if (config == NULL) {
|
||||
ESP_LOGE(TAG, "Invalid configuration (NULL)");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
config->protocol = ESP_DNS_PROTOCOL_TCP;
|
||||
|
||||
esp_dns_handle_t handle = esp_dns_init(config);
|
||||
if (handle == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to initialize DNS");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "DNS module initialized successfully with protocol DNS Over TCP(%d)", config->protocol);
|
||||
return handle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Cleans up the TCP DNS module
|
||||
*
|
||||
* Releases resources allocated for the TCP DNS service. Validates the parameters,
|
||||
* checks the protocol, and cleans up the DNS module.
|
||||
*
|
||||
* @param handle Pointer to the DNS handle to be cleaned up
|
||||
*
|
||||
* @return 0 on success, -1 on failure
|
||||
*/
|
||||
int esp_dns_cleanup_tcp(esp_dns_handle_t handle)
|
||||
{
|
||||
ESP_LOGD(TAG, "Cleaning up TCP DNS");
|
||||
|
||||
/* Validate parameters */
|
||||
if (handle == NULL) {
|
||||
ESP_LOGE(TAG, "Invalid handle (NULL)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (handle->config.protocol != ESP_DNS_PROTOCOL_TCP) {
|
||||
ESP_LOGW(TAG, "Unknown protocol during cleanup: %d", handle->config.protocol);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ret = esp_dns_cleanup(handle);
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "Failed to cleanup DNS");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Empty the handle */
|
||||
memset(handle, 0, sizeof(*handle));
|
||||
|
||||
ESP_LOGD(TAG, "DNS module cleaned up DNS Over TCP successfully");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Resolves a hostname using TCP DNS
|
||||
*
|
||||
* Performs DNS resolution over TCP for the given hostname. Creates a TCP connection,
|
||||
* sends the DNS query, and processes the response.
|
||||
*
|
||||
* @param handle DNS handle
|
||||
* @param name Hostname to resolve
|
||||
* @param addr Pointer to store the resolved IP address
|
||||
* @param rrtype DNS record type
|
||||
*
|
||||
* @return ERR_OK on success, error code on failure
|
||||
*/
|
||||
err_t dns_resolve_tcp(const esp_dns_handle_t handle, const char *name, ip_addr_t *addr, u8_t rrtype)
|
||||
{
|
||||
int err = ERR_OK;
|
||||
esp_transport_handle_t transport = NULL;
|
||||
int len = 0;
|
||||
char tcp_buffer[ESP_DNS_BUFFER_SIZE];
|
||||
size_t query_size;
|
||||
int timeout_ms;
|
||||
int tcp_port;
|
||||
|
||||
if (addr == NULL) {
|
||||
return ERR_ARG;
|
||||
}
|
||||
|
||||
/* Set timeout and port values, using defaults if not specified in config */
|
||||
timeout_ms = handle->config.timeout_ms ? : ESP_DNS_DEFAULT_TIMEOUT_MS;
|
||||
tcp_port = handle->config.port ? : ESP_DNS_DEFAULT_TCP_PORT;
|
||||
|
||||
/* Clear the response buffer to ensure no residual data remains */
|
||||
memset(&handle->response_buffer, 0, sizeof(response_buffer_t));
|
||||
|
||||
/* Create DNS query in wire format, leaving 2 bytes at start for length prefix as required by RFC 7858 */
|
||||
memset(tcp_buffer, 0, ESP_DNS_BUFFER_SIZE);
|
||||
query_size = esp_dns_create_query((uint8_t *)(tcp_buffer + 2), sizeof(tcp_buffer) - 2,
|
||||
name, rrtype, &handle->response_buffer.dns_response.id);
|
||||
if (query_size == -1) {
|
||||
ESP_LOGE(TAG, "Error: Hostname too big");
|
||||
return ERR_MEM;
|
||||
}
|
||||
|
||||
/* Prepends the 2-byte length field to DNS messages as required by RFC 7858 */
|
||||
tcp_buffer[0] = (query_size >> 8) & 0xFF;
|
||||
tcp_buffer[1] = query_size & 0xFF;
|
||||
|
||||
transport = esp_transport_tcp_init();
|
||||
if (!transport) {
|
||||
ESP_LOGE(TAG, "Failed to initialize transport");
|
||||
return ERR_MEM;
|
||||
}
|
||||
|
||||
if (esp_transport_connect(transport, handle->config.dns_server, tcp_port, timeout_ms) < 0) {
|
||||
ESP_LOGE(TAG, "TCP connection failed");
|
||||
err = ERR_CONN;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Send DNS query */
|
||||
len = esp_transport_write(transport,
|
||||
tcp_buffer,
|
||||
query_size + 2,
|
||||
timeout_ms);
|
||||
if (len < 0) {
|
||||
ESP_LOGE(TAG, "Failed to send DNS query");
|
||||
err = ERR_ABRT;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Read response */
|
||||
memset(tcp_buffer, 0, ESP_DNS_BUFFER_SIZE);
|
||||
len = esp_transport_read(transport,
|
||||
tcp_buffer,
|
||||
sizeof(tcp_buffer),
|
||||
timeout_ms);
|
||||
if (len > 0) {
|
||||
/* Skip the 2-byte length field that prepends DNS messages as required by RFC 7858 */
|
||||
handle->response_buffer.buffer = tcp_buffer + 2;
|
||||
handle->response_buffer.length = len - 2;
|
||||
|
||||
/* Parse the DNS response */
|
||||
esp_dns_parse_response((uint8_t *)handle->response_buffer.buffer,
|
||||
handle->response_buffer.length,
|
||||
&handle->response_buffer.dns_response);
|
||||
|
||||
/* Extract IP addresses from DNS response */
|
||||
err = esp_dns_extract_ip_addresses_from_response(&handle->response_buffer.dns_response, addr);
|
||||
if (err != ERR_OK) {
|
||||
ESP_LOGE(TAG, "Failed to extract IP address from DNS response");
|
||||
goto cleanup;
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Failed to receive response");
|
||||
err = ERR_ABRT;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if (transport) {
|
||||
esp_transport_close(transport);
|
||||
esp_transport_destroy(transport);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
110
components/esp_dns/esp_dns_udp.c
Normal file
110
components/esp_dns/esp_dns_udp.c
Normal file
@ -0,0 +1,110 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "esp_dns_priv.h"
|
||||
#include "esp_dns.h"
|
||||
|
||||
|
||||
#define TAG "ESP_DNS_UDP"
|
||||
|
||||
|
||||
/**
|
||||
* @brief Initializes the UDP DNS module
|
||||
*
|
||||
* Sets up the UDP DNS service using the provided configuration. Validates the parameters,
|
||||
* sets the protocol, and initializes the DNS module.
|
||||
*
|
||||
* @param config Pointer to the DNS configuration structure
|
||||
*
|
||||
* @return Handle to the initialized UDP module on success, NULL on failure
|
||||
*/
|
||||
esp_dns_handle_t esp_dns_init_udp(esp_dns_config_t *config)
|
||||
{
|
||||
ESP_LOGD(TAG, "Initializing UDP DNS");
|
||||
|
||||
/* Validate parameters */
|
||||
if (config == NULL) {
|
||||
ESP_LOGE(TAG, "Invalid configuration (NULL)");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
config->protocol = ESP_DNS_PROTOCOL_UDP;
|
||||
|
||||
esp_dns_handle_t handle = esp_dns_init(config);
|
||||
if (handle == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to initialize DNS");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "DNS module initialized successfully with protocol DNS Over UDP(%d)", config->protocol);
|
||||
return handle;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Cleans up the UDP DNS module
|
||||
*
|
||||
* Releases resources allocated for the UDP DNS service. Validates the parameters,
|
||||
* checks the protocol, and cleans up the DNS module.
|
||||
*
|
||||
* @param handle Pointer to the DNS handle to be cleaned up
|
||||
*
|
||||
* @return 0 on success, -1 on failure
|
||||
*/
|
||||
int esp_dns_cleanup_udp(esp_dns_handle_t handle)
|
||||
{
|
||||
ESP_LOGD(TAG, "Cleaning up UDP DNS");
|
||||
|
||||
/* Validate parameters */
|
||||
if (handle == NULL) {
|
||||
ESP_LOGE(TAG, "Invalid handle (NULL)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (handle->config.protocol != ESP_DNS_PROTOCOL_UDP) {
|
||||
ESP_LOGW(TAG, "Unknown protocol during cleanup: %d", handle->config.protocol);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ret = esp_dns_cleanup(handle);
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "Failed to cleanup DNS");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Empty the handle */
|
||||
memset(handle, 0, sizeof(*handle));
|
||||
|
||||
ESP_LOGD(TAG, "DNS module cleaned up DNS Over UDP successfully");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Resolves a hostname using UDP DNS
|
||||
*
|
||||
* Performs DNS resolution over UDP for the given hostname. Creates a UDP connection,
|
||||
* sends the DNS query, and processes the response.
|
||||
*
|
||||
* @note This function is a placeholder and does not contain the actual implementation
|
||||
* for UDP DNS resolution. The implementation needs to be added.
|
||||
* As of now the resolution is performed by lwip dns module.
|
||||
*
|
||||
* @param handle DNS handle
|
||||
* @param name Hostname to resolve
|
||||
* @param addr Pointer to store the resolved IP address
|
||||
* @param rrtype DNS record type
|
||||
*
|
||||
* @return ERR_OK on success, error code on failure
|
||||
*/
|
||||
err_t dns_resolve_udp(const esp_dns_handle_t handle, const char *name, ip_addr_t *addr, u8_t rrtype)
|
||||
{
|
||||
// TBD: Implement UDP DNS resolution
|
||||
if (addr == NULL) {
|
||||
return ERR_ARG;
|
||||
}
|
||||
|
||||
return ERR_OK;
|
||||
}
|
242
components/esp_dns/esp_dns_utils.c
Normal file
242
components/esp_dns/esp_dns_utils.c
Normal file
@ -0,0 +1,242 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <arpa/inet.h>
|
||||
#include "esp_random.h"
|
||||
#include "esp_dns_utils.h"
|
||||
|
||||
/**
|
||||
* @brief Creates a DNS query packet in the provided buffer
|
||||
*
|
||||
* @param buffer Buffer to store the DNS query
|
||||
* @param buffer_size Size of the buffer
|
||||
* @param hostname Domain name to query
|
||||
* @param addrtype Type of address to query (A or AAAA)
|
||||
* @param id_o Pointer to store the generated query ID
|
||||
*
|
||||
* @return size_t Size of the created query packet, or -1 on error
|
||||
*/
|
||||
size_t esp_dns_create_query(uint8_t *buffer, size_t buffer_size, const char *hostname, int addrtype, uint16_t *id_o)
|
||||
{
|
||||
/*
|
||||
* Sample DNS Query for example.com (Type A)
|
||||
* 0x00, 0x00, // Transaction ID
|
||||
* 0x01, 0x00, // Flags: Standard query
|
||||
* 0x00, 0x01, // Questions: 1
|
||||
* 0x00, 0x00, // Answer RRs: 0
|
||||
* 0x00, 0x00, // Authority RRs: 0
|
||||
* 0x00, 0x00, // Additional RRs: 0
|
||||
* 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', // QNAME: example.com
|
||||
* 0x03, 'c', 'o', 'm',
|
||||
* 0x00, // End of QNAME
|
||||
* 0x00, 0x01, // QTYPE: A (host address)
|
||||
* 0x00, 0x01 // QCLASS: IN (internet)
|
||||
*/
|
||||
|
||||
dns_header_t *header = (dns_header_t *)buffer;
|
||||
memset(buffer, 0, buffer_size);
|
||||
|
||||
/* Set header fields */
|
||||
*id_o = (uint16_t)(esp_random() & 0xFFFF); /* Return the id for response validation */
|
||||
header->id = htons(*id_o); /* Random transaction ID */
|
||||
header->flags = htons(0x0100); /* Standard query with recursion */
|
||||
header->qdcount = htons(1); /* One question */
|
||||
|
||||
/* Add the question name */
|
||||
uint8_t *qname = buffer + sizeof(dns_header_t);
|
||||
const char *dot = hostname;
|
||||
while (*dot) {
|
||||
const char *next_dot = strchr(dot, '.');
|
||||
if (!next_dot) {
|
||||
next_dot = dot + strlen(dot);
|
||||
}
|
||||
uint8_t len = next_dot - dot;
|
||||
*qname++ = len;
|
||||
/* Check for buffer overflow */
|
||||
if ((qname - buffer) > buffer_size) {
|
||||
return -1;
|
||||
}
|
||||
memcpy(qname, dot, len);
|
||||
qname += len;
|
||||
dot = (*next_dot) ? next_dot + 1 : next_dot;
|
||||
}
|
||||
*qname++ = 0; /* Null-terminate the question name */
|
||||
|
||||
/* Set question fields */
|
||||
dns_question_t *question = (dns_question_t *)qname;
|
||||
question->qtype = htons(addrtype);
|
||||
question->qclass = htons(DNS_RRCLASS_IN);
|
||||
|
||||
/* Return the total query size */
|
||||
return (qname + sizeof(dns_question_t)) - buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Skips over a DNS name in a DNS reply message and returns the offset to the end of the name.
|
||||
*
|
||||
* This function handles both uncompressed labels and compression pointers according to RFC 1035.
|
||||
* Reference: RFC 1035, sections 3.1 (Name Space Definitions) and 4.1.4 (Message Compression).
|
||||
*
|
||||
* @param ptr Pointer to the start of the DNS name in the DNS message
|
||||
* @param remaining_bytes Number of bytes remaining in the buffer
|
||||
*
|
||||
* @return uint8_t* Pointer to the end of the DNS name, or NULL on error
|
||||
*/
|
||||
static uint8_t *skip_dns_name(uint8_t *ptr, size_t remaining_bytes)
|
||||
{
|
||||
uint8_t offset = 0;
|
||||
|
||||
/* Loop through each part of the name, handling labels and compression pointers */
|
||||
while (ptr[offset] != 0) {
|
||||
if (offset >= remaining_bytes) {
|
||||
return NULL;
|
||||
}
|
||||
/* Check if this part is a compression pointer, indicated by the two high bits set to 1 (0xC0) */
|
||||
/* RFC 1035, Section 4.1.4: Compression pointers */
|
||||
if ((ptr[offset] & 0xC0) == 0xC0) {
|
||||
/* Compression pointer is 2 bytes; move offset by 2 and stop */
|
||||
offset += 2;
|
||||
return ptr + offset; /* End of name processing due to pointer */
|
||||
} else {
|
||||
/* Otherwise, it's a label
|
||||
RFC 1035, Section 3.1: Labels
|
||||
- The first byte is the length of this label
|
||||
- Followed by 'length' bytes of label content */
|
||||
offset += ptr[offset] + 1; /* Move past this label (1 byte for length + label content) */
|
||||
}
|
||||
}
|
||||
|
||||
/* RFC 1035, Section 3.1: End of a name is indicated by a zero-length byte (0x00) */
|
||||
offset += 1; /* Move past the terminating zero byte */
|
||||
return ptr + offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Parses a DNS response message
|
||||
*
|
||||
* @param buffer Buffer containing the DNS response
|
||||
* @param response_size Size of the response buffer
|
||||
*
|
||||
* @param dns_response Structure to store parsed response
|
||||
*/
|
||||
void esp_dns_parse_response(uint8_t *buffer, size_t response_size, dns_response_t *dns_response)
|
||||
{
|
||||
/* Validate input buffer */
|
||||
assert(buffer != NULL);
|
||||
|
||||
dns_header_t *header = (dns_header_t *)buffer;
|
||||
|
||||
dns_response->status_code = ERR_OK; /* Initialize DNS response code */
|
||||
|
||||
/* Check if there are answers and Transaction id matches */
|
||||
int answer_count = ntohs(header->ancount);
|
||||
if ((ntohs(header->id) != dns_response->id) || (answer_count == 0)) {
|
||||
dns_response->status_code = ERR_VAL; /* DNS response code */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Ensure only MAX_ANSWERS are processed */
|
||||
dns_response->num_answers = (answer_count < MAX_ANSWERS ? answer_count : MAX_ANSWERS);
|
||||
|
||||
/* Skip the header and question section */
|
||||
uint8_t *ptr = buffer + sizeof(dns_header_t);
|
||||
|
||||
/* Skip the question name */
|
||||
ptr = skip_dns_name(ptr, response_size - (ptr - buffer));
|
||||
if (ptr == NULL) {
|
||||
dns_response->status_code = ERR_VAL;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Skip the question type and class */
|
||||
ptr += sizeof(dns_question_t);
|
||||
|
||||
/* Parse each answer record */
|
||||
for (int i = 0; i < dns_response->num_answers; i++) {
|
||||
|
||||
/* Answer fields */
|
||||
ptr = skip_dns_name(ptr, response_size - (ptr - buffer));
|
||||
if (ptr == NULL) {
|
||||
dns_response->status_code = ERR_VAL;
|
||||
return;
|
||||
}
|
||||
|
||||
dns_answer_t *answer = (dns_answer_t *)ptr;
|
||||
uint16_t type = ntohs(answer->type);
|
||||
uint16_t class = ntohs(answer->class);
|
||||
uint32_t ttl = ntohl(answer->ttl);
|
||||
uint16_t data_len = ntohs(answer->data_len);
|
||||
|
||||
/* Skip fixed parts of answer (type, class, ttl, data_len) */
|
||||
ptr += SIZEOF_DNS_ANSWER_FIXED;
|
||||
|
||||
/* Validate RR class and ttl */
|
||||
if ((class != DNS_RRCLASS_IN) || (ttl > DNS_MAX_TTL)) {
|
||||
dns_response->answers[i].status = ERR_VAL;
|
||||
goto next_answer;
|
||||
}
|
||||
|
||||
/* Initialize status for this answer */
|
||||
dns_response->answers[i].status = ERR_OK;
|
||||
|
||||
/* Check the type of answer */
|
||||
if (type == DNS_RRTYPE_A && data_len == 4) {
|
||||
/* IPv4 Address (A record) */
|
||||
memcpy(&dns_response->answers[i].ip, ptr, sizeof(struct in_addr));
|
||||
IP_SET_TYPE(&dns_response->answers[i].ip, IPADDR_TYPE_V4);
|
||||
} else if (type == DNS_RRTYPE_AAAA && data_len == 16) {
|
||||
/* IPv6 Address (AAAA record) */
|
||||
memcpy(&dns_response->answers[i].ip, ptr, sizeof(struct in6_addr));
|
||||
IP_SET_TYPE(&dns_response->answers[i].ip, IPADDR_TYPE_V6);
|
||||
} else {
|
||||
dns_response->answers[i].status = ERR_VAL;
|
||||
}
|
||||
|
||||
next_answer:
|
||||
/* Move pointer to next answer */
|
||||
ptr += data_len;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Converts a dns_response_t to an array of IP addresses.
|
||||
*
|
||||
* This function iterates over the DNS response and extracts valid
|
||||
* IPv4 and IPv6 addresses, storing them in the provided array.
|
||||
*
|
||||
* @param response The DNS response to process
|
||||
* @param ipaddr Array to store the extracted IP addresses
|
||||
*
|
||||
* @return err_t Status of DNS response parsing
|
||||
*/
|
||||
err_t esp_dns_extract_ip_addresses_from_response(const dns_response_t *response, ip_addr_t ipaddr[])
|
||||
{
|
||||
int count = 0;
|
||||
memset(ipaddr, 0, DNS_MAX_HOST_IP * sizeof(ip_addr_t));
|
||||
|
||||
if (response->status_code != ERR_OK) {
|
||||
return response->status_code;
|
||||
}
|
||||
|
||||
/* Iterate over the DNS answers */
|
||||
for (int i = 0; i < response->num_answers && count < DNS_MAX_HOST_IP; i++) {
|
||||
const dns_answer_storage_t *answer = &response->answers[i];
|
||||
|
||||
/* Check if the answer is valid */
|
||||
if (answer->status != ERR_OK) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ipaddr[count] = answer->ip;
|
||||
count++;
|
||||
}
|
||||
|
||||
if (count == 0) {
|
||||
return ERR_VAL;
|
||||
}
|
||||
|
||||
/* Store the number of valid IP addresses */
|
||||
return ERR_OK;
|
||||
}
|
139
components/esp_dns/esp_dns_utils.h
Normal file
139
components/esp_dns/esp_dns_utils.h
Normal file
@ -0,0 +1,139 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_log.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "esp_tls.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "lwip/prot/dns.h"
|
||||
#include "lwip/api.h"
|
||||
#include "lwip/opt.h"
|
||||
#include "lwip/dns.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* @brief DNS header structure
|
||||
*
|
||||
* Contains the basic fields of a DNS message header as defined in RFC 1035
|
||||
*/
|
||||
typedef struct {
|
||||
uint16_t id; /* Identification - unique identifier for the query */
|
||||
uint16_t flags; /* Flags - control bits for the DNS message */
|
||||
uint16_t qdcount; /* Number of questions in the question section */
|
||||
uint16_t ancount; /* Number of answers in the answer section */
|
||||
uint16_t nscount; /* Number of authority records in the authority section */
|
||||
uint16_t arcount; /* Number of additional records in the additional section */
|
||||
} dns_header_t;
|
||||
|
||||
/**
|
||||
* @brief DNS question structure
|
||||
*
|
||||
* Represents a single question in the question section of a DNS message
|
||||
*/
|
||||
typedef struct {
|
||||
uint16_t qtype; /* Question type (e.g., A, AAAA, MX) */
|
||||
uint16_t qclass; /* Question class (e.g., IN for internet) */
|
||||
} dns_question_t;
|
||||
|
||||
/**
|
||||
* @brief DNS answer message structure
|
||||
*
|
||||
* Represents a single resource record in the answer section of a DNS message
|
||||
* No packing needed as it's only used locally on the stack
|
||||
*/
|
||||
typedef struct {
|
||||
uint16_t type; /* Resource record type (e.g., A, AAAA, MX) */
|
||||
uint16_t class; /* Resource record class (e.g., IN for internet) */
|
||||
uint32_t ttl; /* Time-to-live in seconds */
|
||||
uint16_t data_len; /* Length of the resource data */
|
||||
} dns_answer_t;
|
||||
|
||||
#define SIZEOF_DNS_ANSWER_FIXED 10 /* Size of dns_answer_t structure in bytes */
|
||||
|
||||
/** Maximum TTL value for DNS resource records (one week) */
|
||||
#define DNS_MAX_TTL 604800
|
||||
|
||||
#ifndef CONFIG_LWIP_DNS_MAX_HOST_IP
|
||||
#define CONFIG_LWIP_DNS_MAX_HOST_IP 1
|
||||
#endif
|
||||
|
||||
/** Maximum number of answers that can be stored */
|
||||
#define MAX_ANSWERS (CONFIG_LWIP_DNS_MAX_HOST_IP)
|
||||
|
||||
#define ESP_DNS_BUFFER_SIZE 512
|
||||
|
||||
/**
|
||||
* @brief Structure to store a single DNS answer
|
||||
*/
|
||||
typedef struct {
|
||||
err_t status; /* Status of the answer */
|
||||
ip_addr_t ip; /* IP address from the answer */
|
||||
} dns_answer_storage_t;
|
||||
|
||||
/**
|
||||
* @brief Structure to store a complete DNS response
|
||||
*/
|
||||
typedef struct {
|
||||
err_t status_code; /* Overall status of the DNS response */
|
||||
uint16_t id; /* Transaction ID */
|
||||
int num_answers; /* Number of valid answers */
|
||||
dns_answer_storage_t answers[MAX_ANSWERS]; /* Array of answers */
|
||||
} dns_response_t;
|
||||
|
||||
/**
|
||||
* @brief Buffer structure for DNS response processing
|
||||
*/
|
||||
typedef struct {
|
||||
char *buffer; /* Pointer to response data buffer */
|
||||
int length; /* Current length of data in buffer */
|
||||
dns_response_t dns_response; /* Parsed DNS response information */
|
||||
} response_buffer_t;
|
||||
|
||||
/**
|
||||
* @brief Creates a DNS query for A and AAAA records
|
||||
*
|
||||
* @param buffer Buffer to store the query
|
||||
* @param buffer_size Size of the buffer
|
||||
* @param hostname Hostname to query
|
||||
* @param addrtype Address type (A or AAAA)
|
||||
* @param id_o Pointer to store the generated query ID
|
||||
*
|
||||
* @return size_t Size of the created query, or -1 on error
|
||||
*/
|
||||
size_t esp_dns_create_query(uint8_t *buffer, size_t buffer_size, const char *hostname, int addrtype, uint16_t *id_o);
|
||||
|
||||
/**
|
||||
* @brief Parses a DNS response message
|
||||
*
|
||||
* @param buffer Buffer containing the DNS response
|
||||
* @param response_size Size of the response
|
||||
* @param dns_response Structure to store parsed response
|
||||
*/
|
||||
void esp_dns_parse_response(uint8_t *buffer, size_t response_size, dns_response_t *dns_response);
|
||||
|
||||
/**
|
||||
* @brief Converts a dns_response_t to an array of IP addresses.
|
||||
*
|
||||
* This function iterates over the DNS response and extracts valid
|
||||
* IPv4 and IPv6 addresses, storing them in the provided array.
|
||||
*
|
||||
* @param response The DNS response to process.
|
||||
* @param ipaddr An array to store the extracted IP addresses.
|
||||
*
|
||||
* @return err Status of dns response parsing
|
||||
*/
|
||||
err_t esp_dns_extract_ip_addresses_from_response(const dns_response_t *response, ip_addr_t ipaddr[]);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
8
components/esp_dns/examples/esp_dns_basic/CMakeLists.txt
Normal file
8
components/esp_dns/examples/esp_dns_basic/CMakeLists.txt
Normal file
@ -0,0 +1,8 @@
|
||||
# For more information about build system see
|
||||
# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html
|
||||
# The following five lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(esp_dns_example)
|
152
components/esp_dns/examples/esp_dns_basic/README.md
Normal file
152
components/esp_dns/examples/esp_dns_basic/README.md
Normal file
@ -0,0 +1,152 @@
|
||||
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- |
|
||||
|
||||
# ESP DNS Example
|
||||
|
||||
This example demonstrates how to use the ESP DNS component in an ESP32 application. The example resolves domain names using various DNS protocols including standard UDP, TCP, DNS over TLS (DoT), and DNS over HTTPS (DoH).
|
||||
|
||||
## Features
|
||||
|
||||
- **Standard UDP DNS**: Traditional DNS resolution over UDP
|
||||
- **DNS over TCP**: DNS resolution using TCP transport
|
||||
- **DNS over TLS (DoT)**: Secure DNS resolution using TLS encryption
|
||||
- **DNS over HTTPS (DoH)**: Secure DNS resolution using HTTPS
|
||||
|
||||
## Certificate Options
|
||||
|
||||
This example provides two certificate options for secure DNS protocols (DoT and DoH):
|
||||
|
||||
1. **Certificate Bundle (Default)**: Uses the ESP-IDF certificate bundle, making it easy to get started with popular DNS providers like Google.
|
||||
2. **Custom Certificate**: Uses a specific certificate for the DNS server. The example includes a Google DNS certificate.
|
||||
|
||||
## How It Works
|
||||
|
||||
1. **Network Initialization**: The application initializes the network interfaces (Wi-Fi or Ethernet) and establishes a connection.
|
||||
2. **DNS Resolution Tests**: The example performs DNS resolution using different protocols:
|
||||
- Native UDP DNS (system default)
|
||||
- ESP DNS with UDP protocol
|
||||
- ESP DNS with TCP protocol
|
||||
- ESP DNS with DoT protocol (using server certificate)
|
||||
- ESP DNS with DoT protocol (using certificate bundle)
|
||||
- ESP DNS with DoH protocol (using server certificate)
|
||||
- ESP DNS with DoH protocol (using certificate bundle)
|
||||
3. **Domain Resolution**: For each protocol, the application resolves several domain names including:
|
||||
- yahoo.com
|
||||
- www.google.com
|
||||
- IP addresses (0.0.0.0 and IPv6 address)
|
||||
|
||||
## How to use example
|
||||
|
||||
Before project configuration and build, be sure to set the correct chip target using `idf.py set-target <chip_name>`.
|
||||
|
||||
### Hardware Required
|
||||
|
||||
* A development board with ESP32/ESP32-S2/ESP32-C3 SoC (e.g., ESP32-DevKitC, ESP-WROVER-KIT, etc.)
|
||||
* A USB cable for power supply and programming
|
||||
|
||||
### Build and Flash
|
||||
|
||||
Build the project and flash it to the board, then run monitor tool to view serial output:
|
||||
|
||||
idf.py -p PORT flash monitor
|
||||
|
||||
|
||||
(Replace PORT with the name of the serial port to use.)
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
## Troubleshooting Tips
|
||||
|
||||
* **Connectivity**:
|
||||
Ensure that the network connection details are accurate. For example, verify the Wi-Fi SSID and password or check that the Ethernet connection is secure and not faulty.
|
||||
|
||||
* **Memory Issues**:
|
||||
If you encounter memory-related errors, check the system information output which displays free heap and stack high water mark. You may need to increase task stack sizes for more complex DNS operations.
|
||||
|
||||
* **Certificate Issues**:
|
||||
For DoT and DoH protocols, ensure that the certificates are valid for the DNS server you're using. The example includes Google DNS certificates, but these may need to be updated if they expire.
|
||||
|
||||
## Example Output
|
||||
|
||||
```
|
||||
I (4583) example_esp_dns: Executing DNS without initializing ESP_DNS module
|
||||
I (4603) wifi:<ba-add>idx:1 (ifx:0, a0:36:bc:0e:c4:f0), tid:7, ssn:3, winSize:64
|
||||
I (4613) example_esp_dns: Hostname: yahoo.com: 98.137.11.163(IPv4)
|
||||
I (4613) example_esp_dns: Hostname: yahoo.com: 74.6.143.26(IPv4)
|
||||
I (4613) example_esp_dns: Hostname: yahoo.com: 74.6.231.20(IPv4)
|
||||
I (4613) wifi:<ba-del>idx:0, tid:6
|
||||
I (4623) example_esp_dns: Hostname: yahoo.com: 74.6.231.21(IPv4)
|
||||
I (4623) wifi:<ba-add>idx:0 (ifx:0, a0:36:bc:0e:c4:f0), tid:0, ssn:1, winSize:64
|
||||
I (4643) example_esp_dns: Hostname: www.google.com: 2404:6800:4015:803::2004(IPv6)
|
||||
I (4643) example_esp_dns: Hostname: 0.0.0.0: 0.0.0.0(IPv4)
|
||||
I (4643) example_esp_dns: Hostname: fe80:0000:0000:0000:5abf:25ff:fee0:4100: FE80::5ABF:25FF:FEE0:4100(IPv6)
|
||||
I (4653) example_esp_dns: Free Heap: 215292 bytes, Min Free Heap: 206008 bytes, Stack High Water Mark: 1220 bytes
|
||||
|
||||
I (4663) example_esp_dns: Executing UDP DNS
|
||||
I (4673) example_esp_dns: Hostname: yahoo.com: 98.137.11.163(IPv4)
|
||||
I (4673) example_esp_dns: Hostname: yahoo.com: 74.6.143.26(IPv4)
|
||||
I (4683) example_esp_dns: Hostname: yahoo.com: 74.6.231.20(IPv4)
|
||||
I (4683) example_esp_dns: Hostname: yahoo.com: 74.6.231.21(IPv4)
|
||||
I (4693) example_esp_dns: Hostname: www.google.com: 2404:6800:4015:803::2004(IPv6)
|
||||
I (4703) example_esp_dns: Hostname: 0.0.0.0: 0.0.0.0(IPv4)
|
||||
I (4703) example_esp_dns: Hostname: fe80:0000:0000:0000:5abf:25ff:fee0:4100: FE80::5ABF:25FF:FEE0:4100(IPv6)
|
||||
I (4713) example_esp_dns: Free Heap: 215116 bytes, Min Free Heap: 206008 bytes, Stack High Water Mark: 1220 bytes
|
||||
|
||||
I (4723) example_esp_dns: Executing TCP DNS
|
||||
I (4763) example_esp_dns: Hostname: yahoo.com: 98.137.11.163(IPv4)
|
||||
I (4763) example_esp_dns: Hostname: yahoo.com: 74.6.143.26(IPv4)
|
||||
I (4763) example_esp_dns: Hostname: yahoo.com: 98.137.11.164(IPv4)
|
||||
I (4763) example_esp_dns: Hostname: yahoo.com: 74.6.231.21(IPv4)
|
||||
I (4793) example_esp_dns: Hostname: www.google.com: 2404:6800:4015:803::2004(IPv6)
|
||||
I (4793) example_esp_dns: Hostname: 0.0.0.0: 0.0.0.0(IPv4)
|
||||
I (4793) example_esp_dns: Hostname: fe80:0000:0000:0000:5abf:25ff:fee0:4100: FE80::5ABF:25FF:FEE0:4100(IPv6)
|
||||
I (4803) example_esp_dns: Free Heap: 214580 bytes, Min Free Heap: 206008 bytes, Stack High Water Mark: 1220 bytes
|
||||
|
||||
I (4813) example_esp_dns: Executing DNS over TLS
|
||||
I (5963) example_esp_dns: Hostname: yahoo.com: 74.6.143.25(IPv4)
|
||||
I (5963) example_esp_dns: Hostname: yahoo.com: 98.137.11.163(IPv4)
|
||||
I (5963) example_esp_dns: Hostname: yahoo.com: 74.6.231.21(IPv4)
|
||||
I (5973) example_esp_dns: Hostname: yahoo.com: 74.6.231.20(IPv4)
|
||||
I (7083) example_esp_dns: Hostname: www.google.com: 2404:6800:4015:803::2004(IPv6)
|
||||
I (7083) example_esp_dns: Hostname: 0.0.0.0: 0.0.0.0(IPv4)
|
||||
I (7083) example_esp_dns: Hostname: fe80:0000:0000:0000:5abf:25ff:fee0:4100: FE80::5ABF:25FF:FEE0:4100(IPv6)
|
||||
I (7093) example_esp_dns: Free Heap: 213504 bytes, Min Free Heap: 165308 bytes, Stack High Water Mark: 1220 bytes
|
||||
|
||||
I (7103) example_esp_dns: Executing DNS over TLS
|
||||
I (7413) esp-x509-crt-bundle: Certificate validated
|
||||
I (8233) example_esp_dns: Hostname: yahoo.com: 98.137.11.164(IPv4)
|
||||
I (8233) example_esp_dns: Hostname: yahoo.com: 74.6.231.21(IPv4)
|
||||
I (8233) example_esp_dns: Hostname: yahoo.com: 98.137.11.163(IPv4)
|
||||
I (8243) example_esp_dns: Hostname: yahoo.com: 74.6.231.20(IPv4)
|
||||
I (8553) esp-x509-crt-bundle: Certificate validated
|
||||
I (9363) example_esp_dns: Hostname: www.google.com: 2404:6800:4015:803::2004(IPv6)
|
||||
I (9363) example_esp_dns: Hostname: 0.0.0.0: 0.0.0.0(IPv4)
|
||||
I (9363) example_esp_dns: Hostname: fe80:0000:0000:0000:5abf:25ff:fee0:4100: FE80::5ABF:25FF:FEE0:4100(IPv6)
|
||||
I (9373) example_esp_dns: Free Heap: 213120 bytes, Min Free Heap: 165308 bytes, Stack High Water Mark: 1220 bytes
|
||||
|
||||
I (9383) example_esp_dns: Executing DNS over HTTPS
|
||||
I (10563) example_esp_dns: Hostname: yahoo.com: 74.6.143.26(IPv4)
|
||||
I (10563) example_esp_dns: Hostname: yahoo.com: 74.6.231.20(IPv4)
|
||||
I (10563) example_esp_dns: Hostname: yahoo.com: 74.6.143.25(IPv4)
|
||||
I (10573) example_esp_dns: Hostname: yahoo.com: 74.6.231.21(IPv4)
|
||||
I (11713) example_esp_dns: Hostname: www.google.com: 2404:6800:4015:803::2004(IPv6)
|
||||
I (11713) example_esp_dns: Hostname: 0.0.0.0: 0.0.0.0(IPv4)
|
||||
I (11723) example_esp_dns: Hostname: fe80:0000:0000:0000:5abf:25ff:fee0:4100: FE80::5ABF:25FF:FEE0:4100(IPv6)
|
||||
I (11723) example_esp_dns: Free Heap: 212664 bytes, Min Free Heap: 162780 bytes, Stack High Water Mark: 1220 bytes
|
||||
|
||||
I (11733) example_esp_dns: Executing DNS over HTTPS
|
||||
I (12033) esp-x509-crt-bundle: Certificate validated
|
||||
I (12863) example_esp_dns: Hostname: yahoo.com: 74.6.231.21(IPv4)
|
||||
I (12863) example_esp_dns: Hostname: yahoo.com: 98.137.11.163(IPv4)
|
||||
I (12863) example_esp_dns: Hostname: yahoo.com: 98.137.11.164(IPv4)
|
||||
I (12873) example_esp_dns: Hostname: yahoo.com: 74.6.143.25(IPv4)
|
||||
I (13153) esp-x509-crt-bundle: Certificate validated
|
||||
I (13993) example_esp_dns: Hostname: www.google.com: 2404:6800:4015:803::2004(IPv6)
|
||||
I (13993) example_esp_dns: Hostname: 0.0.0.0: 0.0.0.0(IPv4)
|
||||
I (13993) example_esp_dns: Hostname: fe80:0000:0000:0000:5abf:25ff:fee0:4100: FE80::5ABF:25FF:FEE0:4100(IPv6)
|
||||
I (14003) example_esp_dns: Free Heap: 212044 bytes, Min Free Heap: 162780 bytes, Stack High Water Mark: 1220 bytes
|
||||
|
||||
I (14013) main_task: Returned from app_main()
|
||||
```
|
@ -0,0 +1,3 @@
|
||||
idf_component_register(SRCS "esp_dns_example.c"
|
||||
INCLUDE_DIRS "."
|
||||
EMBED_TXTFILES "cert_google_root.pem")
|
@ -0,0 +1,31 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFVzCCAz+gAwIBAgINAgPlk28xsBNJiGuiFzANBgkqhkiG9w0BAQwFADBHMQsw
|
||||
CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU
|
||||
MBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw
|
||||
MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp
|
||||
Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEBAQUA
|
||||
A4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaMf/vo
|
||||
27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vXmX7w
|
||||
Cl7raKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7zUjw
|
||||
TcLCeoiKu7rPWRnWr4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0Pfybl
|
||||
qAj+lug8aJRT7oM6iCsVlgmy4HqMLnXWnOunVmSPlk9orj2XwoSPwLxAwAtcvfaH
|
||||
szVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk9+aCEI3oncKKiPo4Zor8
|
||||
Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zqkUspzBmk
|
||||
MiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOORc92
|
||||
wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYWk70p
|
||||
aDPvOmbsB4om3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+DVrN
|
||||
VjzRlwW5y0vtOUucxD/SVRNuJLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgFlQID
|
||||
AQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E
|
||||
FgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQADggIBAJ+qQibb
|
||||
C5u+/x6Wki4+omVKapi6Ist9wTrYggoGxval3sBOh2Z5ofmmWJyq+bXmYOfg6LEe
|
||||
QkEzCzc9zolwFcq1JKjPa7XSQCGYzyI0zzvFIoTgxQ6KfF2I5DUkzps+GlQebtuy
|
||||
h6f88/qBVRRiClmpIgUxPoLW7ttXNLwzldMXG+gnoot7TiYaelpkttGsN/H9oPM4
|
||||
7HLwEXWdyzRSjeZ2axfG34arJ45JK3VmgRAhpuo+9K4l/3wV3s6MJT/KYnAK9y8J
|
||||
ZgfIPxz88NtFMN9iiMG1D53Dn0reWVlHxYciNuaCp+0KueIHoI17eko8cdLiA6Ef
|
||||
MgfdG+RCzgwARWGAtQsgWSl4vflVy2PFPEz0tv/bal8xa5meLMFrUKTX5hgUvYU/
|
||||
Z6tGn6D/Qqc6f1zLXbBwHSs09dR2CQzreExZBfMzQsNhFRAbd03OIozUhfJFfbdT
|
||||
6u9AWpQKXCBfTkBdYiJ23//OYb2MI3jSNwLgjt7RETeJ9r/tSQdirpLsQBqvFAnZ
|
||||
0E6yove+7u7Y/9waLd64NnHi/Hm3lCXRSHNboTXns5lndcEZOitHTtNCjv0xyBZm
|
||||
2tIMPNuzjsmhDYAPexZ3FL//2wmUspO8IFgV6dtxQ/PeEMMA3KgqlbbC1j+Qa3bb
|
||||
bP6MvPJwNQzcmRk13NfIRmPVNnGuV/u3gm3c
|
||||
-----END CERTIFICATE-----
|
324
components/esp_dns/examples/esp_dns_basic/main/esp_dns_example.c
Normal file
324
components/esp_dns/examples/esp_dns_basic/main/esp_dns_example.c
Normal file
@ -0,0 +1,324 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include <unistd.h>
|
||||
#include "esp_log.h"
|
||||
#include "esp_system.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_timer.h"
|
||||
#include "lwip/opt.h"
|
||||
#include "protocol_examples_common.h"
|
||||
#include "esp_dns.h"
|
||||
#if defined(CONFIG_MBEDTLS_CERTIFICATE_BUNDLE)
|
||||
#include "esp_crt_bundle.h"
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef INET6_ADDRSTRLEN
|
||||
#define INET6_ADDRSTRLEN INET_ADDRSTRLEN
|
||||
#endif
|
||||
|
||||
#define TAG "example_esp_dns"
|
||||
|
||||
extern const char server_root_cert_pem_start[] asm("_binary_cert_google_root_pem_start");
|
||||
extern const char server_root_cert_pem_end[] asm("_binary_cert_google_root_pem_end");
|
||||
|
||||
|
||||
/**
|
||||
* @brief Performs DNS lookup for a given hostname and address family
|
||||
* @param hostname The hostname to resolve
|
||||
* @param family The address family (AF_INET, AF_INET6, or AF_UNSPEC)
|
||||
*/
|
||||
static void do_getaddrinfo(char *hostname, int family)
|
||||
{
|
||||
struct addrinfo hints, *res, *p;
|
||||
int status;
|
||||
char ipstr[INET6_ADDRSTRLEN];
|
||||
void *addr = NULL;
|
||||
char *ipver = NULL;
|
||||
|
||||
/* Initialize the hints structure */
|
||||
memset(&hints, 0, sizeof hints);
|
||||
hints.ai_family = family;
|
||||
hints.ai_socktype = SOCK_DGRAM; /* UDP datagram sockets */
|
||||
|
||||
/* Get address information */
|
||||
if ((status = getaddrinfo(hostname, NULL, &hints, &res)) != 0) {
|
||||
ESP_LOGE(TAG, "getaddrinfo error: %d", status);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Loop through all the results */
|
||||
for (p = res; p != NULL; p = p->ai_next) {
|
||||
|
||||
/* Get pointer to the address itself */
|
||||
#if defined(CONFIG_LWIP_IPV4)
|
||||
if (p->ai_family == AF_INET) { /* IPv4 */
|
||||
struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr;
|
||||
addr = &(ipv4->sin_addr);
|
||||
ipver = "IPv4";
|
||||
|
||||
/* Convert the IP to a string and print it */
|
||||
inet_ntop(p->ai_family, addr, ipstr, sizeof ipstr);
|
||||
ESP_LOGI(TAG, "Hostname: %s: %s(%s)", hostname, ipstr, ipver);
|
||||
}
|
||||
#endif
|
||||
#if defined(CONFIG_LWIP_IPV6)
|
||||
if (p->ai_family == AF_INET6) { /* IPv6 */
|
||||
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr;
|
||||
addr = &(ipv6->sin6_addr);
|
||||
ipver = "IPv6";
|
||||
|
||||
/* Convert the IP to a string and print it */
|
||||
inet_ntop(p->ai_family, addr, ipstr, sizeof ipstr);
|
||||
ESP_LOGI(TAG, "Hostname: %s: %s(%s)", hostname, ipstr, ipver);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
cleanup:
|
||||
freeaddrinfo(res); /* Free the linked list */
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Task that performs DNS lookups for various hostnames
|
||||
* @param pvParameters Parent task handle for notification
|
||||
*/
|
||||
static void addr_info_task(void *pvParameters)
|
||||
{
|
||||
TaskHandle_t parent_handle = (TaskHandle_t)pvParameters;
|
||||
|
||||
do_getaddrinfo("yahoo.com", AF_UNSPEC);
|
||||
do_getaddrinfo("www.google.com", AF_INET6);
|
||||
do_getaddrinfo("0.0.0.0", AF_UNSPEC);
|
||||
do_getaddrinfo("fe80:0000:0000:0000:5abf:25ff:fee0:4100", AF_UNSPEC);
|
||||
|
||||
/* Notify parent task before deleting */
|
||||
if (parent_handle) {
|
||||
xTaskNotifyGive(parent_handle);
|
||||
}
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Prints system information including heap and stack usage
|
||||
*/
|
||||
void print_system_info(void)
|
||||
{
|
||||
/* Get the free heap size */
|
||||
uint32_t free_heap = esp_get_free_heap_size();
|
||||
uint32_t min_free_heap = esp_get_minimum_free_heap_size();
|
||||
|
||||
/* Get the stack high water mark for the current task */
|
||||
UBaseType_t stack_high_water_mark = uxTaskGetStackHighWaterMark(NULL);
|
||||
|
||||
ESP_LOGI(TAG, "Free Heap: %lu bytes, Min Free Heap: %lu bytes, Stack High Water Mark: %u bytes\n",
|
||||
free_heap, min_free_heap, stack_high_water_mark);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Creates and runs the DNS query task
|
||||
*/
|
||||
static void run_dns_query_task(void)
|
||||
{
|
||||
TaskHandle_t task_handle = NULL;
|
||||
TaskHandle_t parent_handle = xTaskGetCurrentTaskHandle();
|
||||
xTaskCreate(addr_info_task, "AddressInfo", 4 * 1024, parent_handle, 5, &task_handle);
|
||||
|
||||
/* Wait for task to complete */
|
||||
if (task_handle != NULL) {
|
||||
xTaskNotifyWait(0, 0, NULL, portMAX_DELAY);
|
||||
}
|
||||
|
||||
print_system_info();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Performs DNS queries using UDP protocol
|
||||
*/
|
||||
void perform_esp_dns_udp_query(void)
|
||||
{
|
||||
esp_dns_handle_t dns_handle;
|
||||
|
||||
ESP_LOGI(TAG, "Executing UDP DNS");
|
||||
|
||||
/* Initialize with UDP DNS configuration */
|
||||
esp_dns_config_t udp_config = {
|
||||
.dns_server = "dns.google", /* Google DNS */
|
||||
};
|
||||
|
||||
/* Initialize UDP DNS module */
|
||||
dns_handle = esp_dns_init_udp(&udp_config);
|
||||
if (!dns_handle) {
|
||||
ESP_LOGE(TAG, "Failed to initialize UDP DNS module");
|
||||
return;
|
||||
}
|
||||
|
||||
run_dns_query_task();
|
||||
|
||||
/* Cleanup */
|
||||
esp_dns_cleanup_udp(dns_handle);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Performs DNS queries using TCP protocol
|
||||
*/
|
||||
void perform_esp_dns_tcp_query(void)
|
||||
{
|
||||
esp_dns_handle_t dns_handle;
|
||||
|
||||
ESP_LOGI(TAG, "Executing TCP DNS");
|
||||
|
||||
/* Initialize with TCP DNS configuration */
|
||||
esp_dns_config_t tcp_config = {
|
||||
.dns_server = "dns.google",
|
||||
.port = ESP_DNS_DEFAULT_TCP_PORT,
|
||||
.timeout_ms = ESP_DNS_DEFAULT_TIMEOUT_MS,
|
||||
};
|
||||
|
||||
/* Initialize TCP DNS module */
|
||||
dns_handle = esp_dns_init_tcp(&tcp_config);
|
||||
if (!dns_handle) {
|
||||
ESP_LOGE(TAG, "Failed to initialize TCP DNS module");
|
||||
return;
|
||||
}
|
||||
|
||||
run_dns_query_task();
|
||||
|
||||
/* Cleanup */
|
||||
esp_dns_cleanup_tcp(dns_handle);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Performs DNS queries using DNS over TLS protocol
|
||||
* @param val_type Type of certificate validation ("cert" or "bndl")
|
||||
*/
|
||||
void perform_esp_dns_dot_query(char *val_type)
|
||||
{
|
||||
esp_dns_handle_t dns_handle;
|
||||
|
||||
ESP_LOGI(TAG, "Executing DNS over TLS");
|
||||
|
||||
/* Initialize with DNS over TLS configuration */
|
||||
esp_dns_config_t dot_config = {
|
||||
.dns_server = "dns.google",
|
||||
.port = ESP_DNS_DEFAULT_DOT_PORT,
|
||||
.timeout_ms = ESP_DNS_DEFAULT_TIMEOUT_MS,
|
||||
};
|
||||
|
||||
if (strcmp(val_type, "cert") == 0) {
|
||||
dot_config.tls_config.cert_pem = server_root_cert_pem_start;
|
||||
} else if (strcmp(val_type, "bndl") == 0) {
|
||||
dot_config.tls_config.crt_bundle_attach = esp_crt_bundle_attach;
|
||||
}
|
||||
|
||||
/* Initialize DoT DNS module */
|
||||
dns_handle = esp_dns_init_dot(&dot_config);
|
||||
if (!dns_handle) {
|
||||
ESP_LOGE(TAG, "Failed to initialize DoT DNS module");
|
||||
return;
|
||||
}
|
||||
|
||||
run_dns_query_task();
|
||||
|
||||
/* Cleanup */
|
||||
esp_dns_cleanup_dot(dns_handle);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Performs DNS queries using DNS over HTTPS protocol
|
||||
* @param val_type Type of certificate validation ("cert" or "bndl")
|
||||
*/
|
||||
void perform_esp_dns_doh_query(char *val_type)
|
||||
{
|
||||
esp_dns_handle_t dns_handle;
|
||||
|
||||
ESP_LOGI(TAG, "Executing DNS over HTTPS");
|
||||
|
||||
/* Initialize with DNS over HTTPS configuration */
|
||||
esp_dns_config_t doh_config = {
|
||||
.dns_server = "dns.google",
|
||||
.port = ESP_DNS_DEFAULT_DOH_PORT,
|
||||
|
||||
.protocol_config.doh_config = {
|
||||
.url_path = "/dns-query",
|
||||
},
|
||||
};
|
||||
|
||||
if (strcmp(val_type, "cert") == 0) {
|
||||
doh_config.tls_config.cert_pem = server_root_cert_pem_start;
|
||||
} else if (strcmp(val_type, "bndl") == 0) {
|
||||
doh_config.tls_config.crt_bundle_attach = esp_crt_bundle_attach;
|
||||
}
|
||||
|
||||
/* Initialize DoH DNS module */
|
||||
dns_handle = esp_dns_init_doh(&doh_config);
|
||||
if (!dns_handle) {
|
||||
ESP_LOGE(TAG, "Failed to initialize DoH DNS module");
|
||||
return;
|
||||
}
|
||||
|
||||
run_dns_query_task();
|
||||
|
||||
/* Cleanup */
|
||||
esp_dns_cleanup_doh(dns_handle);
|
||||
}
|
||||
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
esp_err_t ret = nvs_flash_init(); /* Initialize NVS */
|
||||
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||
ret = nvs_flash_init();
|
||||
}
|
||||
ESP_ERROR_CHECK(ret);
|
||||
|
||||
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
|
||||
* Read "Establishing Wi-Fi or Ethernet Connection" section in
|
||||
* examples/protocols/README.md for more information about this function.
|
||||
*/
|
||||
ESP_ERROR_CHECK(example_connect());
|
||||
|
||||
/* Test Without ESP_DNS module */
|
||||
ESP_LOGI(TAG, "Executing DNS without initializing ESP_DNS module");
|
||||
run_dns_query_task();
|
||||
|
||||
/* DNS over UDP Test */
|
||||
perform_esp_dns_udp_query();
|
||||
|
||||
/* DNS over TCP Test */
|
||||
perform_esp_dns_tcp_query();
|
||||
|
||||
/* DNS over TLS Test with cert */
|
||||
perform_esp_dns_dot_query("cert");
|
||||
|
||||
/* DNS over TLS Test with cert bundle */
|
||||
perform_esp_dns_dot_query("bndl");
|
||||
|
||||
/* DNS over HTTPS Test with cert */
|
||||
perform_esp_dns_doh_query("cert");
|
||||
|
||||
/* DNS over HTTPS Test with cert bundle */
|
||||
perform_esp_dns_doh_query("bndl");
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
dependencies:
|
||||
idf:
|
||||
version: ">=5.1"
|
||||
protocol_examples_common:
|
||||
path: ${IDF_PATH}/examples/common_components/protocol_examples_common
|
||||
esp_dns:
|
||||
version: "*"
|
||||
override_path: '../../../'
|
28
components/esp_dns/examples/esp_dns_basic/pytest_esp_dns.py
Normal file
28
components/esp_dns/examples/esp_dns_basic/pytest_esp_dns.py
Normal file
@ -0,0 +1,28 @@
|
||||
# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.esp32
|
||||
def test_esp_dns_resolution(dut):
|
||||
"""
|
||||
Test DNS resolution for different protocols (UDP, TCP, DoT, DoH).
|
||||
"""
|
||||
dut.expect('Executing UDP DNS', timeout=10)
|
||||
dut.expect('Executing TCP DNS', timeout=10)
|
||||
dut.expect('Executing DNS over TLS', timeout=10)
|
||||
dut.expect('Executing DNS over HTTPS', timeout=10)
|
||||
|
||||
# Check for successful DNS resolution
|
||||
dut.expect('Hostname: yahoo.com:', timeout=10)
|
||||
dut.expect('Hostname: www.google.com:', timeout=10)
|
||||
dut.expect('Hostname: 0.0.0.0:', timeout=10)
|
||||
dut.expect('Hostname: fe80:0000:0000:0000:5abf:25ff:fee0:4100', timeout=10)
|
||||
|
||||
# Check for system information logs
|
||||
dut.expect('Free Heap:', timeout=10)
|
||||
dut.expect('Min Free Heap:', timeout=10)
|
||||
dut.expect('Stack High Water Mark:', timeout=10)
|
@ -0,0 +1,7 @@
|
||||
# This file was generated using idf.py save-defconfig. It can be edited manually.
|
||||
# Espressif IoT Development Framework (ESP-IDF) 5.5.0 Project Minimal Configuration
|
||||
#
|
||||
CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y
|
||||
CONFIG_LWIP_DNS_MAX_HOST_IP=4
|
||||
CONFIG_LWIP_USE_ESP_GETADDRINFO=y
|
||||
CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_CUSTOM=y
|
5
components/esp_dns/idf_component.yml
Normal file
5
components/esp_dns/idf_component.yml
Normal file
@ -0,0 +1,5 @@
|
||||
## IDF Component Manager Manifest File
|
||||
version: 0.1.0
|
||||
dependencies:
|
||||
idf:
|
||||
version: ">=5.1"
|
155
components/esp_dns/include/esp_dns.h
Normal file
155
components/esp_dns/include/esp_dns.h
Normal file
@ -0,0 +1,155 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_err.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define ESP_DNS_DEFAULT_TCP_PORT 53 /* Default TCP port for DNS */
|
||||
#define ESP_DNS_DEFAULT_DOT_PORT 853 /* Default TLS port for DNS over TLS */
|
||||
#define ESP_DNS_DEFAULT_DOH_PORT 443 /* Default HTTPS port for DNS over HTTPS */
|
||||
|
||||
#define ESP_DNS_DEFAULT_TIMEOUT_MS 10000 /* Default timeout for DNS queries in milliseconds */
|
||||
|
||||
typedef enum {
|
||||
ESP_DNS_PROTOCOL_UDP, /* Traditional UDP DNS (Port 53) */
|
||||
ESP_DNS_PROTOCOL_TCP, /* TCP DNS (Port 53) */
|
||||
ESP_DNS_PROTOCOL_DOT, /* DNS over TLS (Port 853) */
|
||||
ESP_DNS_PROTOCOL_DOH, /* DNS over HTTPS (Port 443) */
|
||||
} esp_dns_protocol_type_t;
|
||||
|
||||
/**
|
||||
* @brief DNS configuration structure
|
||||
*/
|
||||
typedef struct {
|
||||
/* Basic protocol selection */
|
||||
esp_dns_protocol_type_t protocol; /* DNS protocol type */
|
||||
|
||||
/* Common settings */
|
||||
const char *dns_server; /* DNS server IP address or hostname */
|
||||
uint16_t port; /* Custom port number (if not using default) */
|
||||
uint32_t timeout_ms; /* Query timeout in milliseconds */
|
||||
|
||||
/* Secure protocol options */
|
||||
struct {
|
||||
const char *cert_pem; /* SSL server certification in PEM format as string */
|
||||
esp_err_t (*crt_bundle_attach)(void *conf); /* Function pointer to attach cert bundle */
|
||||
} tls_config; /* Used for DoT, DoH, DoH3, DNSCrypt, DoQ */
|
||||
|
||||
/* Protocol-specific options */
|
||||
union {
|
||||
/* DoH options */
|
||||
struct {
|
||||
const char *url_path; /* URL path for DoH service (e.g., "/dns-query") */
|
||||
} doh_config; /* DNS over HTTPS configuration */
|
||||
} protocol_config; /* Protocol-specific configuration */
|
||||
} esp_dns_config_t;
|
||||
|
||||
typedef struct esp_dns_handle* esp_dns_handle_t;
|
||||
|
||||
/**
|
||||
* @brief Initialize DNS over HTTPS (DoH) module
|
||||
*
|
||||
* Sets up the DoH service using the provided configuration. Validates the parameters,
|
||||
* sets the protocol, and initializes the DNS module.
|
||||
*
|
||||
* @param config Pointer to the DNS configuration structure
|
||||
*
|
||||
* @return Handle to the initialized DoH module on success, NULL on failure
|
||||
*/
|
||||
esp_dns_handle_t esp_dns_init_doh(esp_dns_config_t *config);
|
||||
|
||||
/**
|
||||
* @brief Initialize DNS over TLS (DoT) module
|
||||
*
|
||||
* Sets up the DoT service using the provided configuration. Validates the parameters,
|
||||
* sets the protocol, and initializes the DNS module.
|
||||
*
|
||||
* @param config Pointer to the DNS configuration structure
|
||||
*
|
||||
* @return Handle to the initialized DoT module on success, NULL on failure
|
||||
*/
|
||||
esp_dns_handle_t esp_dns_init_dot(esp_dns_config_t *config);
|
||||
|
||||
/**
|
||||
* @brief Initialize TCP DNS module
|
||||
*
|
||||
* Sets up the TCP DNS service using the provided configuration. Validates the parameters,
|
||||
* sets the protocol, and initializes the DNS module.
|
||||
*
|
||||
* @param config Pointer to the DNS configuration structure
|
||||
*
|
||||
* @return Handle to the initialized TCP module on success, NULL on failure
|
||||
*/
|
||||
esp_dns_handle_t esp_dns_init_tcp(esp_dns_config_t *config);
|
||||
|
||||
/**
|
||||
* @brief Initialize UDP DNS module
|
||||
*
|
||||
* Sets up the UDP DNS service using the provided configuration. Validates the parameters,
|
||||
* sets the protocol, and initializes the DNS module.
|
||||
*
|
||||
* @param config Pointer to the DNS configuration structure
|
||||
*
|
||||
* @return Handle to the initialized UDP module on success, NULL on failure
|
||||
*/
|
||||
esp_dns_handle_t esp_dns_init_udp(esp_dns_config_t *config);
|
||||
|
||||
/**
|
||||
* @brief Clean up DNS over HTTPS (DoH) module
|
||||
*
|
||||
* Releases resources allocated for the DoH service. Validates the parameters,
|
||||
* checks the protocol, and cleans up the DNS module.
|
||||
*
|
||||
* @param handle Pointer to the DNS handle to be cleaned up
|
||||
*
|
||||
* @return 0 on success, -1 on failure
|
||||
*/
|
||||
int esp_dns_cleanup_doh(esp_dns_handle_t handle);
|
||||
|
||||
/**
|
||||
* @brief Clean up DNS over TLS (DoT) module
|
||||
*
|
||||
* Releases resources allocated for the DoT service. Validates the parameters,
|
||||
* checks the protocol, and cleans up the DNS module.
|
||||
*
|
||||
* @param handle Pointer to the DNS handle to be cleaned up
|
||||
*
|
||||
* @return 0 on success, -1 on failure
|
||||
*/
|
||||
int esp_dns_cleanup_dot(esp_dns_handle_t handle);
|
||||
|
||||
/**
|
||||
* @brief Clean up TCP DNS module
|
||||
*
|
||||
* Releases resources allocated for the TCP DNS service. Validates the parameters,
|
||||
* checks the protocol, and cleans up the DNS module.
|
||||
*
|
||||
* @param handle Pointer to the DNS handle to be cleaned up
|
||||
*
|
||||
* @return 0 on success, -1 on failure
|
||||
*/
|
||||
int esp_dns_cleanup_tcp(esp_dns_handle_t handle);
|
||||
|
||||
/**
|
||||
* @brief Clean up UDP DNS module
|
||||
*
|
||||
* Releases resources allocated for the UDP DNS service. Validates the parameters,
|
||||
* checks the protocol, and cleans up the DNS module.
|
||||
*
|
||||
* @param handle Pointer to the DNS handle to be cleaned up
|
||||
*
|
||||
* @return 0 on success, -1 on failure
|
||||
*/
|
||||
int esp_dns_cleanup_udp(esp_dns_handle_t handle);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -3,6 +3,6 @@ commitizen:
|
||||
bump_message: 'bump(modem): $current_version -> $new_version'
|
||||
pre_bump_hooks: python ../../ci/changelog.py esp_modem
|
||||
tag_format: modem-v$version
|
||||
version: 1.3.0
|
||||
version: 1.4.0
|
||||
version_files:
|
||||
- idf_component.yml
|
||||
|
@ -1,5 +1,19 @@
|
||||
# Changelog
|
||||
|
||||
## [1.4.0](https://github.com/espressif/esp-protocols/commits/modem-v1.4.0)
|
||||
|
||||
### Features
|
||||
|
||||
- added config_edrx api function ([74b7d85d](https://github.com/espressif/esp-protocols/commit/74b7d85d))
|
||||
- added sqn_gm02s connect function ([b97dfc08](https://github.com/espressif/esp-protocols/commit/b97dfc08))
|
||||
- add support for sequans GM02S modem ([8560f021](https://github.com/espressif/esp-protocols/commit/8560f021))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Fix cmux log message ([6ed672da](https://github.com/espressif/esp-protocols/commit/6ed672da))
|
||||
- fixed minor code mistakes. ([317faf89](https://github.com/espressif/esp-protocols/commit/317faf89))
|
||||
- handle nullptr in DTE constructors to prevent invalid access ([95b56600](https://github.com/espressif/esp-protocols/commit/95b56600))
|
||||
|
||||
## [1.3.0](https://github.com/espressif/esp-protocols/commits/modem-v1.3.0)
|
||||
|
||||
### Features
|
||||
|
@ -15,6 +15,13 @@ else()
|
||||
endif()
|
||||
|
||||
|
||||
if(CONFIG_ESP_MODEM_ENABLE_DEVELOPMENT_MODE)
|
||||
set(command_dir "generate") # using in-place macro expansion with AT commands
|
||||
else()
|
||||
set(command_dir "command") # using pre-generated AT commands
|
||||
endif()
|
||||
|
||||
|
||||
set(srcs ${platform_srcs}
|
||||
"src/esp_modem_dte.cpp"
|
||||
"src/esp_modem_dce.cpp"
|
||||
@ -26,18 +33,16 @@ set(srcs ${platform_srcs}
|
||||
"src/esp_modem_term_fs.cpp"
|
||||
"src/esp_modem_vfs_uart_creator.cpp"
|
||||
"src/esp_modem_vfs_socket_creator.cpp"
|
||||
"src/esp_modem_modules.cpp")
|
||||
|
||||
set(include_dirs "include")
|
||||
"${command_dir}/src/esp_modem_modules.cpp")
|
||||
|
||||
idf_component_register(SRCS "${srcs}"
|
||||
INCLUDE_DIRS "${include_dirs}"
|
||||
INCLUDE_DIRS include ${command_dir}/include
|
||||
PRIV_INCLUDE_DIRS private_include
|
||||
REQUIRES ${dependencies})
|
||||
|
||||
|
||||
set_target_properties(${COMPONENT_LIB} PROPERTIES
|
||||
CXX_STANDARD 17
|
||||
CXX_STANDARD 23
|
||||
CXX_STANDARD_REQUIRED ON
|
||||
CXX_EXTENSIONS ON
|
||||
)
|
||||
|
@ -92,4 +92,15 @@ menu "esp-modem"
|
||||
If enabled, the library dumps all transmitted and received data.
|
||||
This option is only used for debugging.
|
||||
|
||||
config ESP_MODEM_ENABLE_DEVELOPMENT_MODE
|
||||
bool "Use development mode"
|
||||
default n
|
||||
help
|
||||
We use pre-generated headers and sources with common AT commands.
|
||||
This is useful for using ESP-MODEM library with IDEs and code navigation.
|
||||
When developing ESP-MODEM library, it's usually more convenient
|
||||
to work with sources directly, using C-preprocessor's metaprogramming.
|
||||
Set this to 'y' if you're making changes to the actual sources of
|
||||
the AT command definitions (typically in esp_modem_command_declare.inc)
|
||||
|
||||
endmenu
|
||||
|
@ -0,0 +1,347 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cxx_include/esp_modem_dte.hpp"
|
||||
#include "cxx_include/esp_modem_dce_module.hpp"
|
||||
#include "cxx_include/esp_modem_types.hpp"
|
||||
|
||||
namespace esp_modem {
|
||||
namespace dce_commands {
|
||||
/**
|
||||
* @defgroup ESP_MODEM_DCE_COMMAND ESP_MODEM DCE command library
|
||||
* @brief Library of the most useful DCE commands
|
||||
*/
|
||||
/** @addtogroup ESP_MODEM_DCE_COMMAND
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief Generic AT command to be send with pass and fail phrases
|
||||
*
|
||||
* @param t Commandable object (anything that can accept commands)
|
||||
* @param command Command to be sent do the commandable object
|
||||
* @param pass_phrase String to be present in the reply to pass this command
|
||||
* @param fail_phrase String to be present in the reply to fail this command
|
||||
* @param timeout_ms Timeout in ms
|
||||
*/
|
||||
command_result generic_command(CommandableIf *t, std::string_view command,
|
||||
std::string_view pass_phrase,
|
||||
std::string_view fail_phrase, uint32_t timeout_ms);
|
||||
/**
|
||||
* @brief Declaration of all commands is generated from esp_modem_command_declare.inc
|
||||
*/
|
||||
/**
|
||||
* @brief Sends the initial AT sequence to sync up with the device
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result sync(CommandableIf *t);
|
||||
/**
|
||||
* @brief Reads the operator name
|
||||
* @param[out] name operator name
|
||||
* @param[out] act access technology
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result get_operator_name(CommandableIf *t, std::string &name, int &act);
|
||||
/**
|
||||
* @brief Stores current user profile
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result store_profile(CommandableIf *t);
|
||||
/**
|
||||
* @brief Sets the supplied PIN code
|
||||
* @param[in] pin Pin
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result set_pin(CommandableIf *t, const std::string &pin);
|
||||
/**
|
||||
* @brief Execute the supplied AT command in raw mode (doesn't append '\r' to command, returns everything)
|
||||
* @param[in] cmd String command that's send to DTE
|
||||
* @param[out] out Raw output from DTE
|
||||
* @param[in] pass Pattern in response for the API to return OK
|
||||
* @param[in] fail Pattern in response for the API to return FAIL
|
||||
* @param[in] timeout AT command timeout in milliseconds
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result at_raw(CommandableIf *t, const std::string &cmd, std::string &out, const std::string &pass, const std::string &fail, int timeout);
|
||||
/**
|
||||
* @brief Execute the supplied AT command
|
||||
* @param[in] cmd AT command
|
||||
* @param[out] out Command output string
|
||||
* @param[in] timeout AT command timeout in milliseconds
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result at(CommandableIf *t, const std::string &cmd, std::string &out, int timeout);
|
||||
/**
|
||||
* @brief Checks if the SIM needs a PIN
|
||||
* @param[out] pin_ok true if the SIM card doesn't need a PIN to unlock
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result read_pin(CommandableIf *t, bool &pin_ok);
|
||||
/**
|
||||
* @brief Sets echo mode
|
||||
* @param[in] echo_on true if echo mode on (repeats the commands)
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result set_echo(CommandableIf *t, const bool echo_on);
|
||||
/**
|
||||
* @brief Sets the Txt or Pdu mode for SMS (only txt is supported)
|
||||
* @param[in] txt true if txt mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result sms_txt_mode(CommandableIf *t, const bool txt);
|
||||
/**
|
||||
* @brief Sets the default (GSM) character set
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result sms_character_set(CommandableIf *t);
|
||||
/**
|
||||
* @brief Sends SMS message in txt mode
|
||||
* @param[in] number Phone number to send the message to
|
||||
* @param[in] message Text message to be sent
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result send_sms(CommandableIf *t, const std::string &number, const std::string &message);
|
||||
/**
|
||||
* @brief Resumes data mode (Switches back to the data mode, which was temporarily suspended)
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result resume_data_mode(CommandableIf *t);
|
||||
/**
|
||||
* @brief Sets php context
|
||||
* @param[in] p1 PdP context struct to setup modem cellular connection
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result set_pdp_context(CommandableIf *t, PdpContext &pdp);
|
||||
/**
|
||||
* @brief Switches to the command mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result set_command_mode(CommandableIf *t);
|
||||
/**
|
||||
* @brief Switches to the CMUX mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result set_cmux(CommandableIf *t);
|
||||
/**
|
||||
* @brief Reads the IMSI number
|
||||
* @param[out] imsi Module's IMSI number
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result get_imsi(CommandableIf *t, std::string &imsi);
|
||||
/**
|
||||
* @brief Reads the IMEI number
|
||||
* @param[out] imei Module's IMEI number
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result get_imei(CommandableIf *t, std::string &imei);
|
||||
/**
|
||||
* @brief Reads the module name
|
||||
* @param[out] name module name
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result get_module_name(CommandableIf *t, std::string &name);
|
||||
/**
|
||||
* @brief Sets the modem to data mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result set_data_mode(CommandableIf *t);
|
||||
/**
|
||||
* @brief Get Signal quality
|
||||
* @param[out] rssi signal strength indication
|
||||
* @param[out] ber channel bit error rate
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result get_signal_quality(CommandableIf *t, int &rssi, int &ber);
|
||||
/**
|
||||
* @brief Sets HW control flow
|
||||
* @param[in] dce_flow 0=none, 2=RTS hw flow control of DCE
|
||||
* @param[in] dte_flow 0=none, 2=CTS hw flow control of DTE
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result set_flow_control(CommandableIf *t, int dce_flow, int dte_flow);
|
||||
/**
|
||||
* @brief Hangs up current data call
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result hang_up(CommandableIf *t);
|
||||
/**
|
||||
* @brief Get voltage levels of modem power up circuitry
|
||||
* @param[out] voltage Current status in mV
|
||||
* @param[out] bcs charge status (-1-Not available, 0-Not charging, 1-Charging, 2-Charging done)
|
||||
* @param[out] bcl 1-100% battery capacity, -1-Not available
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result get_battery_status(CommandableIf *t, int &voltage, int &bcs, int &bcl);
|
||||
/**
|
||||
* @brief Power down the module
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result power_down(CommandableIf *t);
|
||||
/**
|
||||
* @brief Reset the module
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result reset(CommandableIf *t);
|
||||
/**
|
||||
* @brief Configures the baudrate
|
||||
* @param[in] baud Desired baud rate of the DTE
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result set_baud(CommandableIf *t, int baud);
|
||||
/**
|
||||
* @brief Force an attempt to connect to a specific operator
|
||||
* @param[in] mode mode of attempt
|
||||
* mode=0 - automatic
|
||||
* mode=1 - manual
|
||||
* mode=2 - deregister
|
||||
* mode=3 - set format for read operation
|
||||
* mode=4 - manual with fallback to automatic
|
||||
* @param[in] format what format the operator is given in
|
||||
* format=0 - long format
|
||||
* format=1 - short format
|
||||
* format=2 - numeric
|
||||
* @param[in] oper the operator to connect to
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result set_operator(CommandableIf *t, int mode, int format, const std::string &oper);
|
||||
/**
|
||||
* @brief Attach or detach from the GPRS service
|
||||
* @param[in] state 1-attach 0-detach
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result set_network_attachment_state(CommandableIf *t, int state);
|
||||
/**
|
||||
* @brief Get network attachment state
|
||||
* @param[out] state 1-attached 0-detached
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result get_network_attachment_state(CommandableIf *t, int &state);
|
||||
/**
|
||||
* @brief What mode the radio should be set to
|
||||
* @param[in] state state 1-full 0-minimum ...
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result set_radio_state(CommandableIf *t, int state);
|
||||
/**
|
||||
* @brief Get current radio state
|
||||
* @param[out] state 1-full 0-minimum ...
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result get_radio_state(CommandableIf *t, int &state);
|
||||
/**
|
||||
* @brief Set network mode
|
||||
* @param[in] mode preferred mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result set_network_mode(CommandableIf *t, int mode);
|
||||
/**
|
||||
* @brief Preferred network mode (CAT-M and/or NB-IoT)
|
||||
* @param[in] mode preferred selection
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result set_preferred_mode(CommandableIf *t, int mode);
|
||||
/**
|
||||
* @brief Set network bands for CAT-M or NB-IoT
|
||||
* @param[in] mode CAT-M or NB-IoT
|
||||
* @param[in] bands bitmap in hex representing bands
|
||||
* @param[in] size size of teh bands bitmap
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result set_network_bands(CommandableIf *t, const std::string &mode, const int *bands, int size);
|
||||
/**
|
||||
* @brief Show network system mode
|
||||
* @param[out] mode current network mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result get_network_system_mode(CommandableIf *t, int &mode);
|
||||
/**
|
||||
* @brief GNSS power control
|
||||
* @param[out] mode power mode (0 - off, 1 - on)
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result set_gnss_power_mode(CommandableIf *t, int mode);
|
||||
/**
|
||||
* @brief GNSS power control
|
||||
* @param[out] mode power mode (0 - off, 1 - on)
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result get_gnss_power_mode(CommandableIf *t, int &mode);
|
||||
/**
|
||||
* @brief Configure PSM
|
||||
* @param[in] mode psm mode (0 - off, 1 - on, 2 - off & discard stored params)
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result config_psm(CommandableIf *t, int mode, const std::string &tau, const std::string &active_time);
|
||||
/**
|
||||
* @brief Configure CEREG urc
|
||||
* @param[in] value
|
||||
* value = 0 - Disable network URC
|
||||
* value = 1 - Enable network URC
|
||||
* value = 2 - Enable network URC with location information
|
||||
* value = 3 - Enable network URC with location information and EMM cause
|
||||
* value = 4 - Enable network URC with location information and PSM value
|
||||
* value = 5 - Enable network URC with location information and PSM value, EMM cause
|
||||
*/
|
||||
command_result config_network_registration_urc(CommandableIf *t, int value);
|
||||
/**
|
||||
* @brief Gets the current network registration state
|
||||
* @param[out] state The current network registration state
|
||||
* state = 0 - Not registered, MT is not currently searching an operator to register to
|
||||
* state = 1 - Registered, home network
|
||||
* state = 2 - Not registered, but MT is currently trying to attach or searching an operator to register to
|
||||
* state = 3 - Registration denied
|
||||
* state = 4 - Unknown
|
||||
* state = 5 - Registered, Roaming
|
||||
* state = 6 - Registered, for SMS only, home network (NB-IoT only)
|
||||
* state = 7 - Registered, for SMS only, roaming (NB-IoT only)
|
||||
* state = 8 - Attached for emergency bearer services only
|
||||
* state = 9 - Registered for CSFB not preferred, home network
|
||||
* state = 10 - Registered for CSFB not preferred, roaming
|
||||
*/
|
||||
command_result get_network_registration_state(CommandableIf *t, int &state);
|
||||
/**
|
||||
* @brief Configures the mobile termination error (+CME ERROR)
|
||||
* @param[in] mode The form of the final result code
|
||||
* mode = 0 - Disable, use and send ERROR instead
|
||||
* mode = 1 - Enable, use numeric error values
|
||||
* mode = 2 - Enable, result code and use verbose error values
|
||||
*/
|
||||
command_result config_mobile_termination_error(CommandableIf *t, int mode);
|
||||
/**
|
||||
* @brief Configure eDRX
|
||||
* @param[in] mode
|
||||
* mode = 0 - Disable
|
||||
* mode = 1 - Enable
|
||||
* mode = 2 - Enable + URC
|
||||
* mode = 3 - Disable + Reset parameter.
|
||||
* @param[in] access_technology
|
||||
* act = 0 - ACT is not using eDRX (used in URC)
|
||||
* act = 1 - EC-GSM-IoT (A/Gb mode)
|
||||
* act = 2 - GSM (A/Gb mode)
|
||||
* act = 3 - UTRAN (Iu mode)
|
||||
* act = 4 - E-UTRAN (WB-S1 mode)
|
||||
* act = 5 - E-UTRAN (NB-S1 mode)
|
||||
* @param[in] edrx_value nible string containing encoded eDRX time
|
||||
* @param[in] ptw_value nible string containing encoded Paging Time Window
|
||||
*/
|
||||
command_result config_edrx(CommandableIf *t, int mode, int access_technology, const std::string &edrx_value);
|
||||
/**
|
||||
* @brief Following commands that are different for some specific modules
|
||||
*/
|
||||
command_result get_battery_status_sim7xxx(CommandableIf *t, int &voltage, int &bcs, int &bcl);
|
||||
command_result set_gnss_power_mode_sim76xx(CommandableIf *t, int mode);
|
||||
command_result power_down_sim76xx(CommandableIf *t);
|
||||
command_result power_down_sim70xx(CommandableIf *t);
|
||||
command_result set_network_bands_sim76xx(CommandableIf *t, const std::string &mode, const int *bands, int size);
|
||||
command_result power_down_sim8xx(CommandableIf *t);
|
||||
command_result set_data_mode_alt(CommandableIf *t);
|
||||
command_result set_pdp_context(CommandableIf *t, PdpContext &pdp, uint32_t timeout_ms);
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
} // dce_commands
|
||||
} // esp_modem
|
@ -0,0 +1,453 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace esp_modem {
|
||||
/**
|
||||
* @defgroup ESP_MODEM_DCE
|
||||
* @brief Definition of DCE abstraction
|
||||
*/
|
||||
/** @addtogroup ESP_MODEM_DCE
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief Common abstraction of the modem DCE, specialized by the GenericModule which is a parent class for the supported
|
||||
* devices and most common modems, as well.
|
||||
*/
|
||||
class DCE : public DCE_T<GenericModule> {
|
||||
public:
|
||||
command_result get_operator_name(std::string &name)
|
||||
{
|
||||
return device->get_operator_name(name);
|
||||
}
|
||||
using DCE_T<GenericModule>::DCE_T;
|
||||
/**
|
||||
* @brief Sends the initial AT sequence to sync up with the device
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result sync()
|
||||
{
|
||||
return device->sync();
|
||||
}
|
||||
/**
|
||||
* @brief Reads the operator name
|
||||
* @param[out] name operator name
|
||||
* @param[out] act access technology
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result get_operator_name(std::string &name, int &act)
|
||||
{
|
||||
return device->get_operator_name(name, act);
|
||||
}
|
||||
/**
|
||||
* @brief Stores current user profile
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result store_profile()
|
||||
{
|
||||
return device->store_profile();
|
||||
}
|
||||
/**
|
||||
* @brief Sets the supplied PIN code
|
||||
* @param[in] pin Pin
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result set_pin(const std::string &pin)
|
||||
{
|
||||
return device->set_pin(pin);
|
||||
}
|
||||
/**
|
||||
* @brief Execute the supplied AT command in raw mode (doesn't append '\r' to command, returns everything)
|
||||
* @param[in] cmd String command that's send to DTE
|
||||
* @param[out] out Raw output from DTE
|
||||
* @param[in] pass Pattern in response for the API to return OK
|
||||
* @param[in] fail Pattern in response for the API to return FAIL
|
||||
* @param[in] timeout AT command timeout in milliseconds
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result at_raw(const std::string &cmd, std::string &out, const std::string &pass, const std::string &fail, int timeout)
|
||||
{
|
||||
return device->at_raw(cmd, out, pass, fail, timeout);
|
||||
}
|
||||
/**
|
||||
* @brief Execute the supplied AT command
|
||||
* @param[in] cmd AT command
|
||||
* @param[out] out Command output string
|
||||
* @param[in] timeout AT command timeout in milliseconds
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result at(const std::string &cmd, std::string &out, int timeout)
|
||||
{
|
||||
return device->at(cmd, out, timeout);
|
||||
}
|
||||
/**
|
||||
* @brief Checks if the SIM needs a PIN
|
||||
* @param[out] pin_ok true if the SIM card doesn't need a PIN to unlock
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result read_pin(bool &pin_ok)
|
||||
{
|
||||
return device->read_pin(pin_ok);
|
||||
}
|
||||
/**
|
||||
* @brief Sets echo mode
|
||||
* @param[in] echo_on true if echo mode on (repeats the commands)
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result set_echo(const bool echo_on)
|
||||
{
|
||||
return device->set_echo(echo_on);
|
||||
}
|
||||
/**
|
||||
* @brief Sets the Txt or Pdu mode for SMS (only txt is supported)
|
||||
* @param[in] txt true if txt mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result sms_txt_mode(const bool txt)
|
||||
{
|
||||
return device->sms_txt_mode(txt);
|
||||
}
|
||||
/**
|
||||
* @brief Sets the default (GSM) character set
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result sms_character_set()
|
||||
{
|
||||
return device->sms_character_set();
|
||||
}
|
||||
/**
|
||||
* @brief Sends SMS message in txt mode
|
||||
* @param[in] number Phone number to send the message to
|
||||
* @param[in] message Text message to be sent
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result send_sms(const std::string &number, const std::string &message)
|
||||
{
|
||||
return device->send_sms(number, message);
|
||||
}
|
||||
/**
|
||||
* @brief Resumes data mode (Switches back to the data mode, which was temporarily suspended)
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result resume_data_mode()
|
||||
{
|
||||
return device->resume_data_mode();
|
||||
}
|
||||
/**
|
||||
* @brief Sets php context
|
||||
* @param[in] p1 PdP context struct to setup modem cellular connection
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result set_pdp_context(PdpContext &pdp)
|
||||
{
|
||||
return device->set_pdp_context(pdp);
|
||||
}
|
||||
/**
|
||||
* @brief Switches to the command mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result set_command_mode()
|
||||
{
|
||||
return device->set_command_mode();
|
||||
}
|
||||
/**
|
||||
* @brief Switches to the CMUX mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result set_cmux()
|
||||
{
|
||||
return device->set_cmux();
|
||||
}
|
||||
/**
|
||||
* @brief Reads the IMSI number
|
||||
* @param[out] imsi Module's IMSI number
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result get_imsi(std::string &imsi)
|
||||
{
|
||||
return device->get_imsi(imsi);
|
||||
}
|
||||
/**
|
||||
* @brief Reads the IMEI number
|
||||
* @param[out] imei Module's IMEI number
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result get_imei(std::string &imei)
|
||||
{
|
||||
return device->get_imei(imei);
|
||||
}
|
||||
/**
|
||||
* @brief Reads the module name
|
||||
* @param[out] name module name
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result get_module_name(std::string &name)
|
||||
{
|
||||
return device->get_module_name(name);
|
||||
}
|
||||
/**
|
||||
* @brief Sets the modem to data mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result set_data_mode()
|
||||
{
|
||||
return device->set_data_mode();
|
||||
}
|
||||
/**
|
||||
* @brief Get Signal quality
|
||||
* @param[out] rssi signal strength indication
|
||||
* @param[out] ber channel bit error rate
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result get_signal_quality(int &rssi, int &ber)
|
||||
{
|
||||
return device->get_signal_quality(rssi, ber);
|
||||
}
|
||||
/**
|
||||
* @brief Sets HW control flow
|
||||
* @param[in] dce_flow 0=none, 2=RTS hw flow control of DCE
|
||||
* @param[in] dte_flow 0=none, 2=CTS hw flow control of DTE
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result set_flow_control(int dce_flow, int dte_flow)
|
||||
{
|
||||
return device->set_flow_control(dce_flow, dte_flow);
|
||||
}
|
||||
/**
|
||||
* @brief Hangs up current data call
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result hang_up()
|
||||
{
|
||||
return device->hang_up();
|
||||
}
|
||||
/**
|
||||
* @brief Get voltage levels of modem power up circuitry
|
||||
* @param[out] voltage Current status in mV
|
||||
* @param[out] bcs charge status (-1-Not available, 0-Not charging, 1-Charging, 2-Charging done)
|
||||
* @param[out] bcl 1-100% battery capacity, -1-Not available
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result get_battery_status(int &voltage, int &bcs, int &bcl)
|
||||
{
|
||||
return device->get_battery_status(voltage, bcs, bcl);
|
||||
}
|
||||
/**
|
||||
* @brief Power down the module
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result power_down()
|
||||
{
|
||||
return device->power_down();
|
||||
}
|
||||
/**
|
||||
* @brief Reset the module
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result reset()
|
||||
{
|
||||
return device->reset();
|
||||
}
|
||||
/**
|
||||
* @brief Configures the baudrate
|
||||
* @param[in] baud Desired baud rate of the DTE
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result set_baud(int baud)
|
||||
{
|
||||
return device->set_baud(baud);
|
||||
}
|
||||
/**
|
||||
* @brief Force an attempt to connect to a specific operator
|
||||
* @param[in] mode mode of attempt
|
||||
* mode=0 - automatic
|
||||
* mode=1 - manual
|
||||
* mode=2 - deregister
|
||||
* mode=3 - set format for read operation
|
||||
* mode=4 - manual with fallback to automatic
|
||||
* @param[in] format what format the operator is given in
|
||||
* format=0 - long format
|
||||
* format=1 - short format
|
||||
* format=2 - numeric
|
||||
* @param[in] oper the operator to connect to
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result set_operator(int mode, int format, const std::string &oper)
|
||||
{
|
||||
return device->set_operator(mode, format, oper);
|
||||
}
|
||||
/**
|
||||
* @brief Attach or detach from the GPRS service
|
||||
* @param[in] state 1-attach 0-detach
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result set_network_attachment_state(int state)
|
||||
{
|
||||
return device->set_network_attachment_state(state);
|
||||
}
|
||||
/**
|
||||
* @brief Get network attachment state
|
||||
* @param[out] state 1-attached 0-detached
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result get_network_attachment_state(int &state)
|
||||
{
|
||||
return device->get_network_attachment_state(state);
|
||||
}
|
||||
/**
|
||||
* @brief What mode the radio should be set to
|
||||
* @param[in] state state 1-full 0-minimum ...
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result set_radio_state(int state)
|
||||
{
|
||||
return device->set_radio_state(state);
|
||||
}
|
||||
/**
|
||||
* @brief Get current radio state
|
||||
* @param[out] state 1-full 0-minimum ...
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result get_radio_state(int &state)
|
||||
{
|
||||
return device->get_radio_state(state);
|
||||
}
|
||||
/**
|
||||
* @brief Set network mode
|
||||
* @param[in] mode preferred mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result set_network_mode(int mode)
|
||||
{
|
||||
return device->set_network_mode(mode);
|
||||
}
|
||||
/**
|
||||
* @brief Preferred network mode (CAT-M and/or NB-IoT)
|
||||
* @param[in] mode preferred selection
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result set_preferred_mode(int mode)
|
||||
{
|
||||
return device->set_preferred_mode(mode);
|
||||
}
|
||||
/**
|
||||
* @brief Set network bands for CAT-M or NB-IoT
|
||||
* @param[in] mode CAT-M or NB-IoT
|
||||
* @param[in] bands bitmap in hex representing bands
|
||||
* @param[in] size size of teh bands bitmap
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result set_network_bands(const std::string &mode, const int *bands, int size)
|
||||
{
|
||||
return device->set_network_bands(mode, bands, size);
|
||||
}
|
||||
/**
|
||||
* @brief Show network system mode
|
||||
* @param[out] mode current network mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result get_network_system_mode(int &mode)
|
||||
{
|
||||
return device->get_network_system_mode(mode);
|
||||
}
|
||||
/**
|
||||
* @brief GNSS power control
|
||||
* @param[out] mode power mode (0 - off, 1 - on)
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result set_gnss_power_mode(int mode)
|
||||
{
|
||||
return device->set_gnss_power_mode(mode);
|
||||
}
|
||||
/**
|
||||
* @brief GNSS power control
|
||||
* @param[out] mode power mode (0 - off, 1 - on)
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result get_gnss_power_mode(int &mode)
|
||||
{
|
||||
return device->get_gnss_power_mode(mode);
|
||||
}
|
||||
/**
|
||||
* @brief Configure PSM
|
||||
* @param[in] mode psm mode (0 - off, 1 - on, 2 - off & discard stored params)
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result config_psm(int mode, const std::string &tau, const std::string &active_time)
|
||||
{
|
||||
return device->config_psm(mode, tau, active_time);
|
||||
}
|
||||
/**
|
||||
* @brief Configure CEREG urc
|
||||
* @param[in] value
|
||||
* value = 0 - Disable network URC
|
||||
* value = 1 - Enable network URC
|
||||
* value = 2 - Enable network URC with location information
|
||||
* value = 3 - Enable network URC with location information and EMM cause
|
||||
* value = 4 - Enable network URC with location information and PSM value
|
||||
* value = 5 - Enable network URC with location information and PSM value, EMM cause
|
||||
*/
|
||||
command_result config_network_registration_urc(int value)
|
||||
{
|
||||
return device->config_network_registration_urc(value);
|
||||
}
|
||||
/**
|
||||
* @brief Gets the current network registration state
|
||||
* @param[out] state The current network registration state
|
||||
* state = 0 - Not registered, MT is not currently searching an operator to register to
|
||||
* state = 1 - Registered, home network
|
||||
* state = 2 - Not registered, but MT is currently trying to attach or searching an operator to register to
|
||||
* state = 3 - Registration denied
|
||||
* state = 4 - Unknown
|
||||
* state = 5 - Registered, Roaming
|
||||
* state = 6 - Registered, for SMS only, home network (NB-IoT only)
|
||||
* state = 7 - Registered, for SMS only, roaming (NB-IoT only)
|
||||
* state = 8 - Attached for emergency bearer services only
|
||||
* state = 9 - Registered for CSFB not preferred, home network
|
||||
* state = 10 - Registered for CSFB not preferred, roaming
|
||||
*/
|
||||
command_result get_network_registration_state(int &state)
|
||||
{
|
||||
return device->get_network_registration_state(state);
|
||||
}
|
||||
/**
|
||||
* @brief Configures the mobile termination error (+CME ERROR)
|
||||
* @param[in] mode The form of the final result code
|
||||
* mode = 0 - Disable, use and send ERROR instead
|
||||
* mode = 1 - Enable, use numeric error values
|
||||
* mode = 2 - Enable, result code and use verbose error values
|
||||
*/
|
||||
command_result config_mobile_termination_error(int mode)
|
||||
{
|
||||
return device->config_mobile_termination_error(mode);
|
||||
}
|
||||
/**
|
||||
* @brief Configure eDRX
|
||||
* @param[in] mode
|
||||
* mode = 0 - Disable
|
||||
* mode = 1 - Enable
|
||||
* mode = 2 - Enable + URC
|
||||
* mode = 3 - Disable + Reset parameter.
|
||||
* @param[in] access_technology
|
||||
* act = 0 - ACT is not using eDRX (used in URC)
|
||||
* act = 1 - EC-GSM-IoT (A/Gb mode)
|
||||
* act = 2 - GSM (A/Gb mode)
|
||||
* act = 3 - UTRAN (Iu mode)
|
||||
* act = 4 - E-UTRAN (WB-S1 mode)
|
||||
* act = 5 - E-UTRAN (NB-S1 mode)
|
||||
* @param[in] edrx_value nible string containing encoded eDRX time
|
||||
* @param[in] ptw_value nible string containing encoded Paging Time Window
|
||||
*/
|
||||
command_result config_edrx(int mode, int access_technology, const std::string &edrx_value)
|
||||
{
|
||||
return device->config_edrx(mode, access_technology, edrx_value);
|
||||
}
|
||||
};
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
} // esp_modem
|
@ -0,0 +1,461 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
//#include "generate/esp_modem_command_declare.inc"
|
||||
#include "cxx_include/esp_modem_command_library.hpp"
|
||||
#include "cxx_include/esp_modem_types.hpp"
|
||||
#include "esp_modem_dce_config.h"
|
||||
|
||||
|
||||
namespace esp_modem {
|
||||
/**
|
||||
* @defgroup ESP_MODEM_MODULE
|
||||
* @brief Definition of modules representing specific modem devices
|
||||
*/
|
||||
/** @addtogroup ESP_MODEM_MODULE
|
||||
* @{
|
||||
*/
|
||||
enum class command_result;
|
||||
class DTE;
|
||||
struct PdpContext;
|
||||
/**
|
||||
* @brief This is a basic building block for custom modules as well as for the supported modules in the esp-modem component
|
||||
* It derives from the ModuleIf.
|
||||
*/
|
||||
class GenericModule: public ModuleIf {
|
||||
public:
|
||||
/**
|
||||
* @brief We can construct a generic device with an existent DTE and it's configuration
|
||||
* The configuration could be either the dce-config struct or just a pdp context
|
||||
*/
|
||||
explicit GenericModule(std::shared_ptr<DTE> dte, std::unique_ptr<PdpContext> pdp):
|
||||
dte(std::move(dte)), pdp(std::move(pdp)) {}
|
||||
explicit GenericModule(std::shared_ptr<DTE> dte, const esp_modem_dce_config *config);
|
||||
/**
|
||||
* @brief This is a mandatory method for ModuleIf class, which sets up the device
|
||||
* to be able to connect to the network. This typically consists of setting basic
|
||||
* communication parameters and setting the PDP (defining logical access point
|
||||
* to cellular network)
|
||||
*/
|
||||
bool setup_data_mode() override
|
||||
{
|
||||
if (set_echo(false) != command_result::OK) {
|
||||
return false;
|
||||
}
|
||||
if (set_pdp_context(*pdp) != command_result::OK) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* @brief This is a mandatory method of ModuleIf class, which defines
|
||||
* basic commands for switching between DATA, COMMAND and CMUX modes
|
||||
*/
|
||||
bool set_mode(modem_mode mode) override
|
||||
{
|
||||
if (mode == modem_mode::DATA_MODE) {
|
||||
if (set_data_mode() != command_result::OK) {
|
||||
return resume_data_mode() == command_result::OK;
|
||||
}
|
||||
return true;
|
||||
} else if (mode == modem_mode::COMMAND_MODE) {
|
||||
Task::Delay(1000); // Mandatory 1s pause before
|
||||
int retry = 0;
|
||||
while (retry++ < 3) {
|
||||
if (set_command_mode() == command_result::OK) {
|
||||
return true;
|
||||
}
|
||||
// send a newline to delimit the escape from the upcoming sync command
|
||||
uint8_t delim = '\n';
|
||||
dte->write(&delim, 1);
|
||||
if (sync() == command_result::OK) {
|
||||
return true;
|
||||
}
|
||||
Task::Delay(1000); // Mandatory 1s pause before escape
|
||||
}
|
||||
return false;
|
||||
} else if (mode == modem_mode::CMUX_MODE) {
|
||||
return set_cmux() == command_result::OK;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* @brief Additional method providing runtime configuration of PDP context
|
||||
*/
|
||||
void configure_pdp_context(std::unique_ptr<PdpContext> new_pdp)
|
||||
{
|
||||
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
|
||||
*/
|
||||
// DECLARE_ALL_COMMAND_APIS(virtual return_type name(...); )
|
||||
/**
|
||||
* @brief Sends the initial AT sequence to sync up with the device
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
virtual command_result sync();
|
||||
/**
|
||||
* @brief Reads the operator name
|
||||
* @param[out] name operator name
|
||||
* @param[out] act access technology
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
virtual command_result get_operator_name(std::string &name, int &act);
|
||||
/**
|
||||
* @brief Stores current user profile
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
virtual command_result store_profile();
|
||||
/**
|
||||
* @brief Sets the supplied PIN code
|
||||
* @param[in] pin Pin
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
virtual command_result set_pin(const std::string &pin);
|
||||
/**
|
||||
* @brief Execute the supplied AT command in raw mode (doesn't append '\r' to command, returns everything)
|
||||
* @param[in] cmd String command that's send to DTE
|
||||
* @param[out] out Raw output from DTE
|
||||
* @param[in] pass Pattern in response for the API to return OK
|
||||
* @param[in] fail Pattern in response for the API to return FAIL
|
||||
* @param[in] timeout AT command timeout in milliseconds
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
virtual command_result at_raw(const std::string &cmd, std::string &out, const std::string &pass, const std::string &fail, int timeout);
|
||||
/**
|
||||
* @brief Execute the supplied AT command
|
||||
* @param[in] cmd AT command
|
||||
* @param[out] out Command output string
|
||||
* @param[in] timeout AT command timeout in milliseconds
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
virtual command_result at(const std::string &cmd, std::string &out, int timeout);
|
||||
/**
|
||||
* @brief Checks if the SIM needs a PIN
|
||||
* @param[out] pin_ok true if the SIM card doesn't need a PIN to unlock
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
virtual command_result read_pin(bool &pin_ok);
|
||||
/**
|
||||
* @brief Sets echo mode
|
||||
* @param[in] echo_on true if echo mode on (repeats the commands)
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
virtual command_result set_echo(const bool echo_on);
|
||||
/**
|
||||
* @brief Sets the Txt or Pdu mode for SMS (only txt is supported)
|
||||
* @param[in] txt true if txt mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
virtual command_result sms_txt_mode(const bool txt);
|
||||
/**
|
||||
* @brief Sets the default (GSM) character set
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
virtual command_result sms_character_set();
|
||||
/**
|
||||
* @brief Sends SMS message in txt mode
|
||||
* @param[in] number Phone number to send the message to
|
||||
* @param[in] message Text message to be sent
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
virtual command_result send_sms(const std::string &number, const std::string &message);
|
||||
/**
|
||||
* @brief Resumes data mode (Switches back to the data mode, which was temporarily suspended)
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
virtual command_result resume_data_mode();
|
||||
/**
|
||||
* @brief Sets php context
|
||||
* @param[in] p1 PdP context struct to setup modem cellular connection
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
virtual command_result set_pdp_context(PdpContext &pdp);
|
||||
/**
|
||||
* @brief Switches to the command mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
virtual command_result set_command_mode();
|
||||
/**
|
||||
* @brief Switches to the CMUX mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
virtual command_result set_cmux();
|
||||
/**
|
||||
* @brief Reads the IMSI number
|
||||
* @param[out] imsi Module's IMSI number
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
virtual command_result get_imsi(std::string &imsi);
|
||||
/**
|
||||
* @brief Reads the IMEI number
|
||||
* @param[out] imei Module's IMEI number
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
virtual command_result get_imei(std::string &imei);
|
||||
/**
|
||||
* @brief Reads the module name
|
||||
* @param[out] name module name
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
virtual command_result get_module_name(std::string &name);
|
||||
/**
|
||||
* @brief Sets the modem to data mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
virtual command_result set_data_mode();
|
||||
/**
|
||||
* @brief Get Signal quality
|
||||
* @param[out] rssi signal strength indication
|
||||
* @param[out] ber channel bit error rate
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
virtual command_result get_signal_quality(int &rssi, int &ber);
|
||||
/**
|
||||
* @brief Sets HW control flow
|
||||
* @param[in] dce_flow 0=none, 2=RTS hw flow control of DCE
|
||||
* @param[in] dte_flow 0=none, 2=CTS hw flow control of DTE
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
virtual command_result set_flow_control(int dce_flow, int dte_flow);
|
||||
/**
|
||||
* @brief Hangs up current data call
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
virtual command_result hang_up();
|
||||
/**
|
||||
* @brief Get voltage levels of modem power up circuitry
|
||||
* @param[out] voltage Current status in mV
|
||||
* @param[out] bcs charge status (-1-Not available, 0-Not charging, 1-Charging, 2-Charging done)
|
||||
* @param[out] bcl 1-100% battery capacity, -1-Not available
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
virtual command_result get_battery_status(int &voltage, int &bcs, int &bcl);
|
||||
/**
|
||||
* @brief Power down the module
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
virtual command_result power_down();
|
||||
/**
|
||||
* @brief Reset the module
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
virtual command_result reset();
|
||||
/**
|
||||
* @brief Configures the baudrate
|
||||
* @param[in] baud Desired baud rate of the DTE
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
virtual command_result set_baud(int baud);
|
||||
/**
|
||||
* @brief Force an attempt to connect to a specific operator
|
||||
* @param[in] mode mode of attempt
|
||||
* mode=0 - automatic
|
||||
* mode=1 - manual
|
||||
* mode=2 - deregister
|
||||
* mode=3 - set format for read operation
|
||||
* mode=4 - manual with fallback to automatic
|
||||
* @param[in] format what format the operator is given in
|
||||
* format=0 - long format
|
||||
* format=1 - short format
|
||||
* format=2 - numeric
|
||||
* @param[in] oper the operator to connect to
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
virtual command_result set_operator(int mode, int format, const std::string &oper);
|
||||
/**
|
||||
* @brief Attach or detach from the GPRS service
|
||||
* @param[in] state 1-attach 0-detach
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
virtual command_result set_network_attachment_state(int state);
|
||||
/**
|
||||
* @brief Get network attachment state
|
||||
* @param[out] state 1-attached 0-detached
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
virtual command_result get_network_attachment_state(int &state);
|
||||
/**
|
||||
* @brief What mode the radio should be set to
|
||||
* @param[in] state state 1-full 0-minimum ...
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
virtual command_result set_radio_state(int state);
|
||||
/**
|
||||
* @brief Get current radio state
|
||||
* @param[out] state 1-full 0-minimum ...
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
virtual command_result get_radio_state(int &state);
|
||||
/**
|
||||
* @brief Set network mode
|
||||
* @param[in] mode preferred mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
virtual command_result set_network_mode(int mode);
|
||||
/**
|
||||
* @brief Preferred network mode (CAT-M and/or NB-IoT)
|
||||
* @param[in] mode preferred selection
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
virtual command_result set_preferred_mode(int mode);
|
||||
/**
|
||||
* @brief Set network bands for CAT-M or NB-IoT
|
||||
* @param[in] mode CAT-M or NB-IoT
|
||||
* @param[in] bands bitmap in hex representing bands
|
||||
* @param[in] size size of teh bands bitmap
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
virtual command_result set_network_bands(const std::string &mode, const int *bands, int size);
|
||||
/**
|
||||
* @brief Show network system mode
|
||||
* @param[out] mode current network mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
virtual command_result get_network_system_mode(int &mode);
|
||||
/**
|
||||
* @brief GNSS power control
|
||||
* @param[out] mode power mode (0 - off, 1 - on)
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
virtual command_result set_gnss_power_mode(int mode);
|
||||
/**
|
||||
* @brief GNSS power control
|
||||
* @param[out] mode power mode (0 - off, 1 - on)
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
virtual command_result get_gnss_power_mode(int &mode);
|
||||
/**
|
||||
* @brief Configure PSM
|
||||
* @param[in] mode psm mode (0 - off, 1 - on, 2 - off & discard stored params)
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
virtual command_result config_psm(int mode, const std::string &tau, const std::string &active_time);
|
||||
/**
|
||||
* @brief Configure CEREG urc
|
||||
* @param[in] value
|
||||
* value = 0 - Disable network URC
|
||||
* value = 1 - Enable network URC
|
||||
* value = 2 - Enable network URC with location information
|
||||
* value = 3 - Enable network URC with location information and EMM cause
|
||||
* value = 4 - Enable network URC with location information and PSM value
|
||||
* value = 5 - Enable network URC with location information and PSM value, EMM cause
|
||||
*/
|
||||
virtual command_result config_network_registration_urc(int value);
|
||||
/**
|
||||
* @brief Gets the current network registration state
|
||||
* @param[out] state The current network registration state
|
||||
* state = 0 - Not registered, MT is not currently searching an operator to register to
|
||||
* state = 1 - Registered, home network
|
||||
* state = 2 - Not registered, but MT is currently trying to attach or searching an operator to register to
|
||||
* state = 3 - Registration denied
|
||||
* state = 4 - Unknown
|
||||
* state = 5 - Registered, Roaming
|
||||
* state = 6 - Registered, for SMS only, home network (NB-IoT only)
|
||||
* state = 7 - Registered, for SMS only, roaming (NB-IoT only)
|
||||
* state = 8 - Attached for emergency bearer services only
|
||||
* state = 9 - Registered for CSFB not preferred, home network
|
||||
* state = 10 - Registered for CSFB not preferred, roaming
|
||||
*/
|
||||
virtual command_result get_network_registration_state(int &state);
|
||||
/**
|
||||
* @brief Configures the mobile termination error (+CME ERROR)
|
||||
* @param[in] mode The form of the final result code
|
||||
* mode = 0 - Disable, use and send ERROR instead
|
||||
* mode = 1 - Enable, use numeric error values
|
||||
* mode = 2 - Enable, result code and use verbose error values
|
||||
*/
|
||||
virtual command_result config_mobile_termination_error(int mode);
|
||||
/**
|
||||
* @brief Configure eDRX
|
||||
* @param[in] mode
|
||||
* mode = 0 - Disable
|
||||
* mode = 1 - Enable
|
||||
* mode = 2 - Enable + URC
|
||||
* mode = 3 - Disable + Reset parameter.
|
||||
* @param[in] access_technology
|
||||
* act = 0 - ACT is not using eDRX (used in URC)
|
||||
* act = 1 - EC-GSM-IoT (A/Gb mode)
|
||||
* act = 2 - GSM (A/Gb mode)
|
||||
* act = 3 - UTRAN (Iu mode)
|
||||
* act = 4 - E-UTRAN (WB-S1 mode)
|
||||
* act = 5 - E-UTRAN (NB-S1 mode)
|
||||
* @param[in] edrx_value nible string containing encoded eDRX time
|
||||
* @param[in] ptw_value nible string containing encoded Paging Time Window
|
||||
*/
|
||||
virtual command_result config_edrx(int mode, int access_technology, const std::string &edrx_value);
|
||||
protected:
|
||||
std::shared_ptr<DTE> dte; /*!< Generic device needs the DTE as a channel talk to the module using AT commands */
|
||||
std::unique_ptr<PdpContext> pdp; /*!< It also needs a PDP data, const information used for setting up cellular network */
|
||||
};
|
||||
// Definitions of other supported modules with some specific commands overwritten
|
||||
/**
|
||||
* @brief Specific definition of the SIM7600 module
|
||||
*/
|
||||
class SIM7600: public GenericModule {
|
||||
using GenericModule::GenericModule;
|
||||
public:
|
||||
command_result get_battery_status(int &voltage, int &bcs, int &bcl) override;
|
||||
command_result power_down() override;
|
||||
command_result set_gnss_power_mode(int mode) override;
|
||||
command_result set_network_bands(const std::string &mode, const int *bands, int size) override;
|
||||
};
|
||||
/**
|
||||
* @brief Specific definition of the SIM7070 module
|
||||
*/
|
||||
class SIM7070: public GenericModule {
|
||||
using GenericModule::GenericModule;
|
||||
public:
|
||||
command_result power_down() override;
|
||||
command_result set_data_mode() override;
|
||||
};
|
||||
/**
|
||||
* @brief Specific definition of the SIM7000 module
|
||||
*/
|
||||
class SIM7000: public GenericModule {
|
||||
using GenericModule::GenericModule;
|
||||
public:
|
||||
command_result power_down() override;
|
||||
};
|
||||
/**
|
||||
* @brief Specific definition of the SIM800 module
|
||||
*/
|
||||
class SIM800: public GenericModule {
|
||||
using GenericModule::GenericModule;
|
||||
public:
|
||||
command_result power_down() override;
|
||||
};
|
||||
/**
|
||||
* @brief Specific definition of the BG96 module
|
||||
*/
|
||||
class BG96: public GenericModule {
|
||||
using GenericModule::GenericModule;
|
||||
public:
|
||||
command_result set_pdp_context(PdpContext &pdp) override;
|
||||
};
|
||||
class SQNGM02S : public GenericModule {
|
||||
using GenericModule::GenericModule;
|
||||
public:
|
||||
command_result connect(PdpContext &pdp);
|
||||
bool setup_data_mode() override;
|
||||
};
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
} // namespace esp_modem
|
316
components/esp_modem/command/include/esp_modem_api.h
Normal file
316
components/esp_modem/command/include/esp_modem_api.h
Normal file
@ -0,0 +1,316 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "esp_err.h"
|
||||
//#include "generate/esp_modem_command_declare.inc"
|
||||
#include "esp_modem_c_api_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Sends the initial AT sequence to sync up with the device
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_err_t esp_modem_sync(esp_modem_dce_t *dce);
|
||||
/**
|
||||
* @brief Reads the operator name
|
||||
* @param[out] name operator name
|
||||
* @param[out] act access technology
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_err_t esp_modem_get_operator_name(esp_modem_dce_t *dce, char *name, int *act);
|
||||
/**
|
||||
* @brief Stores current user profile
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_err_t esp_modem_store_profile(esp_modem_dce_t *dce);
|
||||
/**
|
||||
* @brief Sets the supplied PIN code
|
||||
* @param[in] pin Pin
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_err_t esp_modem_set_pin(esp_modem_dce_t *dce, const char *pin);
|
||||
/**
|
||||
* @brief Execute the supplied AT command in raw mode (doesn't append '\r' to command, returns everything)
|
||||
* @param[in] cmd String command that's send to DTE
|
||||
* @param[out] out Raw output from DTE
|
||||
* @param[in] pass Pattern in response for the API to return OK
|
||||
* @param[in] fail Pattern in response for the API to return FAIL
|
||||
* @param[in] timeout AT command timeout in milliseconds
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_err_t esp_modem_at_raw(esp_modem_dce_t *dce, const char *cmd, char *out, const char *pass, const char *fail, int timeout);
|
||||
/**
|
||||
* @brief Execute the supplied AT command
|
||||
* @param[in] cmd AT command
|
||||
* @param[out] out Command output string
|
||||
* @param[in] timeout AT command timeout in milliseconds
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_err_t esp_modem_at(esp_modem_dce_t *dce, const char *cmd, char *out, int timeout);
|
||||
/**
|
||||
* @brief Checks if the SIM needs a PIN
|
||||
* @param[out] pin_ok true if the SIM card doesn't need a PIN to unlock
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_err_t esp_modem_read_pin(esp_modem_dce_t *dce, bool *pin_ok);
|
||||
/**
|
||||
* @brief Sets echo mode
|
||||
* @param[in] echo_on true if echo mode on (repeats the commands)
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_err_t esp_modem_set_echo(esp_modem_dce_t *dce, const bool echo_on);
|
||||
/**
|
||||
* @brief Sets the Txt or Pdu mode for SMS (only txt is supported)
|
||||
* @param[in] txt true if txt mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_err_t esp_modem_sms_txt_mode(esp_modem_dce_t *dce, const bool txt);
|
||||
/**
|
||||
* @brief Sets the default (GSM) character set
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_err_t esp_modem_sms_character_set(esp_modem_dce_t *dce);
|
||||
/**
|
||||
* @brief Sends SMS message in txt mode
|
||||
* @param[in] number Phone number to send the message to
|
||||
* @param[in] message Text message to be sent
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_err_t esp_modem_send_sms(esp_modem_dce_t *dce, const char *number, const char *message);
|
||||
/**
|
||||
* @brief Resumes data mode (Switches back to the data mode, which was temporarily suspended)
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_err_t esp_modem_resume_data_mode(esp_modem_dce_t *dce);
|
||||
/**
|
||||
* @brief Sets php context
|
||||
* @param[in] p1 PdP context struct to setup modem cellular connection
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_err_t esp_modem_set_pdp_context(esp_modem_dce_t *dce, esp_modem_PdpContext_t *pdp);
|
||||
/**
|
||||
* @brief Switches to the command mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_err_t esp_modem_set_command_mode(esp_modem_dce_t *dce);
|
||||
/**
|
||||
* @brief Switches to the CMUX mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_err_t esp_modem_set_cmux(esp_modem_dce_t *dce);
|
||||
/**
|
||||
* @brief Reads the IMSI number
|
||||
* @param[out] imsi Module's IMSI number
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_err_t esp_modem_get_imsi(esp_modem_dce_t *dce, char *imsi);
|
||||
/**
|
||||
* @brief Reads the IMEI number
|
||||
* @param[out] imei Module's IMEI number
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_err_t esp_modem_get_imei(esp_modem_dce_t *dce, char *imei);
|
||||
/**
|
||||
* @brief Reads the module name
|
||||
* @param[out] name module name
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_err_t esp_modem_get_module_name(esp_modem_dce_t *dce, char *name);
|
||||
/**
|
||||
* @brief Sets the modem to data mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_err_t esp_modem_set_data_mode(esp_modem_dce_t *dce);
|
||||
/**
|
||||
* @brief Get Signal quality
|
||||
* @param[out] rssi signal strength indication
|
||||
* @param[out] ber channel bit error rate
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_err_t esp_modem_get_signal_quality(esp_modem_dce_t *dce, int *rssi, int *ber);
|
||||
/**
|
||||
* @brief Sets HW control flow
|
||||
* @param[in] dce_flow 0=none, 2=RTS hw flow control of DCE
|
||||
* @param[in] dte_flow 0=none, 2=CTS hw flow control of DTE
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_err_t esp_modem_set_flow_control(esp_modem_dce_t *dce, int dce_flow, int dte_flow);
|
||||
/**
|
||||
* @brief Hangs up current data call
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_err_t esp_modem_hang_up(esp_modem_dce_t *dce);
|
||||
/**
|
||||
* @brief Get voltage levels of modem power up circuitry
|
||||
* @param[out] voltage Current status in mV
|
||||
* @param[out] bcs charge status (-1-Not available, 0-Not charging, 1-Charging, 2-Charging done)
|
||||
* @param[out] bcl 1-100% battery capacity, -1-Not available
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_err_t esp_modem_get_battery_status(esp_modem_dce_t *dce, int *voltage, int *bcs, int *bcl);
|
||||
/**
|
||||
* @brief Power down the module
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_err_t esp_modem_power_down(esp_modem_dce_t *dce);
|
||||
/**
|
||||
* @brief Reset the module
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_err_t esp_modem_reset(esp_modem_dce_t *dce);
|
||||
/**
|
||||
* @brief Configures the baudrate
|
||||
* @param[in] baud Desired baud rate of the DTE
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_err_t esp_modem_set_baud(esp_modem_dce_t *dce, int baud);
|
||||
/**
|
||||
* @brief Force an attempt to connect to a specific operator
|
||||
* @param[in] mode mode of attempt
|
||||
* mode=0 - automatic
|
||||
* mode=1 - manual
|
||||
* mode=2 - deregister
|
||||
* mode=3 - set format for read operation
|
||||
* mode=4 - manual with fallback to automatic
|
||||
* @param[in] format what format the operator is given in
|
||||
* format=0 - long format
|
||||
* format=1 - short format
|
||||
* format=2 - numeric
|
||||
* @param[in] oper the operator to connect to
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_err_t esp_modem_set_operator(esp_modem_dce_t *dce, int mode, int format, const char *oper);
|
||||
/**
|
||||
* @brief Attach or detach from the GPRS service
|
||||
* @param[in] state 1-attach 0-detach
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_err_t esp_modem_set_network_attachment_state(esp_modem_dce_t *dce, int state);
|
||||
/**
|
||||
* @brief Get network attachment state
|
||||
* @param[out] state 1-attached 0-detached
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_err_t esp_modem_get_network_attachment_state(esp_modem_dce_t *dce, int *state);
|
||||
/**
|
||||
* @brief What mode the radio should be set to
|
||||
* @param[in] state state 1-full 0-minimum ...
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_err_t esp_modem_set_radio_state(esp_modem_dce_t *dce, int state);
|
||||
/**
|
||||
* @brief Get current radio state
|
||||
* @param[out] state 1-full 0-minimum ...
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_err_t esp_modem_get_radio_state(esp_modem_dce_t *dce, int *state);
|
||||
/**
|
||||
* @brief Set network mode
|
||||
* @param[in] mode preferred mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_err_t esp_modem_set_network_mode(esp_modem_dce_t *dce, int mode);
|
||||
/**
|
||||
* @brief Preferred network mode (CAT-M and/or NB-IoT)
|
||||
* @param[in] mode preferred selection
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_err_t esp_modem_set_preferred_mode(esp_modem_dce_t *dce, int mode);
|
||||
/**
|
||||
* @brief Set network bands for CAT-M or NB-IoT
|
||||
* @param[in] mode CAT-M or NB-IoT
|
||||
* @param[in] bands bitmap in hex representing bands
|
||||
* @param[in] size size of teh bands bitmap
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_err_t esp_modem_set_network_bands(esp_modem_dce_t *dce, const char *mode, const int *bands, int size);
|
||||
/**
|
||||
* @brief Show network system mode
|
||||
* @param[out] mode current network mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_err_t esp_modem_get_network_system_mode(esp_modem_dce_t *dce, int *mode);
|
||||
/**
|
||||
* @brief GNSS power control
|
||||
* @param[out] mode power mode (0 - off, 1 - on)
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_err_t esp_modem_set_gnss_power_mode(esp_modem_dce_t *dce, int mode);
|
||||
/**
|
||||
* @brief GNSS power control
|
||||
* @param[out] mode power mode (0 - off, 1 - on)
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_err_t esp_modem_get_gnss_power_mode(esp_modem_dce_t *dce, int *mode);
|
||||
/**
|
||||
* @brief Configure PSM
|
||||
* @param[in] mode psm mode (0 - off, 1 - on, 2 - off & discard stored params)
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_err_t esp_modem_config_psm(esp_modem_dce_t *dce, int mode, const char *tau, const char *active_time);
|
||||
/**
|
||||
* @brief Configure CEREG urc
|
||||
* @param[in] value
|
||||
* value = 0 - Disable network URC
|
||||
* value = 1 - Enable network URC
|
||||
* value = 2 - Enable network URC with location information
|
||||
* value = 3 - Enable network URC with location information and EMM cause
|
||||
* value = 4 - Enable network URC with location information and PSM value
|
||||
* value = 5 - Enable network URC with location information and PSM value, EMM cause
|
||||
*/
|
||||
esp_err_t esp_modem_config_network_registration_urc(esp_modem_dce_t *dce, int value);
|
||||
/**
|
||||
* @brief Gets the current network registration state
|
||||
* @param[out] state The current network registration state
|
||||
* state = 0 - Not registered, MT is not currently searching an operator to register to
|
||||
* state = 1 - Registered, home network
|
||||
* state = 2 - Not registered, but MT is currently trying to attach or searching an operator to register to
|
||||
* state = 3 - Registration denied
|
||||
* state = 4 - Unknown
|
||||
* state = 5 - Registered, Roaming
|
||||
* state = 6 - Registered, for SMS only, home network (NB-IoT only)
|
||||
* state = 7 - Registered, for SMS only, roaming (NB-IoT only)
|
||||
* state = 8 - Attached for emergency bearer services only
|
||||
* state = 9 - Registered for CSFB not preferred, home network
|
||||
* state = 10 - Registered for CSFB not preferred, roaming
|
||||
*/
|
||||
esp_err_t esp_modem_get_network_registration_state(esp_modem_dce_t *dce, int *state);
|
||||
/**
|
||||
* @brief Configures the mobile termination error (+CME ERROR)
|
||||
* @param[in] mode The form of the final result code
|
||||
* mode = 0 - Disable, use and send ERROR instead
|
||||
* mode = 1 - Enable, use numeric error values
|
||||
* mode = 2 - Enable, result code and use verbose error values
|
||||
*/
|
||||
esp_err_t esp_modem_config_mobile_termination_error(esp_modem_dce_t *dce, int mode);
|
||||
/**
|
||||
* @brief Configure eDRX
|
||||
* @param[in] mode
|
||||
* mode = 0 - Disable
|
||||
* mode = 1 - Enable
|
||||
* mode = 2 - Enable + URC
|
||||
* mode = 3 - Disable + Reset parameter.
|
||||
* @param[in] access_technology
|
||||
* act = 0 - ACT is not using eDRX (used in URC)
|
||||
* act = 1 - EC-GSM-IoT (A/Gb mode)
|
||||
* act = 2 - GSM (A/Gb mode)
|
||||
* act = 3 - UTRAN (Iu mode)
|
||||
* act = 4 - E-UTRAN (WB-S1 mode)
|
||||
* act = 5 - E-UTRAN (NB-S1 mode)
|
||||
* @param[in] edrx_value nible string containing encoded eDRX time
|
||||
* @param[in] ptw_value nible string containing encoded Paging Time Window
|
||||
*/
|
||||
esp_err_t esp_modem_config_edrx(esp_modem_dce_t *dce, int mode, int access_technology, const char *edrx_value);
|
||||
// --- ESP-MODEM command module ends here ---
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
512
components/esp_modem/command/src/esp_modem_modules.cpp
Normal file
512
components/esp_modem/command/src/esp_modem_modules.cpp
Normal file
@ -0,0 +1,512 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "cxx_include/esp_modem_api.hpp"
|
||||
#include "cxx_include/esp_modem_dce_module.hpp"
|
||||
#include "cxx17_include/esp_modem_command_library_17.hpp"
|
||||
#include "cxx_include/esp_modem_dte.hpp"
|
||||
|
||||
namespace esp_modem {
|
||||
GenericModule::GenericModule(std::shared_ptr<DTE> dte, const dce_config *config) :
|
||||
dte(std::move(dte)), pdp(std::make_unique<PdpContext>(config->apn)) {}
|
||||
/**
|
||||
* @brief Sends the initial AT sequence to sync up with the device
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result GenericModule::sync()
|
||||
{
|
||||
return esp_modem::dce_commands::sync(dte.get());
|
||||
}
|
||||
/**
|
||||
* @brief Reads the operator name
|
||||
* @param[out] name operator name
|
||||
* @param[out] act access technology
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result GenericModule::get_operator_name(std::string &name, int &act)
|
||||
{
|
||||
return esp_modem::dce_commands::get_operator_name(dte.get(), name, act);
|
||||
}
|
||||
/**
|
||||
* @brief Stores current user profile
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result GenericModule::store_profile()
|
||||
{
|
||||
return esp_modem::dce_commands::store_profile(dte.get());
|
||||
}
|
||||
/**
|
||||
* @brief Sets the supplied PIN code
|
||||
* @param[in] pin Pin
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result GenericModule::set_pin(const std::string &pin)
|
||||
{
|
||||
return esp_modem::dce_commands::set_pin(dte.get(), pin);
|
||||
}
|
||||
/**
|
||||
* @brief Execute the supplied AT command in raw mode (doesn't append '\r' to command, returns everything)
|
||||
* @param[in] cmd String command that's send to DTE
|
||||
* @param[out] out Raw output from DTE
|
||||
* @param[in] pass Pattern in response for the API to return OK
|
||||
* @param[in] fail Pattern in response for the API to return FAIL
|
||||
* @param[in] timeout AT command timeout in milliseconds
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result GenericModule::at_raw(const std::string &cmd, std::string &out, const std::string &pass, const std::string &fail, int timeout)
|
||||
{
|
||||
return esp_modem::dce_commands::at_raw(dte.get(), cmd, out, pass, fail, timeout);
|
||||
}
|
||||
/**
|
||||
* @brief Execute the supplied AT command
|
||||
* @param[in] cmd AT command
|
||||
* @param[out] out Command output string
|
||||
* @param[in] timeout AT command timeout in milliseconds
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result GenericModule::at(const std::string &cmd, std::string &out, int timeout)
|
||||
{
|
||||
return esp_modem::dce_commands::at(dte.get(), cmd, out, timeout);
|
||||
}
|
||||
/**
|
||||
* @brief Checks if the SIM needs a PIN
|
||||
* @param[out] pin_ok true if the SIM card doesn't need a PIN to unlock
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result GenericModule::read_pin(bool &pin_ok)
|
||||
{
|
||||
return esp_modem::dce_commands::read_pin(dte.get(), pin_ok);
|
||||
}
|
||||
/**
|
||||
* @brief Sets echo mode
|
||||
* @param[in] echo_on true if echo mode on (repeats the commands)
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result GenericModule::set_echo(const bool echo_on)
|
||||
{
|
||||
return esp_modem::dce_commands::set_echo(dte.get(), echo_on);
|
||||
}
|
||||
/**
|
||||
* @brief Sets the Txt or Pdu mode for SMS (only txt is supported)
|
||||
* @param[in] txt true if txt mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result GenericModule::sms_txt_mode(const bool txt)
|
||||
{
|
||||
return esp_modem::dce_commands::sms_txt_mode(dte.get(), txt);
|
||||
}
|
||||
/**
|
||||
* @brief Sets the default (GSM) character set
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result GenericModule::sms_character_set()
|
||||
{
|
||||
return esp_modem::dce_commands::sms_character_set(dte.get());
|
||||
}
|
||||
/**
|
||||
* @brief Sends SMS message in txt mode
|
||||
* @param[in] number Phone number to send the message to
|
||||
* @param[in] message Text message to be sent
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result GenericModule::send_sms(const std::string &number, const std::string &message)
|
||||
{
|
||||
return esp_modem::dce_commands::send_sms(dte.get(), number, message);
|
||||
}
|
||||
/**
|
||||
* @brief Resumes data mode (Switches back to the data mode, which was temporarily suspended)
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result GenericModule::resume_data_mode()
|
||||
{
|
||||
return esp_modem::dce_commands::resume_data_mode(dte.get());
|
||||
}
|
||||
/**
|
||||
* @brief Sets php context
|
||||
* @param[in] p1 PdP context struct to setup modem cellular connection
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result GenericModule::set_pdp_context(PdpContext &pdp)
|
||||
{
|
||||
return esp_modem::dce_commands::set_pdp_context(dte.get(), pdp);
|
||||
}
|
||||
/**
|
||||
* @brief Switches to the command mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result GenericModule::set_command_mode()
|
||||
{
|
||||
return esp_modem::dce_commands::set_command_mode(dte.get());
|
||||
}
|
||||
/**
|
||||
* @brief Switches to the CMUX mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result GenericModule::set_cmux()
|
||||
{
|
||||
return esp_modem::dce_commands::set_cmux(dte.get());
|
||||
}
|
||||
/**
|
||||
* @brief Reads the IMSI number
|
||||
* @param[out] imsi Module's IMSI number
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result GenericModule::get_imsi(std::string &imsi)
|
||||
{
|
||||
return esp_modem::dce_commands::get_imsi(dte.get(), imsi);
|
||||
}
|
||||
/**
|
||||
* @brief Reads the IMEI number
|
||||
* @param[out] imei Module's IMEI number
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result GenericModule::get_imei(std::string &imei)
|
||||
{
|
||||
return esp_modem::dce_commands::get_imei(dte.get(), imei);
|
||||
}
|
||||
/**
|
||||
* @brief Reads the module name
|
||||
* @param[out] name module name
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result GenericModule::get_module_name(std::string &name)
|
||||
{
|
||||
return esp_modem::dce_commands::get_module_name(dte.get(), name);
|
||||
}
|
||||
/**
|
||||
* @brief Sets the modem to data mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result GenericModule::set_data_mode()
|
||||
{
|
||||
return esp_modem::dce_commands::set_data_mode(dte.get());
|
||||
}
|
||||
/**
|
||||
* @brief Get Signal quality
|
||||
* @param[out] rssi signal strength indication
|
||||
* @param[out] ber channel bit error rate
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result GenericModule::get_signal_quality(int &rssi, int &ber)
|
||||
{
|
||||
return esp_modem::dce_commands::get_signal_quality(dte.get(), rssi, ber);
|
||||
}
|
||||
/**
|
||||
* @brief Sets HW control flow
|
||||
* @param[in] dce_flow 0=none, 2=RTS hw flow control of DCE
|
||||
* @param[in] dte_flow 0=none, 2=CTS hw flow control of DTE
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result GenericModule::set_flow_control(int dce_flow, int dte_flow)
|
||||
{
|
||||
return esp_modem::dce_commands::set_flow_control(dte.get(), dce_flow, dte_flow);
|
||||
}
|
||||
/**
|
||||
* @brief Hangs up current data call
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result GenericModule::hang_up()
|
||||
{
|
||||
return esp_modem::dce_commands::hang_up(dte.get());
|
||||
}
|
||||
/**
|
||||
* @brief Get voltage levels of modem power up circuitry
|
||||
* @param[out] voltage Current status in mV
|
||||
* @param[out] bcs charge status (-1-Not available, 0-Not charging, 1-Charging, 2-Charging done)
|
||||
* @param[out] bcl 1-100% battery capacity, -1-Not available
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result GenericModule::get_battery_status(int &voltage, int &bcs, int &bcl)
|
||||
{
|
||||
return esp_modem::dce_commands::get_battery_status(dte.get(), voltage, bcs, bcl);
|
||||
}
|
||||
/**
|
||||
* @brief Power down the module
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result GenericModule::power_down()
|
||||
{
|
||||
return esp_modem::dce_commands::power_down(dte.get());
|
||||
}
|
||||
/**
|
||||
* @brief Reset the module
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result GenericModule::reset()
|
||||
{
|
||||
return esp_modem::dce_commands::reset(dte.get());
|
||||
}
|
||||
/**
|
||||
* @brief Configures the baudrate
|
||||
* @param[in] baud Desired baud rate of the DTE
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result GenericModule::set_baud(int baud)
|
||||
{
|
||||
return esp_modem::dce_commands::set_baud(dte.get(), baud);
|
||||
}
|
||||
/**
|
||||
* @brief Force an attempt to connect to a specific operator
|
||||
* @param[in] mode mode of attempt
|
||||
* mode=0 - automatic
|
||||
* mode=1 - manual
|
||||
* mode=2 - deregister
|
||||
* mode=3 - set format for read operation
|
||||
* mode=4 - manual with fallback to automatic
|
||||
* @param[in] format what format the operator is given in
|
||||
* format=0 - long format
|
||||
* format=1 - short format
|
||||
* format=2 - numeric
|
||||
* @param[in] oper the operator to connect to
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result GenericModule::set_operator(int mode, int format, const std::string &oper)
|
||||
{
|
||||
return esp_modem::dce_commands::set_operator(dte.get(), mode, format, oper);
|
||||
}
|
||||
/**
|
||||
* @brief Attach or detach from the GPRS service
|
||||
* @param[in] state 1-attach 0-detach
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result GenericModule::set_network_attachment_state(int state)
|
||||
{
|
||||
return esp_modem::dce_commands::set_network_attachment_state(dte.get(), state);
|
||||
}
|
||||
/**
|
||||
* @brief Get network attachment state
|
||||
* @param[out] state 1-attached 0-detached
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result GenericModule::get_network_attachment_state(int &state)
|
||||
{
|
||||
return esp_modem::dce_commands::get_network_attachment_state(dte.get(), state);
|
||||
}
|
||||
/**
|
||||
* @brief What mode the radio should be set to
|
||||
* @param[in] state state 1-full 0-minimum ...
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result GenericModule::set_radio_state(int state)
|
||||
{
|
||||
return esp_modem::dce_commands::set_radio_state(dte.get(), state);
|
||||
}
|
||||
/**
|
||||
* @brief Get current radio state
|
||||
* @param[out] state 1-full 0-minimum ...
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result GenericModule::get_radio_state(int &state)
|
||||
{
|
||||
return esp_modem::dce_commands::get_radio_state(dte.get(), state);
|
||||
}
|
||||
/**
|
||||
* @brief Set network mode
|
||||
* @param[in] mode preferred mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result GenericModule::set_network_mode(int mode)
|
||||
{
|
||||
return esp_modem::dce_commands::set_network_mode(dte.get(), mode);
|
||||
}
|
||||
/**
|
||||
* @brief Preferred network mode (CAT-M and/or NB-IoT)
|
||||
* @param[in] mode preferred selection
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result GenericModule::set_preferred_mode(int mode)
|
||||
{
|
||||
return esp_modem::dce_commands::set_preferred_mode(dte.get(), mode);
|
||||
}
|
||||
/**
|
||||
* @brief Set network bands for CAT-M or NB-IoT
|
||||
* @param[in] mode CAT-M or NB-IoT
|
||||
* @param[in] bands bitmap in hex representing bands
|
||||
* @param[in] size size of teh bands bitmap
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result GenericModule::set_network_bands(const std::string &mode, const int *bands, int size)
|
||||
{
|
||||
return esp_modem::dce_commands::set_network_bands(dte.get(), mode, bands, size);
|
||||
}
|
||||
/**
|
||||
* @brief Show network system mode
|
||||
* @param[out] mode current network mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result GenericModule::get_network_system_mode(int &mode)
|
||||
{
|
||||
return esp_modem::dce_commands::get_network_system_mode(dte.get(), mode);
|
||||
}
|
||||
/**
|
||||
* @brief GNSS power control
|
||||
* @param[out] mode power mode (0 - off, 1 - on)
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result GenericModule::set_gnss_power_mode(int mode)
|
||||
{
|
||||
return esp_modem::dce_commands::set_gnss_power_mode(dte.get(), mode);
|
||||
}
|
||||
/**
|
||||
* @brief GNSS power control
|
||||
* @param[out] mode power mode (0 - off, 1 - on)
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result GenericModule::get_gnss_power_mode(int &mode)
|
||||
{
|
||||
return esp_modem::dce_commands::get_gnss_power_mode(dte.get(), mode);
|
||||
}
|
||||
/**
|
||||
* @brief Configure PSM
|
||||
* @param[in] mode psm mode (0 - off, 1 - on, 2 - off & discard stored params)
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result GenericModule::config_psm(int mode, const std::string &tau, const std::string &active_time)
|
||||
{
|
||||
return esp_modem::dce_commands::config_psm(dte.get(), mode, tau, active_time);
|
||||
}
|
||||
/**
|
||||
* @brief Configure CEREG urc
|
||||
* @param[in] value
|
||||
* value = 0 - Disable network URC
|
||||
* value = 1 - Enable network URC
|
||||
* value = 2 - Enable network URC with location information
|
||||
* value = 3 - Enable network URC with location information and EMM cause
|
||||
* value = 4 - Enable network URC with location information and PSM value
|
||||
* value = 5 - Enable network URC with location information and PSM value, EMM cause
|
||||
*/
|
||||
command_result GenericModule::config_network_registration_urc(int value)
|
||||
{
|
||||
return esp_modem::dce_commands::config_network_registration_urc(dte.get(), value);
|
||||
}
|
||||
/**
|
||||
* @brief Gets the current network registration state
|
||||
* @param[out] state The current network registration state
|
||||
* state = 0 - Not registered, MT is not currently searching an operator to register to
|
||||
* state = 1 - Registered, home network
|
||||
* state = 2 - Not registered, but MT is currently trying to attach or searching an operator to register to
|
||||
* state = 3 - Registration denied
|
||||
* state = 4 - Unknown
|
||||
* state = 5 - Registered, Roaming
|
||||
* state = 6 - Registered, for SMS only, home network (NB-IoT only)
|
||||
* state = 7 - Registered, for SMS only, roaming (NB-IoT only)
|
||||
* state = 8 - Attached for emergency bearer services only
|
||||
* state = 9 - Registered for CSFB not preferred, home network
|
||||
* state = 10 - Registered for CSFB not preferred, roaming
|
||||
*/
|
||||
command_result GenericModule::get_network_registration_state(int &state)
|
||||
{
|
||||
return esp_modem::dce_commands::get_network_registration_state(dte.get(), state);
|
||||
}
|
||||
/**
|
||||
* @brief Configures the mobile termination error (+CME ERROR)
|
||||
* @param[in] mode The form of the final result code
|
||||
* mode = 0 - Disable, use and send ERROR instead
|
||||
* mode = 1 - Enable, use numeric error values
|
||||
* mode = 2 - Enable, result code and use verbose error values
|
||||
*/
|
||||
command_result GenericModule::config_mobile_termination_error(int mode)
|
||||
{
|
||||
return esp_modem::dce_commands::config_mobile_termination_error(dte.get(), mode);
|
||||
}
|
||||
/**
|
||||
* @brief Configure eDRX
|
||||
* @param[in] mode
|
||||
* mode = 0 - Disable
|
||||
* mode = 1 - Enable
|
||||
* mode = 2 - Enable + URC
|
||||
* mode = 3 - Disable + Reset parameter.
|
||||
* @param[in] access_technology
|
||||
* act = 0 - ACT is not using eDRX (used in URC)
|
||||
* act = 1 - EC-GSM-IoT (A/Gb mode)
|
||||
* act = 2 - GSM (A/Gb mode)
|
||||
* act = 3 - UTRAN (Iu mode)
|
||||
* act = 4 - E-UTRAN (WB-S1 mode)
|
||||
* act = 5 - E-UTRAN (NB-S1 mode)
|
||||
* @param[in] edrx_value nible string containing encoded eDRX time
|
||||
* @param[in] ptw_value nible string containing encoded Paging Time Window
|
||||
*/
|
||||
command_result GenericModule::config_edrx(int mode, int access_technology, const std::string &edrx_value)
|
||||
{
|
||||
return esp_modem::dce_commands::config_edrx(dte.get(), mode, access_technology, edrx_value);
|
||||
}
|
||||
// Usage examples:
|
||||
// Zero arguments
|
||||
// Helper to apply the correct macro to each parameter
|
||||
//
|
||||
// Repeat all declarations and forward to the AT commands defined in esp_modem::dce_commands:: namespace
|
||||
//
|
||||
//
|
||||
// Handle specific commands for specific supported modems
|
||||
//
|
||||
command_result SIM7600::get_battery_status(int &voltage, int &bcs, int &bcl)
|
||||
{
|
||||
return dce_commands::get_battery_status_sim7xxx(dte.get(), voltage, bcs, bcl);
|
||||
}
|
||||
command_result SIM7600::set_network_bands(const std::string &mode, const int *bands, int size)
|
||||
{
|
||||
return dce_commands::set_network_bands_sim76xx(dte.get(), mode, bands, size);
|
||||
}
|
||||
command_result SIM7600::set_gnss_power_mode(int mode)
|
||||
{
|
||||
return dce_commands::set_gnss_power_mode_sim76xx(dte.get(), mode);
|
||||
}
|
||||
command_result SIM7600::power_down()
|
||||
{
|
||||
return dce_commands::power_down_sim76xx(dte.get());
|
||||
}
|
||||
command_result SIM7070::power_down()
|
||||
{
|
||||
return dce_commands::power_down_sim70xx(dte.get());
|
||||
}
|
||||
command_result SIM7070::set_data_mode()
|
||||
{
|
||||
return dce_commands::set_data_mode_alt(dte.get());
|
||||
}
|
||||
command_result SIM7000::power_down()
|
||||
{
|
||||
return dce_commands::power_down_sim70xx(dte.get());
|
||||
}
|
||||
command_result SIM800::power_down()
|
||||
{
|
||||
return dce_commands::power_down_sim8xx(dte.get());
|
||||
}
|
||||
command_result BG96::set_pdp_context(esp_modem::PdpContext &pdp)
|
||||
{
|
||||
return dce_commands::set_pdp_context(dte.get(), pdp, 300);
|
||||
}
|
||||
bool SQNGM02S::setup_data_mode()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
command_result SQNGM02S::connect(PdpContext &pdp)
|
||||
{
|
||||
command_result res;
|
||||
configure_pdp_context(std::make_unique<PdpContext>(pdp));
|
||||
set_pdp_context(*this->pdp);
|
||||
res = config_network_registration_urc(1);
|
||||
if (res != command_result::OK) {
|
||||
return res;
|
||||
}
|
||||
res = set_radio_state(1);
|
||||
if (res != command_result::OK) {
|
||||
return res;
|
||||
}
|
||||
//wait for +CEREG: 5 or +CEREG: 1.
|
||||
const std::string_view pass[] {"+CEREG: 1", "+CEREG: 5"};
|
||||
const std::string_view fail[] {"ERROR"};
|
||||
res = esp_modem::dce_commands::generic_command(dte.get(), "", pass, fail, 1200000);
|
||||
if (res != command_result::OK) {
|
||||
config_network_registration_urc(0);
|
||||
return res;
|
||||
}
|
||||
res = config_network_registration_urc(0);
|
||||
if (res != command_result::OK) {
|
||||
return res;
|
||||
}
|
||||
return command_result::OK;
|
||||
}
|
||||
}
|
@ -1,7 +1,13 @@
|
||||
if(CONFIG_ESP_MODEM_ENABLE_DEVELOPMENT_MODE)
|
||||
set(command_dir "generate")
|
||||
else()
|
||||
set(command_dir "command")
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS "modem_console_main.cpp"
|
||||
"console_helper.cpp"
|
||||
"my_module_dce.cpp"
|
||||
"${command_dir}/my_module_dce.cpp"
|
||||
"httpget_handle.c"
|
||||
"ping_handle.c"
|
||||
REQUIRES console esp_http_client nvs_flash
|
||||
INCLUDE_DIRS ".")
|
||||
INCLUDE_DIRS "." "${command_dir}")
|
||||
|
@ -0,0 +1,510 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
/* Modem console example: Custom DCE
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include <cstring>
|
||||
#include "cxx_include/esp_modem_api.hpp"
|
||||
#include "cxx_include/esp_modem_dce_module.hpp"
|
||||
//#include "generate/esp_modem_command_declare.inc"
|
||||
#include "my_module_dce.hpp"
|
||||
|
||||
using namespace esp_modem;
|
||||
//
|
||||
// Define preprocessor's forwarding to dce_commands definitions
|
||||
//
|
||||
//
|
||||
// Repeat all declarations and forward to the AT commands defined in esp_modem::dce_commands:: namespace
|
||||
//
|
||||
//DECLARE_ALL_COMMAND_APIS(return_type name(...) )
|
||||
/**
|
||||
* @brief Sends the initial AT sequence to sync up with the device
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result Shiny::DCE::sync()
|
||||
{
|
||||
return esp_modem::dce_commands::sync(this);
|
||||
}
|
||||
/**
|
||||
* @brief Reads the operator name
|
||||
* @param[out] name operator name
|
||||
* @param[out] act access technology
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result Shiny::DCE::get_operator_name(std::string &name, int &act)
|
||||
{
|
||||
return esp_modem::dce_commands::get_operator_name(this, name, act);
|
||||
}
|
||||
/**
|
||||
* @brief Stores current user profile
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result Shiny::DCE::store_profile()
|
||||
{
|
||||
return esp_modem::dce_commands::store_profile(this);
|
||||
}
|
||||
/**
|
||||
* @brief Sets the supplied PIN code
|
||||
* @param[in] pin Pin
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result Shiny::DCE::set_pin(const std::string &pin)
|
||||
{
|
||||
return esp_modem::dce_commands::set_pin(this, pin);
|
||||
}
|
||||
/**
|
||||
* @brief Execute the supplied AT command in raw mode (doesn't append '\r' to command, returns everything)
|
||||
* @param[in] cmd String command that's send to DTE
|
||||
* @param[out] out Raw output from DTE
|
||||
* @param[in] pass Pattern in response for the API to return OK
|
||||
* @param[in] fail Pattern in response for the API to return FAIL
|
||||
* @param[in] timeout AT command timeout in milliseconds
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result Shiny::DCE::at_raw(const std::string &cmd, std::string &out, const std::string &pass, const std::string &fail, int timeout)
|
||||
{
|
||||
return esp_modem::dce_commands::at_raw(this, cmd, out, pass, fail, timeout);
|
||||
}
|
||||
/**
|
||||
* @brief Execute the supplied AT command
|
||||
* @param[in] cmd AT command
|
||||
* @param[out] out Command output string
|
||||
* @param[in] timeout AT command timeout in milliseconds
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result Shiny::DCE::at(const std::string &cmd, std::string &out, int timeout)
|
||||
{
|
||||
return esp_modem::dce_commands::at(this, cmd, out, timeout);
|
||||
}
|
||||
/**
|
||||
* @brief Checks if the SIM needs a PIN
|
||||
* @param[out] pin_ok true if the SIM card doesn't need a PIN to unlock
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result Shiny::DCE::read_pin(bool &pin_ok)
|
||||
{
|
||||
return esp_modem::dce_commands::read_pin(this, pin_ok);
|
||||
}
|
||||
/**
|
||||
* @brief Sets echo mode
|
||||
* @param[in] echo_on true if echo mode on (repeats the commands)
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result Shiny::DCE::set_echo(const bool echo_on)
|
||||
{
|
||||
return esp_modem::dce_commands::set_echo(this, echo_on);
|
||||
}
|
||||
/**
|
||||
* @brief Sets the Txt or Pdu mode for SMS (only txt is supported)
|
||||
* @param[in] txt true if txt mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result Shiny::DCE::sms_txt_mode(const bool txt)
|
||||
{
|
||||
return esp_modem::dce_commands::sms_txt_mode(this, txt);
|
||||
}
|
||||
/**
|
||||
* @brief Sets the default (GSM) character set
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result Shiny::DCE::sms_character_set()
|
||||
{
|
||||
return esp_modem::dce_commands::sms_character_set(this);
|
||||
}
|
||||
/**
|
||||
* @brief Sends SMS message in txt mode
|
||||
* @param[in] number Phone number to send the message to
|
||||
* @param[in] message Text message to be sent
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result Shiny::DCE::send_sms(const std::string &number, const std::string &message)
|
||||
{
|
||||
return esp_modem::dce_commands::send_sms(this, number, message);
|
||||
}
|
||||
/**
|
||||
* @brief Resumes data mode (Switches back to the data mode, which was temporarily suspended)
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result Shiny::DCE::resume_data_mode()
|
||||
{
|
||||
return esp_modem::dce_commands::resume_data_mode(this);
|
||||
}
|
||||
/**
|
||||
* @brief Sets php context
|
||||
* @param[in] p1 PdP context struct to setup modem cellular connection
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result Shiny::DCE::set_pdp_context(PdpContext &pdp)
|
||||
{
|
||||
return esp_modem::dce_commands::set_pdp_context(this, pdp);
|
||||
}
|
||||
/**
|
||||
* @brief Switches to the command mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result Shiny::DCE::set_command_mode()
|
||||
{
|
||||
return esp_modem::dce_commands::set_command_mode(this);
|
||||
}
|
||||
/**
|
||||
* @brief Switches to the CMUX mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result Shiny::DCE::set_cmux()
|
||||
{
|
||||
return esp_modem::dce_commands::set_cmux(this);
|
||||
}
|
||||
/**
|
||||
* @brief Reads the IMSI number
|
||||
* @param[out] imsi Module's IMSI number
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result Shiny::DCE::get_imsi(std::string &imsi)
|
||||
{
|
||||
return esp_modem::dce_commands::get_imsi(this, imsi);
|
||||
}
|
||||
/**
|
||||
* @brief Reads the IMEI number
|
||||
* @param[out] imei Module's IMEI number
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result Shiny::DCE::get_imei(std::string &imei)
|
||||
{
|
||||
return esp_modem::dce_commands::get_imei(this, imei);
|
||||
}
|
||||
/**
|
||||
* @brief Reads the module name
|
||||
* @param[out] name module name
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result Shiny::DCE::get_module_name(std::string &name)
|
||||
{
|
||||
return esp_modem::dce_commands::get_module_name(this, name);
|
||||
}
|
||||
/**
|
||||
* @brief Sets the modem to data mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result Shiny::DCE::set_data_mode()
|
||||
{
|
||||
return esp_modem::dce_commands::set_data_mode(this);
|
||||
}
|
||||
/**
|
||||
* @brief Get Signal quality
|
||||
* @param[out] rssi signal strength indication
|
||||
* @param[out] ber channel bit error rate
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result Shiny::DCE::get_signal_quality(int &rssi, int &ber)
|
||||
{
|
||||
return esp_modem::dce_commands::get_signal_quality(this, rssi, ber);
|
||||
}
|
||||
/**
|
||||
* @brief Sets HW control flow
|
||||
* @param[in] dce_flow 0=none, 2=RTS hw flow control of DCE
|
||||
* @param[in] dte_flow 0=none, 2=CTS hw flow control of DTE
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result Shiny::DCE::set_flow_control(int dce_flow, int dte_flow)
|
||||
{
|
||||
return esp_modem::dce_commands::set_flow_control(this, dce_flow, dte_flow);
|
||||
}
|
||||
/**
|
||||
* @brief Hangs up current data call
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result Shiny::DCE::hang_up()
|
||||
{
|
||||
return esp_modem::dce_commands::hang_up(this);
|
||||
}
|
||||
/**
|
||||
* @brief Get voltage levels of modem power up circuitry
|
||||
* @param[out] voltage Current status in mV
|
||||
* @param[out] bcs charge status (-1-Not available, 0-Not charging, 1-Charging, 2-Charging done)
|
||||
* @param[out] bcl 1-100% battery capacity, -1-Not available
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result Shiny::DCE::get_battery_status(int &voltage, int &bcs, int &bcl)
|
||||
{
|
||||
return esp_modem::dce_commands::get_battery_status(this, voltage, bcs, bcl);
|
||||
}
|
||||
/**
|
||||
* @brief Power down the module
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result Shiny::DCE::power_down()
|
||||
{
|
||||
return esp_modem::dce_commands::power_down(this);
|
||||
}
|
||||
/**
|
||||
* @brief Reset the module
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result Shiny::DCE::reset()
|
||||
{
|
||||
return esp_modem::dce_commands::reset(this);
|
||||
}
|
||||
/**
|
||||
* @brief Configures the baudrate
|
||||
* @param[in] baud Desired baud rate of the DTE
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result Shiny::DCE::set_baud(int baud)
|
||||
{
|
||||
return esp_modem::dce_commands::set_baud(this, baud);
|
||||
}
|
||||
/**
|
||||
* @brief Force an attempt to connect to a specific operator
|
||||
* @param[in] mode mode of attempt
|
||||
* mode=0 - automatic
|
||||
* mode=1 - manual
|
||||
* mode=2 - deregister
|
||||
* mode=3 - set format for read operation
|
||||
* mode=4 - manual with fallback to automatic
|
||||
* @param[in] format what format the operator is given in
|
||||
* format=0 - long format
|
||||
* format=1 - short format
|
||||
* format=2 - numeric
|
||||
* @param[in] oper the operator to connect to
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result Shiny::DCE::set_operator(int mode, int format, const std::string &oper)
|
||||
{
|
||||
return esp_modem::dce_commands::set_operator(this, mode, format, oper);
|
||||
}
|
||||
/**
|
||||
* @brief Attach or detach from the GPRS service
|
||||
* @param[in] state 1-attach 0-detach
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result Shiny::DCE::set_network_attachment_state(int state)
|
||||
{
|
||||
return esp_modem::dce_commands::set_network_attachment_state(this, state);
|
||||
}
|
||||
/**
|
||||
* @brief Get network attachment state
|
||||
* @param[out] state 1-attached 0-detached
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result Shiny::DCE::get_network_attachment_state(int &state)
|
||||
{
|
||||
return esp_modem::dce_commands::get_network_attachment_state(this, state);
|
||||
}
|
||||
/**
|
||||
* @brief What mode the radio should be set to
|
||||
* @param[in] state state 1-full 0-minimum ...
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result Shiny::DCE::set_radio_state(int state)
|
||||
{
|
||||
return esp_modem::dce_commands::set_radio_state(this, state);
|
||||
}
|
||||
/**
|
||||
* @brief Get current radio state
|
||||
* @param[out] state 1-full 0-minimum ...
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result Shiny::DCE::get_radio_state(int &state)
|
||||
{
|
||||
return esp_modem::dce_commands::get_radio_state(this, state);
|
||||
}
|
||||
/**
|
||||
* @brief Set network mode
|
||||
* @param[in] mode preferred mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result Shiny::DCE::set_network_mode(int mode)
|
||||
{
|
||||
return esp_modem::dce_commands::set_network_mode(this, mode);
|
||||
}
|
||||
/**
|
||||
* @brief Preferred network mode (CAT-M and/or NB-IoT)
|
||||
* @param[in] mode preferred selection
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result Shiny::DCE::set_preferred_mode(int mode)
|
||||
{
|
||||
return esp_modem::dce_commands::set_preferred_mode(this, mode);
|
||||
}
|
||||
/**
|
||||
* @brief Set network bands for CAT-M or NB-IoT
|
||||
* @param[in] mode CAT-M or NB-IoT
|
||||
* @param[in] bands bitmap in hex representing bands
|
||||
* @param[in] size size of teh bands bitmap
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result Shiny::DCE::set_network_bands(const std::string &mode, const int *bands, int size)
|
||||
{
|
||||
return esp_modem::dce_commands::set_network_bands(this, mode, bands, size);
|
||||
}
|
||||
/**
|
||||
* @brief Show network system mode
|
||||
* @param[out] mode current network mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result Shiny::DCE::get_network_system_mode(int &mode)
|
||||
{
|
||||
return esp_modem::dce_commands::get_network_system_mode(this, mode);
|
||||
}
|
||||
/**
|
||||
* @brief GNSS power control
|
||||
* @param[out] mode power mode (0 - off, 1 - on)
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result Shiny::DCE::set_gnss_power_mode(int mode)
|
||||
{
|
||||
return esp_modem::dce_commands::set_gnss_power_mode(this, mode);
|
||||
}
|
||||
/**
|
||||
* @brief GNSS power control
|
||||
* @param[out] mode power mode (0 - off, 1 - on)
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result Shiny::DCE::get_gnss_power_mode(int &mode)
|
||||
{
|
||||
return esp_modem::dce_commands::get_gnss_power_mode(this, mode);
|
||||
}
|
||||
/**
|
||||
* @brief Configure PSM
|
||||
* @param[in] mode psm mode (0 - off, 1 - on, 2 - off & discard stored params)
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result Shiny::DCE::config_psm(int mode, const std::string &tau, const std::string &active_time)
|
||||
{
|
||||
return esp_modem::dce_commands::config_psm(this, mode, tau, active_time);
|
||||
}
|
||||
/**
|
||||
* @brief Configure CEREG urc
|
||||
* @param[in] value
|
||||
* value = 0 - Disable network URC
|
||||
* value = 1 - Enable network URC
|
||||
* value = 2 - Enable network URC with location information
|
||||
* value = 3 - Enable network URC with location information and EMM cause
|
||||
* value = 4 - Enable network URC with location information and PSM value
|
||||
* value = 5 - Enable network URC with location information and PSM value, EMM cause
|
||||
*/
|
||||
command_result Shiny::DCE::config_network_registration_urc(int value)
|
||||
{
|
||||
return esp_modem::dce_commands::config_network_registration_urc(this, value);
|
||||
}
|
||||
/**
|
||||
* @brief Gets the current network registration state
|
||||
* @param[out] state The current network registration state
|
||||
* state = 0 - Not registered, MT is not currently searching an operator to register to
|
||||
* state = 1 - Registered, home network
|
||||
* state = 2 - Not registered, but MT is currently trying to attach or searching an operator to register to
|
||||
* state = 3 - Registration denied
|
||||
* state = 4 - Unknown
|
||||
* state = 5 - Registered, Roaming
|
||||
* state = 6 - Registered, for SMS only, home network (NB-IoT only)
|
||||
* state = 7 - Registered, for SMS only, roaming (NB-IoT only)
|
||||
* state = 8 - Attached for emergency bearer services only
|
||||
* state = 9 - Registered for CSFB not preferred, home network
|
||||
* state = 10 - Registered for CSFB not preferred, roaming
|
||||
*/
|
||||
command_result Shiny::DCE::get_network_registration_state(int &state)
|
||||
{
|
||||
return esp_modem::dce_commands::get_network_registration_state(this, state);
|
||||
}
|
||||
/**
|
||||
* @brief Configures the mobile termination error (+CME ERROR)
|
||||
* @param[in] mode The form of the final result code
|
||||
* mode = 0 - Disable, use and send ERROR instead
|
||||
* mode = 1 - Enable, use numeric error values
|
||||
* mode = 2 - Enable, result code and use verbose error values
|
||||
*/
|
||||
command_result Shiny::DCE::config_mobile_termination_error(int mode)
|
||||
{
|
||||
return esp_modem::dce_commands::config_mobile_termination_error(this, mode);
|
||||
}
|
||||
/**
|
||||
* @brief Configure eDRX
|
||||
* @param[in] mode
|
||||
* mode = 0 - Disable
|
||||
* mode = 1 - Enable
|
||||
* mode = 2 - Enable + URC
|
||||
* mode = 3 - Disable + Reset parameter.
|
||||
* @param[in] access_technology
|
||||
* act = 0 - ACT is not using eDRX (used in URC)
|
||||
* act = 1 - EC-GSM-IoT (A/Gb mode)
|
||||
* act = 2 - GSM (A/Gb mode)
|
||||
* act = 3 - UTRAN (Iu mode)
|
||||
* act = 4 - E-UTRAN (WB-S1 mode)
|
||||
* act = 5 - E-UTRAN (NB-S1 mode)
|
||||
* @param[in] edrx_value nible string containing encoded eDRX time
|
||||
* @param[in] ptw_value nible string containing encoded Paging Time Window
|
||||
*/
|
||||
command_result Shiny::DCE::config_edrx(int mode, int access_technology, const std::string &edrx_value)
|
||||
{
|
||||
return esp_modem::dce_commands::config_edrx(this, mode, access_technology, edrx_value);
|
||||
}
|
||||
std::unique_ptr<Shiny::DCE> create_shiny_dce(const esp_modem::dce_config *config,
|
||||
std::shared_ptr<esp_modem::DTE> dte,
|
||||
esp_netif_t *netif)
|
||||
{
|
||||
return Shiny::Factory::create(config, std::move(dte), netif);
|
||||
}
|
||||
/**
|
||||
* @brief Definition of the command API, which makes the Shiny::DCE "command-able class"
|
||||
* @param cmd Command to send
|
||||
* @param got_line Recv line callback
|
||||
* @param time_ms timeout in ms
|
||||
* @param separator line break separator
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
command_result Shiny::DCE::command(const std::string &cmd, got_line_cb got_line, uint32_t time_ms, const char separator)
|
||||
{
|
||||
if (!handling_urc) {
|
||||
return dte->command(cmd, got_line, time_ms, separator);
|
||||
}
|
||||
handle_cmd = got_line;
|
||||
signal.clear((1) | (2));
|
||||
esp_modem::DTE_Command command{cmd};
|
||||
dte->write(command);
|
||||
signal.wait_any((1) | (2), time_ms);
|
||||
handle_cmd = nullptr;
|
||||
if (signal.is_any((1))) {
|
||||
return esp_modem::command_result::OK;
|
||||
}
|
||||
if (signal.is_any((2))) {
|
||||
return esp_modem::command_result::FAIL;
|
||||
}
|
||||
return esp_modem::command_result::TIMEOUT;
|
||||
}
|
||||
/**
|
||||
* @brief Handle received data
|
||||
*
|
||||
* @param data Data received from the device
|
||||
* @param len Length of the data
|
||||
* @return standard command return code (OK|FAIL|TIMEOUT)
|
||||
*/
|
||||
command_result Shiny::DCE::handle_data(uint8_t *data, size_t len)
|
||||
{
|
||||
if (std::memchr(data, '\n', len)) {
|
||||
if (handle_urc) {
|
||||
handle_urc(data, len);
|
||||
}
|
||||
if (handle_cmd) {
|
||||
auto ret = handle_cmd(data, len);
|
||||
if (ret == esp_modem::command_result::TIMEOUT) {
|
||||
return command_result::TIMEOUT;
|
||||
}
|
||||
if (ret == esp_modem::command_result::OK) {
|
||||
signal.set((1));
|
||||
}
|
||||
if (ret == esp_modem::command_result::FAIL) {
|
||||
signal.set((2));
|
||||
}
|
||||
}
|
||||
}
|
||||
return command_result::TIMEOUT;
|
||||
}
|
@ -0,0 +1,381 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modem console example: Custom DCE
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "cxx_include/esp_modem_dce_factory.hpp"
|
||||
#include "cxx_include/esp_modem_dce_module.hpp"
|
||||
|
||||
/**
|
||||
* @brief Definition of a custom DCE uses GenericModule and all its methods
|
||||
* but could override command processing. Here, for demonstration purposes only,
|
||||
* we "inject" URC handler to the actual command processing.
|
||||
* This is possible since we inherit from `CommandableIf` and redefine `command()` method.
|
||||
* Then we're able to use declare all common methods from the command library
|
||||
* to be processed using "our" `command()` method (with custom URC handler).
|
||||
*/
|
||||
namespace Shiny {
|
||||
using namespace esp_modem;
|
||||
class DCE : public esp_modem::DCE_T<GenericModule>, public CommandableIf {
|
||||
public:
|
||||
using DCE_T<GenericModule>::DCE_T;
|
||||
command_result
|
||||
command(const std::string &cmd, got_line_cb got_line, uint32_t time_ms) override
|
||||
{
|
||||
return command(cmd, got_line, time_ms, '\n');
|
||||
}
|
||||
command_result
|
||||
command(const std::string &cmd, got_line_cb got_line, uint32_t time_ms, const char separator) override;
|
||||
int write(uint8_t *data, size_t len) override
|
||||
{
|
||||
return dte->write(data, len);
|
||||
}
|
||||
void on_read(got_line_cb on_data) override
|
||||
{
|
||||
return dte->on_read(on_data);
|
||||
}
|
||||
// DECLARE_ALL_COMMAND_APIS(forwards name(...))
|
||||
/**
|
||||
* @brief Sends the initial AT sequence to sync up with the device
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_modem::command_result sync();
|
||||
/**
|
||||
* @brief Reads the operator name
|
||||
* @param[out] name operator name
|
||||
* @param[out] act access technology
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_modem::command_result get_operator_name(std::string &name, int &act);
|
||||
/**
|
||||
* @brief Stores current user profile
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_modem::command_result store_profile();
|
||||
/**
|
||||
* @brief Sets the supplied PIN code
|
||||
* @param[in] pin Pin
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_modem::command_result set_pin(const std::string &pin);
|
||||
/**
|
||||
* @brief Execute the supplied AT command in raw mode (doesn't append '\r' to command, returns everything)
|
||||
* @param[in] cmd String command that's send to DTE
|
||||
* @param[out] out Raw output from DTE
|
||||
* @param[in] pass Pattern in response for the API to return OK
|
||||
* @param[in] fail Pattern in response for the API to return FAIL
|
||||
* @param[in] timeout AT command timeout in milliseconds
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_modem::command_result at_raw(const std::string &cmd, std::string &out, const std::string &pass, const std::string &fail, int timeout);
|
||||
/**
|
||||
* @brief Execute the supplied AT command
|
||||
* @param[in] cmd AT command
|
||||
* @param[out] out Command output string
|
||||
* @param[in] timeout AT command timeout in milliseconds
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_modem::command_result at(const std::string &cmd, std::string &out, int timeout);
|
||||
/**
|
||||
* @brief Checks if the SIM needs a PIN
|
||||
* @param[out] pin_ok true if the SIM card doesn't need a PIN to unlock
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_modem::command_result read_pin(bool &pin_ok);
|
||||
/**
|
||||
* @brief Sets echo mode
|
||||
* @param[in] echo_on true if echo mode on (repeats the commands)
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_modem::command_result set_echo(const bool echo_on);
|
||||
/**
|
||||
* @brief Sets the Txt or Pdu mode for SMS (only txt is supported)
|
||||
* @param[in] txt true if txt mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_modem::command_result sms_txt_mode(const bool txt);
|
||||
/**
|
||||
* @brief Sets the default (GSM) character set
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_modem::command_result sms_character_set();
|
||||
/**
|
||||
* @brief Sends SMS message in txt mode
|
||||
* @param[in] number Phone number to send the message to
|
||||
* @param[in] message Text message to be sent
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_modem::command_result send_sms(const std::string &number, const std::string &message);
|
||||
/**
|
||||
* @brief Resumes data mode (Switches back to the data mode, which was temporarily suspended)
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_modem::command_result resume_data_mode();
|
||||
/**
|
||||
* @brief Sets php context
|
||||
* @param[in] p1 PdP context struct to setup modem cellular connection
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_modem::command_result set_pdp_context(PdpContext &pdp);
|
||||
/**
|
||||
* @brief Switches to the command mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_modem::command_result set_command_mode();
|
||||
/**
|
||||
* @brief Switches to the CMUX mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_modem::command_result set_cmux();
|
||||
/**
|
||||
* @brief Reads the IMSI number
|
||||
* @param[out] imsi Module's IMSI number
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_modem::command_result get_imsi(std::string &imsi);
|
||||
/**
|
||||
* @brief Reads the IMEI number
|
||||
* @param[out] imei Module's IMEI number
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_modem::command_result get_imei(std::string &imei);
|
||||
/**
|
||||
* @brief Reads the module name
|
||||
* @param[out] name module name
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_modem::command_result get_module_name(std::string &name);
|
||||
/**
|
||||
* @brief Sets the modem to data mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_modem::command_result set_data_mode();
|
||||
/**
|
||||
* @brief Get Signal quality
|
||||
* @param[out] rssi signal strength indication
|
||||
* @param[out] ber channel bit error rate
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_modem::command_result get_signal_quality(int &rssi, int &ber);
|
||||
/**
|
||||
* @brief Sets HW control flow
|
||||
* @param[in] dce_flow 0=none, 2=RTS hw flow control of DCE
|
||||
* @param[in] dte_flow 0=none, 2=CTS hw flow control of DTE
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_modem::command_result set_flow_control(int dce_flow, int dte_flow);
|
||||
/**
|
||||
* @brief Hangs up current data call
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_modem::command_result hang_up();
|
||||
/**
|
||||
* @brief Get voltage levels of modem power up circuitry
|
||||
* @param[out] voltage Current status in mV
|
||||
* @param[out] bcs charge status (-1-Not available, 0-Not charging, 1-Charging, 2-Charging done)
|
||||
* @param[out] bcl 1-100% battery capacity, -1-Not available
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_modem::command_result get_battery_status(int &voltage, int &bcs, int &bcl);
|
||||
/**
|
||||
* @brief Power down the module
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_modem::command_result power_down();
|
||||
/**
|
||||
* @brief Reset the module
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_modem::command_result reset();
|
||||
/**
|
||||
* @brief Configures the baudrate
|
||||
* @param[in] baud Desired baud rate of the DTE
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_modem::command_result set_baud(int baud);
|
||||
/**
|
||||
* @brief Force an attempt to connect to a specific operator
|
||||
* @param[in] mode mode of attempt
|
||||
* mode=0 - automatic
|
||||
* mode=1 - manual
|
||||
* mode=2 - deregister
|
||||
* mode=3 - set format for read operation
|
||||
* mode=4 - manual with fallback to automatic
|
||||
* @param[in] format what format the operator is given in
|
||||
* format=0 - long format
|
||||
* format=1 - short format
|
||||
* format=2 - numeric
|
||||
* @param[in] oper the operator to connect to
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_modem::command_result set_operator(int mode, int format, const std::string &oper);
|
||||
/**
|
||||
* @brief Attach or detach from the GPRS service
|
||||
* @param[in] state 1-attach 0-detach
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_modem::command_result set_network_attachment_state(int state);
|
||||
/**
|
||||
* @brief Get network attachment state
|
||||
* @param[out] state 1-attached 0-detached
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_modem::command_result get_network_attachment_state(int &state);
|
||||
/**
|
||||
* @brief What mode the radio should be set to
|
||||
* @param[in] state state 1-full 0-minimum ...
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_modem::command_result set_radio_state(int state);
|
||||
/**
|
||||
* @brief Get current radio state
|
||||
* @param[out] state 1-full 0-minimum ...
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_modem::command_result get_radio_state(int &state);
|
||||
/**
|
||||
* @brief Set network mode
|
||||
* @param[in] mode preferred mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_modem::command_result set_network_mode(int mode);
|
||||
/**
|
||||
* @brief Preferred network mode (CAT-M and/or NB-IoT)
|
||||
* @param[in] mode preferred selection
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_modem::command_result set_preferred_mode(int mode);
|
||||
/**
|
||||
* @brief Set network bands for CAT-M or NB-IoT
|
||||
* @param[in] mode CAT-M or NB-IoT
|
||||
* @param[in] bands bitmap in hex representing bands
|
||||
* @param[in] size size of teh bands bitmap
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_modem::command_result set_network_bands(const std::string &mode, const int *bands, int size);
|
||||
/**
|
||||
* @brief Show network system mode
|
||||
* @param[out] mode current network mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_modem::command_result get_network_system_mode(int &mode);
|
||||
/**
|
||||
* @brief GNSS power control
|
||||
* @param[out] mode power mode (0 - off, 1 - on)
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_modem::command_result set_gnss_power_mode(int mode);
|
||||
/**
|
||||
* @brief GNSS power control
|
||||
* @param[out] mode power mode (0 - off, 1 - on)
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_modem::command_result get_gnss_power_mode(int &mode);
|
||||
/**
|
||||
* @brief Configure PSM
|
||||
* @param[in] mode psm mode (0 - off, 1 - on, 2 - off & discard stored params)
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_modem::command_result config_psm(int mode, const std::string &tau, const std::string &active_time);
|
||||
/**
|
||||
* @brief Configure CEREG urc
|
||||
* @param[in] value
|
||||
* value = 0 - Disable network URC
|
||||
* value = 1 - Enable network URC
|
||||
* value = 2 - Enable network URC with location information
|
||||
* value = 3 - Enable network URC with location information and EMM cause
|
||||
* value = 4 - Enable network URC with location information and PSM value
|
||||
* value = 5 - Enable network URC with location information and PSM value, EMM cause
|
||||
*/
|
||||
esp_modem::command_result config_network_registration_urc(int value);
|
||||
/**
|
||||
* @brief Gets the current network registration state
|
||||
* @param[out] state The current network registration state
|
||||
* state = 0 - Not registered, MT is not currently searching an operator to register to
|
||||
* state = 1 - Registered, home network
|
||||
* state = 2 - Not registered, but MT is currently trying to attach or searching an operator to register to
|
||||
* state = 3 - Registration denied
|
||||
* state = 4 - Unknown
|
||||
* state = 5 - Registered, Roaming
|
||||
* state = 6 - Registered, for SMS only, home network (NB-IoT only)
|
||||
* state = 7 - Registered, for SMS only, roaming (NB-IoT only)
|
||||
* state = 8 - Attached for emergency bearer services only
|
||||
* state = 9 - Registered for CSFB not preferred, home network
|
||||
* state = 10 - Registered for CSFB not preferred, roaming
|
||||
*/
|
||||
esp_modem::command_result get_network_registration_state(int &state);
|
||||
/**
|
||||
* @brief Configures the mobile termination error (+CME ERROR)
|
||||
* @param[in] mode The form of the final result code
|
||||
* mode = 0 - Disable, use and send ERROR instead
|
||||
* mode = 1 - Enable, use numeric error values
|
||||
* mode = 2 - Enable, result code and use verbose error values
|
||||
*/
|
||||
esp_modem::command_result config_mobile_termination_error(int mode);
|
||||
/**
|
||||
* @brief Configure eDRX
|
||||
* @param[in] mode
|
||||
* mode = 0 - Disable
|
||||
* mode = 1 - Enable
|
||||
* mode = 2 - Enable + URC
|
||||
* mode = 3 - Disable + Reset parameter.
|
||||
* @param[in] access_technology
|
||||
* act = 0 - ACT is not using eDRX (used in URC)
|
||||
* act = 1 - EC-GSM-IoT (A/Gb mode)
|
||||
* act = 2 - GSM (A/Gb mode)
|
||||
* act = 3 - UTRAN (Iu mode)
|
||||
* act = 4 - E-UTRAN (WB-S1 mode)
|
||||
* act = 5 - E-UTRAN (NB-S1 mode)
|
||||
* @param[in] edrx_value nible string containing encoded eDRX time
|
||||
* @param[in] ptw_value nible string containing encoded Paging Time Window
|
||||
*/
|
||||
esp_modem::command_result config_edrx(int mode, int access_technology, const std::string &edrx_value);
|
||||
void set_on_read(esp_modem::got_line_cb on_read_cb)
|
||||
{
|
||||
if (on_read_cb == nullptr) {
|
||||
handling_urc = false;
|
||||
handle_urc = nullptr;
|
||||
dte->on_read(nullptr);
|
||||
return;
|
||||
}
|
||||
handle_urc = std::move(on_read_cb);
|
||||
dte->on_read([this](uint8_t *data, size_t len) {
|
||||
this->handle_data(data, len);
|
||||
return command_result::TIMEOUT;
|
||||
});
|
||||
handling_urc = true;
|
||||
}
|
||||
private:
|
||||
got_line_cb handle_urc{nullptr};
|
||||
got_line_cb handle_cmd{nullptr};
|
||||
SignalGroup signal;
|
||||
bool handling_urc {false};
|
||||
command_result handle_data(uint8_t *data, size_t len);
|
||||
};
|
||||
class Factory: public ::esp_modem::dce_factory::Factory {
|
||||
public:
|
||||
static std::unique_ptr<DCE> create(const esp_modem::dce_config *config,
|
||||
std::shared_ptr<esp_modem::DTE> dte,
|
||||
esp_netif_t *netif)
|
||||
{
|
||||
return build_generic_DCE<GenericModule, DCE, std::unique_ptr<DCE>>(config, std::move(dte), netif);
|
||||
}
|
||||
};
|
||||
} // namespace Shiny
|
||||
/**
|
||||
* @brief Helper create method which employs the DCE factory for creating DCE objects templated by a custom module
|
||||
* @return unique pointer of the resultant DCE
|
||||
*/
|
||||
std::unique_ptr<Shiny::DCE> create_shiny_dce(const esp_modem::dce_config *config,
|
||||
std::shared_ptr<esp_modem::DTE> dte,
|
||||
esp_netif_t *netif);
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
@ -15,43 +15,34 @@
|
||||
#include <cstring>
|
||||
#include "cxx_include/esp_modem_api.hpp"
|
||||
#include "cxx_include/esp_modem_dce_module.hpp"
|
||||
#include "generate/esp_modem_command_declare.inc"
|
||||
//#include "generate/esp_modem_command_declare.inc"
|
||||
#include "my_module_dce.hpp"
|
||||
|
||||
// --- ESP-MODEM command module starts here ---
|
||||
using namespace esp_modem;
|
||||
|
||||
//
|
||||
// Define preprocessor's forwarding to dce_commands definitions
|
||||
//
|
||||
|
||||
// Helper macros to handle multiple arguments of declared API
|
||||
#define ARGS0
|
||||
#define ARGS1 , p1
|
||||
#define ARGS2 , p1 , p2
|
||||
#define ARGS3 , p1 , p2 , p3
|
||||
#define ARGS4 , p1 , p2 , p3, p4
|
||||
#define ARGS5 , p1 , p2 , p3, p4, p5
|
||||
#define ARGS6 , p1 , p2 , p3, p4, p5, p6
|
||||
|
||||
#define _ARGS(x) ARGS ## x
|
||||
#define ARGS(x) _ARGS(x)
|
||||
|
||||
#define CMD_OK (1)
|
||||
#define CMD_FAIL (2)
|
||||
|
||||
//
|
||||
// Repeat all declarations and forward to the AT commands defined in esp_modem::dce_commands:: namespace
|
||||
//
|
||||
#define ESP_MODEM_DECLARE_DCE_COMMAND(name, return_type, arg_nr, ...) \
|
||||
return_type Shiny::DCE::name(__VA_ARGS__) { return esp_modem::dce_commands::name(this ARGS(arg_nr) ); }
|
||||
#include "esp_modem_command_declare_helper.inc"
|
||||
#define ESP_MODEM_DECLARE_DCE_COMMAND(name, return_type, ...) \
|
||||
return_type Shiny::DCE::name(ESP_MODEM_COMMAND_PARAMS(__VA_ARGS__)) { return esp_modem::dce_commands::name(this ESP_MODEM_COMMAND_FORWARD_AFTER(__VA_ARGS__) ); }
|
||||
|
||||
DECLARE_ALL_COMMAND_APIS(return_type name(...) )
|
||||
//DECLARE_ALL_COMMAND_APIS(return_type name(...) )
|
||||
#include "esp_modem_command_declare.inc"
|
||||
|
||||
#undef ESP_MODEM_DECLARE_DCE_COMMAND
|
||||
|
||||
std::unique_ptr<Shiny::DCE> create_shiny_dce(const esp_modem::dce_config *config,
|
||||
std::shared_ptr<esp_modem::DTE> dte,
|
||||
esp_netif_t *netif)
|
||||
std::shared_ptr<esp_modem::DTE> dte,
|
||||
esp_netif_t *netif)
|
||||
{
|
||||
return Shiny::Factory::create(config, std::move(dte), netif);
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
@ -16,6 +16,7 @@
|
||||
#include "cxx_include/esp_modem_dce_factory.hpp"
|
||||
#include "cxx_include/esp_modem_dce_module.hpp"
|
||||
|
||||
// --- ESP-MODEM command module starts here ---
|
||||
/**
|
||||
* @brief Definition of a custom DCE uses GenericModule and all its methods
|
||||
* but could override command processing. Here, for demonstration purposes only,
|
||||
@ -51,10 +52,12 @@ public:
|
||||
return dte->on_read(on_data);
|
||||
}
|
||||
|
||||
#define ESP_MODEM_DECLARE_DCE_COMMAND(name, return_type, num, ...) \
|
||||
esp_modem::return_type name(__VA_ARGS__);
|
||||
#include "../generate/include/esp_modem_command_declare_helper.inc"
|
||||
#define ESP_MODEM_DECLARE_DCE_COMMAND(name, return_type, ...) \
|
||||
esp_modem::return_type name(ESP_MODEM_COMMAND_PARAMS(__VA_ARGS__));
|
||||
|
||||
DECLARE_ALL_COMMAND_APIS(forwards name(...))
|
||||
// DECLARE_ALL_COMMAND_APIS(forwards name(...))
|
||||
#include "../generate/include/esp_modem_command_declare.inc"
|
||||
|
||||
#undef ESP_MODEM_DECLARE_DCE_COMMAND
|
||||
|
||||
@ -103,5 +106,5 @@ public:
|
||||
* @return unique pointer of the resultant DCE
|
||||
*/
|
||||
std::unique_ptr<Shiny::DCE> create_shiny_dce(const esp_modem::dce_config *config,
|
||||
std::shared_ptr<esp_modem::DTE> dte,
|
||||
esp_netif_t *netif);
|
||||
std::shared_ptr<esp_modem::DTE> dte,
|
||||
esp_netif_t *netif);
|
@ -362,7 +362,8 @@ extern "C" void app_main(void)
|
||||
});
|
||||
const ConsoleCommand GetBatteryStatus("get_battery_status", "Reads voltage/battery status", no_args, [&](ConsoleCommand * c) {
|
||||
int volt, bcl, bcs;
|
||||
CHECK_ERR(dce->get_battery_status(volt, bcl, bcs), ESP_LOGI(TAG, "OK. volt=%d, bcl=%d, bcs=%d", volt, bcl, bcs));
|
||||
CHECK_ERR(dce->get_module()->get_battery_status(volt, bcl, bcs), ESP_LOGI(TAG, "OK. volt=%d, bcl=%d, bcs=%d", volt, bcl, bcs));
|
||||
dce->get_battery_status(volt, bcl, bcs);
|
||||
});
|
||||
const ConsoleCommand PowerDown("power_down", "power down the module", no_args, [&](ConsoleCommand * c) {
|
||||
ESP_LOGI(TAG, "Power down the module...");
|
||||
|
@ -4,8 +4,14 @@ elseif(CONFIG_EXAMPLE_MODEM_DEVICE_SIM7600)
|
||||
set(device_srcs sock_commands_sim7600.cpp)
|
||||
endif()
|
||||
|
||||
if(CONFIG_ESP_MODEM_ENABLE_DEVELOPMENT_MODE)
|
||||
set(command_dir "generate")
|
||||
else()
|
||||
set(command_dir "command")
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS "modem_client.cpp"
|
||||
"sock_dce.cpp"
|
||||
"${command_dir}/sock_dce.cpp"
|
||||
"tcp_transport_at.cpp"
|
||||
"${device_srcs}"
|
||||
INCLUDE_DIRS ".")
|
||||
INCLUDE_DIRS "." "${command_dir}")
|
||||
|
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cxx_include/esp_modem_dte.hpp"
|
||||
#include "cxx_include/esp_modem_dce_module.hpp"
|
||||
#include "cxx_include/esp_modem_types.hpp"
|
||||
|
||||
|
||||
namespace sock_commands {
|
||||
|
||||
/**
|
||||
* @brief Opens network in AT command mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_modem::command_result net_open(esp_modem::CommandableIf *t);
|
||||
/**
|
||||
* @brief Closes network in AT command mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_modem::command_result net_close(esp_modem::CommandableIf *t);
|
||||
/**
|
||||
* @brief Opens a TCP connection
|
||||
* @param[in] host Host name or IP address to connect to
|
||||
* @param[in] port Port number
|
||||
* @param[in] timeout Connection timeout
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_modem::command_result tcp_open(esp_modem::CommandableIf *t, const std::string &host, int port, int timeout);
|
||||
/**
|
||||
* @brief Closes opened TCP socket
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_modem::command_result tcp_close(esp_modem::CommandableIf *t);
|
||||
/**
|
||||
* @brief Gets modem IP address
|
||||
* @param[out] addr String representation of modem's IP
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_modem::command_result get_ip(esp_modem::CommandableIf *t, std::string &addr);
|
||||
/**
|
||||
* @brief Sets Rx mode
|
||||
* @param[in] mode 0=auto, 1=manual
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_modem::command_result set_rx_mode(esp_modem::CommandableIf *t, int mode);
|
||||
}
|
@ -0,0 +1,361 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <charconv>
|
||||
#include <sys/socket.h>
|
||||
#include "esp_vfs.h"
|
||||
#include "esp_vfs_eventfd.h"
|
||||
|
||||
#include "sock_dce.hpp"
|
||||
|
||||
namespace sock_dce {
|
||||
|
||||
constexpr auto const *TAG = "sock_dce";
|
||||
|
||||
|
||||
bool DCE::perform_sock()
|
||||
{
|
||||
if (listen_sock == -1) {
|
||||
ESP_LOGE(TAG, "Listening socket not ready");
|
||||
close_sock();
|
||||
return false;
|
||||
}
|
||||
if (sock == -1) { // no active socket, need to accept one first
|
||||
return accept_sock();
|
||||
}
|
||||
|
||||
// we have a socket, let's check the status
|
||||
struct timeval tv = {
|
||||
.tv_sec = 0,
|
||||
.tv_usec = 500000,
|
||||
};
|
||||
if (state == status::PENDING) {
|
||||
vTaskDelay(pdMS_TO_TICKS(500));
|
||||
state = at.pending();
|
||||
return true;
|
||||
}
|
||||
fd_set fdset;
|
||||
FD_ZERO(&fdset);
|
||||
FD_SET(sock, &fdset);
|
||||
FD_SET(data_ready_fd, &fdset);
|
||||
int s = select(std::max(sock, data_ready_fd) + 1, &fdset, nullptr, nullptr, &tv);
|
||||
if (s == 0) {
|
||||
ESP_LOGV(TAG, "perform select timeout...");
|
||||
return true;
|
||||
} else if (s < 0) {
|
||||
ESP_LOGE(TAG, "select error %d", errno);
|
||||
close_sock();
|
||||
return false;
|
||||
}
|
||||
if (FD_ISSET(sock, &fdset) && !sock_to_at()) {
|
||||
return false;
|
||||
}
|
||||
if (FD_ISSET(data_ready_fd, &fdset) && !at_to_sock()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void DCE::perform_at(uint8_t *data, size_t len)
|
||||
{
|
||||
ESP_LOG_BUFFER_HEXDUMP(TAG, data, len, ESP_LOG_VERBOSE);
|
||||
switch (at.process_data(state, data, len)) {
|
||||
case Responder::ret::OK:
|
||||
state = status::IDLE;
|
||||
signal.set(IDLE);
|
||||
return;
|
||||
case Responder::ret::FAIL:
|
||||
state = status::FAILED;
|
||||
signal.set(IDLE);
|
||||
return;
|
||||
case Responder::ret::NEED_MORE_DATA:
|
||||
return;
|
||||
case Responder::ret::IN_PROGRESS:
|
||||
break;
|
||||
case Responder::ret::NEED_MORE_TIME:
|
||||
state = status::PENDING;
|
||||
return;
|
||||
}
|
||||
std::string_view response((char *)data, len);
|
||||
switch (at.check_async_replies(state, response)) {
|
||||
case Responder::ret::OK:
|
||||
state = status::IDLE;
|
||||
signal.set(IDLE);
|
||||
return;
|
||||
case Responder::ret::FAIL:
|
||||
state = status::FAILED;
|
||||
signal.set(IDLE);
|
||||
return;
|
||||
case Responder::ret::NEED_MORE_TIME:
|
||||
state = status::PENDING;
|
||||
return;
|
||||
case Responder::ret::NEED_MORE_DATA:
|
||||
case Responder::ret::IN_PROGRESS:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void DCE::close_sock()
|
||||
{
|
||||
if (sock > 0) {
|
||||
close(sock);
|
||||
sock = -1;
|
||||
}
|
||||
dte->on_read(nullptr);
|
||||
const int retries = 5;
|
||||
int i = 0;
|
||||
while (net_close() != esp_modem::command_result::OK) {
|
||||
if (i++ > retries) {
|
||||
ESP_LOGE(TAG, "Failed to close network");
|
||||
return;
|
||||
}
|
||||
esp_modem::Task::Delay(1000);
|
||||
}
|
||||
}
|
||||
|
||||
bool DCE::at_to_sock()
|
||||
{
|
||||
uint64_t data;
|
||||
read(data_ready_fd, &data, sizeof(data));
|
||||
ESP_LOGD(TAG, "select read: modem data available %" PRIu64, data);
|
||||
if (!signal.wait(IDLE, 1000)) {
|
||||
ESP_LOGE(TAG, "Failed to get idle");
|
||||
close_sock();
|
||||
return false;
|
||||
}
|
||||
if (state != status::IDLE) {
|
||||
ESP_LOGE(TAG, "Unexpected state %d", static_cast<int>(state));
|
||||
close_sock();
|
||||
return false;
|
||||
}
|
||||
state = status::RECEIVING;
|
||||
at.start_receiving(at.get_buf_len());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DCE::sock_to_at()
|
||||
{
|
||||
ESP_LOGD(TAG, "socket read: data available");
|
||||
if (!signal.wait(IDLE, 1000)) {
|
||||
ESP_LOGE(TAG, "Failed to get idle");
|
||||
close_sock();
|
||||
return false;
|
||||
}
|
||||
if (state != status::IDLE) {
|
||||
ESP_LOGE(TAG, "Unexpected state %d", static_cast<int>(state));
|
||||
close_sock();
|
||||
return false;
|
||||
}
|
||||
state = status::SENDING;
|
||||
int len = ::recv(sock, at.get_buf(), at.get_buf_len(), 0);
|
||||
if (len < 0) {
|
||||
ESP_LOGE(TAG, "read error %d", errno);
|
||||
close_sock();
|
||||
return false;
|
||||
} else if (len == 0) {
|
||||
ESP_LOGE(TAG, "EOF %d", errno);
|
||||
close_sock();
|
||||
return false;
|
||||
}
|
||||
ESP_LOG_BUFFER_HEXDUMP(TAG, at.get_buf(), len, ESP_LOG_VERBOSE);
|
||||
at.start_sending(len);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DCE::accept_sock()
|
||||
{
|
||||
struct timeval tv = {
|
||||
.tv_sec = 0,
|
||||
.tv_usec = 500000,
|
||||
};
|
||||
fd_set fdset;
|
||||
FD_ZERO(&fdset);
|
||||
FD_SET(listen_sock, &fdset);
|
||||
int s = select(listen_sock + 1, &fdset, nullptr, nullptr, &tv);
|
||||
if (s > 0 && FD_ISSET(listen_sock, &fdset)) {
|
||||
struct sockaddr_in source_addr = {};
|
||||
socklen_t addr_len = sizeof(source_addr);
|
||||
sock = accept(listen_sock, (struct sockaddr *)&source_addr, &addr_len);
|
||||
if (sock < 0) {
|
||||
ESP_LOGE(TAG, "Unable to accept connection: errno %d", errno);
|
||||
return false;
|
||||
}
|
||||
ESP_LOGD(TAG, "Socket accepted!");
|
||||
FD_ZERO(&fdset);
|
||||
return true;
|
||||
} else if (s == 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DCE::start_listening(int port)
|
||||
{
|
||||
listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
|
||||
if (listen_sock < 0) {
|
||||
ESP_LOGE(TAG, "Unable to create socket: errno %d", errno);
|
||||
return;
|
||||
}
|
||||
int opt = 1;
|
||||
setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
|
||||
ESP_LOGI(TAG, "Socket created");
|
||||
struct sockaddr_in addr = { };
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(port);
|
||||
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
// inet_aton("127.0.0.1", &addr.sin_addr);
|
||||
|
||||
int err = bind(listen_sock, (struct sockaddr *)&addr, sizeof(addr));
|
||||
if (err != 0) {
|
||||
ESP_LOGE(TAG, "Socket unable to bind: errno %d", errno);
|
||||
return;
|
||||
}
|
||||
ESP_LOGI(TAG, "Socket bound, port %d", 1883);
|
||||
err = listen(listen_sock, 1);
|
||||
if (err != 0) {
|
||||
ESP_LOGE(TAG, "Error occurred during listen: errno %d", errno);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool DCE::connect(std::string host, int port)
|
||||
{
|
||||
dte->on_read(nullptr);
|
||||
tcp_close();
|
||||
dte->on_read([this](uint8_t *data, size_t len) {
|
||||
this->perform_at(data, len);
|
||||
return esp_modem::command_result::TIMEOUT;
|
||||
});
|
||||
if (!at.start_connecting(host, port)) {
|
||||
ESP_LOGE(TAG, "Unable to start connecting");
|
||||
dte->on_read(nullptr);
|
||||
return false;
|
||||
}
|
||||
state = status::CONNECTING;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DCE::init()
|
||||
{
|
||||
esp_vfs_eventfd_config_t config = ESP_VFS_EVENTD_CONFIG_DEFAULT();
|
||||
esp_vfs_eventfd_register(&config);
|
||||
|
||||
data_ready_fd = eventfd(0, EFD_SUPPORT_ISR);
|
||||
assert(data_ready_fd > 0);
|
||||
|
||||
dte->on_read(nullptr);
|
||||
const int retries = 5;
|
||||
int i = 0;
|
||||
while (sync() != esp_modem::command_result::OK) {
|
||||
if (i++ > retries) {
|
||||
ESP_LOGE(TAG, "Failed to sync up");
|
||||
return false;
|
||||
}
|
||||
esp_modem::Task::Delay(1000);
|
||||
}
|
||||
ESP_LOGD(TAG, "Modem in sync");
|
||||
i = 0;
|
||||
while (setup_data_mode() != true) {
|
||||
if (i++ > retries) {
|
||||
ESP_LOGE(TAG, "Failed to setup pdp/data");
|
||||
return false;
|
||||
}
|
||||
esp_modem::Task::Delay(1000);
|
||||
}
|
||||
ESP_LOGD(TAG, "PDP configured");
|
||||
i = 0;
|
||||
while (net_open() != esp_modem::command_result::OK) {
|
||||
if (i++ > retries) {
|
||||
ESP_LOGE(TAG, "Failed to open network");
|
||||
return false;
|
||||
}
|
||||
net_close();
|
||||
esp_modem::Task::Delay(1000);
|
||||
}
|
||||
ESP_LOGD(TAG, "Network opened");
|
||||
i = 0;
|
||||
std::string ip_addr;
|
||||
while (get_ip(ip_addr) != esp_modem::command_result::OK) {
|
||||
if (i++ > retries) {
|
||||
ESP_LOGE(TAG, "Failed obtain an IP address");
|
||||
return false;
|
||||
}
|
||||
esp_modem::Task::Delay(5000);
|
||||
}
|
||||
ESP_LOGI(TAG, "Got IP %s", ip_addr.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
class Factory: public ::esp_modem::dce_factory::Factory {
|
||||
public:
|
||||
static std::unique_ptr<DCE> create(const esp_modem::dce_config *config, std::shared_ptr<esp_modem::DTE> dte)
|
||||
{
|
||||
return esp_modem::dce_factory::Factory::build_module_T<DCE, std::unique_ptr<DCE>>(config, std::move(dte));
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<DCE> create(const esp_modem::dce_config *config, std::shared_ptr<esp_modem::DTE> dte)
|
||||
{
|
||||
return Factory::create(config, std::move(dte));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Opens network in AT command mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_modem::command_result DCE::net_open()
|
||||
{
|
||||
return sock_commands::net_open(dte.get());
|
||||
}
|
||||
/**
|
||||
* @brief Closes network in AT command mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_modem::command_result DCE::net_close()
|
||||
{
|
||||
return sock_commands::net_close(dte.get());
|
||||
}
|
||||
/**
|
||||
* @brief Opens a TCP connection
|
||||
* @param[in] host Host name or IP address to connect to
|
||||
* @param[in] port Port number
|
||||
* @param[in] timeout Connection timeout
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_modem::command_result DCE::tcp_open(const std::string &host, int port, int timeout)
|
||||
{
|
||||
return sock_commands::tcp_open(dte.get(), host, port, timeout);
|
||||
}
|
||||
/**
|
||||
* @brief Closes opened TCP socket
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_modem::command_result DCE::tcp_close()
|
||||
{
|
||||
return sock_commands::tcp_close(dte.get());
|
||||
}
|
||||
/**
|
||||
* @brief Gets modem IP address
|
||||
* @param[out] addr String representation of modem's IP
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_modem::command_result DCE::get_ip(std::string &addr)
|
||||
{
|
||||
return sock_commands::get_ip(dte.get(), addr);
|
||||
}
|
||||
/**
|
||||
* @brief Sets Rx mode
|
||||
* @param[in] mode 0=auto, 1=manual
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_modem::command_result DCE::set_rx_mode(int mode)
|
||||
{
|
||||
return sock_commands::set_rx_mode(dte.get(), mode);
|
||||
}
|
||||
} // namespace sock_dce
|
@ -0,0 +1,241 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "esp_modem_config.h"
|
||||
#include "cxx_include/esp_modem_api.hpp"
|
||||
#include <cxx_include/esp_modem_dce_factory.hpp>
|
||||
#include "sock_commands.hpp"
|
||||
#include <sys/socket.h>
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace sock_dce {
|
||||
|
||||
|
||||
enum class status {
|
||||
IDLE,
|
||||
CONNECTING,
|
||||
SENDING,
|
||||
RECEIVING,
|
||||
FAILED,
|
||||
PENDING
|
||||
};
|
||||
|
||||
class Responder {
|
||||
public:
|
||||
enum class ret {
|
||||
OK, FAIL, IN_PROGRESS, NEED_MORE_DATA, NEED_MORE_TIME
|
||||
};
|
||||
Responder(int &s, int &ready_fd, std::shared_ptr<esp_modem::DTE> &dte_arg):
|
||||
sock(s), data_ready_fd(ready_fd), dte(dte_arg) {}
|
||||
ret process_data(status state, uint8_t *data, size_t len);
|
||||
ret check_async_replies(status state, std::string_view &response);
|
||||
|
||||
void start_sending(size_t len);
|
||||
void start_receiving(size_t len);
|
||||
bool start_connecting(std::string host, int port);
|
||||
status pending();
|
||||
uint8_t *get_buf()
|
||||
{
|
||||
return &buffer[0];
|
||||
}
|
||||
size_t get_buf_len()
|
||||
{
|
||||
return buffer_size;
|
||||
}
|
||||
|
||||
void clear_offsets()
|
||||
{
|
||||
actual_read = 0;
|
||||
}
|
||||
|
||||
size_t data_available()
|
||||
{
|
||||
return actual_read;
|
||||
}
|
||||
|
||||
size_t has_data()
|
||||
{
|
||||
return total_len;
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr size_t buffer_size = 512;
|
||||
|
||||
bool on_read(char *data, size_t len)
|
||||
{
|
||||
#ifndef CONFIG_EXAMPLE_CUSTOM_TCP_TRANSPORT
|
||||
::send(sock, data, len, 0);
|
||||
#else
|
||||
::memcpy(&buffer[actual_read], data, len);
|
||||
actual_read += len;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
ret recv(uint8_t *data, size_t len);
|
||||
ret send(uint8_t *data, size_t len);
|
||||
ret send(std::string_view response);
|
||||
ret connect(std::string_view response);
|
||||
void send_cmd(std::string_view command)
|
||||
{
|
||||
dte->write((uint8_t *) command.begin(), command.size());
|
||||
}
|
||||
std::array<uint8_t, buffer_size> buffer;
|
||||
size_t data_to_recv = 0;
|
||||
size_t actual_read = 0;
|
||||
size_t total_len = 0;
|
||||
|
||||
bool read_again = false;
|
||||
int &sock;
|
||||
int &data_ready_fd;
|
||||
int send_stat = 0;
|
||||
size_t data_to_send = 0;
|
||||
std::shared_ptr<esp_modem::DTE> &dte;
|
||||
};
|
||||
|
||||
class DCE : public ::esp_modem::GenericModule {
|
||||
using esp_modem::GenericModule::GenericModule;
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Opens network in AT command mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_modem::command_result net_open();
|
||||
/**
|
||||
* @brief Closes network in AT command mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_modem::command_result net_close();
|
||||
/**
|
||||
* @brief Opens a TCP connection
|
||||
* @param[in] host Host name or IP address to connect to
|
||||
* @param[in] port Port number
|
||||
* @param[in] timeout Connection timeout
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_modem::command_result tcp_open(const std::string &host, int port, int timeout);
|
||||
/**
|
||||
* @brief Closes opened TCP socket
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_modem::command_result tcp_close();
|
||||
/**
|
||||
* @brief Gets modem IP address
|
||||
* @param[out] addr String representation of modem's IP
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_modem::command_result get_ip(std::string &addr);
|
||||
/**
|
||||
* @brief Sets Rx mode
|
||||
* @param[in] mode 0=auto, 1=manual
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
esp_modem::command_result set_rx_mode(int mode);
|
||||
bool init();
|
||||
bool connect(std::string host, int port);
|
||||
void start_listening(int port);
|
||||
bool perform_sock();
|
||||
void set_idle()
|
||||
{
|
||||
signal.set(IDLE);
|
||||
}
|
||||
bool wait_to_idle(uint32_t ms)
|
||||
{
|
||||
if (!signal.wait(IDLE, ms)) {
|
||||
ESP_LOGE("dce", "Failed to get idle");
|
||||
return false;
|
||||
}
|
||||
if (state != status::IDLE) {
|
||||
ESP_LOGE("dce", "Unexpected state %d", static_cast<int>(state));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
int sync_recv(char *buffer, int len, int timeout_ms)
|
||||
{
|
||||
if (!wait_to_idle(timeout_ms)) {
|
||||
return 0;
|
||||
}
|
||||
at.clear_offsets();
|
||||
state = status::RECEIVING;
|
||||
uint64_t data;
|
||||
read(data_ready_fd, &data, sizeof(data));
|
||||
int max_len = std::min(len, (int)at.get_buf_len());
|
||||
at.start_receiving(max_len);
|
||||
if (!signal.wait(IDLE, 500 + timeout_ms)) {
|
||||
return 0;
|
||||
}
|
||||
int ret = at.data_available();
|
||||
if (ret > 0) {
|
||||
memcpy(buffer, at.get_buf(), ret);
|
||||
}
|
||||
set_idle();
|
||||
return ret;
|
||||
}
|
||||
int sync_send(const char *buffer, size_t len, int timeout_ms)
|
||||
{
|
||||
int len_to_send = std::min(len, at.get_buf_len());
|
||||
if (!wait_to_idle(timeout_ms)) {
|
||||
return -1;
|
||||
}
|
||||
state = status::SENDING;
|
||||
memcpy(at.get_buf(), buffer, len_to_send);
|
||||
ESP_LOG_BUFFER_HEXDUMP("dce", at.get_buf(), len, ESP_LOG_VERBOSE);
|
||||
at.start_sending(len_to_send);
|
||||
if (!signal.wait(IDLE, timeout_ms + 1000)) {
|
||||
if (state == status::PENDING) {
|
||||
state = status::IDLE;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
set_idle();
|
||||
return len_to_send;
|
||||
}
|
||||
int wait_to_read(uint32_t ms)
|
||||
{
|
||||
if (at.has_data() > 0) {
|
||||
ESP_LOGD("dce", "Data buffered in modem (len=%d)", at.has_data());
|
||||
return 1;
|
||||
}
|
||||
struct timeval tv = {
|
||||
.tv_sec = static_cast<time_t>(ms / 1000),
|
||||
.tv_usec = 0,
|
||||
};
|
||||
fd_set fdset;
|
||||
FD_ZERO(&fdset);
|
||||
FD_SET(data_ready_fd, &fdset);
|
||||
int s = select(data_ready_fd + 1, &fdset, nullptr, nullptr, &tv);
|
||||
if (s == 0) {
|
||||
return 0;
|
||||
} else if (s < 0) {
|
||||
ESP_LOGE("dce", "select error %d", errno);
|
||||
return -1;
|
||||
}
|
||||
if (FD_ISSET(data_ready_fd, &fdset)) {
|
||||
ESP_LOGD("dce", "select read: modem data available");
|
||||
return 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
private:
|
||||
esp_modem::SignalGroup signal;
|
||||
void close_sock();
|
||||
bool accept_sock();
|
||||
bool sock_to_at();
|
||||
bool at_to_sock();
|
||||
void perform_at(uint8_t *data, size_t len);
|
||||
status state{status::IDLE};
|
||||
static constexpr uint8_t IDLE = 1;
|
||||
Responder at{sock, data_ready_fd, dte};
|
||||
int sock {-1};
|
||||
int listen_sock {-1};
|
||||
int data_ready_fd {-1};
|
||||
};
|
||||
std::unique_ptr<DCE> create(const esp_modem::dce_config *config, std::shared_ptr<esp_modem::DTE> dte);
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cxx_include/esp_modem_dte.hpp"
|
||||
#include "cxx_include/esp_modem_dce_module.hpp"
|
||||
#include "cxx_include/esp_modem_types.hpp"
|
||||
|
||||
|
||||
namespace sock_commands {
|
||||
|
||||
// --- ESP-MODEM command module starts here ---
|
||||
#include "esp_modem_command_declare_helper.inc"
|
||||
#define ESP_MODEM_DECLARE_DCE_COMMAND(name, return_type, ...) \
|
||||
esp_modem::return_type name(esp_modem::CommandableIf *t ESP_MODEM_COMMAND_PARAMS_AFTER(__VA_ARGS__));
|
||||
|
||||
#include "socket_commands.inc"
|
||||
#undef ESP_MODEM_DECLARE_DCE_COMMAND
|
||||
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -304,23 +304,13 @@ std::unique_ptr<DCE> create(const esp_modem::dce_config *config, std::shared_ptr
|
||||
return Factory::create(config, std::move(dte));
|
||||
}
|
||||
|
||||
// Helper macros to handle multiple arguments of declared API
|
||||
#define ARGS0
|
||||
#define ARGS1 , p1
|
||||
#define ARGS2 , p1 , p2
|
||||
#define ARGS3 , p1 , p2 , p3
|
||||
|
||||
#define EXPAND_ARGS(x) ARGS ## x
|
||||
#define ARGS(x) EXPAND_ARGS(x)
|
||||
|
||||
//
|
||||
// Repeat all declarations and forward to the AT commands defined in ::sock_commands namespace
|
||||
//
|
||||
#define ESP_MODEM_DECLARE_DCE_COMMAND(name, return_type, arg_nr, ...) \
|
||||
esp_modem::return_type DCE::name(__VA_ARGS__) { return sock_commands::name(dte.get() ARGS(arg_nr) ); }
|
||||
|
||||
DECLARE_SOCK_COMMANDS(return_type name(...) )
|
||||
// --- ESP-MODEM command module starts here ---
|
||||
#include "esp_modem_command_declare_helper.inc"
|
||||
#define ESP_MODEM_DECLARE_DCE_COMMAND(name, return_type, ...) \
|
||||
esp_modem::return_type DCE::name(ESP_MODEM_COMMAND_PARAMS(__VA_ARGS__)) { return sock_commands::name(dte.get() ESP_MODEM_COMMAND_FORWARD_AFTER(__VA_ARGS__) ); }
|
||||
|
||||
#include "socket_commands.inc"
|
||||
#undef ESP_MODEM_DECLARE_DCE_COMMAND
|
||||
|
||||
} // namespace sock_dce
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -7,7 +7,6 @@
|
||||
#include "esp_modem_config.h"
|
||||
#include "cxx_include/esp_modem_api.hpp"
|
||||
#include <cxx_include/esp_modem_dce_factory.hpp>
|
||||
#include "socket_commands.inc"
|
||||
#include "sock_commands.hpp"
|
||||
#include <sys/socket.h>
|
||||
|
||||
@ -102,11 +101,12 @@ class DCE : public ::esp_modem::GenericModule {
|
||||
using esp_modem::GenericModule::GenericModule;
|
||||
public:
|
||||
|
||||
#define ESP_MODEM_DECLARE_DCE_COMMAND(name, return_type, num, ...) \
|
||||
esp_modem::return_type name(__VA_ARGS__);
|
||||
|
||||
DECLARE_SOCK_COMMANDS(declare name(Commandable *p, ...);)
|
||||
// --- ESP-MODEM command module starts here ---
|
||||
#include "esp_modem_command_declare_helper.inc"
|
||||
#define ESP_MODEM_DECLARE_DCE_COMMAND(name, return_type, ...) \
|
||||
esp_modem::return_type name(ESP_MODEM_COMMAND_PARAMS(__VA_ARGS__));
|
||||
|
||||
#include "socket_commands.inc"
|
||||
#undef ESP_MODEM_DECLARE_DCE_COMMAND
|
||||
|
||||
bool init();
|
@ -0,0 +1,40 @@
|
||||
/**
|
||||
* @brief Opens network in AT command mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
ESP_MODEM_DECLARE_DCE_COMMAND(net_open, command_result)
|
||||
|
||||
/**
|
||||
* @brief Closes network in AT command mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
ESP_MODEM_DECLARE_DCE_COMMAND(net_close, command_result)
|
||||
|
||||
/**
|
||||
* @brief Opens a TCP connection
|
||||
* @param[in] host Host name or IP address to connect to
|
||||
* @param[in] port Port number
|
||||
* @param[in] timeout Connection timeout
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
ESP_MODEM_DECLARE_DCE_COMMAND(tcp_open, command_result, STR_IN(host), INT_IN(port), INT_IN(timeout))
|
||||
|
||||
/**
|
||||
* @brief Closes opened TCP socket
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
ESP_MODEM_DECLARE_DCE_COMMAND(tcp_close, command_result)
|
||||
|
||||
/**
|
||||
* @brief Gets modem IP address
|
||||
* @param[out] addr String representation of modem's IP
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
ESP_MODEM_DECLARE_DCE_COMMAND(get_ip, command_result, STR_OUT(addr))
|
||||
|
||||
/**
|
||||
* @brief Sets Rx mode
|
||||
* @param[in] mode 0=auto, 1=manual
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/
|
||||
ESP_MODEM_DECLARE_DCE_COMMAND(set_rx_mode, command_result, INT_IN(mode))
|
@ -1,23 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cxx_include/esp_modem_dte.hpp"
|
||||
#include "cxx_include/esp_modem_dce_module.hpp"
|
||||
#include "cxx_include/esp_modem_types.hpp"
|
||||
#include "socket_commands.inc"
|
||||
|
||||
namespace sock_commands {
|
||||
|
||||
#define ESP_MODEM_DECLARE_DCE_COMMAND(name, return_type, num, ...) \
|
||||
esp_modem::return_type name(esp_modem::CommandableIf *t, ## __VA_ARGS__);
|
||||
|
||||
DECLARE_SOCK_COMMANDS(declare name(Commandable *p, ...);)
|
||||
|
||||
#undef ESP_MODEM_DECLARE_DCE_COMMAND
|
||||
|
||||
}
|
@ -1,58 +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 "generate/esp_modem_command_declare_helper.inc"
|
||||
|
||||
#define DECLARE_SOCK_COMMANDS(...) \
|
||||
/**
|
||||
* @brief Opens network in AT command mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ \
|
||||
ESP_MODEM_DECLARE_DCE_COMMAND(net_open, command_result, 0) \
|
||||
\
|
||||
/**
|
||||
* @brief Closes network in AT command mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ \
|
||||
ESP_MODEM_DECLARE_DCE_COMMAND(net_close, command_result, 0) \
|
||||
\
|
||||
/**
|
||||
* @brief Opens a TCP connection
|
||||
* @param[in] host Host name or IP address to connect to
|
||||
* @param[in] port Port number
|
||||
* @param[in] timeout Connection timeout
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ \
|
||||
ESP_MODEM_DECLARE_DCE_COMMAND(tcp_open, command_result, 3, STRING_IN(p1, host), INT_IN(p2, port), INT_IN(p3, timeout)) \
|
||||
\
|
||||
/**
|
||||
* @brief Closes opened TCP socket
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ \
|
||||
ESP_MODEM_DECLARE_DCE_COMMAND(tcp_close, command_result, 0) \
|
||||
\
|
||||
/**
|
||||
* @brief Gets modem IP address
|
||||
* @param[out] addr String representation of modem's IP
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ \
|
||||
ESP_MODEM_DECLARE_DCE_COMMAND(get_ip, command_result, 1, STRING_OUT(p1, addr)) \
|
||||
\
|
||||
/**
|
||||
* @brief Sets Rx mode
|
||||
* @param[in] mode 0=auto, 1=manual
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ \
|
||||
ESP_MODEM_DECLARE_DCE_COMMAND(set_rx_mode, command_result, 1, INT_IN(p1, mode))
|
@ -1,5 +1,11 @@
|
||||
if(CONFIG_ESP_MODEM_ENABLE_DEVELOPMENT_MODE)
|
||||
set(command_dir "generate")
|
||||
else()
|
||||
set(command_dir "command")
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS "SIM7070_gnss.cpp"
|
||||
INCLUDE_DIRS "."
|
||||
INCLUDE_DIRS "." "${command_dir}"
|
||||
PRIV_REQUIRES esp_modem)
|
||||
|
||||
set_target_properties(${COMPONENT_LIB} PROPERTIES
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user