forked from espressif/esp-protocols
Compare commits
97 Commits
modem-v1.0
...
websocket-
Author | SHA1 | Date | |
---|---|---|---|
7e83741615 | |||
b880fc0367 | |||
f6d5186e5b | |||
8eb3a0feea | |||
28cd898eca | |||
f5a0d5fb40 | |||
ecc465daa3 | |||
181b6e4013 | |||
40e3875f76 | |||
ddc3eb62d0 | |||
3625889049 | |||
2bd6163ec8 | |||
f1eb46580e | |||
1c20328dcf | |||
6de22f3893 | |||
e280b3b541 | |||
00d7c40848 | |||
4f1769ec71 | |||
20dd910b3a | |||
3635e2fabc | |||
84035d8f3b | |||
e620eb5fb1 | |||
7d4755f119 | |||
588465d9db | |||
c443326a34 | |||
79a0e57ca1 | |||
68392f0ba9 | |||
a67cbbcab9 | |||
b5177cb23a | |||
cab0e1d10e | |||
fbc79a846b | |||
a50f91f422 | |||
4910e89249 | |||
c562461711 | |||
8b9c957fe0 | |||
f0df12dad3 | |||
9637517192 | |||
e085826dbb | |||
c974c14220 | |||
247baeed22 | |||
613d67d1cf | |||
441f79022e | |||
4de52981cb | |||
ef1c5eb28a | |||
9a3aa1d23f | |||
64b0e4ef1a | |||
fcff00740a | |||
1102133458 | |||
4f54c49912 | |||
910f6ffadc | |||
9836a8620f | |||
af0ed62ecf | |||
217a96a2e4 | |||
6a94e61a7e | |||
c8fe4092c4 | |||
31187b7d17 | |||
ab94566995 | |||
f67511c2c1 | |||
05348534a6 | |||
18ea910f02 | |||
62be981c92 | |||
6daf6c6ba6 | |||
b0d3b41aae | |||
f48d9b2fcf | |||
6c299c068b | |||
ea5d3cee29 | |||
7330597586 | |||
1a0a41fa2d | |||
2f7cbd16db | |||
87dcd7dc7d | |||
8e5a27f4b7 | |||
6528f446bc | |||
4fa3023ea2 | |||
10f8200564 | |||
a547ec8147 | |||
db0e20f446 | |||
ca3fce003e | |||
f6ff132eb1 | |||
8bb207e9bb | |||
76047a4cc6 | |||
ee9b04f598 | |||
d238e9311b | |||
a838af46a6 | |||
5ed3e9a6a1 | |||
5b3346f5c5 | |||
a06fb7714b | |||
e69a9ebb3d | |||
2e607e8ffb | |||
0a9765626b | |||
537d170f1d | |||
0a682e7f12 | |||
afb69308df | |||
284cdeb2ed | |||
97d52495d4 | |||
423e965c88 | |||
e762ada551 | |||
ee09ff45e5 |
2
.flake8
2
.flake8
@ -137,4 +137,4 @@ show_source = True
|
||||
statistics = True
|
||||
|
||||
exclude =
|
||||
components/asio/docs/conf_common.py
|
||||
docs/asio/conf_common.py
|
||||
|
2
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
2
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
@ -8,7 +8,7 @@ body:
|
||||
label: Answers checklist.
|
||||
description: Before submitting a new issue, please follow the checklist and try to find the answer.
|
||||
options:
|
||||
- label: I have read the documentation for [esp-protocols components](https://espressif.github.io/esp-protocols/) and the issue is not addressed there.
|
||||
- label: I have read the documentation for esp-protocols [components](https://github.com/espressif/esp-protocols#readme) and the issue is not addressed there.
|
||||
required: true
|
||||
- label: I have updated my esp-protocols branch (master or release) to the latest version and checked that the issue is present there.
|
||||
required: true
|
||||
|
4
.github/ISSUE_TEMPLATE/config.yml
vendored
4
.github/ISSUE_TEMPLATE/config.yml
vendored
@ -1,7 +1,7 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: esp-protocols documentation
|
||||
url: https://espressif.github.io/esp-protocols/
|
||||
- name: esp-protocols documentation links
|
||||
url: https://github.com/espressif/esp-protocols#readme
|
||||
about: Documenation for esp-protocols components.
|
||||
- name: ESP-IDF Programming Guide
|
||||
url: https://docs.espressif.com/projects/esp-idf/en/latest/
|
||||
|
2
.github/ISSUE_TEMPLATE/other-issue.yml
vendored
2
.github/ISSUE_TEMPLATE/other-issue.yml
vendored
@ -7,7 +7,7 @@ body:
|
||||
label: Answers checklist.
|
||||
description: Before submitting a new issue, please follow the checklist and try to find the answer.
|
||||
options:
|
||||
- label: I have read the documentation for [esp-protocols components](https://espressif.github.io/esp-protocols/) and the issue is not addressed there.
|
||||
- label: I have read the documentation for esp-protocols [components](https://github.com/espressif/esp-protocols#readme) and the issue is not addressed there.
|
||||
required: true
|
||||
- label: I have updated my esp-protocols branch (master or release) to the latest version and checked that the issue is present there.
|
||||
required: true
|
||||
|
48
.github/workflows/examples_build-host-test.yml
vendored
Normal file
48
.github/workflows/examples_build-host-test.yml
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
name: "examples: build/host-tests"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, labeled]
|
||||
|
||||
jobs:
|
||||
build_all_examples:
|
||||
if: contains(github.event.pull_request.labels.*.name, 'examples') || github.event_name == 'push'
|
||||
name: Build examples
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest", "release-v5.1"]
|
||||
runs-on: ubuntu-20.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v3
|
||||
- name: Build with IDF-${{ matrix.idf_ver }}
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
python -m pip install idf-build-apps
|
||||
# Build default configs for all targets
|
||||
python ./ci/build_apps.py examples -m examples/.build-test-rules.yml -d -c
|
||||
|
||||
build_and_run_on_host:
|
||||
if: contains(github.event.pull_request.labels.*.name, 'examples') || github.event_name == 'push'
|
||||
name: Build and run examples on linux
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest"]
|
||||
runs-on: ubuntu-20.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v3
|
||||
- name: Build with IDF-${{ matrix.idf_ver }}
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
python -m pip install idf-build-apps
|
||||
python ./ci/build_apps.py examples/mqtt -l -t linux
|
||||
timeout 5 ./examples/mqtt/build_linux_default/esp_mqtt_demo.elf | tee test.log || true
|
||||
grep 'MQTT_EVENT_DATA' test.log
|
121
.github/workflows/mdns__build-target-test.yml
vendored
121
.github/workflows/mdns__build-target-test.yml
vendored
@ -13,122 +13,33 @@ jobs:
|
||||
name: Build
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest"]
|
||||
idf_target: ["esp32", "esp32s2", "esp32c3"]
|
||||
test: [ { app: example, path: "components/mdns/examples" }, { app: unit_test, path: "components/mdns/tests/unit_test" } ]
|
||||
idf_ver: ["latest", "release-v5.0"]
|
||||
test: [ { app: example, path: "examples" }, { app: unit_test, path: "tests/unit_test" }, { app: test_app, path: "tests/test_apps" } ]
|
||||
runs-on: ubuntu-20.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Build ${{ matrix.test.app }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
|
||||
- name: Build ${{ matrix.test.app }} with IDF-${{ matrix.idf_ver }}
|
||||
shell: bash
|
||||
working-directory: ${{ matrix.test.path }}
|
||||
run: |
|
||||
${IDF_PATH}/install.sh --enable-pytest
|
||||
. ${IDF_PATH}/export.sh
|
||||
python $IDF_PATH/tools/ci/ci_build_apps.py . --target ${{ matrix.idf_target }} -vv --preserve-all --pytest-app
|
||||
for dir in `ls -d build_*`; do
|
||||
python -m pip install idf-build-apps
|
||||
# Build default configs for all targets
|
||||
python ./ci/build_apps.py components/mdns/${{ matrix.test.path }} -r default -m components/mdns/.build-test-rules.yml -d
|
||||
# Build specific configs for test targets
|
||||
python ./ci/build_apps.py components/mdns/${{ matrix.test.path }}
|
||||
cd components/mdns/${{ matrix.test.path }}
|
||||
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@v3
|
||||
if: ${{ matrix.idf_target }} == "esp32"
|
||||
with:
|
||||
name: mdns_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.test.app }}
|
||||
path: ${{ matrix.test.path }}/artifacts.zip
|
||||
name: mdns_bin_esp32_${{ matrix.idf_ver }}_${{ matrix.test.app }}
|
||||
path: components/mdns/${{ matrix.test.path }}/artifacts.zip
|
||||
if-no-files-found: error
|
||||
|
||||
build_mdns_app:
|
||||
if: contains(github.event.pull_request.labels.*.name, 'mdns') || github.event_name == 'push'
|
||||
name: Build Test Apps
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest"]
|
||||
idf_target: ["esp32", "esp32s2", "esp32c3"]
|
||||
runs-on: ubuntu-20.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Setup Build Environment
|
||||
working-directory: components/mdns/tests/test_apps
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
pip install -r $GITHUB_WORKSPACE/ci/requirements.txt
|
||||
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
|
||||
env:
|
||||
IDF_TARGET: ${{ matrix.idf_target }}
|
||||
shell: bash
|
||||
working-directory: components/mdns/tests/test_apps
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
python $IDF_PATH/tools/ci/ci_build_apps.py . --target ${{ matrix.idf_target }} -vv --pytest-apps
|
||||
- name: Merge binaries with IDF-${{ matrix.idf_ver }}
|
||||
working-directory: components/mdns/tests/test_apps/build_${{ matrix.idf_target }}_default
|
||||
env:
|
||||
IDF_TARGET: ${{ matrix.idf_target }}
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
esptool.py --chip ${{ matrix.idf_target }} merge_bin --fill-flash-size 4MB -o flash_image.bin @flash_args
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: examples_app_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}
|
||||
path: |
|
||||
components/mdns/tests/test_apps/build_${{ matrix.idf_target }}_default/bootloader/bootloader.bin
|
||||
components/mdns/tests/test_apps/build_${{ matrix.idf_target }}_default/partition_table/partition-table.bin
|
||||
components/mdns/tests/test_apps/build_${{ matrix.idf_target }}_default/*.bin
|
||||
components/mdns/tests/test_apps/build_${{ matrix.idf_target }}_default/*.elf
|
||||
components/mdns/tests/test_apps/build_${{ matrix.idf_target }}_default/flasher_args.json
|
||||
components/mdns/tests/test_apps/build_${{ matrix.idf_target }}_default/config/sdkconfig.h
|
||||
components/mdns/tests/test_apps/build_${{ matrix.idf_target }}_default/config/sdkconfig.json
|
||||
if-no-files-found: error
|
||||
|
||||
target_test_apps_mdns:
|
||||
# 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, 'mdns') || github.event_name == 'push' )
|
||||
name: Target Test Apps
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest"]
|
||||
idf_target: ["esp32"]
|
||||
needs: build_mdns_app
|
||||
runs-on:
|
||||
- self-hosted
|
||||
- ESP32-ETHERNET-KIT
|
||||
steps:
|
||||
- name: Clear repository
|
||||
run: sudo rm -fr $GITHUB_WORKSPACE && mkdir $GITHUB_WORKSPACE
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: examples_app_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}
|
||||
path: components/mdns/tests/test_apps/build
|
||||
- name: Install Python packages
|
||||
env:
|
||||
PIP_EXTRA_INDEX_URL: "https://www.piwheels.org/simple"
|
||||
run: |
|
||||
sudo apt-get install -y dnsutils
|
||||
- name: Download Test apps to target
|
||||
run: |
|
||||
python -m esptool --chip ${{ matrix.idf_target }} write_flash 0x0 components/mdns/tests/test_apps/build/flash_image.bin
|
||||
- name: Run Example Test on target
|
||||
working-directory: components/mdns/tests/test_apps
|
||||
run: |
|
||||
python -m pytest --log-cli-level DEBUG --junit-xml=./examples_results_${{ matrix.idf_target }}_${{ matrix.idf_ver }}.xml --target=${{matrix.idf_target}}
|
||||
- uses: actions/upload-artifact@v2
|
||||
if: always()
|
||||
with:
|
||||
name: test_apps_results_${{ matrix.idf_target }}_${{ matrix.idf_ver }}
|
||||
path: components/mdns/tests/test_apps/*.xml
|
||||
|
||||
target_tests_mdns:
|
||||
# Skip running on forks since it won't have access to secrets
|
||||
if: |
|
||||
@ -139,7 +50,7 @@ jobs:
|
||||
matrix:
|
||||
idf_ver: ["latest"]
|
||||
idf_target: ["esp32"]
|
||||
test: [ { app: example, path: "components/mdns/examples" }, { app: unit_test, path: "components/mdns/tests/unit_test" } ]
|
||||
test: [ { app: example, path: "examples" }, { app: unit_test, path: "tests/unit_test" }, { app: test_app, path: "tests/test_apps" } ]
|
||||
needs: build_mdns
|
||||
runs-on:
|
||||
- self-hosted
|
||||
@ -151,14 +62,14 @@ jobs:
|
||||
- uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: mdns_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.test.app }}
|
||||
path: ${{ matrix.test.path }}/ci/
|
||||
path: components/mdns/${{ matrix.test.path }}/ci/
|
||||
- name: Install Python packages
|
||||
env:
|
||||
PIP_EXTRA_INDEX_URL: "https://www.piwheels.org/simple"
|
||||
run: |
|
||||
sudo apt-get install -y dnsutils
|
||||
- name: Run ${{ matrix.test.app }} application on ${{ matrix.idf_target }}
|
||||
working-directory: ${{ matrix.test.path }}
|
||||
working-directory: components/mdns/${{ matrix.test.path }}
|
||||
run: |
|
||||
unzip ci/artifacts.zip -d ci
|
||||
for dir in `ls -d ci/build_*`; do
|
||||
@ -170,4 +81,4 @@ jobs:
|
||||
if: always()
|
||||
with:
|
||||
name: results_${{ matrix.test.app }}_${{ matrix.idf_target }}_${{ matrix.idf_ver }}.xml
|
||||
path: ${{ matrix.test.path }}/*.xml
|
||||
path: components/mdns/${{ matrix.test.path }}/*.xml
|
||||
|
2
.github/workflows/mdns__host-tests.yml
vendored
2
.github/workflows/mdns__host-tests.yml
vendored
@ -12,7 +12,7 @@ jobs:
|
||||
if: contains(github.event.pull_request.labels.*.name, 'mdns') || github.event_name == 'push'
|
||||
name: Host test
|
||||
runs-on: ubuntu-20.04
|
||||
container: espressif/idf:latest
|
||||
container: espressif/idf:release-v5.1
|
||||
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
|
36
.github/workflows/modem__build-host-tests.yml
vendored
36
.github/workflows/modem__build-host-tests.yml
vendored
@ -48,7 +48,7 @@ jobs:
|
||||
. ${IDF_PATH}/export.sh
|
||||
python -m pip install idf-build-apps
|
||||
cd $GITHUB_WORKSPACE/protocols
|
||||
python ./ci/build_apps.py components/esp_modem/examples/${{ matrix.example }}
|
||||
python ./ci/build_apps.py components/esp_modem/examples/${{ matrix.example }} -m components/esp_modem/examples/.build-test-rules.yml
|
||||
|
||||
host_test_esp_modem:
|
||||
if: contains(github.event.pull_request.labels.*.name, 'modem') || github.event_name == 'push'
|
||||
@ -91,6 +91,8 @@ jobs:
|
||||
if: contains(github.event.pull_request.labels.*.name, 'modem') || github.event_name == 'push'
|
||||
name: Run gcovr on esp modem host test
|
||||
runs-on: ubuntu-22.04
|
||||
permissions:
|
||||
contents: write
|
||||
container: espressif/idf:release-v4.3
|
||||
env:
|
||||
lwip: lwip-2.1.2
|
||||
@ -102,6 +104,7 @@ jobs:
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
path: esp-protocols
|
||||
repository: ''
|
||||
persist-credentials: false
|
||||
- name: Build and Test
|
||||
shell: bash
|
||||
@ -128,8 +131,7 @@ jobs:
|
||||
gcovr --gcov-ignore-parse-errors -g -k -r . --html index.html -x esp_modem_coverage.xml
|
||||
mkdir docs_gcovr
|
||||
cp $GITHUB_WORKSPACE/${{ env.COMP_DIR }}/index.html docs_gcovr
|
||||
touch docs_gcovr/.nojekyll
|
||||
|
||||
cp -rf docs_gcovr $GITHUB_WORKSPACE
|
||||
- name: Code Coverage Summary Report
|
||||
uses: irongut/CodeCoverageSummary@v1.3.0
|
||||
with:
|
||||
@ -142,7 +144,6 @@ jobs:
|
||||
indicators: true
|
||||
output: both
|
||||
thresholds: '60 80'
|
||||
|
||||
- name: Write to Job Summary
|
||||
run: cat code-coverage-results.md >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
@ -154,24 +155,9 @@ jobs:
|
||||
path: |
|
||||
${{ env.COMP_DIR }}/docs_gcovr
|
||||
if-no-files-found: error
|
||||
|
||||
# show_report_data:
|
||||
# name: Publish-Results
|
||||
# if: github.ref == 'refs/heads/master' || github.repository != 'espressif/esp-protocols'
|
||||
# runs-on: ubuntu-22.04
|
||||
# needs: gcovr_analyzer_esp_modem
|
||||
# steps:
|
||||
# - name: Checkout 🛎️
|
||||
# uses: actions/checkout@v3
|
||||
# with:
|
||||
# persist-credentials: false
|
||||
# - name: Download Artifacts
|
||||
# uses: actions/download-artifact@v1
|
||||
# with:
|
||||
# name: docs_gcovr
|
||||
#
|
||||
# - name: Deploy generated docs
|
||||
# uses: JamesIves/github-pages-deploy-action@v4
|
||||
# with:
|
||||
# branch: gh-pages
|
||||
# folder: 'docs_gcovr'
|
||||
- name: Deploy code coverage results
|
||||
if: github.ref == 'refs/heads/master'
|
||||
uses: peaceiris/actions-gh-pages@v3
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
publish_dir: ./docs_gcovr
|
||||
|
2
.github/workflows/modem__target-test.yml
vendored
2
.github/workflows/modem__target-test.yml
vendored
@ -58,7 +58,7 @@ jobs:
|
||||
needs: build_esp_modem_tests
|
||||
runs-on:
|
||||
- self-hosted
|
||||
- BrnoRPI-GH006
|
||||
- modem
|
||||
env:
|
||||
TEST_DIR: components/esp_modem/${{ matrix.test.path }}
|
||||
steps:
|
||||
|
18
.github/workflows/pre_commit_check.yml
vendored
18
.github/workflows/pre_commit_check.yml
vendored
@ -12,12 +12,17 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ github.base_ref }}
|
||||
fetch-depth: 20
|
||||
- name: Fetch head and base refs
|
||||
# This is necessary for pre-commit to check the changes in the PR branch
|
||||
# This is necessary for pre-commit to check the changes in the PR branch (and to set origin/HEAD and HEAD refs)
|
||||
run: |
|
||||
git fetch origin ${{ github.base_ref }}:base_ref
|
||||
git fetch origin pull/${{ github.event.pull_request.number }}/head:pr_ref
|
||||
git fetch origin ${{ github.event.pull_request.head.sha }}:pr_ref
|
||||
git checkout pr_ref
|
||||
git remote set-head origin --auto
|
||||
git merge-base origin/HEAD HEAD || ( echo "Your PR is far behind origin/HEAD, please rebase" && exit 1 )
|
||||
- name: Set up Python environment
|
||||
uses: actions/setup-python@master
|
||||
with:
|
||||
@ -26,13 +31,12 @@ jobs:
|
||||
run: |
|
||||
pip install pre-commit
|
||||
pre-commit install-hooks
|
||||
pre-commit install --hook-type commit-msg --hook-type pre-push
|
||||
- name: Run pre-commit and check for any changes
|
||||
run: |
|
||||
echo "Commits being checked:"
|
||||
git log --oneline --no-decorate base_ref..pr_ref
|
||||
git log --oneline --no-decorate origin/HEAD..HEAD
|
||||
echo ""
|
||||
if ! pre-commit run --from-ref base_ref --to-ref pr_ref --show-diff-on-failure ; then
|
||||
if ! pre-commit run --from-ref origin/HEAD --to-ref HEAD --hook-stage manual --show-diff-on-failure ; then
|
||||
echo ""
|
||||
echo "::notice::It looks like the commits in this PR have been made without having pre-commit hooks installed."
|
||||
echo "::notice::Please see https://github.com/espressif/esp-protocols/CONTRIBUTING.md for instructions."
|
||||
|
123
.github/workflows/publish-docs-component.yml
vendored
123
.github/workflows/publish-docs-component.yml
vendored
@ -5,66 +5,89 @@ on:
|
||||
branches:
|
||||
- master
|
||||
|
||||
env:
|
||||
DOCS_DEPLOY_URL_BASE: ${{ secrets.DOCS_DEPLOY_URL_BASE }}
|
||||
DOCS_DEPLOY_SERVER: ${{ secrets.DOCS_DEPLOY_SERVER }}
|
||||
DOCS_DEPLOY_SERVER_USER: ${{ secrets.DOCS_DEPLOY_SERVER_USER }}
|
||||
DOCS_DEPLOY_KEY: ${{ secrets.DOCS_DEPLOY_PRIVATEKEY }}
|
||||
DOCS_DEPLOY_PATH_ORIG : ${{ secrets.DOCS_DEPLOY_PATH }}
|
||||
|
||||
jobs:
|
||||
docs_build:
|
||||
name: Docs-Build-And-Upload
|
||||
publish:
|
||||
name: Publish Tag, Release, Docs, Component
|
||||
runs-on: ubuntu-latest
|
||||
# Skip running on forks since it won't have access to secrets
|
||||
if: github.repository == 'espressif/esp-protocols'
|
||||
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@master
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
persist-credentials: false
|
||||
fetch-depth: 0
|
||||
submodules: recursive
|
||||
|
||||
- name: Generate docs
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install doxygen clang python3-pip
|
||||
python -m pip install breathe recommonmark esp-docs
|
||||
cd $GITHUB_WORKSPACE/components/esp_modem/docs
|
||||
./generate_docs
|
||||
mkdir -p $GITHUB_WORKSPACE/docs/esp_modem
|
||||
cp -r html/. $GITHUB_WORKSPACE/docs/esp_modem
|
||||
|
||||
cd $GITHUB_WORKSPACE/components/esp_websocket_client/docs
|
||||
./generate_docs
|
||||
mkdir -p $GITHUB_WORKSPACE/docs/esp_websocket_client
|
||||
cp -r html/. $GITHUB_WORKSPACE/docs/esp_websocket_client
|
||||
|
||||
cd $GITHUB_WORKSPACE/components/mdns/docs
|
||||
./generate_docs
|
||||
mkdir -p $GITHUB_WORKSPACE/docs/mdns/en
|
||||
mkdir -p $GITHUB_WORKSPACE/docs/mdns/zh_CN
|
||||
cp -r html_en/. $GITHUB_WORKSPACE/docs/mdns/en
|
||||
cp -r html_zh_CN/. $GITHUB_WORKSPACE/docs/mdns/zh_CN
|
||||
|
||||
cd $GITHUB_WORKSPACE/components/asio/docs
|
||||
./generate_docs
|
||||
mkdir -p $GITHUB_WORKSPACE/docs/asio
|
||||
cp -r html/. $GITHUB_WORKSPACE/docs/asio
|
||||
|
||||
cd $GITHUB_WORKSPACE/docs
|
||||
touch .nojekyll
|
||||
echo '<a href="esp_modem/index.html">esp-modem</a><br>' > index.html
|
||||
echo '<a href="esp_websocket_client/index.html">esp-websocket-client</a><br>' >> index.html
|
||||
echo '<a href="asio/index.html">ASIO</a><br>' >> index.html
|
||||
echo '<a href="mdns/en/index.html">mDNS_en</a><br>' >> index.html
|
||||
echo '<a href="mdns/zh_CN/index.html">mDNS_zh_CN</a><br>' >> index.html
|
||||
|
||||
|
||||
- name: Upload components to component service
|
||||
uses: espressif/github-actions/upload_components@master
|
||||
token: "${{ secrets.GITHUB_TOKEN }}"
|
||||
- name: Check for version update
|
||||
shell: bash
|
||||
run: ./ci/detect_component_bump
|
||||
- name: Tag merge commit
|
||||
if: env.BUMP_VERSION != ''
|
||||
uses: anothrNick/github-tag-action@1.61.0
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
CUSTOM_TAG: ${{ env.BUMP_TAG }}
|
||||
- name: Create Release
|
||||
if: env.BUMP_VERSION != ''
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
directories: "components/esp_modem;components/esp_websocket_client;components/mdns;components/asio"
|
||||
body_path: "release_notes.md"
|
||||
tag_name: ${{ env.BUMP_TAG }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Generate docs
|
||||
shell: bash
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install doxygen clang python3-pip
|
||||
python -m pip install breathe recommonmark esp-docs==1.4.1
|
||||
for comp in `ls components`; do
|
||||
cd $GITHUB_WORKSPACE/docs/${comp}
|
||||
if [[ "${{ env.BUMP_COMPONENT }}" == "${comp}" ]]; then
|
||||
echo "Building specific version of ${comp} (${{ env.BUMP_VERSION }})"
|
||||
./generate_docs ${{ env.BUMP_VERSION }}
|
||||
else
|
||||
echo "Building latest version of ${comp}"
|
||||
./generate_docs
|
||||
fi
|
||||
done
|
||||
- name: Deploying generated docs
|
||||
shell: bash
|
||||
run: |
|
||||
source $GITHUB_WORKSPACE/docs/utils.sh
|
||||
add_doc_server_ssh_keys $DOCS_DEPLOY_KEY $DOCS_DEPLOY_SERVER $DOCS_DEPLOY_SERVER_USER
|
||||
export GIT_VER=$(git describe --always)
|
||||
export GITHUB_REF_NAME=latest
|
||||
for comp in `ls components`; do
|
||||
echo "Deploying latest of ${comp}"
|
||||
export DOCS_BUILD_DIR=$GITHUB_WORKSPACE/docs/${comp}
|
||||
export DOCS_DEPLOY_PATH=$DOCS_DEPLOY_PATH_ORIG/${comp}
|
||||
cd $GITHUB_WORKSPACE/docs/${comp}
|
||||
deploy-docs
|
||||
done;
|
||||
# Deploy docs with version path
|
||||
if [[ "${{ env.BUMP_VERSION }}" != "" ]]; then
|
||||
echo "Deploying specific version of ${comp} (${{ env.BUMP_VERSION }})"
|
||||
cd $GITHUB_WORKSPACE/docs/${{ env.BUMP_COMPONENT }}
|
||||
export GITHUB_REF_NAME=${{ env.BUMP_VERSION }}
|
||||
deploy-docs
|
||||
fi
|
||||
- name: Upload components to component service
|
||||
uses: espressif/upload-components-ci-action@v1
|
||||
with:
|
||||
directories: >
|
||||
components/asio;
|
||||
components/esp_modem;
|
||||
components/esp_mqtt_cxx;
|
||||
components/esp_websocket_client;
|
||||
components/mdns;
|
||||
namespace: "espressif"
|
||||
api_token: ${{ secrets.IDF_COMPONENT_API_TOKEN }}
|
||||
|
||||
- name: Deploy generated docs
|
||||
uses: JamesIves/github-pages-deploy-action@4.1.5
|
||||
with:
|
||||
branch: gh-pages
|
||||
folder: docs
|
||||
|
@ -13,45 +13,32 @@ jobs:
|
||||
name: Build
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["release-v5.0", "latest"]
|
||||
idf_target: ["esp32"]
|
||||
idf_ver: ["release-v5.0", "release-v5.1", "latest"]
|
||||
test: [ { app: example, path: "examples" }, { app: unit_test, path: "test" } ]
|
||||
runs-on: ubuntu-20.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
env:
|
||||
TEST_DIR: components/esp_websocket_client/examples
|
||||
TEST_DIR: components/esp_websocket_client/${{ matrix.test.path }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
|
||||
env:
|
||||
IDF_TARGET: ${{ matrix.idf_target }}
|
||||
shell: bash
|
||||
working-directory: ${{ env.TEST_DIR }}
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
cat sdkconfig.ci >> sdkconfig.defaults
|
||||
idf.py build
|
||||
- name: Merge binaries
|
||||
working-directory: ${{ env.TEST_DIR }}/build
|
||||
env:
|
||||
IDF_TARGET: ${{ matrix.idf_target }}
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
esptool.py --chip ${{ matrix.idf_target }} merge_bin --fill-flash-size 4MB -o flash_image.bin @flash_args
|
||||
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@v3
|
||||
with:
|
||||
name: examples_app_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}
|
||||
path: |
|
||||
${{ env.TEST_DIR }}/build/bootloader/bootloader.bin
|
||||
${{ env.TEST_DIR }}/build/partition_table/partition-table.bin
|
||||
${{ env.TEST_DIR }}/build/*.bin
|
||||
${{ env.TEST_DIR }}/build/*.elf
|
||||
${{ env.TEST_DIR }}/build/flasher_args.json
|
||||
${{ env.TEST_DIR }}/build/config/sdkconfig.h
|
||||
${{ env.TEST_DIR }}/build/config/sdkconfig.json
|
||||
name: websocket_bin_esp32_${{ matrix.idf_ver }}_${{ matrix.test.app }}
|
||||
path: ${{ env.TEST_DIR }}/artifacts.zip
|
||||
if-no-files-found: error
|
||||
|
||||
run-target-websocket:
|
||||
@ -64,32 +51,36 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
idf_ver: ["release-v5.0", "latest"]
|
||||
idf_ver: ["release-v5.0", "release-v5.1", "latest"]
|
||||
idf_target: ["esp32"]
|
||||
test: [ { app: example, path: "examples" }, { app: unit_test, path: "test" } ]
|
||||
runs-on:
|
||||
- self-hosted
|
||||
- ESP32-ETHERNET-KIT
|
||||
env:
|
||||
TEST_DIR: components/esp_websocket_client/examples
|
||||
TEST_DIR: components/esp_websocket_client/${{ matrix.test.path }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: examples_app_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}
|
||||
path: ${{ env.TEST_DIR }}/build/
|
||||
name: websocket_bin_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: Download Example Test to target
|
||||
run: python -m esptool --chip ${{ matrix.idf_target }} write_flash 0x0 components/esp_websocket_client/examples/build/flash_image.bin
|
||||
- name: Run Example Test on target
|
||||
working-directory: ${{ env.TEST_DIR }}
|
||||
run: |
|
||||
python -m pytest --log-cli-level DEBUG --junit-xml=./examples_results_${{ matrix.idf_target }}_${{ matrix.idf_ver }}.xml --target=${{ matrix.idf_target }}
|
||||
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@v3
|
||||
if: always()
|
||||
with:
|
||||
name: examples_results_${{ matrix.idf_target }}_${{ matrix.idf_ver }}
|
||||
path: ${{ env.TEST_DIR }}/*.xml
|
||||
name: results_${{ matrix.test.app }}_${{ matrix.idf_target }}_${{ matrix.idf_ver }}.xml
|
||||
path: components/esp_websocket_client/${{ matrix.test.path }}/*.xml
|
||||
|
@ -57,12 +57,12 @@ repos:
|
||||
hooks:
|
||||
- id: commitizen
|
||||
- id: commitizen-branch
|
||||
stages: [push]
|
||||
stages: [push, manual]
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: commit message scopes
|
||||
name: "commit message must be scoped with: mdns, modem, websocket, asio, mqtt_cxx, common"
|
||||
entry: '\A(?!(feat|fix|ci|bump|test|docs)\((mdns|modem|common|websocket|asio|mqtt_cxx)\)\:)'
|
||||
entry: '\A(?!(feat|fix|ci|bump|test|docs)\((mdns|modem|common|websocket|asio|mqtt_cxx|examples)\)\:)'
|
||||
language: pygrep
|
||||
args: [--multiline]
|
||||
stages: [commit-msg]
|
||||
|
@ -24,8 +24,8 @@ When releasing a new component version we have to:
|
||||
* Deploy the component to component registry
|
||||
* Update the documentation
|
||||
|
||||
This process is not fully automated, the first three steps need to be performed manually by project maintainers running the `bump` command (from within this repository, rather than forks, to publish the release `tag`). Release procedure is as follows:
|
||||
* Create a branch in this repository (not from fork)
|
||||
* Run `cz bump [version]` (version number is optional, `cz` would automatically increment it if not present)
|
||||
* Check the updated `CHANGELOG.md`
|
||||
* Create and merge the branch to master
|
||||
This process is not fully automated, the first step needs to be performed manually by project maintainers running the `bump` command. Release procedure is as follows:
|
||||
* Run `ci/bump [component] [version]` (version number is optional, `cz` would automatically increment it if not present)
|
||||
* Check the updated `CHANGELOG.md` and the generated bump commit message
|
||||
* Create a PR
|
||||
Once the PR is merged, the CI job tags the merge commit, creates a new release, builds and deploys documentation and the new component to the component registry
|
||||
|
17
README.md
17
README.md
@ -1,26 +1,29 @@
|
||||
# Collection of protocol components for ESP-IDF
|
||||
|
||||
[Documentation of esp-protocol](https://espressif.github.io/esp-protocols)
|
||||
|
||||
## Components
|
||||
|
||||
### esp_modem
|
||||
|
||||
* Brief introduction [README](components/esp_modem/README.md)
|
||||
* Full html [documentation](https://espressif.github.io/esp-protocols/esp_modem/index.html)
|
||||
* Full html [documentation](https://docs.espressif.com/projects/esp-protocols/esp_modem/docs/latest/index.html)
|
||||
|
||||
### mDNS
|
||||
|
||||
* Brief introduction [README](components/mdns/README.md)
|
||||
* Full html [documentation(English)](https://espressif.github.io/esp-protocols/mdns/en/index.html)
|
||||
* Full html [documentation(Chinese)](https://espressif.github.io/esp-protocols/mdns/zh_CN/index.html)
|
||||
* Full html [documentation(English)](https://docs.espressif.com/projects/esp-protocols/mdns/docs/latest/en/index.html)
|
||||
* Full html [documentation(Chinese)](https://docs.espressif.com/projects/esp-protocols/mdns/docs/latest/zh_CN/index.html)
|
||||
|
||||
### esp_websocket_client
|
||||
|
||||
* Brief introduction [README](components/esp_websocket_client/README.md)
|
||||
* Full html [documentation](https://espressif.github.io/esp-protocols/esp_websocket_client/index.html)
|
||||
* Full html [documentation](https://docs.espressif.com/projects/esp-protocols/esp_websocket_client/docs/latest/index.html)
|
||||
|
||||
### ASIO port
|
||||
|
||||
* Brief introduction [README](components/asio/README.md)
|
||||
* Full html [documentation](https://espressif.github.io/esp-protocols/asio/index.html)
|
||||
* Full html [documentation](https://docs.espressif.com/projects/esp-protocols/asio/docs/latest/index.html)
|
||||
|
||||
### esp_mqtt_cxx
|
||||
|
||||
* Brief introduction [README](components/esp_mqtt_cxx/README.md)
|
||||
* Full html [documentation](https://docs.espressif.com/projects/esp-protocols/esp_mqtt_cxx/docs/latest/index.html)
|
||||
|
@ -7,7 +7,6 @@ This file is used in CI for esp-protocols build tests
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from idf_build_apps import build_apps, find_apps, setup_logging
|
||||
from idf_build_apps.constants import SUPPORTED_TARGETS
|
||||
@ -24,27 +23,35 @@ if __name__ == '__main__':
|
||||
default='all',
|
||||
help='Build apps for given target',
|
||||
)
|
||||
parser.add_argument('-r', '--rules', nargs='*', default=['sdkconfig.ci=default', 'sdkconfig.ci.*=', '=default'], help='Rules how to treat configs')
|
||||
parser.add_argument('-m', '--manifests', nargs='*', default=[], help='list of manifest files')
|
||||
parser.add_argument('-d', '--delete', action='store_true', help='Delete build artifacts')
|
||||
parser.add_argument('-c', '--recursive', action='store_true', help='Build recursively')
|
||||
parser.add_argument('-l', '--linux', action='store_true', help='Include linux build (dont check warnings)')
|
||||
args = parser.parse_args()
|
||||
|
||||
IDF_PATH = os.environ['IDF_PATH']
|
||||
|
||||
print(args.paths)
|
||||
# Compose the ignore warning strings from the global list and from the environment
|
||||
ignore_warning_file = os.path.join(os.path.dirname(os.path.realpath(__file__)),'ignore_build_warnings.txt')
|
||||
ignore_warning = open(ignore_warning_file).read().rstrip('\n').split('\n')
|
||||
if 'EXPECTED_WARNING' in os.environ:
|
||||
ignore_warning += os.environ['EXPECTED_WARNING'].split('\n')
|
||||
if args.linux:
|
||||
SUPPORTED_TARGETS.append('linux')
|
||||
ignore_warning = 'warning: ' # Ignore all common warnings on linux builds
|
||||
setup_logging(2)
|
||||
apps = find_apps(
|
||||
args.paths,
|
||||
recursive=True,
|
||||
recursive=args.recursive,
|
||||
target=args.target,
|
||||
build_dir='build_@t_@w',
|
||||
config_rules_str=[
|
||||
'sdkconfig.ci=default', 'sdkconfig.ci.*=', '=default'
|
||||
],
|
||||
config_rules_str=args.rules,
|
||||
build_log_path='build_log.txt',
|
||||
size_json_path='size.json',
|
||||
size_json_path='size.json' if not args.linux else None,
|
||||
check_warnings=True,
|
||||
preserve=True,
|
||||
manifest_files=[
|
||||
str(p) for p in Path('.').glob('**/.build-test-rules.yml')
|
||||
],
|
||||
preserve=not args.delete,
|
||||
manifest_files=args.manifests,
|
||||
default_build_targets=SUPPORTED_TARGETS,
|
||||
manifest_rootpath='.',
|
||||
)
|
||||
@ -56,5 +63,5 @@ if __name__ == '__main__':
|
||||
build_apps(apps,
|
||||
dry_run=False,
|
||||
keep_going=False,
|
||||
ignore_warning_strs=os.environ['EXPECTED_WARNING']
|
||||
if 'EXPECTED_WARNING' in os.environ else None))
|
||||
ignore_warning_strs=ignore_warning)
|
||||
)
|
||||
|
23
ci/bump
Executable file
23
ci/bump
Executable file
@ -0,0 +1,23 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: bump component [version]"
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
comp=$1; shift;
|
||||
|
||||
cd components/${comp}
|
||||
if ! cz bump --dry-run; then
|
||||
echo "Commitizen bump commad failed!"
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
cz_bump_out=`cz bump --files-only "$@"`
|
||||
commit_title=`echo "${cz_bump_out}" | head -1`
|
||||
commit_body=`cat ../../release_notes.txt`
|
||||
|
||||
git add -u .
|
||||
git commit -m $"${commit_title}
|
||||
|
||||
${commit_body}"
|
@ -47,7 +47,7 @@ def main():
|
||||
details = '[{}](https://github.com/espressif/esp-protocols/commit/{})'.format(commit, commit)
|
||||
msg_details = git.show('-s', commit, _tty_out=False)
|
||||
# check references
|
||||
if any(str(msg_details) in s for s in ['esp-protocols/issues', 'BREAKING CHANGE', 'MAJOR CHANGE']):
|
||||
if any(s in str(msg_details) for s in ['esp-protocols/issues', 'BREAKING CHANGE', 'MAJOR CHANGE']):
|
||||
# Closes <issue>
|
||||
closes = re.findall(r'Closes ([^\d]+/(\d+))', str(msg_details), re.MULTILINE)
|
||||
if closes and closes[0] is not None:
|
||||
@ -93,6 +93,13 @@ def main():
|
||||
updated_changelog.write(orig_items)
|
||||
git.add(filename)
|
||||
|
||||
# write the current changelog entry to a local text file (removing links, captions and extra newlines)
|
||||
changelog = re.sub(r'\[([^\]]+)\]\([^\)]+\)', r'\1', changelog)
|
||||
changelog = re.sub(r'\#\#[\#\s]*(.+)', r'\1', changelog)
|
||||
changelog = re.sub(r'\n\n', '\n', changelog)
|
||||
with open(os.path.join(root_path, 'release_notes.txt'), 'w') as release_notes:
|
||||
release_notes.write(changelog)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
@ -29,6 +29,7 @@ DEFAULT:
|
||||
# this section sets the default license for examples and unit tests of components
|
||||
examples_and_unit_tests:
|
||||
include:
|
||||
- 'examples/**'
|
||||
- 'components/**/examples/**'
|
||||
- 'components/**/test/**'
|
||||
- 'components/**/tests/**'
|
||||
@ -57,7 +58,7 @@ slim_modem_examples:
|
||||
ignore:
|
||||
perform_check: no
|
||||
include:
|
||||
- 'components/**/docs/**'
|
||||
- '**/docs/**'
|
||||
- 'components/esp_modem/port/linux/**'
|
||||
- 'components/asio/examples/**'
|
||||
- 'components/mdns/**/esp_system_protocols_linux/**'
|
||||
|
41
ci/detect_component_bump
Executable file
41
ci/detect_component_bump
Executable file
@ -0,0 +1,41 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
if ! git show -s | grep -q '^Merge'; then
|
||||
echo "Not a merge commit"
|
||||
exit 0;
|
||||
fi
|
||||
|
||||
for comp in `ls components`; do
|
||||
if git log -1 -m --name-only --pretty="" | grep -q components/${comp}/idf_component.yml; then
|
||||
echo "${comp}: Component version file has changed"
|
||||
version=`grep version: components/${comp}/.cz.yaml`
|
||||
version=${version#*version: }
|
||||
|
||||
tag_format=`grep tag_format: components/${comp}/.cz.yaml`
|
||||
tag_format=${tag_format#*tag_format: }
|
||||
|
||||
eval tag=$tag_format
|
||||
# check if the tag is already created
|
||||
if [ $(git tag -l "$tag") ]; then
|
||||
echo "${comp}: version (${tag}) already exits"
|
||||
else
|
||||
echo "${comp}: Component version has been updated to ${version}"
|
||||
# creates release notes from the last entry (between first two "## sections")
|
||||
awk '/^## \[/{a++};{if(a==1){print}}' components/${comp}/CHANGELOG.md > release_notes.md
|
||||
|
||||
echo "BUMP_VERSION=${version}"
|
||||
echo "BUMP_COMPONENT=${comp}"
|
||||
echo "BUMP_TAG=${tag}"
|
||||
|
||||
# export the findings to github env, so it could be used in other jobs
|
||||
echo "BUMP_VERSION=${version}" >> "$GITHUB_ENV"
|
||||
echo "BUMP_COMPONENT=${comp}" >> "$GITHUB_ENV"
|
||||
echo "BUMP_TAG=${tag}" >> "$GITHUB_ENV"
|
||||
|
||||
exit 0;
|
||||
fi
|
||||
fi
|
||||
done
|
||||
echo "No changes in component version file"
|
1
ci/ignore_build_warnings.txt
Normal file
1
ci/ignore_build_warnings.txt
Normal file
@ -0,0 +1 @@
|
||||
DeprecationWarning: pkg_resources is deprecated as an API
|
@ -1,6 +1,5 @@
|
||||
idf_component_register(SRCS esp_timer_linux.c timer_task.cpp
|
||||
INCLUDE_DIRS include
|
||||
REQUIRES esp_event)
|
||||
INCLUDE_DIRS include)
|
||||
|
||||
set_target_properties(${COMPONENT_LIB} PROPERTIES
|
||||
CXX_STANDARD 17
|
@ -7,6 +7,7 @@
|
||||
#include "esp_timer.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include <pthread.h>
|
||||
|
||||
void *create_tt(esp_timer_cb_t cb);
|
||||
|
||||
@ -37,3 +38,10 @@ esp_err_t esp_timer_delete(esp_timer_handle_t timer)
|
||||
destroy_tt(timer);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
int64_t esp_timer_get_time(void)
|
||||
{
|
||||
struct timespec spec;
|
||||
clock_gettime(CLOCK_REALTIME, &spec);
|
||||
return spec.tv_nsec / 1000 + spec.tv_sec * 1000000;
|
||||
}
|
@ -7,6 +7,12 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bsd/string.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct esp_timer *esp_timer_handle_t;
|
||||
|
||||
@ -31,3 +37,9 @@ esp_err_t esp_timer_start_periodic(esp_timer_handle_t timer, uint64_t period);
|
||||
esp_err_t esp_timer_stop(esp_timer_handle_t timer);
|
||||
|
||||
esp_err_t esp_timer_delete(esp_timer_handle_t timer);
|
||||
|
||||
int64_t esp_timer_get_time(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -1,4 +1,5 @@
|
||||
idf_component_register(SRCS freertos_linux.c queue_unique_ptr.cpp
|
||||
idf_component_register(SRCS freertos_linux.c
|
||||
osal/queue.cpp osal/event_group.cpp osal/mutex.cpp
|
||||
INCLUDE_DIRS include)
|
||||
|
||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
272
common_components/linux_compat/freertos/freertos_linux.c
Normal file
272
common_components/linux_compat/freertos/freertos_linux.c
Normal file
@ -0,0 +1,272 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include <pthread.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "osal/osal_api.h"
|
||||
|
||||
static uint64_t s_semaphore_data = 0;
|
||||
|
||||
typedef enum queue_type_tag {
|
||||
MUTEX_REC,
|
||||
MUTEX,
|
||||
SEMA,
|
||||
QUEUE,
|
||||
} queue_type_t;
|
||||
|
||||
struct generic_queue_handle {
|
||||
queue_type_t type;
|
||||
size_t item_size;
|
||||
void *q;
|
||||
};
|
||||
|
||||
static struct generic_queue_handle *create_generic_queue(queue_type_t type, uint32_t len, uint32_t item_size)
|
||||
{
|
||||
struct generic_queue_handle *h = calloc(1, sizeof(struct generic_queue_handle));
|
||||
h->item_size = len;
|
||||
h->type = type;
|
||||
switch (type) {
|
||||
default:
|
||||
case QUEUE:
|
||||
case SEMA:
|
||||
h->q = osal_queue_create();
|
||||
break;
|
||||
|
||||
case MUTEX:
|
||||
case MUTEX_REC:
|
||||
h->q = osal_mutex_create();
|
||||
break;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
QueueHandle_t xQueueCreate(uint32_t uxQueueLength, uint32_t uxItemSize )
|
||||
{
|
||||
return (QueueHandle_t)create_generic_queue(QUEUE, uxQueueLength, uxItemSize);
|
||||
}
|
||||
|
||||
uint32_t xQueueSend(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait)
|
||||
{
|
||||
struct generic_queue_handle *h = xQueue;
|
||||
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 )
|
||||
{
|
||||
return xQueueSend(xQueue, pvItemToQueue, xTicksToWait);
|
||||
}
|
||||
|
||||
uint32_t xQueueReceive(QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksToWait)
|
||||
{
|
||||
struct generic_queue_handle *h = xQueue;
|
||||
return osal_queue_recv(h->q, (uint8_t *)pvBuffer, h->item_size, xTicksToWait) ? pdTRUE : pdFAIL;
|
||||
}
|
||||
|
||||
BaseType_t xSemaphoreGive( QueueHandle_t xQueue)
|
||||
{
|
||||
struct generic_queue_handle *h = xQueue;
|
||||
if (h->type == MUTEX) {
|
||||
osal_mutex_give(h->q);
|
||||
return pdTRUE;
|
||||
}
|
||||
return xQueueSend(xQueue, &s_semaphore_data, portMAX_DELAY);
|
||||
}
|
||||
|
||||
BaseType_t xSemaphoreGiveRecursive( QueueHandle_t xQueue)
|
||||
{
|
||||
struct generic_queue_handle *h = xQueue;
|
||||
if (h->type == MUTEX_REC) {
|
||||
osal_mutex_give(h->q);
|
||||
return pdTRUE;
|
||||
}
|
||||
return pdFALSE;
|
||||
}
|
||||
BaseType_t xSemaphoreTake( QueueHandle_t xQueue, TickType_t pvTask )
|
||||
{
|
||||
struct generic_queue_handle *h = xQueue;
|
||||
if (h->type == MUTEX) {
|
||||
osal_mutex_take(h->q);
|
||||
return pdTRUE;
|
||||
}
|
||||
return xQueueReceive(xQueue, &s_semaphore_data, portMAX_DELAY);
|
||||
}
|
||||
|
||||
|
||||
BaseType_t xSemaphoreTakeRecursive( QueueHandle_t xQueue, TickType_t pvTask )
|
||||
{
|
||||
struct generic_queue_handle *h = xQueue;
|
||||
if (h->type == MUTEX_REC) {
|
||||
osal_mutex_take(h->q);
|
||||
return pdTRUE;
|
||||
}
|
||||
return pdFALSE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void vQueueDelete( QueueHandle_t xQueue )
|
||||
{
|
||||
struct generic_queue_handle *h = xQueue;
|
||||
if (h->q) {
|
||||
if (h->type == MUTEX || h->type == MUTEX_REC) {
|
||||
osal_mutex_delete(h->q);
|
||||
} else {
|
||||
osal_queue_delete(h->q);
|
||||
}
|
||||
}
|
||||
free(xQueue);
|
||||
}
|
||||
|
||||
QueueHandle_t xSemaphoreCreateBinary(void)
|
||||
{
|
||||
QueueHandle_t sempaphore = xQueueCreate(1, 1);
|
||||
return sempaphore;
|
||||
}
|
||||
|
||||
QueueHandle_t xSemaphoreCreateMutex(void)
|
||||
{
|
||||
return (QueueHandle_t)create_generic_queue(MUTEX, 1, 1);
|
||||
}
|
||||
|
||||
QueueHandle_t xSemaphoreCreateRecursiveMutex(void)
|
||||
{
|
||||
return (QueueHandle_t)create_generic_queue(MUTEX_REC, 1, 1);
|
||||
}
|
||||
|
||||
|
||||
void vTaskDelete(TaskHandle_t *task)
|
||||
{
|
||||
if (task == NULL) {
|
||||
pthread_exit(0);
|
||||
}
|
||||
void *thread_rval = NULL;
|
||||
pthread_join((pthread_t)task, &thread_rval);
|
||||
}
|
||||
|
||||
void vTaskSuspend(void *task)
|
||||
{
|
||||
vTaskDelete(task);
|
||||
}
|
||||
|
||||
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 )
|
||||
{
|
||||
usleep(xTicksToDelay * 1000);
|
||||
}
|
||||
|
||||
void *pthread_task(void *params)
|
||||
{
|
||||
struct {
|
||||
void *const param;
|
||||
TaskFunction_t task;
|
||||
bool started;
|
||||
} *pthread_params = params;
|
||||
|
||||
void *const param = pthread_params->param;
|
||||
TaskFunction_t task = pthread_params->task;
|
||||
pthread_params->started = true;
|
||||
|
||||
task(param);
|
||||
|
||||
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)
|
||||
{
|
||||
xTaskCreate(pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pvCreatedTask);
|
||||
return pdTRUE;
|
||||
}
|
||||
|
||||
|
||||
BaseType_t xTaskCreate(TaskFunction_t pvTaskCode, const char *const pcName, const uint32_t usStackDepth, void *const pvParameters, UBaseType_t uxPriority, TaskHandle_t *const pvCreatedTask)
|
||||
{
|
||||
pthread_t new_thread = (pthread_t)NULL;
|
||||
pthread_attr_t attr;
|
||||
struct {
|
||||
void *const param;
|
||||
TaskFunction_t task;
|
||||
bool started;
|
||||
} pthread_params = { .param = pvParameters, .task = pvTaskCode};
|
||||
int res = pthread_attr_init(&attr);
|
||||
assert(res == 0);
|
||||
res = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
|
||||
assert(res == 0);
|
||||
res = pthread_create(&new_thread, &attr, pthread_task, &pthread_params);
|
||||
assert(res == 0);
|
||||
|
||||
if (pvCreatedTask) {
|
||||
*pvCreatedTask = (void *)new_thread;
|
||||
}
|
||||
|
||||
// just wait till the task started so we can unwind params from the stack
|
||||
while (pthread_params.started == false) {
|
||||
usleep(1000);
|
||||
}
|
||||
return pdTRUE;
|
||||
}
|
||||
|
||||
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 )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
TaskHandle_t xTaskGetCurrentTaskHandle(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EventGroupHandle_t xEventGroupCreate( void )
|
||||
{
|
||||
return osal_signal_create();
|
||||
}
|
||||
|
||||
void vEventGroupDelete( EventGroupHandle_t xEventGroup )
|
||||
{
|
||||
osal_signal_delete(xEventGroup);
|
||||
}
|
||||
|
||||
EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear )
|
||||
{
|
||||
return osal_signal_clear(xEventGroup, uxBitsToClear);
|
||||
}
|
||||
|
||||
EventBits_t xEventGroupGetBits( EventGroupHandle_t xEventGroup)
|
||||
{
|
||||
return osal_signal_get(xEventGroup);
|
||||
}
|
||||
|
||||
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 )
|
||||
{
|
||||
return osal_signal_wait(xEventGroup, uxBitsToWaitFor, xWaitForAllBits, xTicksToWait);
|
||||
}
|
@ -10,3 +10,4 @@
|
||||
|
||||
#define ESP_TASK_PRIO_MAX 25
|
||||
#define ESP_TASKD_EVENT_PRIO 5
|
||||
#define ESP_TASKD_EVENT_STACK 1024
|
@ -16,7 +16,9 @@
|
||||
typedef void *SemaphoreHandle_t;
|
||||
typedef void *QueueHandle_t;
|
||||
typedef void *TaskHandle_t;
|
||||
typedef void *EventGroupHandle_t;
|
||||
typedef uint32_t TickType_t;
|
||||
typedef TickType_t EventBits_t;
|
||||
|
||||
typedef void (*TaskFunction_t)( void * );
|
||||
typedef unsigned int UBaseType_t;
|
||||
@ -30,6 +32,5 @@ typedef int BaseType_t;
|
||||
|
||||
#define pdMS_TO_TICKS(tick) (tick)
|
||||
|
||||
uint32_t esp_get_free_heap_size(void);
|
||||
uint32_t esp_random(void);
|
||||
void vTaskSuspendAll(void);
|
@ -0,0 +1,6 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
@ -3,11 +3,4 @@
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
//
|
||||
// Created by david on 1/13/23.
|
||||
//
|
||||
|
||||
#ifndef _QUEUE_H_
|
||||
#define _QUEUE_H_
|
||||
|
||||
#endif //_QUEUE_H_
|
||||
#pragma once
|
@ -3,11 +3,4 @@
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
//
|
||||
// Created by david on 1/13/23.
|
||||
//
|
||||
|
||||
#ifndef _SEMAPHR_H_
|
||||
#define _SEMAPHR_H_
|
||||
|
||||
#endif //_SEMAPHR_H_
|
||||
#pragma once
|
@ -7,6 +7,10 @@
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define TaskHandle_t TaskHandle_t
|
||||
#define vSemaphoreDelete( xSemaphore ) vQueueDelete( ( QueueHandle_t ) ( xSemaphore ) )
|
||||
|
||||
@ -26,7 +30,7 @@ BaseType_t xTaskCreatePinnedToCore( TaskFunction_t pvTaskCode,
|
||||
TaskHandle_t *const pvCreatedTask,
|
||||
const BaseType_t xCoreID);
|
||||
|
||||
void xTaskCreate(TaskFunction_t pvTaskCode, const char *const pcName, const uint32_t usStackDepth, void *const pvParameters, UBaseType_t uxPriority, TaskHandle_t *const pvCreatedTask);
|
||||
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 );
|
||||
|
||||
@ -35,11 +39,16 @@ 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 xSemaphoreTake( QueueHandle_t xQueue, TickType_t pvTask );
|
||||
|
||||
BaseType_t xSemaphoreGiveRecursive( QueueHandle_t xQueue);
|
||||
|
||||
BaseType_t xSemaphoreTakeRecursive( QueueHandle_t xQueue, TickType_t pvTask );
|
||||
|
||||
void vTaskDelete(TaskHandle_t *task);
|
||||
|
||||
QueueHandle_t xQueueCreate( uint32_t uxQueueLength,
|
||||
@ -48,3 +57,27 @@ QueueHandle_t xQueueCreate( uint32_t uxQueueLength,
|
||||
uint32_t xQueueSend(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait);
|
||||
|
||||
uint32_t xQueueReceive(QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksToWait);
|
||||
|
||||
void vTaskSuspend(void *task);
|
||||
|
||||
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 xEventGroupGetBits( EventGroupHandle_t xEventGroup);
|
||||
|
||||
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup,
|
||||
const EventBits_t uxBitsToSet );
|
||||
|
||||
uint32_t xQueueSendToBack(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif //__cplusplus
|
109
common_components/linux_compat/freertos/osal/event_group.cpp
Normal file
109
common_components/linux_compat/freertos/osal/event_group.cpp
Normal file
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include "osal_api.h"
|
||||
|
||||
|
||||
class SignalGroup {
|
||||
|
||||
struct SignalGroupInternal {
|
||||
std::condition_variable notify;
|
||||
std::mutex m;
|
||||
uint32_t flags{ 0 };
|
||||
};
|
||||
|
||||
using SignalT = std::unique_ptr<SignalGroupInternal>;
|
||||
|
||||
public:
|
||||
|
||||
void set(uint32_t bits)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(event_group->m);
|
||||
event_group->flags |= bits;
|
||||
event_group->notify.notify_all();
|
||||
}
|
||||
|
||||
uint32_t get()
|
||||
{
|
||||
return event_group->flags;
|
||||
}
|
||||
|
||||
void clear(uint32_t bits)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(event_group->m);
|
||||
event_group->flags &= ~bits;
|
||||
event_group->notify.notify_all();
|
||||
}
|
||||
|
||||
// waiting for all and clearing if set
|
||||
bool wait(uint32_t flags, uint32_t time_ms)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(event_group->m);
|
||||
return event_group->notify.wait_for(lock, std::chrono::milliseconds(time_ms), [&] {
|
||||
if ((flags & event_group->flags) == flags)
|
||||
{
|
||||
event_group->flags &= ~flags;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// waiting for any bit, not clearing them
|
||||
bool wait_any(uint32_t flags, uint32_t time_ms)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(event_group->m);
|
||||
return event_group->notify.wait_for(lock, std::chrono::milliseconds(time_ms), [&] { return flags & event_group->flags; });
|
||||
}
|
||||
|
||||
private:
|
||||
SignalT event_group{std::make_unique<SignalGroupInternal>()};
|
||||
};
|
||||
|
||||
|
||||
void *osal_signal_create()
|
||||
{
|
||||
auto signal = new SignalGroup;
|
||||
return signal;
|
||||
}
|
||||
|
||||
void osal_signal_delete(void *s)
|
||||
{
|
||||
delete static_cast<SignalGroup *>(s);
|
||||
}
|
||||
|
||||
uint32_t osal_signal_clear(void *s, uint32_t bits)
|
||||
{
|
||||
auto signal = static_cast<SignalGroup *>(s);
|
||||
signal->clear(bits);
|
||||
return signal->get();
|
||||
}
|
||||
|
||||
uint32_t osal_signal_set(void *s, uint32_t bits)
|
||||
{
|
||||
auto signal = static_cast<SignalGroup *>(s);
|
||||
signal->set(bits);
|
||||
return signal->get();
|
||||
}
|
||||
|
||||
uint32_t osal_signal_get(void *s)
|
||||
{
|
||||
auto signal = static_cast<SignalGroup *>(s);
|
||||
return signal->get();
|
||||
}
|
||||
|
||||
uint32_t osal_signal_wait(void *s, uint32_t flags, bool all, uint32_t timeout)
|
||||
{
|
||||
auto signal = static_cast<SignalGroup *>(s);
|
||||
if (all) {
|
||||
signal->wait(flags, timeout);
|
||||
} else {
|
||||
signal->wait_any(flags, timeout);
|
||||
}
|
||||
return signal->get();
|
||||
}
|
31
common_components/linux_compat/freertos/osal/mutex.cpp
Normal file
31
common_components/linux_compat/freertos/osal/mutex.cpp
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <queue>
|
||||
#include <mutex>
|
||||
#include "osal_api.h"
|
||||
|
||||
void *osal_mutex_create()
|
||||
{
|
||||
auto mut = new std::recursive_mutex();
|
||||
return mut;
|
||||
}
|
||||
|
||||
void osal_mutex_delete(void *mut)
|
||||
{
|
||||
delete static_cast<std::recursive_mutex *>(mut);
|
||||
}
|
||||
|
||||
void osal_mutex_take(void *m)
|
||||
{
|
||||
auto mut = static_cast<std::recursive_mutex *>(m);
|
||||
mut->lock();
|
||||
}
|
||||
|
||||
void osal_mutex_give(void *m)
|
||||
{
|
||||
auto mut = static_cast<std::recursive_mutex *>(m);
|
||||
mut->unlock();
|
||||
}
|
34
common_components/linux_compat/freertos/osal/osal_api.h
Normal file
34
common_components/linux_compat/freertos/osal/osal_api.h
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// queue api
|
||||
void *osal_queue_create(void);
|
||||
void osal_queue_delete(void *q);
|
||||
bool osal_queue_send(void *q, uint8_t *data, size_t len);
|
||||
bool osal_queue_recv(void *q, uint8_t *data, size_t len, uint32_t ms);
|
||||
|
||||
// mutex api
|
||||
void *osal_mutex_create(void);
|
||||
void osal_mutex_delete(void *m);
|
||||
void osal_mutex_take(void *m);
|
||||
void osal_mutex_give(void *m);
|
||||
|
||||
// event groups
|
||||
void *osal_signal_create(void);
|
||||
void osal_signal_delete(void *s);
|
||||
uint32_t osal_signal_clear(void *s, uint32_t bits);
|
||||
uint32_t osal_signal_set(void *s, uint32_t bits);
|
||||
uint32_t osal_signal_get(void *s);
|
||||
uint32_t osal_signal_wait(void *s, uint32_t flags, bool all, uint32_t timeout);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
78
common_components/linux_compat/freertos/osal/queue.cpp
Normal file
78
common_components/linux_compat/freertos/osal/queue.cpp
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
#include <queue>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include <atomic>
|
||||
#include "osal_api.h"
|
||||
|
||||
template <class T>
|
||||
class Queue {
|
||||
public:
|
||||
void send(std::unique_ptr<T> t)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m);
|
||||
q.push(std::move(t));
|
||||
c.notify_one();
|
||||
}
|
||||
|
||||
std::unique_ptr<T> receive(std::chrono::milliseconds ms)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m);
|
||||
while (q.empty()) {
|
||||
if (c.wait_for(lock, ms) == std::cv_status::timeout) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
std::unique_ptr<T> val = std::move(q.front());
|
||||
q.pop();
|
||||
return val;
|
||||
}
|
||||
|
||||
private:
|
||||
std::queue<std::unique_ptr<T>> q{};
|
||||
mutable std::mutex m{};
|
||||
std::condition_variable c{};
|
||||
};
|
||||
|
||||
using item_t = std::vector<uint8_t>;
|
||||
|
||||
void *osal_queue_create(void)
|
||||
{
|
||||
auto *q = new Queue<item_t>();
|
||||
return q;
|
||||
}
|
||||
|
||||
void osal_queue_delete(void *q)
|
||||
{
|
||||
auto *queue = static_cast<Queue<item_t> *>(q);
|
||||
delete (queue);
|
||||
}
|
||||
|
||||
bool osal_queue_send(void *q, uint8_t *data, size_t len)
|
||||
{
|
||||
auto v = std::make_unique<item_t>(len);
|
||||
v->assign(data, data + len);
|
||||
auto queue = static_cast<Queue<item_t> *>(q);
|
||||
queue->send(std::move(v));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool osal_queue_recv(void *q, uint8_t *data, size_t len, uint32_t ms)
|
||||
{
|
||||
auto queue = static_cast<Queue<item_t> *>(q);
|
||||
auto v = queue->receive(std::chrono::milliseconds(ms));
|
||||
if (v != nullptr) {
|
||||
memcpy(data, (void *)v->data(), len);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
@ -6,8 +6,8 @@ Asio is a cross-platform C++ library, see https://think-async.com/Asio/. It prov
|
||||
|
||||
## Examples
|
||||
|
||||
Get started with example test :example:`examples <examples/..>`:
|
||||
Get started with examples [examples](https://github.com/espressif/esp-protocols/tree/master/components/asio/examples)
|
||||
|
||||
## Documentation
|
||||
|
||||
* View the full [html documentation](https://espressif.github.io/esp-protocols/asio/index.html)
|
||||
* View the full [html documentation](https://docs.espressif.com/projects/esp-protocols/asio/docs/latest/index.html)
|
||||
|
@ -1,26 +0,0 @@
|
||||
build-docs --target esp32 --language en
|
||||
|
||||
cp -rf _build/en/esp32/html .
|
||||
rm -rf _build __pycache__
|
||||
|
||||
# Modifes some version and target fields of index.html
|
||||
echo "<script type="text/javascript">
|
||||
window.onload =(function() {
|
||||
var myAnchor = document.getElementById('version-select');
|
||||
var mySpan = document.createElement('input');
|
||||
mySpan.setAttribute('type', 'text');
|
||||
mySpan.setAttribute('maxLength', '10');
|
||||
mySpan.value = 'latest';
|
||||
mySpan.setAttribute('disabled', true);
|
||||
myAnchor.parentNode.replaceChild(mySpan, myAnchor);
|
||||
|
||||
var myAnchor = document.getElementById('target-select');
|
||||
var mySpan = document.createElement('input');
|
||||
mySpan.setAttribute('type', 'text');
|
||||
mySpan.setAttribute('maxLength', '10');
|
||||
mySpan.value = 'all targets';
|
||||
mySpan.setAttribute('disabled', true);
|
||||
myAnchor.parentNode.replaceChild(mySpan, myAnchor);
|
||||
|
||||
})();
|
||||
</script>" >> html/index.html
|
8
components/esp_modem/.cz.yaml
Normal file
8
components/esp_modem/.cz.yaml
Normal file
@ -0,0 +1,8 @@
|
||||
---
|
||||
commitizen:
|
||||
bump_message: 'bump(modem): $current_version -> $new_version'
|
||||
pre_bump_hooks: python ../../ci/changelog.py esp_modem
|
||||
tag_format: modem-v$version
|
||||
version: 1.0.1
|
||||
version_files:
|
||||
- idf_component.yml
|
@ -1,5 +1,46 @@
|
||||
# Changelog
|
||||
|
||||
## [1.0.1](https://github.com/espressif/esp-protocols/commits/modem-v1.0.1)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Support UART clean build with IDF v5.2 ([e620eb5](https://github.com/espressif/esp-protocols/commit/e620eb5))
|
||||
- enable code coverage publishing to github pages ([4910e89](https://github.com/espressif/esp-protocols/commit/4910e89))
|
||||
- fix esp_modem build issue ([ab94566](https://github.com/espressif/esp-protocols/commit/ab94566))
|
||||
- Example to use 1.0.0 ([afb6930](https://github.com/espressif/esp-protocols/commit/afb6930))
|
||||
- Changelog to correctly pick references ([423e965](https://github.com/espressif/esp-protocols/commit/423e965))
|
||||
|
||||
### Updated
|
||||
|
||||
- docs(esp_modem): updated documents to show missed topics ([0534853](https://github.com/espressif/esp-protocols/commit/0534853))
|
||||
- docs(common): improving documentation ([ca3fce0](https://github.com/espressif/esp-protocols/commit/ca3fce0))
|
||||
|
||||
## [1.0.0](https://github.com/espressif/esp-protocols/commits/modem-v1.0.0)
|
||||
|
||||
### Major changes
|
||||
|
||||
- Enable DTE to redefine on_read() and write(cmd) directly ([DTE to support sending and receiving raw data](https://github.com/espressif/esp-protocols/commit/bf114d3))
|
||||
|
||||
### Features
|
||||
|
||||
- Add mqtt example in AT-only mode ([7547267](https://github.com/espressif/esp-protocols/commit/7547267))
|
||||
- DTE to support sending and receiving raw data ([bf114d3](https://github.com/espressif/esp-protocols/commit/bf114d3))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Changelog to correctly pick references ([c59e330](https://github.com/espressif/esp-protocols/commit/c59e330))
|
||||
- AT-only example: support MQTT over TLS on BG96 ([31d4323](https://github.com/espressif/esp-protocols/commit/31d4323))
|
||||
- AT-only example: initial adaptation to BG96 ([ceedcfc](https://github.com/espressif/esp-protocols/commit/ceedcfc))
|
||||
- warning in ap-2-pppos example when using lwip/napt ([bf32e45](https://github.com/espressif/esp-protocols/commit/bf32e45))
|
||||
- trigger PR jobs based on labels ([13eca12](https://github.com/espressif/esp-protocols/commit/13eca12))
|
||||
- Reintroduce missing CHANGELOGs ([200cbb3](https://github.com/espressif/esp-protocols/commit/200cbb3), [#235](https://github.com/espressif/esp-protocols/issues/235))
|
||||
- Use default UART CLK source ([d0814bf](https://github.com/espressif/esp-protocols/commit/d0814bf), [#241](https://github.com/espressif/esp-protocols/issues/241))
|
||||
- run CI build job for all targets ([a089e0d](https://github.com/espressif/esp-protocols/commit/a089e0d))
|
||||
|
||||
### Updated
|
||||
|
||||
- Update examples for USB v1.1 ([610372f](https://github.com/espressif/esp-protocols/commit/610372f))
|
||||
|
||||
|
||||
## [0.1.28](https://github.com/espressif/esp-protocols/commits/01c26c8)
|
||||
|
||||
|
@ -47,15 +47,3 @@ if(${target} STREQUAL "linux")
|
||||
# This is needed for ESP_LOGx() macros, as integer formats differ on ESP32(..) and x64
|
||||
set_target_properties(${COMPONENT_LIB} PROPERTIES COMPILE_FLAGS -Wno-format)
|
||||
endif()
|
||||
|
||||
if(CONFIG_GCOV_ENABLED)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --coverage -fprofile-arcs -ftest-coverage")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --coverage -fprofile-arcs -ftest-coverage")
|
||||
|
||||
|
||||
MARK_AS_ADVANCED(
|
||||
CMAKE_CXX_FLAGS_COVERAGE
|
||||
CMAKE_C_FLAGS_COVERAGE
|
||||
CMAKE_EXE_LINKER_FLAGS_COVERAGE
|
||||
CMAKE_SHARED_LINKER_FLAGS_COVERAGE )
|
||||
endif()
|
||||
|
@ -17,5 +17,5 @@ Get started with one of the examples:
|
||||
|
||||
## Documentation
|
||||
|
||||
* Continue with esp-modem [brief overview](docs/README.md)
|
||||
* View the full [html documentation](https://espressif.github.io/esp-protocols/esp_modem/index.html)
|
||||
* Continue with esp-modem [brief overview](https://github.com/espressif/esp-protocols/tree/master/docs/esp_modem/en/README.rst)
|
||||
* View the full [html documentation](https://docs.espressif.com/projects/esp-protocols/esp_modem/docs/latest/index.html)
|
||||
|
@ -1,92 +0,0 @@
|
||||
# ESP MODEM
|
||||
|
||||
This component is used to communicate with modems in the command mode (using AT commands), as well as the data mode
|
||||
(over PPPoS protocol).
|
||||
The modem device is modeled with a DCE (Data Communication Equipment) object, which is composed of:
|
||||
* DTE (Data Terminal Equipment), which abstracts the terminal (currently only UART implemented).
|
||||
* PPP Netif representing a network interface communicating with the DTE using PPP protocol.
|
||||
* Module abstracting the specific device model and its commands.
|
||||
|
||||
```
|
||||
+-----+
|
||||
| DTE |--+
|
||||
+-----+ | +-------+
|
||||
+-->| DCE |
|
||||
+-------+ | |o--- set_mode(command/data)
|
||||
| Module|--->| |
|
||||
+-------+ | |o--- send_commands
|
||||
+->| |
|
||||
+------+ | +-------+
|
||||
| PPP |--+
|
||||
| netif|------------------> network events
|
||||
+------+
|
||||
```
|
||||
|
||||
## Modem components
|
||||
### DCE
|
||||
|
||||
This is the basic operational unit of the esp_modem component, abstracting a specific module in software,
|
||||
which is basically configured by
|
||||
* the I/O communication media (UART), defined by the DTE configuration
|
||||
* the specific command library supported by the device model, defined with the module type
|
||||
* network interface configuration (PPPoS config in lwip)
|
||||
|
||||
After the object is created, the application interaction with the DCE is in
|
||||
* issuing specific commands to the modem
|
||||
* switching between data and command mode
|
||||
|
||||
### DTE
|
||||
Is an abstraction of the physical interface connected to the modem. Current implementation supports only UART
|
||||
|
||||
### PPP netif
|
||||
|
||||
Is used to attach the specific network interface to a network communication protocol used by the modem. Currently implementation supports only PPPoS protocol.
|
||||
|
||||
### Module
|
||||
|
||||
Abstraction of the specific modem device. Currently the component supports SIM800, BG96, SIM7600.
|
||||
|
||||
## Use cases
|
||||
|
||||
Users interact with the esp-modem using the DCE's interface, to basically
|
||||
* Switch between command and data mode to connect to the internet via cellular network.
|
||||
* Send various commands to the device (e.g. send SMS)
|
||||
|
||||
The applications typically register handlers for network events to receive notification on the network availability and
|
||||
IP address changes.
|
||||
|
||||
Common use cases of the esp-modem are also listed as the examples:
|
||||
* `examples/pppos_client` -- simple client which reads some module properties and switches to the data mode to connect to a public mqtt broker.
|
||||
* `examples/modem_console` -- is an example to exercise all possible module commands in a console application.
|
||||
* `examples/ap_to_pppos` -- this example focuses on the network connectivity of the esp-modem and provides a WiFi AP that forwards packets (and uses NAT) to and from the PPPoS connection.
|
||||
|
||||
## Extensibility
|
||||
|
||||
### CMUX
|
||||
|
||||
Implementation of virtual terminals is an experimental feature, which allows users to also issue commands in the data mode,
|
||||
after creating multiple virtual terminals, designating some of them solely to data mode, others solely to command mode.
|
||||
|
||||
### DTE's
|
||||
|
||||
Currently, we support only UART (and USB as a preview feature), but modern modules support other communication interfaces, such as USB, SPI.
|
||||
|
||||
### Other devices
|
||||
|
||||
Adding a new device is a must-have requirement for the esp-modem component. Different modules support different commands,
|
||||
or some commands might have a different implementation. Adding a new device means to provide a new implementation
|
||||
as a class derived from `GenericModule`, where we could add new commands or modify the existing ones.
|
||||
|
||||
## Configuration
|
||||
|
||||
Modem abstraction is configurable both compile-time and run-time.
|
||||
|
||||
### Component Kconfig
|
||||
|
||||
Compile-time configuration is provided using menuconfig. Please check the description for the CMUX mode configuration options.
|
||||
|
||||
### Runtime configuration
|
||||
|
||||
Is defined using standard configuration structures for `DTE` and `DCE` objects separately. Please find documentation of
|
||||
* :cpp:class:`esp_modem_dte_config_t`
|
||||
* :cpp:class:`esp_modem_dce_config_t`
|
@ -1,23 +0,0 @@
|
||||
# Cleanup the generated html
|
||||
rm -rf html
|
||||
|
||||
# Cleans example and test build dirs (to reduce the component size before upload)
|
||||
rm -rf ../examples/ap_to_pppos/build/ ../examples/simple_cmux_client/build/ ../examples/pppos_client/build/ ../examples/linux_modem/build/ ../examples/modem_console/build ../test/host_test/build/ ../test/target/build/
|
||||
|
||||
# Generate C++ API header of the DCE
|
||||
cat ../include/generate/esp_modem_command_declare.inc | clang++ -E -P -CC -xc++ -I../include -DGENERATE_DOCS - | sed -n '1,/DCE command documentation/!p' > esp_modem_dce.hpp
|
||||
|
||||
# Generate C API header of the modem_api.h
|
||||
cat ../include/generate/esp_modem_command_declare.inc | clang -E -P -CC -xc -I../include -DGENERATE_DOCS - | sed -n '1,/DCE command documentation/!p' > esp_modem_api_commands.h
|
||||
|
||||
# RST with links to C++ API
|
||||
cat ../include/generate/esp_modem_command_declare.inc | clang -E -P -xc -I../include -DGENERATE_DOCS -DGENERATE_RST_LINKS - | sed 's/NL/\n/g' > cxx_api_links.rst
|
||||
|
||||
# Run doxygen
|
||||
doxygen
|
||||
|
||||
# Generate the docs
|
||||
python -u -m sphinx.cmd.build -b html . html
|
||||
|
||||
# Cleanup the doxygen xml's and temporary headers
|
||||
rm -rf xml esp_modem_api_commands.h esp_modem_dce.hpp cxx_api_links.rst
|
@ -1,36 +0,0 @@
|
||||
# Internal design
|
||||
|
||||
## Design decisions
|
||||
|
||||
* Use C++ with additional C API
|
||||
|
||||
* Use exceptions
|
||||
- Use macro wrapper over `try-catch` blocks when exceptions off (use `abort()` if `THROW()`)
|
||||
|
||||
* Initializes and allocates in the constructor (might throw)
|
||||
- easier code with exceptions ON, with exceptions OFF alloc/init failures are not treated as runtime error (program aborts)
|
||||
- break down long initialization in constructor into more private methods
|
||||
|
||||
* Implements different devices using inheritance from `GenericModule`, which is the most general implementation of a common modem
|
||||
- Internally uses templates with device specialization (modeled as `DCE<SpecificModule>`) which could be used as well for some special cases,
|
||||
such as implantation of a minimal device (ModuleIf), add new AT commands (oOnly in compile time), or using the Module with DTE only (no DCE, no Netif) for sending AT commands without network
|
||||
|
||||
## DCE collaboration model
|
||||
|
||||
The diagram describes how the DCE class collaborates with DTE, PPP and the device abstraction
|
||||
|
||||

|
||||
|
||||
## Terminal inheritance
|
||||
|
||||
Terminal is a class which can read or write data, and can handle callbacks when data are available. UART specialization
|
||||
is provided implementing these method using the uart driver.
|
||||
|
||||
## CMUX terminal
|
||||
|
||||
The below diagram depicts the idea of using CMUX terminal mode using the CMuxInstance class which is a terminal
|
||||
(it implements the basic read/write methods) interfacing arbitrary number of virtual terminals,
|
||||
but at the same time it is also composed of CMux class, which consumes the original terminal and uses its read/write methods
|
||||
to multiplex the terminal.
|
||||
|
||||

|
@ -3,7 +3,7 @@ dependencies:
|
||||
## Required IDF version
|
||||
idf: ">=4.1.0"
|
||||
espressif/esp_modem:
|
||||
version: "^0.1.20"
|
||||
version: "^1.0.0"
|
||||
override_path: "../../../"
|
||||
espressif/esp_modem_usb_dte:
|
||||
version: "^1.1.0"
|
||||
|
@ -3,7 +3,7 @@ dependencies:
|
||||
## Required IDF version
|
||||
idf: ">=4.1.0"
|
||||
espressif/esp_modem:
|
||||
version: "^0.1.23"
|
||||
version: "^1.0.0"
|
||||
override_path: "../../../"
|
||||
espressif/esp_modem_usb_dte:
|
||||
version: "^1.1.0"
|
||||
|
@ -1,4 +1,4 @@
|
||||
version: "0.1.28"
|
||||
version: "1.0.1"
|
||||
description: esp modem
|
||||
url: https://github.com/espressif/esp-protocols/tree/master/components/esp_modem
|
||||
dependencies:
|
||||
|
@ -13,7 +13,7 @@
|
||||
// limitations under the License.
|
||||
#pragma once
|
||||
|
||||
#include "esp_modem_command_declare_helper.inc"
|
||||
#include "generate/esp_modem_command_declare_helper.inc"
|
||||
|
||||
|
||||
#define DECLARE_ALL_COMMAND_APIS(...) \
|
||||
|
@ -8,6 +8,11 @@
|
||||
#include "esp_modem_config.h"
|
||||
#include "uart_resource.hpp"
|
||||
|
||||
#ifndef UART_HW_FIFO_LEN
|
||||
// to build with IDF <= v5.1
|
||||
#define UART_HW_FIFO_LEN(uart_nr) UART_FIFO_LEN
|
||||
#endif
|
||||
|
||||
namespace esp_modem {
|
||||
|
||||
uart_resource::~uart_resource()
|
||||
@ -18,7 +23,7 @@ uart_resource::~uart_resource()
|
||||
}
|
||||
|
||||
uart_resource::uart_resource(const esp_modem_uart_term_config *config, QueueHandle_t *event_queue, int fd)
|
||||
: port(-1)
|
||||
: port(UART_NUM_MAX)
|
||||
{
|
||||
esp_err_t res;
|
||||
|
||||
@ -44,9 +49,9 @@ uart_resource::uart_resource(const esp_modem_uart_term_config *config, QueueHand
|
||||
ESP_MODEM_THROW_IF_ERROR(res, "config uart gpio failed");
|
||||
/* Set flow control threshold */
|
||||
if (config->flow_control == ESP_MODEM_FLOW_CONTROL_HW) {
|
||||
res = uart_set_hw_flow_ctrl(config->port_num, UART_HW_FLOWCTRL_CTS_RTS, UART_FIFO_LEN - 8);
|
||||
res = uart_set_hw_flow_ctrl(config->port_num, UART_HW_FLOWCTRL_CTS_RTS, UART_HW_FIFO_LEN(config->port_num) - 8);
|
||||
} else if (config->flow_control == ESP_MODEM_FLOW_CONTROL_SW) {
|
||||
res = uart_set_sw_flow_ctrl(config->port_num, true, 8, UART_FIFO_LEN - 8);
|
||||
res = uart_set_sw_flow_ctrl(config->port_num, true, 8, UART_HW_FIFO_LEN(config->port_num) - 8);
|
||||
}
|
||||
ESP_MODEM_THROW_IF_ERROR(res, "config uart flow control failed");
|
||||
|
||||
|
@ -13,15 +13,3 @@ idf_component_get_property(esp_modem esp_modem COMPONENT_LIB)
|
||||
target_compile_definitions(${esp_modem} PRIVATE "-DCONFIG_COMPILER_CXX_EXCEPTIONS")
|
||||
target_compile_definitions(${esp_modem} PRIVATE "-DCONFIG_IDF_TARGET_LINUX")
|
||||
target_link_options(${esp_modem} INTERFACE -fsanitize=address -fsanitize=undefined)
|
||||
|
||||
if(CONFIG_GCOV_ENABLED)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --coverage -fprofile-arcs -ftest-coverage")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --coverage -fprofile-arcs -ftest-coverage")
|
||||
|
||||
|
||||
MARK_AS_ADVANCED(
|
||||
CMAKE_CXX_FLAGS_COVERAGE
|
||||
CMAKE_C_FLAGS_COVERAGE
|
||||
CMAKE_EXE_LINKER_FLAGS_COVERAGE
|
||||
CMAKE_SHARED_LINKER_FLAGS_COVERAGE )
|
||||
endif()
|
||||
|
@ -12,3 +12,12 @@ set_target_properties(${COMPONENT_LIB} PROPERTIES
|
||||
CXX_EXTENSIONS ON
|
||||
)
|
||||
target_compile_definitions(${COMPONENT_LIB} PRIVATE "-DCONFIG_IDF_TARGET_LINUX")
|
||||
|
||||
if(CONFIG_GCOV_ENABLED)
|
||||
target_compile_options(${COMPONENT_LIB} PUBLIC --coverage -fprofile-arcs -ftest-coverage)
|
||||
target_link_options(${COMPONENT_LIB} PUBLIC --coverage -fprofile-arcs -ftest-coverage)
|
||||
|
||||
idf_component_get_property(esp_modem esp_modem COMPONENT_LIB)
|
||||
target_compile_options(${esp_modem} PUBLIC --coverage -fprofile-arcs -ftest-coverage)
|
||||
target_link_options(${esp_modem} PUBLIC --coverage -fprofile-arcs -ftest-coverage)
|
||||
endif()
|
||||
|
13
components/esp_mqtt_cxx/README.md
Normal file
13
components/esp_mqtt_cxx/README.md
Normal file
@ -0,0 +1,13 @@
|
||||
# esp_mqtt_cxx
|
||||
|
||||
[](https://components.espressif.com/components/espressif/esp_mqtt_cxx)
|
||||
|
||||
The ESP MQTT client is a wrapper over the esp_mqtt client with the goal of providing a higher level API.
|
||||
|
||||
## Examples
|
||||
|
||||
Get started with [examples](https://github.com/espressif/esp-protocols/tree/master/components/esp_mqtt_cxx/examples)
|
||||
|
||||
## Documentation
|
||||
|
||||
* View the full [html documentation](https://docs.espressif.com/projects/esp-protocols/docs/latest/esp_mqtt_cxx/index.html)
|
@ -1,26 +0,0 @@
|
||||
build-docs --target esp32 --language en
|
||||
|
||||
cp -rf _build/en/esp32/html .
|
||||
rm -rf _build __pycache__
|
||||
|
||||
# Modifes some version and target fields of index.html
|
||||
echo "<script type="text/javascript">
|
||||
window.onload =(function() {
|
||||
var myAnchor = document.getElementById('version-select');
|
||||
var mySpan = document.createElement('input');
|
||||
mySpan.setAttribute('type', 'text');
|
||||
mySpan.setAttribute('maxLength', '10');
|
||||
mySpan.value = 'latest';
|
||||
mySpan.setAttribute('disabled', true);
|
||||
myAnchor.parentNode.replaceChild(mySpan, myAnchor);
|
||||
|
||||
var myAnchor = document.getElementById('target-select');
|
||||
var mySpan = document.createElement('input');
|
||||
mySpan.setAttribute('type', 'text');
|
||||
mySpan.setAttribute('maxLength', '10');
|
||||
mySpan.value = 'all targets';
|
||||
mySpan.setAttribute('disabled', true);
|
||||
myAnchor.parentNode.replaceChild(mySpan, myAnchor);
|
||||
|
||||
})();
|
||||
</script>" >> html/index.html
|
@ -92,8 +92,35 @@ void config_client_credentials(esp_mqtt_client_config_t &mqtt_client_cfg, Client
|
||||
{
|
||||
mqtt_client_cfg.credentials.authentication.password = password.data.c_str();
|
||||
},
|
||||
[](ClientCertificate const & certificate) {},
|
||||
[](SecureElement const & enable_secure_element) {},
|
||||
[&mqtt_client_cfg](ClientCertificate const & certificate)
|
||||
{
|
||||
std::visit(overloaded{
|
||||
[&mqtt_client_cfg](PEM const & pem)
|
||||
{
|
||||
mqtt_client_cfg.credentials.authentication.certificate = pem.data;
|
||||
}, [&mqtt_client_cfg](DER const & der)
|
||||
{
|
||||
mqtt_client_cfg.credentials.authentication.certificate = der.data;
|
||||
mqtt_client_cfg.credentials.authentication.certificate_len = der.len;
|
||||
}}, certificate.certificate);
|
||||
std::visit(overloaded{
|
||||
[&mqtt_client_cfg](PEM const & pem)
|
||||
{
|
||||
mqtt_client_cfg.credentials.authentication.key = pem.data;
|
||||
}, [&mqtt_client_cfg](DER const & der)
|
||||
{
|
||||
mqtt_client_cfg.credentials.authentication.key = der.data;
|
||||
mqtt_client_cfg.credentials.authentication.key_len = der.len;
|
||||
}}, certificate.key);
|
||||
if (certificate.key_password.has_value()) {
|
||||
mqtt_client_cfg.credentials.authentication.key_password = certificate.key_password.value().data.c_str();
|
||||
mqtt_client_cfg.credentials.authentication.key_password_len = static_cast<int>(certificate.key_password.value().data.size());
|
||||
}
|
||||
},
|
||||
[&mqtt_client_cfg](SecureElement const & enable_secure_element)
|
||||
{
|
||||
mqtt_client_cfg.credentials.authentication.use_secure_element = true;
|
||||
},
|
||||
[]([[maybe_unused ]]auto & unknown)
|
||||
{
|
||||
static_assert(always_false<decltype(unknown)>, "Missing type handler for variant handler");
|
||||
|
8
components/esp_websocket_client/.cz.yaml
Normal file
8
components/esp_websocket_client/.cz.yaml
Normal file
@ -0,0 +1,8 @@
|
||||
---
|
||||
commitizen:
|
||||
bump_message: 'bump(websocket): $current_version -> $new_version'
|
||||
pre_bump_hooks: python ../../ci/changelog.py esp_websocket_client
|
||||
tag_format: websocket-v$version
|
||||
version: 1.0.1
|
||||
version_files:
|
||||
- idf_component.yml
|
@ -1,5 +1,20 @@
|
||||
# Changelog
|
||||
|
||||
## [1.0.1](https://github.com/espressif/esp-protocols/commits/websocket-v1.0.1)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- esp_websocket_client client allow sending 0 byte packets ([b5177cb](https://github.com/espressif/esp-protocols/commit/b5177cb))
|
||||
- Cleaned up printf/format warnings (-Wno-format) ([e085826](https://github.com/espressif/esp-protocols/commit/e085826))
|
||||
- Added unit tests to CI + minor fix to pass it ([c974c14](https://github.com/espressif/esp-protocols/commit/c974c14))
|
||||
- Reintroduce missing CHANGELOGs ([200cbb3](https://github.com/espressif/esp-protocols/commit/200cbb3), [#235](https://github.com/espressif/esp-protocols/issues/235))
|
||||
|
||||
### Updated
|
||||
|
||||
- docs(common): updated component and example links ([f48d9b2](https://github.com/espressif/esp-protocols/commit/f48d9b2))
|
||||
- docs(common): improving documentation ([ca3fce0](https://github.com/espressif/esp-protocols/commit/ca3fce0))
|
||||
- Fix weird error message spacings ([8bb207e](https://github.com/espressif/esp-protocols/commit/8bb207e))
|
||||
|
||||
## [1.0.0](https://github.com/espressif/esp-protocols/commits/996fef7)
|
||||
|
||||
### Updated
|
||||
|
@ -10,4 +10,3 @@ idf_component_register(SRCS "esp_websocket_client.c"
|
||||
INCLUDE_DIRS "include"
|
||||
REQUIRES lwip esp-tls tcp_transport http_parser
|
||||
PRIV_REQUIRES esp_timer esp_event)
|
||||
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")
|
||||
|
@ -6,8 +6,8 @@ The `esp-websocket_client` component is a managed component for `esp-idf` that c
|
||||
|
||||
## Examples
|
||||
|
||||
Get started with example test [Example](examples/README.md):
|
||||
Get started with example test [example](https://github.com/espressif/esp-protocols/tree/master/components/esp_websocket_client/examples):
|
||||
|
||||
## Documentation
|
||||
|
||||
* View the full [html documentation](https://espressif.github.io/esp-protocols/esp_websocket_client/index.html)
|
||||
* View the full [html documentation](https://docs.espressif.com/projects/esp-protocols/esp_websocket_client/docs/latest/index.html)
|
||||
|
@ -1,26 +0,0 @@
|
||||
build-docs --target esp32 --language en
|
||||
|
||||
cp -rf _build/en/esp32/html .
|
||||
rm -rf _build __pycache__
|
||||
|
||||
# Modifes some version and target fields of index.html
|
||||
echo "<script type="text/javascript">
|
||||
window.onload =(function() {
|
||||
var myAnchor = document.getElementById('version-select');
|
||||
var mySpan = document.createElement('input');
|
||||
mySpan.setAttribute('type', 'text');
|
||||
mySpan.setAttribute('maxLength', '10');
|
||||
mySpan.value = 'latest';
|
||||
mySpan.setAttribute('disabled', true);
|
||||
myAnchor.parentNode.replaceChild(mySpan, myAnchor);
|
||||
|
||||
var myAnchor = document.getElementById('target-select');
|
||||
var mySpan = document.createElement('input');
|
||||
mySpan.setAttribute('type', 'text');
|
||||
mySpan.setAttribute('maxLength', '10');
|
||||
mySpan.value = 'all targets';
|
||||
mySpan.setAttribute('disabled', true);
|
||||
myAnchor.parentNode.replaceChild(mySpan, myAnchor);
|
||||
|
||||
})();
|
||||
</script>" >> html/index.html
|
@ -424,7 +424,9 @@ static void destroy_and_free_resources(esp_websocket_client_handle_t client)
|
||||
free(client->if_name);
|
||||
}
|
||||
esp_websocket_client_destroy_config(client);
|
||||
esp_transport_list_destroy(client->transport_list);
|
||||
if (client->transport_list) {
|
||||
esp_transport_list_destroy(client->transport_list);
|
||||
}
|
||||
vQueueDelete(client->lock);
|
||||
free(client->tx_buffer);
|
||||
free(client->rx_buffer);
|
||||
@ -848,8 +850,8 @@ static void esp_websocket_client_task(void *pv)
|
||||
esp_tls_error_handle_t error_handle = esp_transport_get_error_handle(client->transport);
|
||||
client->error_handle.esp_ws_handshake_status_code = esp_transport_ws_get_upgrade_request_status(client->transport);
|
||||
if (error_handle) {
|
||||
esp_websocket_client_error(client, "esp_transport_connect() failed with %d,\
|
||||
transport_error=%s, tls_error_code=%i, tls_flags=%i, esp_ws_handshake_status_code=%d, errno=%d",
|
||||
esp_websocket_client_error(client, "esp_transport_connect() failed with %d, "
|
||||
"transport_error=%s, tls_error_code=%i, tls_flags=%i, esp_ws_handshake_status_code=%d, errno=%d",
|
||||
result, esp_err_to_name(error_handle->last_error), error_handle->esp_tls_error_code,
|
||||
error_handle->esp_tls_flags, client->error_handle.esp_ws_handshake_status_code, errno);
|
||||
} else {
|
||||
@ -1098,14 +1100,13 @@ int esp_websocket_client_send_with_opcode(esp_websocket_client_handle_t client,
|
||||
int wlen = 0, widx = 0;
|
||||
int ret = ESP_FAIL;
|
||||
|
||||
if (client == NULL || len < 0 ||
|
||||
(opcode != WS_TRANSPORT_OPCODES_CLOSE && (data == NULL || len <= 0))) {
|
||||
if (client == NULL || len < 0 || (data == NULL && len > 0)) {
|
||||
ESP_LOGE(TAG, "Invalid arguments");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
if (xSemaphoreTakeRecursive(client->lock, timeout) != pdPASS) {
|
||||
ESP_LOGE(TAG, "Could not lock ws-client within %d timeout", timeout);
|
||||
ESP_LOGE(TAG, "Could not lock ws-client within %" PRIu32 " timeout", timeout);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,2 @@
|
||||
idf_component_register(SRCS "websocket_example.c"
|
||||
INCLUDE_DIRS ".")
|
||||
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")
|
||||
|
@ -170,7 +170,7 @@ static void websocket_app_start(void)
|
||||
void app_main(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "[APP] Startup..");
|
||||
ESP_LOGI(TAG, "[APP] Free memory: %d bytes", esp_get_free_heap_size());
|
||||
ESP_LOGI(TAG, "[APP] Free memory: %" PRIu32 " bytes", esp_get_free_heap_size());
|
||||
ESP_LOGI(TAG, "[APP] IDF version: %s", esp_get_idf_version());
|
||||
esp_log_level_set("*", ESP_LOG_INFO);
|
||||
esp_log_level_set("websocket_client", ESP_LOG_DEBUG);
|
||||
|
@ -1,4 +1,4 @@
|
||||
version: "1.0.0"
|
||||
version: "1.0.1"
|
||||
description: esp websocket client
|
||||
url: https://github.com/espressif/esp-protocols/tree/master/components/esp_websocket_client
|
||||
dependencies:
|
||||
|
@ -254,6 +254,9 @@ int esp_websocket_client_send_text(esp_websocket_client_handle_t client, const c
|
||||
* @param[in] len The length
|
||||
* @param[in] timeout Write data timeout in RTOS ticks
|
||||
*
|
||||
* Notes:
|
||||
* - In order to send a zero payload, data and len should be set to NULL/0
|
||||
*
|
||||
* @return
|
||||
* - Number of data was sent
|
||||
* - (-1) if any errors
|
||||
|
@ -1,2 +1,8 @@
|
||||
idf_component_register(SRC_DIRS "."
|
||||
PRIV_REQUIRES cmock test_utils esp_websocket_client)
|
||||
# This is the project CMakeLists.txt file for the test subproject
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
set(EXTRA_COMPONENT_DIRS ../../esp_websocket_client
|
||||
"$ENV{IDF_PATH}/tools/unit-test-app/components")
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(websocket_unit_test)
|
||||
|
4
components/esp_websocket_client/test/main/CMakeLists.txt
Normal file
4
components/esp_websocket_client/test/main/CMakeLists.txt
Normal file
@ -0,0 +1,4 @@
|
||||
idf_component_register(SRCS "test_websocket_client.c"
|
||||
REQUIRES test_utils
|
||||
INCLUDE_DIRS "."
|
||||
PRIV_REQUIRES unity esp_websocket_client esp_event)
|
@ -13,19 +13,36 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <esp_websocket_client.h>
|
||||
|
||||
#include "esp_event.h"
|
||||
#include "unity.h"
|
||||
#include "test_utils.h"
|
||||
|
||||
#include "unity_fixture.h"
|
||||
#include "memory_checks.h"
|
||||
|
||||
static void test_leak_setup(const char *file, long line)
|
||||
TEST_GROUP(websocket);
|
||||
|
||||
TEST_SETUP(websocket)
|
||||
{
|
||||
printf("%s:%ld\n", file, line);
|
||||
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 1, 0)
|
||||
/* IDF v5.0 runs some lazy inits within printf()
|
||||
* This test sets the leak threshold to 0, so we need to call printf()
|
||||
* before recording the heap size in test_utils_record_free_mem()
|
||||
*/
|
||||
printf("TEST_SETUP: websocket\n");
|
||||
#endif
|
||||
test_utils_record_free_mem();
|
||||
TEST_ESP_OK(test_utils_set_leak_level(0, ESP_LEAK_TYPE_CRITICAL, ESP_COMP_LEAK_GENERAL));
|
||||
}
|
||||
|
||||
TEST_CASE("websocket init and deinit", "[websocket][leaks=0]")
|
||||
TEST_TEAR_DOWN(websocket)
|
||||
{
|
||||
test_utils_finish_and_evaluate_leaks(0, 0);
|
||||
}
|
||||
|
||||
|
||||
TEST(websocket, websocket_init_deinit)
|
||||
{
|
||||
test_leak_setup(__FILE__, __LINE__);
|
||||
const esp_websocket_client_config_t websocket_cfg = {
|
||||
// no connection takes place, but the uri has to be valid for init() to succeed
|
||||
.uri = "ws://echo.websocket.org",
|
||||
@ -35,9 +52,8 @@ TEST_CASE("websocket init and deinit", "[websocket][leaks=0]")
|
||||
esp_websocket_client_destroy(client);
|
||||
}
|
||||
|
||||
TEST_CASE("websocket init with invalid url", "[websocket][leaks=0]")
|
||||
TEST(websocket, websocket_init_invalid_url)
|
||||
{
|
||||
test_leak_setup(__FILE__, __LINE__);
|
||||
const esp_websocket_client_config_t websocket_cfg = {
|
||||
.uri = "INVALID",
|
||||
};
|
||||
@ -45,12 +61,23 @@ TEST_CASE("websocket init with invalid url", "[websocket][leaks=0]")
|
||||
TEST_ASSERT_NULL(client);
|
||||
}
|
||||
|
||||
TEST_CASE("websocket set url with invalid url", "[websocket][leaks=0]")
|
||||
TEST(websocket, websocket_set_invalid_url)
|
||||
{
|
||||
test_leak_setup(__FILE__, __LINE__);
|
||||
const esp_websocket_client_config_t websocket_cfg = {};
|
||||
esp_websocket_client_handle_t client = esp_websocket_client_init(&websocket_cfg);
|
||||
TEST_ASSERT_NOT_EQUAL(NULL, client);
|
||||
TEST_ASSERT_NOT_EQUAL(ESP_OK, esp_websocket_client_set_uri(client, "INVALID"));
|
||||
esp_websocket_client_destroy(client);
|
||||
}
|
||||
|
||||
TEST_GROUP_RUNNER(websocket)
|
||||
{
|
||||
RUN_TEST_CASE(websocket, websocket_init_deinit)
|
||||
RUN_TEST_CASE(websocket, websocket_init_invalid_url)
|
||||
RUN_TEST_CASE(websocket, websocket_set_invalid_url)
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
UNITY_MAIN(websocket);
|
||||
}
|
8
components/esp_websocket_client/test/pytest_websocket.py
Normal file
8
components/esp_websocket_client/test/pytest_websocket.py
Normal file
@ -0,0 +1,8 @@
|
||||
# SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from pytest_embedded import Dut
|
||||
|
||||
|
||||
def test_websocket(dut: Dut) -> None:
|
||||
dut.expect_unity_test_output()
|
3
components/esp_websocket_client/test/sdkconfig.ci
Normal file
3
components/esp_websocket_client/test/sdkconfig.ci
Normal file
@ -0,0 +1,3 @@
|
||||
CONFIG_IDF_TARGET="esp32"
|
||||
CONFIG_UNITY_ENABLE_FIXTURE=y
|
||||
CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=n
|
2
components/esp_websocket_client/test/sdkconfig.defaults
Normal file
2
components/esp_websocket_client/test/sdkconfig.defaults
Normal file
@ -0,0 +1,2 @@
|
||||
CONFIG_UNITY_ENABLE_FIXTURE=y
|
||||
CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=n
|
11
components/mdns/.build-test-rules.yml
Normal file
11
components/mdns/.build-test-rules.yml
Normal file
@ -0,0 +1,11 @@
|
||||
components/mdns/examples:
|
||||
disable:
|
||||
- if: IDF_TARGET in ["esp32h2"]
|
||||
|
||||
components/mdns/tests/unit_test:
|
||||
disable:
|
||||
- if: IDF_TARGET in ["esp32h2"]
|
||||
|
||||
components/mdns/tests/test_apps:
|
||||
disable:
|
||||
- if: IDF_TARGET in ["esp32h2"]
|
@ -3,6 +3,6 @@ commitizen:
|
||||
bump_message: 'bump(mdns): $current_version -> $new_version'
|
||||
pre_bump_hooks: python ../../ci/changelog.py mdns
|
||||
tag_format: mdns-v$version
|
||||
version: 1.0.9
|
||||
version: 1.2.0
|
||||
version_files:
|
||||
- idf_component.yml
|
||||
|
@ -1,5 +1,47 @@
|
||||
# Changelog
|
||||
|
||||
## [1.2.0](https://github.com/espressif/esp-protocols/commits/mdns-v1.2.0)
|
||||
|
||||
### Features
|
||||
|
||||
- add an API for setting address to a delegated host ([ddc3eb6](https://github.com/espressif/esp-protocols/commit/ddc3eb6))
|
||||
- Add support for lwip build under linux ([588465d](https://github.com/espressif/esp-protocols/commit/588465d))
|
||||
- Allow for adding a delegated host with no address ([c562461](https://github.com/espressif/esp-protocols/commit/c562461))
|
||||
- Add APIs for looking up self hosted services and getting the self hostname ([f0df12d](https://github.com/espressif/esp-protocols/commit/f0df12d))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Refactor freertos linux compat layers ([79a0e57](https://github.com/espressif/esp-protocols/commit/79a0e57))
|
||||
- Fix delegated service PTR response ([cab0e1d](https://github.com/espressif/esp-protocols/commit/cab0e1d))
|
||||
- Added unit tests to CI + minor fix to pass it ([c974c14](https://github.com/espressif/esp-protocols/commit/c974c14))
|
||||
|
||||
### Updated
|
||||
|
||||
- docs: update documentation links ([4de5298](https://github.com/espressif/esp-protocols/commit/4de5298))
|
||||
|
||||
## [1.1.0](https://github.com/espressif/esp-protocols/commits/mdns-v1.1.0)
|
||||
|
||||
### Features
|
||||
|
||||
- Decouple main module from mdns-networking ([d238e93](https://github.com/espressif/esp-protocols/commit/d238e93))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Use idf-build-apps package for building mdns ([1a0a41f](https://github.com/espressif/esp-protocols/commit/1a0a41f))
|
||||
- socket networking to init interfaces properly ([ee9b04f](https://github.com/espressif/esp-protocols/commit/ee9b04f))
|
||||
- Removed unused internal lock from mdns_server struct ([a06fb77](https://github.com/espressif/esp-protocols/commit/a06fb77))
|
||||
- Resolve conflicts only on self hosted items ([e69a9eb](https://github.com/espressif/esp-protocols/commit/e69a9eb), [#185](https://github.com/espressif/esp-protocols/issues/185))
|
||||
- Fix memory issues reported by valgrind ([0a682e7](https://github.com/espressif/esp-protocols/commit/0a682e7))
|
||||
|
||||
### Updated
|
||||
|
||||
- docs(common): updated component and example links ([f48d9b2](https://github.com/espressif/esp-protocols/commit/f48d9b2))
|
||||
- Add APIs to look up delegated services ([87dcd7d](https://github.com/espressif/esp-protocols/commit/87dcd7d))
|
||||
- Fix deadly mdns crash ([4fa3023](https://github.com/espressif/esp-protocols/commit/4fa3023))
|
||||
- docs(common): improving documentation ([ca3fce0](https://github.com/espressif/esp-protocols/commit/ca3fce0))
|
||||
- append all ipv6 address in mdns answer ([5ed3e9a](https://github.com/espressif/esp-protocols/commit/5ed3e9a))
|
||||
- test(mdns): Host tests to use IDF's esp_event_stub ([537d170](https://github.com/espressif/esp-protocols/commit/537d170))
|
||||
|
||||
## [1.0.9](https://github.com/espressif/esp-protocols/commits/mdns-v1.0.9)
|
||||
|
||||
### Features
|
||||
|
@ -6,7 +6,7 @@ endif()
|
||||
|
||||
idf_build_get_property(target IDF_TARGET)
|
||||
if(${target} STREQUAL "linux")
|
||||
set(dependencies esp_event esp_netif_linux esp_timer_linux esp_system)
|
||||
set(dependencies esp_netif_linux esp_timer esp_system)
|
||||
set(srcs "mdns.c" ${MDNS_NETWORKING})
|
||||
else()
|
||||
set(dependencies lwip console esp_netif)
|
||||
|
@ -27,6 +27,13 @@ menu "mDNS"
|
||||
higher than priorities of system tasks. Compile time warning/error
|
||||
would be emitted if the chosen task priority were too high.
|
||||
|
||||
config MDNS_ACTION_QUEUE_LEN
|
||||
int "Maximum actions pending to the server"
|
||||
range 8 64
|
||||
default 16
|
||||
help
|
||||
Allows setting the length of mDNS action queue.
|
||||
|
||||
config MDNS_TASK_STACK_SIZE
|
||||
int "mDNS task stack size"
|
||||
default 4096
|
||||
|
@ -6,9 +6,9 @@ mDNS is a multicast UDP service that is used to provide local network service an
|
||||
|
||||
## Examples
|
||||
|
||||
Get started with example test [Example](examples/README.md):
|
||||
Get started with example test [Example](https://github.com/espressif/esp-protocols/tree/master/components/mdns/examples):
|
||||
|
||||
## Documentation
|
||||
|
||||
* View the full [documentation(English)](https://espressif.github.io/esp-protocols/mdns/en/index.html)
|
||||
* View the full [documentation(Chinese)](https://espressif.github.io/esp-protocols/mdns/zh_CN/index.html)
|
||||
* View the full [documentation(English)](https://docs.espressif.com/projects/esp-protocols/mdns/docs/latest/en/index.html)
|
||||
* View the full [documentation(Chinese)](https://docs.espressif.com/projects/esp-protocols/mdns/docs/latest/zh_CN/index.html)
|
||||
|
@ -1,28 +0,0 @@
|
||||
build-docs --target esp32 --language en
|
||||
build-docs --target esp32 --language zh_CN
|
||||
|
||||
cp -rf _build/en/esp32/html html_en
|
||||
cp -rf _build/zh_CN/esp32/html html_zh_CN
|
||||
rm -rf _build __pycache__ tee
|
||||
|
||||
# Modifes some version and target fields of index.html
|
||||
echo "<script type="text/javascript">
|
||||
window.onload =(function() {
|
||||
var myAnchor = document.getElementById('version-select');
|
||||
var mySpan = document.createElement('input');
|
||||
mySpan.setAttribute('type', 'text');
|
||||
mySpan.setAttribute('maxLength', '10');
|
||||
mySpan.value = 'latest';
|
||||
mySpan.setAttribute('disabled', true);
|
||||
myAnchor.parentNode.replaceChild(mySpan, myAnchor);
|
||||
|
||||
var myAnchor = document.getElementById('target-select');
|
||||
var mySpan = document.createElement('input');
|
||||
mySpan.setAttribute('type', 'text');
|
||||
mySpan.setAttribute('maxLength', '10');
|
||||
mySpan.value = 'all targets';
|
||||
mySpan.setAttribute('disabled', true);
|
||||
myAnchor.parentNode.replaceChild(mySpan, myAnchor);
|
||||
|
||||
})();
|
||||
</script>" | tee -a html_en/index.html html_zh_CN/index.html > /dev/null
|
@ -93,8 +93,10 @@ static void mdns_print_results(mdns_result_t *results)
|
||||
mdns_ip_addr_t *a = NULL;
|
||||
int i = 1, t;
|
||||
while (r) {
|
||||
printf("%d: Interface: %s, Type: %s, TTL: %u\n", i++, esp_netif_get_ifkey(r->esp_netif), ip_protocol_str[r->ip_protocol],
|
||||
r->ttl);
|
||||
if (r->esp_netif) {
|
||||
printf("%d: Interface: %s, Type: %s, TTL: %u\n", i++, esp_netif_get_ifkey(r->esp_netif),
|
||||
ip_protocol_str[r->ip_protocol], r->ttl);
|
||||
}
|
||||
if (r->instance_name) {
|
||||
printf(" PTR : %s.%s.%s\n", r->instance_name, r->service_type, r->proto);
|
||||
}
|
||||
@ -140,6 +142,44 @@ static void query_mdns_service(const char *service_name, const char *proto)
|
||||
mdns_query_results_free(results);
|
||||
}
|
||||
|
||||
#if CONFIG_MDNS_PUBLISH_DELEGATE_HOST
|
||||
static void lookup_mdns_delegated_service(const char *service_name, const char *proto)
|
||||
{
|
||||
ESP_LOGI(TAG, "Lookup delegated service: %s.%s.local", service_name, proto);
|
||||
|
||||
mdns_result_t *results = NULL;
|
||||
esp_err_t err = mdns_lookup_delegated_service(NULL, service_name, proto, 20, &results);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Lookup Failed: %s", esp_err_to_name(err));
|
||||
return;
|
||||
}
|
||||
if (!results) {
|
||||
ESP_LOGW(TAG, "No results found!");
|
||||
return;
|
||||
}
|
||||
|
||||
mdns_print_results(results);
|
||||
mdns_query_results_free(results);
|
||||
}
|
||||
#endif // CONFIG_MDNS_PUBLISH_DELEGATE_HOST
|
||||
|
||||
static void lookup_mdns_selfhosted_service(const char *service_name, const char *proto)
|
||||
{
|
||||
ESP_LOGI(TAG, "Lookup selfhosted service: %s.%s.local", service_name, proto);
|
||||
mdns_result_t *results = NULL;
|
||||
esp_err_t err = mdns_lookup_selfhosted_service(NULL, service_name, proto, 20, &results);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Lookup Failed: %s", esp_err_to_name(err));
|
||||
return;
|
||||
}
|
||||
if (!results) {
|
||||
ESP_LOGW(TAG, "No results found!");
|
||||
return;
|
||||
}
|
||||
mdns_print_results(results);
|
||||
mdns_query_results_free(results);
|
||||
}
|
||||
|
||||
static bool check_and_print_result(mdns_search_once_t *search)
|
||||
{
|
||||
// Check if any result is available
|
||||
@ -234,6 +274,10 @@ static void check_button(void)
|
||||
query_mdns_service("_smb", "_tcp");
|
||||
query_mdns_service("_ftp", "_tcp");
|
||||
query_mdns_service("_nfs", "_tcp");
|
||||
#if CONFIG_MDNS_PUBLISH_DELEGATE_HOST
|
||||
lookup_mdns_delegated_service("_http", "_tcp");
|
||||
#endif // CONFIG_MDNS_PUBLISH_DELEGATE_HOST
|
||||
lookup_mdns_selfhosted_service("_http", "_tcp");
|
||||
}
|
||||
old_level = new_level;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
version: "1.0.9"
|
||||
version: "1.2.0"
|
||||
description: mDNS
|
||||
url: https://github.com/espressif/esp-protocols/tree/master/components/mdns
|
||||
dependencies:
|
||||
|
@ -26,7 +26,6 @@ extern "C" {
|
||||
*/
|
||||
typedef struct mdns_search_once_s mdns_search_once_t;
|
||||
|
||||
|
||||
typedef enum {
|
||||
MDNS_EVENT_ENABLE_IP4 = 1 << 1,
|
||||
MDNS_EVENT_ENABLE_IP6 = 1 << 2,
|
||||
@ -129,6 +128,19 @@ void mdns_free(void);
|
||||
*/
|
||||
esp_err_t mdns_hostname_set(const char *hostname);
|
||||
|
||||
/**
|
||||
* @brief Get the hostname for mDNS server
|
||||
*
|
||||
* @param hostname pointer to the hostname, it should be allocated
|
||||
* and hold at least MDNS_NAME_BUF_LEN chars
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_ERR_INVALID_STATE when mdns is not initialized
|
||||
*/
|
||||
esp_err_t mdns_hostname_get(char *hostname);
|
||||
|
||||
/**
|
||||
* @brief Adds a hostname and address to be delegated
|
||||
* A/AAAA queries will be replied for the hostname and
|
||||
@ -146,6 +158,21 @@ esp_err_t mdns_hostname_set(const char *hostname);
|
||||
*/
|
||||
esp_err_t mdns_delegate_hostname_add(const char *hostname, const mdns_ip_addr_t *address_list);
|
||||
|
||||
/**
|
||||
* @brief Set the address to a delegated hostname
|
||||
*
|
||||
* @param hostname Hostname to set
|
||||
* @param address_list The IP address list of the host
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_INVALID_STATE mDNS is not running
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_ERR_NO_MEM memory error
|
||||
*
|
||||
*/
|
||||
esp_err_t mdns_delegate_hostname_set_address(const char *hostname, const mdns_ip_addr_t *address_list);
|
||||
|
||||
/**
|
||||
* @brief Remove a delegated hostname
|
||||
* All the services added to this host will also be removed.
|
||||
@ -248,7 +275,6 @@ esp_err_t mdns_service_add_for_host(const char *instance_name, const char *servi
|
||||
*/
|
||||
bool mdns_service_exists(const char *service_type, const char *proto, const char *hostname);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Check whether a service has been added.
|
||||
*
|
||||
@ -687,6 +713,42 @@ esp_err_t mdns_query_srv(const char *instance_name, const char *service_type, co
|
||||
*/
|
||||
esp_err_t mdns_query_txt(const char *instance_name, const char *service_type, const char *proto, uint32_t timeout, mdns_result_t **result);
|
||||
|
||||
/**
|
||||
* @brief Look up delegated services.
|
||||
*
|
||||
* @param instance instance name (NULL for uncertain instance)
|
||||
* @param service_type service type (_http, _ftp, etc)
|
||||
* @param proto service protocol (_tcp, _udp)
|
||||
* @param max_results maximum results to be collected
|
||||
* @param result pointer to the result of the search
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_INVALID_STATE mDNS is not running
|
||||
* - ESP_ERR_NO_MEM memory error
|
||||
* - ESP_ERR_INVALID_ARG parameter error
|
||||
*/
|
||||
esp_err_t mdns_lookup_delegated_service(const char *instance, const char *service_type, const char *proto, size_t max_results,
|
||||
mdns_result_t **result);
|
||||
|
||||
/**
|
||||
* @brief Look up self hosted services.
|
||||
*
|
||||
* @param instance instance name (NULL for uncertain instance)
|
||||
* @param service_type service type (_http, _ftp, etc)
|
||||
* @param proto service protocol (_tcp, _udp)
|
||||
* @param max_results maximum results to be collected
|
||||
* @param result pointer to the result of the search
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_INVALID_STATE mDNS is not running
|
||||
* - ESP_ERR_NO_MEM memory error
|
||||
* - ESP_ERR_INVALID_ARG parameter error
|
||||
*/
|
||||
esp_err_t mdns_lookup_selfhosted_service(const char *instance, const char *service_type, const char *proto, size_t max_results,
|
||||
mdns_result_t **result);
|
||||
|
||||
/**
|
||||
* @brief Query mDNS for A record
|
||||
*
|
||||
|
@ -678,7 +678,7 @@ static uint16_t append_fqdn_dots(uint8_t *packet, uint16_t *index, const char *n
|
||||
char *end = host;
|
||||
char *start = host;
|
||||
do {
|
||||
end = memchr(start, '.', len);
|
||||
end = memchr(start, '.', host + len - start);
|
||||
end = end ? end : host + len;
|
||||
int part_len = end - start;
|
||||
if (!append_single_str(packet, index, start, part_len)) {
|
||||
@ -733,6 +733,7 @@ search_next:
|
||||
//read the destination into name and compare
|
||||
name.parts = 0;
|
||||
name.sub = 0;
|
||||
name.invalid = false;
|
||||
name.host[0] = 0;
|
||||
name.service[0] = 0;
|
||||
name.proto[0] = 0;
|
||||
@ -1357,7 +1358,7 @@ static uint8_t _mdns_append_answer(uint8_t *packet, uint16_t *index, mdns_out_an
|
||||
} else if (answer->type == MDNS_TYPE_A) {
|
||||
if (answer->host == &_mdns_self_host) {
|
||||
esp_netif_ip_info_t if_ip_info;
|
||||
if (!_mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V4].pcb && _mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V4].state != PCB_DUP) {
|
||||
if (!mdns_is_netif_ready(tcpip_if, MDNS_IP_PROTOCOL_V4) && _mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V4].state != PCB_DUP) {
|
||||
return 0;
|
||||
}
|
||||
if (esp_netif_get_ip_info(_mdns_get_esp_netif(tcpip_if), &if_ip_info)) {
|
||||
@ -1384,32 +1385,39 @@ static uint8_t _mdns_append_answer(uint8_t *packet, uint16_t *index, mdns_out_an
|
||||
#if CONFIG_LWIP_IPV6
|
||||
else if (answer->type == MDNS_TYPE_AAAA) {
|
||||
if (answer->host == &_mdns_self_host) {
|
||||
struct esp_ip6_addr if_ip6;
|
||||
if (!_mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V6].pcb && _mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V6].state != PCB_DUP) {
|
||||
struct esp_ip6_addr if_ip6s[NETIF_IPV6_MAX_NUMS];
|
||||
uint8_t count = 0;
|
||||
if (!mdns_is_netif_ready(tcpip_if, MDNS_IP_PROTOCOL_V6) && _mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V6].state != PCB_DUP) {
|
||||
return 0;
|
||||
}
|
||||
if (esp_netif_get_ip6_linklocal(_mdns_get_esp_netif(tcpip_if), &if_ip6)) {
|
||||
return 0;
|
||||
}
|
||||
if (_ipv6_address_is_zero(if_ip6)) {
|
||||
return 0;
|
||||
}
|
||||
if (_mdns_append_aaaa_record(packet, index, _mdns_server->hostname, (uint8_t *)if_ip6.addr, answer->flush, answer->bye) <= 0) {
|
||||
return 0;
|
||||
count = esp_netif_get_all_ip6(_mdns_get_esp_netif(tcpip_if), if_ip6s);
|
||||
assert(count <= NETIF_IPV6_MAX_NUMS);
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (_ipv6_address_is_zero(if_ip6s[i])) {
|
||||
return 0;
|
||||
}
|
||||
if (_mdns_append_aaaa_record(packet, index, _mdns_server->hostname, (uint8_t *)if_ip6s[i].addr,
|
||||
answer->flush, answer->bye) <= 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (!_mdns_if_is_dup(tcpip_if)) {
|
||||
return 1;
|
||||
return count;
|
||||
}
|
||||
mdns_if_t other_if = _mdns_get_other_if (tcpip_if);
|
||||
if (esp_netif_get_ip6_linklocal(_mdns_get_esp_netif(other_if), &if_ip6)) {
|
||||
return 1;
|
||||
|
||||
mdns_if_t other_if = _mdns_get_other_if(tcpip_if);
|
||||
struct esp_ip6_addr other_ip6;
|
||||
if (esp_netif_get_ip6_linklocal(_mdns_get_esp_netif(other_if), &other_ip6)) {
|
||||
return count;
|
||||
}
|
||||
if (_mdns_append_aaaa_record(packet, index, _mdns_server->hostname, (uint8_t *)if_ip6.addr, answer->flush, answer->bye) > 0) {
|
||||
return 2;
|
||||
if (_mdns_append_aaaa_record(packet, index, _mdns_server->hostname, (uint8_t *)other_ip6.addr,
|
||||
answer->flush, answer->bye) > 0) {
|
||||
return 1 + count;
|
||||
}
|
||||
return 1;
|
||||
return count;
|
||||
} else if (answer->host != NULL) {
|
||||
return _mdns_append_host_answer(packet, index, answer->host, ESP_IPADDR_TYPE_V6, answer->flush, answer->bye);
|
||||
return _mdns_append_host_answer(packet, index, answer->host, ESP_IPADDR_TYPE_V6, answer->flush,
|
||||
answer->bye);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -1606,18 +1614,20 @@ static void _mdns_remove_scheduled_answer(mdns_if_t tcpip_if, mdns_ip_protocol_t
|
||||
while (q) {
|
||||
if (q->tcpip_if == tcpip_if && q->ip_protocol == ip_protocol && q->distributed) {
|
||||
mdns_out_answer_t *a = q->answers;
|
||||
if (a->type == type && a->service == service->service) {
|
||||
q->answers = q->answers->next;
|
||||
free(a);
|
||||
} else {
|
||||
while (a->next) {
|
||||
if (a->next->type == type && a->next->service == service->service) {
|
||||
mdns_out_answer_t *b = a->next;
|
||||
a->next = b->next;
|
||||
free(b);
|
||||
break;
|
||||
if (a) {
|
||||
if (a->type == type && a->service == service->service) {
|
||||
q->answers = q->answers->next;
|
||||
free(a);
|
||||
} else {
|
||||
while (a->next) {
|
||||
if (a->next->type == type && a->next->service == service->service) {
|
||||
mdns_out_answer_t *b = a->next;
|
||||
a->next = b->next;
|
||||
free(b);
|
||||
break;
|
||||
}
|
||||
a = a->next;
|
||||
}
|
||||
a = a->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1715,13 +1725,16 @@ static bool _mdns_create_answer_from_service(mdns_tx_packet_t *packet, mdns_serv
|
||||
mdns_parsed_question_t *question, bool shared, bool send_flush)
|
||||
{
|
||||
mdns_host_item_t *host = mdns_get_host_item(service->hostname);
|
||||
bool is_delegated = (host != &_mdns_self_host);
|
||||
if (question->type == MDNS_TYPE_PTR || question->type == MDNS_TYPE_ANY) {
|
||||
// According to RFC6763-section12.1, for DNS-SD, SRV, TXT and all address records
|
||||
// should be included in additional records.
|
||||
if (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_PTR, service, NULL, false, false) ||
|
||||
!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_SRV, service, NULL, send_flush, false) ||
|
||||
!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_TXT, service, NULL, send_flush, false) ||
|
||||
!_mdns_alloc_answer(shared ? &packet->additional : &packet->answers, MDNS_TYPE_A, service, host, send_flush,
|
||||
!_mdns_alloc_answer(is_delegated ? &packet->additional : &packet->answers, MDNS_TYPE_SRV, service, NULL, send_flush, false) ||
|
||||
!_mdns_alloc_answer(is_delegated ? &packet->additional : &packet->answers, MDNS_TYPE_TXT, service, NULL, send_flush, false) ||
|
||||
!_mdns_alloc_answer((shared || is_delegated) ? &packet->additional : &packet->answers, MDNS_TYPE_A, service, host, send_flush,
|
||||
false) ||
|
||||
!_mdns_alloc_answer(shared ? &packet->additional : &packet->answers, MDNS_TYPE_AAAA, service, host,
|
||||
!_mdns_alloc_answer((shared || is_delegated) ? &packet->additional : &packet->answers, MDNS_TYPE_AAAA, service, host,
|
||||
send_flush, false)) {
|
||||
return false;
|
||||
}
|
||||
@ -2266,7 +2279,7 @@ static void _mdns_send_bye(mdns_srv_item_t **services, size_t len, bool include_
|
||||
|
||||
for (i = 0; i < MDNS_MAX_INTERFACES; i++) {
|
||||
for (j = 0; j < MDNS_IP_PROTOCOL_MAX; j++) {
|
||||
if (_mdns_server->interfaces[i].pcbs[j].pcb && _mdns_server->interfaces[i].pcbs[j].state == PCB_RUNNING) {
|
||||
if (mdns_is_netif_ready(i, j) && _mdns_server->interfaces[i].pcbs[j].state == PCB_RUNNING) {
|
||||
_mdns_pcb_send_bye((mdns_if_t)i, (mdns_ip_protocol_t)j, services, len, include_ip);
|
||||
}
|
||||
}
|
||||
@ -2280,7 +2293,7 @@ static void _mdns_announce_pcb(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protoco
|
||||
{
|
||||
mdns_pcb_t *_pcb = &_mdns_server->interfaces[tcpip_if].pcbs[ip_protocol];
|
||||
size_t i;
|
||||
if (_pcb->pcb) {
|
||||
if (mdns_is_netif_ready(tcpip_if, ip_protocol)) {
|
||||
if (PCB_STATE_IS_PROBING(_pcb)) {
|
||||
_mdns_init_pcb_probe(tcpip_if, ip_protocol, services, len, include_ip);
|
||||
} else if (PCB_STATE_IS_ANNOUNCING(_pcb)) {
|
||||
@ -2324,7 +2337,7 @@ static void _mdns_probe_all_pcbs(mdns_srv_item_t **services, size_t len, bool pr
|
||||
uint8_t i, j;
|
||||
for (i = 0; i < MDNS_MAX_INTERFACES; i++) {
|
||||
for (j = 0; j < MDNS_IP_PROTOCOL_MAX; j++) {
|
||||
if (_mdns_server->interfaces[i].pcbs[j].pcb) {
|
||||
if (mdns_is_netif_ready(i, j)) {
|
||||
mdns_pcb_t *_pcb = &_mdns_server->interfaces[i].pcbs[j];
|
||||
if (clear_old_probe) {
|
||||
free(_pcb->probe_services);
|
||||
@ -2619,7 +2632,7 @@ static void _mdns_remove_scheduled_service_packets(mdns_service_t *service)
|
||||
|
||||
|
||||
mdns_pcb_t *_pcb = &_mdns_server->interfaces[q->tcpip_if].pcbs[q->ip_protocol];
|
||||
if (_pcb->pcb) {
|
||||
if (mdns_is_netif_ready(q->tcpip_if, q->ip_protocol)) {
|
||||
if (PCB_STATE_IS_PROBING(_pcb)) {
|
||||
uint8_t i;
|
||||
//check if we are probing this service
|
||||
@ -2820,6 +2833,22 @@ static int _mdns_check_txt_collision(mdns_service_t *service, const uint8_t *dat
|
||||
return 0;//same
|
||||
}
|
||||
|
||||
static esp_err_t mdns_pcb_deinit_local(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_proto)
|
||||
{
|
||||
esp_err_t err = _mdns_pcb_deinit(tcpip_if, ip_proto);
|
||||
mdns_pcb_t *_pcb = &_mdns_server->interfaces[tcpip_if].pcbs[ip_proto];
|
||||
if (_pcb == NULL || err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
free(_pcb->probe_services);
|
||||
_pcb->state = PCB_OFF;
|
||||
_pcb->probe_ip = false;
|
||||
_pcb->probe_services = NULL;
|
||||
_pcb->probe_services_len = 0;
|
||||
_pcb->probe_running = false;
|
||||
_pcb->failed_probes = 0;
|
||||
return ESP_OK;
|
||||
}
|
||||
/**
|
||||
* @brief Set interface as duplicate if another is found on the same subnet
|
||||
*/
|
||||
@ -2831,11 +2860,11 @@ static void _mdns_dup_interface(mdns_if_t tcpip_if)
|
||||
return; // no other interface found
|
||||
}
|
||||
for (i = 0; i < MDNS_IP_PROTOCOL_MAX; i++) {
|
||||
if (_mdns_server->interfaces[other_if].pcbs[i].pcb) {
|
||||
if (mdns_is_netif_ready(other_if, i)) {
|
||||
//stop this interface and mark as dup
|
||||
if (_mdns_server->interfaces[tcpip_if].pcbs[i].pcb) {
|
||||
if (mdns_is_netif_ready(tcpip_if, i)) {
|
||||
_mdns_clear_pcb_tx_queue_head(tcpip_if, i);
|
||||
_mdns_pcb_deinit(tcpip_if, i);
|
||||
mdns_pcb_deinit_local(tcpip_if, i);
|
||||
}
|
||||
_mdns_server->interfaces[tcpip_if].pcbs[i].state = PCB_DUP;
|
||||
_mdns_announce_pcb(other_if, i, NULL, 0, true);
|
||||
@ -2964,6 +2993,27 @@ static void free_address_list(mdns_ip_addr_t *address_list)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static bool _mdns_delegate_hostname_set_address(const char *hostname, mdns_ip_addr_t *address_list)
|
||||
{
|
||||
if (!_str_null_or_empty(_mdns_server->hostname) &&
|
||||
strcasecmp(hostname, _mdns_server->hostname) == 0) {
|
||||
return false;
|
||||
}
|
||||
mdns_host_item_t *host = _mdns_host_list;
|
||||
while (host != NULL) {
|
||||
if (strcasecmp(hostname, host->hostname) == 0) {
|
||||
// free previous address list
|
||||
free_address_list(host->address_list);
|
||||
// set current address list to the host
|
||||
host->address_list = address_list;
|
||||
return true;
|
||||
}
|
||||
host = host->next;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static mdns_ip_addr_t *copy_address_list(const mdns_ip_addr_t *address_list)
|
||||
{
|
||||
mdns_ip_addr_t *head = NULL;
|
||||
@ -3058,6 +3108,29 @@ static bool _mdns_name_is_discovery(mdns_name_t *name, uint16_t type)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if the parsed name is self-hosted, i.e. we should resolve conflicts
|
||||
*/
|
||||
static bool _mdns_name_is_selfhosted(mdns_name_t *name)
|
||||
{
|
||||
if (_str_null_or_empty(_mdns_server->hostname)) { // self-hostname needs to be defined
|
||||
return false;
|
||||
}
|
||||
|
||||
// hostname only -- check if selfhosted name
|
||||
if (_str_null_or_empty(name->service) && _str_null_or_empty(name->proto) &&
|
||||
strcasecmp(name->host, _mdns_server->hostname) == 0 ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// service -- check if selfhosted service
|
||||
mdns_srv_item_t *srv = _mdns_get_service_item(name->service, name->proto, NULL);
|
||||
if (srv && strcasecmp(_mdns_server->hostname, srv->service->hostname) == 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if the parsed name is ours (matches service or host name)
|
||||
*/
|
||||
@ -3666,7 +3739,7 @@ void mdns_parse_packet(mdns_rx_packet_t *packet)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool is_selfhosted = _mdns_name_is_selfhosted(name);
|
||||
if (!_mdns_parse_fqdn(data, data_ptr + MDNS_SRV_FQDN_OFFSET, name, len)) {
|
||||
continue;//error
|
||||
}
|
||||
@ -3694,6 +3767,9 @@ void mdns_parse_packet(mdns_rx_packet_t *packet)
|
||||
_mdns_remove_scheduled_answer(packet->tcpip_if, packet->ip_protocol, type, service);
|
||||
continue;
|
||||
}
|
||||
if (!is_selfhosted) {
|
||||
continue;
|
||||
}
|
||||
//detect collision (-1=won, 0=none, 1=lost)
|
||||
int col = 0;
|
||||
if (mdns_class > 1) {
|
||||
@ -3784,6 +3860,9 @@ void mdns_parse_packet(mdns_rx_packet_t *packet)
|
||||
_mdns_remove_parsed_question(parsed_packet, type, service);
|
||||
continue;
|
||||
}
|
||||
if (!_mdns_name_is_selfhosted(name)) {
|
||||
continue;
|
||||
}
|
||||
//detect collision (-1=won, 0=none, 1=lost)
|
||||
int col = 0;
|
||||
if (mdns_class > 1) {
|
||||
@ -3818,6 +3897,9 @@ void mdns_parse_packet(mdns_rx_packet_t *packet)
|
||||
_mdns_remove_parsed_question(parsed_packet, type, NULL);
|
||||
continue;
|
||||
}
|
||||
if (!_mdns_name_is_selfhosted(name)) {
|
||||
continue;
|
||||
}
|
||||
//detect collision (-1=won, 0=none, 1=lost)
|
||||
int col = 0;
|
||||
if (mdns_class > 1) {
|
||||
@ -3868,6 +3950,9 @@ void mdns_parse_packet(mdns_rx_packet_t *packet)
|
||||
_mdns_remove_parsed_question(parsed_packet, type, NULL);
|
||||
continue;
|
||||
}
|
||||
if (!_mdns_name_is_selfhosted(name)) {
|
||||
continue;
|
||||
}
|
||||
//detect collision (-1=won, 0=none, 1=lost)
|
||||
int col = 0;
|
||||
if (mdns_class > 1) {
|
||||
@ -3940,8 +4025,9 @@ clear_rx_packet:
|
||||
*/
|
||||
void _mdns_enable_pcb(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol)
|
||||
{
|
||||
if (!_mdns_server->interfaces[tcpip_if].pcbs[ip_protocol].pcb) {
|
||||
if (!mdns_is_netif_ready(tcpip_if, ip_protocol)) {
|
||||
if (_mdns_pcb_init(tcpip_if, ip_protocol)) {
|
||||
_mdns_server->interfaces[tcpip_if].pcbs[ip_protocol].failed_probes = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -3955,9 +4041,9 @@ void _mdns_disable_pcb(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol)
|
||||
{
|
||||
_mdns_clean_netif_ptr(tcpip_if);
|
||||
|
||||
if (_mdns_server->interfaces[tcpip_if].pcbs[ip_protocol].pcb) {
|
||||
if (mdns_is_netif_ready(tcpip_if, ip_protocol)) {
|
||||
_mdns_clear_pcb_tx_queue_head(tcpip_if, ip_protocol);
|
||||
_mdns_pcb_deinit(tcpip_if, ip_protocol);
|
||||
mdns_pcb_deinit_local(tcpip_if, ip_protocol);
|
||||
mdns_if_t other_if = _mdns_get_other_if (tcpip_if);
|
||||
if (other_if != MDNS_MAX_INTERFACES && _mdns_server->interfaces[other_if].pcbs[ip_protocol].state == PCB_DUP) {
|
||||
_mdns_server->interfaces[other_if].pcbs[ip_protocol].state = PCB_OFF;
|
||||
@ -4625,7 +4711,7 @@ static mdns_tx_packet_t *_mdns_create_search_packet(mdns_search_once_t *search,
|
||||
static void _mdns_search_send_pcb(mdns_search_once_t *search, mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol)
|
||||
{
|
||||
mdns_tx_packet_t *packet = NULL;
|
||||
if (_mdns_server->interfaces[tcpip_if].pcbs[ip_protocol].pcb && _mdns_server->interfaces[tcpip_if].pcbs[ip_protocol].state > PCB_INIT) {
|
||||
if (mdns_is_netif_ready(tcpip_if, ip_protocol) && _mdns_server->interfaces[tcpip_if].pcbs[ip_protocol].state > PCB_INIT) {
|
||||
packet = _mdns_create_search_packet(search, tcpip_if, ip_protocol);
|
||||
if (!packet) {
|
||||
return;
|
||||
@ -4780,6 +4866,7 @@ static void _mdns_free_action(mdns_action_t *action)
|
||||
case ACTION_RX_HANDLE:
|
||||
_mdns_packet_free(action->data.rx_handle.packet);
|
||||
break;
|
||||
case ACTION_DELEGATE_HOSTNAME_SET_ADDR:
|
||||
case ACTION_DELEGATE_HOSTNAME_ADD:
|
||||
free((char *)action->data.delegate_hostname.hostname);
|
||||
free_address_list(action->data.delegate_hostname.address_list);
|
||||
@ -5000,6 +5087,13 @@ static void _mdns_execute_action(mdns_action_t *action)
|
||||
free_address_list(action->data.delegate_hostname.address_list);
|
||||
}
|
||||
break;
|
||||
case ACTION_DELEGATE_HOSTNAME_SET_ADDR:
|
||||
if (!_mdns_delegate_hostname_set_address(action->data.delegate_hostname.hostname,
|
||||
action->data.delegate_hostname.address_list)) {
|
||||
free_address_list(action->data.delegate_hostname.address_list);
|
||||
}
|
||||
free((char *)action->data.delegate_hostname.hostname);
|
||||
break;
|
||||
case ACTION_DELEGATE_HOSTNAME_REMOVE:
|
||||
_mdns_delegate_hostname_remove(action->data.delegate_hostname.hostname);
|
||||
free((char *)action->data.delegate_hostname.hostname);
|
||||
@ -5348,16 +5442,10 @@ esp_err_t mdns_init(void)
|
||||
s_esp_netifs[i].netif = NULL;
|
||||
}
|
||||
|
||||
_mdns_server->lock = xSemaphoreCreateMutex();
|
||||
if (!_mdns_server->lock) {
|
||||
err = ESP_ERR_NO_MEM;
|
||||
goto free_server;
|
||||
}
|
||||
|
||||
_mdns_server->action_queue = xQueueCreate(MDNS_ACTION_QUEUE_LEN, sizeof(mdns_action_t *));
|
||||
if (!_mdns_server->action_queue) {
|
||||
err = ESP_ERR_NO_MEM;
|
||||
goto free_lock;
|
||||
goto free_server;
|
||||
}
|
||||
|
||||
_mdns_server->action_sema = xSemaphoreCreateBinary();
|
||||
@ -5424,8 +5512,6 @@ free_event_handlers:
|
||||
vSemaphoreDelete(_mdns_server->action_sema);
|
||||
free_queue:
|
||||
vQueueDelete(_mdns_server->action_queue);
|
||||
free_lock:
|
||||
vSemaphoreDelete(_mdns_server->lock);
|
||||
free_server:
|
||||
free(_mdns_server);
|
||||
_mdns_server = NULL;
|
||||
@ -5447,7 +5533,7 @@ void mdns_free(void)
|
||||
_mdns_service_task_stop();
|
||||
for (i = 0; i < MDNS_MAX_INTERFACES; i++) {
|
||||
for (j = 0; j < MDNS_IP_PROTOCOL_MAX; j++) {
|
||||
_mdns_pcb_deinit(i, j);
|
||||
mdns_pcb_deinit_local(i, j);
|
||||
}
|
||||
}
|
||||
free((char *)_mdns_server->hostname);
|
||||
@ -5473,7 +5559,6 @@ void mdns_free(void)
|
||||
free(h);
|
||||
}
|
||||
vSemaphoreDelete(_mdns_server->action_sema);
|
||||
vSemaphoreDelete(_mdns_server->lock);
|
||||
free(_mdns_server);
|
||||
_mdns_server = NULL;
|
||||
}
|
||||
@ -5508,12 +5593,23 @@ esp_err_t mdns_hostname_set(const char *hostname)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t mdns_hostname_get(char *hostname)
|
||||
{
|
||||
if (!_mdns_server || !hostname) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
MDNS_SERVICE_LOCK();
|
||||
strncpy(hostname, _mdns_server->hostname, strnlen(_mdns_server->hostname, MDNS_NAME_BUF_LEN));
|
||||
MDNS_SERVICE_UNLOCK();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t mdns_delegate_hostname_add(const char *hostname, const mdns_ip_addr_t *address_list)
|
||||
{
|
||||
if (!_mdns_server) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
if (_str_null_or_empty(hostname) || strlen(hostname) > (MDNS_NAME_BUF_LEN - 1) || address_list == NULL) {
|
||||
if (_str_null_or_empty(hostname) || strlen(hostname) > (MDNS_NAME_BUF_LEN - 1)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
char *new_hostname = strndup(hostname, MDNS_NAME_BUF_LEN - 1);
|
||||
@ -5567,6 +5663,36 @@ esp_err_t mdns_delegate_hostname_remove(const char *hostname)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t mdns_delegate_hostname_set_address(const char *hostname, const mdns_ip_addr_t *address_list)
|
||||
{
|
||||
if (!_mdns_server) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
if (_str_null_or_empty(hostname) || strlen(hostname) > (MDNS_NAME_BUF_LEN - 1)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
char *new_hostname = strndup(hostname, MDNS_NAME_BUF_LEN - 1);
|
||||
if (!new_hostname) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
mdns_action_t *action = (mdns_action_t *)malloc(sizeof(mdns_action_t));
|
||||
if (!action) {
|
||||
HOOK_MALLOC_FAILED;
|
||||
free(new_hostname);
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
action->type = ACTION_DELEGATE_HOSTNAME_SET_ADDR;
|
||||
action->data.delegate_hostname.hostname = new_hostname;
|
||||
action->data.delegate_hostname.address_list = copy_address_list(address_list);
|
||||
if (xQueueSend(_mdns_server->action_queue, &action, (TickType_t)0) != pdPASS) {
|
||||
free(new_hostname);
|
||||
free(action);
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
bool mdns_hostname_exists(const char *hostname)
|
||||
{
|
||||
return _hostname_is_ours(hostname);
|
||||
@ -5685,6 +5811,142 @@ bool mdns_service_exists_with_instance(const char *instance, const char *service
|
||||
return _mdns_get_service_item_instance(instance, service_type, proto, hostname) != NULL;
|
||||
}
|
||||
|
||||
static mdns_txt_item_t *_copy_mdns_txt_items(mdns_txt_linked_item_t *items, uint8_t **txt_value_len, size_t *txt_count)
|
||||
{
|
||||
mdns_txt_item_t *ret = NULL;
|
||||
size_t ret_index = 0;
|
||||
for (mdns_txt_linked_item_t *tmp = items; tmp != NULL; tmp = tmp->next) {
|
||||
ret_index++;
|
||||
}
|
||||
*txt_count = ret_index;
|
||||
ret = (mdns_txt_item_t *)calloc(ret_index, sizeof(mdns_txt_item_t));
|
||||
*txt_value_len = (uint8_t *)calloc(ret_index, sizeof(uint8_t));
|
||||
if (!ret || !(*txt_value_len)) {
|
||||
HOOK_MALLOC_FAILED;
|
||||
goto handle_error;
|
||||
}
|
||||
ret_index = 0;
|
||||
for (mdns_txt_linked_item_t *tmp = items; tmp != NULL; tmp = tmp->next) {
|
||||
size_t key_len = strlen(tmp->key);
|
||||
char *key = (char *)malloc(key_len + 1);
|
||||
if (!key) {
|
||||
HOOK_MALLOC_FAILED;
|
||||
goto handle_error;
|
||||
}
|
||||
memcpy(key, tmp->key, key_len);
|
||||
key[key_len] = 0;
|
||||
ret[ret_index].key = key;
|
||||
char *value = (char *)malloc(tmp->value_len + 1);
|
||||
if (!value) {
|
||||
HOOK_MALLOC_FAILED;
|
||||
goto handle_error;
|
||||
}
|
||||
memcpy(value, tmp->value, tmp->value_len);
|
||||
value[tmp->value_len] = 0;
|
||||
ret[ret_index].value = value;
|
||||
(*txt_value_len)[ret_index] = tmp->value_len;
|
||||
ret_index++;
|
||||
}
|
||||
return ret;
|
||||
|
||||
handle_error:
|
||||
for (size_t y = 0; y < ret_index + 1; y++) {
|
||||
mdns_txt_item_t *t = &ret[y];
|
||||
free((char *)t->key);
|
||||
free((char *)t->value);
|
||||
}
|
||||
free(*txt_value_len);
|
||||
free(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static mdns_ip_addr_t *_copy_delegated_host_address_list(char *hostname)
|
||||
{
|
||||
mdns_host_item_t *host = _mdns_host_list;
|
||||
while (host) {
|
||||
if (strcasecmp(host->hostname, hostname) == 0) {
|
||||
return copy_address_list(host->address_list);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static mdns_result_t *_mdns_lookup_service(const char *instance, const char *service, const char *proto, size_t max_results, bool selfhost)
|
||||
{
|
||||
if (_str_null_or_empty(service) || _str_null_or_empty(proto)) {
|
||||
return NULL;
|
||||
}
|
||||
mdns_result_t *results = NULL;
|
||||
size_t num_results = 0;
|
||||
mdns_srv_item_t *s = _mdns_server->services;
|
||||
while (s) {
|
||||
mdns_service_t *srv = s->service;
|
||||
if (!srv || !srv->hostname) {
|
||||
s = s->next;
|
||||
continue;
|
||||
}
|
||||
bool is_service_selfhosted = !_str_null_or_empty(_mdns_server->hostname) && !strcasecmp(_mdns_server->hostname, srv->hostname);
|
||||
bool is_service_delegated = _str_null_or_empty(_mdns_server->hostname) || strcasecmp(_mdns_server->hostname, srv->hostname);
|
||||
if ((selfhost && is_service_selfhosted) || (!selfhost && is_service_delegated)) {
|
||||
if (!strcasecmp(srv->service, service) && !strcasecmp(srv->proto, proto) &&
|
||||
(_str_null_or_empty(instance) || _mdns_instance_name_match(srv->instance, instance))) {
|
||||
mdns_result_t *item = (mdns_result_t *)malloc(sizeof(mdns_result_t));
|
||||
if (!item) {
|
||||
HOOK_MALLOC_FAILED;
|
||||
goto handle_error;
|
||||
}
|
||||
item->next = results;
|
||||
results = item;
|
||||
item->esp_netif = NULL;
|
||||
item->ttl = _str_null_or_empty(instance) ? MDNS_ANSWER_PTR_TTL : MDNS_ANSWER_SRV_TTL;
|
||||
item->ip_protocol = MDNS_IP_PROTOCOL_MAX;
|
||||
item->instance_name = strndup(srv->instance, MDNS_NAME_BUF_LEN - 1);
|
||||
if (!item->instance_name) {
|
||||
HOOK_MALLOC_FAILED;
|
||||
goto handle_error;
|
||||
}
|
||||
item->service_type = strndup(srv->service, MDNS_NAME_BUF_LEN - 1);
|
||||
if (!item->service_type) {
|
||||
HOOK_MALLOC_FAILED;
|
||||
goto handle_error;
|
||||
}
|
||||
item->proto = strndup(srv->proto, MDNS_NAME_BUF_LEN - 1);
|
||||
if (!item->proto) {
|
||||
HOOK_MALLOC_FAILED;
|
||||
goto handle_error;
|
||||
}
|
||||
item->hostname = strndup(srv->hostname, MDNS_NAME_BUF_LEN - 1);
|
||||
if (!item->hostname) {
|
||||
HOOK_MALLOC_FAILED;
|
||||
goto handle_error;
|
||||
}
|
||||
item->port = srv->port;
|
||||
item->txt = _copy_mdns_txt_items(srv->txt, &(item->txt_value_len), &(item->txt_count));
|
||||
// We should not append addresses for selfhost lookup result as we don't know which interface's address to append.
|
||||
if (selfhost) {
|
||||
item->addr = NULL;
|
||||
} else {
|
||||
item->addr = _copy_delegated_host_address_list(item->hostname);
|
||||
if (!item->addr) {
|
||||
goto handle_error;
|
||||
}
|
||||
}
|
||||
if (num_results < max_results) {
|
||||
num_results++;
|
||||
}
|
||||
if (num_results >= max_results) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
s = s->next;
|
||||
}
|
||||
return results;
|
||||
handle_error:
|
||||
mdns_query_results_free(results);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
esp_err_t mdns_service_port_set_for_host(const char *instance, const char *service, const char *proto, const char *hostname, uint16_t port)
|
||||
{
|
||||
if (!_mdns_server || !_mdns_server->services || _str_null_or_empty(service) || _str_null_or_empty(proto) || !port) {
|
||||
@ -6156,6 +6418,36 @@ esp_err_t mdns_query_txt(const char *instance, const char *service, const char *
|
||||
return mdns_query(instance, service, proto, MDNS_TYPE_TXT, timeout, 1, result);
|
||||
}
|
||||
|
||||
esp_err_t mdns_lookup_delegated_service(const char *instance, const char *service, const char *proto, size_t max_results,
|
||||
mdns_result_t **result)
|
||||
{
|
||||
if (!_mdns_server) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
if (!result || _str_null_or_empty(service) || _str_null_or_empty(proto)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
MDNS_SERVICE_LOCK();
|
||||
*result = _mdns_lookup_service(instance, service, proto, max_results, false);
|
||||
MDNS_SERVICE_UNLOCK();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t mdns_lookup_selfhosted_service(const char *instance, const char *service, const char *proto, size_t max_results,
|
||||
mdns_result_t **result)
|
||||
{
|
||||
if (!_mdns_server) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
if (!result || _str_null_or_empty(service) || _str_null_or_empty(proto)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
MDNS_SERVICE_LOCK();
|
||||
*result = _mdns_lookup_service(instance, service, proto, max_results, true);
|
||||
MDNS_SERVICE_UNLOCK();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t mdns_query_a(const char *name, uint32_t timeout, esp_ip4_addr_t *addr)
|
||||
{
|
||||
mdns_result_t *result = NULL;
|
||||
|
@ -21,16 +21,26 @@
|
||||
#include "mdns_networking.h"
|
||||
#include "esp_netif_net_stack.h"
|
||||
|
||||
extern mdns_server_t *_mdns_server;
|
||||
|
||||
/*
|
||||
* MDNS Server Networking
|
||||
*
|
||||
*/
|
||||
static const char *TAG = "mdns_networking";
|
||||
enum interface_protocol {
|
||||
PROTO_IPV4 = 1 << MDNS_IP_PROTOCOL_V4,
|
||||
PROTO_IPV6 = 1 << MDNS_IP_PROTOCOL_V6
|
||||
};
|
||||
|
||||
typedef struct interfaces {
|
||||
bool ready;
|
||||
int proto;
|
||||
} interfaces_t;
|
||||
|
||||
static interfaces_t s_interfaces[MDNS_MAX_INTERFACES];
|
||||
|
||||
static struct udp_pcb *_pcb_main = NULL;
|
||||
|
||||
static const char *TAG = "mdns_networking";
|
||||
|
||||
static void _udp_recv(void *arg, struct udp_pcb *upcb, struct pbuf *pb, const ip_addr_t *raddr, uint16_t rport);
|
||||
|
||||
/**
|
||||
@ -53,7 +63,7 @@ static esp_err_t _udp_pcb_main_init(void)
|
||||
_pcb_main->mcast_ttl = 255;
|
||||
_pcb_main->remote_port = MDNS_SERVICE_PORT;
|
||||
ip_addr_copy(_pcb_main->remote_ip, *(IP_ANY_TYPE));
|
||||
udp_recv(_pcb_main, &_udp_recv, _mdns_server);
|
||||
udp_recv(_pcb_main, &_udp_recv, NULL);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@ -168,29 +178,26 @@ static void _udp_recv(void *arg, struct udp_pcb *upcb, struct pbuf *pb, const ip
|
||||
|
||||
//lwip does not return the proper pcb if you have more than one for the same multicast address (but different interfaces)
|
||||
struct netif *netif = NULL;
|
||||
struct udp_pcb *pcb = NULL;
|
||||
bool found = false;
|
||||
for (i = 0; i < MDNS_MAX_INTERFACES; i++) {
|
||||
pcb = _mdns_server->interfaces[i].pcbs[packet->ip_protocol].pcb;
|
||||
netif = esp_netif_get_netif_impl(_mdns_get_esp_netif(i));
|
||||
if (pcb && netif && netif == ip_current_input_netif ()) {
|
||||
if (s_interfaces[i].proto && netif && netif == ip_current_input_netif ()) {
|
||||
if (packet->src.type == IPADDR_TYPE_V4) {
|
||||
#if CONFIG_LWIP_IPV6
|
||||
if ((packet->src.u_addr.ip4.addr & netif->netmask.u_addr.ip4.addr) != (netif->ip_addr.u_addr.ip4.addr & netif->netmask.u_addr.ip4.addr)) {
|
||||
#else
|
||||
if ((packet->src.u_addr.ip4.addr & netif->netmask.addr) != (netif->ip_addr.addr & netif->netmask.addr)) {
|
||||
#endif //packet source is not in the same subnet
|
||||
pcb = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
packet->tcpip_if = i;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
pcb = NULL;
|
||||
}
|
||||
|
||||
if (!pcb || !_mdns_server || !_mdns_server->action_queue
|
||||
|| _mdns_send_rx_action(packet) != ESP_OK) {
|
||||
if (!found || _mdns_send_rx_action(packet) != ESP_OK) {
|
||||
pbuf_free(this_pb);
|
||||
free(packet);
|
||||
}
|
||||
@ -198,6 +205,12 @@ static void _udp_recv(void *arg, struct udp_pcb *upcb, struct pbuf *pb, const ip
|
||||
|
||||
}
|
||||
|
||||
bool mdns_is_netif_ready(mdns_if_t netif, mdns_ip_protocol_t ip_proto)
|
||||
{
|
||||
return s_interfaces[netif].ready &&
|
||||
s_interfaces[netif].proto & (ip_proto == MDNS_IP_PROTOCOL_V4 ? PROTO_IPV4 : PROTO_IPV6);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if any of the interfaces is up
|
||||
*/
|
||||
@ -206,7 +219,7 @@ static bool _udp_pcb_is_in_use(void)
|
||||
int i, p;
|
||||
for (i = 0; i < MDNS_MAX_INTERFACES; i++) {
|
||||
for (p = 0; p < MDNS_IP_PROTOCOL_MAX; p++) {
|
||||
if (_mdns_server->interfaces[i].pcbs[p].pcb) {
|
||||
if (mdns_is_netif_ready(i, p)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -219,19 +232,9 @@ static bool _udp_pcb_is_in_use(void)
|
||||
*/
|
||||
static void _udp_pcb_deinit(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol)
|
||||
{
|
||||
if (!_mdns_server) {
|
||||
return;
|
||||
}
|
||||
mdns_pcb_t *_pcb = &_mdns_server->interfaces[tcpip_if].pcbs[ip_protocol];
|
||||
if (_pcb->pcb) {
|
||||
free(_pcb->probe_services);
|
||||
_pcb->state = PCB_OFF;
|
||||
_pcb->pcb = NULL;
|
||||
_pcb->probe_ip = false;
|
||||
_pcb->probe_services = NULL;
|
||||
_pcb->probe_services_len = 0;
|
||||
_pcb->probe_running = false;
|
||||
_pcb->failed_probes = 0;
|
||||
s_interfaces[tcpip_if].proto &= ~(ip_protocol == MDNS_IP_PROTOCOL_V4 ? PROTO_IPV4 : PROTO_IPV6);
|
||||
if (s_interfaces[tcpip_if].proto == 0) {
|
||||
s_interfaces[tcpip_if].ready = false;
|
||||
_udp_join_group(tcpip_if, ip_protocol, false);
|
||||
if (!_udp_pcb_is_in_use()) {
|
||||
_udp_pcb_main_deinit();
|
||||
@ -244,7 +247,7 @@ static void _udp_pcb_deinit(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol)
|
||||
*/
|
||||
static esp_err_t _udp_pcb_init(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol)
|
||||
{
|
||||
if (!_mdns_server || _mdns_server->interfaces[tcpip_if].pcbs[ip_protocol].pcb) {
|
||||
if (mdns_is_netif_ready(tcpip_if, ip_protocol)) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
@ -257,9 +260,9 @@ static esp_err_t _udp_pcb_init(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protoco
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
s_interfaces[tcpip_if].proto |= (ip_protocol == MDNS_IP_PROTOCOL_V4 ? PROTO_IPV4 : PROTO_IPV6);
|
||||
s_interfaces[tcpip_if].ready = true;
|
||||
|
||||
_mdns_server->interfaces[tcpip_if].pcbs[ip_protocol].pcb = _pcb_main;
|
||||
_mdns_server->interfaces[tcpip_if].pcbs[ip_protocol].failed_probes = 0;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@ -323,14 +326,13 @@ static err_t _mdns_udp_pcb_write_api(struct tcpip_api_call_data *api_call_msg)
|
||||
{
|
||||
void *nif = NULL;
|
||||
mdns_api_call_t *msg = (mdns_api_call_t *)api_call_msg;
|
||||
mdns_pcb_t *_pcb = &_mdns_server->interfaces[msg->tcpip_if].pcbs[msg->ip_protocol];
|
||||
nif = esp_netif_get_netif_impl(_mdns_get_esp_netif(msg->tcpip_if));
|
||||
if (!nif) {
|
||||
if (!nif || !mdns_is_netif_ready(msg->tcpip_if, msg->ip_protocol) || _pcb_main == NULL) {
|
||||
pbuf_free(msg->pbt);
|
||||
msg->err = ERR_IF;
|
||||
return ERR_IF;
|
||||
}
|
||||
esp_err_t err = udp_sendto_if (_pcb->pcb, msg->pbt, msg->ip, msg->port, (struct netif *)nif);
|
||||
esp_err_t err = udp_sendto_if (_pcb_main, msg->pbt, msg->ip, msg->port, (struct netif *)nif);
|
||||
pbuf_free(msg->pbt);
|
||||
msg->err = err;
|
||||
return err;
|
||||
|
@ -27,7 +27,17 @@
|
||||
#include <net/if.h>
|
||||
#endif
|
||||
|
||||
extern mdns_server_t *_mdns_server;
|
||||
enum interface_protocol {
|
||||
PROTO_IPV4 = 1 << MDNS_IP_PROTOCOL_V4,
|
||||
PROTO_IPV6 = 1 << MDNS_IP_PROTOCOL_V6
|
||||
};
|
||||
|
||||
typedef struct interfaces {
|
||||
int sock;
|
||||
int proto;
|
||||
} interfaces_t;
|
||||
|
||||
static interfaces_t s_interfaces[MDNS_MAX_INTERFACES];
|
||||
|
||||
static const char *TAG = "mdns_networking";
|
||||
static bool s_run_sock_recv_task = false;
|
||||
@ -47,28 +57,22 @@ struct pbuf {
|
||||
#define s6_addr32 un.u32_addr
|
||||
#endif // CONFIG_IDF_TARGET_LINUX
|
||||
|
||||
static void __attribute__((constructor)) ctor_networking_socket(void)
|
||||
{
|
||||
for (int i = 0; i < sizeof(s_interfaces) / sizeof(s_interfaces[0]); ++i) {
|
||||
s_interfaces[i].sock = -1;
|
||||
s_interfaces[i].proto = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void delete_socket(int sock)
|
||||
{
|
||||
close(sock);
|
||||
}
|
||||
|
||||
static struct udp_pcb *sock_to_pcb(int sock)
|
||||
bool mdns_is_netif_ready(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol)
|
||||
{
|
||||
if (sock < 0) {
|
||||
return NULL;
|
||||
}
|
||||
// Note: sock=0 is a valid descriptor, so save it as +1 ("1" is a valid pointer)
|
||||
intptr_t sock_plus_one = sock + 1;
|
||||
return (struct udp_pcb *)sock_plus_one;
|
||||
}
|
||||
|
||||
static int pcb_to_sock(struct udp_pcb *pcb)
|
||||
{
|
||||
if (pcb == NULL) {
|
||||
return -1;
|
||||
}
|
||||
intptr_t sock_plus_one = (intptr_t)pcb;
|
||||
return sock_plus_one - 1;
|
||||
return s_interfaces[tcpip_if].proto & (ip_protocol == MDNS_IP_PROTOCOL_V4 ? PROTO_IPV4 : PROTO_IPV6);
|
||||
}
|
||||
|
||||
void *_mdns_get_packet_data(mdns_rx_packet_t *packet)
|
||||
@ -90,24 +94,18 @@ void _mdns_packet_free(mdns_rx_packet_t *packet)
|
||||
|
||||
esp_err_t _mdns_pcb_deinit(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol)
|
||||
{
|
||||
struct udp_pcb *pcb = _mdns_server->interfaces[tcpip_if].pcbs[ip_protocol].pcb;
|
||||
_mdns_server->interfaces[tcpip_if].pcbs[ip_protocol].pcb = NULL;
|
||||
if (_mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V4].pcb == NULL &&
|
||||
_mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V6].pcb == NULL) {
|
||||
// if the interface for both protocol uninitialized, close the interface socket
|
||||
int sock = pcb_to_sock(pcb);
|
||||
if (sock >= 0) {
|
||||
delete_socket(sock);
|
||||
s_interfaces[tcpip_if].proto &= ~(ip_protocol == MDNS_IP_PROTOCOL_V4 ? PROTO_IPV4 : PROTO_IPV6);
|
||||
if (s_interfaces[tcpip_if].proto == 0) {
|
||||
// if the interface for both protocols uninitialized, close the interface socket
|
||||
if (s_interfaces[tcpip_if].sock >= 0) {
|
||||
delete_socket(s_interfaces[tcpip_if].sock);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < MDNS_MAX_INTERFACES; i++) {
|
||||
for (int j = 0; j < MDNS_IP_PROTOCOL_MAX; j++) {
|
||||
if (_mdns_server->interfaces[i].pcbs[j].pcb)
|
||||
// If any of the interfaces/protocol initialized
|
||||
{
|
||||
return ESP_OK;
|
||||
}
|
||||
if (s_interfaces[i].sock >= 0) {
|
||||
// If any of the interfaces initialized
|
||||
return ESP_OK;
|
||||
}
|
||||
}
|
||||
|
||||
@ -191,7 +189,10 @@ static inline size_t espaddr_to_inet(const esp_ip_addr_t *addr, const uint16_t p
|
||||
|
||||
size_t _mdns_udp_pcb_write(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol, const esp_ip_addr_t *ip, uint16_t port, uint8_t *data, size_t len)
|
||||
{
|
||||
int sock = pcb_to_sock(_mdns_server->interfaces[tcpip_if].pcbs[ip_protocol].pcb);
|
||||
if (!(s_interfaces[tcpip_if].proto & (ip_protocol == MDNS_IP_PROTOCOL_V4 ? PROTO_IPV4 : PROTO_IPV6))) {
|
||||
return 0;
|
||||
}
|
||||
int sock = s_interfaces[tcpip_if].sock;
|
||||
if (sock < 0) {
|
||||
return 0;
|
||||
}
|
||||
@ -250,12 +251,10 @@ void sock_recv_task(void *arg)
|
||||
FD_ZERO(&rfds);
|
||||
int max_sock = -1;
|
||||
for (int i = 0; i < MDNS_MAX_INTERFACES; i++) {
|
||||
for (int j = 0; j < MDNS_IP_PROTOCOL_MAX; j++) {
|
||||
int sock = pcb_to_sock(_mdns_server->interfaces[i].pcbs[j].pcb);
|
||||
if (sock >= 0) {
|
||||
FD_SET(sock, &rfds);
|
||||
max_sock = MAX(max_sock, sock);
|
||||
}
|
||||
int sock = s_interfaces[i].sock;
|
||||
if (sock >= 0) {
|
||||
FD_SET(sock, &rfds);
|
||||
max_sock = MAX(max_sock, sock);
|
||||
}
|
||||
}
|
||||
if (max_sock < 0) {
|
||||
@ -270,11 +269,7 @@ void sock_recv_task(void *arg)
|
||||
break;
|
||||
} else if (s > 0) {
|
||||
for (int tcpip_if = 0; tcpip_if < MDNS_MAX_INTERFACES; tcpip_if++) {
|
||||
// Both protocols share once socket
|
||||
int sock = pcb_to_sock(_mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V4].pcb);
|
||||
if (sock < 0) {
|
||||
sock = pcb_to_sock(_mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V6].pcb);
|
||||
}
|
||||
int sock = s_interfaces[tcpip_if].sock;
|
||||
if (sock < 0) {
|
||||
continue;
|
||||
}
|
||||
@ -323,7 +318,7 @@ void sock_recv_task(void *arg)
|
||||
packet->dest.type = packet->src.type;
|
||||
packet->ip_protocol =
|
||||
packet->src.type == ESP_IPADDR_TYPE_V4 ? MDNS_IP_PROTOCOL_V4 : MDNS_IP_PROTOCOL_V6;
|
||||
if (!_mdns_server || !_mdns_server->action_queue || _mdns_send_rx_action(packet) != ESP_OK) {
|
||||
if (_mdns_send_rx_action(packet) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "_mdns_send_rx_action failed!");
|
||||
free(packet->pb->payload);
|
||||
free(packet->pb);
|
||||
@ -344,39 +339,43 @@ static void mdns_networking_init(void)
|
||||
}
|
||||
}
|
||||
|
||||
static struct udp_pcb *create_pcb(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol)
|
||||
static bool create_pcb(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol)
|
||||
{
|
||||
if (_mdns_server->interfaces[tcpip_if].pcbs[ip_protocol].pcb) {
|
||||
return _mdns_server->interfaces[tcpip_if].pcbs[ip_protocol].pcb;
|
||||
if (s_interfaces[tcpip_if].proto & (ip_protocol == MDNS_IP_PROTOCOL_V4 ? PROTO_IPV4 : PROTO_IPV6)) {
|
||||
return true;
|
||||
}
|
||||
mdns_ip_protocol_t other_ip_proto = ip_protocol == MDNS_IP_PROTOCOL_V4 ? MDNS_IP_PROTOCOL_V6 : MDNS_IP_PROTOCOL_V4;
|
||||
int sock = s_interfaces[tcpip_if].sock;
|
||||
esp_netif_t *netif = _mdns_get_esp_netif(tcpip_if);
|
||||
if (_mdns_server->interfaces[tcpip_if].pcbs[other_ip_proto].pcb) {
|
||||
struct udp_pcb *other_pcb = _mdns_server->interfaces[tcpip_if].pcbs[other_ip_proto].pcb;
|
||||
int err = join_mdns_multicast_group(pcb_to_sock(other_pcb), netif, ip_protocol);
|
||||
if (sock >= 0) {
|
||||
mdns_ip_protocol_t other_ip_proto = ip_protocol == MDNS_IP_PROTOCOL_V4 ? MDNS_IP_PROTOCOL_V6 : MDNS_IP_PROTOCOL_V4;
|
||||
int err = join_mdns_multicast_group(sock, netif, other_ip_proto);
|
||||
if (err < 0) {
|
||||
ESP_LOGE(TAG, "Failed to add ipv6 multicast group for protocol %d", ip_protocol);
|
||||
return NULL;
|
||||
return false;
|
||||
}
|
||||
return other_pcb;
|
||||
s_interfaces[tcpip_if].proto |= (other_ip_proto == MDNS_IP_PROTOCOL_V4 ? PROTO_IPV4 : PROTO_IPV6);
|
||||
return true;
|
||||
}
|
||||
int sock = create_socket(netif);
|
||||
sock = create_socket(netif);
|
||||
if (sock < 0) {
|
||||
ESP_LOGE(TAG, "Failed to create the socket!");
|
||||
return NULL;
|
||||
return false;
|
||||
}
|
||||
int err = join_mdns_multicast_group(sock, netif, ip_protocol);
|
||||
if (err < 0) {
|
||||
ESP_LOGE(TAG, "Failed to add ipv6 multicast group for protocol %d", ip_protocol);
|
||||
}
|
||||
return sock_to_pcb(sock);
|
||||
s_interfaces[tcpip_if].proto |= (ip_protocol == MDNS_IP_PROTOCOL_V4 ? PROTO_IPV4 : PROTO_IPV6);
|
||||
s_interfaces[tcpip_if].sock = sock;
|
||||
return true;
|
||||
}
|
||||
|
||||
esp_err_t _mdns_pcb_init(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol)
|
||||
{
|
||||
ESP_LOGI(TAG, "_mdns_pcb_init(tcpip_if=%d, ip_protocol=%d)", tcpip_if, ip_protocol);
|
||||
_mdns_server->interfaces[tcpip_if].pcbs[ip_protocol].pcb = create_pcb(tcpip_if, ip_protocol);
|
||||
_mdns_server->interfaces[tcpip_if].pcbs[ip_protocol].failed_probes = 0;
|
||||
if (!create_pcb(tcpip_if, ip_protocol)) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
mdns_networking_init();
|
||||
return ESP_OK;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -19,6 +19,8 @@
|
||||
*/
|
||||
esp_err_t _mdns_send_rx_action(mdns_rx_packet_t *packet);
|
||||
|
||||
bool mdns_is_netif_ready(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol);
|
||||
|
||||
/**
|
||||
* @brief Start PCB
|
||||
*/
|
||||
|
@ -33,6 +33,12 @@
|
||||
#endif
|
||||
#define MDNS_MAX_PREDEF_INTERFACES (CONFIG_MDNS_PREDEF_NETIF_STA + CONFIG_MDNS_PREDEF_NETIF_AP + CONFIG_MDNS_PREDEF_NETIF_ETH)
|
||||
|
||||
#ifdef CONFIG_LWIP_IPV6_NUM_ADDRESSES
|
||||
#define NETIF_IPV6_MAX_NUMS CONFIG_LWIP_IPV6_NUM_ADDRESSES
|
||||
#else
|
||||
#define NETIF_IPV6_MAX_NUMS 3
|
||||
#endif
|
||||
|
||||
/** Number of configured interfaces */
|
||||
#if MDNS_MAX_PREDEF_INTERFACES > CONFIG_MDNS_MAX_INTERFACES
|
||||
#warning Number of configured interfaces is less then number of predefined interfaces. Please update CONFIG_MDNS_MAX_INTERFACES.
|
||||
@ -87,7 +93,7 @@
|
||||
#define MDNS_SERVICE_ADD_TIMEOUT_MS CONFIG_MDNS_SERVICE_ADD_TIMEOUT_MS
|
||||
|
||||
#define MDNS_PACKET_QUEUE_LEN 16 // Maximum packets that can be queued for parsing
|
||||
#define MDNS_ACTION_QUEUE_LEN 16 // Maximum actions pending to the server
|
||||
#define MDNS_ACTION_QUEUE_LEN CONFIG_MDNS_ACTION_QUEUE_LEN // Maximum actions pending to the server
|
||||
#define MDNS_TXT_MAX_LEN 1024 // Maximum string length of text data in TXT record
|
||||
#if defined(CONFIG_LWIP_IPV6) && defined(CONFIG_MDNS_RESPOND_REVERSE_QUERIES)
|
||||
#define MDNS_NAME_MAX_LEN (64+4) // Need to account for IPv6 reverse queries (64 char address + ".ip6" )
|
||||
@ -190,6 +196,7 @@ typedef enum {
|
||||
ACTION_TASK_STOP,
|
||||
ACTION_DELEGATE_HOSTNAME_ADD,
|
||||
ACTION_DELEGATE_HOSTNAME_REMOVE,
|
||||
ACTION_DELEGATE_HOSTNAME_SET_ADDR,
|
||||
ACTION_MAX
|
||||
} mdns_action_type_t;
|
||||
|
||||
@ -341,7 +348,6 @@ typedef struct mdns_tx_packet_s {
|
||||
|
||||
typedef struct {
|
||||
mdns_pcb_state_t state;
|
||||
struct udp_pcb *pcb;
|
||||
mdns_srv_item_t **probe_services;
|
||||
uint8_t probe_services_len;
|
||||
uint8_t probe_ip;
|
||||
@ -382,7 +388,6 @@ typedef struct mdns_server_s {
|
||||
const char *hostname;
|
||||
const char *instance;
|
||||
mdns_srv_item_t *services;
|
||||
SemaphoreHandle_t lock;
|
||||
QueueHandle_t action_queue;
|
||||
SemaphoreHandle_t action_sema;
|
||||
mdns_tx_packet_t *tx_queue_head;
|
||||
|
@ -1,7 +1,11 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
set(EXTRA_COMPONENT_DIRS "../..")
|
||||
set(EXTRA_COMPONENT_DIRS "../.." "../../../../common_components/linux_compat")
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
set(COMPONENTS main esp_netif_linux)
|
||||
project(mdns_host)
|
||||
|
||||
# Enable sanitizers for mdns implementation
|
||||
idf_component_get_property(mdns mdns COMPONENT_LIB)
|
||||
target_link_options(${mdns} INTERFACE -fsanitize=address -fsanitize=undefined)
|
||||
|
@ -1,2 +0,0 @@
|
||||
idf_component_register(SRCS esp_event_mock.c
|
||||
INCLUDE_DIRS include)
|
@ -1,21 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "esp_event.h"
|
||||
|
||||
const char *WIFI_EVENT = "WIFI_EVENT";
|
||||
const char *IP_EVENT = "IP_EVENT";
|
||||
|
||||
esp_err_t esp_event_handler_register(const char *event_base, int32_t event_id, void *event_handler, void *event_handler_arg)
|
||||
{
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_event_handler_unregister(const char *event_base, int32_t event_id, void *event_handler)
|
||||
{
|
||||
return ESP_OK;
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "stdbool.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_event_base.h"
|
||||
#include "bsd/string.h"
|
||||
|
||||
esp_err_t esp_event_handler_register(const char *event_base, int32_t event_id, void *event_handler, void *event_handler_arg);
|
||||
|
||||
esp_err_t esp_event_handler_unregister(const char *event_base, int32_t event_id, void *event_handler);
|
@ -1,19 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
typedef enum {
|
||||
WIFI_EVENT_STA_CONNECTED, /**< ESP32 station connected to AP */
|
||||
WIFI_EVENT_STA_DISCONNECTED, /**< ESP32 station disconnected from AP */
|
||||
WIFI_EVENT_AP_START, /**< ESP32 soft-AP start */
|
||||
WIFI_EVENT_AP_STOP, /**< ESP32 soft-AP stop */
|
||||
} mdns_used_event_t;
|
||||
|
||||
#define ESP_EVENT_DECLARE_BASE(x)
|
||||
#define ESP_EVENT_ANY_ID (-1)
|
||||
|
||||
typedef void *esp_event_base_t;
|
||||
typedef void *system_event_t;
|
@ -1,3 +1,2 @@
|
||||
idf_component_register(SRCS esp_netif_linux.c
|
||||
INCLUDE_DIRS include $ENV{IDF_PATH}/components/esp_netif/include
|
||||
REQUIRES esp_event)
|
||||
INCLUDE_DIRS include $ENV{IDF_PATH}/components/esp_netif/include)
|
||||
|
@ -55,6 +55,7 @@ esp_err_t esp_netif_get_ip_info(esp_netif_t *esp_netif, esp_netif_ip_info_t *ip_
|
||||
}
|
||||
tmp = tmp->ifa_next;
|
||||
}
|
||||
freeifaddrs(addrs);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@ -63,6 +64,29 @@ esp_err_t esp_netif_dhcpc_get_status(esp_netif_t *esp_netif, esp_netif_dhcp_stat
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
int esp_netif_get_all_ip6(esp_netif_t *esp_netif, esp_ip6_addr_t if_ip6[])
|
||||
{
|
||||
if (esp_netif == NULL) {
|
||||
return 0;
|
||||
}
|
||||
struct ifaddrs *addrs, *tmp;
|
||||
int addr_count = 0;
|
||||
getifaddrs(&addrs);
|
||||
tmp = addrs;
|
||||
|
||||
while (tmp) {
|
||||
if (tmp->ifa_addr && tmp->ifa_addr->sa_family == AF_INET6) {
|
||||
struct sockaddr_in6 *pAddr = (struct sockaddr_in6 *)tmp->ifa_addr;
|
||||
if (strcmp(esp_netif->if_desc, tmp->ifa_name) == 0) {
|
||||
memcpy(&if_ip6[addr_count++], &pAddr->sin6_addr, 4 * 4);
|
||||
}
|
||||
}
|
||||
tmp = tmp->ifa_next;
|
||||
}
|
||||
|
||||
freeifaddrs(addrs);
|
||||
return addr_count;
|
||||
}
|
||||
|
||||
esp_err_t esp_netif_get_ip6_linklocal(esp_netif_t *esp_netif, esp_ip6_addr_t *if_ip6)
|
||||
{
|
||||
|
@ -1,174 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include <pthread.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
void *create_q(void);
|
||||
|
||||
void destroy_q(void *q);
|
||||
|
||||
bool send_q(void *q, uint8_t *data, size_t len);
|
||||
|
||||
bool recv_q(void *q, uint8_t *data, size_t len, uint32_t ms);
|
||||
|
||||
static uint64_t s_semaphore_data = 0;
|
||||
|
||||
struct queue_handle {
|
||||
size_t item_size;
|
||||
void *q;
|
||||
};
|
||||
|
||||
QueueHandle_t xQueueCreate( uint32_t uxQueueLength, uint32_t uxItemSize )
|
||||
{
|
||||
struct queue_handle *h = calloc(1, sizeof(struct queue_handle));
|
||||
h->item_size = uxItemSize;
|
||||
h->q = create_q();
|
||||
return (QueueHandle_t)h;
|
||||
}
|
||||
|
||||
uint32_t xQueueSend(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait)
|
||||
{
|
||||
struct queue_handle *h = xQueue;
|
||||
return send_q(h->q, (uint8_t *)pvItemToQueue, h->item_size) ? pdTRUE : pdFAIL;
|
||||
}
|
||||
|
||||
uint32_t xQueueReceive(QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksToWait)
|
||||
{
|
||||
struct queue_handle *h = xQueue;
|
||||
return recv_q(h->q, (uint8_t *)pvBuffer, h->item_size, xTicksToWait) ? pdTRUE : pdFAIL;
|
||||
}
|
||||
|
||||
BaseType_t xSemaphoreGive( QueueHandle_t xQueue)
|
||||
{
|
||||
return xQueueSend(xQueue, &s_semaphore_data, portMAX_DELAY);
|
||||
}
|
||||
|
||||
BaseType_t xSemaphoreTake( QueueHandle_t xQueue, TickType_t pvTask )
|
||||
{
|
||||
return xQueueReceive(xQueue, &s_semaphore_data, portMAX_DELAY);
|
||||
}
|
||||
|
||||
void vQueueDelete( QueueHandle_t xQueue )
|
||||
{
|
||||
struct queue_handle *h = xQueue;
|
||||
if (h->q) {
|
||||
destroy_q(h->q);
|
||||
}
|
||||
free(xQueue);
|
||||
}
|
||||
|
||||
QueueHandle_t xSemaphoreCreateBinary(void)
|
||||
{
|
||||
QueueHandle_t sempaphore = xQueueCreate(1, 1);
|
||||
return sempaphore;
|
||||
}
|
||||
|
||||
QueueHandle_t xSemaphoreCreateMutex(void)
|
||||
{
|
||||
QueueHandle_t sempaphore = xQueueCreate(1, 1);
|
||||
if (sempaphore) {
|
||||
xSemaphoreGive(sempaphore);
|
||||
}
|
||||
return sempaphore;
|
||||
}
|
||||
|
||||
void vTaskDelete(TaskHandle_t *task)
|
||||
{
|
||||
if (task == NULL) {
|
||||
pthread_exit(0);
|
||||
}
|
||||
void *thread_rval = NULL;
|
||||
pthread_join((pthread_t)task, &thread_rval);
|
||||
}
|
||||
|
||||
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 )
|
||||
{
|
||||
usleep(xTicksToDelay * 1000);
|
||||
}
|
||||
|
||||
void *pthread_task(void *params)
|
||||
{
|
||||
struct {
|
||||
void *const param;
|
||||
TaskFunction_t task;
|
||||
bool started;
|
||||
} *pthread_params = params;
|
||||
|
||||
void *const param = pthread_params->param;
|
||||
TaskFunction_t task = pthread_params->task;
|
||||
pthread_params->started = true;
|
||||
|
||||
task(param);
|
||||
|
||||
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)
|
||||
{
|
||||
xTaskCreate(pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pvCreatedTask);
|
||||
return pdTRUE;
|
||||
}
|
||||
|
||||
|
||||
void xTaskCreate(TaskFunction_t pvTaskCode, const char *const pcName, const uint32_t usStackDepth, void *const pvParameters, UBaseType_t uxPriority, TaskHandle_t *const pvCreatedTask)
|
||||
{
|
||||
pthread_t new_thread = (pthread_t)NULL;
|
||||
pthread_attr_t attr;
|
||||
struct {
|
||||
void *const param;
|
||||
TaskFunction_t task;
|
||||
bool started;
|
||||
} pthread_params = { .param = pvParameters, .task = pvTaskCode};
|
||||
int res = pthread_attr_init(&attr);
|
||||
assert(res == 0);
|
||||
res = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
|
||||
assert(res == 0);
|
||||
res = pthread_create(&new_thread, &attr, pthread_task, &pthread_params);
|
||||
assert(res == 0);
|
||||
|
||||
if (pvCreatedTask) {
|
||||
*pvCreatedTask = (void *)new_thread;
|
||||
}
|
||||
|
||||
// just wait till the task started so we can unwind params from the stack
|
||||
while (pthread_params.started == false) {
|
||||
usleep(1000);
|
||||
}
|
||||
}
|
||||
|
||||
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 )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
TaskHandle_t xTaskGetCurrentTaskHandle(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "queue_unique_ptr.hpp"
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <cstring>
|
||||
|
||||
extern "C" void *create_q(void)
|
||||
{
|
||||
auto *q = new QueueMock<std::vector<uint8_t>>();
|
||||
return q;
|
||||
}
|
||||
|
||||
extern "C" void destroy_q(void *q)
|
||||
{
|
||||
auto *queue = static_cast<QueueMock<std::vector<uint8_t>> *>(q);
|
||||
delete (queue);
|
||||
}
|
||||
|
||||
extern "C" bool send_q(void *q, uint8_t *data, size_t len)
|
||||
{
|
||||
auto v = std::make_unique<std::vector<uint8_t>>(len);
|
||||
v->assign(data, data + len);
|
||||
auto queue = static_cast<QueueMock<std::vector<uint8_t>> *>(q);
|
||||
queue->send(std::move(v));
|
||||
return true;
|
||||
}
|
||||
|
||||
extern "C" bool recv_q(void *q, uint8_t *data, size_t len, uint32_t ms)
|
||||
{
|
||||
auto queue = static_cast<QueueMock<std::vector<uint8_t>> *>(q);
|
||||
auto v = queue->receive(ms);
|
||||
if (v == nullptr) {
|
||||
return false;
|
||||
}
|
||||
memcpy(data, (void *)v->data(), len);
|
||||
return true;
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <queue>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
|
||||
template <class T>
|
||||
class QueueMock {
|
||||
public:
|
||||
QueueMock(void): q(), m(), c() {}
|
||||
~QueueMock(void) {}
|
||||
|
||||
void send(std::unique_ptr<T> t)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m);
|
||||
q.push(std::move(t));
|
||||
c.notify_one();
|
||||
}
|
||||
|
||||
std::unique_ptr<T> receive(uint32_t ms)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m);
|
||||
while (q.empty()) {
|
||||
if (c.wait_for(lock, std::chrono::milliseconds(ms)) == std::cv_status::timeout) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
std::unique_ptr<T> val = std::move(q.front());
|
||||
q.pop();
|
||||
return val;
|
||||
}
|
||||
|
||||
private:
|
||||
std::queue<std::unique_ptr<T>> q;
|
||||
mutable std::mutex m;
|
||||
std::condition_variable c;
|
||||
};
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
@ -24,3 +24,8 @@ static inline void _mdns_packet_free(mdns_rx_packet_t *packet)
|
||||
free(packet->pb);
|
||||
free(packet);
|
||||
}
|
||||
|
||||
static inline bool mdns_is_netif_ready(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user