Compare commits

..

2 Commits

Author SHA1 Message Date
a66d8a6fc8 bump(modem): 0.1.28 -> 1.0.0 2023-03-16 20:11:02 +01:00
c59e3302b4 fix(common): Changelog to correctly pick references
Also added .cz config for modem components
2023-03-16 20:10:10 +01:00
201 changed files with 1257 additions and 4363 deletions

View File

@ -137,4 +137,4 @@ show_source = True
statistics = True
exclude =
docs/asio/conf_common.py
components/asio/docs/conf_common.py

View File

@ -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://github.com/espressif/esp-protocols#readme) and the issue is not addressed there.
- label: I have read the documentation for [esp-protocols components](https://espressif.github.io/esp-protocols/) 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

View File

@ -1,7 +1,7 @@
blank_issues_enabled: false
contact_links:
- name: esp-protocols documentation links
url: https://github.com/espressif/esp-protocols#readme
- name: esp-protocols documentation
url: https://espressif.github.io/esp-protocols/
about: Documenation for esp-protocols components.
- name: ESP-IDF Programming Guide
url: https://docs.espressif.com/projects/esp-idf/en/latest/

View File

@ -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://github.com/espressif/esp-protocols#readme) and the issue is not addressed there.
- label: I have read the documentation for [esp-protocols components](https://espressif.github.io/esp-protocols/) 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

View File

@ -1,48 +0,0 @@
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

View File

@ -13,33 +13,122 @@ jobs:
name: Build
strategy:
matrix:
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" } ]
idf_ver: ["latest"]
idf_target: ["esp32", "esp32s2", "esp32c3"]
test: [ { app: example, path: "components/mdns/examples" }, { app: unit_test, path: "components/mdns/tests/unit_test" } ]
runs-on: ubuntu-20.04
container: espressif/idf:${{ matrix.idf_ver }}
steps:
- name: Checkout esp-protocols
uses: actions/checkout@v3
- name: Build ${{ matrix.test.app }} with IDF-${{ matrix.idf_ver }}
with:
submodules: recursive
- name: Build ${{ matrix.test.app }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
shell: bash
working-directory: ${{ matrix.test.path }}
run: |
${IDF_PATH}/install.sh --enable-pytest
. ${IDF_PATH}/export.sh
python -m pip install idf-build-apps
# Build default configs for all targets
python ./ci/build_apps.py components/mdns/${{ matrix.test.path }} -r default -m components/mdns/.build-test-rules.yml -d
# 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
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
$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_esp32_${{ matrix.idf_ver }}_${{ matrix.test.app }}
path: components/mdns/${{ matrix.test.path }}/artifacts.zip
name: mdns_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.test.app }}
path: ${{ 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: |
@ -50,7 +139,7 @@ jobs:
matrix:
idf_ver: ["latest"]
idf_target: ["esp32"]
test: [ { app: example, path: "examples" }, { app: unit_test, path: "tests/unit_test" }, { app: test_app, path: "tests/test_apps" } ]
test: [ { app: example, path: "components/mdns/examples" }, { app: unit_test, path: "components/mdns/tests/unit_test" } ]
needs: build_mdns
runs-on:
- self-hosted
@ -62,14 +151,14 @@ jobs:
- uses: actions/download-artifact@v3
with:
name: mdns_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.test.app }}
path: components/mdns/${{ matrix.test.path }}/ci/
path: ${{ 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: components/mdns/${{ matrix.test.path }}
working-directory: ${{ matrix.test.path }}
run: |
unzip ci/artifacts.zip -d ci
for dir in `ls -d ci/build_*`; do
@ -81,4 +170,4 @@ jobs:
if: always()
with:
name: results_${{ matrix.test.app }}_${{ matrix.idf_target }}_${{ matrix.idf_ver }}.xml
path: components/mdns/${{ matrix.test.path }}/*.xml
path: ${{ matrix.test.path }}/*.xml

View File

@ -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:release-v5.1
container: espressif/idf:latest
steps:
- name: Checkout esp-protocols

View File

@ -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 }} -m components/esp_modem/examples/.build-test-rules.yml
python ./ci/build_apps.py components/esp_modem/examples/${{ matrix.example }}
host_test_esp_modem:
if: contains(github.event.pull_request.labels.*.name, 'modem') || github.event_name == 'push'
@ -91,8 +91,6 @@ 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
@ -104,11 +102,11 @@ jobs:
uses: actions/checkout@v3
with:
path: esp-protocols
repository: ''
persist-credentials: false
- name: Build and Test
shell: bash
run: |
apt-get update
apt-get update && apt-get install -y gcc-8 g++-8 python3-pip
apt-get install -y rsync
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-8 800 --slave /usr/bin/g++ g++ /usr/bin/g++-8
@ -128,9 +126,10 @@ jobs:
cd $GITHUB_WORKSPACE/${{ env.COMP_DIR }}
gcov-8 `find . -name "esp_modem*gcda" -printf '%h\n' | head -n 1`/*
gcovr --gcov-ignore-parse-errors -g -k -r . --html index.html -x esp_modem_coverage.xml
mkdir modem_coverage_report
cp $GITHUB_WORKSPACE/${{ env.COMP_DIR }}/index.html modem_coverage_report
cp -rf modem_coverage_report $GITHUB_WORKSPACE
mkdir docs_gcovr
cp $GITHUB_WORKSPACE/${{ env.COMP_DIR }}/index.html docs_gcovr
touch docs_gcovr/.nojekyll
- name: Code Coverage Summary Report
uses: irongut/CodeCoverageSummary@v1.3.0
with:
@ -143,6 +142,7 @@ jobs:
indicators: true
output: both
thresholds: '60 80'
- name: Write to Job Summary
run: cat code-coverage-results.md >> $GITHUB_STEP_SUMMARY
@ -150,7 +150,28 @@ jobs:
uses: actions/upload-artifact@v3
if: always()
with:
name: modem_coverage_report
name: docs_gcovr
path: |
${{ env.COMP_DIR }}/modem_coverage_report
${{ 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'

View File

@ -58,7 +58,7 @@ jobs:
needs: build_esp_modem_tests
runs-on:
- self-hosted
- modem
- BrnoRPI-GH006
env:
TEST_DIR: components/esp_modem/${{ matrix.test.path }}
steps:

View File

@ -12,17 +12,12 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
with:
ref: ${{ github.base_ref }}
fetch-depth: 20
uses: actions/checkout@v2
- name: Fetch head and base refs
# This is necessary for pre-commit to check the changes in the PR branch (and to set origin/HEAD and HEAD refs)
# This is necessary for pre-commit to check the changes in the PR branch
run: |
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 )
git fetch origin ${{ github.base_ref }}:base_ref
git fetch origin pull/${{ github.event.pull_request.number }}/head:pr_ref
- name: Set up Python environment
uses: actions/setup-python@master
with:
@ -31,12 +26,13 @@ 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 origin/HEAD..HEAD
git log --oneline --no-decorate base_ref..pr_ref
echo ""
if ! pre-commit run --from-ref origin/HEAD --to-ref HEAD --hook-stage manual --show-diff-on-failure ; then
if ! pre-commit run --from-ref base_ref --to-ref pr_ref --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."

View File

@ -1,45 +0,0 @@
name: Publish coverage report to Github Pages
on:
workflow_run:
workflows: ["websocket: build/host-tests", "esp-modem: build/host-tests"]
types:
- completed
branches:
- master
jobs:
publish_github_pages:
runs-on: ubuntu-latest
if: github.repository == 'espressif/esp-protocols'
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Download Websocket Artifact
uses: dawidd6/action-download-artifact@v2
with:
workflow: websocket__build-host-tests.yml
workflow_conclusion: success
name: websocket_coverage_report
path: websocket_coverage_report_artifact
- name: Download Modem Artifact
uses: dawidd6/action-download-artifact@v2
with:
workflow: modem__build-host-tests.yml
workflow_conclusion: success
name: modem_coverage_report
path: modem_coverage_report_artifact
- name: Merge HTML files
run: |
echo "<html><body>" > index.html
cat modem_coverage_report_artifact/index.html >> index.html
cat websocket_coverage_report_artifact/index.html >> index.html
echo "</body></html>" >> index.html
mkdir coverage_report
mv index.html coverage_report
- name: Deploy generated docs
uses: JamesIves/github-pages-deploy-action@4.1.5
with:
branch: gh-pages
folder: coverage_report

View File

@ -5,89 +5,66 @@ 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:
publish:
name: Publish Tag, Release, Docs, Component
docs_build:
name: Docs-Build-And-Upload
runs-on: ubuntu-latest
# Skip running on forks since it won't have access to secrets
if: github.repository == 'espressif/esp-protocols'
steps:
- name: Checkout esp-protocols
uses: actions/checkout@v3
uses: actions/checkout@master
with:
persist-credentials: false
fetch-depth: 0
submodules: recursive
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:
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
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/upload-components-ci-action@v1
uses: espressif/github-actions/upload_components@master
with:
directories: >
components/asio;
components/esp_modem;
components/esp_mqtt_cxx;
components/esp_websocket_client;
components/mdns;
directories: "components/esp_modem;components/esp_websocket_client;components/mdns;components/asio"
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

View File

@ -1,86 +0,0 @@
name: Run on host
on:
workflow_call:
inputs:
idf_version:
required: true
type: string
app_name:
type: string
required: true
app_path:
type: string
required: true
component_path:
type: string
required: true
upload_artifacts:
type: boolean
required: true
jobs:
build:
name: Build App
runs-on: ubuntu-20.04
permissions:
contents: write
container: espressif/idf:${{inputs.idf_version}}
steps:
- name: Checkout esp-protocols
uses: actions/checkout@v3
with:
path: esp-protocols
- name: Build ${{ inputs.app_name }} with IDF-${{ inputs.idf_version }}
shell: bash
run: |
. ${IDF_PATH}/export.sh
cd $GITHUB_WORKSPACE/${{inputs.app_path}}
rm -rf sdkconfig sdkconfig.defaults build
cp sdkconfig.ci.linux sdkconfig.defaults
idf.py build
./build/${{inputs.app_name}}.elf
- name: Build with Coverage Enabled
shell: bash
run: |
. ${IDF_PATH}/export.sh
cd $GITHUB_WORKSPACE/${{inputs.app_path}}
rm -rf build sdkconfig sdkconfig.defaults
cp sdkconfig.ci.coverage sdkconfig.defaults
idf.py fullclean
idf.py build
./build/${{inputs.app_name}}.elf
- name: Run Coverage
shell: bash
run: |
apt-get update && apt-get install -y python3-pip rsync
python -m pip install gcovr
cd $GITHUB_WORKSPACE/${{inputs.component_path}}
gcov `find . -name "*gcda"`
gcovr --gcov-ignore-parse-errors -g -k -r . --html index.html -x ${{inputs.app_name}}_coverage.xml
mkdir ${{inputs.app_name}}_coverage_report
touch ${{inputs.app_name}}_coverage_report/.nojekyll
cp index.html ${{inputs.app_name}}_coverage_report
cp -rf ${{inputs.app_name}}_coverage_report ${{inputs.app_name}}_coverage.xml $GITHUB_WORKSPACE
- name: Code Coverage Summary Report
uses: irongut/CodeCoverageSummary@v1.3.0
with:
filename: esp-protocols/**/${{inputs.app_name}}_coverage.xml
badge: true
fail_below_min: false
format: markdown
hide_branch_rate: false
hide_complexity: false
indicators: true
output: both
thresholds: '60 80'
- name: Write to Job Summary
run: cat code-coverage-results.md >> $GITHUB_STEP_SUMMARY
- name: Upload files to artifacts for run-target job
uses: actions/upload-artifact@v3
if: ${{inputs.upload_artifacts}}
with:
name: ${{inputs.app_name}}_coverage_report
path: |
${{inputs.component_path}}/${{inputs.app_name}}_coverage_report
if-no-files-found: error

View File

@ -1,20 +0,0 @@
name: "websocket: build/host-tests"
on:
push:
branches:
- master
pull_request:
types: [opened, synchronize, reopened, labeled]
jobs:
host_test_websocket:
if: contains(github.event.pull_request.labels.*.name, 'websocket') || github.event_name == 'push'
uses: "./.github/workflows/run-host-tests.yml"
with:
idf_version: "latest"
app_name: "websocket"
app_path: "esp-protocols/components/esp_websocket_client/examples/linux"
component_path: "esp-protocols/components/esp_websocket_client"
upload_artifacts: true

View File

@ -13,32 +13,45 @@ jobs:
name: Build
strategy:
matrix:
idf_ver: ["release-v5.0", "release-v5.1", "latest"]
test: [ { app: example, path: "examples/target" }, { app: unit_test, path: "test" } ]
idf_ver: ["release-v5.0", "latest"]
idf_target: ["esp32"]
runs-on: ubuntu-20.04
container: espressif/idf:${{ matrix.idf_ver }}
env:
TEST_DIR: components/esp_websocket_client/${{ matrix.test.path }}
TEST_DIR: components/esp_websocket_client/examples
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
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
esptool.py --chip ${{ matrix.idf_target }} merge_bin --fill-flash-size 4MB -o flash_image.bin @flash_args
- uses: actions/upload-artifact@v3
with:
name: websocket_bin_esp32_${{ matrix.idf_ver }}_${{ matrix.test.app }}
path: ${{ env.TEST_DIR }}/artifacts.zip
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
if-no-files-found: error
run-target-websocket:
@ -51,36 +64,32 @@ jobs:
strategy:
fail-fast: false
matrix:
idf_ver: ["release-v5.0", "release-v5.1", "latest"]
idf_ver: ["release-v5.0", "latest"]
idf_target: ["esp32"]
test: [ { app: example, path: "examples/target" }, { app: unit_test, path: "test" } ]
runs-on:
- self-hosted
- ESP32-ETHERNET-KIT
env:
TEST_DIR: components/esp_websocket_client/${{ matrix.test.path }}
TEST_DIR: components/esp_websocket_client/examples
steps:
- uses: actions/checkout@v3
- uses: actions/download-artifact@v3
with:
name: websocket_bin_esp32_${{ matrix.idf_ver }}_${{ matrix.test.app }}
path: ${{ env.TEST_DIR }}/ci/
name: examples_app_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}
path: ${{ env.TEST_DIR }}/build/
- name: Install Python packages
env:
PIP_EXTRA_INDEX_URL: "https://www.piwheels.org/simple"
run: |
pip install --only-binary cryptography --extra-index-url https://dl.espressif.com/pypi/ -r $GITHUB_WORKSPACE/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: |
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
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@v3
if: always()
with:
name: results_${{ matrix.test.app }}_${{ matrix.idf_target }}_${{ matrix.idf_ver }}.xml
path: components/esp_websocket_client/${{ matrix.test.path }}/*.xml
name: examples_results_${{ matrix.idf_target }}_${{ matrix.idf_ver }}
path: ${{ env.TEST_DIR }}/*.xml

View File

@ -43,7 +43,7 @@ repos:
hooks:
- id: eradicate
- repo: https://github.com/espressif/check-copyright/
rev: v1.0.3
rev: v1.0.1
hooks:
- id: check-copyright
args: ['--ignore', 'ci/check_copyright_ignore.txt', '--config', 'ci/check_copyright_config.yaml']
@ -57,12 +57,12 @@ repos:
hooks:
- id: commitizen
- id: commitizen-branch
stages: [push, manual]
stages: [push]
- 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|examples)\)\:)'
entry: '\A(?!(feat|fix|ci|bump|test|docs)\((mdns|modem|common|websocket|asio|mqtt_cxx)\)\:)'
language: pygrep
args: [--multiline]
stages: [commit-msg]

View File

@ -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 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
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

View File

@ -1,35 +1,26 @@
# Collection of protocol components for ESP-IDF
## How to use
The [ESP-Protocols](https://github.com/espressif/esp-protocols) repository contains a collection of protocol components for [ESP-IDF](https://github.com/espressif/esp-idf).
Additionally, each component is available in [IDF Component Registry](https://components.espressif.com).
Please refer to instructions in [ESP-IDF](https://github.com/espressif/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://docs.espressif.com/projects/esp-protocols/esp_modem/docs/latest/index.html)
* Full html [documentation](https://espressif.github.io/esp-protocols/esp_modem/index.html)
### mDNS
* Brief introduction [README](components/mdns/README.md)
* 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)
* 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)
### esp_websocket_client
* Brief introduction [README](components/esp_websocket_client/README.md)
* Full html [documentation](https://docs.espressif.com/projects/esp-protocols/esp_websocket_client/docs/latest/index.html)
* Full html [documentation](https://espressif.github.io/esp-protocols/esp_websocket_client/index.html)
### ASIO port
* Brief introduction [README](components/asio/README.md)
* 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)
* Full html [documentation](https://espressif.github.io/esp-protocols/asio/index.html)

View File

@ -7,6 +7,7 @@ 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
@ -23,35 +24,27 @@ 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']
# 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
print(args.paths)
setup_logging(2)
apps = find_apps(
args.paths,
recursive=args.recursive,
recursive=True,
target=args.target,
build_dir='build_@t_@w',
config_rules_str=args.rules,
config_rules_str=[
'sdkconfig.ci=default', 'sdkconfig.ci.*=', '=default'
],
build_log_path='build_log.txt',
size_json_path='size.json' if not args.linux else None,
size_json_path='size.json',
check_warnings=True,
preserve=not args.delete,
manifest_files=args.manifests,
preserve=True,
manifest_files=[
str(p) for p in Path('.').glob('**/.build-test-rules.yml')
],
default_build_targets=SUPPORTED_TARGETS,
manifest_rootpath='.',
)
@ -63,5 +56,5 @@ if __name__ == '__main__':
build_apps(apps,
dry_run=False,
keep_going=False,
ignore_warning_strs=ignore_warning)
)
ignore_warning_strs=os.environ['EXPECTED_WARNING']
if 'EXPECTED_WARNING' in os.environ else None))

23
ci/bump
View File

@ -1,23 +0,0 @@
#!/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}"

View File

@ -93,13 +93,6 @@ 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()

View File

@ -29,7 +29,6 @@ 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/**'
@ -58,7 +57,7 @@ slim_modem_examples:
ignore:
perform_check: no
include:
- '**/docs/**'
- 'components/**/docs/**'
- 'components/esp_modem/port/linux/**'
- 'components/asio/examples/**'
- 'components/mdns/**/esp_system_protocols_linux/**'

View File

@ -1,41 +0,0 @@
#!/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"

View File

@ -1 +0,0 @@
DeprecationWarning: pkg_resources is deprecated as an API

View File

@ -1,272 +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>
#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);
}

View File

@ -1,6 +0,0 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once

View File

@ -1,109 +0,0 @@
/*
* 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();
}

View File

@ -1,31 +0,0 @@
/*
* 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();
}

View File

@ -1,34 +0,0 @@
/*
* 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

View File

@ -1,78 +0,0 @@
/*
* 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;
}

View File

@ -6,8 +6,8 @@ Asio is a cross-platform C++ library, see https://think-async.com/Asio/. It prov
## Examples
Get started with examples [examples](https://github.com/espressif/esp-protocols/tree/master/components/asio/examples)
Get started with example test :example:`examples <examples/..>`:
## Documentation
* View the full [html documentation](https://docs.espressif.com/projects/esp-protocols/asio/docs/latest/index.html)
* View the full [html documentation](https://espressif.github.io/esp-protocols/asio/index.html)

View File

@ -0,0 +1,26 @@
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

View File

@ -1,4 +0,0 @@
dependencies:
## Required IDF version
idf: ">=5.0"
espressif/asio: ">=1.0.1"

View File

@ -1,4 +0,0 @@
dependencies:
## Required IDF version
idf: ">=5.0"
espressif/asio: ">=1.0.1"

View File

@ -1,4 +0,0 @@
dependencies:
## Required IDF version
idf: ">=5.0"
espressif/asio: ">=1.0.1"

View File

@ -1,4 +0,0 @@
dependencies:
## Required IDF version
idf: ">=5.0"
espressif/asio: ">=1.0.1"

View File

@ -1,4 +0,0 @@
dependencies:
## Required IDF version
idf: ">=5.0"
espressif/asio: ">=1.0.1"

View File

@ -1,4 +0,0 @@
dependencies:
## Required IDF version
idf: ">=5.0"
espressif/asio: ">=1.0.1"

View File

@ -3,6 +3,6 @@ commitizen:
bump_message: 'bump(modem): $current_version -> $new_version'
pre_bump_hooks: python ../../ci/changelog.py esp_modem
tag_format: modem-v$version
version: 1.0.1
version: 1.0.0
version_files:
- idf_component.yml

View File

@ -1,20 +1,5 @@
# 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

View File

@ -47,3 +47,15 @@ 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()

View File

@ -16,17 +16,6 @@ menu "esp-modem"
in command mode might come fragmented in rare cases so might need to retry
AT commands.
config ESP_MODEM_USE_INFLATABLE_BUFFER_IF_NEEDED
bool "Use inflatable buffer in DCE"
default n
help
If enabled we will process the ongoing AT command by growing the current
buffer (if we've run out the preconfigured buffer).
If disabled, we simply report a failure.
Use this if additional allocation is not a problem and you need to reliably process
all commands, usually with sporadically longer responses than the configured buffer.
Could be also used to defragment AT replies in CMUX mode if CMUX_DEFRAGMENT_PAYLOAD=n
config ESP_MODEM_CMUX_DELAY_AFTER_DLCI_SETUP
int "Delay in ms to wait before creating another virtual terminal"
default 0

View File

@ -17,5 +17,5 @@ Get started with one of the examples:
## Documentation
* 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)
* Continue with esp-modem [brief overview](docs/README.md)
* View the full [html documentation](https://espressif.github.io/esp-protocols/esp_modem/index.html)

View File

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View File

Before

Width:  |  Height:  |  Size: 139 KiB

After

Width:  |  Height:  |  Size: 139 KiB

View File

@ -93,6 +93,14 @@ ALLOW_UNICODE_NAMES = NO
OUTPUT_LANGUAGE = English
# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all
# documentation generated by doxygen is written. Doxygen will use this
# information to generate all generated output in the proper direction.
# Possible values are: None, LTR, RTL and Context.
# The default value is: None.
OUTPUT_TEXT_DIRECTION = None
# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
# descriptions after the members that are listed in the file and class
# documentation (similar to Javadoc). Set to NO to disable this.
@ -259,6 +267,13 @@ ALIASES =
# A mapping has the form "name=value". For example adding "class=itcl::class"
# will allow you to use the command class in the itcl::class meaning.
TCL_SUBST =
# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
# only. Doxygen will then generate output that is more tailored for C. For
# instance, some of the names that are used will be different. The list of all
# members will be omitted, etc.
# The default value is: NO.
OPTIMIZE_OUTPUT_FOR_C = NO
@ -814,25 +829,22 @@ WARN_LOGFILE =
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
# Note: If this tag is empty the current directory is searched.
INPUT = \
$(PROJECT_PATH)/../components/esp_modem/include/esp_modem_api.h \
$(PROJECT_PATH)/../components/esp_modem/include/esp_modem_c_api_types.h \
$(PROJECT_PATH)/../components/esp_modem/include/cxx_include/esp_modem_api.hpp \
$(PROJECT_PATH)/../components/esp_modem/include/esp_modem_config.h \
$(PROJECT_PATH)/../components/esp_modem/include/esp_modem_dce_config.h \
$(PROJECT_PATH)/../components/esp_modem/include/cxx_include/esp_modem_dce_factory.hpp \
$(PROJECT_PATH)/../components/esp_modem/include/cxx_include/esp_modem_command_library.hpp \
$(PROJECT_PATH)/../components/esp_modem/include/cxx_include/esp_modem_dce_module.hpp \
$(PROJECT_PATH)/../components/esp_modem/include/cxx_include/esp_modem_dte.hpp \
$(PROJECT_PATH)/../components/esp_modem/include/cxx_include/esp_modem_netif.hpp \
$(PROJECT_PATH)/../components/esp_modem/include/cxx_include/esp_modem_types.hpp \
$(PROJECT_PATH)/../components/esp_modem/include/cxx_include/esp_modem_terminal.hpp \
$(PROJECT_PATH)/../components/esp_modem/include/cxx_include/esp_modem_cmux.hpp \
$(PROJECT_PATH)/../components/esp_modem/include/cxx_include/esp_modem_dce.hpp \
$(PROJECT_PATH)/../docs/esp_modem/en/esp_modem_api_commands.h \
$(PROJECT_PATH)/../docs/esp_modem/en/esp_modem_dce.hpp
INPUT = ../include/esp_modem_api.h \
../include/esp_modem_c_api_types.h \
../include/cxx_include/esp_modem_api.hpp \
../include/cxx_include/esp_modem_dce.hpp \
../include/esp_modem_config.h \
../include/esp_modem_dce_config.h \
../include/cxx_include/esp_modem_dce_factory.hpp \
../include/cxx_include/esp_modem_command_library.hpp \
../include/cxx_include/esp_modem_dce_module.hpp \
../include/cxx_include/esp_modem_dte.hpp \
../include/cxx_include/esp_modem_netif.hpp \
../include/cxx_include/esp_modem_types.hpp \
../include/cxx_include/esp_modem_terminal.hpp \
../include/cxx_include/esp_modem_cmux.hpp \
esp_modem_api_commands.h \
esp_modem_dce.hpp
# The last two are generated
# This tag can be used to specify the character encoding of the source files
@ -1082,6 +1094,12 @@ VERBATIM_HEADERS = YES
ALPHABETICAL_INDEX = YES
# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
# which the alphabetical index list will be split.
# Minimum value: 1, maximum value: 20, default value: 5.
# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
COLS_IN_ALPHA_INDEX = 5
# In case all classes in a project start with a common prefix, all classes will
# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
@ -1500,6 +1518,16 @@ EXT_LINKS_IN_WINDOW = NO
FORMULA_FONTSIZE = 10
# Use the FORMULA_TRANSPARENT tag to determine whether or not the images
# generated for formulas are transparent PNGs. Transparent PNGs are not
# supported properly for IE 6.0, but are supported on all modern browsers.
#
# Note that when changing this option you need to delete any form_*.png files in
# the HTML output directory before the changes have effect.
# The default value is: YES.
# This tag requires that the tag GENERATE_HTML is set to YES.
FORMULA_TRANSPARENT = YES
# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
# https://www.mathjax.org) which uses client side Javascript for the rendering
@ -1793,6 +1821,15 @@ LATEX_BATCHMODE = NO
LATEX_HIDE_INDICES = NO
# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
# code with syntax highlighting in the LaTeX output.
#
# Note that which sources are shown also depends on other settings such as
# SOURCE_BROWSER.
# The default value is: NO.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_SOURCE_CODE = NO
# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
# bibliography, e.g. plainnat, or ieeetr. See
@ -1874,6 +1911,15 @@ RTF_STYLESHEET_FILE =
RTF_EXTENSIONS_FILE =
# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
# with syntax highlighting in the RTF output.
#
# Note that which sources are shown also depends on other settings such as
# SOURCE_BROWSER.
# The default value is: NO.
# This tag requires that the tag GENERATE_RTF is set to YES.
RTF_SOURCE_CODE = NO
#---------------------------------------------------------------------------
# Configuration options related to the man page output
@ -1971,6 +2017,14 @@ GENERATE_DOCBOOK = NO
DOCBOOK_OUTPUT = docbook
# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
# program listings (including syntax highlighting and cross-referencing
# information) to the DOCBOOK output. Note that enabling this will significantly
# increase the size of the DOCBOOK output.
# The default value is: NO.
# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
DOCBOOK_PROGRAMLISTING = NO
#---------------------------------------------------------------------------
# Configuration options for the AutoGen Definitions output
@ -2150,6 +2204,14 @@ EXTERNAL_PAGES = YES
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
# NO turns the diagrams off. Note that this option also works with HAVE_DOT
# disabled, but it is recommended to install and use dot, since it yields more
# powerful graphs.
# The default value is: YES.
CLASS_DIAGRAMS = YES
# You can include diagrams made with dia in doxygen documentation. Doxygen will
# then run dia to produce the diagram and insert it in the documentation. The
@ -2183,7 +2245,22 @@ HAVE_DOT = YES
DOT_NUM_THREADS = 0
# When you want a differently looking font in the dot files that doxygen
# generates you can specify the font name using DOT_FONTNAME. You need to make
# sure dot is able to find the font, which can be done by putting it in a
# standard location or by setting the DOTFONTPATH environment variable or by
# setting DOT_FONTPATH to the directory containing the font.
# The default value is: Helvetica.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_FONTNAME = Helvetica
# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
# dot graphs.
# Minimum value: 4, maximum value: 24, default value: 10.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_FONTSIZE = 10
# By default doxygen will tell dot to use the default font as specified with
# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
@ -2397,6 +2474,17 @@ DOT_GRAPH_MAX_NODES = 250
MAX_DOT_GRAPH_DEPTH = 3
# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
# background. This is disabled by default, because dot on Windows does not seem
# to support this out of the box.
#
# Warning: Depending on the platform used, enabling this option may lead to
# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
# read).
# The default value is: NO.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_TRANSPARENT = NO
# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
# files in one run (i.e. multiple -o and -T options on the command line). This

View File

@ -0,0 +1,92 @@
# 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`

View File

@ -0,0 +1,23 @@
# 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

View File

@ -0,0 +1,36 @@
# 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
![DCE_architecture](DCE_DTE_collaboration.png)
## 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.
![CMUX Terminal](CMux_collaboration.png)

View File

@ -3,7 +3,7 @@ dependencies:
## Required IDF version
idf: ">=4.1.0"
espressif/esp_modem:
version: "^1.0.0"
version: "^0.1.20"
override_path: "../../../"
espressif/esp_modem_usb_dte:
version: "^1.1.0"

View File

@ -3,7 +3,7 @@ dependencies:
## Required IDF version
idf: ">=4.1.0"
espressif/esp_modem:
version: "^1.0.0"
version: "^0.1.23"
override_path: "../../../"
espressif/esp_modem_usb_dte:
version: "^1.1.0"

View File

@ -175,9 +175,6 @@ extern "C" void app_main(void)
#endif
assert(dce);
/* Try to connect to the network and publish an mqtt topic */
StatusHandler handler;
if (dte_config.uart_config.flow_control == ESP_MODEM_FLOW_CONTROL_HW) {
if (command_result::OK != dce->set_flow_control(2, 2)) {
ESP_LOGE(TAG, "Failed to set the set_flow_control mode");
@ -218,6 +215,8 @@ extern "C" void app_main(void)
}
#endif
/* Try to connect to the network and publish an mqtt topic */
StatusHandler handler;
if (!handler.wait_for(StatusHandler::IP_Event, 60000)) {
ESP_LOGE(TAG, "Cannot get IP within specified timeout... exiting");
return;

View File

@ -1,4 +1,4 @@
version: "1.0.1"
version: "1.0.0"
description: esp modem
url: https://github.com/espressif/esp-protocols/tree/master/components/esp_modem
dependencies:

View File

@ -236,14 +236,6 @@ public:
return nullptr;
}
template <typename T_Module>
static std::unique_ptr<DCE> create_unique_dce_from(const esp_modem::dce_config *config,
std::shared_ptr<esp_modem::DTE> dte,
esp_netif_t *netif)
{
return build_generic_DCE<T_Module, DCE, std::unique_ptr<DCE>>(config, std::move(dte), netif);
}
private:
ModemType m;

View File

@ -79,13 +79,6 @@ public:
*/
void set_read_cb(std::function<bool(uint8_t *data, size_t len)> f);
/**
* @brief Sets read callback for manual command processing
* Note that this API also locks the command API, which can only be used
* after you remove the callback by dte->on_read(nullptr)
*
* @param on_data Function to be called when a command response is available
*/
void on_read(got_line_cb on_data) override;
/**
@ -129,10 +122,10 @@ protected:
}
friend class Scoped<DTE>; /*!< Declaring "Scoped<DTE> lock(dte)" locks this instance */
private:
static const size_t GOT_LINE = SignalGroup::bit0; /*!< Bit indicating response available */
[[nodiscard]] bool setup_cmux(); /*!< Internal setup of CMUX mode */
[[nodiscard]] bool exit_cmux(); /*!< Exit of CMUX mode and cleanup */
void exit_cmux_internal(); /*!< Cleanup CMUX */
[[nodiscard]] bool exit_cmux(); /*!< Exit of CMUX mode */
Lock internal_lock{}; /*!< Locks DTE operations */
unique_buffer buffer; /*!< DTE buffer */
@ -140,73 +133,9 @@ private:
std::shared_ptr<Terminal> primary_term; /*!< Reference to the primary terminal (mostly for sending commands) */
std::shared_ptr<Terminal> secondary_term; /*!< Secondary terminal for this DTE */
modem_mode mode; /*!< DTE operation mode */
SignalGroup signal; /*!< Event group used to signal request-response operations */
command_result result; /*!< Command result of the currently exectuted command */
std::function<bool(uint8_t *data, size_t len)> on_data; /*!< on data callback for current terminal */
#ifdef CONFIG_ESP_MODEM_USE_INFLATABLE_BUFFER_IF_NEEDED
/**
* @brief Implements an extra buffer that is used to capture partial reads from underlying terminals
* when we run out of the standard buffer
*/
struct extra_buffer {
extra_buffer(): buffer(nullptr) {}
~extra_buffer()
{
delete buffer;
}
std::vector<uint8_t> *buffer;
size_t consumed{0};
void grow(size_t need_size);
void deflate()
{
grow(0);
consumed = 0;
}
[[nodiscard]] uint8_t *begin() const
{
return &buffer->at(0);
}
[[nodiscard]] uint8_t *current() const
{
return &buffer->at(0) + consumed;
}
} inflatable;
#endif // CONFIG_ESP_MODEM_USE_INFLATABLE_BUFFER_IF_NEEDED
/**
* @brief Set internal command callbacks to the underlying terminal.
* Here we capture command replies to be processed by supplied command callbacks in struct command_cb.
*/
void set_command_callbacks();
/**
* @brief This abstracts command callback processing and implements its locking, signaling of completion and timeouts.
*/
struct command_cb {
static const size_t GOT_LINE = SignalGroup::bit0; /*!< Bit indicating response available */
got_line_cb got_line; /*!< Supplied command callback */
Lock line_lock{}; /*!< Command callback locking mechanism */
char separator{}; /*!< Command reply separator (end of line/processing unit) */
command_result result{}; /*!< Command return code */
SignalGroup signal; /*!< Event group used to signal request-response operations */
bool process_line(uint8_t *data, size_t consumed, size_t len); /*!< Lets the processing callback handle one line (processing unit) */
bool wait_for_line(uint32_t time_ms); /*!< Waiting for command processing */
void set(got_line_cb l, char s = '\n') /*!< Sets the command callback atomically */
{
Scoped<Lock> lock(line_lock);
if (l) {
// if we set the line callback, we have to reset the signal and the result
signal.clear(GOT_LINE);
result = command_result::TIMEOUT;
}
got_line = std::move(l);
separator = s;
}
void give_up() /*!< Reports other than timeout error when processing replies (out of buffer) */
{
result = command_result::FAIL;
signal.set(GOT_LINE);
}
} command_cb; /*!< Command callback utility class */
};
/**

View File

@ -54,9 +54,8 @@ public:
*/
void stop();
void receive(uint8_t *data, size_t len);
private:
void receive(uint8_t *data, size_t len);
static esp_err_t esp_modem_dte_transmit(void *h, void *buffer, size_t len);

View File

@ -13,7 +13,7 @@
// limitations under the License.
#pragma once
#include "generate/esp_modem_command_declare_helper.inc"
#include "esp_modem_command_declare_helper.inc"
#define DECLARE_ALL_COMMAND_APIS(...) \

View File

@ -21,17 +21,10 @@ static bool exit_data(DTE &dte, ModuleIf &device, Netif &netif)
netif.stop();
auto signal = std::make_shared<SignalGroup>();
std::weak_ptr<SignalGroup> weak_signal = signal;
dte.set_read_cb([&netif, weak_signal](uint8_t *data, size_t len) -> bool {
// post the transitioning data to the network layers if it contains PPP SOF marker
if (memchr(data, 0x7E, len))
{
ESP_LOG_BUFFER_HEXDUMP("esp-modem: debug_data (PPP)", data, len, ESP_LOG_DEBUG);
netif.receive(data, len);
}
// treat the transitioning data as a textual message if it contains a newline char
dte.set_read_cb([weak_signal](uint8_t *data, size_t len) -> bool {
if (memchr(data, '\n', len))
{
ESP_LOG_BUFFER_HEXDUMP("esp-modem: debug_data (CMD)", data, len, ESP_LOG_DEBUG);
ESP_LOG_BUFFER_HEXDUMP("esp-modem: debug_data", data, len, ESP_LOG_DEBUG);
const auto pass = std::list<std::string_view>({"NO CARRIER", "DISCONNECTED"});
std::string_view response((char *) data, len);
for (auto &it : pass)
@ -46,7 +39,6 @@ static bool exit_data(DTE &dte, ModuleIf &device, Netif &netif)
});
netif.wait_until_ppp_exits();
if (!signal->wait(1, 2000)) {
dte.set_read_cb(nullptr);
if (!device.set_mode(modem_mode::COMMAND_MODE)) {
return false;
}

View File

@ -17,118 +17,53 @@ static const size_t dte_default_buffer_size = 1000;
DTE::DTE(const esp_modem_dte_config *config, std::unique_ptr<Terminal> terminal):
buffer(config->dte_buffer_size),
cmux_term(nullptr), primary_term(std::move(terminal)), secondary_term(primary_term),
mode(modem_mode::UNDEF)
{
set_command_callbacks();
}
mode(modem_mode::UNDEF) {}
DTE::DTE(std::unique_ptr<Terminal> terminal):
buffer(dte_default_buffer_size),
cmux_term(nullptr), primary_term(std::move(terminal)), secondary_term(primary_term),
mode(modem_mode::UNDEF)
{
set_command_callbacks();
}
mode(modem_mode::UNDEF) {}
DTE::DTE(const esp_modem_dte_config *config, std::unique_ptr<Terminal> t, std::unique_ptr<Terminal> s):
buffer(config->dte_buffer_size),
cmux_term(nullptr), primary_term(std::move(t)), secondary_term(std::move(s)),
mode(modem_mode::UNDEF)
{
set_command_callbacks();
}
mode(modem_mode::DUAL_MODE) {}
DTE::DTE(std::unique_ptr<Terminal> t, std::unique_ptr<Terminal> s):
buffer(dte_default_buffer_size),
cmux_term(nullptr), primary_term(std::move(t)), secondary_term(std::move(s)),
mode(modem_mode::UNDEF)
{
set_command_callbacks();
}
void DTE::set_command_callbacks()
{
primary_term->set_read_cb([this](uint8_t *data, size_t len) {
Scoped<Lock> l(command_cb.line_lock);
if (command_cb.got_line == nullptr) {
return false;
}
if (data) {
// For terminals which post data directly with the callback (CMUX)
// we cannot defragment unless we allocate, but
// we'll try to process the data on the actual buffer
#ifdef CONFIG_ESP_MODEM_USE_INFLATABLE_BUFFER_IF_NEEDED
if (inflatable.consumed != 0) {
inflatable.grow(inflatable.consumed + len);
std::memcpy(inflatable.current(), data, len);
data = inflatable.begin();
}
if (command_cb.process_line(data, inflatable.consumed, len)) {
return true;
}
// at this point we're sure that the data processing hasn't finished,
// and we have to grow the inflatable buffer (if enabled) or give up
if (inflatable.consumed == 0) {
inflatable.grow(len);
std::memcpy(inflatable.begin(), data, len);
}
inflatable.consumed += len;
return false;
#else
if (command_cb.process_line(data, 0, len)) {
return true;
}
// cannot inflate and the processing hasn't finishes in the first iteration -> report a failure
command_cb.give_up();
return true;
#endif
}
// data == nullptr: Terminals which request users to read current data
// we're able to use DTE's buffer to defragment it; as long as we consume less that the buffer size
if (buffer.size > buffer.consumed) {
data = buffer.get();
len = primary_term->read(data + buffer.consumed, buffer.size - buffer.consumed);
if (command_cb.process_line(data, buffer.consumed, len)) {
return true;
}
buffer.consumed += len;
return false;
}
// we have used the entire DTE's buffer, need to use the inflatable buffer to continue
#ifdef CONFIG_ESP_MODEM_USE_INFLATABLE_BUFFER_IF_NEEDED
if (inflatable.consumed == 0) {
inflatable.grow(buffer.size + len);
std::memcpy(inflatable.begin(), buffer.get(), buffer.size);
inflatable.consumed = buffer.size;
} else {
inflatable.grow(inflatable.consumed + len);
}
len = primary_term->read(inflatable.current(), len);
if (command_cb.process_line(inflatable.begin(), inflatable.consumed, len)) {
return true;
}
inflatable.consumed += len;
return false;
#else
// cannot inflate -> report a failure
command_cb.give_up();
return true;
#endif
});
}
mode(modem_mode::DUAL_MODE) {}
command_result DTE::command(const std::string &command, got_line_cb got_line, uint32_t time_ms, const char separator)
{
Scoped<Lock> l1(internal_lock);
command_cb.set(got_line, separator);
Scoped<Lock> l(internal_lock);
result = command_result::TIMEOUT;
signal.clear(GOT_LINE);
primary_term->set_read_cb([this, got_line, separator](uint8_t *data, size_t len) {
if (!data) {
data = buffer.get();
len = primary_term->read(data + buffer.consumed, buffer.size - buffer.consumed);
} else {
buffer.consumed = 0; // if the underlying terminal contains data, we cannot fragment
}
if (memchr(data + buffer.consumed, separator, len)) {
result = got_line(data, buffer.consumed + len);
if (result == command_result::OK || result == command_result::FAIL) {
signal.set(GOT_LINE);
return true;
}
}
buffer.consumed += len;
return false;
});
primary_term->write((uint8_t *)command.c_str(), command.length());
command_cb.wait_for_line(time_ms);
command_cb.set(nullptr);
auto got_lf = signal.wait(GOT_LINE, time_ms);
if (got_lf && result == command_result::TIMEOUT) {
ESP_MODEM_THROW_IF_ERROR(ESP_ERR_INVALID_STATE);
}
buffer.consumed = 0;
#ifdef CONFIG_ESP_MODEM_USE_INFLATABLE_BUFFER_IF_NEEDED
inflatable.deflate();
#endif
return command_cb.result;
primary_term->set_read_cb(nullptr);
return result;
}
command_result DTE::command(const std::string &cmd, got_line_cb got_line, uint32_t time_ms)
@ -141,22 +76,12 @@ bool DTE::exit_cmux()
if (!cmux_term->deinit()) {
return false;
}
exit_cmux_internal();
return true;
}
void DTE::exit_cmux_internal()
{
if (!cmux_term) {
return;
}
auto ejected = cmux_term->detach();
// return the ejected terminal and buffer back to this DTE
primary_term = std::move(ejected.first);
buffer = std::move(ejected.second);
secondary_term = primary_term;
set_command_callbacks();
return true;
}
bool DTE::setup_cmux()
@ -165,21 +90,14 @@ bool DTE::setup_cmux()
if (cmux_term == nullptr) {
return false;
}
if (!cmux_term->init()) {
exit_cmux_internal();
cmux_term = nullptr;
return false;
}
primary_term = std::make_unique<CMuxInstance>(cmux_term, 0);
primary_term = std::make_unique<CMuxInstance>(cmux_term, 0);
if (primary_term == nullptr) {
return false;
}
secondary_term = std::make_unique<CMuxInstance>(cmux_term, 1);
if (primary_term == nullptr || secondary_term == nullptr) {
exit_cmux_internal();
cmux_term = nullptr;
return false;
}
set_command_callbacks();
return true;
}
@ -201,7 +119,6 @@ bool DTE::set_mode(modem_mode m)
if (mode == modem_mode::CMUX_MODE || mode == modem_mode::CMUX_MANUAL_MODE || mode == modem_mode::DUAL_MODE) {
// mode stays the same, but need to swap terminals (as command has been switched)
secondary_term.swap(primary_term);
set_command_callbacks();
} else {
mode = m;
}
@ -244,7 +161,6 @@ bool DTE::set_mode(modem_mode m)
// manual CMUX transitions: Swap terminals
if (m == modem_mode::CMUX_MANUAL_SWAP && mode == modem_mode::CMUX_MANUAL_MODE) {
secondary_term.swap(primary_term);
set_command_callbacks();
return true;
}
mode = modem_mode::UNDEF;
@ -253,10 +169,6 @@ bool DTE::set_mode(modem_mode m)
void DTE::set_read_cb(std::function<bool(uint8_t *, size_t)> f)
{
if (f == nullptr) {
set_command_callbacks();
return;
}
on_data = std::move(f);
secondary_term->set_read_cb([this](uint8_t *data, size_t len) {
if (!data) { // if no data available from terminal callback -> need to explicitly read some
@ -318,41 +230,6 @@ void DTE::on_read(got_line_cb on_read_cb)
});
}
bool DTE::command_cb::process_line(uint8_t *data, size_t consumed, size_t len)
{
if (memchr(data + consumed, separator, len)) {
result = got_line(data, consumed + len);
if (result == command_result::OK || result == command_result::FAIL) {
signal.set(GOT_LINE);
return true;
}
}
return false;
}
bool DTE::command_cb::wait_for_line(uint32_t time_ms)
{
auto got_lf = signal.wait(command_cb::GOT_LINE, time_ms);
if (got_lf && result == command_result::TIMEOUT) {
ESP_MODEM_THROW_IF_ERROR(ESP_ERR_INVALID_STATE);
}
return got_lf;
}
#ifdef CONFIG_ESP_MODEM_USE_INFLATABLE_BUFFER_IF_NEEDED
void DTE::extra_buffer::grow(size_t need_size)
{
if (need_size == 0) {
delete buffer;
buffer = nullptr;
} else if (buffer == nullptr) {
buffer = new std::vector<uint8_t>(need_size);
} else {
buffer->resize(need_size);
}
}
#endif
/**
* Implemented here to keep all headers C++11 compliant
*/

View File

@ -65,7 +65,9 @@ esp_err_t Netif::esp_modem_post_attach(esp_netif_t *esp_netif, void *args)
void Netif::receive(uint8_t *data, size_t len)
{
esp_netif_receive(driver.base.netif, data, len, nullptr);
if (signal.is_any(PPP_STARTED)) {
esp_netif_receive(driver.base.netif, data, len, nullptr);
}
}
Netif::Netif(std::shared_ptr<DTE> e, esp_netif_t *ppp_netif) :
@ -87,8 +89,8 @@ void Netif::start()
receive(data, len);
return true;
});
signal.set(PPP_STARTED);
esp_netif_action_start(driver.base.netif, nullptr, 0, nullptr);
signal.set(PPP_STARTED);
}
void Netif::stop()

View File

@ -8,11 +8,6 @@
#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()
@ -23,7 +18,7 @@ uart_resource::~uart_resource()
}
uart_resource::uart_resource(const esp_modem_uart_term_config *config, QueueHandle_t *event_queue, int fd)
: port(UART_NUM_MAX)
: port(-1)
{
esp_err_t res;
@ -49,9 +44,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_HW_FIFO_LEN(config->port_num) - 8);
res = uart_set_hw_flow_ctrl(config->port_num, UART_HW_FLOWCTRL_CTS_RTS, UART_FIFO_LEN - 8);
} else if (config->flow_control == ESP_MODEM_FLOW_CONTROL_SW) {
res = uart_set_sw_flow_ctrl(config->port_num, true, 8, UART_HW_FIFO_LEN(config->port_num) - 8);
res = uart_set_sw_flow_ctrl(config->port_num, true, 8, UART_FIFO_LEN - 8);
}
ESP_MODEM_THROW_IF_ERROR(res, "config uart flow control failed");

View File

@ -64,6 +64,7 @@ public:
void set_read_cb(std::function<bool(uint8_t *data, size_t len)> f) override
{
ESP_MODEM_THROW_IF_FALSE(signal.wait(TASK_PARAMS, 1000), "Failed to set UART task params");
on_read = std::move(f);
}
@ -90,6 +91,7 @@ private:
static const size_t TASK_INIT = BIT0;
static const size_t TASK_START = BIT1;
static const size_t TASK_STOP = BIT2;
static const size_t TASK_PARAMS = BIT3;
QueueHandle_t event_queue;
uart_resource uart;
@ -116,7 +118,9 @@ void UartTerminal::task()
return; // exits to the static method where the task gets deleted
}
while (signal.is_any(TASK_START)) {
signal.set(TASK_PARAMS);
if (get_event(event, 100)) {
signal.clear(TASK_PARAMS);
switch (event.type) {
case UART_DATA:
uart_get_buffered_data_len(uart.port, &len);

View File

@ -13,3 +13,15 @@ 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()

View File

@ -12,12 +12,3 @@ 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()

View File

@ -1,13 +0,0 @@
# esp_mqtt_cxx
[![Component Registry](https://components.espressif.com/components/espressif/esp_mqtt_cxx/badge.svg)](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)

View File

@ -21,8 +21,8 @@ PROJECT_NAME = "MQTT C++ client"
## and used to include in API reference documentation
INPUT = \
$(PROJECT_PATH)/../components/esp_mqtt_cxx/include/esp_mqtt.hpp \
$(PROJECT_PATH)/../components/esp_mqtt_cxx/include/esp_mqtt_client_config.hpp
$(PROJECT_PATH)/include/esp_mqtt.hpp \
$(PROJECT_PATH)/include/esp_mqtt_client_config.hpp
## Get warnings for functions that have no documentation for their parameters or return value
##

View File

@ -36,8 +36,8 @@ Events are dispatched throug calls to member functions each one dedicated to a t
Application Example
-------------------
* :example:`tcp <../../components/esp_mqtt_cxx/examples/tcp>`
* :example:`ssl <../../components/esp_mqtt_cxx/examples/ssl>`
* :example:`tcp <../examples/tcp>`
* :example:`ssl <../examples/ssl>`
API Reference
-------------

View File

@ -0,0 +1,26 @@
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

View File

@ -92,35 +92,8 @@ void config_client_credentials(esp_mqtt_client_config_t &mqtt_client_cfg, Client
{
mqtt_client_cfg.credentials.authentication.password = password.data.c_str();
},
[&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;
},
[](ClientCertificate const & certificate) {},
[](SecureElement const & enable_secure_element) {},
[]([[maybe_unused ]]auto & unknown)
{
static_assert(always_false<decltype(unknown)>, "Missing type handler for variant handler");

View File

@ -1,5 +0,0 @@
dependencies:
## Required IDF version
idf: ">=5.0"
espressif/esp_mqtt_cxx:
version: "^0.1.0"

View File

@ -1,5 +0,0 @@
dependencies:
## Required IDF version
idf: ">=5.0"
espressif/esp_mqtt_cxx:
version: "^0.1.0"

View File

@ -1,8 +0,0 @@
---
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.1.0
version_files:
- idf_component.yml

View File

@ -1,30 +1,5 @@
# Changelog
## [1.1.0](https://github.com/espressif/esp-protocols/commits/websocket-v1.1.0)
### Features
- Added linux port for websocket ([a22391a](https://github.com/espressif/esp-protocols/commit/a22391a))
### Bug Fixes
- added idf_component.yml for examples ([d273e10](https://github.com/espressif/esp-protocols/commit/d273e10))
## [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

View File

@ -1,5 +1,3 @@
idf_build_get_property(target IDF_TARGET)
if(NOT CONFIG_WS_TRANSPORT AND NOT CMAKE_BUILD_EARLY_EXPANSION)
message(STATUS "Websocket transport is disabled so the esp_websocket_client component will not be built")
# note: the component is still included in the build so it can become visible again in config
@ -8,14 +6,8 @@ if(NOT CONFIG_WS_TRANSPORT AND NOT CMAKE_BUILD_EARLY_EXPANSION)
return()
endif()
if(${IDF_TARGET} STREQUAL "linux")
idf_component_register(SRCS "esp_websocket_client.c"
INCLUDE_DIRS "include"
REQUIRES esp-tls tcp_transport http_parser esp_event nvs_flash esp_stubs json
PRIV_REQUIRES esp_timer)
else()
idf_component_register(SRCS "esp_websocket_client.c"
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)
endif()
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")

View File

@ -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](https://github.com/espressif/esp-protocols/tree/master/components/esp_websocket_client/examples):
Get started with example test [Example](examples/README.md):
## Documentation
* View the full [html documentation](https://docs.espressif.com/projects/esp-protocols/esp_websocket_client/docs/latest/index.html)
* View the full [html documentation](https://espressif.github.io/esp-protocols/esp_websocket_client/index.html)

View File

@ -21,7 +21,7 @@ PROJECT_NAME = "ESP Protocols Programming Guide"
## and used to include in API reference documentation
INPUT = \
$(PROJECT_PATH)/../components/mdns/include/mdns.h
$(PROJECT_PATH)/include/esp_websocket_client.h
## Get warnings for functions that have no documentation for their parameters or return value
##

View File

@ -109,7 +109,7 @@ Limitations and Known Issues
Application Example
-------------------
A simple WebSocket example that uses esp_websocket_client to establish a websocket connection and send/receive data with the `websocket.org <https://websocket.org>`_ server can be found here: `example <https://github.com/espressif/esp-protocols/tree/master/components/esp_websocket_client/examples>`_
A simple WebSocket example that uses esp_websocket_client to establish a websocket connection and send/receive data with the `websocket.org <https://websocket.org>`_ server can be found here: :example:`example <../examples>`.
Sending Text Data
^^^^^^^^^^^^^^^^^

View File

@ -0,0 +1,26 @@
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

View File

@ -19,9 +19,6 @@
#include "esp_log.h"
#include "esp_timer.h"
#include "esp_tls_crypto.h"
#include "esp_system.h"
#include <errno.h>
#include <arpa/inet.h>
static const char *TAG = "websocket_client";
@ -427,9 +424,7 @@ static void destroy_and_free_resources(esp_websocket_client_handle_t client)
free(client->if_name);
}
esp_websocket_client_destroy_config(client);
if (client->transport_list) {
esp_transport_list_destroy(client->transport_list);
}
esp_transport_list_destroy(client->transport_list);
vQueueDelete(client->lock);
free(client->tx_buffer);
free(client->rx_buffer);
@ -853,8 +848,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 {
@ -1103,13 +1098,14 @@ 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 || (data == NULL && len > 0)) {
if (client == NULL || len < 0 ||
(opcode != WS_TRANSPORT_OPCODES_CLOSE && (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 %" PRIu32 " timeout", timeout);
ESP_LOGE(TAG, "Could not lock ws-client within %d timeout", timeout);
return ESP_FAIL;
}

View File

@ -2,9 +2,9 @@
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
set(EXTRA_COMPONENT_DIRS "../..")
set(EXTRA_COMPONENT_DIRS "..")
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
list(APPEND EXTRA_COMPONENT_DIRS "../../../../common_components/protocol_examples_common")
list(APPEND EXTRA_COMPONENT_DIRS "../../../common_components/protocol_examples_common")
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(websocket_example)

View File

@ -1,15 +0,0 @@
cmake_minimum_required(VERSION 3.5)
set(COMPONENTS esp_websocket_client main)
set(common_component_dir ../../../../common_components)
set(EXTRA_COMPONENT_DIRS
../../..
"${common_component_dir}/linux_compat/esp_timer"
"${common_component_dir}/linux_compat"
"${common_component_dir}/linux_compat/freertos")
list(APPEND EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common)
list(APPEND EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/protocols/linux_stubs/esp_stubs)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(websocket)

View File

@ -1,14 +0,0 @@
idf_component_register(SRCS "main.c"
INCLUDE_DIRS
"."
REQUIRES esp_websocket_client protocol_examples_common)
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_websocket_client esp_websocket_client COMPONENT_LIB)
target_compile_options(${esp_websocket_client} PUBLIC --coverage -fprofile-arcs -ftest-coverage)
target_link_options(${esp_websocket_client} PUBLIC --coverage -fprofile-arcs -ftest-coverage)
endif()

Some files were not shown because too many files have changed in this diff Show More