mirror of
https://github.com/espressif/esp-protocols.git
synced 2025-07-26 16:57:28 +02:00
Compare commits
74 Commits
mdns-v1.1.
...
websocket-
Author | SHA1 | Date | |
---|---|---|---|
b992ef6914 | |||
9cc594afaa | |||
4cf9e505e1 | |||
c8c05075fb | |||
cb6e03ac62 | |||
2e42b9bb49 | |||
86f7a8bbe3 | |||
7b5a41deea | |||
38d50eede0 | |||
27303d28b2 | |||
d273e10819 | |||
60c87ddf26 | |||
a95891e211 | |||
411dced3e2 | |||
42fe60828f | |||
36899f1135 | |||
0714e100ee | |||
cbfee945a0 | |||
71bb461ed8 | |||
5143f5ac01 | |||
7e83741615 | |||
b880fc0367 | |||
f6d5186e5b | |||
8eb3a0feea | |||
28cd898eca | |||
a22391ae2c | |||
f5a0d5fb40 | |||
ecc465daa3 | |||
181b6e4013 | |||
40e3875f76 | |||
ddc3eb62d0 | |||
3625889049 | |||
2bd6163ec8 | |||
f1eb46580e | |||
1c20328dcf | |||
6de22f3893 | |||
e280b3b541 | |||
00d7c40848 | |||
4f1769ec71 | |||
20dd910b3a | |||
3635e2fabc | |||
84035d8f3b | |||
e620eb5fb1 | |||
7d4755f119 | |||
588465d9db | |||
c443326a34 | |||
79a0e57ca1 | |||
68392f0ba9 | |||
a67cbbcab9 | |||
b5177cb23a | |||
cab0e1d10e | |||
fbc79a846b | |||
a50f91f422 | |||
4910e89249 | |||
c562461711 | |||
8b9c957fe0 | |||
f0df12dad3 | |||
9637517192 | |||
e085826dbb | |||
c974c14220 | |||
247baeed22 | |||
613d67d1cf | |||
441f79022e | |||
4de52981cb | |||
ef1c5eb28a | |||
9a3aa1d23f | |||
64b0e4ef1a | |||
fcff00740a | |||
1102133458 | |||
4f54c49912 | |||
910f6ffadc | |||
9836a8620f | |||
af0ed62ecf | |||
217a96a2e4 |
2
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
2
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
@ -8,7 +8,7 @@ body:
|
||||
label: Answers checklist.
|
||||
description: Before submitting a new issue, please follow the checklist and try to find the answer.
|
||||
options:
|
||||
- label: I have read the documentation for [esp-protocols components](https://espressif.github.io/esp-protocols/) and the issue is not addressed there.
|
||||
- label: I have read the documentation for esp-protocols [components](https://github.com/espressif/esp-protocols#readme) and the issue is not addressed there.
|
||||
required: true
|
||||
- label: I have updated my esp-protocols branch (master or release) to the latest version and checked that the issue is present there.
|
||||
required: true
|
||||
|
4
.github/ISSUE_TEMPLATE/config.yml
vendored
4
.github/ISSUE_TEMPLATE/config.yml
vendored
@ -1,7 +1,7 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: esp-protocols documentation
|
||||
url: https://espressif.github.io/esp-protocols/
|
||||
- name: esp-protocols documentation links
|
||||
url: https://github.com/espressif/esp-protocols#readme
|
||||
about: Documenation for esp-protocols components.
|
||||
- name: ESP-IDF Programming Guide
|
||||
url: https://docs.espressif.com/projects/esp-idf/en/latest/
|
||||
|
2
.github/ISSUE_TEMPLATE/other-issue.yml
vendored
2
.github/ISSUE_TEMPLATE/other-issue.yml
vendored
@ -7,7 +7,7 @@ body:
|
||||
label: Answers checklist.
|
||||
description: Before submitting a new issue, please follow the checklist and try to find the answer.
|
||||
options:
|
||||
- label: I have read the documentation for [esp-protocols components](https://espressif.github.io/esp-protocols/) and the issue is not addressed there.
|
||||
- label: I have read the documentation for esp-protocols [components](https://github.com/espressif/esp-protocols#readme) and the issue is not addressed there.
|
||||
required: true
|
||||
- label: I have updated my esp-protocols branch (master or release) to the latest version and checked that the issue is present there.
|
||||
required: true
|
||||
|
48
.github/workflows/examples_build-host-test.yml
vendored
Normal file
48
.github/workflows/examples_build-host-test.yml
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
name: "examples: build/host-tests"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, labeled]
|
||||
|
||||
jobs:
|
||||
build_all_examples:
|
||||
if: contains(github.event.pull_request.labels.*.name, 'examples') || github.event_name == 'push'
|
||||
name: Build examples
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest", "release-v5.1"]
|
||||
runs-on: ubuntu-20.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v3
|
||||
- name: Build with IDF-${{ matrix.idf_ver }}
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
python -m pip install idf-build-apps
|
||||
# Build default configs for all targets
|
||||
python ./ci/build_apps.py examples -m examples/.build-test-rules.yml -d -c
|
||||
|
||||
build_and_run_on_host:
|
||||
if: contains(github.event.pull_request.labels.*.name, 'examples') || github.event_name == 'push'
|
||||
name: Build and run examples on linux
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest"]
|
||||
runs-on: ubuntu-20.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v3
|
||||
- name: Build with IDF-${{ matrix.idf_ver }}
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
python -m pip install idf-build-apps
|
||||
python ./ci/build_apps.py examples/mqtt -l -t linux
|
||||
timeout 5 ./examples/mqtt/build_linux_default/esp_mqtt_demo.elf | tee test.log || true
|
||||
grep 'MQTT_EVENT_DATA' test.log
|
2
.github/workflows/mdns__host-tests.yml
vendored
2
.github/workflows/mdns__host-tests.yml
vendored
@ -12,7 +12,7 @@ jobs:
|
||||
if: contains(github.event.pull_request.labels.*.name, 'mdns') || github.event_name == 'push'
|
||||
name: Host test
|
||||
runs-on: ubuntu-20.04
|
||||
container: espressif/idf:latest
|
||||
container: espressif/idf:release-v5.1
|
||||
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
|
37
.github/workflows/modem__build-host-tests.yml
vendored
37
.github/workflows/modem__build-host-tests.yml
vendored
@ -91,6 +91,8 @@ jobs:
|
||||
if: contains(github.event.pull_request.labels.*.name, 'modem') || github.event_name == 'push'
|
||||
name: Run gcovr on esp modem host test
|
||||
runs-on: ubuntu-22.04
|
||||
permissions:
|
||||
contents: write
|
||||
container: espressif/idf:release-v4.3
|
||||
env:
|
||||
lwip: lwip-2.1.2
|
||||
@ -102,11 +104,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
|
||||
@ -126,10 +128,9 @@ 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 docs_gcovr
|
||||
cp $GITHUB_WORKSPACE/${{ env.COMP_DIR }}/index.html docs_gcovr
|
||||
touch docs_gcovr/.nojekyll
|
||||
|
||||
mkdir modem_coverage_report
|
||||
cp $GITHUB_WORKSPACE/${{ env.COMP_DIR }}/index.html modem_coverage_report
|
||||
cp -rf modem_coverage_report $GITHUB_WORKSPACE
|
||||
- name: Code Coverage Summary Report
|
||||
uses: irongut/CodeCoverageSummary@v1.3.0
|
||||
with:
|
||||
@ -142,7 +143,6 @@ jobs:
|
||||
indicators: true
|
||||
output: both
|
||||
thresholds: '60 80'
|
||||
|
||||
- name: Write to Job Summary
|
||||
run: cat code-coverage-results.md >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
@ -150,28 +150,7 @@ jobs:
|
||||
uses: actions/upload-artifact@v3
|
||||
if: always()
|
||||
with:
|
||||
name: docs_gcovr
|
||||
name: modem_coverage_report
|
||||
path: |
|
||||
${{ env.COMP_DIR }}/docs_gcovr
|
||||
${{ env.COMP_DIR }}/modem_coverage_report
|
||||
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'
|
||||
|
2
.github/workflows/modem__target-test.yml
vendored
2
.github/workflows/modem__target-test.yml
vendored
@ -58,7 +58,7 @@ jobs:
|
||||
needs: build_esp_modem_tests
|
||||
runs-on:
|
||||
- self-hosted
|
||||
- BrnoRPI-GH006
|
||||
- modem
|
||||
env:
|
||||
TEST_DIR: components/esp_modem/${{ matrix.test.path }}
|
||||
steps:
|
||||
|
45
.github/workflows/publish-coverage-report.yml
vendored
Normal file
45
.github/workflows/publish-coverage-report.yml
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
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
|
74
.github/workflows/publish-docs-component.yml
vendored
74
.github/workflows/publish-docs-component.yml
vendored
@ -10,7 +10,7 @@ env:
|
||||
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 : ${{ secrets.DOCS_DEPLOY_PATH }}
|
||||
DOCS_DEPLOY_PATH_ORIG : ${{ secrets.DOCS_DEPLOY_PATH }}
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
@ -43,27 +43,51 @@ jobs:
|
||||
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
|
||||
# cd $GITHUB_WORKSPACE/docs
|
||||
# ./generate_docs
|
||||
# - name: Deploying generated docs
|
||||
# if: always()
|
||||
# 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
|
||||
# export DOCS_BUILD_DIR=$GITHUB_WORKSPACE/docs
|
||||
# deploy-docs
|
||||
# - name: Upload components to component service
|
||||
# uses: espressif/github-actions/upload_components@master
|
||||
# with:
|
||||
# directories: "components/esp_modem;components/esp_websocket_client;components/mdns;components/asio;components/esp_mqtt_cxx"
|
||||
# namespace: "espressif"
|
||||
# api_token: ${{ secrets.IDF_COMPONENT_API_TOKEN }}
|
||||
- name: Generate docs
|
||||
shell: bash
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install doxygen clang python3-pip
|
||||
python -m pip install breathe recommonmark esp-docs==1.4.1
|
||||
for comp in `ls components`; do
|
||||
cd $GITHUB_WORKSPACE/docs/${comp}
|
||||
if [[ "${{ env.BUMP_COMPONENT }}" == "${comp}" ]]; then
|
||||
echo "Building specific version of ${comp} (${{ env.BUMP_VERSION }})"
|
||||
./generate_docs ${{ env.BUMP_VERSION }}
|
||||
else
|
||||
echo "Building latest version of ${comp}"
|
||||
./generate_docs
|
||||
fi
|
||||
done
|
||||
- name: Deploying generated docs
|
||||
shell: bash
|
||||
run: |
|
||||
source $GITHUB_WORKSPACE/docs/utils.sh
|
||||
add_doc_server_ssh_keys $DOCS_DEPLOY_KEY $DOCS_DEPLOY_SERVER $DOCS_DEPLOY_SERVER_USER
|
||||
export GIT_VER=$(git describe --always)
|
||||
export GITHUB_REF_NAME=latest
|
||||
for comp in `ls components`; do
|
||||
echo "Deploying latest of ${comp}"
|
||||
export DOCS_BUILD_DIR=$GITHUB_WORKSPACE/docs/${comp}
|
||||
export DOCS_DEPLOY_PATH=$DOCS_DEPLOY_PATH_ORIG/${comp}
|
||||
cd $GITHUB_WORKSPACE/docs/${comp}
|
||||
deploy-docs
|
||||
done;
|
||||
# Deploy docs with version path
|
||||
if [[ "${{ env.BUMP_VERSION }}" != "" ]]; then
|
||||
echo "Deploying specific version of ${comp} (${{ env.BUMP_VERSION }})"
|
||||
cd $GITHUB_WORKSPACE/docs/${{ env.BUMP_COMPONENT }}
|
||||
export GITHUB_REF_NAME=${{ env.BUMP_VERSION }}
|
||||
deploy-docs
|
||||
fi
|
||||
- name: Upload components to component service
|
||||
uses: espressif/upload-components-ci-action@v1
|
||||
with:
|
||||
directories: >
|
||||
components/asio;
|
||||
components/esp_modem;
|
||||
components/esp_mqtt_cxx;
|
||||
components/esp_websocket_client;
|
||||
components/mdns;
|
||||
namespace: "espressif"
|
||||
api_token: ${{ secrets.IDF_COMPONENT_API_TOKEN }}
|
||||
|
86
.github/workflows/run-host-tests.yml
vendored
Normal file
86
.github/workflows/run-host-tests.yml
vendored
Normal file
@ -0,0 +1,86 @@
|
||||
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
|
20
.github/workflows/websocket__build-host-tests.yml
vendored
Normal file
20
.github/workflows/websocket__build-host-tests.yml
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
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
|
@ -13,45 +13,32 @@ jobs:
|
||||
name: Build
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["release-v5.0", "latest"]
|
||||
idf_target: ["esp32"]
|
||||
idf_ver: ["release-v5.0", "release-v5.1", "latest"]
|
||||
test: [ { app: example, path: "examples/target" }, { app: unit_test, path: "test" } ]
|
||||
runs-on: ubuntu-20.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
env:
|
||||
TEST_DIR: components/esp_websocket_client/examples
|
||||
TEST_DIR: components/esp_websocket_client/${{ matrix.test.path }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
|
||||
env:
|
||||
IDF_TARGET: ${{ matrix.idf_target }}
|
||||
shell: bash
|
||||
working-directory: ${{ env.TEST_DIR }}
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
cat sdkconfig.ci >> sdkconfig.defaults
|
||||
idf.py build
|
||||
- name: Merge binaries
|
||||
working-directory: ${{ env.TEST_DIR }}/build
|
||||
env:
|
||||
IDF_TARGET: ${{ matrix.idf_target }}
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
esptool.py --chip ${{ matrix.idf_target }} merge_bin --fill-flash-size 4MB -o flash_image.bin @flash_args
|
||||
python -m pip install idf-build-apps
|
||||
python ./ci/build_apps.py ${TEST_DIR}
|
||||
cd ${TEST_DIR}
|
||||
for dir in `ls -d build_esp32_*`; do
|
||||
$GITHUB_WORKSPACE/ci/clean_build_artifacts.sh `pwd`/$dir
|
||||
zip -qur artifacts.zip $dir
|
||||
done
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: examples_app_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}
|
||||
path: |
|
||||
${{ env.TEST_DIR }}/build/bootloader/bootloader.bin
|
||||
${{ env.TEST_DIR }}/build/partition_table/partition-table.bin
|
||||
${{ env.TEST_DIR }}/build/*.bin
|
||||
${{ env.TEST_DIR }}/build/*.elf
|
||||
${{ env.TEST_DIR }}/build/flasher_args.json
|
||||
${{ env.TEST_DIR }}/build/config/sdkconfig.h
|
||||
${{ env.TEST_DIR }}/build/config/sdkconfig.json
|
||||
name: websocket_bin_esp32_${{ matrix.idf_ver }}_${{ matrix.test.app }}
|
||||
path: ${{ env.TEST_DIR }}/artifacts.zip
|
||||
if-no-files-found: error
|
||||
|
||||
run-target-websocket:
|
||||
@ -64,32 +51,36 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
idf_ver: ["release-v5.0", "latest"]
|
||||
idf_ver: ["release-v5.0", "release-v5.1", "latest"]
|
||||
idf_target: ["esp32"]
|
||||
test: [ { app: example, path: "examples/target" }, { app: unit_test, path: "test" } ]
|
||||
runs-on:
|
||||
- self-hosted
|
||||
- ESP32-ETHERNET-KIT
|
||||
env:
|
||||
TEST_DIR: components/esp_websocket_client/examples
|
||||
TEST_DIR: components/esp_websocket_client/${{ matrix.test.path }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: examples_app_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}
|
||||
path: ${{ env.TEST_DIR }}/build/
|
||||
name: websocket_bin_esp32_${{ matrix.idf_ver }}_${{ matrix.test.app }}
|
||||
path: ${{ env.TEST_DIR }}/ci/
|
||||
- name: Install Python packages
|
||||
env:
|
||||
PIP_EXTRA_INDEX_URL: "https://www.piwheels.org/simple"
|
||||
run: |
|
||||
pip install --only-binary cryptography --extra-index-url https://dl.espressif.com/pypi/ -r $GITHUB_WORKSPACE/ci/requirements.txt
|
||||
- name: Download Example Test to target
|
||||
run: python -m esptool --chip ${{ matrix.idf_target }} write_flash 0x0 components/esp_websocket_client/examples/build/flash_image.bin
|
||||
- name: Run Example Test on target
|
||||
working-directory: ${{ env.TEST_DIR }}
|
||||
run: |
|
||||
python -m pytest --log-cli-level DEBUG --junit-xml=./examples_results_${{ matrix.idf_target }}_${{ matrix.idf_ver }}.xml --target=${{ matrix.idf_target }}
|
||||
unzip ci/artifacts.zip -d ci
|
||||
for dir in `ls -d ci/build_*`; do
|
||||
rm -rf build sdkconfig.defaults
|
||||
mv $dir build
|
||||
python -m pytest --log-cli-level DEBUG --junit-xml=./results_${{ matrix.test.app }}_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${dir#"ci/build_"}.xml --target=${{ matrix.idf_target }}
|
||||
done
|
||||
- uses: actions/upload-artifact@v3
|
||||
if: always()
|
||||
with:
|
||||
name: examples_results_${{ matrix.idf_target }}_${{ matrix.idf_ver }}
|
||||
path: ${{ env.TEST_DIR }}/*.xml
|
||||
name: results_${{ matrix.test.app }}_${{ matrix.idf_target }}_${{ matrix.idf_ver }}.xml
|
||||
path: components/esp_websocket_client/${{ matrix.test.path }}/*.xml
|
||||
|
@ -43,7 +43,7 @@ repos:
|
||||
hooks:
|
||||
- id: eradicate
|
||||
- repo: https://github.com/espressif/check-copyright/
|
||||
rev: v1.0.1
|
||||
rev: v1.0.3
|
||||
hooks:
|
||||
- id: check-copyright
|
||||
args: ['--ignore', 'ci/check_copyright_ignore.txt', '--config', 'ci/check_copyright_config.yaml']
|
||||
@ -62,7 +62,7 @@ repos:
|
||||
hooks:
|
||||
- id: commit message scopes
|
||||
name: "commit message must be scoped with: mdns, modem, websocket, asio, mqtt_cxx, common"
|
||||
entry: '\A(?!(feat|fix|ci|bump|test|docs)\((mdns|modem|common|websocket|asio|mqtt_cxx)\)\:)'
|
||||
entry: '\A(?!(feat|fix|ci|bump|test|docs)\((mdns|modem|common|websocket|asio|mqtt_cxx|examples)\)\:)'
|
||||
language: pygrep
|
||||
args: [--multiline]
|
||||
stages: [commit-msg]
|
||||
|
@ -1,5 +1,11 @@
|
||||
# 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)
|
||||
|
||||
## Components
|
||||
|
||||
### esp_modem
|
||||
|
@ -26,20 +26,29 @@ if __name__ == '__main__':
|
||||
parser.add_argument('-r', '--rules', nargs='*', default=['sdkconfig.ci=default', 'sdkconfig.ci.*=', '=default'], help='Rules how to treat configs')
|
||||
parser.add_argument('-m', '--manifests', nargs='*', default=[], help='list of manifest files')
|
||||
parser.add_argument('-d', '--delete', action='store_true', help='Delete build artifacts')
|
||||
parser.add_argument('-c', '--recursive', action='store_true', help='Build recursively')
|
||||
parser.add_argument('-l', '--linux', action='store_true', help='Include linux build (dont check warnings)')
|
||||
args = parser.parse_args()
|
||||
|
||||
IDF_PATH = os.environ['IDF_PATH']
|
||||
|
||||
print(args.paths)
|
||||
# Compose the ignore warning strings from the global list and from the environment
|
||||
ignore_warning_file = os.path.join(os.path.dirname(os.path.realpath(__file__)),'ignore_build_warnings.txt')
|
||||
ignore_warning = open(ignore_warning_file).read().rstrip('\n').split('\n')
|
||||
if 'EXPECTED_WARNING' in os.environ:
|
||||
ignore_warning += os.environ['EXPECTED_WARNING'].split('\n')
|
||||
if args.linux:
|
||||
SUPPORTED_TARGETS.append('linux')
|
||||
ignore_warning = 'warning: ' # Ignore all common warnings on linux builds
|
||||
setup_logging(2)
|
||||
apps = find_apps(
|
||||
args.paths,
|
||||
recursive=False,
|
||||
recursive=args.recursive,
|
||||
target=args.target,
|
||||
build_dir='build_@t_@w',
|
||||
config_rules_str=args.rules,
|
||||
build_log_path='build_log.txt',
|
||||
size_json_path='size.json',
|
||||
size_json_path='size.json' if not args.linux else None,
|
||||
check_warnings=True,
|
||||
preserve=not args.delete,
|
||||
manifest_files=args.manifests,
|
||||
@ -54,5 +63,5 @@ if __name__ == '__main__':
|
||||
build_apps(apps,
|
||||
dry_run=False,
|
||||
keep_going=False,
|
||||
ignore_warning_strs=os.environ['EXPECTED_WARNING']
|
||||
if 'EXPECTED_WARNING' in os.environ else None))
|
||||
ignore_warning_strs=ignore_warning)
|
||||
)
|
||||
|
@ -29,6 +29,7 @@ DEFAULT:
|
||||
# this section sets the default license for examples and unit tests of components
|
||||
examples_and_unit_tests:
|
||||
include:
|
||||
- 'examples/**'
|
||||
- 'components/**/examples/**'
|
||||
- 'components/**/test/**'
|
||||
- 'components/**/tests/**'
|
||||
|
@ -9,7 +9,7 @@ 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 has been updated"
|
||||
echo "${comp}: Component version file has changed"
|
||||
version=`grep version: components/${comp}/.cz.yaml`
|
||||
version=${version#*version: }
|
||||
|
||||
@ -17,20 +17,25 @@ if git log -1 -m --name-only --pretty="" | grep -q components/${comp}/idf_compon
|
||||
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
|
||||
|
||||
# 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}"
|
||||
|
||||
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"
|
||||
|
||||
# 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;
|
||||
exit 0;
|
||||
fi
|
||||
fi
|
||||
done
|
||||
echo "No changes in component version file"
|
||||
|
1
ci/ignore_build_warnings.txt
Normal file
1
ci/ignore_build_warnings.txt
Normal file
@ -0,0 +1 @@
|
||||
DeprecationWarning: pkg_resources is deprecated as an API
|
@ -7,6 +7,7 @@
|
||||
#include "esp_timer.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include <pthread.h>
|
||||
|
||||
void *create_tt(esp_timer_cb_t cb);
|
||||
|
||||
@ -37,3 +38,10 @@ esp_err_t esp_timer_delete(esp_timer_handle_t timer)
|
||||
destroy_tt(timer);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
int64_t esp_timer_get_time(void)
|
||||
{
|
||||
struct timespec spec;
|
||||
clock_gettime(CLOCK_REALTIME, &spec);
|
||||
return spec.tv_nsec / 1000 + spec.tv_sec * 1000000;
|
||||
}
|
@ -9,6 +9,11 @@
|
||||
#include <stdint.h>
|
||||
#include "bsd/string.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct esp_timer *esp_timer_handle_t;
|
||||
|
||||
typedef void (*esp_timer_cb_t)(void *arg);
|
||||
@ -32,3 +37,9 @@ esp_err_t esp_timer_start_periodic(esp_timer_handle_t timer, uint64_t period);
|
||||
esp_err_t esp_timer_stop(esp_timer_handle_t timer);
|
||||
|
||||
esp_err_t esp_timer_delete(esp_timer_handle_t timer);
|
||||
|
||||
int64_t esp_timer_get_time(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -1,4 +1,5 @@
|
||||
idf_component_register(SRCS freertos_linux.c queue_unique_ptr.cpp
|
||||
idf_component_register(SRCS freertos_linux.c
|
||||
osal/queue.cpp osal/event_group.cpp osal/mutex.cpp
|
||||
INCLUDE_DIRS include)
|
||||
|
||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
272
common_components/linux_compat/freertos/freertos_linux.c
Normal file
272
common_components/linux_compat/freertos/freertos_linux.c
Normal file
@ -0,0 +1,272 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include <pthread.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "osal/osal_api.h"
|
||||
|
||||
static uint64_t s_semaphore_data = 0;
|
||||
|
||||
typedef enum queue_type_tag {
|
||||
MUTEX_REC,
|
||||
MUTEX,
|
||||
SEMA,
|
||||
QUEUE,
|
||||
} queue_type_t;
|
||||
|
||||
struct generic_queue_handle {
|
||||
queue_type_t type;
|
||||
size_t item_size;
|
||||
void *q;
|
||||
};
|
||||
|
||||
static struct generic_queue_handle *create_generic_queue(queue_type_t type, uint32_t len, uint32_t item_size)
|
||||
{
|
||||
struct generic_queue_handle *h = calloc(1, sizeof(struct generic_queue_handle));
|
||||
h->item_size = len;
|
||||
h->type = type;
|
||||
switch (type) {
|
||||
default:
|
||||
case QUEUE:
|
||||
case SEMA:
|
||||
h->q = osal_queue_create();
|
||||
break;
|
||||
|
||||
case MUTEX:
|
||||
case MUTEX_REC:
|
||||
h->q = osal_mutex_create();
|
||||
break;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
QueueHandle_t xQueueCreate(uint32_t uxQueueLength, uint32_t uxItemSize )
|
||||
{
|
||||
return (QueueHandle_t)create_generic_queue(QUEUE, uxQueueLength, uxItemSize);
|
||||
}
|
||||
|
||||
uint32_t xQueueSend(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait)
|
||||
{
|
||||
struct generic_queue_handle *h = xQueue;
|
||||
return osal_queue_send(h->q, (uint8_t *)pvItemToQueue, h->item_size) ? pdTRUE : pdFAIL;
|
||||
}
|
||||
|
||||
uint32_t xQueueSendToBack(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait )
|
||||
{
|
||||
return xQueueSend(xQueue, pvItemToQueue, xTicksToWait);
|
||||
}
|
||||
|
||||
uint32_t xQueueReceive(QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksToWait)
|
||||
{
|
||||
struct generic_queue_handle *h = xQueue;
|
||||
return osal_queue_recv(h->q, (uint8_t *)pvBuffer, h->item_size, xTicksToWait) ? pdTRUE : pdFAIL;
|
||||
}
|
||||
|
||||
BaseType_t xSemaphoreGive( QueueHandle_t xQueue)
|
||||
{
|
||||
struct generic_queue_handle *h = xQueue;
|
||||
if (h->type == MUTEX) {
|
||||
osal_mutex_give(h->q);
|
||||
return pdTRUE;
|
||||
}
|
||||
return xQueueSend(xQueue, &s_semaphore_data, portMAX_DELAY);
|
||||
}
|
||||
|
||||
BaseType_t xSemaphoreGiveRecursive( QueueHandle_t xQueue)
|
||||
{
|
||||
struct generic_queue_handle *h = xQueue;
|
||||
if (h->type == MUTEX_REC) {
|
||||
osal_mutex_give(h->q);
|
||||
return pdTRUE;
|
||||
}
|
||||
return pdFALSE;
|
||||
}
|
||||
BaseType_t xSemaphoreTake( QueueHandle_t xQueue, TickType_t pvTask )
|
||||
{
|
||||
struct generic_queue_handle *h = xQueue;
|
||||
if (h->type == MUTEX) {
|
||||
osal_mutex_take(h->q);
|
||||
return pdTRUE;
|
||||
}
|
||||
return xQueueReceive(xQueue, &s_semaphore_data, portMAX_DELAY);
|
||||
}
|
||||
|
||||
|
||||
BaseType_t xSemaphoreTakeRecursive( QueueHandle_t xQueue, TickType_t pvTask )
|
||||
{
|
||||
struct generic_queue_handle *h = xQueue;
|
||||
if (h->type == MUTEX_REC) {
|
||||
osal_mutex_take(h->q);
|
||||
return pdTRUE;
|
||||
}
|
||||
return pdFALSE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void vQueueDelete( QueueHandle_t xQueue )
|
||||
{
|
||||
struct generic_queue_handle *h = xQueue;
|
||||
if (h->q) {
|
||||
if (h->type == MUTEX || h->type == MUTEX_REC) {
|
||||
osal_mutex_delete(h->q);
|
||||
} else {
|
||||
osal_queue_delete(h->q);
|
||||
}
|
||||
}
|
||||
free(xQueue);
|
||||
}
|
||||
|
||||
QueueHandle_t xSemaphoreCreateBinary(void)
|
||||
{
|
||||
QueueHandle_t sempaphore = xQueueCreate(1, 1);
|
||||
return sempaphore;
|
||||
}
|
||||
|
||||
QueueHandle_t xSemaphoreCreateMutex(void)
|
||||
{
|
||||
return (QueueHandle_t)create_generic_queue(MUTEX, 1, 1);
|
||||
}
|
||||
|
||||
QueueHandle_t xSemaphoreCreateRecursiveMutex(void)
|
||||
{
|
||||
return (QueueHandle_t)create_generic_queue(MUTEX_REC, 1, 1);
|
||||
}
|
||||
|
||||
|
||||
void vTaskDelete(TaskHandle_t *task)
|
||||
{
|
||||
if (task == NULL) {
|
||||
pthread_exit(0);
|
||||
}
|
||||
void *thread_rval = NULL;
|
||||
pthread_join((pthread_t)task, &thread_rval);
|
||||
}
|
||||
|
||||
void vTaskSuspend(void *task)
|
||||
{
|
||||
vTaskDelete(task);
|
||||
}
|
||||
|
||||
TickType_t xTaskGetTickCount( void )
|
||||
{
|
||||
struct timespec spec;
|
||||
clock_gettime(CLOCK_REALTIME, &spec);
|
||||
return spec.tv_nsec / 1000000 + spec.tv_sec * 1000;
|
||||
}
|
||||
|
||||
void vTaskDelay( const TickType_t xTicksToDelay )
|
||||
{
|
||||
usleep(xTicksToDelay * 1000);
|
||||
}
|
||||
|
||||
void *pthread_task(void *params)
|
||||
{
|
||||
struct {
|
||||
void *const param;
|
||||
TaskFunction_t task;
|
||||
bool started;
|
||||
} *pthread_params = params;
|
||||
|
||||
void *const param = pthread_params->param;
|
||||
TaskFunction_t task = pthread_params->task;
|
||||
pthread_params->started = true;
|
||||
|
||||
task(param);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BaseType_t xTaskCreatePinnedToCore( TaskFunction_t pvTaskCode,
|
||||
const char *const pcName,
|
||||
const uint32_t usStackDepth,
|
||||
void *const pvParameters,
|
||||
UBaseType_t uxPriority,
|
||||
TaskHandle_t *const pvCreatedTask,
|
||||
const BaseType_t xCoreID)
|
||||
{
|
||||
xTaskCreate(pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pvCreatedTask);
|
||||
return pdTRUE;
|
||||
}
|
||||
|
||||
|
||||
BaseType_t xTaskCreate(TaskFunction_t pvTaskCode, const char *const pcName, const uint32_t usStackDepth, void *const pvParameters, UBaseType_t uxPriority, TaskHandle_t *const pvCreatedTask)
|
||||
{
|
||||
pthread_t new_thread = (pthread_t)NULL;
|
||||
pthread_attr_t attr;
|
||||
struct {
|
||||
void *const param;
|
||||
TaskFunction_t task;
|
||||
bool started;
|
||||
} pthread_params = { .param = pvParameters, .task = pvTaskCode};
|
||||
int res = pthread_attr_init(&attr);
|
||||
assert(res == 0);
|
||||
res = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
|
||||
assert(res == 0);
|
||||
res = pthread_create(&new_thread, &attr, pthread_task, &pthread_params);
|
||||
assert(res == 0);
|
||||
|
||||
if (pvCreatedTask) {
|
||||
*pvCreatedTask = (void *)new_thread;
|
||||
}
|
||||
|
||||
// just wait till the task started so we can unwind params from the stack
|
||||
while (pthread_params.started == false) {
|
||||
usleep(1000);
|
||||
}
|
||||
return pdTRUE;
|
||||
}
|
||||
|
||||
void xTaskNotifyGive(TaskHandle_t task)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
BaseType_t xTaskNotifyWait(uint32_t bits_entry_clear, uint32_t bits_exit_clear, uint32_t *value, TickType_t wait_time )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
TaskHandle_t xTaskGetCurrentTaskHandle(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EventGroupHandle_t xEventGroupCreate( void )
|
||||
{
|
||||
return osal_signal_create();
|
||||
}
|
||||
|
||||
void vEventGroupDelete( EventGroupHandle_t xEventGroup )
|
||||
{
|
||||
osal_signal_delete(xEventGroup);
|
||||
}
|
||||
|
||||
EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear )
|
||||
{
|
||||
return osal_signal_clear(xEventGroup, uxBitsToClear);
|
||||
}
|
||||
|
||||
EventBits_t xEventGroupGetBits( EventGroupHandle_t xEventGroup)
|
||||
{
|
||||
return osal_signal_get(xEventGroup);
|
||||
}
|
||||
|
||||
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet )
|
||||
{
|
||||
return osal_signal_set(xEventGroup, uxBitsToSet);
|
||||
}
|
||||
|
||||
EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait )
|
||||
{
|
||||
return osal_signal_wait(xEventGroup, uxBitsToWaitFor, xWaitForAllBits, xTicksToWait);
|
||||
}
|
@ -10,3 +10,4 @@
|
||||
|
||||
#define ESP_TASK_PRIO_MAX 25
|
||||
#define ESP_TASKD_EVENT_PRIO 5
|
||||
#define ESP_TASKD_EVENT_STACK 1024
|
@ -16,7 +16,9 @@
|
||||
typedef void *SemaphoreHandle_t;
|
||||
typedef void *QueueHandle_t;
|
||||
typedef void *TaskHandle_t;
|
||||
typedef void *EventGroupHandle_t;
|
||||
typedef uint32_t TickType_t;
|
||||
typedef TickType_t EventBits_t;
|
||||
|
||||
typedef void (*TaskFunction_t)( void * );
|
||||
typedef unsigned int UBaseType_t;
|
||||
@ -30,6 +32,5 @@ typedef int BaseType_t;
|
||||
|
||||
#define pdMS_TO_TICKS(tick) (tick)
|
||||
|
||||
uint32_t esp_get_free_heap_size(void);
|
||||
uint32_t esp_random(void);
|
||||
void vTaskSuspendAll(void);
|
@ -0,0 +1,6 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
@ -3,11 +3,4 @@
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
//
|
||||
// Created by david on 1/13/23.
|
||||
//
|
||||
|
||||
#ifndef _QUEUE_H_
|
||||
#define _QUEUE_H_
|
||||
|
||||
#endif //_QUEUE_H_
|
||||
#pragma once
|
@ -3,11 +3,4 @@
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
//
|
||||
// Created by david on 1/13/23.
|
||||
//
|
||||
|
||||
#ifndef _SEMAPHR_H_
|
||||
#define _SEMAPHR_H_
|
||||
|
||||
#endif //_SEMAPHR_H_
|
||||
#pragma once
|
@ -7,6 +7,10 @@
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define TaskHandle_t TaskHandle_t
|
||||
#define vSemaphoreDelete( xSemaphore ) vQueueDelete( ( QueueHandle_t ) ( xSemaphore ) )
|
||||
|
||||
@ -26,7 +30,7 @@ BaseType_t xTaskCreatePinnedToCore( TaskFunction_t pvTaskCode,
|
||||
TaskHandle_t *const pvCreatedTask,
|
||||
const BaseType_t xCoreID);
|
||||
|
||||
void xTaskCreate(TaskFunction_t pvTaskCode, const char *const pcName, const uint32_t usStackDepth, void *const pvParameters, UBaseType_t uxPriority, TaskHandle_t *const pvCreatedTask);
|
||||
BaseType_t xTaskCreate(TaskFunction_t pvTaskCode, const char *const pcName, const uint32_t usStackDepth, void *const pvParameters, UBaseType_t uxPriority, TaskHandle_t *const pvCreatedTask);
|
||||
|
||||
TickType_t xTaskGetTickCount( void );
|
||||
|
||||
@ -35,11 +39,16 @@ void vQueueDelete( QueueHandle_t xQueue );
|
||||
QueueHandle_t xSemaphoreCreateBinary(void);
|
||||
|
||||
QueueHandle_t xSemaphoreCreateMutex(void);
|
||||
QueueHandle_t xSemaphoreCreateRecursiveMutex(void);
|
||||
|
||||
BaseType_t xSemaphoreGive( QueueHandle_t xQueue);
|
||||
|
||||
BaseType_t xSemaphoreTake( QueueHandle_t xQueue, TickType_t pvTask );
|
||||
|
||||
BaseType_t xSemaphoreGiveRecursive( QueueHandle_t xQueue);
|
||||
|
||||
BaseType_t xSemaphoreTakeRecursive( QueueHandle_t xQueue, TickType_t pvTask );
|
||||
|
||||
void vTaskDelete(TaskHandle_t *task);
|
||||
|
||||
QueueHandle_t xQueueCreate( uint32_t uxQueueLength,
|
||||
@ -48,3 +57,27 @@ QueueHandle_t xQueueCreate( uint32_t uxQueueLength,
|
||||
uint32_t xQueueSend(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait);
|
||||
|
||||
uint32_t xQueueReceive(QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksToWait);
|
||||
|
||||
void vTaskSuspend(void *task);
|
||||
|
||||
EventGroupHandle_t xEventGroupCreate( void );
|
||||
void vEventGroupDelete( EventGroupHandle_t xEventGroup );
|
||||
EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup,
|
||||
const EventBits_t uxBitsToClear );
|
||||
|
||||
EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup,
|
||||
const EventBits_t uxBitsToWaitFor,
|
||||
const BaseType_t xClearOnExit,
|
||||
const BaseType_t xWaitForAllBits,
|
||||
TickType_t xTicksToWait );
|
||||
|
||||
EventBits_t xEventGroupGetBits( EventGroupHandle_t xEventGroup);
|
||||
|
||||
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup,
|
||||
const EventBits_t uxBitsToSet );
|
||||
|
||||
uint32_t xQueueSendToBack(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif //__cplusplus
|
109
common_components/linux_compat/freertos/osal/event_group.cpp
Normal file
109
common_components/linux_compat/freertos/osal/event_group.cpp
Normal file
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include "osal_api.h"
|
||||
|
||||
|
||||
class SignalGroup {
|
||||
|
||||
struct SignalGroupInternal {
|
||||
std::condition_variable notify;
|
||||
std::mutex m;
|
||||
uint32_t flags{ 0 };
|
||||
};
|
||||
|
||||
using SignalT = std::unique_ptr<SignalGroupInternal>;
|
||||
|
||||
public:
|
||||
|
||||
void set(uint32_t bits)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(event_group->m);
|
||||
event_group->flags |= bits;
|
||||
event_group->notify.notify_all();
|
||||
}
|
||||
|
||||
uint32_t get()
|
||||
{
|
||||
return event_group->flags;
|
||||
}
|
||||
|
||||
void clear(uint32_t bits)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(event_group->m);
|
||||
event_group->flags &= ~bits;
|
||||
event_group->notify.notify_all();
|
||||
}
|
||||
|
||||
// waiting for all and clearing if set
|
||||
bool wait(uint32_t flags, uint32_t time_ms)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(event_group->m);
|
||||
return event_group->notify.wait_for(lock, std::chrono::milliseconds(time_ms), [&] {
|
||||
if ((flags & event_group->flags) == flags)
|
||||
{
|
||||
event_group->flags &= ~flags;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// waiting for any bit, not clearing them
|
||||
bool wait_any(uint32_t flags, uint32_t time_ms)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(event_group->m);
|
||||
return event_group->notify.wait_for(lock, std::chrono::milliseconds(time_ms), [&] { return flags & event_group->flags; });
|
||||
}
|
||||
|
||||
private:
|
||||
SignalT event_group{std::make_unique<SignalGroupInternal>()};
|
||||
};
|
||||
|
||||
|
||||
void *osal_signal_create()
|
||||
{
|
||||
auto signal = new SignalGroup;
|
||||
return signal;
|
||||
}
|
||||
|
||||
void osal_signal_delete(void *s)
|
||||
{
|
||||
delete static_cast<SignalGroup *>(s);
|
||||
}
|
||||
|
||||
uint32_t osal_signal_clear(void *s, uint32_t bits)
|
||||
{
|
||||
auto signal = static_cast<SignalGroup *>(s);
|
||||
signal->clear(bits);
|
||||
return signal->get();
|
||||
}
|
||||
|
||||
uint32_t osal_signal_set(void *s, uint32_t bits)
|
||||
{
|
||||
auto signal = static_cast<SignalGroup *>(s);
|
||||
signal->set(bits);
|
||||
return signal->get();
|
||||
}
|
||||
|
||||
uint32_t osal_signal_get(void *s)
|
||||
{
|
||||
auto signal = static_cast<SignalGroup *>(s);
|
||||
return signal->get();
|
||||
}
|
||||
|
||||
uint32_t osal_signal_wait(void *s, uint32_t flags, bool all, uint32_t timeout)
|
||||
{
|
||||
auto signal = static_cast<SignalGroup *>(s);
|
||||
if (all) {
|
||||
signal->wait(flags, timeout);
|
||||
} else {
|
||||
signal->wait_any(flags, timeout);
|
||||
}
|
||||
return signal->get();
|
||||
}
|
31
common_components/linux_compat/freertos/osal/mutex.cpp
Normal file
31
common_components/linux_compat/freertos/osal/mutex.cpp
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <queue>
|
||||
#include <mutex>
|
||||
#include "osal_api.h"
|
||||
|
||||
void *osal_mutex_create()
|
||||
{
|
||||
auto mut = new std::recursive_mutex();
|
||||
return mut;
|
||||
}
|
||||
|
||||
void osal_mutex_delete(void *mut)
|
||||
{
|
||||
delete static_cast<std::recursive_mutex *>(mut);
|
||||
}
|
||||
|
||||
void osal_mutex_take(void *m)
|
||||
{
|
||||
auto mut = static_cast<std::recursive_mutex *>(m);
|
||||
mut->lock();
|
||||
}
|
||||
|
||||
void osal_mutex_give(void *m)
|
||||
{
|
||||
auto mut = static_cast<std::recursive_mutex *>(m);
|
||||
mut->unlock();
|
||||
}
|
34
common_components/linux_compat/freertos/osal/osal_api.h
Normal file
34
common_components/linux_compat/freertos/osal/osal_api.h
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// queue api
|
||||
void *osal_queue_create(void);
|
||||
void osal_queue_delete(void *q);
|
||||
bool osal_queue_send(void *q, uint8_t *data, size_t len);
|
||||
bool osal_queue_recv(void *q, uint8_t *data, size_t len, uint32_t ms);
|
||||
|
||||
// mutex api
|
||||
void *osal_mutex_create(void);
|
||||
void osal_mutex_delete(void *m);
|
||||
void osal_mutex_take(void *m);
|
||||
void osal_mutex_give(void *m);
|
||||
|
||||
// event groups
|
||||
void *osal_signal_create(void);
|
||||
void osal_signal_delete(void *s);
|
||||
uint32_t osal_signal_clear(void *s, uint32_t bits);
|
||||
uint32_t osal_signal_set(void *s, uint32_t bits);
|
||||
uint32_t osal_signal_get(void *s);
|
||||
uint32_t osal_signal_wait(void *s, uint32_t flags, bool all, uint32_t timeout);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
78
common_components/linux_compat/freertos/osal/queue.cpp
Normal file
78
common_components/linux_compat/freertos/osal/queue.cpp
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
#include <queue>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include <atomic>
|
||||
#include "osal_api.h"
|
||||
|
||||
template <class T>
|
||||
class Queue {
|
||||
public:
|
||||
void send(std::unique_ptr<T> t)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m);
|
||||
q.push(std::move(t));
|
||||
c.notify_one();
|
||||
}
|
||||
|
||||
std::unique_ptr<T> receive(std::chrono::milliseconds ms)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m);
|
||||
while (q.empty()) {
|
||||
if (c.wait_for(lock, ms) == std::cv_status::timeout) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
std::unique_ptr<T> val = std::move(q.front());
|
||||
q.pop();
|
||||
return val;
|
||||
}
|
||||
|
||||
private:
|
||||
std::queue<std::unique_ptr<T>> q{};
|
||||
mutable std::mutex m{};
|
||||
std::condition_variable c{};
|
||||
};
|
||||
|
||||
using item_t = std::vector<uint8_t>;
|
||||
|
||||
void *osal_queue_create(void)
|
||||
{
|
||||
auto *q = new Queue<item_t>();
|
||||
return q;
|
||||
}
|
||||
|
||||
void osal_queue_delete(void *q)
|
||||
{
|
||||
auto *queue = static_cast<Queue<item_t> *>(q);
|
||||
delete (queue);
|
||||
}
|
||||
|
||||
bool osal_queue_send(void *q, uint8_t *data, size_t len)
|
||||
{
|
||||
auto v = std::make_unique<item_t>(len);
|
||||
v->assign(data, data + len);
|
||||
auto queue = static_cast<Queue<item_t> *>(q);
|
||||
queue->send(std::move(v));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool osal_queue_recv(void *q, uint8_t *data, size_t len, uint32_t ms)
|
||||
{
|
||||
auto queue = static_cast<Queue<item_t> *>(q);
|
||||
auto v = queue->receive(std::chrono::milliseconds(ms));
|
||||
if (v != nullptr) {
|
||||
memcpy(data, (void *)v->data(), len);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
dependencies:
|
||||
## Required IDF version
|
||||
idf: ">=5.0"
|
||||
espressif/asio: ">=1.0.1"
|
@ -0,0 +1,4 @@
|
||||
dependencies:
|
||||
## Required IDF version
|
||||
idf: ">=5.0"
|
||||
espressif/asio: ">=1.0.1"
|
4
components/asio/examples/socks4/main/idf_component.yml
Normal file
4
components/asio/examples/socks4/main/idf_component.yml
Normal file
@ -0,0 +1,4 @@
|
||||
dependencies:
|
||||
## Required IDF version
|
||||
idf: ">=5.0"
|
||||
espressif/asio: ">=1.0.1"
|
@ -0,0 +1,4 @@
|
||||
dependencies:
|
||||
## Required IDF version
|
||||
idf: ">=5.0"
|
||||
espressif/asio: ">=1.0.1"
|
@ -0,0 +1,4 @@
|
||||
dependencies:
|
||||
## Required IDF version
|
||||
idf: ">=5.0"
|
||||
espressif/asio: ">=1.0.1"
|
@ -0,0 +1,4 @@
|
||||
dependencies:
|
||||
## Required IDF version
|
||||
idf: ">=5.0"
|
||||
espressif/asio: ">=1.0.1"
|
@ -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.0
|
||||
version: 1.0.1
|
||||
version_files:
|
||||
- idf_component.yml
|
||||
|
@ -1,5 +1,20 @@
|
||||
# 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
|
||||
|
@ -47,15 +47,3 @@ if(${target} STREQUAL "linux")
|
||||
# This is needed for ESP_LOGx() macros, as integer formats differ on ESP32(..) and x64
|
||||
set_target_properties(${COMPONENT_LIB} PROPERTIES COMPILE_FLAGS -Wno-format)
|
||||
endif()
|
||||
|
||||
if(CONFIG_GCOV_ENABLED)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --coverage -fprofile-arcs -ftest-coverage")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --coverage -fprofile-arcs -ftest-coverage")
|
||||
|
||||
|
||||
MARK_AS_ADVANCED(
|
||||
CMAKE_CXX_FLAGS_COVERAGE
|
||||
CMAKE_C_FLAGS_COVERAGE
|
||||
CMAKE_EXE_LINKER_FLAGS_COVERAGE
|
||||
CMAKE_SHARED_LINKER_FLAGS_COVERAGE )
|
||||
endif()
|
||||
|
@ -16,6 +16,17 @@ 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
|
||||
|
@ -175,6 +175,9 @@ 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");
|
||||
@ -215,8 +218,6 @@ 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;
|
||||
|
@ -1,4 +1,4 @@
|
||||
version: "1.0.0"
|
||||
version: "1.0.1"
|
||||
description: esp modem
|
||||
url: https://github.com/espressif/esp-protocols/tree/master/components/esp_modem
|
||||
dependencies:
|
||||
|
@ -236,6 +236,14 @@ 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;
|
||||
|
||||
|
@ -79,6 +79,13 @@ 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;
|
||||
|
||||
/**
|
||||
@ -122,10 +129,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 */
|
||||
[[nodiscard]] bool exit_cmux(); /*!< Exit of CMUX mode and cleanup */
|
||||
void exit_cmux_internal(); /*!< Cleanup CMUX */
|
||||
|
||||
Lock internal_lock{}; /*!< Locks DTE operations */
|
||||
unique_buffer buffer; /*!< DTE buffer */
|
||||
@ -133,9 +140,73 @@ 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 */
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -54,9 +54,10 @@ public:
|
||||
*/
|
||||
void stop();
|
||||
|
||||
private:
|
||||
void receive(uint8_t *data, size_t len);
|
||||
|
||||
private:
|
||||
|
||||
static esp_err_t esp_modem_dte_transmit(void *h, void *buffer, size_t len);
|
||||
|
||||
static esp_err_t esp_modem_post_attach(esp_netif_t *esp_netif, void *args);
|
||||
|
@ -21,10 +21,17 @@ 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([weak_signal](uint8_t *data, size_t len) -> bool {
|
||||
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
|
||||
if (memchr(data, '\n', len))
|
||||
{
|
||||
ESP_LOG_BUFFER_HEXDUMP("esp-modem: debug_data", data, len, ESP_LOG_DEBUG);
|
||||
ESP_LOG_BUFFER_HEXDUMP("esp-modem: debug_data (CMD)", data, len, ESP_LOG_DEBUG);
|
||||
const auto pass = std::list<std::string_view>({"NO CARRIER", "DISCONNECTED"});
|
||||
std::string_view response((char *) data, len);
|
||||
for (auto &it : pass)
|
||||
@ -39,6 +46,7 @@ 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;
|
||||
}
|
||||
|
@ -17,53 +17,118 @@ 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) {}
|
||||
mode(modem_mode::UNDEF)
|
||||
{
|
||||
set_command_callbacks();
|
||||
}
|
||||
|
||||
DTE::DTE(std::unique_ptr<Terminal> terminal):
|
||||
buffer(dte_default_buffer_size),
|
||||
cmux_term(nullptr), primary_term(std::move(terminal)), secondary_term(primary_term),
|
||||
mode(modem_mode::UNDEF) {}
|
||||
mode(modem_mode::UNDEF)
|
||||
{
|
||||
set_command_callbacks();
|
||||
}
|
||||
|
||||
DTE::DTE(const esp_modem_dte_config *config, std::unique_ptr<Terminal> t, std::unique_ptr<Terminal> s):
|
||||
buffer(config->dte_buffer_size),
|
||||
cmux_term(nullptr), primary_term(std::move(t)), secondary_term(std::move(s)),
|
||||
mode(modem_mode::DUAL_MODE) {}
|
||||
mode(modem_mode::UNDEF)
|
||||
{
|
||||
set_command_callbacks();
|
||||
}
|
||||
|
||||
DTE::DTE(std::unique_ptr<Terminal> t, std::unique_ptr<Terminal> s):
|
||||
buffer(dte_default_buffer_size),
|
||||
cmux_term(nullptr), primary_term(std::move(t)), secondary_term(std::move(s)),
|
||||
mode(modem_mode::DUAL_MODE) {}
|
||||
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
|
||||
});
|
||||
}
|
||||
|
||||
command_result DTE::command(const std::string &command, got_line_cb got_line, uint32_t time_ms, const char separator)
|
||||
{
|
||||
Scoped<Lock> l(internal_lock);
|
||||
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;
|
||||
});
|
||||
Scoped<Lock> l1(internal_lock);
|
||||
command_cb.set(got_line, separator);
|
||||
primary_term->write((uint8_t *)command.c_str(), command.length());
|
||||
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);
|
||||
}
|
||||
command_cb.wait_for_line(time_ms);
|
||||
command_cb.set(nullptr);
|
||||
buffer.consumed = 0;
|
||||
primary_term->set_read_cb(nullptr);
|
||||
return result;
|
||||
#ifdef CONFIG_ESP_MODEM_USE_INFLATABLE_BUFFER_IF_NEEDED
|
||||
inflatable.deflate();
|
||||
#endif
|
||||
return command_cb.result;
|
||||
}
|
||||
|
||||
command_result DTE::command(const std::string &cmd, got_line_cb got_line, uint32_t time_ms)
|
||||
@ -76,12 +141,22 @@ 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;
|
||||
return true;
|
||||
set_command_callbacks();
|
||||
}
|
||||
|
||||
bool DTE::setup_cmux()
|
||||
@ -90,14 +165,21 @@ 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);
|
||||
if (primary_term == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
primary_term = std::make_unique<CMuxInstance>(cmux_term, 0);
|
||||
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;
|
||||
}
|
||||
|
||||
@ -119,6 +201,7 @@ 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;
|
||||
}
|
||||
@ -161,6 +244,7 @@ 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;
|
||||
@ -169,6 +253,10 @@ 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
|
||||
@ -230,6 +318,41 @@ 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
|
||||
*/
|
||||
|
@ -65,9 +65,7 @@ esp_err_t Netif::esp_modem_post_attach(esp_netif_t *esp_netif, void *args)
|
||||
|
||||
void Netif::receive(uint8_t *data, size_t len)
|
||||
{
|
||||
if (signal.is_any(PPP_STARTED)) {
|
||||
esp_netif_receive(driver.base.netif, data, len, nullptr);
|
||||
}
|
||||
esp_netif_receive(driver.base.netif, data, len, nullptr);
|
||||
}
|
||||
|
||||
Netif::Netif(std::shared_ptr<DTE> e, esp_netif_t *ppp_netif) :
|
||||
@ -89,8 +87,8 @@ void Netif::start()
|
||||
receive(data, len);
|
||||
return true;
|
||||
});
|
||||
esp_netif_action_start(driver.base.netif, nullptr, 0, nullptr);
|
||||
signal.set(PPP_STARTED);
|
||||
esp_netif_action_start(driver.base.netif, nullptr, 0, nullptr);
|
||||
}
|
||||
|
||||
void Netif::stop()
|
||||
|
@ -8,6 +8,11 @@
|
||||
#include "esp_modem_config.h"
|
||||
#include "uart_resource.hpp"
|
||||
|
||||
#ifndef UART_HW_FIFO_LEN
|
||||
// to build with IDF <= v5.1
|
||||
#define UART_HW_FIFO_LEN(uart_nr) UART_FIFO_LEN
|
||||
#endif
|
||||
|
||||
namespace esp_modem {
|
||||
|
||||
uart_resource::~uart_resource()
|
||||
@ -18,7 +23,7 @@ uart_resource::~uart_resource()
|
||||
}
|
||||
|
||||
uart_resource::uart_resource(const esp_modem_uart_term_config *config, QueueHandle_t *event_queue, int fd)
|
||||
: port(-1)
|
||||
: port(UART_NUM_MAX)
|
||||
{
|
||||
esp_err_t res;
|
||||
|
||||
@ -44,9 +49,9 @@ uart_resource::uart_resource(const esp_modem_uart_term_config *config, QueueHand
|
||||
ESP_MODEM_THROW_IF_ERROR(res, "config uart gpio failed");
|
||||
/* Set flow control threshold */
|
||||
if (config->flow_control == ESP_MODEM_FLOW_CONTROL_HW) {
|
||||
res = uart_set_hw_flow_ctrl(config->port_num, UART_HW_FLOWCTRL_CTS_RTS, UART_FIFO_LEN - 8);
|
||||
res = uart_set_hw_flow_ctrl(config->port_num, UART_HW_FLOWCTRL_CTS_RTS, UART_HW_FIFO_LEN(config->port_num) - 8);
|
||||
} else if (config->flow_control == ESP_MODEM_FLOW_CONTROL_SW) {
|
||||
res = uart_set_sw_flow_ctrl(config->port_num, true, 8, UART_FIFO_LEN - 8);
|
||||
res = uart_set_sw_flow_ctrl(config->port_num, true, 8, UART_HW_FIFO_LEN(config->port_num) - 8);
|
||||
}
|
||||
ESP_MODEM_THROW_IF_ERROR(res, "config uart flow control failed");
|
||||
|
||||
|
@ -64,7 +64,6 @@ 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);
|
||||
}
|
||||
|
||||
@ -91,7 +90,6 @@ 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;
|
||||
@ -118,9 +116,7 @@ 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);
|
||||
|
@ -13,15 +13,3 @@ idf_component_get_property(esp_modem esp_modem COMPONENT_LIB)
|
||||
target_compile_definitions(${esp_modem} PRIVATE "-DCONFIG_COMPILER_CXX_EXCEPTIONS")
|
||||
target_compile_definitions(${esp_modem} PRIVATE "-DCONFIG_IDF_TARGET_LINUX")
|
||||
target_link_options(${esp_modem} INTERFACE -fsanitize=address -fsanitize=undefined)
|
||||
|
||||
if(CONFIG_GCOV_ENABLED)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --coverage -fprofile-arcs -ftest-coverage")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --coverage -fprofile-arcs -ftest-coverage")
|
||||
|
||||
|
||||
MARK_AS_ADVANCED(
|
||||
CMAKE_CXX_FLAGS_COVERAGE
|
||||
CMAKE_C_FLAGS_COVERAGE
|
||||
CMAKE_EXE_LINKER_FLAGS_COVERAGE
|
||||
CMAKE_SHARED_LINKER_FLAGS_COVERAGE )
|
||||
endif()
|
||||
|
@ -12,3 +12,12 @@ set_target_properties(${COMPONENT_LIB} PROPERTIES
|
||||
CXX_EXTENSIONS ON
|
||||
)
|
||||
target_compile_definitions(${COMPONENT_LIB} PRIVATE "-DCONFIG_IDF_TARGET_LINUX")
|
||||
|
||||
if(CONFIG_GCOV_ENABLED)
|
||||
target_compile_options(${COMPONENT_LIB} PUBLIC --coverage -fprofile-arcs -ftest-coverage)
|
||||
target_link_options(${COMPONENT_LIB} PUBLIC --coverage -fprofile-arcs -ftest-coverage)
|
||||
|
||||
idf_component_get_property(esp_modem esp_modem COMPONENT_LIB)
|
||||
target_compile_options(${esp_modem} PUBLIC --coverage -fprofile-arcs -ftest-coverage)
|
||||
target_link_options(${esp_modem} PUBLIC --coverage -fprofile-arcs -ftest-coverage)
|
||||
endif()
|
||||
|
@ -0,0 +1,5 @@
|
||||
dependencies:
|
||||
## Required IDF version
|
||||
idf: ">=5.0"
|
||||
espressif/esp_mqtt_cxx:
|
||||
version: "^0.1.0"
|
@ -0,0 +1,5 @@
|
||||
dependencies:
|
||||
## Required IDF version
|
||||
idf: ">=5.0"
|
||||
espressif/esp_mqtt_cxx:
|
||||
version: "^0.1.0"
|
8
components/esp_websocket_client/.cz.yaml
Normal file
8
components/esp_websocket_client/.cz.yaml
Normal file
@ -0,0 +1,8 @@
|
||||
---
|
||||
commitizen:
|
||||
bump_message: 'bump(websocket): $current_version -> $new_version'
|
||||
pre_bump_hooks: python ../../ci/changelog.py esp_websocket_client
|
||||
tag_format: websocket-v$version
|
||||
version: 1.1.0
|
||||
version_files:
|
||||
- idf_component.yml
|
@ -1,5 +1,30 @@
|
||||
# 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
|
||||
|
@ -1,3 +1,5 @@
|
||||
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
|
||||
@ -6,8 +8,14 @@ if(NOT CONFIG_WS_TRANSPORT AND NOT CMAKE_BUILD_EARLY_EXPANSION)
|
||||
return()
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS "esp_websocket_client.c"
|
||||
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"
|
||||
INCLUDE_DIRS "include"
|
||||
REQUIRES lwip esp-tls tcp_transport http_parser
|
||||
PRIV_REQUIRES esp_timer esp_event)
|
||||
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")
|
||||
endif()
|
||||
|
@ -19,6 +19,9 @@
|
||||
#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";
|
||||
|
||||
@ -424,7 +427,9 @@ static void destroy_and_free_resources(esp_websocket_client_handle_t client)
|
||||
free(client->if_name);
|
||||
}
|
||||
esp_websocket_client_destroy_config(client);
|
||||
esp_transport_list_destroy(client->transport_list);
|
||||
if (client->transport_list) {
|
||||
esp_transport_list_destroy(client->transport_list);
|
||||
}
|
||||
vQueueDelete(client->lock);
|
||||
free(client->tx_buffer);
|
||||
free(client->rx_buffer);
|
||||
@ -1098,14 +1103,13 @@ int esp_websocket_client_send_with_opcode(esp_websocket_client_handle_t client,
|
||||
int wlen = 0, widx = 0;
|
||||
int ret = ESP_FAIL;
|
||||
|
||||
if (client == NULL || len < 0 ||
|
||||
(opcode != WS_TRANSPORT_OPCODES_CLOSE && (data == NULL || len <= 0))) {
|
||||
if (client == NULL || len < 0 || (data == NULL && len > 0)) {
|
||||
ESP_LOGE(TAG, "Invalid arguments");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
if (xSemaphoreTakeRecursive(client->lock, timeout) != pdPASS) {
|
||||
ESP_LOGE(TAG, "Could not lock ws-client within %d timeout", timeout);
|
||||
ESP_LOGE(TAG, "Could not lock ws-client within %" PRIu32 " timeout", timeout);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,15 @@
|
||||
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)
|
@ -0,0 +1,14 @@
|
||||
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()
|
@ -0,0 +1,15 @@
|
||||
menu "Host-test config"
|
||||
|
||||
config GCOV_ENABLED
|
||||
bool "Coverage analyzer"
|
||||
default n
|
||||
help
|
||||
Enables coverage analyzing for host tests.
|
||||
|
||||
config WEBSOCKET_URI
|
||||
string "Websocket endpoint URI"
|
||||
default "ws://echo.websocket.events"
|
||||
help
|
||||
URL of websocket endpoint this example connects to and sends echo
|
||||
|
||||
endmenu
|
122
components/esp_websocket_client/examples/linux/main/main.c
Normal file
122
components/esp_websocket_client/examples/linux/main/main.c
Normal file
@ -0,0 +1,122 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include "esp_log.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "protocol_examples_common.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/event_groups.h"
|
||||
|
||||
#include "esp_websocket_client.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_netif.h"
|
||||
|
||||
static const char *TAG = "websocket";
|
||||
|
||||
static void log_error_if_nonzero(const char *message, int error_code)
|
||||
{
|
||||
if (error_code != 0) {
|
||||
ESP_LOGE(TAG, "Last error %s: 0x%x", message, error_code);
|
||||
}
|
||||
}
|
||||
|
||||
static void websocket_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
|
||||
{
|
||||
esp_websocket_event_data_t *data = (esp_websocket_event_data_t *)event_data;
|
||||
switch (event_id) {
|
||||
case WEBSOCKET_EVENT_CONNECTED:
|
||||
ESP_LOGI(TAG, "WEBSOCKET_EVENT_CONNECTED");
|
||||
break;
|
||||
case WEBSOCKET_EVENT_DISCONNECTED:
|
||||
ESP_LOGI(TAG, "WEBSOCKET_EVENT_DISCONNECTED");
|
||||
log_error_if_nonzero("HTTP status code", data->error_handle.esp_ws_handshake_status_code);
|
||||
if (data->error_handle.error_type == WEBSOCKET_ERROR_TYPE_TCP_TRANSPORT) {
|
||||
log_error_if_nonzero("reported from esp-tls", data->error_handle.esp_tls_last_esp_err);
|
||||
log_error_if_nonzero("reported from tls stack", data->error_handle.esp_tls_stack_err);
|
||||
log_error_if_nonzero("captured as transport's socket errno", data->error_handle.esp_transport_sock_errno);
|
||||
}
|
||||
break;
|
||||
case WEBSOCKET_EVENT_DATA:
|
||||
ESP_LOGI(TAG, "WEBSOCKET_EVENT_DATA");
|
||||
ESP_LOGI(TAG, "Received opcode=%d", data->op_code);
|
||||
if (data->op_code == 0x08 && data->data_len == 2) {
|
||||
ESP_LOGW(TAG, "Received closed message with code=%d", 256 * data->data_ptr[0] + data->data_ptr[1]);
|
||||
} else {
|
||||
ESP_LOGW(TAG, "Received=%.*s", data->data_len, (char *)data->data_ptr);
|
||||
}
|
||||
|
||||
// If received data contains json structure it succeed to parse
|
||||
ESP_LOGW(TAG, "Total payload length=%d, data_len=%d, current payload offset=%d\r\n", data->payload_len, data->data_len, data->payload_offset);
|
||||
|
||||
break;
|
||||
case WEBSOCKET_EVENT_ERROR:
|
||||
ESP_LOGI(TAG, "WEBSOCKET_EVENT_ERROR");
|
||||
log_error_if_nonzero("HTTP status code", data->error_handle.esp_ws_handshake_status_code);
|
||||
if (data->error_handle.error_type == WEBSOCKET_ERROR_TYPE_TCP_TRANSPORT) {
|
||||
log_error_if_nonzero("reported from esp-tls", data->error_handle.esp_tls_last_esp_err);
|
||||
log_error_if_nonzero("reported from tls stack", data->error_handle.esp_tls_stack_err);
|
||||
log_error_if_nonzero("captured as transport's socket errno", data->error_handle.esp_transport_sock_errno);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void websocket_app_start(void)
|
||||
{
|
||||
esp_websocket_client_config_t websocket_cfg = {};
|
||||
|
||||
websocket_cfg.uri = CONFIG_WEBSOCKET_URI;
|
||||
|
||||
ESP_LOGI(TAG, "Connecting to %s...", websocket_cfg.uri);
|
||||
|
||||
esp_websocket_client_handle_t client = esp_websocket_client_init(&websocket_cfg);
|
||||
esp_websocket_register_events(client, WEBSOCKET_EVENT_ANY, websocket_event_handler, (void *)client);
|
||||
|
||||
esp_websocket_client_start(client);
|
||||
char data[32];
|
||||
int i = 0;
|
||||
while (i < 1) {
|
||||
if (esp_websocket_client_is_connected(client)) {
|
||||
int len = sprintf(data, "hello %04d", i++);
|
||||
ESP_LOGI(TAG, "Sending %s", data);
|
||||
esp_websocket_client_send_text(client, data, len, portMAX_DELAY);
|
||||
}
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
|
||||
esp_websocket_client_destroy(client);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
|
||||
ESP_LOGI(TAG, "[APP] Startup..");
|
||||
ESP_LOGI(TAG, "[APP] Free memory: %" PRIu32 " bytes", esp_get_free_heap_size());
|
||||
ESP_LOGI(TAG, "[APP] IDF version: %s", esp_get_idf_version());
|
||||
esp_log_level_set("*", ESP_LOG_INFO);
|
||||
esp_log_level_set("websocket_client", ESP_LOG_DEBUG);
|
||||
esp_log_level_set("transport_ws", ESP_LOG_DEBUG);
|
||||
esp_log_level_set("trans_tcp", ESP_LOG_DEBUG);
|
||||
|
||||
ESP_ERROR_CHECK(nvs_flash_init());
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
|
||||
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
|
||||
* Read "Establishing Wi-Fi or Ethernet Connection" section in
|
||||
* examples/protocols/README.md for more information about this function.
|
||||
*/
|
||||
ESP_ERROR_CHECK(example_connect());
|
||||
|
||||
websocket_app_start();
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
CONFIG_GCOV_ENABLED=y
|
||||
CONFIG_IDF_TARGET="linux"
|
||||
CONFIG_IDF_TARGET_LINUX=y
|
||||
CONFIG_ESP_EVENT_POST_FROM_ISR=n
|
||||
CONFIG_ESP_EVENT_POST_FROM_IRAM_ISR=n
|
||||
CONFIG_WEBSOCKET_URI="ws://echo.websocket.events"
|
||||
CONFIG_WEBSOCKET_URI_FROM_STRING=y
|
||||
CONFIG_WEBSOCKET_URI_FROM_STDIN=n
|
@ -0,0 +1,8 @@
|
||||
CONFIG_IDF_TARGET="linux"
|
||||
CONFIG_IDF_TARGET_LINUX=y
|
||||
CONFIG_ESP_EVENT_POST_FROM_ISR=n
|
||||
CONFIG_ESP_EVENT_POST_FROM_IRAM_ISR=n
|
||||
CONFIG_WEBSOCKET_URI="ws://echo.websocket.events"
|
||||
CONFIG_WEBSOCKET_URI_FROM_STRING=y
|
||||
CONFIG_WEBSOCKET_URI_FROM_STDIN=n
|
||||
CONFIG_EXAMPLE_CONNECT_WIFI=n
|
@ -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)
|
@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "websocket_example.c"
|
||||
INCLUDE_DIRS ".")
|
@ -20,4 +20,11 @@ menu "Example Configuration"
|
||||
help
|
||||
URL of websocket endpoint this example connects to and sends echo
|
||||
|
||||
if CONFIG_IDF_TARGET = "linux"
|
||||
config GCOV_ENABLED
|
||||
bool "Coverage analyzer"
|
||||
default n
|
||||
help
|
||||
Enables coverage analyzing for host tests.
|
||||
endif
|
||||
endmenu
|
@ -0,0 +1,5 @@
|
||||
dependencies:
|
||||
## Required IDF version
|
||||
idf: ">=5.0"
|
||||
espressif/esp_websocket_client:
|
||||
version: "^1.0.0"
|
@ -170,7 +170,7 @@ static void websocket_app_start(void)
|
||||
void app_main(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "[APP] Startup..");
|
||||
ESP_LOGI(TAG, "[APP] Free memory: %d bytes", esp_get_free_heap_size());
|
||||
ESP_LOGI(TAG, "[APP] Free memory: %" PRIu32 " bytes", esp_get_free_heap_size());
|
||||
ESP_LOGI(TAG, "[APP] IDF version: %s", esp_get_idf_version());
|
||||
esp_log_level_set("*", ESP_LOG_INFO);
|
||||
esp_log_level_set("websocket_client", ESP_LOG_DEBUG);
|
@ -1,3 +1,5 @@
|
||||
CONFIG_IDF_TARGET="esp32"
|
||||
CONFIG_IDF_TARGET_LINUX=n
|
||||
CONFIG_WEBSOCKET_URI_FROM_STDIN=y
|
||||
CONFIG_WEBSOCKET_URI_FROM_STRING=n
|
||||
CONFIG_EXAMPLE_CONNECT_ETHERNET=y
|
@ -1,4 +1,4 @@
|
||||
version: "1.0.0"
|
||||
version: "1.1.0"
|
||||
description: esp websocket client
|
||||
url: https://github.com/espressif/esp-protocols/tree/master/components/esp_websocket_client
|
||||
dependencies:
|
||||
|
@ -254,6 +254,9 @@ int esp_websocket_client_send_text(esp_websocket_client_handle_t client, const c
|
||||
* @param[in] len The length
|
||||
* @param[in] timeout Write data timeout in RTOS ticks
|
||||
*
|
||||
* Notes:
|
||||
* - In order to send a zero payload, data and len should be set to NULL/0
|
||||
*
|
||||
* @return
|
||||
* - Number of data was sent
|
||||
* - (-1) if any errors
|
||||
|
@ -1,2 +1,8 @@
|
||||
idf_component_register(SRC_DIRS "."
|
||||
PRIV_REQUIRES cmock test_utils esp_websocket_client)
|
||||
# This is the project CMakeLists.txt file for the test subproject
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
set(EXTRA_COMPONENT_DIRS ../../esp_websocket_client
|
||||
"$ENV{IDF_PATH}/tools/unit-test-app/components")
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(websocket_unit_test)
|
||||
|
4
components/esp_websocket_client/test/main/CMakeLists.txt
Normal file
4
components/esp_websocket_client/test/main/CMakeLists.txt
Normal file
@ -0,0 +1,4 @@
|
||||
idf_component_register(SRCS "test_websocket_client.c"
|
||||
REQUIRES test_utils
|
||||
INCLUDE_DIRS "."
|
||||
PRIV_REQUIRES unity esp_websocket_client esp_event)
|
@ -13,19 +13,36 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <esp_websocket_client.h>
|
||||
|
||||
#include "esp_event.h"
|
||||
#include "unity.h"
|
||||
#include "test_utils.h"
|
||||
|
||||
#include "unity_fixture.h"
|
||||
#include "memory_checks.h"
|
||||
|
||||
static void test_leak_setup(const char *file, long line)
|
||||
TEST_GROUP(websocket);
|
||||
|
||||
TEST_SETUP(websocket)
|
||||
{
|
||||
printf("%s:%ld\n", file, line);
|
||||
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 1, 0)
|
||||
/* IDF v5.0 runs some lazy inits within printf()
|
||||
* This test sets the leak threshold to 0, so we need to call printf()
|
||||
* before recording the heap size in test_utils_record_free_mem()
|
||||
*/
|
||||
printf("TEST_SETUP: websocket\n");
|
||||
#endif
|
||||
test_utils_record_free_mem();
|
||||
TEST_ESP_OK(test_utils_set_leak_level(0, ESP_LEAK_TYPE_CRITICAL, ESP_COMP_LEAK_GENERAL));
|
||||
}
|
||||
|
||||
TEST_CASE("websocket init and deinit", "[websocket][leaks=0]")
|
||||
TEST_TEAR_DOWN(websocket)
|
||||
{
|
||||
test_utils_finish_and_evaluate_leaks(0, 0);
|
||||
}
|
||||
|
||||
|
||||
TEST(websocket, websocket_init_deinit)
|
||||
{
|
||||
test_leak_setup(__FILE__, __LINE__);
|
||||
const esp_websocket_client_config_t websocket_cfg = {
|
||||
// no connection takes place, but the uri has to be valid for init() to succeed
|
||||
.uri = "ws://echo.websocket.org",
|
||||
@ -35,9 +52,8 @@ TEST_CASE("websocket init and deinit", "[websocket][leaks=0]")
|
||||
esp_websocket_client_destroy(client);
|
||||
}
|
||||
|
||||
TEST_CASE("websocket init with invalid url", "[websocket][leaks=0]")
|
||||
TEST(websocket, websocket_init_invalid_url)
|
||||
{
|
||||
test_leak_setup(__FILE__, __LINE__);
|
||||
const esp_websocket_client_config_t websocket_cfg = {
|
||||
.uri = "INVALID",
|
||||
};
|
||||
@ -45,12 +61,23 @@ TEST_CASE("websocket init with invalid url", "[websocket][leaks=0]")
|
||||
TEST_ASSERT_NULL(client);
|
||||
}
|
||||
|
||||
TEST_CASE("websocket set url with invalid url", "[websocket][leaks=0]")
|
||||
TEST(websocket, websocket_set_invalid_url)
|
||||
{
|
||||
test_leak_setup(__FILE__, __LINE__);
|
||||
const esp_websocket_client_config_t websocket_cfg = {};
|
||||
esp_websocket_client_handle_t client = esp_websocket_client_init(&websocket_cfg);
|
||||
TEST_ASSERT_NOT_EQUAL(NULL, client);
|
||||
TEST_ASSERT_NOT_EQUAL(ESP_OK, esp_websocket_client_set_uri(client, "INVALID"));
|
||||
esp_websocket_client_destroy(client);
|
||||
}
|
||||
|
||||
TEST_GROUP_RUNNER(websocket)
|
||||
{
|
||||
RUN_TEST_CASE(websocket, websocket_init_deinit)
|
||||
RUN_TEST_CASE(websocket, websocket_init_invalid_url)
|
||||
RUN_TEST_CASE(websocket, websocket_set_invalid_url)
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
UNITY_MAIN(websocket);
|
||||
}
|
8
components/esp_websocket_client/test/pytest_websocket.py
Normal file
8
components/esp_websocket_client/test/pytest_websocket.py
Normal file
@ -0,0 +1,8 @@
|
||||
# SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from pytest_embedded import Dut
|
||||
|
||||
|
||||
def test_websocket(dut: Dut) -> None:
|
||||
dut.expect_unity_test_output()
|
3
components/esp_websocket_client/test/sdkconfig.ci
Normal file
3
components/esp_websocket_client/test/sdkconfig.ci
Normal file
@ -0,0 +1,3 @@
|
||||
CONFIG_IDF_TARGET="esp32"
|
||||
CONFIG_UNITY_ENABLE_FIXTURE=y
|
||||
CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=n
|
2
components/esp_websocket_client/test/sdkconfig.defaults
Normal file
2
components/esp_websocket_client/test/sdkconfig.defaults
Normal file
@ -0,0 +1,2 @@
|
||||
CONFIG_UNITY_ENABLE_FIXTURE=y
|
||||
CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=n
|
@ -3,6 +3,6 @@ commitizen:
|
||||
bump_message: 'bump(mdns): $current_version -> $new_version'
|
||||
pre_bump_hooks: python ../../ci/changelog.py mdns
|
||||
tag_format: mdns-v$version
|
||||
version: 1.1.0
|
||||
version: 1.2.0
|
||||
version_files:
|
||||
- idf_component.yml
|
||||
|
@ -1,5 +1,24 @@
|
||||
# Changelog
|
||||
|
||||
## [1.2.0](https://github.com/espressif/esp-protocols/commits/mdns-v1.2.0)
|
||||
|
||||
### Features
|
||||
|
||||
- add an API for setting address to a delegated host ([ddc3eb6](https://github.com/espressif/esp-protocols/commit/ddc3eb6))
|
||||
- Add support for lwip build under linux ([588465d](https://github.com/espressif/esp-protocols/commit/588465d))
|
||||
- Allow for adding a delegated host with no address ([c562461](https://github.com/espressif/esp-protocols/commit/c562461))
|
||||
- Add APIs for looking up self hosted services and getting the self hostname ([f0df12d](https://github.com/espressif/esp-protocols/commit/f0df12d))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Refactor freertos linux compat layers ([79a0e57](https://github.com/espressif/esp-protocols/commit/79a0e57))
|
||||
- Fix delegated service PTR response ([cab0e1d](https://github.com/espressif/esp-protocols/commit/cab0e1d))
|
||||
- Added unit tests to CI + minor fix to pass it ([c974c14](https://github.com/espressif/esp-protocols/commit/c974c14))
|
||||
|
||||
### Updated
|
||||
|
||||
- docs: update documentation links ([4de5298](https://github.com/espressif/esp-protocols/commit/4de5298))
|
||||
|
||||
## [1.1.0](https://github.com/espressif/esp-protocols/commits/mdns-v1.1.0)
|
||||
|
||||
### Features
|
||||
|
@ -6,7 +6,7 @@ endif()
|
||||
|
||||
idf_build_get_property(target IDF_TARGET)
|
||||
if(${target} STREQUAL "linux")
|
||||
set(dependencies esp_netif_linux esp_timer_linux esp_system)
|
||||
set(dependencies esp_netif_linux esp_timer esp_system)
|
||||
set(srcs "mdns.c" ${MDNS_NETWORKING})
|
||||
else()
|
||||
set(dependencies lwip console esp_netif)
|
||||
|
@ -27,6 +27,13 @@ menu "mDNS"
|
||||
higher than priorities of system tasks. Compile time warning/error
|
||||
would be emitted if the chosen task priority were too high.
|
||||
|
||||
config MDNS_ACTION_QUEUE_LEN
|
||||
int "Maximum actions pending to the server"
|
||||
range 8 64
|
||||
default 16
|
||||
help
|
||||
Allows setting the length of mDNS action queue.
|
||||
|
||||
config MDNS_TASK_STACK_SIZE
|
||||
int "mDNS task stack size"
|
||||
default 4096
|
||||
|
@ -11,4 +11,4 @@ Get started with example test [Example](https://github.com/espressif/esp-protoco
|
||||
## Documentation
|
||||
|
||||
* View the full [documentation(English)](https://docs.espressif.com/projects/esp-protocols/mdns/docs/latest/en/index.html)
|
||||
* View the full [documentation(Chinese)](https://docs.espressif.com/projects/esp-protocols/mdns/latest/zh_CN/index.html)
|
||||
* View the full [documentation(Chinese)](https://docs.espressif.com/projects/esp-protocols/mdns/docs/latest/zh_CN/index.html)
|
||||
|
5
components/mdns/examples/main/idf_component.yml
Normal file
5
components/mdns/examples/main/idf_component.yml
Normal file
@ -0,0 +1,5 @@
|
||||
dependencies:
|
||||
## Required IDF version
|
||||
idf: ">=5.0"
|
||||
espressif/mdns:
|
||||
version: "^1.0.0"
|
@ -163,6 +163,23 @@ static void lookup_mdns_delegated_service(const char *service_name, const char *
|
||||
}
|
||||
#endif // CONFIG_MDNS_PUBLISH_DELEGATE_HOST
|
||||
|
||||
static void lookup_mdns_selfhosted_service(const char *service_name, const char *proto)
|
||||
{
|
||||
ESP_LOGI(TAG, "Lookup selfhosted service: %s.%s.local", service_name, proto);
|
||||
mdns_result_t *results = NULL;
|
||||
esp_err_t err = mdns_lookup_selfhosted_service(NULL, service_name, proto, 20, &results);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Lookup Failed: %s", esp_err_to_name(err));
|
||||
return;
|
||||
}
|
||||
if (!results) {
|
||||
ESP_LOGW(TAG, "No results found!");
|
||||
return;
|
||||
}
|
||||
mdns_print_results(results);
|
||||
mdns_query_results_free(results);
|
||||
}
|
||||
|
||||
static bool check_and_print_result(mdns_search_once_t *search)
|
||||
{
|
||||
// Check if any result is available
|
||||
@ -260,6 +277,7 @@ static void check_button(void)
|
||||
#if CONFIG_MDNS_PUBLISH_DELEGATE_HOST
|
||||
lookup_mdns_delegated_service("_http", "_tcp");
|
||||
#endif // CONFIG_MDNS_PUBLISH_DELEGATE_HOST
|
||||
lookup_mdns_selfhosted_service("_http", "_tcp");
|
||||
}
|
||||
old_level = new_level;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
version: "1.1.0"
|
||||
version: "1.2.0"
|
||||
description: mDNS
|
||||
url: https://github.com/espressif/esp-protocols/tree/master/components/mdns
|
||||
dependencies:
|
||||
|
@ -128,6 +128,19 @@ void mdns_free(void);
|
||||
*/
|
||||
esp_err_t mdns_hostname_set(const char *hostname);
|
||||
|
||||
/**
|
||||
* @brief Get the hostname for mDNS server
|
||||
*
|
||||
* @param hostname pointer to the hostname, it should be allocated
|
||||
* and hold at least MDNS_NAME_BUF_LEN chars
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_ERR_INVALID_STATE when mdns is not initialized
|
||||
*/
|
||||
esp_err_t mdns_hostname_get(char *hostname);
|
||||
|
||||
/**
|
||||
* @brief Adds a hostname and address to be delegated
|
||||
* A/AAAA queries will be replied for the hostname and
|
||||
@ -145,6 +158,21 @@ esp_err_t mdns_hostname_set(const char *hostname);
|
||||
*/
|
||||
esp_err_t mdns_delegate_hostname_add(const char *hostname, const mdns_ip_addr_t *address_list);
|
||||
|
||||
/**
|
||||
* @brief Set the address to a delegated hostname
|
||||
*
|
||||
* @param hostname Hostname to set
|
||||
* @param address_list The IP address list of the host
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_INVALID_STATE mDNS is not running
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_ERR_NO_MEM memory error
|
||||
*
|
||||
*/
|
||||
esp_err_t mdns_delegate_hostname_set_address(const char *hostname, const mdns_ip_addr_t *address_list);
|
||||
|
||||
/**
|
||||
* @brief Remove a delegated hostname
|
||||
* All the services added to this host will also be removed.
|
||||
@ -703,6 +731,24 @@ esp_err_t mdns_query_txt(const char *instance_name, const char *service_type, co
|
||||
esp_err_t mdns_lookup_delegated_service(const char *instance, const char *service_type, const char *proto, size_t max_results,
|
||||
mdns_result_t **result);
|
||||
|
||||
/**
|
||||
* @brief Look up self hosted services.
|
||||
*
|
||||
* @param instance instance name (NULL for uncertain instance)
|
||||
* @param service_type service type (_http, _ftp, etc)
|
||||
* @param proto service protocol (_tcp, _udp)
|
||||
* @param max_results maximum results to be collected
|
||||
* @param result pointer to the result of the search
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_INVALID_STATE mDNS is not running
|
||||
* - ESP_ERR_NO_MEM memory error
|
||||
* - ESP_ERR_INVALID_ARG parameter error
|
||||
*/
|
||||
esp_err_t mdns_lookup_selfhosted_service(const char *instance, const char *service_type, const char *proto, size_t max_results,
|
||||
mdns_result_t **result);
|
||||
|
||||
/**
|
||||
* @brief Query mDNS for A record
|
||||
*
|
||||
|
@ -1725,13 +1725,16 @@ static bool _mdns_create_answer_from_service(mdns_tx_packet_t *packet, mdns_serv
|
||||
mdns_parsed_question_t *question, bool shared, bool send_flush)
|
||||
{
|
||||
mdns_host_item_t *host = mdns_get_host_item(service->hostname);
|
||||
bool is_delegated = (host != &_mdns_self_host);
|
||||
if (question->type == MDNS_TYPE_PTR || question->type == MDNS_TYPE_ANY) {
|
||||
// According to RFC6763-section12.1, for DNS-SD, SRV, TXT and all address records
|
||||
// should be included in additional records.
|
||||
if (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_PTR, service, NULL, false, false) ||
|
||||
!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_SRV, service, NULL, send_flush, false) ||
|
||||
!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_TXT, service, NULL, send_flush, false) ||
|
||||
!_mdns_alloc_answer(shared ? &packet->additional : &packet->answers, MDNS_TYPE_A, service, host, send_flush,
|
||||
!_mdns_alloc_answer(is_delegated ? &packet->additional : &packet->answers, MDNS_TYPE_SRV, service, NULL, send_flush, false) ||
|
||||
!_mdns_alloc_answer(is_delegated ? &packet->additional : &packet->answers, MDNS_TYPE_TXT, service, NULL, send_flush, false) ||
|
||||
!_mdns_alloc_answer((shared || is_delegated) ? &packet->additional : &packet->answers, MDNS_TYPE_A, service, host, send_flush,
|
||||
false) ||
|
||||
!_mdns_alloc_answer(shared ? &packet->additional : &packet->answers, MDNS_TYPE_AAAA, service, host,
|
||||
!_mdns_alloc_answer((shared || is_delegated) ? &packet->additional : &packet->answers, MDNS_TYPE_AAAA, service, host,
|
||||
send_flush, false)) {
|
||||
return false;
|
||||
}
|
||||
@ -2990,6 +2993,27 @@ static void free_address_list(mdns_ip_addr_t *address_list)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static bool _mdns_delegate_hostname_set_address(const char *hostname, mdns_ip_addr_t *address_list)
|
||||
{
|
||||
if (!_str_null_or_empty(_mdns_server->hostname) &&
|
||||
strcasecmp(hostname, _mdns_server->hostname) == 0) {
|
||||
return false;
|
||||
}
|
||||
mdns_host_item_t *host = _mdns_host_list;
|
||||
while (host != NULL) {
|
||||
if (strcasecmp(hostname, host->hostname) == 0) {
|
||||
// free previous address list
|
||||
free_address_list(host->address_list);
|
||||
// set current address list to the host
|
||||
host->address_list = address_list;
|
||||
return true;
|
||||
}
|
||||
host = host->next;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static mdns_ip_addr_t *copy_address_list(const mdns_ip_addr_t *address_list)
|
||||
{
|
||||
mdns_ip_addr_t *head = NULL;
|
||||
@ -4842,6 +4866,7 @@ static void _mdns_free_action(mdns_action_t *action)
|
||||
case ACTION_RX_HANDLE:
|
||||
_mdns_packet_free(action->data.rx_handle.packet);
|
||||
break;
|
||||
case ACTION_DELEGATE_HOSTNAME_SET_ADDR:
|
||||
case ACTION_DELEGATE_HOSTNAME_ADD:
|
||||
free((char *)action->data.delegate_hostname.hostname);
|
||||
free_address_list(action->data.delegate_hostname.address_list);
|
||||
@ -5062,6 +5087,13 @@ static void _mdns_execute_action(mdns_action_t *action)
|
||||
free_address_list(action->data.delegate_hostname.address_list);
|
||||
}
|
||||
break;
|
||||
case ACTION_DELEGATE_HOSTNAME_SET_ADDR:
|
||||
if (!_mdns_delegate_hostname_set_address(action->data.delegate_hostname.hostname,
|
||||
action->data.delegate_hostname.address_list)) {
|
||||
free_address_list(action->data.delegate_hostname.address_list);
|
||||
}
|
||||
free((char *)action->data.delegate_hostname.hostname);
|
||||
break;
|
||||
case ACTION_DELEGATE_HOSTNAME_REMOVE:
|
||||
_mdns_delegate_hostname_remove(action->data.delegate_hostname.hostname);
|
||||
free((char *)action->data.delegate_hostname.hostname);
|
||||
@ -5561,12 +5593,23 @@ esp_err_t mdns_hostname_set(const char *hostname)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t mdns_hostname_get(char *hostname)
|
||||
{
|
||||
if (!_mdns_server || !hostname) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
MDNS_SERVICE_LOCK();
|
||||
strncpy(hostname, _mdns_server->hostname, strnlen(_mdns_server->hostname, MDNS_NAME_BUF_LEN));
|
||||
MDNS_SERVICE_UNLOCK();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t mdns_delegate_hostname_add(const char *hostname, const mdns_ip_addr_t *address_list)
|
||||
{
|
||||
if (!_mdns_server) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
if (_str_null_or_empty(hostname) || strlen(hostname) > (MDNS_NAME_BUF_LEN - 1) || address_list == NULL) {
|
||||
if (_str_null_or_empty(hostname) || strlen(hostname) > (MDNS_NAME_BUF_LEN - 1)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
char *new_hostname = strndup(hostname, MDNS_NAME_BUF_LEN - 1);
|
||||
@ -5620,6 +5663,36 @@ esp_err_t mdns_delegate_hostname_remove(const char *hostname)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t mdns_delegate_hostname_set_address(const char *hostname, const mdns_ip_addr_t *address_list)
|
||||
{
|
||||
if (!_mdns_server) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
if (_str_null_or_empty(hostname) || strlen(hostname) > (MDNS_NAME_BUF_LEN - 1)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
char *new_hostname = strndup(hostname, MDNS_NAME_BUF_LEN - 1);
|
||||
if (!new_hostname) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
mdns_action_t *action = (mdns_action_t *)malloc(sizeof(mdns_action_t));
|
||||
if (!action) {
|
||||
HOOK_MALLOC_FAILED;
|
||||
free(new_hostname);
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
action->type = ACTION_DELEGATE_HOSTNAME_SET_ADDR;
|
||||
action->data.delegate_hostname.hostname = new_hostname;
|
||||
action->data.delegate_hostname.address_list = copy_address_list(address_list);
|
||||
if (xQueueSend(_mdns_server->action_queue, &action, (TickType_t)0) != pdPASS) {
|
||||
free(new_hostname);
|
||||
free(action);
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
bool mdns_hostname_exists(const char *hostname)
|
||||
{
|
||||
return _hostname_is_ours(hostname);
|
||||
@ -5777,7 +5850,7 @@ static mdns_txt_item_t *_copy_mdns_txt_items(mdns_txt_linked_item_t *items, uint
|
||||
return ret;
|
||||
|
||||
handle_error:
|
||||
for (size_t y = 0; y < ret_index + 1; y++) {
|
||||
for (size_t y = 0; y < ret_index + 1 && ret != NULL; y++) {
|
||||
mdns_txt_item_t *t = &ret[y];
|
||||
free((char *)t->key);
|
||||
free((char *)t->value);
|
||||
@ -5798,7 +5871,7 @@ static mdns_ip_addr_t *_copy_delegated_host_address_list(char *hostname)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static mdns_result_t *_mdns_lookup_delegated_service(const char *instance, const char *service, const char *proto, size_t max_results)
|
||||
static mdns_result_t *_mdns_lookup_service(const char *instance, const char *service, const char *proto, size_t max_results, bool selfhost)
|
||||
{
|
||||
if (_str_null_or_empty(service) || _str_null_or_empty(proto)) {
|
||||
return NULL;
|
||||
@ -5808,7 +5881,13 @@ static mdns_result_t *_mdns_lookup_delegated_service(const char *instance, const
|
||||
mdns_srv_item_t *s = _mdns_server->services;
|
||||
while (s) {
|
||||
mdns_service_t *srv = s->service;
|
||||
if (srv && srv->hostname && (_str_null_or_empty(_mdns_server->hostname) || strcmp(_mdns_server->hostname, srv->hostname) != 0)) {
|
||||
if (!srv || !srv->hostname) {
|
||||
s = s->next;
|
||||
continue;
|
||||
}
|
||||
bool is_service_selfhosted = !_str_null_or_empty(_mdns_server->hostname) && !strcasecmp(_mdns_server->hostname, srv->hostname);
|
||||
bool is_service_delegated = _str_null_or_empty(_mdns_server->hostname) || strcasecmp(_mdns_server->hostname, srv->hostname);
|
||||
if ((selfhost && is_service_selfhosted) || (!selfhost && is_service_delegated)) {
|
||||
if (!strcasecmp(srv->service, service) && !strcasecmp(srv->proto, proto) &&
|
||||
(_str_null_or_empty(instance) || _mdns_instance_name_match(srv->instance, instance))) {
|
||||
mdns_result_t *item = (mdns_result_t *)malloc(sizeof(mdns_result_t));
|
||||
@ -5819,7 +5898,7 @@ static mdns_result_t *_mdns_lookup_delegated_service(const char *instance, const
|
||||
item->next = results;
|
||||
results = item;
|
||||
item->esp_netif = NULL;
|
||||
item->ttl = UINT32_MAX;
|
||||
item->ttl = _str_null_or_empty(instance) ? MDNS_ANSWER_PTR_TTL : MDNS_ANSWER_SRV_TTL;
|
||||
item->ip_protocol = MDNS_IP_PROTOCOL_MAX;
|
||||
item->instance_name = strndup(srv->instance, MDNS_NAME_BUF_LEN - 1);
|
||||
if (!item->instance_name) {
|
||||
@ -5843,9 +5922,14 @@ static mdns_result_t *_mdns_lookup_delegated_service(const char *instance, const
|
||||
}
|
||||
item->port = srv->port;
|
||||
item->txt = _copy_mdns_txt_items(srv->txt, &(item->txt_value_len), &(item->txt_count));
|
||||
item->addr = _copy_delegated_host_address_list(item->hostname);
|
||||
if (!item->addr) {
|
||||
goto handle_error;
|
||||
// We should not append addresses for selfhost lookup result as we don't know which interface's address to append.
|
||||
if (selfhost) {
|
||||
item->addr = NULL;
|
||||
} else {
|
||||
item->addr = _copy_delegated_host_address_list(item->hostname);
|
||||
if (!item->addr) {
|
||||
goto handle_error;
|
||||
}
|
||||
}
|
||||
if (num_results < max_results) {
|
||||
num_results++;
|
||||
@ -6344,7 +6428,22 @@ esp_err_t mdns_lookup_delegated_service(const char *instance, const char *servic
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
MDNS_SERVICE_LOCK();
|
||||
*result = _mdns_lookup_delegated_service(instance, service, proto, max_results);
|
||||
*result = _mdns_lookup_service(instance, service, proto, max_results, false);
|
||||
MDNS_SERVICE_UNLOCK();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t mdns_lookup_selfhosted_service(const char *instance, const char *service, const char *proto, size_t max_results,
|
||||
mdns_result_t **result)
|
||||
{
|
||||
if (!_mdns_server) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
if (!result || _str_null_or_empty(service) || _str_null_or_empty(proto)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
MDNS_SERVICE_LOCK();
|
||||
*result = _mdns_lookup_service(instance, service, proto, max_results, true);
|
||||
MDNS_SERVICE_UNLOCK();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
@ -93,7 +93,7 @@
|
||||
#define MDNS_SERVICE_ADD_TIMEOUT_MS CONFIG_MDNS_SERVICE_ADD_TIMEOUT_MS
|
||||
|
||||
#define MDNS_PACKET_QUEUE_LEN 16 // Maximum packets that can be queued for parsing
|
||||
#define MDNS_ACTION_QUEUE_LEN 16 // Maximum actions pending to the server
|
||||
#define MDNS_ACTION_QUEUE_LEN CONFIG_MDNS_ACTION_QUEUE_LEN // Maximum actions pending to the server
|
||||
#define MDNS_TXT_MAX_LEN 1024 // Maximum string length of text data in TXT record
|
||||
#if defined(CONFIG_LWIP_IPV6) && defined(CONFIG_MDNS_RESPOND_REVERSE_QUERIES)
|
||||
#define MDNS_NAME_MAX_LEN (64+4) // Need to account for IPv6 reverse queries (64 char address + ".ip6" )
|
||||
@ -196,6 +196,7 @@ typedef enum {
|
||||
ACTION_TASK_STOP,
|
||||
ACTION_DELEGATE_HOSTNAME_ADD,
|
||||
ACTION_DELEGATE_HOSTNAME_REMOVE,
|
||||
ACTION_DELEGATE_HOSTNAME_SET_ADDR,
|
||||
ACTION_MAX
|
||||
} mdns_action_type_t;
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
set(EXTRA_COMPONENT_DIRS "../..")
|
||||
set(EXTRA_COMPONENT_DIRS "../.." "../../../../common_components/linux_compat")
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
set(COMPONENTS main esp_netif_linux)
|
||||
|
@ -1,174 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include <pthread.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
void *create_q(void);
|
||||
|
||||
void destroy_q(void *q);
|
||||
|
||||
bool send_q(void *q, uint8_t *data, size_t len);
|
||||
|
||||
bool recv_q(void *q, uint8_t *data, size_t len, uint32_t ms);
|
||||
|
||||
static uint64_t s_semaphore_data = 0;
|
||||
|
||||
struct queue_handle {
|
||||
size_t item_size;
|
||||
void *q;
|
||||
};
|
||||
|
||||
QueueHandle_t xQueueCreate( uint32_t uxQueueLength, uint32_t uxItemSize )
|
||||
{
|
||||
struct queue_handle *h = calloc(1, sizeof(struct queue_handle));
|
||||
h->item_size = uxItemSize;
|
||||
h->q = create_q();
|
||||
return (QueueHandle_t)h;
|
||||
}
|
||||
|
||||
uint32_t xQueueSend(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait)
|
||||
{
|
||||
struct queue_handle *h = xQueue;
|
||||
return send_q(h->q, (uint8_t *)pvItemToQueue, h->item_size) ? pdTRUE : pdFAIL;
|
||||
}
|
||||
|
||||
uint32_t xQueueReceive(QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksToWait)
|
||||
{
|
||||
struct queue_handle *h = xQueue;
|
||||
return recv_q(h->q, (uint8_t *)pvBuffer, h->item_size, xTicksToWait) ? pdTRUE : pdFAIL;
|
||||
}
|
||||
|
||||
BaseType_t xSemaphoreGive( QueueHandle_t xQueue)
|
||||
{
|
||||
return xQueueSend(xQueue, &s_semaphore_data, portMAX_DELAY);
|
||||
}
|
||||
|
||||
BaseType_t xSemaphoreTake( QueueHandle_t xQueue, TickType_t pvTask )
|
||||
{
|
||||
return xQueueReceive(xQueue, &s_semaphore_data, portMAX_DELAY);
|
||||
}
|
||||
|
||||
void vQueueDelete( QueueHandle_t xQueue )
|
||||
{
|
||||
struct queue_handle *h = xQueue;
|
||||
if (h->q) {
|
||||
destroy_q(h->q);
|
||||
}
|
||||
free(xQueue);
|
||||
}
|
||||
|
||||
QueueHandle_t xSemaphoreCreateBinary(void)
|
||||
{
|
||||
QueueHandle_t sempaphore = xQueueCreate(1, 1);
|
||||
return sempaphore;
|
||||
}
|
||||
|
||||
QueueHandle_t xSemaphoreCreateMutex(void)
|
||||
{
|
||||
QueueHandle_t sempaphore = xQueueCreate(1, 1);
|
||||
if (sempaphore) {
|
||||
xSemaphoreGive(sempaphore);
|
||||
}
|
||||
return sempaphore;
|
||||
}
|
||||
|
||||
void vTaskDelete(TaskHandle_t *task)
|
||||
{
|
||||
if (task == NULL) {
|
||||
pthread_exit(0);
|
||||
}
|
||||
void *thread_rval = NULL;
|
||||
pthread_join((pthread_t)task, &thread_rval);
|
||||
}
|
||||
|
||||
TickType_t xTaskGetTickCount( void )
|
||||
{
|
||||
struct timespec spec;
|
||||
clock_gettime(CLOCK_REALTIME, &spec);
|
||||
return spec.tv_nsec / 1000000 + spec.tv_sec * 1000;
|
||||
}
|
||||
|
||||
void vTaskDelay( const TickType_t xTicksToDelay )
|
||||
{
|
||||
usleep(xTicksToDelay * 1000);
|
||||
}
|
||||
|
||||
void *pthread_task(void *params)
|
||||
{
|
||||
struct {
|
||||
void *const param;
|
||||
TaskFunction_t task;
|
||||
bool started;
|
||||
} *pthread_params = params;
|
||||
|
||||
void *const param = pthread_params->param;
|
||||
TaskFunction_t task = pthread_params->task;
|
||||
pthread_params->started = true;
|
||||
|
||||
task(param);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BaseType_t xTaskCreatePinnedToCore( TaskFunction_t pvTaskCode,
|
||||
const char *const pcName,
|
||||
const uint32_t usStackDepth,
|
||||
void *const pvParameters,
|
||||
UBaseType_t uxPriority,
|
||||
TaskHandle_t *const pvCreatedTask,
|
||||
const BaseType_t xCoreID)
|
||||
{
|
||||
xTaskCreate(pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pvCreatedTask);
|
||||
return pdTRUE;
|
||||
}
|
||||
|
||||
|
||||
void xTaskCreate(TaskFunction_t pvTaskCode, const char *const pcName, const uint32_t usStackDepth, void *const pvParameters, UBaseType_t uxPriority, TaskHandle_t *const pvCreatedTask)
|
||||
{
|
||||
pthread_t new_thread = (pthread_t)NULL;
|
||||
pthread_attr_t attr;
|
||||
struct {
|
||||
void *const param;
|
||||
TaskFunction_t task;
|
||||
bool started;
|
||||
} pthread_params = { .param = pvParameters, .task = pvTaskCode};
|
||||
int res = pthread_attr_init(&attr);
|
||||
assert(res == 0);
|
||||
res = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
|
||||
assert(res == 0);
|
||||
res = pthread_create(&new_thread, &attr, pthread_task, &pthread_params);
|
||||
assert(res == 0);
|
||||
|
||||
if (pvCreatedTask) {
|
||||
*pvCreatedTask = (void *)new_thread;
|
||||
}
|
||||
|
||||
// just wait till the task started so we can unwind params from the stack
|
||||
while (pthread_params.started == false) {
|
||||
usleep(1000);
|
||||
}
|
||||
}
|
||||
|
||||
void xTaskNotifyGive(TaskHandle_t task)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
BaseType_t xTaskNotifyWait(uint32_t bits_entry_clear, uint32_t bits_exit_clear, uint32_t *value, TickType_t wait_time )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
TaskHandle_t xTaskGetCurrentTaskHandle(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "queue_unique_ptr.hpp"
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <cstring>
|
||||
|
||||
extern "C" void *create_q(void)
|
||||
{
|
||||
auto *q = new QueueMock<std::vector<uint8_t>>();
|
||||
return q;
|
||||
}
|
||||
|
||||
extern "C" void destroy_q(void *q)
|
||||
{
|
||||
auto *queue = static_cast<QueueMock<std::vector<uint8_t>> *>(q);
|
||||
delete (queue);
|
||||
}
|
||||
|
||||
extern "C" bool send_q(void *q, uint8_t *data, size_t len)
|
||||
{
|
||||
auto v = std::make_unique<std::vector<uint8_t>>(len);
|
||||
v->assign(data, data + len);
|
||||
auto queue = static_cast<QueueMock<std::vector<uint8_t>> *>(q);
|
||||
queue->send(std::move(v));
|
||||
return true;
|
||||
}
|
||||
|
||||
extern "C" bool recv_q(void *q, uint8_t *data, size_t len, uint32_t ms)
|
||||
{
|
||||
auto queue = static_cast<QueueMock<std::vector<uint8_t>> *>(q);
|
||||
auto v = queue->receive(ms);
|
||||
if (v == nullptr) {
|
||||
return false;
|
||||
}
|
||||
memcpy(data, (void *)v->data(), len);
|
||||
return true;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user