Compare commits

..

97 Commits

Author SHA1 Message Date
c92ce075fd bump(mdns): 1.0.8 -> 1.0.9 2023-03-16 08:18:33 +01:00
f29719fa0b ci(common): force scoping commit messages with components
Add simple changelog generator and mdns tag formatter
2023-03-16 08:18:33 +01:00
2d1990614a Merge pull request #253 from david-cermak/bufix/precommit_check_only_pr
fix(ci): Run pre-commit checker only on PRs
2023-03-15 19:27:01 +01:00
2863e94a11 fix(ci): Run pre-commit checker only on PRs
Regression from a089e0d680 Merged as https://github.com/espressif/esp-protocols/pull/242
2023-03-15 19:11:27 +01:00
ba45e9a07e Merge pull request #242 from david-cermak/bugfix/modem_strip_idf_4.1
fix(esp_modem): run CI build job for all targets
2023-03-15 18:55:26 +01:00
13eca128fb fix(ci): trigger PR jobs based on labels 2023-03-15 15:38:06 +01:00
c492d87316 Merge pull request #247 from david-cermak/fix/add_missing_changelogs
fix(common): Reintroduce missing CHANGELOGs
2023-03-13 19:38:15 +01:00
200cbb3383 fix(common): Reintroduce missing CHANGELOGs
Closes https://github.com/espressif/esp-protocols/issues/235
2023-03-13 12:58:25 +01:00
a96f17d9a1 Merge pull request #236 from gabsuren/CI/conventional_commits
ci: added conventionl commit pre-commit hook
2023-03-10 18:56:26 +01:00
cbda15724c ci: regroup tests per components and purpose 2023-03-08 17:33:48 +01:00
d0814bf963 fix(esp_modem): Use default UART CLK source
Some targets don't support UART_SCLK_APB (e.g. esp32c2)
This change is applicable only for IDFv5.0 and later, as older version
didn't define UART_SCLK_DEFAULT.

Closes https://github.com/espressif/esp-protocols/issues/241
2023-03-08 11:51:31 +01:00
a089e0d680 fix(esp_modem): run CI build job for all targets
Also
* removed IDFv4.1 from tests
* added common build_apps.py utility for finding/building apps
2023-03-08 11:51:25 +01:00
ef4985cce6 Merge pull request #243 from tore-espressif/feature/esp_modem/dual_dte
esp_modem: Dual DTE support
2023-03-08 11:01:16 +01:00
01c26c82fa esp_modem: Dual DTE support
Modems can expose 2 terminals, which can be used simultaneously.
One for AT commands, the other one for data.
2023-03-07 13:35:34 +01:00
08f1f0175d Merge pull request #228 from gabsuren/CI/update_websocket_version
websocket: Updated version to 1.0.0
2023-03-06 12:36:30 +04:00
a6817e0c7f ci: Add conventionl commit pre-commit hook 2023-03-03 12:38:27 +04:00
a2050ac041 Merge pull request #233 from tom-borcin/feature/add_issue_templates
Add issue templates
2023-03-02 17:19:59 +01:00
6015c19c31 Merge pull request #239 from kumekay/feature/add_url_license
Add homepage URL and License to all components (IDFGH-9521)
2023-03-02 17:17:00 +01:00
5df8fdb713 Add input for component version 2023-03-02 15:38:10 +01:00
ef3f0ee688 Add homepage URL and License to all components 2023-03-02 12:35:17 +01:00
996fef7fcf esp_websocket_client: Updated version to 1.0.0
Updated tests to run agains release-v5.0
2023-02-28 19:00:46 +04:00
9f87a8ca77 Add issue templates 2023-02-24 15:53:31 +01:00
3bf0511938 Merge pull request #216 from gabsuren/feature/websocket-errorhandling
esp_websocket_client: Improve error handling (IDFGH-8444)
2023-02-24 07:35:41 +01:00
319fce018e Merge pull request #231 from tore-espressif/fix/esp_modem/on_data_cb
esp_modem: Return true from on_data callback in data mode
2023-02-24 07:34:20 +01:00
44bae24c78 esp_modem: Return true from on_data callback in data mode
The callback should return false only if there is a problem with the received data.
The updated UART Terminal implementation cannot longer clear is callback.
It is DTE's responsibility to clear the callback.
2023-02-23 20:32:13 +01:00
d047ff569c esp_websocket_client:
* Error handling improved to show status code from server
* Added new API `esp_websocket_client_set_headers`
* Dispatches 'WEBSOCKET_EVENT_BEFORE_CONNECT' event before tcp connection
2023-02-22 11:41:33 +04:00
02be2b76f8 Merge pull request #227 from gabsuren/docs/mdns_document_link_fix
docs: fix of mdns link translation
2023-02-20 16:19:30 +04:00
1c850ddacf docs: fix of mdns link translation 2023-02-20 16:11:24 +04:00
9ae88aab48 Merge pull request #223 from AndriiFilippov/master
Unite all tags under common structure (IDFGH-9399)
2023-02-17 15:08:18 +01:00
c6db3ea84c unite all tags under common structure
py test: update tags under common structure
2023-02-17 14:27:34 +01:00
b23eedac3a Merge pull request #189 from euripedesrocha/master
Adds esp_mqtt_cxx component
2023-02-16 06:17:08 -03:00
1407dfc2e7 Adds esp_mqtt_cxx component
- Component moved from esp-idf
- Files moved to adjust to esp-protocol structure
2023-02-16 09:59:46 +01:00
34c6f52f70 build system: re-add -Wno-format as private flag for some example components 2023-02-15 10:26:19 +01:00
c674b8855d [MQTT] - Updates esp_mqtt configuration struct
- Layered config struct
- Fix examples.
2023-02-15 10:26:19 +01:00
256389613f docs: changes docs supported targets tables 2023-02-15 10:26:19 +01:00
2865255ec0 examples, components: remove C/C++ standard overrides
...where they are not necessary after switching to C17 and C++20.
2023-02-15 10:26:19 +01:00
7b2470ddd6 ci: partially enable example build for esp32c2 2023-02-15 10:26:19 +01:00
dda2722563 tools: Increase the minimal supported CMake version to 3.16
This updates the minimal supported version of CMake to 3.16, which in turn enables us to use more CMake features and have a cleaner build system.
This is the version that provides most new features and also the one we use in our latest docker image for CI.
2023-02-15 10:26:19 +01:00
36db37ea2b examples/cxx: add missing header 2023-02-15 10:26:19 +01:00
4f013e3522 Build & config: Remove leftover files from the unsupported "make" build system 2023-02-15 10:26:19 +01:00
231392d0c6 experimental/mqtt_cxx: Adds a C++ Mqtt client wrapper
- Base class with separated event handlers for each Mqtt client event.
- Topic matcher added to support data events.
- Filter class to allow only mqtt valid topic filters.
- Initial code for unit test on the host.
2023-02-15 10:26:19 +01:00
9fb01ca534 Merge pull request #219 from david-cermak/feat/mdns_reverse_query_ip6
feat(mdns): Add support for IPv6 reverse query
2023-02-15 08:07:17 +01:00
d464ed7d30 feat(mdns): Add reverse lookup to the example and test 2023-02-15 07:48:04 +01:00
b94a211e4b Merge pull request #222 from boborjan2/mdns_task_notification
components/mdns: use semaphore instead of task notification bits (IDFGH-9380) (IDFGH-9388)
2023-02-15 07:12:26 +01:00
73f2800b59 components/mdns: use semaphore instead of task notification bits (IDFGH-9380)
Component should not alter the task notification bits of the calling task.
2023-02-14 11:43:02 +01:00
e00e056162 Merge pull request #215 from ESP-YJM/feat/add_auth_for_websocket
websocket: Support HTTP basic authorization
2023-02-10 17:29:31 +04:00
1b134486db websocket: Support HTTP basic authorization 2023-02-09 15:09:40 +08:00
7ba1085e9f Merge pull request #32 from 0xFEEDC0DE64/websocketclient-errormsg
Add websocket client error message string (IDFGH-7591)
2023-02-08 16:11:38 +01:00
3bdb2067e0 Merge pull request #218 from 0xFEEDC0DE64/add_task_name
Add task_name config option (for websocket client) (IDFGH-9346)
2023-02-08 16:10:05 +01:00
1d6888445d Add task_name config option 2023-02-08 15:52:03 +01:00
d68624ec4f Add websocket error messages 2023-02-08 15:35:01 +01:00
d4825f5c53 feat(mdns): Add support for IPv6 reverse query
Implements reverse querries together with
b87bef52e5 (IPv4)

Closes https://github.com/espressif/esp-protocols/issues/101
2023-02-07 20:16:26 +01:00
de1480a072 Merge pull request #217 from david-cermak/mdns/bump_component_version
mdns: bump the component version to 1.0.8
2023-02-06 20:13:17 +01:00
b9b4a75000 mdns: bump the component version to 1.0.8 2023-02-06 15:43:01 +01:00
cc259aa035 Merge pull request #203 from david-cermak/feat/mdns_reverse_query
feat(mdns): Add support for IPv4 reverse query
2023-02-03 15:21:38 +01:00
91134f10ff mdns: Make reverse query conditional per Kconfig
and auto-register reverse logical names
2023-02-02 10:32:01 +01:00
fb8a2f0198 fix(mdns): Host test with IDFv5.1 2023-02-02 10:31:01 +01:00
b87bef52e5 feat(mdns): Add support for IPv4 reverse query
Partially addresses https://github.com/espressif/esp-protocols/issues/101
2023-02-02 10:31:00 +01:00
28813148b2 Merge pull request #211 from gabsuren/websocket/add_new_api_esp_destroy_selected
websocket: Added new API `esp_websocket_client_destroy_on_exit` (IDF-6458)
2023-02-01 18:00:30 +04:00
ae38f27997 Merge pull request #206 from david-cermak/bugfix/mdns_unit_tests
fix(mdns): Make unit test executable with pytest
2023-02-01 12:28:52 +01:00
d0c9070715 fix(mdns): Remove strict mode as it's invalid
Strict mode was introduced to support "one-shot" queries (described in
RFC6762/sec5.1) that are sent by lwip or dig. It was incorrectly assumed
that responding to such queries violates the spec, as we have to repeat
queries in responces, which is forbidden in RFC6762/sec6. It is however
required to repeat query fields according to the Section 6.7. Legacy
Unicast Responses: "it MUST repeat the query ID and the question
given in the query message."
2023-01-31 16:06:52 +01:00
a8339e4618 fix(mdns): Allow setting instance name only after hostname set
Closes https://github.com/espressif/esp-protocols/issues/190
2023-01-31 16:06:52 +01:00
12cfcb5aed fix(mdns): Make unit test executable with pytest 2023-01-31 16:06:52 +01:00
2cfffb056e Merge pull request #214 from david-cermak/bugfix/modem_cxx_broken_components
fix(esp_modem): Fix cmux client compilation issue
2023-01-31 14:42:46 +01:00
0247926219 fix(mdns): AFL port layer per IDF-latest changes 2023-01-31 11:15:06 +01:00
05fff94b91 update(esp_modem): Bump component version to 0.1.26
Closes https://github.com/espressif/esp-protocols/issues/213
Closes https://github.com/espressif/esp-protocols/issues/212
2023-01-31 11:02:52 +01:00
8958d5e37c fix(esp-modem): Example to use variable mqtt topic/data
This example is used in the CI with public broker and
users playing with the example can influence stability
of tests if we share the same topic id
2023-01-31 11:02:52 +01:00
f71192b876 fix(esp_modem): Fix cmux client compilation issue
Removed dependency on esp_event_cxx
2023-01-30 15:30:48 +01:00
f9b47900f2 websocket: Added new API esp_websocket_client_destroy_on_exit 2023-01-24 22:29:09 +04:00
0e215b118f Added the missing definition for the esp_modem_set_baud function (IDFGH-9181) (#209)
fix(esp_modem): Added the missing definition for the esp_modem_set_baud function
2023-01-19 13:57:06 +01:00
dc8b916561 Merge pull request #205 from gabsuren/docs/fix_documentation
docs: Disable code coverage report publishing to Github Pages
2023-01-13 17:54:04 +04:00
a01096f621 docs: Disable code coverage report publishing to Github Pages 2023-01-13 17:30:33 +04:00
3de4727385 Merge pull request #202 from gabsuren/CI/minor_fix_ci
CI: minor fix of host test *yml file
2023-01-12 20:02:12 +01:00
59053b8c98 CI: minor fix of host test *yml file 2023-01-09 22:09:53 +04:00
2956477353 Merge pull request #196 from gabsuren/CI/gcovr_analyser
CI: Added coverage analyzer for esp_modem host tests
2023-01-09 14:09:11 +01:00
1d9b6f7e90 Merge pull request #199 from franz-ms-muc/patch-1
Update esp_modem_command_library.cpp (IDFGH-9018)
2023-01-04 12:30:45 +01:00
6b684ceb0f CI: Added coverage analyzer for esp_modem host tests 2022-12-30 13:11:59 +04:00
5304a6ec0e Update esp_modem_command_library.cpp
AT+IFC=2,2 instead AT+IFC=2, 2
2022-12-22 11:55:37 +01:00
c7f20ee98e Merge pull request #191 from gabsuren/CI/refactor_yml_files
CI: Minor refactoring of *yml files for the target tests
2022-12-16 11:32:14 +04:00
7d47ec3b6b Merge pull request #192 from XDanielPaul/master
Added badges with version of components to the respective README files (IDFGH-8940)
2022-12-14 12:47:48 +01:00
e4c8a5932c Added badges with version of components to the respective README files 2022-12-12 18:13:04 +01:00
b56b1c577b CI: Minor refactoring of *yml files for target tests 2022-12-12 12:31:44 +04:00
4e212c31fe Merge pull request #182 from david-cermak/feat/modem_target_test
feat(esp_modem): Added target test
2022-12-09 15:26:26 +01:00
9a7bd90ad9 fix(esp_modem): Exit data mode only after state change
Previously, we set the notification also for  event
causing permature PPP mode exit
2022-12-01 18:35:06 +01:00
4314c78ca0 feat(esp_modem): Added target test 2022-12-01 18:35:01 +01:00
457f8335bb Merge pull request #169 from david-cermak/feat/modem_dce_on_read
fix(esp-modem): Extend CMUX mode to support manual transitions
2022-11-23 20:24:26 +01:00
42565ff5d7 Merge pull request #177 from gabsuren/CI/asio_fix
CI: Fix ASIO example test
2022-11-23 20:23:20 +01:00
6e2bb518fd CI: Fix ASIO example test 2022-11-23 19:07:26 +04:00
2180ab17d8 fix(esp-modem): Support AT with callback in C-API
Closes https://github.com/espressif/esp-protocols/issues/143
2022-11-21 14:58:15 +01:00
ac5d43882b feat(esp-modem): Add support for manual CMUX operations
Closes https://github.com/espressif/esp-protocols/issues/168
2022-11-21 14:58:15 +01:00
3f0262dfe5 Merge pull request #176 from gabsuren/CI/flake_use_github
CI: Updated flake8 to use github repo
2022-11-21 14:41:43 +01:00
74787c9aa8 CI: Updated flake8 to use github repo 2022-11-21 16:31:20 +04:00
045009bb82 Merge pull request #173 from mahavirj/bugfix/some_issue_with_coverity_scan
mdns: fix some coverity reported issues
2022-11-07 15:11:08 +01:00
79c11e9ecd Merge pull request #171 from gabsuren/feature/make_public_websocket_client_send_with_opcode
websocket: make `esp_websocket_client_send_with_opcode` a public API (IDFGH-6937)
2022-11-07 14:28:36 +01:00
c73c797595 mdns: fix some coverity reported issues
- Array compared against 0 NO_EFFECT
- dereference null pointer, FORWARD_NULL check
2022-11-07 18:38:06 +05:30
1547aa8c03 Merge pull request #166 from espressif-abhikroy/esp_modem/power_saving_mode
esp_modem/examples: Added example Power Saving Mode(PSM) in LTE modem.
2022-11-07 08:36:30 +01:00
1ca139109a esp_modem/examples: Add an example to synchronise PSM sleep in Sim70XX modem and esp32.
This example enables Power saving mode in Sim70XX modem and tries to synchronise the sleep cycle of the modem with esp32.
When the modem wakes up from PSM sleep it wakes up the esp32. While the modem is awake esp32 is set to light sleep.

Closes: https://github.com/espressif/esp-protocols/issues/54
2022-11-06 18:52:50 +05:30
163 changed files with 5672 additions and 1280 deletions

51
.github/ISSUE_TEMPLATE/bug-report.yml vendored Normal file
View File

@ -0,0 +1,51 @@
name: Installation or build bug report
description: Report installation or build bugs
labels: ['Type: Bug']
body:
- type: checkboxes
id: checklist
attributes:
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.
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
- label: I have searched the issue tracker for a similar issue and not found a similar issue.
required: true
- type: dropdown
id: component
attributes:
label: What component are you using? If you choose Other, provide details in More Information.
multiple: false
options:
- ASIO port
- esp_modem
- esp_websocket_client
- mDNS
- Other
validations:
required: true
- type: input
id: component_id
attributes:
label: component version
description: Which component version does this issue occur on? (see your `idf_component.yml`)
placeholder: ex. 1.0.0
- type: input
id: idf_version
attributes:
label: IDF version.
description: On which IDF version does this issue occur on? Run `git describe --tags` to find it.
placeholder: ex. v3.2-dev-1148-g96cd3b75c
validations:
required: true
- type: textarea
id: more-info
attributes:
label: More Information.
description: Do you have any other information from investigating this?
placeholder: ex. I tried on my friend's Windows 10 PC and the command works there.
validations:
required: false

14
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@ -0,0 +1,14 @@
blank_issues_enabled: false
contact_links:
- name: esp-protocols documentation
url: https://espressif.github.io/esp-protocols/
about: Documenation for esp-protocols components.
- name: ESP-IDF Programming Guide
url: https://docs.espressif.com/projects/esp-idf/en/latest/
about: Documentation for configuring and using ESP-IDF.
- name: Espressif documentation page
url: https://www.espressif.com/en/support/download/documents
about: Hardware documentation (datasheets, Technical Reference Manual, etc).
- name: Forum
url: https://esp32.com
about: For questions about using ESP-IDF and/or ESP32 series chips. Please submit all questions starting "How do I..." here.

View File

@ -0,0 +1,33 @@
name: Feature request
description: Suggest an idea or new component for this project.
labels: ['Type: Feature Request']
body:
- type: markdown
attributes:
value: |
* We welcome any ideas or feature requests! Its helpful if you can explain exactly why the feature would be useful.
* There are usually some outstanding feature requests in the [existing issues list](https://github.com/espressif/esp-protocols/labels/Type%3A%20Feature%20Request), feel free to add comments to them.
- type: textarea
id: problem-related
attributes:
label: Is your feature request related to a problem?
description: Please provide a clear and concise description of what the problem is.
placeholder: ex. I'm always frustrated when ...
- type: textarea
id: solution
attributes:
label: Describe the solution you'd like.
description: Please provide a clear and concise description of what you want to happen.
placeholder: ex. When building my application ...
- type: textarea
id: alternatives
attributes:
label: Describe alternatives you've considered.
description: Please provide a clear and concise description of any alternative solutions or features you've considered.
placeholder: ex. Choosing other approach wouldn't work, because ...
- type: textarea
id: context
attributes:
label: Additional context.
description: Please add any other context or screenshots about the feature request here.
placeholder: ex. This would work only when ...

23
.github/ISSUE_TEMPLATE/other-issue.yml vendored Normal file
View File

@ -0,0 +1,23 @@
name: General issue report
description: File an issue report
body:
- type: checkboxes
id: checklist
attributes:
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.
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
- label: I have searched the issue tracker for a similar issue and not found a similar issue.
required: true
- type: textarea
id: issue
attributes:
label: General issue report
description: Your issue report goes here.
placeholder: ex. How do I...
validations:
required: true

View File

@ -0,0 +1,98 @@
name: "asio: build/target-tests"
on:
push:
branches:
- master
pull_request:
types: [opened, synchronize, reopened, labeled]
jobs:
build_asio:
if: contains(github.event.pull_request.labels.*.name, 'asio')
name: Build
strategy:
matrix:
idf_ver: ["latest", "release-v5.0"]
idf_target: ["esp32", "esp32s2"]
example: ["asio_chat", "async_request", "socks4", "ssl_client_server", "tcp_echo_server", "udp_echo_server"]
runs-on: ubuntu-20.04
container: espressif/idf:${{ matrix.idf_ver }}
env:
TEST_DIR: components/asio/examples
steps:
- name: Checkout esp-protocols
uses: actions/checkout@v3
with:
submodules: recursive
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
working-directory: ${{ env.TEST_DIR }}/${{ matrix.example }}
env:
IDF_TARGET: ${{ matrix.idf_target }}
shell: bash
run: |
. ${IDF_PATH}/export.sh
test -f sdkconfig.ci && cat sdkconfig.ci >> sdkconfig.defaults || echo "No sdkconfig.ci"
idf.py set-target ${{ matrix.idf_target }}
idf.py build
- name: Merge binaries with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }} for ${{ matrix.example }}
working-directory: ${{ env.TEST_DIR }}/${{ matrix.example }}/build
env:
IDF_TARGET: ${{ matrix.idf_target }}
shell: bash
run: |
. ${IDF_PATH}/export.sh
esptool.py --chip ${{ matrix.idf_target }} merge_bin --fill-flash-size 4MB -o flash_image.bin @flash_args
- uses: actions/upload-artifact@v3
with:
name: examples_app_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.example }}
path: |
${{ env.TEST_DIR }}/${{ matrix.example }}/build/bootloader/bootloader.bin
${{ env.TEST_DIR }}/${{ matrix.example }}/build//partition_table/partition-table.bin
${{ env.TEST_DIR }}/${{ matrix.example }}/build/*.bin
${{ env.TEST_DIR }}/${{ matrix.example }}/build/*.elf
${{ env.TEST_DIR }}/${{ matrix.example }}/build/flasher_args.json
${{ env.TEST_DIR }}/${{ matrix.example }}/build/config/sdkconfig.h
${{ env.TEST_DIR }}/${{ matrix.example }}/build/config/sdkconfig.json
if-no-files-found: error
target_tests_asio:
# Skip running on forks since it won't have access to secrets
if: ${{ contains(github.event.pull_request.labels.*.name, 'asio') && (github.repository == 'espressif/esp-protocols') }}
name: Target tests
strategy:
matrix:
idf_ver: ["latest", "release-v5.0"]
idf_target: ["esp32"]
example: ["asio_chat", "tcp_echo_server", "udp_echo_server", "ssl_client_server"]
needs: build_asio
runs-on:
- self-hosted
- ESP32-ETHERNET-KIT
env:
TEST_DIR: components/asio/examples
steps:
- name: Clear repository
run: sudo rm -fr $GITHUB_WORKSPACE && mkdir $GITHUB_WORKSPACE
- uses: actions/checkout@v3
- uses: actions/download-artifact@v3
with:
name: examples_app_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.example }}
path: ${{ env.TEST_DIR }}/${{ matrix.example }}/build
- name: Install Python packages
env:
PIP_EXTRA_INDEX_URL: "https://www.piwheels.org/simple"
run: |
sudo apt-get install -y dnsutils
- name: Download Example Test to target ${{ matrix.config }}
run: |
python -m esptool --chip ${{ matrix.idf_target }} write_flash 0x0 ${{ env.TEST_DIR }}/${{ matrix.example }}/build/flash_image.bin
- name: Run Example Test ${{ matrix.example }} on target
working-directory: ${{ env.TEST_DIR }}/${{ matrix.example }}
run: |
python -m pytest --log-cli-level DEBUG --junit-xml=./examples_results_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.config }}.xml --target=${{ matrix.idf_target }}
- uses: actions/upload-artifact@v3
if: always()
with:
name: examples_results_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.example }}
path: ${{ env.TEST_DIR }}/${{ matrix.example }}/*.xml

View File

@ -1,44 +0,0 @@
name: Host test
on: [push, pull_request]
jobs:
host_test:
name: Build and Test on Host
runs-on: ubuntu-20.04
container: espressif/idf:release-v4.3
env:
lwip: lwip-2.1.2
lwip_contrib: contrib-2.1.0
lwip_uri: http://download.savannah.nongnu.org/releases/lwip
steps:
- name: Checkout esp-protocols
uses: actions/checkout@master
with:
path: esp-protocols
- name: Build and Test
shell: bash
run: |
apt-get update && apt-get install -y gcc-8 g++-8
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-8 800 --slave /usr/bin/g++ g++ /usr/bin/g++-8
export LWIP_PATH=`pwd`/${{ env.lwip }}
export LWIP_CONTRIB_PATH=`pwd`/${{ env.lwip_contrib }}
wget --no-verbose ${lwip_uri}/${lwip}.zip
unzip -oq ${lwip}.zip
wget --no-verbose ${lwip_uri}/${lwip_contrib}.zip
unzip -oq ${lwip_contrib}.zip
. ${IDF_PATH}/export.sh
cd $GITHUB_WORKSPACE/esp-protocols/components/esp_modem/examples/linux_modem
idf.py build
cd $GITHUB_WORKSPACE/esp-protocols/components/esp_modem/test/host_test
idf.py build
./build/host_modem_test.elf -r junit -o junit.xml
- name: Publish Results
uses: EnricoMi/publish-unit-test-result-action@v1
if: always()
with:
files: esp-protocols/components/esp_modem/test/host_test/junit.xml

View File

@ -1,15 +1,49 @@
name: Build and Run Test apps
name: "mdns: build/target-tests"
on:
push:
paths:
- 'components/mdns/**'
pull_request:
paths:
- 'components/mdns/**'
push:
branches:
- master
pull_request:
types: [opened, synchronize, reopened, labeled]
jobs:
build_mdns:
if: contains(github.event.pull_request.labels.*.name, 'mdns')
name: Build
strategy:
matrix:
idf_ver: ["latest"]
idf_target: ["esp32", "esp32s2", "esp32c3"]
test: [ { app: example, path: "components/mdns/examples" }, { app: unit_test, path: "components/mdns/tests/unit_test" } ]
runs-on: ubuntu-20.04
container: espressif/idf:${{ matrix.idf_ver }}
steps:
- name: Checkout esp-protocols
uses: actions/checkout@v3
with:
submodules: recursive
- name: Build ${{ matrix.test.app }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
shell: bash
working-directory: ${{ matrix.test.path }}
run: |
${IDF_PATH}/install.sh --enable-pytest
. ${IDF_PATH}/export.sh
python $IDF_PATH/tools/ci/ci_build_apps.py . --target ${{ matrix.idf_target }} -vv --preserve-all --pytest-app
for dir in `ls -d build_*`; do
$GITHUB_WORKSPACE/ci/clean_build_artifacts.sh `pwd`/$dir
zip -qur artifacts.zip $dir
done
- uses: actions/upload-artifact@v3
if: ${{ matrix.idf_target }} == "esp32"
with:
name: mdns_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.test.app }}
path: ${{ matrix.test.path }}/artifacts.zip
if-no-files-found: error
build_mdns_app:
if: contains(github.event.pull_request.labels.*.name, 'mdns')
name: Build Test Apps
strategy:
matrix:
idf_ver: ["latest"]
@ -55,18 +89,18 @@ jobs:
components/mdns/tests/test_apps/build_${{ matrix.idf_target }}_default/config/sdkconfig.json
if-no-files-found: error
run-target-mdns-app:
target_test_apps_mdns:
# Skip running on forks since it won't have access to secrets
if: ${{ contains(github.event.pull_request.labels.*.name, 'mdns') && (github.repository == 'espressif/esp-protocols') }}
name: Target Test Apps
strategy:
matrix:
idf_ver: ["latest"]
idf_target: ["esp32"]
name: Run mDNS Test apps on target
needs: build_mdns_app
runs-on:
- self-hosted
- ESP32-ETHERNET-KIT
# Skip running on forks since it won't have access to secrets
if: github.repository == 'espressif/esp-protocols'
steps:
- name: Clear repository
run: sudo rm -fr $GITHUB_WORKSPACE && mkdir $GITHUB_WORKSPACE
@ -92,3 +126,44 @@ jobs:
with:
name: test_apps_results_${{ matrix.idf_target }}_${{ matrix.idf_ver }}
path: components/mdns/tests/test_apps/*.xml
target_tests_mdns:
# Skip running on forks since it won't have access to secrets
if: ${{ contains(github.event.pull_request.labels.*.name, 'mdns') && (github.repository == 'espressif/esp-protocols') }}
name: Target Example and Unit tests
strategy:
matrix:
idf_ver: ["latest"]
idf_target: ["esp32"]
test: [ { app: example, path: "components/mdns/examples" }, { app: unit_test, path: "components/mdns/tests/unit_test" } ]
needs: build_mdns
runs-on:
- self-hosted
- ESP32-ETHERNET-KIT
steps:
- name: Clear repository
run: sudo rm -fr $GITHUB_WORKSPACE && mkdir $GITHUB_WORKSPACE
- uses: actions/checkout@v3
- uses: actions/download-artifact@v3
with:
name: mdns_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.test.app }}
path: ${{ matrix.test.path }}/ci/
- name: Install Python packages
env:
PIP_EXTRA_INDEX_URL: "https://www.piwheels.org/simple"
run: |
sudo apt-get install -y dnsutils
- name: Run ${{ matrix.test.app }} application on ${{ matrix.idf_target }}
working-directory: ${{ matrix.test.path }}
run: |
unzip ci/artifacts.zip -d ci
for dir in `ls -d ci/build_*`; do
rm -rf build sdkconfig.defaults
mv $dir build
python -m pytest --log-cli-level DEBUG --junit-xml=./results_${{ matrix.test.app }}_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${dir#"ci/build_"}.xml --target=${{ matrix.idf_target }}
done
- uses: actions/upload-artifact@v3
if: always()
with:
name: results_${{ matrix.test.app }}_${{ matrix.idf_target }}_${{ matrix.idf_ver }}.xml
path: ${{ matrix.test.path }}/*.xml

61
.github/workflows/mdns__host-tests.yml vendored Normal file
View File

@ -0,0 +1,61 @@
name: "mdns: host-tests"
on:
push:
branches:
- master
pull_request:
types: [opened, synchronize, reopened, labeled]
jobs:
host_test_mdns:
if: contains(github.event.pull_request.labels.*.name, 'mdns')
name: Host test
runs-on: ubuntu-20.04
container: espressif/idf:latest
steps:
- name: Checkout esp-protocols
uses: actions/checkout@master
with:
path: esp-protocols
- name: Build and Test
shell: bash
run: |
apt-get update && apt-get install -y dnsutils gcc g++
. ${IDF_PATH}/export.sh
cd $GITHUB_WORKSPACE/esp-protocols/components/mdns/tests/host_test
idf.py build
./build/mdns_host.elf &
dig +short -p 5353 @224.0.0.251 myesp.local > ip.txt
cat ip.txt | xargs dig +short -p 5353 @224.0.0.251 -x
cat ip.txt
build_afl_host_test_mdns:
if: contains(github.event.pull_request.labels.*.name, 'mdns')
name: Build AFL host test
strategy:
matrix:
idf_ver: ["latest"]
idf_target: ["esp32"]
runs-on: ubuntu-20.04
container: espressif/idf:${{ matrix.idf_ver }}
steps:
- name: Checkout esp-protocols
uses: actions/checkout@master
with:
path: esp-protocols
- name: Install Necessary Libs
run: |
apt-get update -y
apt-get install -y libbsd-dev
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
env:
IDF_TARGET: ${{ matrix.idf_target }}
shell: bash
run: |
. ${IDF_PATH}/export.sh
cd $GITHUB_WORKSPACE/esp-protocols/components/mdns/tests/test_afl_fuzz_host/
make INSTR=off

View File

@ -0,0 +1,173 @@
name: "esp-modem: build/host-tests"
on:
push:
branches:
- master
pull_request:
types: [opened, synchronize, reopened, labeled]
jobs:
build_esp_modem:
if: contains(github.event.pull_request.labels.*.name, 'modem')
name: Build
strategy:
matrix:
idf_ver: ["latest", "release-v4.2", "release-v4.3", "release-v4.4", "release-v5.0"]
example: ["pppos_client", "modem_console", "ap_to_pppos", "simple_cmux_client"]
exclude:
- idf_ver: "release-v4.2"
example: simple_cmux_client
include:
- idf_ver: "release-v4.2"
skip_config: usb
- idf_ver: "release-v4.3"
skip_config: usb
- idf_ver: "release-v5.0"
example: "simple_cmux_client"
warning: "Warning: The smallest app partition is nearly full"
runs-on: ubuntu-20.04
container: espressif/idf:${{ matrix.idf_ver }}
steps:
- name: Checkout esp-protocols
uses: actions/checkout@v3
with:
path: protocols
- if: ${{ matrix.skip_config }}
run: rm -f $GITHUB_WORKSPACE/protocols/components/esp_modem/examples/${{ matrix.example }}/sdkconfig.ci.${{ matrix.skip_config }}*
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }}
env:
EXPECTED_WARNING: ${{ matrix.warning }}
shell: bash
run: |
. ${IDF_PATH}/export.sh
python -m pip install idf-build-apps
cd $GITHUB_WORKSPACE/protocols
python ./ci/build_apps.py components/esp_modem/examples/${{ matrix.example }}
host_test_esp_modem:
if: contains(github.event.pull_request.labels.*.name, 'modem')
name: Host Tests
runs-on: ubuntu-20.04
container: espressif/idf:release-v4.3
env:
lwip: lwip-2.1.2
lwip_contrib: contrib-2.1.0
lwip_uri: http://download.savannah.nongnu.org/releases/lwip
COMP_DIR: esp-protocols/components/esp_modem
steps:
- name: Checkout esp-protocols
uses: actions/checkout@master
with:
path: esp-protocols
- name: Build and Test
shell: bash
run: |
apt-get update && apt-get install -y gcc-8 g++-8
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-8 800 --slave /usr/bin/g++ g++ /usr/bin/g++-8
export LWIP_PATH=`pwd`/${{ env.lwip }}
export LWIP_CONTRIB_PATH=`pwd`/${{ env.lwip_contrib }}
. ${IDF_PATH}/export.sh
$GITHUB_WORKSPACE/${{ env.COMP_DIR }}/test/host_test/env.sh $lwip $lwip_uri $lwip_contrib
cd $GITHUB_WORKSPACE/esp-protocols/components/esp_modem/examples/linux_modem
idf.py build
cd $GITHUB_WORKSPACE/esp-protocols/components/esp_modem/test/host_test
idf.py build
./build/host_modem_test.elf -r junit -o junit.xml
- name: Publish Results
uses: EnricoMi/publish-unit-test-result-action@v1
if: always()
with:
files: esp-protocols/components/esp_modem/test/host_test/junit.xml
host_test_gcov_esp_modem:
if: contains(github.event.pull_request.labels.*.name, 'modem')
name: Run gcovr on esp modem host test
runs-on: ubuntu-22.04
container: espressif/idf:release-v4.3
env:
lwip: lwip-2.1.2
lwip_contrib: contrib-2.1.0
lwip_uri: http://download.savannah.nongnu.org/releases/lwip
COMP_DIR: esp-protocols/components/esp_modem
steps:
- name: Checkout esp-protocols
uses: actions/checkout@v3
with:
path: esp-protocols
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
export DEBIAN_FRONTEND=noninteractive
export LWIP_PATH=`pwd`/${{ env.lwip }}
export LWIP_CONTRIB_PATH=`pwd`/${{ env.lwip_contrib }}
. ${IDF_PATH}/export.sh
${{ env.COMP_DIR }}/test/host_test/env.sh $lwip $lwip_uri $lwip_contrib
cd $GITHUB_WORKSPACE/${{ env.COMP_DIR }}/test/host_test
cat sdkconfig.ci.coverage >> sdkconfig.defaults
idf.py build
./build/host_modem_test.elf
- name: Run gcovr
shell: bash
run: |
python -m pip install gcovr
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
- name: Code Coverage Summary Report
uses: irongut/CodeCoverageSummary@v1.3.0
with:
filename: esp-protocols/**/esp_modem_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 artifacts
uses: actions/upload-artifact@v3
if: always()
with:
name: docs_gcovr
path: |
${{ env.COMP_DIR }}/docs_gcovr
if-no-files-found: error
# show_report_data:
# name: Publish-Results
# if: github.ref == 'refs/heads/master' || github.repository != 'espressif/esp-protocols'
# runs-on: ubuntu-22.04
# needs: gcovr_analyzer_esp_modem
# steps:
# - name: Checkout 🛎️
# uses: actions/checkout@v3
# with:
# persist-credentials: false
# - name: Download Artifacts
# uses: actions/download-artifact@v1
# with:
# name: docs_gcovr
#
# - name: Deploy generated docs
# uses: JamesIves/github-pages-deploy-action@v4
# with:
# branch: gh-pages
# folder: 'docs_gcovr'

View File

@ -0,0 +1,73 @@
name: "esp-modem: target-tests"
on:
push:
branches:
- master
pull_request:
types: [opened, synchronize, reopened, labeled]
jobs:
build_esp_modem_tests:
if: contains(github.event.pull_request.labels.*.name, 'modem')
name: Build Target tests
strategy:
matrix:
idf_ver: ["latest"]
idf_target: ["esp32c3"]
test: [ { app: pppd, path: test/target }, { app: sim800_c3, path: examples/pppos_client } ]
runs-on: ubuntu-20.04
container: espressif/idf:${{ matrix.idf_ver }}
env:
TEST_DIR: components/esp_modem/${{ matrix.test.path }}
steps:
- name: Checkout esp-protocols
uses: actions/checkout@v3
with:
submodules: recursive
- name: Build esp-modem target tests with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
env:
IDF_TARGET: ${{ matrix.idf_target }}
SDKCONFIG: sdkconfig.ci.${{ matrix.test.app }}
shell: bash
working-directory: ${{ env.TEST_DIR }}
run: |
. ${IDF_PATH}/export.sh
rm -rf sdkconfig build
[ -f ${SDKCONFIG} ] && cp ${SDKCONFIG} sdkconfig.defaults
idf.py set-target ${{ matrix.idf_target }}
idf.py build
$GITHUB_WORKSPACE/ci/clean_build_artifacts.sh ${GITHUB_WORKSPACE}/${TEST_DIR}/build
- uses: actions/upload-artifact@v3
with:
name: modem_target_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.test.app }}
path: ${{ env.TEST_DIR }}/build
if-no-files-found: error
target_tests_esp_modem:
# Skip running on forks since it won't have access to secrets
if: ${{ contains(github.event.pull_request.labels.*.name, 'modem') && (github.repository == 'espressif/esp-protocols') }}
name: Run Target tests
strategy:
matrix:
idf_ver: ["latest"]
idf_target: ["esp32c3"]
test: [ { app: pppd, path: test/target }, { app: sim800_c3, path: examples/pppos_client } ]
needs: build_esp_modem_tests
runs-on:
- self-hosted
- BrnoRPI-GH006
env:
TEST_DIR: components/esp_modem/${{ matrix.test.path }}
steps:
- name: Clear repository
run: sudo rm -fr $GITHUB_WORKSPACE && mkdir $GITHUB_WORKSPACE
- uses: actions/checkout@v3
- uses: actions/download-artifact@v3
with:
name: modem_target_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.test.app }}
path: ${{ env.TEST_DIR }}/build
- name: Run Example Test on target
working-directory: ${{ env.TEST_DIR }}
run: |
python -m pytest --log-cli-level DEBUG --target=${{ matrix.idf_target }}

32
.github/workflows/mqtt_cxx__build.yml vendored Normal file
View File

@ -0,0 +1,32 @@
name: "mqtt-cxx: build-tests"
on:
push:
branches:
- master
pull_request:
types: [opened, synchronize, reopened, labeled]
jobs:
build_esp_mqtt_cxx:
if: contains(github.event.pull_request.labels.*.name, 'mqtt')
name: Build
strategy:
matrix:
idf_ver: ["latest", "release-v5.0"]
idf_target: ["esp32"]
test: [ { app: example, path: "components/esp_mqtt_cxx/examples" }]
runs-on: ubuntu-20.04
container: espressif/idf:${{ matrix.idf_ver }}
steps:
- name: Checkout esp-protocols
uses: actions/checkout@v3
with:
submodules: recursive
- name: Build ${{ matrix.test.app }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
shell: bash
working-directory: ${{matrix.test.path}}
run: |
${IDF_PATH}/install.sh --enable-pytest
. ${IDF_PATH}/export.sh
python $IDF_PATH/tools/ci/ci_build_apps.py . --target ${{ matrix.idf_target }} -vv --preserve-all --pytest-app

View File

@ -26,6 +26,7 @@ jobs:
run: |
pip install pre-commit
pre-commit install-hooks
pre-commit install --hook-type commit-msg --hook-type pre-push
- name: Run pre-commit and check for any changes
run: |
echo "Commits being checked:"

View File

@ -1,312 +0,0 @@
name: Build and Run Target tests
on: [push, pull_request]
jobs:
build_esp_modem:
strategy:
matrix:
idf_ver: ["latest", "release-v4.1", "release-v4.2", "release-v4.3", "release-v4.4"]
example: ["pppos_client", "modem_console", "ap_to_pppos", "simple_cmux_client"]
idf_target: ["esp32"]
exclude:
- idf_ver: "release-v4.1"
example: modem_console
- idf_ver: "release-v4.1"
example: ap_to_pppos
- idf_ver: "release-v4.1"
example: simple_cmux_client
- idf_ver: "release-v4.2"
example: simple_cmux_client
runs-on: ubuntu-20.04
container: espressif/idf:${{ matrix.idf_ver }}
steps:
- name: Checkout esp-protocols
uses: actions/checkout@master
with:
path: esp-protocols
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
env:
IDF_TARGET: ${{ matrix.idf_target }}
shell: bash
run: |
. ${IDF_PATH}/export.sh
cd $GITHUB_WORKSPACE/esp-protocols/components/esp_modem/examples/${{ matrix.example }}
idf.py build
build_esp_modem_usb:
strategy:
matrix:
idf_ver: ["latest", "release-v4.4", "release-v5.0"]
example: ["modem_console", "pppos_client"]
idf_target: ["esp32s2", "esp32s3"]
runs-on: ubuntu-20.04
container: espressif/idf:${{ matrix.idf_ver }}
steps:
- name: Checkout esp-protocols
uses: actions/checkout@v3
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
working-directory: components/esp_modem/examples/${{ matrix.example }}
env:
IDF_TARGET: ${{ matrix.idf_target }}
shell: bash
run: |
. ${IDF_PATH}/export.sh
cat sdkconfig.ci.usb >> sdkconfig.defaults
idf.py build
build_mdns:
strategy:
matrix:
idf_ver: ["latest"]
idf_target: ["esp32", "esp32s2", "esp32c3"]
config: ["eth_custom_netif", "eth_def", "eth_no_ipv6", "eth_socket"]
runs-on: ubuntu-20.04
container: espressif/idf:${{ matrix.idf_ver }}
steps:
- name: Checkout esp-protocols
uses: actions/checkout@v3
with:
submodules: recursive
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }} for ${{ matrix.config }}
env:
IDF_TARGET: ${{ matrix.idf_target }}
shell: bash
working-directory: components/mdns/examples/
run: |
. ${IDF_PATH}/export.sh
rm -rf sdkconfig sdkconfig.defaults build build_${{ matrix.config }}
cat sdkconfig.ci.${{ matrix.config }} >> sdkconfig.defaults
idf.py set-target ${{ matrix.idf_target }}
idf.py build
mv build build_${{ matrix.config }}
- name: Merge binaries with IDF-${{ matrix.idf_ver }} for ${{ matrix.config }}
working-directory: components/mdns/examples
env:
IDF_TARGET: ${{ matrix.idf_target }}
shell: bash
run: |
. ${IDF_PATH}/export.sh
cd build_${{ matrix.config }}
esptool.py --chip ${{ matrix.idf_target }} merge_bin --fill-flash-size 4MB -o flash_image.bin @flash_args
cd ../
cat build_${{ matrix.config }}/config/sdkconfig.json
- uses: actions/upload-artifact@v2
with:
name: examples_app_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.config }}
path: |
components/mdns/examples/build_${{ matrix.config }}/bootloader/bootloader.bin
components/mdns/examples/build_${{ matrix.config }}/partition_table/partition-table.bin
components/mdns/examples/build_${{ matrix.config }}/*.bin
components/mdns/examples/build_${{ matrix.config }}/*.elf
components/mdns/examples/build_${{ matrix.config }}/flasher_args.json
components/mdns/examples/build_${{ matrix.config }}/config/sdkconfig.h
components/mdns/examples/build_${{ matrix.config }}/config/sdkconfig.json
if-no-files-found: error
build_asio:
strategy:
matrix:
idf_ver: ["latest"]
idf_target: ["esp32", "esp32s2"]
example: ["asio_chat", "async_request", "socks4", "ssl_client_server", "tcp_echo_server", "udp_echo_server"]
runs-on: ubuntu-20.04
container: espressif/idf:${{ matrix.idf_ver }}
steps:
- name: Checkout esp-protocols
uses: actions/checkout@v3
with:
submodules: recursive
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
working-directory: components/asio/examples/${{ matrix.example }}
env:
IDF_TARGET: ${{ matrix.idf_target }}
shell: bash
run: |
. ${IDF_PATH}/export.sh
test -f sdkconfig.ci && cat sdkconfig.ci >> sdkconfig.defaults || echo "No sdkconfig.ci"
idf.py set-target ${{ matrix.idf_target }}
idf.py build
- name: Merge binaries with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }} for ${{ matrix.example }}
working-directory: components/asio/examples/${{ matrix.example }}/build
env:
IDF_TARGET: ${{ matrix.idf_target }}
shell: bash
run: |
. ${IDF_PATH}/export.sh
esptool.py --chip ${{ matrix.idf_target }} merge_bin --fill-flash-size 4MB -o flash_image.bin @flash_args
- uses: actions/upload-artifact@v3
with:
name: examples_app_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.example }}
path: |
components/asio/examples/${{ matrix.example }}/build/bootloader/bootloader.bin
components/asio/examples/${{ matrix.example }}/build//partition_table/partition-table.bin
components/asio/examples/${{ matrix.example }}/build/*.bin
components/asio/examples/${{ matrix.example }}/build/*.elf
components/asio/examples/${{ matrix.example }}/build/flasher_args.json
components/asio/examples/${{ matrix.example }}/build/config/sdkconfig.h
components/asio/examples/${{ matrix.example }}/build/config/sdkconfig.json
if-no-files-found: error
build_websocket:
strategy:
matrix:
idf_ver: ["latest"]
idf_target: ["esp32"]
runs-on: ubuntu-20.04
container: espressif/idf:${{ matrix.idf_ver }}
steps:
- name: Checkout esp-protocols
uses: actions/checkout@v3
with:
submodules: recursive
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
env:
IDF_TARGET: ${{ matrix.idf_target }}
shell: bash
working-directory: components/esp_websocket_client/examples/
run: |
. ${IDF_PATH}/export.sh
cat sdkconfig.ci >> sdkconfig.defaults
idf.py build
- name: Merge binaries
working-directory: components/esp_websocket_client/examples/build
env:
IDF_TARGET: ${{ matrix.idf_target }}
shell: bash
run: |
. ${IDF_PATH}/export.sh
esptool.py --chip ${{ matrix.idf_target }} merge_bin --fill-flash-size 4MB -o flash_image.bin @flash_args
- uses: actions/upload-artifact@v2
with:
name: examples_app_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}
path: |
components/esp_websocket_client/examples/build/bootloader/bootloader.bin
components/esp_websocket_client/examples/build/partition_table/partition-table.bin
components/esp_websocket_client/examples/build/*.bin
components/esp_websocket_client/examples/build/*.elf
components/esp_websocket_client/examples/build/flasher_args.json
components/esp_websocket_client/examples/build/config/sdkconfig.h
components/esp_websocket_client/examples/build/config/sdkconfig.json
if-no-files-found: error
run-target-websocket:
name: Run Websocket Example Test on target
needs: build_websocket
strategy:
fail-fast: false
matrix:
idf_ver: ["latest"]
idf_target: ["esp32"]
runs-on:
- self-hosted
- ESP32-ETHERNET-KIT
# Skip running on forks since it won't have access to secrets
if: github.repository == 'espressif/esp-protocols'
steps:
- uses: actions/checkout@v3
- uses: actions/download-artifact@v2
with:
name: examples_app_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}
path: components/esp_websocket_client/examples/build/
- name: Install Python packages
env:
PIP_EXTRA_INDEX_URL: "https://www.piwheels.org/simple"
run: |
pip install --only-binary cryptography --extra-index-url https://dl.espressif.com/pypi/ -r $GITHUB_WORKSPACE/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: components/esp_websocket_client/examples
run: |
python -m pytest --log-cli-level DEBUG --junit-xml=./examples_results_${{ matrix.idf_target }}_${{ matrix.idf_ver }}.xml --target=${{ matrix.idf_target }}
- uses: actions/upload-artifact@v2
if: always()
with:
name: examples_results_${{ matrix.idf_target }}_${{ matrix.idf_ver }}
path: components/esp_websocket_client/examples/*.xml
run-target-mdns:
strategy:
matrix:
idf_ver: ["latest"]
idf_target: ["esp32"]
config: ["eth_custom_netif", "eth_def", "eth_no_ipv6", "eth_socket"]
name: Run mDNS Example Test on target
needs: build_mdns
runs-on:
- self-hosted
- ESP32-ETHERNET-KIT
# Skip running on forks since it won't have access to secrets
if: github.repository == 'espressif/esp-protocols'
steps:
- name: Clear repository
run: sudo rm -fr $GITHUB_WORKSPACE && mkdir $GITHUB_WORKSPACE
- uses: actions/checkout@v3
- uses: actions/download-artifact@v2
with:
name: examples_app_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.config }}
path: components/mdns/examples/build_${{ matrix.config }}
- name: Install Python packages
env:
PIP_EXTRA_INDEX_URL: "https://www.piwheels.org/simple"
run: |
sudo apt-get install -y dnsutils
- name: Download Example Test to target ${{ matrix.config }}
run: |
python -m esptool --chip ${{ matrix.idf_target }} write_flash 0x0 components/mdns/examples/build_${{ matrix.config }}/flash_image.bin
- name: Run Example Test on target ${{ matrix.config }}
working-directory: components/mdns/examples
run: |
rm -rf build
mv build_${{ matrix.config }} build
cat sdkconfig.ci.${{ matrix.config }} >> sdkconfig.defaults
python -m pytest --log-cli-level DEBUG --junit-xml=./examples_results_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.config }}.xml --target=${{ matrix.idf_target }}
rm -rf build sdkconfig.defaults
- uses: actions/upload-artifact@v2
if: always()
with:
name: examples_results_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.config }}
path: components/mdns/examples/*.xml
run-target-asio:
strategy:
matrix:
idf_ver: ["latest"]
idf_target: ["esp32"]
example: ["asio_chat", "tcp_echo_server", "udp_echo_server", "ssl_client_server"]
name: Run ASIO Example Test on target
needs: build_asio
runs-on:
- self-hosted
- ESP32-ETHERNET-KIT
# Skip running on forks since it won't have access to secrets
if: github.repository == 'espressif/esp-protocols'
steps:
- name: Clear repository
run: sudo rm -fr $GITHUB_WORKSPACE && mkdir $GITHUB_WORKSPACE
- uses: actions/checkout@v3
- uses: actions/download-artifact@v2
with:
name: examples_app_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.example }}
path: components/asio/examples/${{ matrix.example }}/build
- name: Install Python packages
env:
PIP_EXTRA_INDEX_URL: "https://www.piwheels.org/simple"
run: |
sudo apt-get install -y dnsutils
- name: Download Example Test to target ${{ matrix.config }}
run: |
python -m esptool --chip ${{ matrix.idf_target }} write_flash 0x0 components/asio/examples/${{ matrix.example }}/build/flash_image.bin
- name: Run Example Test ${{ matrix.example }} on target
working-directory: components/asio/examples/${{ matrix.example }}
run: |
python -m pytest --log-cli-level DEBUG --junit-xml=./examples_results_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.config }}.xml --target=${{ matrix.idf_target }}
- uses: actions/upload-artifact@v2
if: always()
with:
name: examples_results_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.example }}
path: components/asio/examples/${{ matrix.example }}/*.xml

View File

@ -1,30 +0,0 @@
name: AFL fuzzer compilation test
on: [push, pull_request]
jobs:
build:
strategy:
matrix:
idf_ver: ["latest"]
idf_target: ["esp32"]
runs-on: ubuntu-20.04
container: espressif/idf:${{ matrix.idf_ver }}
steps:
- name: Checkout esp-protocols
uses: actions/checkout@master
with:
path: esp-protocols
- name: Install Necessary Libs
run: |
apt-get update -y
apt-get install -y libbsd-dev
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
env:
IDF_TARGET: ${{ matrix.idf_target }}
shell: bash
run: |
. ${IDF_PATH}/export.sh
cd $GITHUB_WORKSPACE/esp-protocols/components/mdns/tests/test_afl_fuzz_host/
make INSTR=off

View File

@ -0,0 +1,93 @@
name: "websocket: build/target-tests"
on:
push:
branches:
- master
pull_request:
types: [opened, synchronize, reopened, labeled]
jobs:
build_websocket:
if: contains(github.event.pull_request.labels.*.name, 'websocket')
name: Build
strategy:
matrix:
idf_ver: ["release-v5.0", "latest"]
idf_target: ["esp32"]
runs-on: ubuntu-20.04
container: espressif/idf:${{ matrix.idf_ver }}
env:
TEST_DIR: components/esp_websocket_client/examples
steps:
- name: Checkout esp-protocols
uses: actions/checkout@v3
with:
submodules: recursive
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
env:
IDF_TARGET: ${{ matrix.idf_target }}
shell: bash
working-directory: ${{ env.TEST_DIR }}
run: |
. ${IDF_PATH}/export.sh
cat sdkconfig.ci >> sdkconfig.defaults
idf.py build
- name: Merge binaries
working-directory: ${{ env.TEST_DIR }}/build
env:
IDF_TARGET: ${{ matrix.idf_target }}
shell: bash
run: |
. ${IDF_PATH}/export.sh
esptool.py --chip ${{ matrix.idf_target }} merge_bin --fill-flash-size 4MB -o flash_image.bin @flash_args
- uses: actions/upload-artifact@v3
with:
name: examples_app_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}
path: |
${{ env.TEST_DIR }}/build/bootloader/bootloader.bin
${{ env.TEST_DIR }}/build/partition_table/partition-table.bin
${{ env.TEST_DIR }}/build/*.bin
${{ env.TEST_DIR }}/build/*.elf
${{ env.TEST_DIR }}/build/flasher_args.json
${{ env.TEST_DIR }}/build/config/sdkconfig.h
${{ env.TEST_DIR }}/build/config/sdkconfig.json
if-no-files-found: error
run-target-websocket:
# Skip running on forks since it won't have access to secrets
if: ${{ contains(github.event.pull_request.labels.*.name, 'websocket') && (github.repository == 'espressif/esp-protocols') }}
name: Target test
needs: build_websocket
strategy:
fail-fast: false
matrix:
idf_ver: ["release-v5.0", "latest"]
idf_target: ["esp32"]
runs-on:
- self-hosted
- ESP32-ETHERNET-KIT
env:
TEST_DIR: components/esp_websocket_client/examples
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: 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 }}
- uses: actions/upload-artifact@v3
if: always()
with:
name: examples_results_${{ matrix.idf_target }}_${{ matrix.idf_ver }}
path: ${{ env.TEST_DIR }}/*.xml

View File

@ -12,10 +12,11 @@ repos:
- id: trailing-whitespace
- id: mixed-line-ending
- id: debug-statements
- repo: https://gitlab.com/pycqa/flake8
- repo: https://github.com/pycqa/flake8
rev: 5.0.4
hooks:
- id: flake8
args: ['--config=.flake8', '--tee', '--benchmark']
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v0.981
hooks:
@ -32,6 +33,7 @@ repos:
rev: "v0.32.0"
hooks:
- id: yapf
args: ['style={based_on_style: google, column_limit: 160, indent_width: 4}']
- repo: https://github.com/pre-commit/mirrors-isort
rev: v5.10.1
hooks:
@ -50,3 +52,17 @@ repos:
hooks:
- id: astyle_py
args: ['--style=otbs', '--attach-namespaces', '--attach-classes', '--indent=spaces=4', '--convert-tabs', '--align-pointer=name', '--align-reference=name', '--keep-one-line-statements', '--pad-header', '--pad-oper']
- repo: https://github.com/commitizen-tools/commitizen
rev: v2.42.1
hooks:
- id: commitizen
- id: commitizen-branch
stages: [push]
- repo: local
hooks:
- id: commit message scopes
name: "commit message must be scoped with: mdns, modem, websocket, asio, mqtt_cxx, common"
entry: '\A(?!(feat|fix|ci|bump|test|docs)\((mdns|modem|common|websocket|asio|mqtt_cxx)\)\:)'
language: pygrep
args: [--multiline]
stages: [commit-msg]

View File

@ -6,8 +6,10 @@ Contributions in the form of pull requests, issue reports, and feature requests
- [ ] Fork the [esp-protocols repository on GitHub](https://github.com/espressif/esp-protocols) to start making your changes.
- [ ] Install pre-commit hooks: `pip install pre-commit && pre-commit install`
- [ ] Install pre-commit hooks: `pip install pre-commit && pre-commit install-hooks && pre-commit install --hook-type commit-msg --hook-type pre-push`
- [ ] Send a pull request (PR) and work with us until it gets merged and published. Contributions may need some modifications, so a few rounds of review and fixing may be necessary.
For quick merging, the contribution should be short, and concentrated on a single feature or topic. The larger the contribution is, the longer it would take to review it and merge it.
Please follow the [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/) rule when writing commit messages.

60
ci/build_apps.py Normal file
View File

@ -0,0 +1,60 @@
# SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
"""
This file is used in CI for esp-protocols build tests
"""
import argparse
import os
import sys
from pathlib import Path
from idf_build_apps import build_apps, find_apps, setup_logging
from idf_build_apps.constants import SUPPORTED_TARGETS
if __name__ == '__main__':
parser = argparse.ArgumentParser(
description='Build all projects',
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
)
parser.add_argument('paths', nargs='+', help='Paths to the apps to build.')
parser.add_argument(
'-t',
'--target',
default='all',
help='Build apps for given target',
)
args = parser.parse_args()
IDF_PATH = os.environ['IDF_PATH']
print(args.paths)
setup_logging(2)
apps = find_apps(
args.paths,
recursive=True,
target=args.target,
build_dir='build_@t_@w',
config_rules_str=[
'sdkconfig.ci=default', 'sdkconfig.ci.*=', '=default'
],
build_log_path='build_log.txt',
size_json_path='size.json',
check_warnings=True,
preserve=True,
manifest_files=[
str(p) for p in Path('.').glob('**/.build-test-rules.yml')
],
default_build_targets=SUPPORTED_TARGETS,
manifest_rootpath='.',
)
for app in apps:
print(app)
sys.exit(
build_apps(apps,
dry_run=False,
keep_going=False,
ignore_warning_strs=os.environ['EXPECTED_WARNING']
if 'EXPECTED_WARNING' in os.environ else None))

98
ci/changelog.py Normal file
View File

@ -0,0 +1,98 @@
# SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
import argparse
import os
import re
import sh
def main():
parser = argparse.ArgumentParser(
description='Generates a change log from cz commits')
parser.add_argument('component')
args = parser.parse_args()
old_ref = os.environ.get('CZ_PRE_CURRENT_TAG_VERSION')
new_tag = os.environ.get('CZ_PRE_NEW_TAG_VERSION')
new_ref = os.environ.get('CZ_PRE_NEW_VERSION')
component = args.component
root_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
git = sh.git.bake(_cwd=root_path)
keys = ['breaking', 'major', 'feat', 'fix', 'update']
items = {key: [] for key in keys}
sections = {
'feat': 'Features',
'fix': 'Bug Fixes',
'update': 'Updated',
'breaking': 'Breaking changes',
'major': 'Major changes'
}
brief_log = git.log('--oneline', '{}..HEAD'.format(old_ref), '--', 'components/' + component, _tty_out=False)
for oneline in brief_log.splitlines():
[commit, brief_msg] = oneline.split(' ', 1)
if 'Merge' in str(brief_msg) or brief_msg.startswith('bump('): # skip Merge commits and bumps
continue
find_title = re.findall(r'^(fix|feat|esp_modem|esp-modem|mdns)(\([^\)]+\))?:\s*(.+)$', str(brief_msg))
item_type = '' # default prefix
item_message = brief_msg # default body
if find_title is not None and len(find_title) > 0: # Use scopes & types
item_type = find_title[0][0] # prefix (fix/feat/ci)
item_message = find_title[0][-1] # title body
# Add details in parentheses (commit-id and references from the FOOTER section)
details = '[{}](https://github.com/espressif/esp-protocols/commit/{})'.format(commit, commit)
msg_details = git.show('-s', commit, _tty_out=False)
# check references
if any(str(msg_details) in s for s in ['esp-protocols/issues', 'BREAKING CHANGE', 'MAJOR CHANGE']):
# Closes <issue>
closes = re.findall(r'Closes ([^\d]+/(\d+))', str(msg_details), re.MULTILINE)
if closes and closes[0] is not None:
details += ', [#{}]({})'.format(closes[0][1], closes[0][0])
# Breaking changes
find_breaking = re.findall(r'BREAKING CHANGE:\s*([^\n]*)', str(msg_details), re.MULTILINE)
if find_breaking is not None and len(find_breaking) > 0:
if find_breaking[0] != '':
items['breaking'].append('{} ([{}](https://github.com/espressif/esp-protocols/commit/{}))'.format(find_breaking[0], item_message, commit))
else:
items['breaking'].append('{} ({})'.format(item_message, details))
details += ', !BREAKING'
# Major changes
find_major = re.findall(r'MAJOR CHANGE:\s*([^\n]*)',
str(msg_details), re.MULTILINE)
if find_major is not None and len(
find_major) > 0 and find_major[0] != '':
items['major'].append('{} ([{}](https://github.com/espressif/esp-protocols/commit/{}))'.format(find_major[0], item_message, commit))
if item_type in ['fix', 'feat']:
items[item_type].append('{} ({})'.format(item_message, details))
else:
items['update'].append('{} ({})'.format(item_message, details))
# Generate changelog
changelog = '## [{}](https://github.com/espressif/esp-protocols/commits/{})\n'.format(
new_ref, new_tag)
for section, item in items.items():
if len(item) > 0:
changelog += '\n### {}\n\n'.format(sections[section])
for it in item:
changelog += '- {}\n'.format(it)
changelog += '\n'
filename = os.path.join(root_path, 'components', component, 'CHANGELOG.md')
# insert the actual changelog to the beginning of the file, just after the title (2nd line)
with open(filename, 'r') as orig_changelog:
changelog_title = orig_changelog.readline(
) # expect # Changelog title on the first line
changelog_nl = orig_changelog.readline()
orig_items = orig_changelog.read()
with open(filename, 'w') as updated_changelog:
updated_changelog.write(changelog_title)
updated_changelog.write(changelog_nl)
updated_changelog.write(changelog)
updated_changelog.write(orig_items)
git.add(filename)
if __name__ == '__main__':
main()

7
ci/clean_build_artifacts.sh Executable file
View File

@ -0,0 +1,7 @@
# Remove everything, but
# - elf/bin files in the build dir
# - partition-table and bootloader binaries
# - flasher args
# - sdkconfigs (header and json)
# (Ignoring the command failure as it refuses to delete nonempty dirs)
find $1 ! -regex ".*/build[^/]*/[^/]+.\(bin\|elf\)" -a ! -regex ".*\(bootloader\|partition-table\).bin" -a ! -name "flasher_args.json" -a ! -regex ".*/build[^/]*/config/sdkconfig.\(h\|json\)" -delete || true

View File

@ -5,3 +5,4 @@ SimpleWebSocketServer
dpkt
pytest
idf_build_apps
netifaces

View File

@ -0,0 +1,43 @@
# Changelog
## [1.14.1~3](https://github.com/espressif/esp-protocols/commits/f148c98)
### Updated
- ASIO: Updated package version to "1.14.1~3" ([f148c98](https://github.com/espressif/esp-protocols/commit/f148c98))
- ASIO: Example tests integration ([5193ebc](https://github.com/espressif/esp-protocols/commit/5193ebc))
## [1.0.2](https://github.com/espressif/esp-protocols/commits/57afa38)
### Updated
- Bump asio/mdns/esp_websocket_client versions ([57afa38](https://github.com/espressif/esp-protocols/commit/57afa38))
- ignore format warnings ([d66f9dc](https://github.com/espressif/esp-protocols/commit/d66f9dc))
- asio: Fix exampels build ([3662c14](https://github.com/espressif/esp-protocols/commit/3662c14))
## [1.0.1](https://github.com/espressif/esp-protocols/commits/055f051)
### Updated
- ASIO: Initial version based on IDF 5.0 with history ([055f051](https://github.com/espressif/esp-protocols/commit/055f051))
- asio: Disable concepts support Fix example for compatibility with C++20 ([ac7bf46](https://github.com/espressif/esp-protocols/commit/ac7bf46), [IDF@9dba047](https://github.com/espressif/esp-idf/commit/9dba0476a01cd80d76e21706ad350009606b877e))
- lwip: Update socket API to include port-version of sockets/netdb ([057a5d2](https://github.com/espressif/esp-protocols/commit/057a5d2), [IDF@53c009e](https://github.com/espressif/esp-idf/commit/53c009e62631bae569fa849c6b6c9e70a10b3afe))
- esp_netif/lwip: Implement basic support for vanilla-lwip (2.1.3-REL) ([63bff63](https://github.com/espressif/esp-protocols/commit/63bff63), [IDF@5b471a1](https://github.com/espressif/esp-idf/commit/5b471a18489b056f65fe8dcbb2c992d27909ebc9))
- mbedtls: Remove certs.c and certs.h from port directory ([e3c4391](https://github.com/espressif/esp-protocols/commit/e3c4391), [IDF@f31d8dd](https://github.com/espressif/esp-idf/commit/f31d8dd2955be0fe949340dcf3b043ec6daf4378))
- mbedtls-3 update: 1) Fix build issue in mbedtls 2) skip the public headers check in IDF 3)Update Kconfig Macros 4)Remove deprecated config options 5) Update the sha API according to new nomenclature 6) Update mbedtls_rsa_init usage 7) Include mbedtls/build_info.h instead of mbedtls/config.h 8) Dont include check_config.h 9) Add additional error message in esp_blufi_api.h ([9813818](https://github.com/espressif/esp-protocols/commit/9813818), [IDF@4512253](https://github.com/espressif/esp-idf/commit/45122533e0bca5d538585e22308f14b74c33e474))
- asio: Use internal ssl context and engine impl ([f605fdd](https://github.com/espressif/esp-protocols/commit/f605fdd), [IDF@d823106](https://github.com/espressif/esp-idf/commit/d823106aa6b24b8bdcc30373513c8688c61438c4))
- Build & config: Remove leftover files from the unsupported "make" build system ([abbc8d9](https://github.com/espressif/esp-protocols/commit/abbc8d9), [IDF@766aa57](https://github.com/espressif/esp-idf/commit/766aa5708443099f3f033b739cda0e1de101cca6))
- openssl: Add deprecation warning to ssl.h ([a029774](https://github.com/espressif/esp-protocols/commit/a029774), [IDF@cfc0018](https://github.com/espressif/esp-idf/commit/cfc001870c5e0afed7b42b6bf8c326eae053fe96))
- asio coap: If LWIP IPV6 is disabled, automatically don't build asio & coap ([cc0f2b3](https://github.com/espressif/esp-protocols/commit/cc0f2b3), [IDF@e305f29](https://github.com/espressif/esp-idf/commit/e305f2938278c2a39e75c21a3ed59d8f4d4e62fa))
- asio: update copyright notice ([47d57a5](https://github.com/espressif/esp-protocols/commit/47d57a5), [IDF@2d0895e](https://github.com/espressif/esp-idf/commit/2d0895e9a98bc7846d0ac7321f2b86b47346bf21))
- Whitespace: Automated whitespace fixes (large commit) ([622a360](https://github.com/espressif/esp-protocols/commit/622a360), [IDF@66fb5a2](https://github.com/espressif/esp-idf/commit/66fb5a29bbdc2482d67c52e6f66b303378c9b789))
- cmake: Apply cmakelint fixes ([4358c3c](https://github.com/espressif/esp-protocols/commit/4358c3c), [IDF@e82eac4](https://github.com/espressif/esp-idf/commit/e82eac4354b8b4111697656f3acce7450eeff366))
- asio: option to use wolfSSL as TLS stack for ASIO ([c05558b](https://github.com/espressif/esp-protocols/commit/c05558b), [IDF@1c8171c](https://github.com/espressif/esp-idf/commit/1c8171c3e8d5a67e47dc8d6abac27ad2989470c3))
- asio: Basic SSL/TLS support in asio port for ESP platform ([dab1230](https://github.com/espressif/esp-protocols/commit/dab1230), [IDF@9459c0d](https://github.com/espressif/esp-idf/commit/9459c0dd432fdd0fccb49ea65bb5c72d1849e1ba))
- asio: updated ASIO port to use latest asio and esp-idf features ([9190917](https://github.com/espressif/esp-protocols/commit/9190917), [IDF@13d603e](https://github.com/espressif/esp-idf/commit/13d603e486624380d49f2e89614b10425c208d14))
- components: use new component registration api ([9e83b1e](https://github.com/espressif/esp-protocols/commit/9e83b1e), [IDF@9eccd7c](https://github.com/espressif/esp-idf/commit/9eccd7c0826d6cc2e9de59304d1e5f76c0063ccf))
- Rename Kconfig options (root) ([3b49d1f](https://github.com/espressif/esp-protocols/commit/3b49d1f), [IDF@c5000c8](https://github.com/espressif/esp-idf/commit/c5000c83d250896fffbddd7a3991384ea0fc286d))
- cmake: make main a component again ([57672d5](https://github.com/espressif/esp-protocols/commit/57672d5), [IDF@d9939ce](https://github.com/espressif/esp-idf/commit/d9939cedd9b44d63dc148354c3a0a139b9c7113d))
- asio: initial idf port of asio library without ssl ([5472d5c](https://github.com/espressif/esp-protocols/commit/5472d5c), [IDF@1ef13c5](https://github.com/espressif/esp-idf/commit/1ef13c524c484e9fb62e6c0b11482c30c5383728))

23
components/asio/LICENSE Normal file
View File

@ -0,0 +1,23 @@
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

View File

@ -1,5 +1,7 @@
# ASIO port
[![Component Registry](https://components.espressif.com/components/espressif/asio/badge.svg)](https://components.espressif.com/components/espressif/asio)
Asio is a cross-platform C++ library, see https://think-async.com/Asio/. It provides a consistent asynchronous model using a modern C++ approach.
## Examples

View File

@ -1,2 +1,8 @@
CONFIG_ESP_MAIN_TASK_STACK_SIZE=8192
CONFIG_COMPILER_CXX_EXCEPTIONS=y
#
# Partition Table
#
# Leave some room for larger apps without needing to reduce other features
CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y

View File

@ -1,5 +1,6 @@
version: "1.14.1~3"
description: ASIO
url: https://github.com/espressif/esp-protocols/tree/master/components/asio
dependencies:
idf:
version: ">=5.0"

View File

@ -0,0 +1,311 @@
# Changelog
## [0.1.28](https://github.com/espressif/esp-protocols/commits/01c26c8)
### Updated
- Dual DTE support ([01c26c8](https://github.com/espressif/esp-protocols/commit/01c26c8))
## [0.1.27](https://github.com/espressif/esp-protocols/commits/44bae24)
### Updated
- Return true from on_data callback in data mode ([44bae24](https://github.com/espressif/esp-protocols/commit/44bae24))
## [0.1.26](https://github.com/espressif/esp-protocols/commits/05fff94)
### Features
- Added target test ([4314c78](https://github.com/espressif/esp-protocols/commit/4314c78))
- Add support for manual CMUX operations ([ac5d438](https://github.com/espressif/esp-protocols/commit/ac5d438), [#168](https://github.com/espressif/esp-protocols/issues/168))
### Bug Fixes
- Example to use variable mqtt topic/data ([8958d5e](https://github.com/espressif/esp-protocols/commit/8958d5e))
- Fix cmux client compilation issue ([f71192b](https://github.com/espressif/esp-protocols/commit/f71192b))
- Exit data mode only after state change ([9a7bd90](https://github.com/espressif/esp-protocols/commit/9a7bd90))
- Support AT with callback in C-API ([2180ab1](https://github.com/espressif/esp-protocols/commit/2180ab1), [#143](https://github.com/espressif/esp-protocols/issues/143))
### Updated
- update(esp_modem): Bump component version to 0.1.26 ([05fff94](https://github.com/espressif/esp-protocols/commit/05fff94), [#213](https://github.com/espressif/esp-protocols/issues/213))
- Added the missing definition for the esp_modem_set_baud function (IDFGH-9181) (#209) ([0e215b1](https://github.com/espressif/esp-protocols/commit/0e215b1))
- CI: Added coverage analyzer for esp_modem host tests ([6b684ce](https://github.com/espressif/esp-protocols/commit/6b684ce))
- Update esp_modem_command_library.cpp ([5304a6e](https://github.com/espressif/esp-protocols/commit/5304a6e))
- Added badges with version of components to the respective README files ([e4c8a59](https://github.com/espressif/esp-protocols/commit/e4c8a59))
- esp_modem/examples: Add an example to synchronise PSM sleep in Sim70XX modem and esp32. ([1ca1391](https://github.com/espressif/esp-protocols/commit/1ca1391))
## [0.1.25](https://github.com/espressif/esp-protocols/commits/f1ae14f)
### Bug Fixes
- Cleanup custom lib-commands and factory ([65c0e0e](https://github.com/espressif/esp-protocols/commit/65c0e0e))
- Examples to configure MQTT Broker ([71a2388](https://github.com/espressif/esp-protocols/commit/71a2388))
- Extend pppos example project config ([ebc36a3](https://github.com/espressif/esp-protocols/commit/ebc36a3))
- Uart Terminal read_cb race ([a02bf05](https://github.com/espressif/esp-protocols/commit/a02bf05))
### Updated
- update(esp_modem): Bump component version ([f1ae14f](https://github.com/espressif/esp-protocols/commit/f1ae14f))
- fix(esp_modem) Add example that reads GNSS info ([652314e](https://github.com/espressif/esp-protocols/commit/652314e))
- CI: fixing the files to be complient with pre-commit hooks ([945bd17](https://github.com/espressif/esp-protocols/commit/945bd17))
- Quick fix esp_modem: Added modem_console commands for deep-sleep and modem PSM. ([cf504ec](https://github.com/espressif/esp-protocols/commit/cf504ec))
- fix(esp-modem) Make simple_cmux_client example configurable ([511ed54](https://github.com/espressif/esp-protocols/commit/511ed54))
- Added modem_console commands for deep-sleep and modem PSM. ([85a2e25](https://github.com/espressif/esp-protocols/commit/85a2e25))
- ci: Compile esp_modem examples with USB support ([988b3f9](https://github.com/espressif/esp-protocols/commit/988b3f9))
- Expand PPPoS example with USB DTE ([53b5933](https://github.com/espressif/esp-protocols/commit/53b5933))
- Allow USB DTE reconnection ([bf84ae9](https://github.com/espressif/esp-protocols/commit/bf84ae9))
- Add ConsoleCommand destructor ([a89a0ab](https://github.com/espressif/esp-protocols/commit/a89a0ab))
- esp_modem_get_gnss_power_mode (#136) ([fe536e4](https://github.com/espressif/esp-protocols/commit/fe536e4))
- remove unused Config Parameters ! ([55b4775](https://github.com/espressif/esp-protocols/commit/55b4775))
## [0.1.24](https://github.com/espressif/esp-protocols/commits/9b48b0a)
### Features
- Make some CMUX params compile-time configurable ([25ac2d9](https://github.com/espressif/esp-protocols/commit/25ac2d9))
### Bug Fixes
- CMUX to ignore MSC frames ([ce175df](https://github.com/espressif/esp-protocols/commit/ce175df), [#140](https://github.com/espressif/esp-protocols/issues/140))
- Fix CRLF endlines in examples ([07a347f](https://github.com/espressif/esp-protocols/commit/07a347f))
- Console example to use configurable flow-ctrl ([d9c9681](https://github.com/espressif/esp-protocols/commit/d9c9681))
### Updated
- update(esp_modem): Bump component version ([9b48b0a](https://github.com/espressif/esp-protocols/commit/9b48b0a))
- Allow error handler register in C ([62cb235](https://github.com/espressif/esp-protocols/commit/62cb235))
## [0.1.23](https://github.com/espressif/esp-protocols/commits/04c711f)
### Features
- Add exit PPP in example ([290197c](https://github.com/espressif/esp-protocols/commit/290197c))
### Updated
- Move common C definitions in to separate header ([04c711f](https://github.com/espressif/esp-protocols/commit/04c711f))
- Minor formatting fix and spelling ([accf924](https://github.com/espressif/esp-protocols/commit/accf924))
- extended the modem_console example. (#120) ([ef0e48a](https://github.com/espressif/esp-protocols/commit/ef0e48a))
## [0.1.22](https://github.com/espressif/esp-protocols/commits/187ef76)
### Bug Fixes
- DTE command race of timeout vs reply's signal ([a871473](https://github.com/espressif/esp-protocols/commit/a871473), [#110](https://github.com/espressif/esp-protocols/issues/110))
- Correct timeouts for certain commands ([1029078](https://github.com/espressif/esp-protocols/commit/1029078), [#129](https://github.com/espressif/esp-protocols/issues/129))
- Make get_operator_name() return also ACT value ([0015e54](https://github.com/espressif/esp-protocols/commit/0015e54), [#128](https://github.com/espressif/esp-protocols/issues/128))
### Updated
- update(esp_modem): Bump component version ([187ef76](https://github.com/espressif/esp-protocols/commit/187ef76))
## [0.1.21](https://github.com/espressif/esp-protocols/commits/d07237b)
### Updated
- Fix IDF version resolution ([d07237b](https://github.com/espressif/esp-protocols/commit/d07237b))
- Fix format warnings ([98bf3ef](https://github.com/espressif/esp-protocols/commit/98bf3ef), [#79](https://github.com/espressif/esp-protocols/issues/79))
## [0.1.20](https://github.com/espressif/esp-protocols/commits/ae8479c)
### Bug Fixes
- Correct exit of CMUX mode ([2099434](https://github.com/espressif/esp-protocols/commit/2099434), [#103](https://github.com/espressif/esp-protocols/issues/103))
- Add filename/line info to exception message ([89e1bd2](https://github.com/espressif/esp-protocols/commit/89e1bd2))
### Updated
- Expose set_error_cb method ([ae8479c](https://github.com/espressif/esp-protocols/commit/ae8479c))
## [0.1.19](https://github.com/espressif/esp-protocols/commits/469f953)
### Features
- Add optional ACT to operator-name ([a286634](https://github.com/espressif/esp-protocols/commit/a286634), [#80](https://github.com/espressif/esp-protocols/issues/80))
### Bug Fixes
- Add missing set_pdp_context() to C-API ([4980ac8](https://github.com/espressif/esp-protocols/commit/4980ac8))
### Updated
- updated package version to 0.1.19 ([469f953](https://github.com/espressif/esp-protocols/commit/469f953))
- CI: Fix build issues ([6e4e4fa](https://github.com/espressif/esp-protocols/commit/6e4e4fa))
- esp_err_to_name (IDFGH-7793) (#78) ([d1129f3](https://github.com/espressif/esp-protocols/commit/d1129f3))
## [0.1.18](https://github.com/espressif/esp-protocols/commits/e8145fc)
### Features
- Add CMUX mode to C-API ([3fd4391](https://github.com/espressif/esp-protocols/commit/3fd4391), [#41](https://github.com/espressif/esp-protocols/issues/41))
- Add support to CMUX exit ([a16aab6](https://github.com/espressif/esp-protocols/commit/a16aab6), [#37](https://github.com/espressif/esp-protocols/issues/37))
### Bug Fixes
- Update ap2ppp example to recover network on disconnection ([a243d7e](https://github.com/espressif/esp-protocols/commit/a243d7e), [#44](https://github.com/espressif/esp-protocols/issues/44))
- Implement movable unique_buffer to bundle data, size, ptr ([66e6d4c](https://github.com/espressif/esp-protocols/commit/66e6d4c))
- DTE should own both command and data terminal ([f3ff98b](https://github.com/espressif/esp-protocols/commit/f3ff98b))
- Update CMUX example to use CMUX mode automatically ([58a0b57](https://github.com/espressif/esp-protocols/commit/58a0b57))
- Improve PPP exit sequence ([1e0aefd](https://github.com/espressif/esp-protocols/commit/1e0aefd), [#47](https://github.com/espressif/esp-protocols/issues/47))
### Updated
- Ignore format warnings ([e8145fc](https://github.com/espressif/esp-protocols/commit/e8145fc))
- Allow to customize uart source_clk ([d723fb7](https://github.com/espressif/esp-protocols/commit/d723fb7))
- Add "at" api for custom commands ([0cf08fb](https://github.com/espressif/esp-protocols/commit/0cf08fb))
## [0.1.17](https://github.com/espressif/esp-protocols/commits/5addf9e)
### Features
- Bumped version number to 0.1.17 ([5addf9e](https://github.com/espressif/esp-protocols/commit/5addf9e))
### Bug Fixes
- Support 2 byte size packets ([128c0a2](https://github.com/espressif/esp-protocols/commit/128c0a2), [#46](https://github.com/espressif/esp-protocols/issues/46))
- Correction of switching to CMUX ([503218b](https://github.com/espressif/esp-protocols/commit/503218b), [#33](https://github.com/espressif/esp-protocols/issues/33))
### Updated
- Fix param description for get_operator_name() ([a661e51](https://github.com/espressif/esp-protocols/commit/a661e51))
- Update: Removed stringstream to decrease static sizes ([3ced2d9](https://github.com/espressif/esp-protocols/commit/3ced2d9))
- Update: Renamed list_in to be type-specific Update: Removed modem-specific comment ([ba88d7f](https://github.com/espressif/esp-protocols/commit/ba88d7f))
- Update: Changed tests to coincide with new initial esp_modem mode ([4f3c429](https://github.com/espressif/esp-protocols/commit/4f3c429))
- typo ([52de8f1](https://github.com/espressif/esp-protocols/commit/52de8f1))
- Update: Removed duplicate power down function Add: gnss power mode function ([e98cf16](https://github.com/espressif/esp-protocols/commit/e98cf16))
- Update: Formatting ([be3d2ec](https://github.com/espressif/esp-protocols/commit/be3d2ec))
- Add: Sim7600 extended support ([15ed885](https://github.com/espressif/esp-protocols/commit/15ed885))
- Add: Support for SIM7000 modules ([0733ea8](https://github.com/espressif/esp-protocols/commit/0733ea8))
- Update: modem_mode::UNDEF initially ([15cbc9b](https://github.com/espressif/esp-protocols/commit/15cbc9b))
- Add: sim7070 support ([bb7f198](https://github.com/espressif/esp-protocols/commit/bb7f198))
- Add: Expanded modem_command_library with more "standard" commands ([d3f7ea6](https://github.com/espressif/esp-protocols/commit/d3f7ea6))
- Fix DCE selection in pppos_client example ([d191a72](https://github.com/espressif/esp-protocols/commit/d191a72))
- Fix AT command in set_data_mode_sim8xx() for SIM800 modem device ([cc0d527](https://github.com/espressif/esp-protocols/commit/cc0d527))
## [0.1.16](https://github.com/espressif/esp-protocols/commits/74040cf)
### Updated
- Extend modem_console example with USB DTE ([74040cf](https://github.com/espressif/esp-protocols/commit/74040cf))
## [0.1.15](https://github.com/espressif/esp-protocols/commits/1f5eb39)
### Updated
- Fix IDFv5.0 include paths ([1f5eb39](https://github.com/espressif/esp-protocols/commit/1f5eb39))
## [0.1.14](https://github.com/espressif/esp-protocols/commits/745201b)
### Bug Fixes
- missing default statement in a switch in the modem_console example ([325a193](https://github.com/espressif/esp-protocols/commit/325a193))
- add virtual destructors to ModuleIf and CommandableIf ([face03e](https://github.com/espressif/esp-protocols/commit/face03e))
### Updated
- build: fix issue with passing cxx_std option, a common workaround ([745201b](https://github.com/espressif/esp-protocols/commit/745201b))
- add(esp_modem): Add unit test to check polymorphic delete ([e54b240](https://github.com/espressif/esp-protocols/commit/e54b240))
- Implement esp_modem_sync for the C API ([8b3d420](https://github.com/espressif/esp-protocols/commit/8b3d420))
## [0.1.13](https://github.com/espressif/esp-protocols/commits/2cb74cf)
### Bug Fixes
- Update the test to exersise CBC parser ([d879e82](https://github.com/espressif/esp-protocols/commit/d879e82))
- Fix battery status parse ([4f1d31f](https://github.com/espressif/esp-protocols/commit/4f1d31f))
- Read module name with AT commands ([8417e23](https://github.com/espressif/esp-protocols/commit/8417e23))
- linux port to work with lwip-2.1.2 ([8465b14](https://github.com/espressif/esp-protocols/commit/8465b14))
### Updated
- Update(esp_modem): Bump component version ([2cb74cf](https://github.com/espressif/esp-protocols/commit/2cb74cf))
## [0.1.12](https://github.com/espressif/esp-protocols/commits/5d9ad9c)
### Updated
- Update FreeRTOS EventQueueHandle_t forward declaration ([5d9ad9c](https://github.com/espressif/esp-protocols/commit/5d9ad9c))
## [0.1.11](https://github.com/espressif/esp-protocols/commits/9649876)
### Updated
- New version to publish to component registry ([9649876](https://github.com/espressif/esp-protocols/commit/9649876))
- Docs: Add links to GitHub pages ([cf990d1](https://github.com/espressif/esp-protocols/commit/cf990d1))
- Add missing AT commands to plain C-API ([5299b42](https://github.com/espressif/esp-protocols/commit/5299b42))
- CI/Docs: Generate docs locally before uploading to registry ([2c21aa1](https://github.com/espressif/esp-protocols/commit/2c21aa1))
- CI/Docs: Add jobs to deploy component docs ([b9ff1e4](https://github.com/espressif/esp-protocols/commit/b9ff1e4))
- Update Task handle and Event Group handle to match freertos v10.4.3 ([5888717](https://github.com/espressif/esp-protocols/commit/5888717))
- Examples: Fix print format for http_client() API ([01e2a9c](https://github.com/espressif/esp-protocols/commit/01e2a9c))
- Examples: Fix build error when SIM needs no PIN ([c8c24ed](https://github.com/espressif/esp-protocols/commit/c8c24ed))
- Examples: Use bigger 4M flash for OTA example ([b380ded](https://github.com/espressif/esp-protocols/commit/b380ded))
## [0.1.9](https://github.com/espressif/esp-protocols/commits/2a2d270)
### Updated
- Fix CMake3.5 build with no cxx_std_17 feature ([2a2d270](https://github.com/espressif/esp-protocols/commit/2a2d270))
## [0.1.8](https://github.com/espressif/esp-protocols/commits/9dd1bd5)
### Updated
- 0.1.8: Update comonent version ([9dd1bd5](https://github.com/espressif/esp-protocols/commit/9dd1bd5))
- Add pre upload script to deploy the docs before component upload ([918db0d](https://github.com/espressif/esp-protocols/commit/918db0d))
- Minor correction of the docs ([c1b1330](https://github.com/espressif/esp-protocols/commit/c1b1330))
- Examples/console: Remove unnecessary event-base check on IP handler ([fb7295e](https://github.com/espressif/esp-protocols/commit/fb7295e))
- Examples: Extend CMux client default stack size for the main task ([8236b3d](https://github.com/espressif/esp-protocols/commit/8236b3d))
- CMUX: Refactor the protocol decoder to multiple methods per cmux state ([fb6029b](https://github.com/espressif/esp-protocols/commit/fb6029b))
- Factory: Rename Builder class to Creator, since it's not 100% builder pattern ([6e34954](https://github.com/espressif/esp-protocols/commit/6e34954))
- Formal updates per code review ([148a930](https://github.com/espressif/esp-protocols/commit/148a930))
- Docs: Update CMux collaboration diagram to resemble composite ([1fb9150](https://github.com/espressif/esp-protocols/commit/1fb9150))
- Applied astyle code formatting ([a61e9e2](https://github.com/espressif/esp-protocols/commit/a61e9e2))
- Minor corrections per code review ([dc64f86](https://github.com/espressif/esp-protocols/commit/dc64f86))
- Bulk replace header guards to use ([3332c27](https://github.com/espressif/esp-protocols/commit/3332c27))
- Host test fix: renamed Loopback inherited member ([84b0dcf](https://github.com/espressif/esp-protocols/commit/84b0dcf))
- Update documentation and minor fixes ([e0e6585](https://github.com/espressif/esp-protocols/commit/e0e6585))
## [0.1.7](https://github.com/espressif/esp-protocols/commits/28433de)
### Updated
- Update version to 0.1.7 -- support socket VFS ([28433de](https://github.com/espressif/esp-protocols/commit/28433de))
- Reworked decouple resources from the file system ([8f17a90](https://github.com/espressif/esp-protocols/commit/8f17a90))
- Make the component compatible with IDFv4.1, v4.2, v4.3 ([69ad3ea](https://github.com/espressif/esp-protocols/commit/69ad3ea))
## [0.1.6](https://github.com/espressif/esp-protocols/commits/a67d749)
### Updated
- Bump the version and upload the component ([a67d749](https://github.com/espressif/esp-protocols/commit/a67d749))
- Updated per review comments ([ab93c13](https://github.com/espressif/esp-protocols/commit/ab93c13))
## [0.1.5](https://github.com/espressif/esp-protocols/commits/90641c8)
### Updated
- Moved to component folder ([90641c8](https://github.com/espressif/esp-protocols/commit/90641c8))

View File

@ -47,3 +47,15 @@ if(${target} STREQUAL "linux")
# This is needed for ESP_LOGx() macros, as integer formats differ on ESP32(..) and x64
set_target_properties(${COMPONENT_LIB} PROPERTIES COMPILE_FLAGS -Wno-format)
endif()
if(CONFIG_GCOV_ENABLED)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --coverage -fprofile-arcs -ftest-coverage")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --coverage -fprofile-arcs -ftest-coverage")
MARK_AS_ADVANCED(
CMAKE_CXX_FLAGS_COVERAGE
CMAKE_C_FLAGS_COVERAGE
CMAKE_EXE_LINKER_FLAGS_COVERAGE
CMAKE_SHARED_LINKER_FLAGS_COVERAGE )
endif()

View File

@ -1,5 +1,7 @@
# ESP MODEM
[![Component Registry](https://components.espressif.com/components/espressif/esp_modem/badge.svg)](https://components.espressif.com/components/espressif/esp_modem)
The `esp-modem` component is a managed component for `esp-idf` that is used for communication with GSM/LTE modems
that support AT commands and PPP protocol as a network interface.

View File

@ -0,0 +1,7 @@
components/esp_modem/examples/ap_to_pppos:
disable:
- if: IDF_TARGET in ["esp32h2"]
components/esp_modem/examples/modem_console:
disable:
- if: IDF_TARGET in ["esp32h2"]

View File

@ -7,4 +7,6 @@ endif()
idf_component_register(SRCS "ap_to_pppos.c"
${NETWORK_DCE}
INCLUDE_DIRS ".")
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")
# Ignore strict prototypes, as the network_dce.h can used in both C and C++ compilation
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-strict-prototypes")

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
@ -38,7 +38,7 @@ static const int DISCONNECT_BIT = BIT1;
static void on_ip_event(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data)
{
ESP_LOGD(TAG, "IP event! %d", event_id);
ESP_LOGD(TAG, "IP event! %" PRId32, event_id);
if (event_id == IP_EVENT_PPP_GOT_IP) {
esp_netif_dns_info_t dns_info;
ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data;

View File

@ -210,7 +210,17 @@ extern "C" void app_main(void)
if (c->get_count_of(&SetModeArgs::mode)) {
auto mode = c->get_string_of(&SetModeArgs::mode);
modem_mode dev_mode;
if (mode == "CMD") {
if (mode == "CMUX1") {
dev_mode = esp_modem::modem_mode::CMUX_MANUAL_MODE;
} else if (mode == "CMUX2") {
dev_mode = esp_modem::modem_mode::CMUX_MANUAL_EXIT;
} else if (mode == "CMUX3") {
dev_mode = esp_modem::modem_mode::CMUX_MANUAL_SWAP;
} else if (mode == "CMUX4") {
dev_mode = esp_modem::modem_mode::CMUX_MANUAL_DATA;
} else if (mode == "CMUX5") {
dev_mode = esp_modem::modem_mode::CMUX_MANUAL_COMMAND;
} else if (mode == "CMD") {
dev_mode = esp_modem::modem_mode::COMMAND_MODE;
} else if (mode == "PPP") {
dev_mode = esp_modem::modem_mode::DATA_MODE;

View File

@ -1 +1,2 @@
CONFIG_IDF_TARGET="esp32s2"
CONFIG_EXAMPLE_SERIAL_CONFIG_USB=y

View File

@ -1 +1,2 @@
CONFIG_IDF_TARGET="esp32s3"
CONFIG_EXAMPLE_SERIAL_CONFIG_USB=y

View File

@ -0,0 +1,10 @@
# For more information about build system see
# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html
# The following five lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
set(EXTRA_COMPONENT_DIRS "../..")
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(modem_psm)

View File

@ -0,0 +1,32 @@
# Modem Power Saving Mode, sleep modes example
## Overview
This example demonstrates Power Saving Mode(PSM) in Sim70XX modems along with Deep sleep and Light Sleep modes in esp32.
This example enables Power saving mode in Sim70XX modem and tries to synchronise the sleep cycle of the modem with esp32.
When the modem wakes up from PSM sleep it wakes up the esp32. While the modem is awake esp32 goes to light sleep.
This example is tested on a SIM7080 modem.
## Supported devices
This example is supported only on ESP32, ESP32-S2 and ESP32-S3.
## Configuration
* EXAMPLE_MODEM_UART_TX_PIN: Connect this pin to the UART Tx pin of the modem.
* EXAMPLE_MODEM_UART_RX_PIN: Connect this pin to the UART Rx pin of the modem.
* EXAMPLE_MODEM_PWRKEY_PIN: Connect this pin to the PWRKEY pin of the modem.
* EXAMPLE_MODEM_STATUS_PIN: Connect this pin to the Status pin of the modem.
The status pin might not be exposed on a modem. It needs to tapped out from the LED indicator marked as STS.
* EXAMPLE_MODEM_LIGHT_SLEEP_DURATION: Duration for which the esp32 will go into light sleep, while the modem is awake.
If the esp32 goes into deep sleep while the modem is awake, esp32 will be awaken by the STATUS pin. So it's recommended to go to light sleep while the modem is awake.
* EXAMPLE_MODEM_T3412_PERIODIC_TAU: T3412 timer is the duration of one awake and sleep cycle of the modem in PSM.
* EXAMPLE_MODEM_T3324_ACTIVE_TIME: T3324 timer is the duration for which the modem stays PSM.
The timeout information is coded in bit format for T3412 and T3324 timer.

View File

@ -0,0 +1,3 @@
idf_component_register(SRCS "modem_psm.c"
INCLUDE_DIRS ".")

View File

@ -0,0 +1,109 @@
menu "Example Configuration"
choice EXAMPLE_MODEM_DEVICE
prompt "Choose supported modem device (DCE)"
default EXAMPLE_MODEM_DEVICE_SIM7080
help
Select modem device connected to the ESP DTE.
config EXAMPLE_MODEM_DEVICE_SIM7070
bool "SIM7070"
help
SIM7070 is Multi-Band CAT M and NB IoT module.
config EXAMPLE_MODEM_DEVICE_SIM7080
bool "SIM7080"
help
SIM7080 is Multi-Band CAT M and NB IoT module.
endchoice
menu "UART Configuration"
config EXAMPLE_MODEM_UART_TX_PIN
int "TXD Pin Number"
default 4
range 0 31
help
Pin number of UART TX.
config EXAMPLE_MODEM_UART_RX_PIN
int "RXD Pin Number"
default 5
range 0 31
help
Pin number of UART RX.
config EXAMPLE_MODEM_UART_EVENT_TASK_STACK_SIZE
int "UART Event Task Stack Size"
range 2000 6000
default 4096
help
Stack size of UART event task.
config EXAMPLE_MODEM_UART_EVENT_TASK_PRIORITY
int "UART Event Task Priority"
range 3 22
default 5
help
Priority of UART event task.
config EXAMPLE_MODEM_UART_EVENT_QUEUE_SIZE
int "UART Event Queue Size"
range 10 40
default 30
help
Length of UART event queue.
config EXAMPLE_MODEM_UART_TX_BUFFER_SIZE
int "UART TX Buffer Size"
range 256 2048
default 512
help
Buffer size of UART TX buffer.
config EXAMPLE_MODEM_UART_RX_BUFFER_SIZE
int "UART RX Buffer Size"
range 256 2048
default 1024
help
Buffer size of UART RX buffer.
endmenu
config EXAMPLE_MODEM_PWRKEY_PIN
int "PWRKEY Pin Number"
default 18
range 0 31
help
Pin number connected to modem's power key pin.
config EXAMPLE_MODEM_STATUS_PIN
int "STATUS Pin Number"
default 19
range 0 31
help
Pin number connected to modem's status pin.
config EXAMPLE_MODEM_LIGHT_SLEEP_DURATION
int "Light Sleep Duration"
default 10
range 0 15000
help
Duration in seconds, of which the esp32 goes into light sleep while the modem is awake.
config EXAMPLE_MODEM_PPP_APN
string "Set MODEM APN"
default "internet"
help
Set APN (Access Point Name), a logical name to choose data network
config EXAMPLE_MODEM_T3412_PERIODIC_TAU
string "T3412 Requester Periodic TAU"
default "00000100"
help
T3412 timer, i.e the duration of one awake and sleep cycle of the modem in PSM.
config EXAMPLE_MODEM_T3324_ACTIVE_TIME
string "T3324 Requester Active Time"
default "00000001"
help
T3324 timer, i.e the duration for which the modem stays PSM.
endmenu

View File

@ -0,0 +1,202 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
/*
* Power Saving Mode(PSM) in Sim70XX modems along with
* Deep sleep and Light Sleep modes in esp32.
*/
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_log.h"
#include "driver/uart.h"
#include "string.h"
#include "driver/gpio.h"
#include "esp_sleep.h"
#include "driver/rtc_io.h"
#include "esp_modem_api.h"
#include "esp_event.h"
#include "sdkconfig.h"
#define BUF_SIZE 1024
#define TXD_PIN ((gpio_num_t)CONFIG_EXAMPLE_MODEM_UART_TX_PIN)
#define RXD_PIN ((gpio_num_t)CONFIG_EXAMPLE_MODEM_UART_RX_PIN)
#define GPIO_INPUT_STATUS ((gpio_num_t)CONFIG_EXAMPLE_MODEM_STATUS_PIN)
#define GPIO_OUTPUT_PWRKEY ((gpio_num_t)CONFIG_EXAMPLE_MODEM_PWRKEY_PIN)
#define GPIO_OUTPUT_PIN_SEL (1ULL<<GPIO_OUTPUT_PWRKEY)
#define CHECK_ERR(cmd, success_action) do { \
esp_err_t ret = cmd; \
if (ret == ESP_OK) { \
success_action; \
} else { \
ESP_LOGE(TAG, "Failed with %s", ret == ESP_ERR_TIMEOUT ? "TIMEOUT":"ERROR"); \
} } while (0)
const char *TAG = "modem_psm";
RTC_DATA_ATTR static int boot_count = 0;
void dce_init(esp_modem_dce_t **dce, esp_netif_t **esp_netif)
{
esp_modem_dce_config_t dce_config = ESP_MODEM_DCE_DEFAULT_CONFIG(CONFIG_EXAMPLE_MODEM_PPP_APN);
esp_modem_dte_config_t dte_config = ESP_MODEM_DTE_DEFAULT_CONFIG();
esp_netif_config_t netif_ppp_config = ESP_NETIF_DEFAULT_PPP();
*esp_netif = esp_netif_new(&netif_ppp_config);
assert(*esp_netif);
/* setup UART specific configuration based on kconfig options */
dte_config.uart_config.tx_io_num = CONFIG_EXAMPLE_MODEM_UART_TX_PIN;
dte_config.uart_config.rx_io_num = CONFIG_EXAMPLE_MODEM_UART_RX_PIN;
dte_config.uart_config.rx_buffer_size = CONFIG_EXAMPLE_MODEM_UART_RX_BUFFER_SIZE;
dte_config.uart_config.tx_buffer_size = CONFIG_EXAMPLE_MODEM_UART_TX_BUFFER_SIZE;
dte_config.uart_config.event_queue_size = CONFIG_EXAMPLE_MODEM_UART_EVENT_QUEUE_SIZE;
dte_config.task_stack_size = CONFIG_EXAMPLE_MODEM_UART_EVENT_TASK_STACK_SIZE;
dte_config.task_priority = CONFIG_EXAMPLE_MODEM_UART_EVENT_TASK_PRIORITY;
dte_config.dte_buffer_size = CONFIG_EXAMPLE_MODEM_UART_RX_BUFFER_SIZE / 2;
ESP_LOGI(TAG, "Initializing esp_modem for a generic module...");
*dce = esp_modem_new(&dte_config, &dce_config, *esp_netif);
assert(*dce);
}
void config_pwrkey_gpio(void)
{
gpio_config_t io_conf = {}; //zero-initialize the config structure.
io_conf.intr_type = GPIO_INTR_DISABLE; //disable interrupt
io_conf.mode = GPIO_MODE_OUTPUT; //set as output mode
io_conf.pin_bit_mask = GPIO_OUTPUT_PIN_SEL; //bit mask of the pins that you want to set,e.g.GPIO18/19
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE; //disable pull-down mode
io_conf.pull_up_en = GPIO_PULLUP_DISABLE; //disable pull-up mode
gpio_config(&io_conf); //configure GPIO with the given settings
}
void power_on_modem(esp_modem_dce_t *dce)
{
rtc_gpio_hold_dis(GPIO_OUTPUT_PWRKEY);
/* Power on the modem */
ESP_LOGI(TAG, "Power on the modem");
gpio_set_level(GPIO_OUTPUT_PWRKEY, 1);
vTaskDelay(pdMS_TO_TICKS(500));
gpio_set_level(GPIO_OUTPUT_PWRKEY, 0);
rtc_gpio_hold_en(GPIO_OUTPUT_PWRKEY);
vTaskDelay(pdMS_TO_TICKS(2000));
CHECK_ERR(esp_modem_sync(dce), ESP_LOGI(TAG, "OK"));
}
void power_down_modem(esp_modem_dce_t *dce)
{
char data[BUF_SIZE];
ESP_LOGI(TAG, "Power down the modem");
/* Power down the modem by AT command */
CHECK_ERR(esp_modem_at(dce, "AT+CPOWD=1", data, 500), ESP_LOGI(TAG, "OK. %s", data));
}
void run_at(esp_modem_dce_t *dce, uint8_t count)
{
for (int i = 0; i < count; i++) {
CHECK_ERR(esp_modem_sync(dce), ESP_LOGI(TAG, "OK"));
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
void run_at_ping(esp_modem_dce_t *dce)
{
char data[BUF_SIZE];
int rssi, ber;
CHECK_ERR(esp_modem_get_signal_quality(dce, &rssi, &ber), ESP_LOGI(TAG, "OK. rssi=%d, ber=%d", rssi, ber));
vTaskDelay(pdMS_TO_TICKS(1000));
CHECK_ERR(esp_modem_at(dce, "AT+CPSMS?", data, 500), ESP_LOGI(TAG, "OK. %s", data));
vTaskDelay(pdMS_TO_TICKS(1000));
CHECK_ERR(esp_modem_at(dce, "AT+CPSI?", data, 500), ESP_LOGI(TAG, "OK. %s", data)); // Inquiring UE system information
CHECK_ERR(esp_modem_at(dce, "AT+CNACT=0,1", data, 500), ESP_LOGI(TAG, "OK. %s", data)); // Activate the APP network
CHECK_ERR(esp_modem_at(dce, "AT+SNPDPID=0", data, 500), ESP_LOGI(TAG, "OK. %s", data)); // Select PDP index for PING
CHECK_ERR(esp_modem_at(dce, "AT+SNPING4=\"8.8.8.8\",3,16,1000", data, 500), ESP_LOGI(TAG, "OK. %s", data)); // Send IPv4 PING
CHECK_ERR(esp_modem_at(dce, "AT+CNACT=0,0", data, 500), ESP_LOGI(TAG, "OK. %s", data)); // Deactivate the APP network
}
void app_main(void)
{
char *cmd;
char data[BUF_SIZE];
esp_modem_dce_t *dce = NULL;
esp_netif_t *esp_netif = NULL;
esp_sleep_wakeup_cause_t wakeup_cause = esp_sleep_get_wakeup_cause();
ESP_LOGI(TAG, "Deep sleep Wake Up Cause: %d\n", wakeup_cause);
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
dce_init(&dce, &esp_netif);
switch (wakeup_cause) {
case ESP_SLEEP_WAKEUP_UNDEFINED:
/* Power on the modem */
config_pwrkey_gpio();
power_on_modem(dce);
run_at(dce, 3);
/* Configure Power Saving Mode in the modem */
asprintf(&cmd, "AT+CPSMS=1,,,\"%s\",\"%s\"\r\n", CONFIG_EXAMPLE_MODEM_T3412_PERIODIC_TAU,
CONFIG_EXAMPLE_MODEM_T3324_ACTIVE_TIME);
CHECK_ERR(esp_modem_at(dce, cmd, data, 500), ESP_LOGI(TAG, "OK. %s", data));
free(cmd);
vTaskDelay(pdMS_TO_TICKS(1000));
/* Perform Communication tasks */
run_at_ping(dce);
vTaskDelay(pdMS_TO_TICKS(1000));
break;
case ESP_SLEEP_WAKEUP_EXT0:
run_at(dce, 3);
/* Perform Communication tasks */
run_at_ping(dce);
vTaskDelay(pdMS_TO_TICKS(1000));
break;
default:
ESP_LOGI(TAG, "Not a deep sleep reset: %d\n", wakeup_cause);
}
ESP_LOGI(TAG, "Light sleep before going to Deep sleep\n\n");
/* Enter light sleep mode as long as the modem is awake */
esp_sleep_enable_timer_wakeup(CONFIG_EXAMPLE_MODEM_LIGHT_SLEEP_DURATION * 1000000);
esp_light_sleep_start();
esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_TIMER); // Disabling timer before going to deep sleep.
wakeup_cause = esp_sleep_get_wakeup_cause();
ESP_LOGI(TAG, "Light sleep wakeup cause: %d\n", wakeup_cause);
/* DCE and netif clean-up */
/* In Deep-sleep mode, the CPUs, most of the RAM, and all digital peripherals are powered off.
* So dce and netif would be lost anyway if they are not explicitly destroyed.
* But since dce is also linked with UART communication with the modem it's better to exit gracefully before going to deep sleep.
*/
esp_modem_destroy(dce);
esp_netif_destroy(esp_netif);
/* Enable wakeup if status pin is high */
esp_sleep_enable_ext0_wakeup(GPIO_INPUT_STATUS, 1);
ESP_LOGI(TAG, "Entering deep sleep: %d\n", boot_count++);
esp_deep_sleep_start();
}

View File

@ -0,0 +1,4 @@
# This file was generated using idf.py save-defconfig. It can be edited manually.
# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration
#
CONFIG_LWIP_PPP_SUPPORT=y

View File

@ -184,4 +184,22 @@ menu "Example Configuration"
endmenu
config EXAMPLE_MQTT_BROKER_URI
string "MQTT Broker URL"
default "mqtt://mqtt.eclipseprojects.io"
help
URL of the mqtt broker which this example connects to.
config EXAMPLE_MQTT_TEST_TOPIC
string "MQTT topic to publish/subscribe"
default "/topic/esp-pppos"
help
MQTT topic, which we subscribe on and publish to.
config EXAMPLE_MQTT_TEST_DATA
string "MQTT data to publish/receive"
default "esp32-pppos"
help
MQTT data message, which we publish and expect to receive.
endmenu

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
@ -30,7 +30,6 @@
#define EXAMPLE_FLOW_CONTROL ESP_MODEM_FLOW_CONTROL_HW
#endif
#define BROKER_URL "mqtt://mqtt.eclipseprojects.io"
static const char *TAG = "pppos_example";
static EventGroupHandle_t event_group = NULL;
@ -68,7 +67,7 @@ static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_
switch ((esp_mqtt_event_id_t)event_id) {
case MQTT_EVENT_CONNECTED:
ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
msg_id = esp_mqtt_client_subscribe(client, "/topic/esp-pppos", 0);
msg_id = esp_mqtt_client_subscribe(client, CONFIG_EXAMPLE_MQTT_TEST_TOPIC, 0);
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
break;
case MQTT_EVENT_DISCONNECTED:
@ -76,7 +75,7 @@ static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_
break;
case MQTT_EVENT_SUBSCRIBED:
ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id);
msg_id = esp_mqtt_client_publish(client, "/topic/esp-pppos", "esp32-pppos", 0, 0, 0);
msg_id = esp_mqtt_client_publish(client, CONFIG_EXAMPLE_MQTT_TEST_TOPIC, CONFIG_EXAMPLE_MQTT_TEST_DATA, 0, 0, 0);
ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);
break;
case MQTT_EVENT_UNSUBSCRIBED:
@ -271,11 +270,11 @@ void app_main(void)
/* Config MQTT */
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
esp_mqtt_client_config_t mqtt_config = {
.broker.address.uri = BROKER_URL,
.broker.address.uri = CONFIG_EXAMPLE_MQTT_BROKER_URI,
};
#else
esp_mqtt_client_config_t mqtt_config = {
.uri = BROKER_URL,
.uri = CONFIG_EXAMPLE_MQTT_BROKER_URI,
};
#endif
esp_mqtt_client_handle_t mqtt_client = esp_mqtt_client_init(&mqtt_config);

View File

@ -0,0 +1,24 @@
# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Unlicense OR CC0-1.0
from __future__ import print_function, unicode_literals
def test_pppos_connect(dut):
"""
steps:
1. initializes connection with SIM800
2. checks we get an IP
3. checks for the MQTT events
4. checks that the client cleanly disconnects
"""
# Check the sequence of connecting, publishing, disconnecting
dut.expect('Modem Connect to PPP Server')
# Check for MQTT connection and the data event
dut.expect('MQTT_EVENT_CONNECTED')
dut.expect('MQTT_EVENT_DATA')
dut.expect('TOPIC=/ci/esp-modem/pppos-client')
dut.expect('DATA=esp32-pppos')
# Check that we have disconnected
dut.expect('User interrupted event')
# And can use commands again
dut.expect('IMSI=[0-9]+')

View File

@ -0,0 +1,15 @@
CONFIG_IDF_TARGET="esp32c3"
# Override some defaults to enable PPP
CONFIG_LWIP_PPP_SUPPORT=y
CONFIG_LWIP_PPP_NOTIFY_PHASE_SUPPORT=y
CONFIG_LWIP_PPP_PAP_SUPPORT=y
CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=4096
CONFIG_LWIP_PPP_ENABLE_IPV6=n
CONFIG_EXAMPLE_MODEM_UART_TX_PIN=4
CONFIG_EXAMPLE_MODEM_UART_RX_PIN=5
CONFIG_EXAMPLE_MODEM_DEVICE_SIM800=y
CONFIG_EXAMPLE_MODEM_DEVICE_BG96=n
CONFIG_EXAMPLE_MODEM_PPP_APN="lpwa.vodafone.com"
CONFIG_EXAMPLE_MQTT_TEST_TOPIC="/ci/esp-modem/pppos-client"
CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT=y
CONFIG_ESP32_PANIC_PRINT_HALT=y

View File

@ -0,0 +1,2 @@
CONFIG_IDF_TARGET="esp32s2"
CONFIG_EXAMPLE_SERIAL_CONFIG_USB=y

View File

@ -0,0 +1,2 @@
CONFIG_IDF_TARGET="esp32s3"
CONFIG_EXAMPLE_SERIAL_CONFIG_USB=y

View File

@ -2,7 +2,7 @@
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
set(EXTRA_COMPONENT_DIRS "../.." $ENV{IDF_PATH}/examples/cxx/experimental/experimental_cpp_component)
set(EXTRA_COMPONENT_DIRS "../..")
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(simple_cmux_client)

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
@ -17,10 +17,10 @@
#include "freertos/event_groups.h"
#include "esp_netif.h"
#include "esp_log.h"
#include "esp_event.h"
#include "cxx_include/esp_modem_dte.hpp"
#include "esp_modem_config.h"
#include "cxx_include/esp_modem_api.hpp"
#include "esp_event_cxx.hpp"
#include "simple_mqtt_client.hpp"
#include "esp_vfs_dev.h" // For optional VFS support
#include "esp_https_ota.h" // For potential OTA configuration
@ -39,16 +39,87 @@
using namespace esp_modem;
using namespace idf::event;
static const char *TAG = "cmux_example";
class StatusHandler {
public:
static constexpr auto IP_Event = SignalGroup::bit0;
static constexpr auto MQTT_Connect = SignalGroup::bit1;
static constexpr auto MQTT_Data = SignalGroup::bit2;
StatusHandler()
{
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, ESP_EVENT_ANY_ID, on_event, this));
}
~StatusHandler()
{
esp_event_handler_unregister(IP_EVENT, ESP_EVENT_ANY_ID, on_event);
}
void handle_mqtt(MqttClient *client)
{
mqtt_client = client;
client->register_handler(ESP_EVENT_ANY_ID, on_event, this);
}
esp_err_t wait_for(decltype(IP_Event) event, int milliseconds)
{
return signal.wait_any(event, milliseconds);
}
ip_event_t get_ip_event_type()
{
return ip_event_type;
}
private:
static void on_event(void *arg, esp_event_base_t base, int32_t event, void *data)
{
auto *handler = static_cast<StatusHandler *>(arg);
if (base == IP_EVENT) {
handler->ip_event(event, data);
} else {
handler->mqtt_event(event, data);
}
}
void ip_event(int32_t id, void *data)
{
if (id == IP_EVENT_PPP_GOT_IP) {
auto *event = (ip_event_got_ip_t *)data;
ESP_LOGI(TAG, "IP : " IPSTR, IP2STR(&event->ip_info.ip));
ESP_LOGI(TAG, "Netmask : " IPSTR, IP2STR(&event->ip_info.netmask));
ESP_LOGI(TAG, "Gateway : " IPSTR, IP2STR(&event->ip_info.gw));
signal.set(IP_Event);
} else if (id == IP_EVENT_PPP_LOST_IP) {
signal.set(IP_Event);
}
ip_event_type = static_cast<ip_event_t>(id);
}
void mqtt_event(int32_t event, void *data)
{
if (mqtt_client && event == mqtt_client->get_event(MqttClient::Event::CONNECT)) {
signal.set(MQTT_Connect);
} else if (mqtt_client && event == mqtt_client->get_event(MqttClient::Event::DATA)) {
ESP_LOGI(TAG, " TOPIC: %s", mqtt_client->get_topic(data).c_str());
ESP_LOGI(TAG, " DATA: %s", mqtt_client->get_data(data).c_str());
signal.set(MQTT_Data);
}
}
esp_modem::SignalGroup signal{};
MqttClient *mqtt_client{nullptr};
ip_event_t ip_event_type;
};
extern "C" void app_main(void)
{
/* Init and register system/core components */
auto loop = std::make_shared<ESPEventLoop>();
ESP_ERROR_CHECK(esp_event_loop_create_default());
ESP_ERROR_CHECK(esp_netif_init());
/* Configure and create the DTE */
@ -145,45 +216,32 @@ extern "C" void app_main(void)
#endif
/* Try to connect to the network and publish an mqtt topic */
ESPEventHandlerSync event_handler(loop);
event_handler.listen_to(ESPEvent(IP_EVENT, ESPEventID(ESP_EVENT_ANY_ID)));
auto result = event_handler.wait_event_for(std::chrono::milliseconds(60000));
if (result.timeout) {
StatusHandler handler;
if (!handler.wait_for(StatusHandler::IP_Event, 60000)) {
ESP_LOGE(TAG, "Cannot get IP within specified timeout... exiting");
return;
} else if (result.event.id == ESPEventID(IP_EVENT_PPP_GOT_IP)) {
auto *event = (ip_event_got_ip_t *)result.ev_data;
ESP_LOGI(TAG, "IP : " IPSTR, IP2STR(&event->ip_info.ip));
ESP_LOGI(TAG, "Netmask : " IPSTR, IP2STR(&event->ip_info.netmask));
ESP_LOGI(TAG, "Gateway : " IPSTR, IP2STR(&event->ip_info.gw));
} else if (handler.get_ip_event_type() == IP_EVENT_PPP_GOT_IP) {
std::cout << "Got IP address" << std::endl;
/* When connected to network, subscribe and publish some MQTT data */
MqttClient mqtt(BROKER_URL);
event_handler.listen_to(MqttClient::get_event(MqttClient::Event::CONNECT));
event_handler.listen_to(MqttClient::get_event(MqttClient::Event::DATA));
auto reg = loop->register_event(MqttClient::get_event(MqttClient::Event::DATA),
[&mqtt](const ESPEvent & event, void *data) {
std::cout << " TOPIC:" << mqtt.get_topic(data) << std::endl;
std::cout << " DATA:" << mqtt.get_data(data) << std::endl;
});
handler.handle_mqtt(&mqtt);
mqtt.connect();
while (true) {
result = event_handler.wait_event_for(std::chrono::milliseconds(60000));
if (result.event == MqttClient::get_event(MqttClient::Event::CONNECT)) {
mqtt.subscribe("/topic/esp-modem");
mqtt.publish("/topic/esp-modem", "Hello modem");
continue;
} else if (result.event == MqttClient::get_event(MqttClient::Event::DATA)) {
std::cout << "Data received" << std::endl;
break; /* Continue with CMUX example after getting data from MQTT */
} else {
break;
}
if (!handler.wait_for(StatusHandler::MQTT_Connect, 60000)) {
ESP_LOGE(TAG, "Cannot connect to %s within specified timeout... exiting", BROKER_URL);
return;
}
std::cout << "Connected" << std::endl;
} else if (result.event.id == ESPEventID(IP_EVENT_PPP_LOST_IP)) {
mqtt.subscribe("/topic/esp-modem");
mqtt.publish("/topic/esp-modem", "Hello modem");
if (!handler.wait_for(StatusHandler::MQTT_Data, 60000)) {
ESP_LOGE(TAG, "Didn't receive published data within specified timeout... exiting");
return;
}
std::cout << "Received MQTT data" << std::endl;
} else if (handler.get_ip_event_type() == IP_EVENT_PPP_LOST_IP) {
ESP_LOGE(TAG, "PPP client has lost connection... exiting");
return;
}

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
@ -10,11 +10,8 @@
#include <memory>
#include "mqtt_client.h"
#include "esp_event_cxx.hpp"
#include "simple_mqtt_client.hpp"
using namespace idf::event;
/**
* Reference to the MQTT event base
*/
@ -33,7 +30,6 @@ struct MqttClientHandle {
config.uri = uri.c_str();
#endif
client = esp_mqtt_client_init(&config);
esp_mqtt_client_register_event(client, MQTT_EVENT_ANY, mqtt_event_handler, this);
}
~MqttClientHandle()
@ -41,12 +37,6 @@ struct MqttClientHandle {
esp_mqtt_client_destroy(client);
}
static void mqtt_event_handler(void *args, esp_event_base_t base, int32_t id, void *data)
{
// forwards the internal event to the global ESPEvent
esp_event_post(base, id, data, sizeof(esp_mqtt_event_t), portMAX_DELAY);
}
esp_mqtt_client_handle_t client;
};
@ -62,16 +52,16 @@ void MqttClient::connect()
esp_mqtt_client_start(h->client);
}
idf::event::ESPEvent MqttClient::get_event(MqttClient::Event ev)
int32_t MqttClient::get_event(MqttClient::Event ev)
{
switch (ev) {
case Event::CONNECT: {
return { MQTT_EVENTS, ESPEventID(MQTT_EVENT_CONNECTED) };
return MQTT_EVENT_CONNECTED;
}
case Event::DATA:
return { MQTT_EVENTS, ESPEventID(MQTT_EVENT_DATA) };
return MQTT_EVENT_DATA;
}
return { };
return -1;
}
int MqttClient::publish(const std::string &topic, const std::string &data, int qos)
@ -102,4 +92,9 @@ std::string MqttClient::get_data(void *event_data)
return std::string(event->data, event->data_len);
}
void MqttClient::register_handler(int32_t event_id, esp_event_handler_t event_handler, void *arg)
{
ESP_ERROR_CHECK(esp_mqtt_client_register_event(h->client, MQTT_EVENT_ANY, event_handler, arg));
}
MqttClient::~MqttClient() = default;

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
@ -11,7 +11,6 @@
#include <string>
#include <memory>
#include "esp_event_cxx.hpp"
struct MqttClientHandle;
@ -62,12 +61,20 @@ public:
*/
std::string get_data(void *);
/**
* @brief Register MQTT event
* @param id Event id
* @param event_handler Event handler
* @param event_handler_arg Event handler parameters
*/
void register_handler(int32_t id, esp_event_handler_t event_handler, void *event_handler_arg);
/**
* @brief Convert internal MQTT event to standard ESPEvent
* @param ev internal mqtt event
* @return corresponding ESPEvent
* @return corresponding esp_event id
*/
static idf::event::ESPEvent get_event(Event ev);
static int32_t get_event(Event ev);
private:
std::unique_ptr<MqttClientHandle> h;

View File

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

View File

@ -39,9 +39,12 @@ public:
* @brief Creates a DTE instance from the terminal
* @param config DTE config structure
* @param t unique-ptr to Terminal
* @param s unique-ptr to secondary Terminal
*/
explicit DTE(const esp_modem_dte_config *config, std::unique_ptr<Terminal> t);
explicit DTE(std::unique_ptr<Terminal> t);
explicit DTE(const esp_modem_dte_config *config, std::unique_ptr<Terminal> t, std::unique_ptr<Terminal> s);
explicit DTE(std::unique_ptr<Terminal> t, std::unique_ptr<Terminal> s);
~DTE() = default;
@ -116,8 +119,8 @@ private:
Lock internal_lock{}; /*!< Locks DTE operations */
unique_buffer buffer; /*!< DTE buffer */
std::shared_ptr<CMux> cmux_term; /*!< Primary terminal for this DTE */
std::shared_ptr<Terminal> command_term; /*!< Reference to the terminal used for sending commands */
std::shared_ptr<Terminal> data_term; /*!< Secondary terminal for this DTE */
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 */

View File

@ -27,10 +27,16 @@ namespace esp_modem {
*/
enum class modem_mode {
UNDEF,
COMMAND_MODE, /*!< Command mode -- the modem is supposed to send AT commands in this mode */
COMMAND_MODE, /*!< Command mode -- the modem is supposed to send AT commands in this mode */
DATA_MODE, /*!< Data mode -- the modem communicates with network interface on PPP protocol */
CMUX_MODE /*!< CMUX (Multiplex mode) -- Simplified CMUX mode, which creates two virtual terminals,
DUAL_MODE, /*!< Dual mode -- the modem has two real terminals. Data and commands work at the same time */
CMUX_MODE, /*!< CMUX (Multiplex mode) -- Simplified CMUX mode, which creates two virtual terminals,
* assigning one solely to command interface and the other to the data mode */
CMUX_MANUAL_MODE, /*!< Enter CMUX mode manually -- just creates two virtual terminals */
CMUX_MANUAL_EXIT, /*!< Exits CMUX mode manually -- just destroys two virtual terminals */
CMUX_MANUAL_DATA, /*!< Sets the primary terminal to DATA mode in manual CMUX */
CMUX_MANUAL_COMMAND, /*!< Sets the primary terminal to COMMAND mode in manual CMUX */
CMUX_MANUAL_SWAP, /*!< Swaps virtual terminals in manual CMUX mode (primary <-> secondary) */
};
/**

View File

@ -36,6 +36,11 @@ typedef enum esp_modem_dce_mode {
ESP_MODEM_MODE_COMMAND, /**< Default mode after modem startup, used for sending AT commands */
ESP_MODEM_MODE_DATA, /**< Used for switching to PPP mode for the modem to connect to a network */
ESP_MODEM_MODE_CMUX, /**< Multiplexed terminal mode */
ESP_MODEM_MODE_CMUX_MANUAL, /**< CMUX manual mode */
ESP_MODEM_MODE_CMUX_MANUAL_EXIT, /**< Exit CMUX manual mode */
ESP_MODEM_MODE_CMUX_MANUAL_SWAP, /**< Swap terminals in CMUX manual mode */
ESP_MODEM_MODE_CMUX_MANUAL_DATA, /**< Set DATA mode in CMUX manual mode */
ESP_MODEM_MODE_CMUX_MANUAL_COMMAND, /**< Set COMMAND mode in CMUX manual mode */
} esp_modem_dce_mode_t;
/**
@ -113,6 +118,8 @@ esp_err_t esp_modem_set_error_cb(esp_modem_dce_t *dce, esp_modem_terminal_error_
*/
esp_err_t esp_modem_set_mode(esp_modem_dce_t *dce, esp_modem_dce_mode_t mode);
esp_err_t esp_modem_command(esp_modem_dce_t *dce, const char *command, esp_err_t(*got_line_cb)(uint8_t *data, size_t len), uint32_t timeout_ms);
/**
* @}
*/

View File

@ -84,6 +84,11 @@ struct esp_modem_dte_config {
};
};
#if ESP_IDF_VERSION_MAJOR >= 5
#define ESP_MODEM_DEFAULT_UART_CLK UART_SCLK_DEFAULT
#else
#define ESP_MODEM_DEFAULT_UART_CLK UART_SCLK_APB
#endif
/**
* @brief ESP Modem DTE Default Configuration
@ -92,15 +97,15 @@ struct esp_modem_dte_config {
#define ESP_MODEM_DTE_DEFAULT_CONFIG() \
{ \
.dte_buffer_size = 512, \
.task_stack_size = 4096, \
.task_priority = 5, \
.task_stack_size = 4096, \
.task_priority = 5, \
.uart_config = { \
.port_num = UART_NUM_1, \
.data_bits = UART_DATA_8_BITS, \
.stop_bits = UART_STOP_BITS_1, \
.parity = UART_PARITY_DISABLE, \
.flow_control = ESP_MODEM_FLOW_CONTROL_NONE,\
.source_clk = UART_SCLK_APB, \
.source_clk = ESP_MODEM_DEFAULT_UART_CLK, \
.baud_rate = 115200, \
.tx_io_num = 25, \
.rx_io_num = 26, \

View File

@ -1,393 +1,425 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <cassert>
#include "cxx_include/esp_modem_dte.hpp"
#include "uart_terminal.hpp"
#include "esp_log.h"
#include "cxx_include/esp_modem_api.hpp"
#include "cxx_include/esp_modem_dce_factory.hpp"
#include "esp_modem_c_api_types.h"
#include "esp_modem_config.h"
#include "exception_stub.hpp"
#include "esp_private/c_api_wrapper.hpp"
#include "cstring"
#ifndef ESP_MODEM_C_API_STR_MAX
#define ESP_MODEM_C_API_STR_MAX 64
#endif
#ifndef HAVE_STRLCPY
size_t strlcpy(char *dest, const char *src, size_t len);
#endif
//
// C API definitions
using namespace esp_modem;
extern "C" esp_modem_dce_t *esp_modem_new_dev(esp_modem_dce_device_t module, const esp_modem_dte_config_t *dte_config, const esp_modem_dce_config_t *dce_config, esp_netif_t *netif)
{
auto dce_wrap = new (std::nothrow) esp_modem_dce_wrap;
if (dce_wrap == nullptr) {
return nullptr;
}
auto dte = create_uart_dte(dte_config);
if (dte == nullptr) {
delete dce_wrap;
return nullptr;
}
dce_wrap->dte = dte;
dce_factory::Factory f(convert_modem_enum(module));
dce_wrap->dce = f.build(dce_config, std::move(dte), netif);
if (dce_wrap->dce == nullptr) {
delete dce_wrap;
return nullptr;
}
dce_wrap->modem_type = convert_modem_enum(module);
dce_wrap->dte_type = esp_modem_dce_wrap::modem_wrap_dte_type::UART;
return dce_wrap;
}
extern "C" esp_modem_dce_t *esp_modem_new(const esp_modem_dte_config_t *dte_config, const esp_modem_dce_config_t *dce_config, esp_netif_t *netif)
{
return esp_modem_new_dev(ESP_MODEM_DCE_GENETIC, dte_config, dce_config, netif);
}
extern "C" void esp_modem_destroy(esp_modem_dce_t *dce_wrap)
{
if (dce_wrap) {
delete dce_wrap->dce;
delete dce_wrap;
}
}
extern "C" esp_err_t esp_modem_set_error_cb(esp_modem_dce_t *dce_wrap, esp_modem_terminal_error_cbt err_cb)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr || dce_wrap->dte == nullptr) {
return ESP_ERR_INVALID_ARG;
}
if (err_cb) {
dce_wrap->dte->set_error_cb([err_cb](terminal_error err) {
err_cb(convert_terminal_error_enum(err));
});
} else {
dce_wrap->dte->set_error_cb(nullptr);
}
return ESP_OK;
}
extern "C" esp_err_t esp_modem_sync(esp_modem_dce_t *dce_wrap)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
return command_response_to_esp_err(dce_wrap->dce->sync());
}
extern "C" esp_err_t esp_modem_set_mode(esp_modem_dce_t *dce_wrap, esp_modem_dce_mode_t mode)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
if (mode == ESP_MODEM_MODE_DATA) {
return dce_wrap->dce->set_mode(modem_mode::DATA_MODE) ? ESP_OK : ESP_FAIL;
}
if (mode == ESP_MODEM_MODE_COMMAND) {
return dce_wrap->dce->set_mode(modem_mode::COMMAND_MODE) ? ESP_OK : ESP_FAIL;
}
if (mode == ESP_MODEM_MODE_CMUX) {
return dce_wrap->dce->set_mode(modem_mode::CMUX_MODE) ? ESP_OK : ESP_FAIL;
}
return ESP_ERR_NOT_SUPPORTED;
}
extern "C" esp_err_t esp_modem_read_pin(esp_modem_dce_t *dce_wrap, bool *pin)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
return command_response_to_esp_err(dce_wrap->dce->read_pin(*pin));
}
extern "C" esp_err_t esp_modem_sms_txt_mode(esp_modem_dce_t *dce_wrap, bool txt)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
return command_response_to_esp_err(dce_wrap->dce->sms_txt_mode(txt));
}
extern "C" esp_err_t esp_modem_send_sms(esp_modem_dce_t *dce_wrap, const char *number, const char *message)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
std::string number_str(number);
std::string message_str(message);
return command_response_to_esp_err(dce_wrap->dce->send_sms(number_str, message_str));
}
extern "C" esp_err_t esp_modem_sms_character_set(esp_modem_dce_t *dce_wrap)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
return command_response_to_esp_err(dce_wrap->dce->sms_character_set());
}
extern "C" esp_err_t esp_modem_set_pin(esp_modem_dce_t *dce_wrap, const char *pin)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
std::string pin_str(pin);
return command_response_to_esp_err(dce_wrap->dce->set_pin(pin_str));
}
extern "C" esp_err_t esp_modem_at(esp_modem_dce_t *dce_wrap, const char *at, char *p_out, int timeout)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
std::string out;
std::string at_str(at);
auto ret = command_response_to_esp_err(dce_wrap->dce->at(at_str, out, timeout));
if ((p_out != NULL) && (!out.empty())) {
strlcpy(p_out, out.c_str(), ESP_MODEM_C_API_STR_MAX);
}
return ret;
}
extern "C" esp_err_t esp_modem_get_signal_quality(esp_modem_dce_t *dce_wrap, int *rssi, int *ber)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
return command_response_to_esp_err(dce_wrap->dce->get_signal_quality(*rssi, *ber));
}
extern "C" esp_err_t esp_modem_get_imsi(esp_modem_dce_t *dce_wrap, char *p_imsi)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
std::string imsi;
auto ret = command_response_to_esp_err(dce_wrap->dce->get_imsi(imsi));
if (ret == ESP_OK && !imsi.empty()) {
strlcpy(p_imsi, imsi.c_str(), ESP_MODEM_C_API_STR_MAX);
}
return ret;
}
extern "C" esp_err_t esp_modem_set_flow_control(esp_modem_dce_t *dce_wrap, int dce_flow, int dte_flow)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
return command_response_to_esp_err(dce_wrap->dce->set_flow_control(dce_flow, dte_flow));
}
extern "C" esp_err_t esp_modem_store_profile(esp_modem_dce_t *dce_wrap)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
return command_response_to_esp_err(dce_wrap->dce->store_profile());
}
extern "C" esp_err_t esp_modem_get_imei(esp_modem_dce_t *dce_wrap, char *p_imei)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
std::string imei;
auto ret = command_response_to_esp_err(dce_wrap->dce->get_imei(imei));
if (ret == ESP_OK && !imei.empty()) {
strlcpy(p_imei, imei.c_str(), ESP_MODEM_C_API_STR_MAX);
}
return ret;
}
extern "C" esp_err_t esp_modem_get_operator_name(esp_modem_dce_t *dce_wrap, char *p_name, int *p_act)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr || p_name == nullptr || p_act == nullptr) {
return ESP_ERR_INVALID_ARG;
}
std::string name;
int act;
auto ret = command_response_to_esp_err(dce_wrap->dce->get_operator_name(name, act));
if (ret == ESP_OK && !name.empty()) {
strlcpy(p_name, name.c_str(), ESP_MODEM_C_API_STR_MAX);
*p_act = act;
}
return ret;
}
extern "C" esp_err_t esp_modem_get_module_name(esp_modem_dce_t *dce_wrap, char *p_name)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
std::string name;
auto ret = command_response_to_esp_err(dce_wrap->dce->get_module_name(name));
if (ret == ESP_OK && !name.empty()) {
strlcpy(p_name, name.c_str(), ESP_MODEM_C_API_STR_MAX);
}
return ret;
}
extern "C" esp_err_t esp_modem_get_battery_status(esp_modem_dce_t *dce_wrap, int *p_volt, int *p_bcs, int *p_bcl)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr || p_bcs == nullptr || p_bcl == nullptr || p_volt == nullptr) {
return ESP_ERR_INVALID_ARG;
}
int bcs, bcl, volt;
auto ret = command_response_to_esp_err(dce_wrap->dce->get_battery_status(volt, bcs, bcl));
if (ret == ESP_OK) {
*p_volt = volt;
*p_bcs = bcs;
*p_bcl = bcl;
}
return ret;
}
extern "C" esp_err_t esp_modem_power_down(esp_modem_dce_t *dce_wrap)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
return command_response_to_esp_err(dce_wrap->dce->power_down());
}
extern "C" esp_err_t esp_modem_set_operator(esp_modem_dce_t *dce_wrap, int mode, int format, const char *oper)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
std::string operator_str(oper);
return command_response_to_esp_err(dce_wrap->dce->set_operator(mode, format, operator_str));
}
extern "C" esp_err_t esp_modem_set_network_attachment_state(esp_modem_dce_t *dce_wrap, int state)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
return command_response_to_esp_err(dce_wrap->dce->set_network_attachment_state(state));
}
extern "C" esp_err_t esp_modem_get_network_attachment_state(esp_modem_dce_t *dce_wrap, int *p_state)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
int state;
auto ret = command_response_to_esp_err(dce_wrap->dce->get_network_attachment_state(state));
if (ret == ESP_OK) {
*p_state = state;
}
return ret;
}
extern "C" esp_err_t esp_modem_set_radio_state(esp_modem_dce_t *dce_wrap, int state)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
return command_response_to_esp_err(dce_wrap->dce->set_radio_state(state));
}
extern "C" esp_err_t esp_modem_get_radio_state(esp_modem_dce_t *dce_wrap, int *p_state)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
int state;
auto ret = command_response_to_esp_err(dce_wrap->dce->get_radio_state(state));
if (ret == ESP_OK) {
*p_state = state;
}
return ret;
}
extern "C" esp_err_t esp_modem_set_network_mode(esp_modem_dce_t *dce_wrap, int mode)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
return command_response_to_esp_err(dce_wrap->dce->set_network_mode(mode));
}
extern "C" esp_err_t esp_modem_set_preferred_mode(esp_modem_dce_t *dce_wrap, int mode)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
return command_response_to_esp_err(dce_wrap->dce->set_preferred_mode(mode));
}
extern "C" esp_err_t esp_modem_set_network_bands(esp_modem_dce_t *dce_wrap, const char *mode, const int *bands, int size)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
std::string mode_str(mode);
return command_response_to_esp_err(dce_wrap->dce->set_network_bands(mode, bands, size));
}
extern "C" esp_err_t esp_modem_get_network_system_mode(esp_modem_dce_t *dce_wrap, int *p_mode)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
int mode;
auto ret = command_response_to_esp_err(dce_wrap->dce->get_network_system_mode(mode));
if (ret == ESP_OK) {
*p_mode = mode;
}
return ret;
}
extern "C" esp_err_t esp_modem_set_gnss_power_mode(esp_modem_dce_t *dce_wrap, int mode)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
return command_response_to_esp_err(dce_wrap->dce->set_gnss_power_mode(mode));
}
extern "C" esp_err_t esp_modem_get_gnss_power_mode(esp_modem_dce_t *dce_wrap, int *p_mode)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
int mode;
auto ret = command_response_to_esp_err(dce_wrap->dce->get_gnss_power_mode(mode));
if (ret == ESP_OK) {
*p_mode = mode;
}
return ret;
}
extern "C" esp_err_t esp_modem_reset(esp_modem_dce_t *dce_wrap)
{
return command_response_to_esp_err(dce_wrap->dce->reset());
}
extern "C" esp_err_t esp_modem_set_pdp_context(esp_modem_dce_t *dce_wrap, esp_modem_PdpContext_t *c_api_pdp)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
esp_modem::PdpContext pdp{c_api_pdp->apn};
pdp.context_id = c_api_pdp->context_id;
pdp.protocol_type = c_api_pdp->protocol_type;
return command_response_to_esp_err(dce_wrap->dce->set_pdp_context(pdp));
}
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <cassert>
#include "cxx_include/esp_modem_dte.hpp"
#include "uart_terminal.hpp"
#include "esp_log.h"
#include "cxx_include/esp_modem_api.hpp"
#include "cxx_include/esp_modem_dce_factory.hpp"
#include "esp_modem_c_api_types.h"
#include "esp_modem_config.h"
#include "exception_stub.hpp"
#include "esp_private/c_api_wrapper.hpp"
#include "cstring"
#ifndef ESP_MODEM_C_API_STR_MAX
#define ESP_MODEM_C_API_STR_MAX 64
#endif
#ifndef HAVE_STRLCPY
size_t strlcpy(char *dest, const char *src, size_t len);
#endif
//
// C API definitions
using namespace esp_modem;
extern "C" esp_modem_dce_t *esp_modem_new_dev(esp_modem_dce_device_t module, const esp_modem_dte_config_t *dte_config, const esp_modem_dce_config_t *dce_config, esp_netif_t *netif)
{
auto dce_wrap = new (std::nothrow) esp_modem_dce_wrap;
if (dce_wrap == nullptr) {
return nullptr;
}
auto dte = create_uart_dte(dte_config);
if (dte == nullptr) {
delete dce_wrap;
return nullptr;
}
dce_wrap->dte = dte;
dce_factory::Factory f(convert_modem_enum(module));
dce_wrap->dce = f.build(dce_config, std::move(dte), netif);
if (dce_wrap->dce == nullptr) {
delete dce_wrap;
return nullptr;
}
dce_wrap->modem_type = convert_modem_enum(module);
dce_wrap->dte_type = esp_modem_dce_wrap::modem_wrap_dte_type::UART;
return dce_wrap;
}
extern "C" esp_modem_dce_t *esp_modem_new(const esp_modem_dte_config_t *dte_config, const esp_modem_dce_config_t *dce_config, esp_netif_t *netif)
{
return esp_modem_new_dev(ESP_MODEM_DCE_GENETIC, dte_config, dce_config, netif);
}
extern "C" void esp_modem_destroy(esp_modem_dce_t *dce_wrap)
{
if (dce_wrap) {
delete dce_wrap->dce;
delete dce_wrap;
}
}
extern "C" esp_err_t esp_modem_set_error_cb(esp_modem_dce_t *dce_wrap, esp_modem_terminal_error_cbt err_cb)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr || dce_wrap->dte == nullptr) {
return ESP_ERR_INVALID_ARG;
}
if (err_cb) {
dce_wrap->dte->set_error_cb([err_cb](terminal_error err) {
err_cb(convert_terminal_error_enum(err));
});
} else {
dce_wrap->dte->set_error_cb(nullptr);
}
return ESP_OK;
}
extern "C" esp_err_t esp_modem_sync(esp_modem_dce_t *dce_wrap)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
return command_response_to_esp_err(dce_wrap->dce->sync());
}
extern "C" esp_err_t esp_modem_set_mode(esp_modem_dce_t *dce_wrap, esp_modem_dce_mode_t mode)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
switch (mode) {
case ESP_MODEM_MODE_DATA:
return dce_wrap->dce->set_mode(modem_mode::DATA_MODE) ? ESP_OK : ESP_FAIL;
case ESP_MODEM_MODE_COMMAND:
return dce_wrap->dce->set_mode(modem_mode::COMMAND_MODE) ? ESP_OK : ESP_FAIL;
case ESP_MODEM_MODE_CMUX:
return dce_wrap->dce->set_mode(modem_mode::CMUX_MODE) ? ESP_OK : ESP_FAIL;
case ESP_MODEM_MODE_CMUX_MANUAL:
return dce_wrap->dce->set_mode(modem_mode::CMUX_MANUAL_MODE) ? ESP_OK : ESP_FAIL;
case ESP_MODEM_MODE_CMUX_MANUAL_EXIT:
return dce_wrap->dce->set_mode(modem_mode::CMUX_MANUAL_EXIT) ? ESP_OK : ESP_FAIL;
case ESP_MODEM_MODE_CMUX_MANUAL_SWAP:
return dce_wrap->dce->set_mode(modem_mode::CMUX_MANUAL_SWAP) ? ESP_OK : ESP_FAIL;
case ESP_MODEM_MODE_CMUX_MANUAL_DATA:
return dce_wrap->dce->set_mode(modem_mode::CMUX_MANUAL_DATA) ? ESP_OK : ESP_FAIL;
case ESP_MODEM_MODE_CMUX_MANUAL_COMMAND:
return dce_wrap->dce->set_mode(modem_mode::CMUX_MANUAL_COMMAND) ? ESP_OK : ESP_FAIL;
}
return ESP_ERR_NOT_SUPPORTED;
}
extern "C" esp_err_t esp_modem_read_pin(esp_modem_dce_t *dce_wrap, bool *pin)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
return command_response_to_esp_err(dce_wrap->dce->read_pin(*pin));
}
extern "C" esp_err_t esp_modem_sms_txt_mode(esp_modem_dce_t *dce_wrap, bool txt)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
return command_response_to_esp_err(dce_wrap->dce->sms_txt_mode(txt));
}
extern "C" esp_err_t esp_modem_send_sms(esp_modem_dce_t *dce_wrap, const char *number, const char *message)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
std::string number_str(number);
std::string message_str(message);
return command_response_to_esp_err(dce_wrap->dce->send_sms(number_str, message_str));
}
extern "C" esp_err_t esp_modem_sms_character_set(esp_modem_dce_t *dce_wrap)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
return command_response_to_esp_err(dce_wrap->dce->sms_character_set());
}
extern "C" esp_err_t esp_modem_set_pin(esp_modem_dce_t *dce_wrap, const char *pin)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
std::string pin_str(pin);
return command_response_to_esp_err(dce_wrap->dce->set_pin(pin_str));
}
extern "C" esp_err_t esp_modem_at(esp_modem_dce_t *dce_wrap, const char *at, char *p_out, int timeout)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
std::string out;
std::string at_str(at);
auto ret = command_response_to_esp_err(dce_wrap->dce->at(at_str, out, timeout));
if ((p_out != NULL) && (!out.empty())) {
strlcpy(p_out, out.c_str(), ESP_MODEM_C_API_STR_MAX);
}
return ret;
}
extern "C" esp_err_t esp_modem_get_signal_quality(esp_modem_dce_t *dce_wrap, int *rssi, int *ber)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
return command_response_to_esp_err(dce_wrap->dce->get_signal_quality(*rssi, *ber));
}
extern "C" esp_err_t esp_modem_get_imsi(esp_modem_dce_t *dce_wrap, char *p_imsi)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
std::string imsi;
auto ret = command_response_to_esp_err(dce_wrap->dce->get_imsi(imsi));
if (ret == ESP_OK && !imsi.empty()) {
strlcpy(p_imsi, imsi.c_str(), ESP_MODEM_C_API_STR_MAX);
}
return ret;
}
extern "C" esp_err_t esp_modem_set_flow_control(esp_modem_dce_t *dce_wrap, int dce_flow, int dte_flow)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
return command_response_to_esp_err(dce_wrap->dce->set_flow_control(dce_flow, dte_flow));
}
extern "C" esp_err_t esp_modem_store_profile(esp_modem_dce_t *dce_wrap)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
return command_response_to_esp_err(dce_wrap->dce->store_profile());
}
extern "C" esp_err_t esp_modem_get_imei(esp_modem_dce_t *dce_wrap, char *p_imei)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
std::string imei;
auto ret = command_response_to_esp_err(dce_wrap->dce->get_imei(imei));
if (ret == ESP_OK && !imei.empty()) {
strlcpy(p_imei, imei.c_str(), ESP_MODEM_C_API_STR_MAX);
}
return ret;
}
extern "C" esp_err_t esp_modem_get_operator_name(esp_modem_dce_t *dce_wrap, char *p_name, int *p_act)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr || p_name == nullptr || p_act == nullptr) {
return ESP_ERR_INVALID_ARG;
}
std::string name;
int act;
auto ret = command_response_to_esp_err(dce_wrap->dce->get_operator_name(name, act));
if (ret == ESP_OK && !name.empty()) {
strlcpy(p_name, name.c_str(), ESP_MODEM_C_API_STR_MAX);
*p_act = act;
}
return ret;
}
extern "C" esp_err_t esp_modem_get_module_name(esp_modem_dce_t *dce_wrap, char *p_name)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
std::string name;
auto ret = command_response_to_esp_err(dce_wrap->dce->get_module_name(name));
if (ret == ESP_OK && !name.empty()) {
strlcpy(p_name, name.c_str(), ESP_MODEM_C_API_STR_MAX);
}
return ret;
}
extern "C" esp_err_t esp_modem_get_battery_status(esp_modem_dce_t *dce_wrap, int *p_volt, int *p_bcs, int *p_bcl)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr || p_bcs == nullptr || p_bcl == nullptr || p_volt == nullptr) {
return ESP_ERR_INVALID_ARG;
}
int bcs, bcl, volt;
auto ret = command_response_to_esp_err(dce_wrap->dce->get_battery_status(volt, bcs, bcl));
if (ret == ESP_OK) {
*p_volt = volt;
*p_bcs = bcs;
*p_bcl = bcl;
}
return ret;
}
extern "C" esp_err_t esp_modem_power_down(esp_modem_dce_t *dce_wrap)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
return command_response_to_esp_err(dce_wrap->dce->power_down());
}
extern "C" esp_err_t esp_modem_set_operator(esp_modem_dce_t *dce_wrap, int mode, int format, const char *oper)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
std::string operator_str(oper);
return command_response_to_esp_err(dce_wrap->dce->set_operator(mode, format, operator_str));
}
extern "C" esp_err_t esp_modem_set_network_attachment_state(esp_modem_dce_t *dce_wrap, int state)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
return command_response_to_esp_err(dce_wrap->dce->set_network_attachment_state(state));
}
extern "C" esp_err_t esp_modem_get_network_attachment_state(esp_modem_dce_t *dce_wrap, int *p_state)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
int state;
auto ret = command_response_to_esp_err(dce_wrap->dce->get_network_attachment_state(state));
if (ret == ESP_OK) {
*p_state = state;
}
return ret;
}
extern "C" esp_err_t esp_modem_set_radio_state(esp_modem_dce_t *dce_wrap, int state)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
return command_response_to_esp_err(dce_wrap->dce->set_radio_state(state));
}
extern "C" esp_err_t esp_modem_get_radio_state(esp_modem_dce_t *dce_wrap, int *p_state)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
int state;
auto ret = command_response_to_esp_err(dce_wrap->dce->get_radio_state(state));
if (ret == ESP_OK) {
*p_state = state;
}
return ret;
}
extern "C" esp_err_t esp_modem_set_network_mode(esp_modem_dce_t *dce_wrap, int mode)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
return command_response_to_esp_err(dce_wrap->dce->set_network_mode(mode));
}
extern "C" esp_err_t esp_modem_set_preferred_mode(esp_modem_dce_t *dce_wrap, int mode)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
return command_response_to_esp_err(dce_wrap->dce->set_preferred_mode(mode));
}
extern "C" esp_err_t esp_modem_set_network_bands(esp_modem_dce_t *dce_wrap, const char *mode, const int *bands, int size)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
std::string mode_str(mode);
return command_response_to_esp_err(dce_wrap->dce->set_network_bands(mode, bands, size));
}
extern "C" esp_err_t esp_modem_get_network_system_mode(esp_modem_dce_t *dce_wrap, int *p_mode)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
int mode;
auto ret = command_response_to_esp_err(dce_wrap->dce->get_network_system_mode(mode));
if (ret == ESP_OK) {
*p_mode = mode;
}
return ret;
}
extern "C" esp_err_t esp_modem_set_gnss_power_mode(esp_modem_dce_t *dce_wrap, int mode)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
return command_response_to_esp_err(dce_wrap->dce->set_gnss_power_mode(mode));
}
extern "C" esp_err_t esp_modem_get_gnss_power_mode(esp_modem_dce_t *dce_wrap, int *p_mode)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
int mode;
auto ret = command_response_to_esp_err(dce_wrap->dce->get_gnss_power_mode(mode));
if (ret == ESP_OK) {
*p_mode = mode;
}
return ret;
}
extern "C" esp_err_t esp_modem_reset(esp_modem_dce_t *dce_wrap)
{
return command_response_to_esp_err(dce_wrap->dce->reset());
}
extern "C" esp_err_t esp_modem_set_pdp_context(esp_modem_dce_t *dce_wrap, esp_modem_PdpContext_t *c_api_pdp)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
esp_modem::PdpContext pdp{c_api_pdp->apn};
pdp.context_id = c_api_pdp->context_id;
pdp.protocol_type = c_api_pdp->protocol_type;
return command_response_to_esp_err(dce_wrap->dce->set_pdp_context(pdp));
}
extern "C" esp_err_t esp_modem_command(esp_modem_dce_t *dce_wrap, const char *command, esp_err_t(*got_line_fn)(uint8_t *data, size_t len), uint32_t timeout_ms)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr || command == nullptr || got_line_fn == nullptr) {
return ESP_ERR_INVALID_ARG;
}
std::string cmd(command);
return command_response_to_esp_err(dce_wrap->dce->command(cmd, [got_line_fn](uint8_t *data, size_t len) {
switch (got_line_fn(data, len)) {
case ESP_OK:
return command_result::OK;
case ESP_FAIL:
return command_result::FAIL;
default:
return command_result::TIMEOUT;
}
}, timeout_ms));
}
extern "C" esp_err_t esp_modem_set_baud(esp_modem_dce_t *dce_wrap, int baud)
{
return command_response_to_esp_err(dce_wrap->dce->set_baud(baud));
}

View File

@ -218,7 +218,7 @@ command_result get_battery_status_sim7xxx(CommandableIf *t, int &voltage, int &b
command_result set_flow_control(CommandableIf *t, int dce_flow, int dte_flow)
{
ESP_LOGV(TAG, "%s", __func__ );
return generic_command_common(t, "AT+IFC=" + std::to_string(dce_flow) + ", " + std::to_string(dte_flow) + "\r");
return generic_command_common(t, "AT+IFC=" + std::to_string(dce_flow) + "," + std::to_string(dte_flow) + "\r");
}
command_result get_operator_name(CommandableIf *t, std::string &operator_name, int &act)

View File

@ -14,6 +14,59 @@
namespace esp_modem {
namespace transitions {
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 {
if (memchr(data, '\n', len))
{
ESP_LOG_BUFFER_HEXDUMP("esp-modem: debug_data", data, len, ESP_LOG_DEBUG);
const auto pass = std::list<std::string_view>({"NO CARRIER", "DISCONNECTED"});
std::string_view response((char *) data, len);
for (auto &it : pass)
if (response.find(it) != std::string::npos) {
if (auto signal = weak_signal.lock()) {
signal->set(1);
}
return true;
}
}
return false;
});
netif.wait_until_ppp_exits();
if (!signal->wait(1, 2000)) {
if (!device.set_mode(modem_mode::COMMAND_MODE)) {
return false;
}
}
dte.set_read_cb(nullptr);
if (!dte.set_mode(modem_mode::COMMAND_MODE)) {
return false;
}
return true;
}
static bool enter_data(DTE &dte, ModuleIf &device, Netif &netif)
{
if (!device.setup_data_mode()) {
return false;
}
if (!device.set_mode(modem_mode::DATA_MODE)) {
return false;
}
if (!dte.set_mode(modem_mode::DATA_MODE)) {
return false;
}
netif.start();
return true;
}
} // namespace transitions
/**
* Set mode while the entire DTE is locked
*/
@ -35,9 +88,10 @@ bool DCE_Mode::set_unsafe(DTE *dte, ModuleIf *device, Netif &netif, modem_mode m
{
switch (m) {
case modem_mode::UNDEF:
case modem_mode::DUAL_MODE: // Only DTE can be in Dual mode
break;
case modem_mode::COMMAND_MODE: {
if (mode == modem_mode::COMMAND_MODE) {
case modem_mode::COMMAND_MODE:
if (mode == modem_mode::COMMAND_MODE || mode >= modem_mode::CMUX_MANUAL_MODE) {
return false;
}
if (mode == modem_mode::CMUX_MODE) {
@ -49,59 +103,23 @@ bool DCE_Mode::set_unsafe(DTE *dte, ModuleIf *device, Netif &netif, modem_mode m
mode = m;
return true;
}
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 {
if (memchr(data, '\n', len))
{
ESP_LOG_BUFFER_HEXDUMP("esp-modem: debug_data", data, len, ESP_LOG_DEBUG);
const auto pass = std::list<std::string_view>({"NO CARRIER", "DISCONNECTED"});
std::string_view response((char *) data, len);
for (auto &it : pass)
if (response.find(it) != std::string::npos) {
if (auto signal = weak_signal.lock()) {
signal->set(1);
}
return true;
}
}
return false;
});
netif.wait_until_ppp_exits();
if (!signal->wait(1, 2000)) {
if (!device->set_mode(modem_mode::COMMAND_MODE)) {
mode = modem_mode::UNDEF;
return false;
}
}
dte->set_read_cb(nullptr);
if (!dte->set_mode(modem_mode::COMMAND_MODE)) {
if (!transitions::exit_data(*dte, *device, netif)) {
mode = modem_mode::UNDEF;
return false;
}
mode = m;
return true;
}
break;
case modem_mode::DATA_MODE:
if (mode == modem_mode::DATA_MODE || mode == modem_mode::CMUX_MODE) {
if (mode == modem_mode::DATA_MODE || mode == modem_mode::CMUX_MODE || mode >= modem_mode::CMUX_MANUAL_MODE) {
return false;
}
if (!device->setup_data_mode()) {
if (!transitions::enter_data(*dte, *device, netif)) {
return false;
}
if (!device->set_mode(modem_mode::DATA_MODE)) {
return false;
}
if (!dte->set_mode(modem_mode::DATA_MODE)) {
return false;
}
netif.start();
mode = m;
return true;
case modem_mode::CMUX_MODE:
if (mode == modem_mode::DATA_MODE || mode == modem_mode::CMUX_MODE) {
if (mode == modem_mode::DATA_MODE || mode == modem_mode::CMUX_MODE || mode >= modem_mode::CMUX_MANUAL_MODE) {
return false;
}
device->set_mode(modem_mode::CMUX_MODE); // switch the device into CMUX mode
@ -111,17 +129,46 @@ bool DCE_Mode::set_unsafe(DTE *dte, ModuleIf *device, Netif &netif, modem_mode m
return false;
}
mode = modem_mode::CMUX_MODE;
if (!device->setup_data_mode()) {
return transitions::enter_data(*dte, *device, netif);
case modem_mode::CMUX_MANUAL_MODE:
if (mode != modem_mode::COMMAND_MODE && mode != modem_mode::UNDEF) {
return false;
}
if (!device->set_mode(modem_mode::DATA_MODE)) {
device->set_mode(modem_mode::CMUX_MODE);
usleep(100'000);
if (!dte->set_mode(m)) {
return false;
}
if (!dte->set_mode(modem_mode::DATA_MODE)) {
return false;
}
netif.start();
mode = modem_mode::CMUX_MANUAL_MODE;
return true;
case modem_mode::CMUX_MANUAL_EXIT:
if (mode != modem_mode::CMUX_MANUAL_MODE) {
return false;
}
if (!dte->set_mode(m)) {
return false;
}
mode = modem_mode::COMMAND_MODE;
return true;
case modem_mode::CMUX_MANUAL_SWAP:
if (mode != modem_mode::CMUX_MANUAL_MODE) {
return false;
}
if (!dte->set_mode(m)) {
return false;
}
return true;
case modem_mode::CMUX_MANUAL_DATA:
if (mode != modem_mode::CMUX_MANUAL_MODE) {
return false;
}
return transitions::enter_data(*dte, *device, netif);
case modem_mode::CMUX_MANUAL_COMMAND:
if (mode != modem_mode::CMUX_MANUAL_MODE) {
return false;
}
return transitions::exit_data(*dte, *device, netif);
}
return false;
}

View File

@ -16,23 +16,33 @@ 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), command_term(std::move(terminal)), data_term(command_term),
cmux_term(nullptr), primary_term(std::move(terminal)), secondary_term(primary_term),
mode(modem_mode::UNDEF) {}
DTE::DTE(std::unique_ptr<Terminal> terminal):
buffer(dte_default_buffer_size),
cmux_term(nullptr), command_term(std::move(terminal)), data_term(command_term),
cmux_term(nullptr), primary_term(std::move(terminal)), secondary_term(primary_term),
mode(modem_mode::UNDEF) {}
DTE::DTE(const esp_modem_dte_config *config, std::unique_ptr<Terminal> t, std::unique_ptr<Terminal> s):
buffer(config->dte_buffer_size),
cmux_term(nullptr), primary_term(std::move(t)), secondary_term(std::move(s)),
mode(modem_mode::DUAL_MODE) {}
DTE::DTE(std::unique_ptr<Terminal> t, std::unique_ptr<Terminal> s):
buffer(dte_default_buffer_size),
cmux_term(nullptr), primary_term(std::move(t)), secondary_term(std::move(s)),
mode(modem_mode::DUAL_MODE) {}
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);
command_term->set_read_cb([this, got_line, separator](uint8_t *data, size_t len) {
primary_term->set_read_cb([this, got_line, separator](uint8_t *data, size_t len) {
if (!data) {
data = buffer.get();
len = command_term->read(data + buffer.consumed, buffer.size - buffer.consumed);
len = primary_term->read(data + buffer.consumed, buffer.size - buffer.consumed);
} else {
buffer.consumed = 0; // if the underlying terminal contains data, we cannot fragment
}
@ -46,13 +56,13 @@ command_result DTE::command(const std::string &command, got_line_cb got_line, ui
buffer.consumed += len;
return false;
});
command_term->write((uint8_t *)command.c_str(), command.length());
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);
}
buffer.consumed = 0;
command_term->set_read_cb(nullptr);
primary_term->set_read_cb(nullptr);
return result;
}
@ -68,26 +78,26 @@ bool DTE::exit_cmux()
}
auto ejected = cmux_term->detach();
// return the ejected terminal and buffer back to this DTE
command_term = std::move(ejected.first);
primary_term = std::move(ejected.first);
buffer = std::move(ejected.second);
data_term = command_term;
secondary_term = primary_term;
return true;
}
bool DTE::setup_cmux()
{
cmux_term = std::make_shared<CMux>(command_term, std::move(buffer));
cmux_term = std::make_shared<CMux>(primary_term, std::move(buffer));
if (cmux_term == nullptr) {
return false;
}
if (!cmux_term->init()) {
return false;
}
command_term = std::make_unique<CMuxInstance>(cmux_term, 0);
if (command_term == nullptr) {
primary_term = std::make_unique<CMuxInstance>(cmux_term, 0);
if (primary_term == nullptr) {
return false;
}
data_term = std::make_unique<CMuxInstance>(cmux_term, 1);
secondary_term = std::make_unique<CMuxInstance>(cmux_term, 1);
return true;
}
@ -104,19 +114,17 @@ bool DTE::set_mode(modem_mode m)
return false;
}
}
// transitions (COMMAND|CMUX|UNDEF) -> DATA
// transitions (COMMAND|DUAL|CMUX|UNDEF) -> DATA
if (m == modem_mode::DATA_MODE) {
if (mode == modem_mode::CMUX_MODE) {
// mode stays the same, but need to swap terminals (as command has been switch)
data_term.swap(command_term);
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);
} else {
mode = m;
}
// prepare the data terminal's callback to the configured std::function (used by netif)
data_term->set_read_cb(on_data);
return true;
}
// transitions (DATA|CMUX|UNDEF) -> COMMAND
// transitions (DATA|DUAL|CMUX|UNDEF) -> COMMAND
if (m == modem_mode::COMMAND_MODE) {
if (mode == modem_mode::CMUX_MODE) {
if (exit_cmux()) {
@ -125,21 +133,47 @@ bool DTE::set_mode(modem_mode m)
}
mode = modem_mode::UNDEF;
return false;
} if (mode == modem_mode::CMUX_MANUAL_MODE || mode == modem_mode::DUAL_MODE) {
return true;
} else {
mode = m;
return true;
}
}
return true;
// manual CMUX transitions: Enter CMUX
if (m == modem_mode::CMUX_MANUAL_MODE) {
if (setup_cmux()) {
mode = m;
return true;
}
mode = modem_mode::UNDEF;
return false;
}
// manual CMUX transitions: Exit CMUX
if (m == modem_mode::CMUX_MANUAL_EXIT && mode == modem_mode::CMUX_MANUAL_MODE) {
if (exit_cmux()) {
mode = modem_mode::COMMAND_MODE;
return true;
}
mode = modem_mode::UNDEF;
return false;
}
// manual CMUX transitions: Swap terminals
if (m == modem_mode::CMUX_MANUAL_SWAP && mode == modem_mode::CMUX_MANUAL_MODE) {
secondary_term.swap(primary_term);
return true;
}
mode = modem_mode::UNDEF;
return false;
}
void DTE::set_read_cb(std::function<bool(uint8_t *, size_t)> f)
{
on_data = std::move(f);
data_term->set_read_cb([this](uint8_t *data, size_t len) {
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
data = buffer.get();
len = data_term->read(buffer.get(), buffer.size);
len = secondary_term->read(buffer.get(), buffer.size);
}
if (on_data) {
return on_data(data, len);
@ -150,22 +184,22 @@ void DTE::set_read_cb(std::function<bool(uint8_t *, size_t)> f)
void DTE::set_error_cb(std::function<void(terminal_error err)> f)
{
data_term->set_error_cb(f);
command_term->set_error_cb(f);
secondary_term->set_error_cb(f);
primary_term->set_error_cb(f);
}
int DTE::read(uint8_t **d, size_t len)
{
auto data_to_read = std::min(len, buffer.size);
auto data = buffer.get();
auto actual_len = data_term->read(data, data_to_read);
auto actual_len = secondary_term->read(data, data_to_read);
*d = data;
return actual_len;
}
int DTE::write(uint8_t *data, size_t len)
{
return data_term->write(data, len);
return secondary_term->write(data, len);
}
/**

View File

@ -21,7 +21,7 @@ void Netif::on_ppp_changed(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data)
{
auto *ppp = static_cast<Netif *>(arg);
if (event_id < NETIF_PP_PHASE_OFFSET) {
if (event_id > NETIF_PPP_ERRORNONE && event_id < NETIF_PP_PHASE_OFFSET) {
ESP_LOGI("esp_modem_netif", "PPP state changed event %" PRId32, event_id);
// only notify the modem on state/error events, ignoring phase transitions
ppp->signal.set(PPP_EXIT);
@ -87,7 +87,7 @@ void Netif::start()
{
ppp_dte->set_read_cb([this](uint8_t *data, size_t len) -> bool {
receive(data, len);
return false;
return true;
});
esp_netif_action_start(driver.base.netif, nullptr, 0, nullptr);
signal.set(PPP_STARTED);

View File

@ -39,7 +39,7 @@ void Netif::start()
{
ppp_dte->set_read_cb([this](uint8_t *data, size_t len) -> bool {
receive(data, len);
return false;
return true;
});
netif->transmit = esp_modem_dte_transmit;
netif->ctx = (void *)this;

View File

@ -125,9 +125,7 @@ void UartTerminal::task()
case UART_DATA:
uart_get_buffered_data_len(uart.port, &len);
if (len && on_read) {
if (on_read(nullptr, len)) {
on_read = nullptr;
}
on_read(nullptr, len);
}
break;
case UART_FIFO_OVF:

View File

@ -13,3 +13,15 @@ idf_component_get_property(esp_modem esp_modem COMPONENT_LIB)
target_compile_definitions(${esp_modem} PRIVATE "-DCONFIG_COMPILER_CXX_EXCEPTIONS")
target_compile_definitions(${esp_modem} PRIVATE "-DCONFIG_IDF_TARGET_LINUX")
target_link_options(${esp_modem} INTERFACE -fsanitize=address -fsanitize=undefined)
if(CONFIG_GCOV_ENABLED)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --coverage -fprofile-arcs -ftest-coverage")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --coverage -fprofile-arcs -ftest-coverage")
MARK_AS_ADVANCED(
CMAKE_CXX_FLAGS_COVERAGE
CMAKE_C_FLAGS_COVERAGE
CMAKE_EXE_LINKER_FLAGS_COVERAGE
CMAKE_SHARED_LINKER_FLAGS_COVERAGE )
endif()

View File

@ -0,0 +1,10 @@
#!/bin/bash
lwip=$1
lwip_uri=$2
lwip_contrib=$3
wget --no-verbose ${lwip_uri}/${lwip}.zip
unzip -oq ${lwip}.zip
wget --no-verbose ${lwip_uri}/${lwip_contrib}.zip
unzip -oq ${lwip_contrib}.zip

View File

@ -0,0 +1,9 @@
menu "Host-test config"
config GCOV_ENABLED
bool "Coverage analyzer"
default n
help
Enables coverage analyzing for host tests.
endmenu

View File

@ -0,0 +1 @@
CONFIG_GCOV_ENABLED=y

View File

@ -8,3 +8,5 @@ set_target_properties(${COMPONENT_LIB} PROPERTIES
CXX_STANDARD_REQUIRED ON
CXX_EXTENSIONS ON
)
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")

View File

@ -1,26 +1,38 @@
menu "Example Configuration"
menu "Test App Configuration"
config ESP_WIFI_SSID
string "WiFi SSID"
default "myssid"
config TEST_APP_PPP_SERVER_IP
string "IP address of PPP server"
default "10.0.0.1"
help
SSID (network name) for the example to connect to.
IP address of PPP server. Note: this is also the address
where the TCP server is started to test the connection
config ESP_WIFI_PASSWORD
string "WiFi Password"
default "mypassword"
config TEST_APP_PPP_CLIENT_IP
string "IP address of PPP client"
default "10.0.0.2"
help
WiFi password (WPA or WPA2) for the example to use.
config ESP_WIFI_CHANNEL
int "WiFi Channel"
range 1 13
default 1
help
WiFi channel (network channel) for the example to use.
IP address that PPP server assigns to PPP client.
config ESP_MAX_STA_CONN
int "Maximal STA connections"
default 4
config TEST_APP_UART_TX_PIN
int "TXD Pin Number"
default 6
range 0 31
help
Max number of the STA connects to AP.
Pin number of UART TX.
config TEST_APP_UART_RX_PIN
int "RXD Pin Number"
default 7
range 0 31
help
Pin number of UART RX.
config TEST_APP_TCP_PORT
int "Port of test"
range 0 65535
default 2222
help
The remote port to which the client will connects to
once the PPP connection established
endmenu

View File

@ -60,6 +60,8 @@ public:
{
// configure
esp_modem_dte_config_t dte_config = ESP_MODEM_DTE_DEFAULT_CONFIG();
dte_config.uart_config.tx_io_num = CONFIG_TEST_APP_UART_TX_PIN;
dte_config.uart_config.rx_io_num = CONFIG_TEST_APP_UART_RX_PIN;
esp_modem_dce_config dce_config = ESP_MODEM_DCE_DEFAULT_CONFIG("");
// create DTE and minimal network DCE
@ -96,6 +98,7 @@ esp_err_t modem_init_network(esp_netif_t *netif)
esp_err_t modem_start_network()
{
NetModule::start();
return ESP_OK;
}
void modem_stop_network()

View File

@ -0,0 +1,83 @@
# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Unlicense OR CC0-1.0
from __future__ import print_function, unicode_literals
import subprocess
import time
from threading import Event, Thread
import netifaces
def run_server(server_stop, port, server_ip, client_ip):
print('Starting PPP server on port: {}'.format(port))
try:
arg_list = [
'sudo', 'pppd', port, '115200',
'{}:{}'.format(server_ip, client_ip), 'modem', 'local', 'noauth',
'debug', 'nocrtscts', 'nodetach', '+ipv6'
]
p = subprocess.Popen(arg_list, stdout=subprocess.PIPE, bufsize=1)
while not server_stop.is_set():
if p.poll() is not None:
if p.poll() == 16:
print('[PPPD:] Terminated: hang-up received')
break
else:
raise ValueError(
'ENV_TEST_FAILURE: PPP terminated unexpectedly with {}'
.format(p.poll()))
line = p.stdout.readline()
if line:
print('[PPPD:]{}'.format(line.rstrip()))
time.sleep(0.1)
except Exception as e:
print(e)
raise ValueError('ENV_TEST_FAILURE: Error running PPP server')
finally:
p.terminate()
print('PPP server stopped')
def test_examples_protocol_pppos_connect(dut):
"""
steps:
1. starts PPP server
2. get DUT as PPP client to connect to the server
3. run unit test FW
"""
# Look for test case symbolic names
try:
server_ip = dut.app.sdkconfig.get('TEST_APP_PPP_SERVER_IP')
client_ip = dut.app.sdkconfig.get('TEST_APP_PPP_CLIENT_IP')
except Exception:
print(
'ENV_TEST_FAILURE: Some mandatory configuration not found in sdkconfig'
)
raise
# the PPP test env uses two ttyUSB's: one for ESP32 board, another one for ppp server
# use the other port for PPP server than the DUT/ESP
port = '/dev/ttyUSB0' if dut.serial.port == '/dev/ttyUSB1' else '/dev/ttyUSB1'
# Start the PPP server
server_stop = Event()
t = Thread(target=run_server,
args=(server_stop, port, server_ip, client_ip))
t.start()
try:
ppp_server_timeout = time.time() + 30
while 'ppp0' not in netifaces.interfaces():
print(
"PPP server haven't yet setup its netif, list of active netifs:{}"
.format(netifaces.interfaces()))
time.sleep(0.5)
if time.time() > ppp_server_timeout:
raise ValueError(
'ENV_TEST_FAILURE: PPP server failed to setup ppp0 interface within timeout'
)
dut.expect('All tests passed')
finally:
server_stop.set()
t.join()

View File

@ -1,3 +1,4 @@
CONFIG_COMPILER_CXX_EXCEPTIONS=y
CONFIG_CXX_EXCEPTIONS=y
CONFIG_PPP_SUPPORT=y
CONFIG_ESP_MAIN_TASK_STACK_SIZE=4096

View File

@ -0,0 +1,7 @@
# Changelog
## [0.1.0](https://github.com/espressif/esp-protocols/commits/1407dfc)
### Updated
- Adds esp_mqtt_cxx component ([1407dfc](https://github.com/espressif/esp-protocols/commit/1407dfc))

View File

@ -0,0 +1,8 @@
idf_build_get_property(target IDF_TARGET)
idf_component_register(SRCS "esp_mqtt_cxx.cpp"
INCLUDE_DIRS "include"
REQUIRES mqtt
)
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")

View File

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -0,0 +1,73 @@
# This is Doxygen configuration file
#
# Doxygen provides over 260 configuration statements
# To make this file easier to follow,
# it contains only statements that are non-default
#
# NOTE:
# It is recommended not to change defaults unless specifically required
# Test any changes how they affect generated documentation
# Make sure that correct warnings are generated to flag issues with documented code
#
# For the complete list of configuration statements see:
# http://doxygen.nl/manual/config.html
PROJECT_NAME = "MQTT C++ client"
## The 'INPUT' statement below is used as input by script 'gen-df-input.py'
## to automatically generate API reference list files heder_file.inc
## These files are placed in '_inc' directory
## and used to include in API reference documentation
INPUT = \
$(PROJECT_PATH)/include/esp_mqtt.hpp \
$(PROJECT_PATH)/include/esp_mqtt_client_config.hpp
## Get warnings for functions that have no documentation for their parameters or return value
##
WARN_NO_PARAMDOC = YES
## Enable preprocessing and remove __attribute__(...) expressions from the INPUT files
##
ENABLE_PREPROCESSING = YES
MACRO_EXPANSION = YES
EXPAND_ONLY_PREDEF = YES
PREDEFINED = \
$(ENV_DOXYGEN_DEFINES) \
__DOXYGEN__=1 \
__attribute__(x)= \
_Static_assert()= \
IDF_DEPRECATED(X)= \
IRAM_ATTR= \
configSUPPORT_DYNAMIC_ALLOCATION=1 \
configSUPPORT_STATIC_ALLOCATION=1 \
configQUEUE_REGISTRY_SIZE=1 \
configUSE_RECURSIVE_MUTEXES=1 \
configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS=1 \
configNUM_THREAD_LOCAL_STORAGE_POINTERS=1 \
configUSE_APPLICATION_TASK_TAG=1 \
configTASKLIST_INCLUDE_COREID=1 \
"ESP_EVENT_DECLARE_BASE(x)=extern esp_event_base_t x"
## Do not complain about not having dot
##
HAVE_DOT = NO
## Generate XML that is required for Breathe
##
GENERATE_XML = YES
XML_OUTPUT = xml
GENERATE_HTML = NO
HAVE_DOT = NO
GENERATE_LATEX = NO
GENERATE_MAN = YES
## Skip distracting progress messages
##
QUIET = YES
## Enable Section Tags for conditional documentation
##
ENABLED_SECTIONS += \
DOC_EXCLUDE_HEADER_SECTION ## To conditionally remove doc sections from IDF source files without affecting documentation in upstream files.

View File

@ -0,0 +1,23 @@
# flake8: noqa
from esp_docs.conf_docs import *
extensions += [
'sphinx_copybutton',
# Needed as a trigger for running doxygen
'esp_docs.esp_extensions.dummy_build_system',
'esp_docs.esp_extensions.run_doxygen',
]
# link roles config
github_repo = 'espressif/esp-protocols'
# context used by sphinx_idf_theme
html_context['github_user'] = 'espressif'
html_context['github_repo'] = 'esp-docs'
# Extra options required by sphinx_idf_theme
project_slug = 'esp-idf' # >=5.0
versions_url = 'https://github.com/espressif/esp-protocols/docs/docs_versions.js'
idf_targets = ['esp32']
languages = ['en']

View File

@ -0,0 +1,25 @@
esp_mqtt_client_config.hpp:line: warning: Compound idf::mqtt::BrokerConfiguration is not documented.
esp_mqtt_client_config.hpp:line: warning: Compound idf::mqtt::ClientCredentials is not documented.
esp_mqtt_client_config.hpp:line: warning: Compound idf::mqtt::Configuration is not documented.
esp_mqtt_client_config.hpp:line: warning: Compound idf::mqtt::Connection is not documented.
esp_mqtt_client_config.hpp:line: warning: Compound idf::mqtt::Event is not documented.
esp_mqtt_client_config.hpp:line: warning: Compound idf::mqtt::LastWill is not documented.
esp_mqtt_client_config.hpp:line: warning: Compound idf::mqtt::Session is not documented.
esp_mqtt_client_config.hpp:line: warning: Compound idf::mqtt::Task is not documented.
esp_mqtt_client_config.hpp:line: warning: Member address (variable) of struct idf::mqtt::BrokerConfiguration is not documented.
esp_mqtt_client_config.hpp:line: warning: Member security (variable) of struct idf::mqtt::BrokerConfiguration is not documented.
esp_mqtt.hpp:line: warning: Member operator()(esp_mqtt_client *client_handler) (function) of struct idf::mqtt::Client::MqttClientDeleter is not documented.
esp_mqtt_client_config.hpp:line: warning: Member username (variable) of struct idf::mqtt::ClientCredentials is not documented.
esp_mqtt_client_config.hpp:line: warning: Member authentication (variable) of struct idf::mqtt::ClientCredentials is not documented.
esp_mqtt_client_config.hpp:line: warning: Member client_id (variable) of struct idf::mqtt::ClientCredentials is not documented.
esp_mqtt_client_config.hpp:line: warning: Member event (variable) of struct idf::mqtt::Configuration is not documented.
esp_mqtt_client_config.hpp:line: warning: Member task (variable) of struct idf::mqtt::Configuration is not documented.
esp_mqtt_client_config.hpp:line: warning: Member session (variable) of struct idf::mqtt::Configuration is not documented.
esp_mqtt_client_config.hpp:line: warning: Member connection (variable) of struct idf::mqtt::Configuration is not documented.
esp_mqtt_client_config.hpp:line: warning: Member data (variable) of struct idf::mqtt::DER is not documented.
esp_mqtt_client_config.hpp:line: warning: Member len (variable) of struct idf::mqtt::DER is not documented.
esp_mqtt_client_config.hpp:line: warning: Member ds_data (variable) of struct idf::mqtt::DigitalSignatureData is not documented.
esp_mqtt_client_config.hpp:line: warning: Member data (variable) of struct idf::mqtt::Password is not documented.
esp_mqtt_client_config.hpp:line: warning: Member data (variable) of struct idf::mqtt::PEM is not documented.
esp_mqtt_client_config.hpp:line: warning: Member hint_key (variable) of struct idf::mqtt::PSK is not documented.
esp_mqtt_client_config.hpp:line: warning: Member last_will (variable) of struct idf::mqtt::Session is not documented.

View File

@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
#
# English Language RTD & Sphinx config file
#
# Uses ../conf_common.py for most non-language-specific settings.
# Importing conf_common adds all the non-language-specific
# parts to this conf module
try:
from conf_common import * # noqa: F403,F401
except ImportError:
import os
import sys
sys.path.insert(0, os.path.abspath('../'))
from conf_common import * # noqa: F403,F401
# General information about the project.
project = u'ESP-Protocols'
copyright = u'2016 - 2023, Espressif Systems (Shanghai) Co., Ltd'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
language = 'en'

View File

@ -0,0 +1,132 @@
ESP MQTT C++ client
====================
Overview
--------
The ESP MQTT client is a wrapper over the `esp_mqtt` client with the goal of providing a higher level API.
Features
--------
* Supports MQTT version 3.11
* Adds a Filter validation class for topic filters
* Split the event handlers to member functions
Configuration
-------------
The current design uses exception as an error handling mechanism, therefore exceptions need to be enabled in menuconfig.
Usage
-----
User code needs to inherit fromm :cpp:class:`idf::mqtt::Client` and provide overloads for the event handlers.
.. note:: The handler is available to allow user code to interact directly with it in case of need. This member will likely be made private in the future once the class API stabilizes.
.. doxygenclass:: idf::mqtt::Client
:members:
:protected-members:
Event Handling
--------------
Events are dispatched throug calls to member functions each one dedicated to a type of event.
Application Example
-------------------
* :example:`tcp <../examples/tcp>`
* :example:`ssl <../examples/ssl>`
API Reference
-------------
Header File
^^^^^^^^^^^
* :project_file:`include/esp_mqtt.hpp`
Structures
^^^^^^^^^^
.. doxygenstruct:: idf::mqtt::MQTTException
:members:
.. doxygenstruct:: idf::mqtt::Message
:members:
Classes
^^^^^^^
.. doxygenclass:: idf::mqtt::Filter
:members:
Header File
^^^^^^^^^^^
* :project_file:`include/esp_mqtt_client_config.hpp`
Structures
^^^^^^^^^^
.. doxygenstruct:: idf::mqtt::Host
:members:
.. doxygenstruct:: idf::mqtt::URI
:members:
.. doxygenstruct:: idf::mqtt::BrokerAddress
:members:
.. doxygenstruct:: idf::mqtt::PEM
:members:
.. doxygenstruct:: idf::mqtt::DER
:members:
.. doxygenstruct:: idf::mqtt::Insecure
:members:
.. doxygenstruct:: idf::mqtt::GlobalCAStore
:members:
.. doxygenstruct:: idf::mqtt::PSK
:members:
.. doxygenstruct:: idf::mqtt::Password
:members:
.. doxygenstruct:: idf::mqtt::ClientCertificate
:members:
.. doxygenstruct:: idf::mqtt::SecureElement
:members:
.. doxygenstruct:: idf::mqtt::DigitalSignatureData
:members:
.. doxygenstruct:: idf::mqtt::BrokerConfiguration
:members:
.. doxygenstruct:: idf::mqtt::ClientCredentials
:members:
.. doxygenstruct:: idf::mqtt::Event
:members:
.. doxygenstruct:: idf::mqtt::LastWill
:members:
.. doxygenstruct:: idf::mqtt::Session
:members:
.. doxygenstruct:: idf::mqtt::Task
:members:
.. doxygenstruct:: idf::mqtt::Connection
:members:
.. doxygenstruct:: idf::mqtt::Configuration
:members:

View File

@ -0,0 +1,26 @@
build-docs --target esp32 --language en
cp -rf _build/en/esp32/html .
rm -rf _build __pycache__
# Modifes some version and target fields of index.html
echo "<script type="text/javascript">
window.onload =(function() {
var myAnchor = document.getElementById('version-select');
var mySpan = document.createElement('input');
mySpan.setAttribute('type', 'text');
mySpan.setAttribute('maxLength', '10');
mySpan.value = 'latest';
mySpan.setAttribute('disabled', true);
myAnchor.parentNode.replaceChild(mySpan, myAnchor);
var myAnchor = document.getElementById('target-select');
var mySpan = document.createElement('input');
mySpan.setAttribute('type', 'text');
mySpan.setAttribute('maxLength', '10');
mySpan.value = 'all targets';
mySpan.setAttribute('disabled', true);
myAnchor.parentNode.replaceChild(mySpan, myAnchor);
})();
</script>" >> html/index.html

View File

@ -0,0 +1,292 @@
/*
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string>
#include <algorithm>
#include <stdexcept>
#include "mqtt_client.h"
#include "esp_log.h"
#include "esp_mqtt.hpp"
#include "esp_mqtt_client_config.hpp"
namespace {
// Helper for static assert.
template<class T>
constexpr bool always_false = false;
template<class... Ts> struct overloaded : Ts... {
using Ts::operator()...;
};
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
using namespace idf::mqtt;
/*
* This function is responsible for fill in the configurations for the broker related data
* of mqtt_client_config_t
*/
void config_broker(esp_mqtt_client_config_t &mqtt_client_cfg, BrokerConfiguration const &broker)
{
std::visit(overloaded{
[&mqtt_client_cfg](Host const & host)
{
mqtt_client_cfg.broker.address.hostname = host.address.c_str();
mqtt_client_cfg.broker.address.path = host.path.c_str();
mqtt_client_cfg.broker.address.transport = host.transport;
},
[&mqtt_client_cfg](URI const & uri)
{
mqtt_client_cfg.broker.address.uri = uri.address.c_str();
},
[]([[maybe_unused ]]auto & unknown)
{
static_assert(always_false<decltype(unknown)>, "Missing type handler for variant handler");
}
},
broker.address.address);
std::visit(overloaded{
[]([[maybe_unused]]Insecure const & insecure) {},
[&mqtt_client_cfg](GlobalCAStore const & use_global_store)
{
mqtt_client_cfg.broker.verification.use_global_ca_store = true;
},
[&mqtt_client_cfg](CryptographicInformation const & certificates)
{
std::visit(overloaded{
[&mqtt_client_cfg](PEM const & pem)
{
mqtt_client_cfg.broker.verification.certificate = pem.data;
}, [&mqtt_client_cfg](DER const & der)
{
mqtt_client_cfg.broker.verification.certificate = der.data;
mqtt_client_cfg.broker.verification.certificate_len = der.len;
}}, certificates);
},
[]([[maybe_unused]] PSK const & psk) {},
[]([[maybe_unused]] auto & unknown)
{
static_assert(always_false<decltype(unknown)>, "Missing type handler for variant handler");
}
},
broker.security);
mqtt_client_cfg.broker.address.port = broker.address.port;
}
/*
* This function is responsible for fill in the configurations for the client credentials related data
* of mqtt_client_config_t
*/
void config_client_credentials(esp_mqtt_client_config_t &mqtt_client_cfg, ClientCredentials const &credentials)
{
mqtt_client_cfg.credentials.client_id = credentials.client_id.has_value() ? credentials.client_id.value().c_str() : nullptr ;
mqtt_client_cfg.credentials.username = credentials.username.has_value() ? credentials.username.value().c_str() : nullptr ;
std::visit(overloaded{
[&mqtt_client_cfg](Password const & password)
{
mqtt_client_cfg.credentials.authentication.password = password.data.c_str();
},
[](ClientCertificate const & certificate) {},
[](SecureElement const & enable_secure_element) {},
[]([[maybe_unused ]]auto & unknown)
{
static_assert(always_false<decltype(unknown)>, "Missing type handler for variant handler");
}
}, credentials.authentication);
}
esp_mqtt_client_config_t make_config(BrokerConfiguration const &broker, ClientCredentials const &credentials, Configuration const &config)
{
esp_mqtt_client_config_t mqtt_client_cfg{};
config_broker(mqtt_client_cfg, broker);
config_client_credentials(mqtt_client_cfg, credentials);
return mqtt_client_cfg;
}
}
namespace idf::mqtt {
Client::Client(BrokerConfiguration const &broker, ClientCredentials const &credentials, Configuration const &config): Client(make_config(broker, credentials, config)) {}
Client::Client(esp_mqtt_client_config_t const &config) : handler(esp_mqtt_client_init(&config))
{
if (handler == nullptr) {
throw MQTTException(ESP_FAIL);
};
CHECK_THROW_SPECIFIC(esp_mqtt_client_register_event(handler.get(), MQTT_EVENT_ANY, mqtt_event_handler, this), mqtt::MQTTException);
CHECK_THROW_SPECIFIC(esp_mqtt_client_start(handler.get()), mqtt::MQTTException);
}
void Client::mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) noexcept
{
ESP_LOGD(TAG, "Event dispatched from event loop base=%s, event_id=%d", base, event_id);
auto *event = static_cast<esp_mqtt_event_t *>(event_data);
auto &client = *static_cast<Client *>(handler_args);
switch (event->event_id) {
case MQTT_EVENT_CONNECTED:
ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
client.on_connected(event);
break;
case MQTT_EVENT_DISCONNECTED:
ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
client.on_disconnected(event);
break;
case MQTT_EVENT_SUBSCRIBED:
ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id);
client.on_subscribed(event);
break;
case MQTT_EVENT_UNSUBSCRIBED:
ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);
client.on_unsubscribed(event);
break;
case MQTT_EVENT_PUBLISHED:
ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
client.on_published(event);
break;
case MQTT_EVENT_DATA:
ESP_LOGI(TAG, "MQTT_EVENT_DATA");
client.on_data(event);
break;
case MQTT_EVENT_ERROR:
ESP_LOGI(TAG, "MQTT_EVENT_ERROR");
client.on_error(event);
break;
case MQTT_EVENT_BEFORE_CONNECT:
ESP_LOGI(TAG, "MQTT_EVENT_BEFORE_CONNECT");
client.on_before_connect(event);
break;
default:
ESP_LOGI(TAG, "Other event id:%d", event->event_id);
break;
}
}
void Client::on_error(esp_mqtt_event_handle_t const event)
{
auto 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);
}
};
if (event->error_handle->error_type == MQTT_ERROR_TYPE_TCP_TRANSPORT) {
log_error_if_nonzero("reported from esp-tls", event->error_handle->esp_tls_last_esp_err);
log_error_if_nonzero("reported from tls stack", event->error_handle->esp_tls_stack_err);
log_error_if_nonzero("captured as transport's socket errno", event->error_handle->esp_transport_sock_errno);
ESP_LOGI(TAG, "Last errno string (%s)", strerror(event->error_handle->esp_transport_sock_errno));
}
}
void Client::on_disconnected(esp_mqtt_event_handle_t const event)
{
}
void Client::on_subscribed(esp_mqtt_event_handle_t const event)
{
printf("Subscribed to %.*s\r\n", event->topic_len, event->topic);
}
void Client::on_unsubscribed(esp_mqtt_event_handle_t const event)
{
}
void Client::on_published(esp_mqtt_event_handle_t const event)
{
}
void Client::on_before_connect(esp_mqtt_event_handle_t const event)
{
}
void Client::on_connected(esp_mqtt_event_handle_t const event)
{
}
void Client::on_data(esp_mqtt_event_handle_t const event)
{
}
std::optional<MessageID> Client::subscribe(std::string const &topic, QoS qos)
{
auto res = esp_mqtt_client_subscribe(handler.get(), topic.c_str(),
static_cast<int>(qos));
if (res < 0) {
return std::nullopt;
}
return MessageID{res};
}
bool is_valid(std::string::const_iterator first, std::string::const_iterator last)
{
if (first == last) {
return false;
}
auto number = std::find(first, last, '#');
if (number != last) {
if (std::next(number) != last) {
return false;
}
if (*std::prev(number) != '/' && number != first) {
return false;
}
}
auto plus = std::find(first, last, '+');
if (plus != last) {
if (*(std::prev(plus)) != '/' && plus != first) {
return false;
}
if (std::next(plus) != last && *(std::next(plus)) != '/') {
return false;
}
}
return true;
}
Filter::Filter(std::string user_filter) : filter(std::move(user_filter))
{
if (!is_valid(filter.begin(), filter.end())) {
throw std::domain_error("Forbidden Filter string");
}
}
[[nodiscard]] bool Filter::match(std::string::const_iterator topic_begin, std::string::const_iterator topic_end) const noexcept
{
auto filter_begin = filter.begin();
auto filter_end = filter.end();
for (auto mismatch = std::mismatch(filter_begin, filter_end, topic_begin);
mismatch.first != filter.end() and mismatch.second != topic_end;
mismatch = std::mismatch(filter_begin, filter_end, topic_begin)) {
if (*mismatch.first != '#' and * mismatch.first != '+') {
return false;
}
if (*mismatch.first == '#') {
return true;
}
if (*mismatch.first == '+') {
filter_begin = advance(mismatch.first, filter_end);
topic_begin = advance(mismatch.second, topic_end);
if (filter_begin == filter_end and topic_begin != topic_end) {
return false;
}
}
}
return true;
}
const std::string &Filter::get()
{
return filter;
}
[[nodiscard]] bool Filter::match(char *const begin, int size) const noexcept
{
auto it = static_cast<std::string::const_iterator>(begin);
return match(it, it + size);
}
std::string::const_iterator Filter::advance(std::string::const_iterator begin, std::string::const_iterator end) const
{
constexpr auto separator = '/';
return std::find(begin, end, separator);
}
}

View File

@ -0,0 +1,14 @@
# The following four lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
# (Not part of the boilerplate) This example uses an extra component for common
# functions such as Wi-Fi and Ethernet connection.
# The path to esp_mqtt_cxx is also added.
set(EXTRA_COMPONENT_DIRS
"../../../../common_components/protocol_examples_common" "../../")
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(mqtt_ssl_cxx)
target_add_binary_data(mqtt_ssl_cxx.elf "main/mqtt_eclipseprojects_io.pem" TEXT)

View File

@ -0,0 +1,2 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- |

View File

@ -0,0 +1,3 @@
idf_component_register(SRCS "mqtt_ssl_example.cpp"
INCLUDE_DIRS ".")
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")

View File

@ -0,0 +1,9 @@
menu "Example Configuration"
config BROKER_URI
string "Broker URL"
default "mqtts://mqtt.eclipseprojects.io:8883"
help
URL of the broker to connect to
endmenu

View File

@ -0,0 +1,27 @@
-----BEGIN CERTIFICATE-----
MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/
MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow
SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT
GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC
AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF
q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8
SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0
Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA
a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj
/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T
AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG
CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv
bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k
c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw
VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC
ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz
MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu
Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF
AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo
uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/
wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu
X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG
PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6
KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==
-----END CERTIFICATE-----

View File

@ -0,0 +1,30 @@
-----BEGIN CERTIFICATE-----
MIIFFjCCAv6gAwIBAgIRAJErCErPDBinU/bWLiWnX1owDQYJKoZIhvcNAQELBQAw
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjAwOTA0MDAwMDAw
WhcNMjUwOTE1MTYwMDAwWjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg
RW5jcnlwdDELMAkGA1UEAxMCUjMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
AoIBAQC7AhUozPaglNMPEuyNVZLD+ILxmaZ6QoinXSaqtSu5xUyxr45r+XXIo9cP
R5QUVTVXjJ6oojkZ9YI8QqlObvU7wy7bjcCwXPNZOOftz2nwWgsbvsCUJCWH+jdx
sxPnHKzhm+/b5DtFUkWWqcFTzjTIUu61ru2P3mBw4qVUq7ZtDpelQDRrK9O8Zutm
NHz6a4uPVymZ+DAXXbpyb/uBxa3Shlg9F8fnCbvxK/eG3MHacV3URuPMrSXBiLxg
Z3Vms/EY96Jc5lP/Ooi2R6X/ExjqmAl3P51T+c8B5fWmcBcUr2Ok/5mzk53cU6cG
/kiFHaFpriV1uxPMUgP17VGhi9sVAgMBAAGjggEIMIIBBDAOBgNVHQ8BAf8EBAMC
AYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMBIGA1UdEwEB/wQIMAYB
Af8CAQAwHQYDVR0OBBYEFBQusxe3WFbLrlAJQOYfr52LFMLGMB8GA1UdIwQYMBaA
FHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcw
AoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzAnBgNVHR8EIDAeMBygGqAYhhZodHRw
Oi8veDEuYy5sZW5jci5vcmcvMCIGA1UdIAQbMBkwCAYGZ4EMAQIBMA0GCysGAQQB
gt8TAQEBMA0GCSqGSIb3DQEBCwUAA4ICAQCFyk5HPqP3hUSFvNVneLKYY611TR6W
PTNlclQtgaDqw+34IL9fzLdwALduO/ZelN7kIJ+m74uyA+eitRY8kc607TkC53wl
ikfmZW4/RvTZ8M6UK+5UzhK8jCdLuMGYL6KvzXGRSgi3yLgjewQtCPkIVz6D2QQz
CkcheAmCJ8MqyJu5zlzyZMjAvnnAT45tRAxekrsu94sQ4egdRCnbWSDtY7kh+BIm
lJNXoB1lBMEKIq4QDUOXoRgffuDghje1WrG9ML+Hbisq/yFOGwXD9RiX8F6sw6W4
avAuvDszue5L3sz85K+EC4Y/wFVDNvZo4TYXao6Z0f+lQKc0t8DQYzk1OXVu8rp2
yJMC6alLbBfODALZvYH7n7do1AZls4I9d1P4jnkDrQoxB3UqQ9hVl3LEKQ73xF1O
yK5GhDDX8oVfGKF5u+decIsH4YaTw7mP3GFxJSqv3+0lUFJoi5Lc5da149p90Ids
hCExroL1+7mryIkXPeFM5TgO9r0rvZaBFOvV2z0gp35Z0+L4WPlbuEjN/lxPFin+
HlUjr8gRsI3qfJOQFy/9rKIJR0Y/8Omwt/8oTWgy1mdeHmmjk7j1nYsvC9JSQ6Zv
MldlTTKB3zhThV1+XWYp6rjd5JW1zbVWEkLNxE7GJThEUG3szgBVGP7pSWTUTsqX
nLRbwHOoq7hHwg==
-----END CERTIFICATE-----

View File

@ -0,0 +1,90 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
/* C++ MQTT (over TCP) Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <cstdint>
#include <string>
#include "esp_mqtt_client_config.hpp"
#include "nvs_flash.h"
#include "protocol_examples_common.h"
#include "esp_log.h"
#include "esp_mqtt.hpp"
namespace {
constexpr auto *TAG = "MQTT_EXAMPLE";
extern const char mqtt_eclipse_org_pem_start[] asm("_binary_mqtt_eclipseprojects_io_pem_start");
extern const char mqtt_eclipse_org_pem_end[] asm("_binary_mqtt_eclipseprojects_io_pem_end");
class MyClient final : public idf::mqtt::Client {
public:
using idf::mqtt::Client::Client;
private:
void on_connected(esp_mqtt_event_handle_t const event) override
{
using idf::mqtt::QoS;
subscribe(messages.get());
subscribe(sent_load.get(), QoS::AtMostOnce);
}
void on_data(esp_mqtt_event_handle_t const event) override
{
if (messages.match(event->topic, event->topic_len)) {
ESP_LOGI(TAG, "Received in the messages topic");
}
}
idf::mqtt::Filter messages{std::string{"$SYS/broker/messages/received"}};
idf::mqtt::Filter sent_load{std::string{"$SYS/broker/load/+/sent"}};
};
}
namespace mqtt = idf::mqtt;
extern "C" 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] IDF version: %s", esp_get_idf_version());
esp_log_level_set("*", ESP_LOG_INFO);
esp_log_level_set("MQTT_CLIENT", ESP_LOG_VERBOSE);
esp_log_level_set("MQTT_EXAMPLE", ESP_LOG_VERBOSE);
esp_log_level_set("TRANSPORT_TCP", ESP_LOG_VERBOSE);
esp_log_level_set("TRANSPORT_SSL", ESP_LOG_VERBOSE);
esp_log_level_set("TRANSPORT", ESP_LOG_VERBOSE);
esp_log_level_set("OUTBOX", ESP_LOG_VERBOSE);
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());
mqtt::BrokerConfiguration broker{
.address = {mqtt::URI{std::string{CONFIG_BROKER_URI}}},
.security = mqtt::CryptographicInformation{mqtt::PEM{mqtt_eclipse_org_pem_start}}
};
idf::mqtt::ClientCredentials credentials{};
idf::mqtt::Configuration config{};
MyClient client{broker, credentials, config};
while (true) {
constexpr TickType_t xDelay = 500 / portTICK_PERIOD_MS;
vTaskDelay( xDelay );
}
}

View File

@ -0,0 +1,8 @@
# SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Unlicense OR CC0-1.0
import pytest
@pytest.mark.esp32
def test_dummy() -> None:
pass

View File

@ -0,0 +1,21 @@
# Enable C++ exceptions and set emergency pool size for exception objects
CONFIG_COMPILER_CXX_EXCEPTIONS=y
CONFIG_COMPILER_CXX_EXCEPTIONS_EMG_POOL_SIZE=1024
CONFIG_EXAMPLE_CONNECT_ETHERNET=y
CONFIG_EXAMPLE_CONNECT_WIFI=n
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
CONFIG_EXAMPLE_ETH_PHY_IP101=y
CONFIG_EXAMPLE_ETH_MDC_GPIO=23
CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5
CONFIG_EXAMPLE_ETH_PHY_ADDR=1
CONFIG_EXAMPLE_CONNECT_IPV6=y
CONFIG_EXAMPLE_CONNECT_ETHERNET=y
CONFIG_EXAMPLE_CONNECT_WIFI=n
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
CONFIG_EXAMPLE_ETH_PHY_IP101=y
CONFIG_EXAMPLE_ETH_MDC_GPIO=23
CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5
CONFIG_EXAMPLE_ETH_PHY_ADDR=1
CONFIG_EXAMPLE_CONNECT_IPV6=y

View File

@ -0,0 +1,12 @@
# The following four lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
# (Not part of the boilerplate)
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
# The path to esp_mqtt_cxx is also added.
set(EXTRA_COMPONENT_DIRS
"../../../../common_components/protocol_examples_common" "../../")
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(mqtt_tcp_cxx)

View File

@ -0,0 +1,2 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- |

View File

@ -0,0 +1,3 @@
idf_component_register(SRCS "mqtt_tcp_example.cpp"
INCLUDE_DIRS ".")
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")

View File

@ -0,0 +1,9 @@
menu "Example Configuration"
config BROKER_URL
string "Broker URL"
default "mqtt://mqtt.eclipseprojects.io"
help
URL of the broker to connect to
endmenu

View File

@ -0,0 +1,86 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
/* C++ MQTT (over TCP) Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include "nvs_flash.h"
#include "protocol_examples_common.h"
#include "esp_log.h"
#include "esp_mqtt.hpp"
#include "esp_mqtt_client_config.hpp"
namespace mqtt = idf::mqtt;
namespace {
constexpr auto *TAG = "MQTT_EXAMPLE";
class MyClient final : public mqtt::Client {
public:
using mqtt::Client::Client;
private:
void on_connected(esp_mqtt_event_handle_t const event) override
{
using mqtt::QoS;
subscribe(messages.get());
subscribe(sent_load.get(), QoS::AtMostOnce);
}
void on_data(esp_mqtt_event_handle_t const event) override
{
if (messages.match(event->topic, event->topic_len)) {
ESP_LOGI(TAG, "Received in the messages topic");
}
}
mqtt::Filter messages{"$SYS/broker/messages/received"};
mqtt::Filter sent_load{"$SYS/broker/load/+/sent"};
};
}
extern "C" 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] IDF version: %s", esp_get_idf_version());
esp_log_level_set("*", ESP_LOG_INFO);
esp_log_level_set("MQTT_CLIENT", ESP_LOG_VERBOSE);
esp_log_level_set("MQTT_EXAMPLE", ESP_LOG_VERBOSE);
esp_log_level_set("TRANSPORT_TCP", ESP_LOG_VERBOSE);
esp_log_level_set("TRANSPORT_SSL", ESP_LOG_VERBOSE);
esp_log_level_set("TRANSPORT", ESP_LOG_VERBOSE);
esp_log_level_set("OUTBOX", ESP_LOG_VERBOSE);
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());
mqtt::BrokerConfiguration broker{
.address = {mqtt::URI{std::string{CONFIG_BROKER_URL}}},
.security = mqtt::Insecure{}
};
mqtt::ClientCredentials credentials{};
mqtt::Configuration config{};
MyClient client{broker, credentials, config};
while (true) {
constexpr TickType_t xDelay = 500 / portTICK_PERIOD_MS;
vTaskDelay(xDelay);
}
}

View File

@ -0,0 +1,8 @@
# SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Unlicense OR CC0-1.0
import pytest
@pytest.mark.esp32
def test_dummy() -> None:
pass

View File

@ -0,0 +1,3 @@
# Enable C++ exceptions and set emergency pool size for exception objects
CONFIG_COMPILER_CXX_EXCEPTIONS=y
CONFIG_COMPILER_CXX_EXCEPTIONS_EMG_POOL_SIZE=1024

View File

@ -0,0 +1,8 @@
version: "0.1.0"
description: esp mqtt cxx
url: https://github.com/espressif/esp-protocols/tree/master/components/esp_mqtt_cxx
dependencies:
espressif/esp-idf-cxx: "^1.0.0-beta"
# Required IDF version
idf:
version: ">=5.0"

View File

@ -0,0 +1,296 @@
/*
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <string_view>
#ifndef __cpp_exceptions
#error MQTT class can only be used when __cpp_exceptions is enabled. Enable CONFIG_COMPILER_CXX_EXCEPTIONS in Kconfig
#endif
#include <optional>
#include <variant>
#include <utility>
#include <memory>
#include <string>
#include "esp_exception.hpp"
#include "esp_mqtt_client_config.hpp"
#include "mqtt_client.h"
namespace idf::mqtt {
constexpr auto *TAG = "mqtt_client_cpp";
struct MQTTException : ESPException {
using ESPException::ESPException;
};
/**
* @brief QoS for publish and subscribe
*
* Sets the QoS as:
* AtMostOnce : Best effort delivery of messages. Message loss can occur.
* AtLeastOnce : Guaranteed delivery of messages. Duplicates can occur.
* ExactlyOnce : Guaranteed delivery of messages exactly once.
*
* @note
* When subscribing to a topic the QoS means the maximum QoS that should be sent to
* client on this topic
*/
enum class QoS { AtMostOnce = 0, AtLeastOnce = 1, ExactlyOnce = 2 };
/**
* @brief Sets if a message must be retained.
*
* Retained messages are delivered to future subscribers that match the topic name.
*
*/
enum class Retain : bool { NotRetained = false, Retained = true };
/**
* @brief Message class template to publish.
*
*/
template <typename T> struct Message {
T data; /*!< Data for publish. Should be a contiguous type*/
QoS qos = QoS::AtLeastOnce; /*!< QoS for the message*/
Retain retain = Retain::NotRetained; /*!< Retention mark for the message.*/
};
/**
* @brief Message type that holds std::string for data
*
*/
using StringMessage = Message<std::string>;
[[nodiscard]] bool filter_is_valid(std::string::const_iterator first, std::string::const_iterator last);
/**
* @brief Filter for mqtt topic subscription.
*
* Topic filter.
*
*/
class Filter {
public:
/**
* @brief Constructs the topic filter from the user filter
* @throws std::domain_error if the filter is invalid.
*
* @param user_filter Filter to be used.
*/
explicit Filter(std::string user_filter);
/**
* @brief Get the filter string used.
*
* @return Reference to the topic filter.
*/
const std::string &get();
/**
* @brief Checks the filter string against a topic name.
*
* @param topic_begin Iterator to the beginning of the sequence.
* @param topic_end Iterator to the end of the sequence.
*
* @return true if the topic name match the filter
*/
[[nodiscard]] bool match(std::string::const_iterator topic_begin, std::string::const_iterator topic_end) const noexcept;
/**
* @brief Checks the filter string against a topic name.
*
* @param topic topic name
*
* @return true if the topic name match the filter
*/
[[nodiscard]] bool match(const std::string &topic) const noexcept;
/**
* @brief Checks the filter string against a topic name.
*
* @param begin Char array with topic name.
* @param size Size of given topic name.
*
* @return true if the topic name match the filter
*/
[[nodiscard]] bool match(char *begin, int size) const noexcept;
private:
/**
* @brief Advance the topic to the next level.
*
* An mqtt topic ends with a /. This function is used to iterate in topic levels.
*
* @return Iterator to the start of the topic.
*/
[[nodiscard]] std::string::const_iterator advance(std::string::const_iterator begin, std::string::const_iterator end) const;
std::string filter;
};
/**
* @brief Message identifier to track delivery.
*
*/
enum class MessageID : int {};
/**
* @brief Base class for MQTT client
*
* Should be inherited to provide event handlers.
*/
class Client {
public:
/**
* @brief Constructor of the client
*
* @param broker Configuration for broker connection
* @param credentials client credentials to be presented to the broker
* @param config Mqtt client configuration
*/
Client(const BrokerConfiguration &broker, const ClientCredentials &credentials, const Configuration &config);
/**
* @brief Constructs Client using the same configuration used for
* `esp_mqtt_client`
* @param config config struct to `esp_mqtt_client`
*/
Client(const esp_mqtt_client_config_t &config);
/**
* @brief Subscribe to topic
*
* @param topic_filter MQTT topic filter
* @param qos QoS subscription, defaulted as QoS::AtLeastOnce
*
* @return Optional MessageID. In case of failure std::nullopt is returned.
*/
std::optional<MessageID> subscribe(const std::string &topic_filter, QoS qos = QoS::AtLeastOnce);
/**
* @brief publish message to topic
*
* @tparam Container Type for data container. Must be a contiguous memory.
* @param topic Topic name
* @param message Message struct containing data, qos and retain
* configuration.
*
* @return Optional MessageID. In case of failure std::nullopt is returned.
*/
template <class Container>
std::optional<MessageID> publish(const std::string &topic, const Message<Container> &message)
{
return publish(topic, std::begin(message.data), std::end(message.data), message.qos, message.retain);
}
/**
* @brief publish message to topic
*
* @tparam InputIt Input data iterator type.
* @param topic Topic name
* @param first, last Iterator pair of data to publish
* @param qos Set qos message
* @param retain Set if message should be retained
*
* @return Optional MessageID. In case of failure std::nullopt is returned.
*/
template <class InputIt>
std::optional<MessageID> publish(const std::string &topic, InputIt first, InputIt last, QoS qos = QoS::AtLeastOnce, Retain retain = Retain::NotRetained)
{
auto size = std::distance(first, last);
auto res = esp_mqtt_client_publish(handler.get(), topic.c_str(), &(*first), size, static_cast<int>(qos),
static_cast<int>(retain));
if (res < 0) {
return std::nullopt;
}
return MessageID{res};
}
virtual ~Client() = default;
protected:
/**
* @brief Helper type to be used as custom deleter for std::unique_ptr.
*/
struct MqttClientDeleter {
void operator()(esp_mqtt_client *client_handler)
{
esp_mqtt_client_destroy(client_handler);
}
};
/**
* @brief Type of the handler for the underlying mqtt_client handler.
* It uses std::unique_ptr for lifetime management
*/
using ClientHandler = std::unique_ptr<esp_mqtt_client, MqttClientDeleter>;
/**
* @brief esp_mqtt_client handler
*
*/
ClientHandler handler;
/**
* @brief Called if there is an error event
*
* @param event mqtt event data
*/
virtual void on_error(const esp_mqtt_event_handle_t event);
/**
* @brief Called if there is an disconnection event
*
* @param event mqtt event data
*/
virtual void on_disconnected(const esp_mqtt_event_handle_t event);
/**
* @brief Called if there is an subscribed event
*
* @param event mqtt event data
*/
virtual void on_subscribed(const esp_mqtt_event_handle_t event);
/**
* @brief Called if there is an unsubscribed event
*
* @param event mqtt event data
*/
virtual void on_unsubscribed(const esp_mqtt_event_handle_t event);
/**
* @brief Called if there is an published event
*
* @param event mqtt event data
*/
virtual void on_published(const esp_mqtt_event_handle_t event);
/**
* @brief Called if there is an before connect event
*
* @param event mqtt event data
*/
virtual void on_before_connect(const esp_mqtt_event_handle_t event);
/**
* @brief Called if there is an connected event
*
* @param event mqtt event data
*
*/
virtual void on_connected(const esp_mqtt_event_handle_t event) = 0;
/**
* @brief Called if there is an data event
*
* @param event mqtt event data
*
*/
virtual void on_data(const esp_mqtt_event_handle_t event) = 0;
private:
static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id,
void *event_data) noexcept;
void init(const esp_mqtt_client_config_t &config);
};
} // namespace idf::mqtt

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