Compare commits

...

173 Commits

Author SHA1 Message Date
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
3330b96b10 websocket: make esp_websocket_client_send_with_opcode a public API 2022-11-07 16:20:34 +04:00
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
55c1223a1e Merge pull request #165 from david-cermak/update/pick_update_prs
Accept some long standing example/demo PRs
2022-11-03 11:05:01 +01:00
0643613eee Merge pull request #172 from gabsuren/feauture/websocket_update_example
websocket: updated example to use local websocket echo server
2022-11-03 11:04:23 +01:00
55dc56462f websocket: updated example to use local websocket echo server 2022-11-03 10:35:14 +04:00
698fb3ae00 Merge pull request #152 from gabsuren/test_apps/mdns_pytest_migration
mDNS: test_app pytest migration
2022-10-26 07:12:07 +02:00
23a537b19b CI: Created a common requirements.txt 2022-10-25 23:59:44 +04:00
aee016d6e4 Examples: using pytest.ini from top level directory 2022-10-25 23:59:33 +04:00
f1ae14f263 update(esp_modem): Bump component version 2022-10-20 16:11:25 +02:00
65c0e0e195 fix(esp_modem): Cleanup custom lib-commands and factory 2022-10-20 16:11:19 +02:00
f71f61ff0a mDNS: test_app pytest migration 2022-10-19 09:23:36 +02:00
652314e73d fix(esp_modem) Add example that reads GNSS info 2022-10-17 20:30:55 +02:00
71a2388acb fix(esp_modem): Examples to configure MQTT Broker 2022-10-17 20:10:10 +02:00
ebc36a3519 fix(esp_modem): Extend pppos example project config 2022-10-17 20:01:45 +02:00
5097065a22 Merge pull request #153 from gabsuren/CI/pre-commit-hooks
CI: pre-commit hook integration (IDFGH-8439)
2022-10-17 19:23:55 +02:00
193ac643e4 Add .git-blame-ignore-revs file 2022-10-17 18:19:49 +02:00
945bd17701 CI: fixing the files to be complient with pre-commit hooks 2022-10-17 18:16:52 +02:00
9d45d505d5 CI: pre-commit hook integration 2022-10-17 18:07:54 +02:00
96fcbc0694 Merge pull request #142 from david-cermak/bugfix/cmux_missed_msc
(esp_modem): Fix switching to CMUX mode for devices that send `MSC`s
2022-10-17 14:43:22 +02:00
6b4767cba0 Merge pull request #163 from gabsuren/CI/asio_update_version
ASIO: Updated package version to "1.14.1~3"
2022-10-17 13:45:41 +02:00
f148c98b13 ASIO: Updated package version to "1.14.1~3" 2022-10-17 09:46:10 +02:00
06103e4bb4 Merge pull request #157 from david-cermak/bugfix/modem_lambda_capture
fix(esp-modem): On read/command callback fixes
2022-10-13 21:25:04 +02:00
c6fc267e5f Merge pull request #162 from gabsuren/CI/asio_package_update
CI: Updated repo-checkout flag to consider submodules (IDFGH-8515)
2022-10-13 21:24:21 +02:00
52b7f001a2 Merge pull request #161 from espressif-abhikroy/esp_modem/power_saving_mode_commands
Quick fix esp_modem: Added modem_console commands for deep-sleep and modem PSM.
2022-10-13 21:23:28 +02:00
cf504ec900 Quick fix esp_modem: Added modem_console commands for deep-sleep and modem PSM. 2022-10-13 20:54:08 +05:30
ab2e08f96c CI: Updated checkout flag to consider submodules 2022-10-13 17:23:43 +02:00
511ed541b8 fix(esp-modem) Make simple_cmux_client example configurable
* extended simple_cmux_client

* add the Descriptions as proposed by @david-cermak

* EXAMPLE_FLOW_CONTROL

Co-authored-by: Franz Höpfinger <krone-trailer@franzhoepfinger.de>
2022-10-13 09:00:16 +02:00
8d0e2aab6b Merge pull request #155 from espressif-abhikroy/esp_modem/power_saving_mode_commands
esp_modem: Added modem_console commands for deep-sleep and modem PSM. (IDFGH-8468)
2022-10-10 19:20:44 +02:00
a02bf05eed fix(esp-modem): Uart Terminal read_cb race 2022-10-10 15:39:09 +02:00
85a2e25093 esp_modem: Added modem_console commands for deep-sleep and modem PSM. 2022-10-10 12:51:47 +05:30
a9b5e66d0f Merge pull request #89 from tore-espressif/feature/esp_modem_usb
Use USB CDC driver from component registry (IDFGH-7816)
2022-10-05 11:58:43 +02:00
988b3f9905 ci: Compile esp_modem examples with USB support 2022-10-05 11:25:20 +02:00
53b59332dc esp_modem: Expand PPPoS example with USB DTE 2022-10-05 11:25:14 +02:00
bf84ae940a esp_modem: Allow USB DTE reconnection
esp_modem_usb_dte component is fetched from IDF component registry.
2022-10-05 11:25:06 +02:00
a89a0ab7a3 esp_modem: Add ConsoleCommand destructor
Commands are registered in Constructor. But there is now of deregistering it
This is needed for correct console re-construction,
for example with USB modem replugging.
2022-10-05 11:14:42 +02:00
fe536e476c esp_modem_get_gnss_power_mode (#136)
Co-authored-by: Franz Höpfinger <krone-trailer@franzhoepfinger.de>
2022-10-05 08:54:41 +02:00
afafcb7c24 Merge pull request #149 from diplfranzhoepfinger/feature/extend_example_modem_console2
remove unused Config Parameters ! (IDFGH-8442)
2022-10-04 10:10:08 +02:00
55b4775ca8 remove unused Config Parameters ! 2022-10-04 09:30:53 +02:00
1c6c610f20 Merge pull request #146 from MicroDev1/master
Prevent crash when hostname is null (IDFGH-8356)
2022-10-01 07:47:38 +02:00
9b48b0a5e0 update(esp_modem): Bump component version 2022-09-30 17:37:11 +02:00
25ac2d98c6 feat(esp_modem): Make some CMUX params compile-time configurable
* bool flag to defragment CMUX payload (useful for devices that send longer messages)
* int flag to force a delay between creating virtual terminals (useful for chatty devices that send some requests)
2022-09-30 17:36:38 +02:00
ce175df376 fix(esp_modem): CMUX to ignore MSC frames
Otherwise it gets confused with DISC frame and causes trouble when entering
CMUX mode (if device sends MSC requests)

Closes https://github.com/espressif/esp-protocols/issues/140
2022-09-30 17:36:38 +02:00
9d9d0db1ee Merge pull request #145 from david-cermak/bugfix/modem_console_flow_ctrl_config
fix(esp_modem): Console example to use configurable flow-ctrl
2022-09-30 16:56:22 +02:00
b704aaa33b Merge pull request #113 from david-cermak/feature/add_slip_example
Add protocols SLIP example
2022-09-30 16:39:30 +02:00
7a21db23ad fix(examples): Update SLIP example with error checks 2022-09-30 16:04:46 +02:00
fcd6f0bb14 feat(examples): Move the slip example to esp-netif folder
And update the slip_modem_get_ipv6_address() to return the address by
copy instead of reference (to employ return value optimizaiton where
possible)
2022-09-30 14:46:13 +02:00
52d7458b99 esp_netif: Migrate SLIP interface to user-space
* Original commit: espressif/esp-idf@83b8556f10
2022-09-30 14:46:13 +02:00
56cb58ced7 build system: re-add -Wno-format as private flag for some example components
* Original commit: espressif/esp-idf@e596c84d49
2022-09-30 14:46:13 +02:00
77a7538a02 docs: changes docs supported targets tables
* Original commit: espressif/esp-idf@c0568611dd
2022-09-30 14:46:13 +02:00
c8d0a13f0e ci: partially enable example build for esp32c2
* Original commit: espressif/esp-idf@f7be540222
2022-09-30 14:46:13 +02:00
582f5b5ff6 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.


* Original commit: espressif/esp-idf@facab8c5a7
2022-09-30 14:46:13 +02:00
06dd536d52 G0: target component (components/esp32*) doesn't depend on driver anymore
* Original commit: espressif/esp-idf@2571aaf3c9
2022-09-30 14:46:13 +02:00
e66b19c414 freertos: Remove legacy data types
This commit removes the usage of all legacy FreeRTOS data types that
are exposed via configENABLE_BACKWARD_COMPATIBILITY. Legacy types can
still be used by enabling CONFIG_FREERTOS_ENABLE_BACKWARD_COMPATIBILITY.


* Original commit: espressif/esp-idf@57fd78f5ba
2022-09-30 14:46:13 +02:00
0ad6cad8b2 Build & config: Remove leftover files from the unsupported "make" build system
* Original commit: espressif/esp-idf@766aa57084
2022-09-30 14:46:13 +02:00
ffa13e4b90 bugfix for ipv6_address_value_issue
Closes https://github.com/espressif/esp-idf/issues/5663


* Original commit: espressif/esp-idf@74236f0b29
2022-09-30 14:46:13 +02:00
0fc1fc6b23 Whitespace: Automated whitespace fixes (large commit)
Apply the pre-commit hook whitespace fixes to all files in the repo.

(Line endings, blank lines at end of file, trailing whitespace)


* Original commit: espressif/esp-idf@66fb5a29bb
2022-09-30 14:46:13 +02:00
f1d1d79daf esp-netif: Fix SLIP interface to start with correct IPv6 addr
Merges https://github.com/espressif/esp-idf/pull/4985


* Original commit: espressif/esp-idf@5dae28069f
2022-09-30 14:46:13 +02:00
36d0d32b35 esp-netif: removing SLIP related events as the slip-modem set state synchronously
* Original commit: espressif/esp-idf@bb9a7356ac
2022-09-30 14:46:13 +02:00
3bf488eb86 esp-netif: SLIP interface refactor to isolate interface from drivers
* Original commit: espressif/esp-idf@1a41545c3e
2022-09-30 14:46:13 +02:00
061885ad23 esp-netif: Added esp_netif slip support, slip_modem component and example
Merges https://github.com/espressif/esp-idf/pull/4985


* Original commit: espressif/esp-idf@266be00254
2022-09-30 14:46:13 +02:00
ab70791625 Merge pull request #147 from tore-espressif/feature/esp_modem/c_error
esp_modem: Allow C API extensions (IDFGH-8368)
2022-09-30 14:25:21 +02:00
62cb235aa9 esp_modem: Allow error handler register in C
C++ API offers interface to register error callback.
C API isn't flexible enough, so we offer conversion function between C++ and C enums.
2022-09-30 11:55:09 +02:00
04c711f757 esp_modem: Move common C definitions in to separate header
Separate header for C API created.
It can be used by C DTE extensions.
2022-09-30 11:41:34 +02:00
467fec5c9b Merge pull request #141 from gabsuren/examples/asio_examples_integrationn
ASIO: Example tests integration
2022-09-30 10:38:38 +02:00
5193ebc6ea ASIO: Example tests integration 2022-09-27 16:09:50 +04:00
3498e86d8b prevent crash when hostname is null 2022-09-21 21:03:07 +05:30
07a347f907 fix(esp_modem): Fix CRLF endlines in examples 2022-09-20 08:20:05 +02:00
d9c9681094 fix(esp_modem): Console example to use configurable flow-ctrl 2022-09-20 08:18:53 +02:00
7310a7a0bc Merge pull request #144 from jonathandreyer/feature/modem_cmux_exit_example
esp_modem: Exit CMUX after end of example
2022-09-20 07:37:21 +02:00
accf9244ca Minor formatting fix and spelling 2022-09-19 17:11:57 +02:00
290197c210 feat(esp-modem): Add exit PPP in example 2022-09-19 17:07:49 +02:00
b8d1e58778 Merge pull request #116 from gabsuren/examples/mdns_examples_integration
mdns: Example tests integration
2022-09-15 11:41:58 +02:00
cc4d33d871 Merge pull request #125 from david-cermak/bugfix/modem_command_race
fix(esp_modem): DTE command race of timeout vs reply's signal
2022-09-14 14:46:06 +02:00
ef0e48a678 extended the modem_console example. (#120)
Co-authored-by: Franz Höpfinger <krone-trailer@franzhoepfinger.de>
Co-authored-by: david-cermak <38914379+david-cermak@users.noreply.github.com>
2022-09-14 14:05:25 +02:00
187ef7676e update(esp_modem): Bump component version 2022-09-14 13:52:00 +02:00
a8714730fb fix(esp_modem): DTE command race of timeout vs reply's signal
Race condtion:
* First command timeouted, but the reply came just after evaluation and
set signal variable to GOT_LINE
* Second command should timeout too, but a consistency check validates
that it timeouted and at the same time GOT_LINE (from previous step) and
throws an exception

STR:
* Revert change in esp_modem_dte.cpp
* Run TEST_CASE("DTE command races", "[esp_modem]")

Closes https://github.com/espressif/esp-protocols/issues/110
2022-09-14 13:50:22 +02:00
d2f519f9e5 Merge pull request #139 from david-cermak/bugfix/modem_get_operator_name_with_act
fix(esp_modem): Make get_operator_name() return also ACT value
2022-09-14 13:46:28 +02:00
a045c1c885 mdns: Example tests integration 2022-09-14 10:58:31 +04:00
543521a220 Merge pull request #123 from thorrak/hygiene/TTL
Replace hardcoded TTL values with named defines (IDFGH-8113)
2022-09-09 15:13:22 +02:00
85be67e708 Merge pull request #126 from jonathandreyer/bugfix/ci-partial-disable
CI: Disable some runs on forks (which are not able to access to secrets) (IDFGH-8152)
2022-09-09 15:11:41 +02:00
5b1b2cce75 Disable specific runs..
.. which are not access to secrets
2022-09-09 14:30:37 +02:00
1029078541 fix(esp_modem): Correct timeouts for certain commands
And adds an explicit timeout parameter to the esp_modem_at()

Closes https://github.com/espressif/esp-protocols/issues/129
2022-09-09 11:23:21 +02:00
0015e5411c fix(esp_modem): Make get_operator_name() return also ACT value
Closes https://github.com/espressif/esp-protocols/issues/128
2022-09-09 10:54:55 +02:00
65b64e1fc1 Merge pull request #138 from tore-espressif/fix/idf_version_check
esp_modem: Fix IDF version resolution (IDFGH-8271)
2022-09-09 10:13:40 +02:00
d07237b2ce esp_modem: Fix IDF version resolution 2022-09-09 09:31:26 +02:00
3c65fde2a7 Merge pull request #117 from david-cermak/bugfix/mdns_add_service_fail_if_nohostname
mdns: Fix add_service() to report error if no hostname has been set
2022-09-08 12:59:08 +02:00
35833d2730 Merge pull request #131 from tore-espressif/feature/esp_modem/err_cb
esp_modem: Expose set_error_cb method
2022-09-08 12:54:13 +02:00
bbb4b7e686 Merge pull request #135 from mahavirj/bugfix/fix_broken_ipv4_only_build
mdns: fix IPV4 only build and also update CI configuration
2022-09-07 22:10:18 +05:30
64e31dae48 ci: fix issue with cryptography package installation 2022-09-07 13:58:10 +05:30
63ce3a5d59 protocol_examples_common: fix build for SPI_ETHERNET case with IDF v5.x 2022-09-07 12:52:39 +05:30
5dd138c883 ci: remove sdkconfig before starting new config based build 2022-09-07 12:52:39 +05:30
088f7ac3f8 mdns: bump up the component version 2022-09-07 09:44:33 +05:30
e079f8ba98 mdns: fix IPV4 only build and also update CI configuration
Earlier commit 48c157bc46 had typo
regarding variable name. This was not caught in CI because IPV6
was not really getting disabled due to an indirect dependency
of `CONFIG_EXAMPLE_CONNECT_IPV6`.

This commit fixes both the problems.
2022-09-07 09:43:46 +05:30
ff2b0734ea Merge pull request #132 from mahavirj/bugfix/build_issue_with_ipv6_disabled
mdns: fix build issue with CONFIG_LWIP_IPV6 disabled
2022-09-06 21:28:33 +05:30
330332a0fb mdns: add test configuration for IPV6 disabled build 2022-09-05 13:24:14 +05:30
48c157bc46 mdns: fix build issue with CONFIG_LWIP_IPV6 disabled 2022-09-02 16:13:17 +05:30
98bf3efeb6 esp_modem: Fix format warnings
Closes https://github.com/espressif/esp-protocols/issues/79
2022-09-02 10:02:34 +02:00
ae8479c77e esp_modem: Expose set_error_cb method 2022-09-02 09:17:49 +02:00
444fae9066 Merge pull request #115 from david-cermak/bugfix/cmux_exit_bg96
fix(esp_modem): Correct exit of CMUX mode
2022-08-29 16:13:31 +02:00
bb4c002841 Replace hardcoded TTL values with named defines
- Replaces hardcoded PTR "half-TTL" with `MDNS_ANSWER_PTR_TTL/2` (defined in mdns_private.h)
- Replaces hardcoded TXT "half-TTL" with `MDNS_ANSWER_TXT_TTL/2` (defined in mdns_private.h)
2022-08-23 08:44:36 -04:00
656ab21c9b mdns: Fix add_service() to report error if no-hostname 2022-08-19 18:47:47 +02:00
2099434b3f fix(esp_modem): Correct exit of CMUX mode
* Fix DISC message's control field (0xFF->0xFE) to keep Poll bit cleared
* Accept UIH resp on DISC for both (0xFF, 0xFE) ignoring P/F bit
* Fix timeout processing when handling DISC message

Closes https://github.com/espressif/esp-protocols/issues/103
2022-08-19 11:45:59 +02:00
8f00fc182a Merge pull request #114 from david-cermak/bugfix/dns-header-bit-order
mdns: fix bit order issue in DNS header flags (updated)
2022-08-19 09:03:04 +02:00
d74c296182 fix(mdns): Example makefile to add only mdns as extra comps 2022-08-18 16:41:38 +02:00
c4e85bd099 mdns: fix bit order issue in DNS header flags
The bit field in the header flags does not match its intended order on
little endian machines. The PR removes the bit field and uses bit
operations instead.
2022-08-18 16:39:38 +02:00
85ba60e405 Merge pull request #88 from david-cermak/bugfix/modem_better_exception_report
fix(esp-modem): Add filename/line info to exception message
2022-08-18 15:27:47 +02:00
89e1bd27b3 fix(esp-modem): Add filename/line info to exception message
This is useful if exceptions are enabled, but caught internally on C++ API boundary
2022-08-18 14:52:21 +02:00
341fcb0f40 Merge pull request #112 from gabsuren/bugfix/updated_esp_modem_package
esp_modem: updated package version to 0.1.19 (IDFGH-8032)
2022-08-18 14:47:47 +02:00
332 changed files with 10090 additions and 5021 deletions

140
.flake8 Normal file
View File

@ -0,0 +1,140 @@
[flake8]
select =
# Full lists are given in order to suppress all errors from other plugins
# Full list of pyflakes error codes:
F401, # module imported but unused
F402, # import module from line N shadowed by loop variable
F403, # 'from module import *' used; unable to detect undefined names
F404, # future import(s) name after other statements
F405, # name may be undefined, or defined from star imports: module
F406, # 'from module import *' only allowed at module level
F407, # an undefined __future__ feature name was imported
F601, # dictionary key name repeated with different values
F602, # dictionary key variable name repeated with different values
F621, # too many expressions in an assignment with star-unpacking
F622, # two or more starred expressions in an assignment (a, *b, *c = d)
F631, # assertion test is a tuple, which are always True
F701, # a break statement outside of a while or for loop
F702, # a continue statement outside of a while or for loop
F703, # a continue statement in a finally block in a loop
F704, # a yield or yield from statement outside of a function
F705, # a return statement with arguments inside a generator
F706, # a return statement outside of a function/method
F707, # an except: block as not the last exception handler
F721, F722, # doctest syntax error syntax error in forward type annotation
F811, # redefinition of unused name from line N
F812, # list comprehension redefines name from line N
F821, # undefined name name
F822, # undefined name name in __all__
F823, # local variable name referenced before assignment
F831, # duplicate argument name in function definition
F841, # local variable name is assigned to but never used
F901, # raise NotImplemented should be raise NotImplementedError
# Full list of pycodestyle violations:
E101, # indentation contains mixed spaces and tabs
E111, # indentation is not a multiple of four
E112, # expected an indented block
E113, # unexpected indentation
E114, # indentation is not a multiple of four (comment)
E115, # expected an indented block (comment)
E116, # unexpected indentation (comment)
E121, # continuation line under-indented for hanging indent
E122, # continuation line missing indentation or outdented
E123, # closing bracket does not match indentation of opening bracket's line
E124, # closing bracket does not match visual indentation
E125, # continuation line with same indent as next logical line
E126, # continuation line over-indented for hanging indent
E127, # continuation line over-indented for visual indent
E128, # continuation line under-indented for visual indent
E129, # visually indented line with same indent as next logical line
E131, # continuation line unaligned for hanging indent
E133, # closing bracket is missing indentation
E201, # whitespace after '('
E202, # whitespace before ')'
E203, # whitespace before ':'
E211, # whitespace before '('
E221, # multiple spaces before operator
E222, # multiple spaces after operator
E223, # tab before operator
E224, # tab after operator
E225, # missing whitespace around operator
E226, # missing whitespace around arithmetic operator
E227, # missing whitespace around bitwise or shift operator
E228, # missing whitespace around modulo operator
E231, # missing whitespace after ',', ';', or ':'
E241, # multiple spaces after ','
E242, # tab after ','
E251, # unexpected spaces around keyword / parameter equals
E261, # at least two spaces before inline comment
E262, # inline comment should start with '# '
E265, # block comment should start with '# '
E266, # too many leading '#' for block comment
E271, # multiple spaces after keyword
E272, # multiple spaces before keyword
E273, # tab after keyword
E274, # tab before keyword
E275, # missing whitespace after keyword
E301, # expected 1 blank line, found 0
E302, # expected 2 blank lines, found 0
E303, # too many blank lines
E304, # blank lines found after function decorator
E305, # expected 2 blank lines after end of function or class
E306, # expected 1 blank line before a nested definition
E401, # multiple imports on one line
E402, # module level import not at top of file
E501, # line too long (82 > 79 characters)
E502, # the backslash is redundant between brackets
E701, # multiple statements on one line (colon)
E702, # multiple statements on one line (semicolon)
E703, # statement ends with a semicolon
E704, # multiple statements on one line (def)
E711, # comparison to None should be 'if cond is None:'
E712, # comparison to True should be 'if cond is True:' or 'if cond:'
E713, # test for membership should be 'not in'
E714, # test for object identity should be 'is not'
E721, # do not compare types, use 'isinstance()'
E722, # do not use bare except, specify exception instead
E731, # do not assign a lambda expression, use a def
E741, # do not use variables named 'l', 'O', or 'I'
E742, # do not define classes named 'l', 'O', or 'I'
E743, # do not define functions named 'l', 'O', or 'I'
E901, # SyntaxError or IndentationError
E902, # IOError
W191, # indentation contains tabs
W291, # trailing whitespace
W292, # no newline at end of file
W293, # blank line contains whitespace
W391, # blank line at end of file
W503, # line break before binary operator
W504, # line break after binary operator
W505, # doc line too long (82 > 79 characters)
W601, # .has_key() is deprecated, use 'in'
W602, # deprecated form of raising exception
W603, # '<>' is deprecated, use '!='
W604, # backticks are deprecated, use 'repr()'
W605, # invalid escape sequence 'x'
W606, # 'async' and 'await' are reserved keywords starting with Python 3.7
# Full list of flake8 violations
E999, # failed to compile a file into an Abstract Syntax Tree for the plugins that require it
# Full list of mccabe violations
C901 # complexity value provided by the user
ignore =
E221, # multiple spaces before operator
E231, # missing whitespace after ',', ';', or ':'
E241, # multiple spaces after ','
W503, # line break before binary operator
W504 # line break after binary operator
max-line-length = 160
show_source = True
statistics = True
exclude =
components/asio/docs/conf_common.py

2
.git-blame-ignore-revs Normal file
View File

@ -0,0 +1,2 @@
# Formating according pre-commit hooks
945bd177011d984b705daee9b895f88212292a42

92
.github/workflows/gcov_analyzer.yml vendored Normal file
View File

@ -0,0 +1,92 @@
name: Code Coverage Analyzer
on: [push, pull_request]
jobs:
gcovr_analyzer_esp_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

@ -3,16 +3,15 @@ name: Host test
on: [push, pull_request]
jobs:
host_test:
name: Build and Test on Host
host_test_esp_modem:
name: esp-modem 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
COMP_DIR: esp-protocols/components/esp_modem
steps:
- name: Checkout esp-protocols
uses: actions/checkout@master
@ -26,11 +25,8 @@ jobs:
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
$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
@ -42,3 +38,26 @@ jobs:
if: always()
with:
files: esp-protocols/components/esp_modem/test/host_test/junit.xml
host_test_mdns:
name: mdns Build and Test on Host
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

40
.github/workflows/pre_commit_check.yml vendored Normal file
View File

@ -0,0 +1,40 @@
name: Check pre-commit rules
on:
pull_request:
types: [opened, reopened, synchronize]
permissions:
contents: read
jobs:
pre_commit_check:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Fetch head and base refs
# This is necessary for pre-commit to check the changes in the PR branch
run: |
git fetch origin ${{ github.base_ref }}:base_ref
git fetch origin pull/${{ github.event.pull_request.number }}/head:pr_ref
- name: Set up Python environment
uses: actions/setup-python@master
with:
python-version: v3.7
- name: Install python packages
run: |
pip install pre-commit
pre-commit install-hooks
- name: Run pre-commit and check for any changes
run: |
echo "Commits being checked:"
git log --oneline --no-decorate base_ref..pr_ref
echo ""
if ! pre-commit run --from-ref base_ref --to-ref pr_ref --show-diff-on-failure ; then
echo ""
echo "::notice::It looks like the commits in this PR have been made without having pre-commit hooks installed."
echo "::notice::Please see https://github.com/espressif/esp-protocols/CONTRIBUTING.md for instructions."
echo ""
exit 1
fi

View File

@ -9,6 +9,8 @@ jobs:
docs_build:
name: Docs-Build-And-Upload
runs-on: ubuntu-latest
# Skip running on forks since it won't have access to secrets
if: github.repository == 'espressif/esp-protocols'
steps:
- name: Checkout esp-protocols
@ -16,6 +18,7 @@ jobs:
with:
persist-credentials: false
fetch-depth: 0
submodules: recursive
- name: Generate docs
run: |

View File

@ -6,9 +6,9 @@ jobs:
build_esp_modem:
strategy:
matrix:
idf_ver: ["latest", "release-v4.1", "release-v4.2", "release-v4.3", "release-v4.4"]
idf_ver: ["latest", "release-v4.1", "release-v4.2", "release-v4.3", "release-v4.4", "release-v5.0"]
example: ["pppos_client", "modem_console", "ap_to_pppos", "simple_cmux_client"]
idf_target: ["esp32"]
idf_target: ["esp32"]
exclude:
- idf_ver: "release-v4.1"
example: modem_console
@ -23,7 +23,7 @@ jobs:
container: espressif/idf:${{ matrix.idf_ver }}
steps:
- name: Checkout esp-protocols
uses: actions/checkout@v3
uses: actions/checkout@master
with:
path: esp-protocols
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
@ -35,39 +35,58 @@ jobs:
cd $GITHUB_WORKSPACE/esp-protocols/components/esp_modem/examples/${{ matrix.example }}
idf.py build
build_mdns:
strategy:
matrix:
idf_ver: ["latest"]
idf_target: ["esp32", "esp32s2", "esp32c3"]
runs-on: ubuntu-20.04
container: espressif/idf:${{ matrix.idf_ver }}
steps:
- name: Checkout esp-protocols
uses: actions/checkout@v3
with:
submodules: recursive
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/mdns/examples/
idf.py set-target ${{ matrix.idf_target }}
cat sdkconfig.ci.eth_def >> sdkconfig.defaults
idf.py build
rm sdkconfig.defaults
cat sdkconfig.ci.eth_custom_netif >> sdkconfig.defaults
idf.py build
rm sdkconfig.defaults
cat sdkconfig.ci.eth_socket >> sdkconfig.defaults
idf.py build
cd $GITHUB_WORKSPACE/esp-protocols/components/mdns/tests/test_apps/
idf.py set-target ${{ matrix.idf_target }}
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"]
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_asio:
strategy:
@ -75,33 +94,56 @@ jobs:
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 }}
env:
TEST_DIR: components/asio/examples
steps:
- name: Checkout esp-protocols
uses: actions/checkout@v3
with:
submodules: recursive
path: esp-protocols
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
cd $GITHUB_WORKSPACE/esp-protocols/components/asio/examples/${{ matrix.example }}
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
build_websocket:
strategy:
matrix:
idf_ver: ["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
@ -111,26 +153,54 @@ jobs:
env:
IDF_TARGET: ${{ matrix.idf_target }}
shell: bash
working-directory: components/esp_websocket_client/examples/
working-directory: ${{ env.TEST_DIR }}
run: |
. ${IDF_PATH}/export.sh
cat sdkconfig.ci >> sdkconfig.defaults
idf.py build
- name: Merge binaries
working-directory: components/esp_websocket_client/examples/build
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@v2
- uses: actions/upload-artifact@v3
with:
name: examples_app_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}
path: components/esp_websocket_client/examples/build/
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:
build_esp_mqtt_cxx:
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
run-target-websocket:
name: Run Websocket Example Test on target
needs: build_websocket
strategy:
@ -141,29 +211,173 @@ jobs:
runs-on:
- self-hosted
- ESP32-ETHERNET-KIT
container:
image: python:3.7-buster
options: --privileged # Privileged mode has access to serial ports
env:
TEST_DIR: components/esp_websocket_client/examples
# 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
- uses: actions/download-artifact@v3
with:
name: examples_app_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}
path: components/esp_websocket_client/examples/build/
path: ${{ env.TEST_DIR }}/build/
- name: Install Python packages
env:
PIP_EXTRA_INDEX_URL: "https://www.piwheels.org/simple"
run: |
pip install -r $GITHUB_WORKSPACE/components/esp_websocket_client/examples/requirements.txt
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
working-directory: ${{ env.TEST_DIR }}
run: |
cp sdkconfig.ci sdkconfig.defaults
pytest --log-cli-level DEBUG --junit-xml=./test_app_results_${{ matrix.idf_target }}_${{ matrix.idf_ver }}.xml --target=${{ matrix.idf_target }}
- uses: actions/upload-artifact@v2
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: examples/*.xml
path: ${{ env.TEST_DIR }}/*.xml
run-target-mdns:
strategy:
matrix:
idf_ver: ["latest"]
idf_target: ["esp32"]
test: [ { app: example, path: "components/mdns/examples" }, { app: unit_test, path: "components/mdns/tests/unit_test" } ]
name: Run mDNS target tests
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@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
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
env:
TEST_DIR: components/asio/examples
# 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@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
build_esp_modem_tests:
strategy:
matrix:
idf_ver: ["latest"]
idf_target: ["esp32c3"]
test: [ { app: pppd, path: test/target }, { app: sim800, 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
run_esp_modem_tests:
strategy:
matrix:
idf_ver: ["latest"]
idf_target: ["esp32c3"]
test: [ { app: pppd, path: test/target }, { app: sim800, path: examples/pppos_client } ]
name: Run esp_modem Test on target
needs: build_esp_modem_tests
runs-on:
- self-hosted
- BrnoRPI-GH006
env:
TEST_DIR: components/esp_modem/${{ matrix.test.path }}
# 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@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 }}

94
.github/workflows/test_apps.yml vendored Normal file
View File

@ -0,0 +1,94 @@
name: Build and Run Test apps
on:
push:
paths:
- 'components/mdns/**'
pull_request:
paths:
- 'components/mdns/**'
jobs:
build_mdns_app:
strategy:
matrix:
idf_ver: ["latest"]
idf_target: ["esp32", "esp32s2", "esp32c3"]
runs-on: ubuntu-20.04
container: espressif/idf:${{ matrix.idf_ver }}
steps:
- name: Checkout esp-protocols
uses: actions/checkout@v3
with:
submodules: recursive
- name: Setup Build Environment
working-directory: components/mdns/tests/test_apps
run: |
. ${IDF_PATH}/export.sh
pip install -r $GITHUB_WORKSPACE/ci/requirements.txt
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
env:
IDF_TARGET: ${{ matrix.idf_target }}
shell: bash
working-directory: components/mdns/tests/test_apps
run: |
. ${IDF_PATH}/export.sh
python $IDF_PATH/tools/ci/ci_build_apps.py . --target ${{ matrix.idf_target }} -vv --pytest-apps
- name: Merge binaries with IDF-${{ matrix.idf_ver }}
working-directory: components/mdns/tests/test_apps/build_${{ matrix.idf_target }}_default
env:
IDF_TARGET: ${{ matrix.idf_target }}
shell: bash
run: |
. ${IDF_PATH}/export.sh
esptool.py --chip ${{ matrix.idf_target }} merge_bin --fill-flash-size 4MB -o flash_image.bin @flash_args
- uses: actions/upload-artifact@v2
with:
name: examples_app_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}
path: |
components/mdns/tests/test_apps/build_${{ matrix.idf_target }}_default/bootloader/bootloader.bin
components/mdns/tests/test_apps/build_${{ matrix.idf_target }}_default/partition_table/partition-table.bin
components/mdns/tests/test_apps/build_${{ matrix.idf_target }}_default/*.bin
components/mdns/tests/test_apps/build_${{ matrix.idf_target }}_default/*.elf
components/mdns/tests/test_apps/build_${{ matrix.idf_target }}_default/flasher_args.json
components/mdns/tests/test_apps/build_${{ matrix.idf_target }}_default/config/sdkconfig.h
components/mdns/tests/test_apps/build_${{ matrix.idf_target }}_default/config/sdkconfig.json
if-no-files-found: error
run-target-mdns-app:
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
- uses: actions/checkout@v3
- uses: actions/download-artifact@v2
with:
name: examples_app_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}
path: components/mdns/tests/test_apps/build
- name: Install Python packages
env:
PIP_EXTRA_INDEX_URL: "https://www.piwheels.org/simple"
run: |
sudo apt-get install -y dnsutils
- name: Download Test apps to target
run: |
python -m esptool --chip ${{ matrix.idf_target }} write_flash 0x0 components/mdns/tests/test_apps/build/flash_image.bin
- name: Run Example Test on target
working-directory: components/mdns/tests/test_apps
run: |
python -m pytest --log-cli-level DEBUG --junit-xml=./examples_results_${{ matrix.idf_target }}_${{ matrix.idf_ver }}.xml --target=${{matrix.idf_target}}
- uses: actions/upload-artifact@v2
if: always()
with:
name: test_apps_results_${{ matrix.idf_target }}_${{ matrix.idf_ver }}
path: components/mdns/tests/test_apps/*.xml

26
.mypy.ini Normal file
View File

@ -0,0 +1,26 @@
[mypy]
# Specifies the Python version used to parse and check the target program
python_version = 3.9
# Disallows defining functions without type annotations or with incomplete type annotations
# True => enforce type annotation in all function definitions
disallow_untyped_defs = True
# Shows a warning when returning a value with type Any from a function declared with a non- Any return type
warn_return_any = True
# Shows errors for missing return statements on some execution paths
warn_no_return = True
# Suppress error messages about imports that cannot be resolved
# True => ignore all import errors
ignore_missing_imports = True
# Disallows defining functions with incomplete type annotations
disallow_incomplete_defs = False
# Directs what to do with imports when the imported module is found as a .py file and not part of the files,
# modules and packages provided on the command line.
# SKIP -> mypy checks only single file, not included imports
follow_imports = skip

52
.pre-commit-config.yaml Normal file
View File

@ -0,0 +1,52 @@
# See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.3.0
hooks:
- id: check-yaml
- id: check-added-large-files
- id: fix-byte-order-marker
- id: check-case-conflict
- id: end-of-file-fixer
- id: trailing-whitespace
- id: mixed-line-ending
- id: debug-statements
- repo: https://github.com/pycqa/flake8
rev: 5.0.4
hooks:
- id: flake8
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v0.981
hooks:
- id: mypy
exclude: >
(?x)^(
.*.py
)$
- repo: https://github.com/myint/unify
rev: v0.5
hooks:
- id: unify
- repo: https://github.com/pre-commit/mirrors-yapf
rev: "v0.32.0"
hooks:
- id: yapf
- repo: https://github.com/pre-commit/mirrors-isort
rev: v5.10.1
hooks:
- id: isort
- repo: https://github.com/myint/eradicate/
rev: v2.1.0
hooks:
- id: eradicate
- repo: https://github.com/espressif/check-copyright/
rev: v1.0.1
hooks:
- id: check-copyright
args: ['--ignore', 'ci/check_copyright_ignore.txt', '--config', 'ci/check_copyright_config.yaml']
- repo: https://github.com/igrr/astyle_py.git
rev: c0013808882a15a0c0c2c1a9b5c903866c53a653
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']

13
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,13 @@
# Information for Contributors
Contributions in the form of pull requests, issue reports, and feature requests are welcome!
## Submitting a PR
- [ ] 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`
- [ ] 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.

View File

@ -0,0 +1,64 @@
# don't modify this section!
DEFAULT:
perform_check: yes # should the check be performed?
# Sections setting this to 'no' don't need to include any other options as they are ignored
# When a file is using a section with the option set to 'no', no checks are performed.
# what licenses (or license expressions) are allowed for files in this section
# when setting this option in a section, you need to list all the allowed licenses
allowed_licenses:
- Apache-2.0
license_for_new_files: Apache-2.0 # license to be used when inserting a new copyright notice
new_notice_c: | # notice for new C, CPP, H, HPP and LD files
/*
* SPDX-FileCopyrightText: {years} Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: {license}
*/
new_notice_python: | # notice for new python files
# SPDX-FileCopyrightText: {years} Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: {license}
# comment lines matching:
# SPDX-FileCopyrightText: year[-year] Espressif Systems
# or
# SPDX-FileContributor: year[-year] Espressif Systems
# are replaced with this template prefixed with the correct comment notation (# or // or *) and SPDX- notation
espressif_copyright: '{years} Espressif Systems (Shanghai) CO LTD'
# this section sets the default license for examples and unit tests of components
examples_and_unit_tests:
include:
- 'components/**/examples/**'
- 'components/**/test/**'
- 'components/**/tests/**'
- 'common_components/**'
allowed_licenses:
- Apache-2.0
- Unlicense
- CC0-1.0
license_for_new_files: Unlicense OR CC0-1.0
asio_component:
include:
- 'components/asio/port/**'
allowed_licenses:
- Apache-2.0
- BSL-1.0
slim_modem_examples:
include:
- 'examples/esp_netif/slip_custom_netif/**'
allowed_licenses:
- Apache-2.0
- Unlicense
- CC0-1.0
ignore:
perform_check: no
include:
- 'components/**/docs/**'
- 'components/esp_modem/port/linux/**'
- 'components/asio/examples/**'
- 'components/mdns/**/esp_system_protocols_linux/**'
- 'common_components/protocol_examples_common/**'

View File

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

8
ci/requirements.txt Normal file
View File

@ -0,0 +1,8 @@
pytest-embedded-serial-esp
pytest-embedded-idf
junit_xml
SimpleWebSocketServer
dpkt
pytest
idf_build_apps
netifaces

View File

@ -26,7 +26,7 @@ esp_err_t get_addr_from_stdin(int port, int sock_type, int *ip_protocol, int *ad
do {
fgets(host_ip, HOST_IP_SIZE, stdin);
len = strlen(host_ip);
} while (len<=1 && host_ip[0] == '\n');
} while (len <= 1 && host_ip[0] == '\n');
host_ip[len - 1] = '\0';
struct addrinfo hints, *addr_list, *cur;
@ -36,16 +36,16 @@ esp_err_t get_addr_from_stdin(int port, int sock_type, int *ip_protocol, int *ad
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = sock_type;
hints.ai_protocol = IPPROTO_TCP;
if( getaddrinfo( host_ip, NULL, &hints, &addr_list ) != 0 ) {
if ( getaddrinfo( host_ip, NULL, &hints, &addr_list ) != 0 ) {
return ESP_FAIL;
}
for( cur = addr_list; cur != NULL; cur = cur->ai_next ) {
for ( cur = addr_list; cur != NULL; cur = cur->ai_next ) {
memcpy(dest_addr, cur->ai_addr, sizeof(*dest_addr));
if (cur->ai_family == AF_INET) {
*ip_protocol = IPPROTO_IP;
*addr_family = AF_INET;
// add port number and return on first IPv4 match
((struct sockaddr_in*)dest_addr)->sin_port = htons(port);
((struct sockaddr_in *)dest_addr)->sin_port = htons(port);
freeaddrinfo( addr_list );
return ESP_OK;
@ -55,8 +55,8 @@ esp_err_t get_addr_from_stdin(int port, int sock_type, int *ip_protocol, int *ad
*ip_protocol = IPPROTO_IPV6;
*addr_family = AF_INET6;
// add port and interface number and return on first IPv6 match
((struct sockaddr_in6*)dest_addr)->sin6_port = htons(port);
((struct sockaddr_in6*)dest_addr)->sin6_scope_id = esp_netif_get_netif_impl_index(EXAMPLE_INTERFACE);
((struct sockaddr_in6 *)dest_addr)->sin6_port = htons(port);
((struct sockaddr_in6 *)dest_addr)->sin6_scope_id = esp_netif_get_netif_impl_index(EXAMPLE_INTERFACE);
freeaddrinfo( addr_list );
return ESP_OK;
}

View File

@ -1,10 +1,11 @@
/* Common functions for protocol examples, to establish Wi-Fi or Ethernet connection.
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
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.
/*
* Common functions for protocol examples, to establish Wi-Fi or Ethernet connection.
*/
#include <string.h>
@ -396,7 +397,9 @@ static esp_netif_t *eth_start(void)
#endif
#elif CONFIG_EXAMPLE_USE_SPI_ETHERNET
gpio_install_isr_service(0);
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
spi_device_handle_t spi_handle = NULL;
#endif
spi_bus_config_t buscfg = {
.miso_io_num = CONFIG_EXAMPLE_ETH_SPI_MISO_GPIO,
.mosi_io_num = CONFIG_EXAMPLE_ETH_SPI_MOSI_GPIO,
@ -414,9 +417,14 @@ static esp_netif_t *eth_start(void)
.spics_io_num = CONFIG_EXAMPLE_ETH_SPI_CS_GPIO,
.queue_size = 20
};
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_EXAMPLE_ETH_SPI_HOST, &devcfg, &spi_handle));
/* dm9051 ethernet driver is based on spi driver */
eth_dm9051_config_t dm9051_config = ETH_DM9051_DEFAULT_CONFIG(spi_handle);
#else
eth_dm9051_config_t dm9051_config = ETH_DM9051_DEFAULT_CONFIG(CONFIG_EXAMPLE_ETH_SPI_HOST, &devcfg);
#endif // ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
dm9051_config.int_gpio_num = CONFIG_EXAMPLE_ETH_SPI_INT_GPIO;
s_mac = esp_eth_mac_new_dm9051(&dm9051_config, &mac_config);
s_phy = esp_eth_phy_new_dm9051(&phy_config);
@ -429,9 +437,13 @@ static esp_netif_t *eth_start(void)
.spics_io_num = CONFIG_EXAMPLE_ETH_SPI_CS_GPIO,
.queue_size = 20
};
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_EXAMPLE_ETH_SPI_HOST, &devcfg, &spi_handle));
/* w5500 ethernet driver is based on spi driver */
eth_w5500_config_t w5500_config = ETH_W5500_DEFAULT_CONFIG(spi_handle);
#else
eth_w5500_config_t w5500_config = ETH_W5500_DEFAULT_CONFIG(CONFIG_EXAMPLE_ETH_SPI_HOST, &devcfg);
#endif // ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
w5500_config.int_gpio_num = CONFIG_EXAMPLE_ETH_SPI_INT_GPIO;
s_mac = esp_eth_mac_new_w5500(&w5500_config, &mac_config);
s_phy = esp_eth_phy_new_w5500(&phy_config);

View File

@ -1,13 +1,14 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
/* Common utilities for socket address input interface:
The API get_addr_from_stdin() is mainly used by socket client examples which read IP address from stdin (if configured).
This option is typically used in the CI, but could be enabled in the project configuration.
In that case this component is used to receive a string that is evaluated and processed to output
socket structures to open a connectio
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.
*/
#pragma once

View File

@ -1,10 +1,11 @@
/* Common functions for protocol examples, to establish Wi-Fi or Ethernet connection.
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
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.
/*
* Common functions for protocol examples, to establish Wi-Fi or Ethernet connection.
*/
#pragma once

View File

@ -1,10 +1,11 @@
/* Common functions for protocol examples, to configure stdin and stdout.
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
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.
/*
* Common functions for protocol examples, to configure stdin and stdout.
*/
#include "protocol_examples_common.h"
@ -19,7 +20,7 @@ esp_err_t example_configure_stdin_stdout(void)
setvbuf(stdin, NULL, _IONBF, 0);
/* Install UART driver for interrupt-driven reads and writes */
ESP_ERROR_CHECK( uart_driver_install( (uart_port_t)CONFIG_ESP_CONSOLE_UART_NUM,
256, 0, 0, NULL, 0) );
256, 0, 0, NULL, 0) );
/* Tell VFS to use UART driver */
esp_vfs_dev_uart_use_driver(CONFIG_ESP_CONSOLE_UART_NUM);
esp_vfs_dev_uart_port_set_rx_line_endings(CONFIG_ESP_CONSOLE_UART_NUM, ESP_LINE_ENDINGS_CR);

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,10 +1,11 @@
from esp_docs.conf_docs import * # noqa: F403,F401
extensions += ['sphinx_copybutton',
# Needed as a trigger for running doxygen
'esp_docs.esp_extensions.dummy_build_system',
'esp_docs.esp_extensions.run_doxygen',
]
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'
@ -14,7 +15,7 @@ html_context['github_user'] = 'espressif'
html_context['github_repo'] = 'esp-protocols'
# Extra options required by sphinx_idf_theme
project_slug = 'esp-idf' # >=5.0
project_slug = 'esp-idf' # >=5.0
versions_url = 'https://github.com/espressif/esp-protocols/docs/docs_versions.js'
idf_targets = ['esp32']

View File

@ -13,7 +13,7 @@ window.onload =(function() {
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');
@ -24,4 +24,3 @@ window.onload =(function() {
})();
</script>" >> html/index.html

View File

@ -1 +1 @@
.. include:: ../../../en/api-reference/protocols/asio.rst
.. include:: ../../../en/api-reference/protocols/asio.rst

View File

@ -1,29 +0,0 @@
# 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.
# -*- coding: utf-8 -*-
from __future__ import print_function, unicode_literals
import re
import ttfw_idf
@ttfw_idf.idf_example_test(env_tag='Example_GENERIC')
def test_examples_asio_chat(env, _): # type: (ttfw_idf.TinyFW.Env, None) -> None
msg = 'asio-chat: received hi'
dut = env.get_dut('asio_chat', 'examples/protocols/asio/asio_chat')
# start the test and expect the client to receive back it's original data
dut.start_app()
dut.expect(re.compile(r'{}'.format('Waiting for input')), timeout=30)
dut.write(msg)
dut.write('exit')
dut.expect(re.compile(r'{}'.format(msg)), timeout=30)
if __name__ == '__main__':
test_examples_asio_chat()

View File

@ -53,14 +53,15 @@ void start_client(void)
#ifdef CONFIG_EXAMPLE_CHAT_SERVER
std::lock_guard<std::mutex> guard(server_ready);
#endif
std::thread t([&io_context]() { try {
io_context.run();
} catch (const std::exception &e) {
ESP_LOGE(TAG, "Exception occured during client thread execution %s", e.what());
}
catch (...) {
ESP_LOGE(TAG, "Unknown exception");
}});
std::thread t([&io_context]() {
try {
io_context.run();
} catch (const std::exception &e) {
ESP_LOGE(TAG, "Exception occured during client thread execution %s", e.what());
} catch (...) {
ESP_LOGE(TAG, "Unknown exception");
}
});
do {
ESP_LOGI(TAG, "CLIENT: Waiting for input");
get_string(line, sizeof(line));
@ -95,14 +96,14 @@ extern "C" void app_main(void)
asio::io_context io_context;
chat_server server(io_context, tcp::endpoint(tcp::v4(), std::atoi(CONFIG_EXAMPLE_CHAT_SERVER_BIND_PORT)));
std::thread t = std::thread([&io_context]() { // Chat server starting here
try {
io_context.run();
} catch (const std::exception &e) {
ESP_LOGE(TAG, "Exception occured during server thread execution %s", e.what());
}
catch (...) {
ESP_LOGE(TAG, "Unknown exception");
}});;
try {
io_context.run();
} catch (const std::exception &e) {
ESP_LOGE(TAG, "Exception occured during server thread execution %s", e.what());
} catch (...) {
ESP_LOGE(TAG, "Unknown exception");
}
});;
#endif
#ifdef CONFIG_EXAMPLE_CHAT_CLIENT
start_client();

View File

@ -15,77 +15,76 @@
#include <cstdlib>
#include <cstring>
class chat_message
{
class chat_message {
public:
static constexpr std::size_t header_length = 4;
static constexpr std::size_t max_body_length = 512;
static constexpr std::size_t header_length = 4;
static constexpr std::size_t max_body_length = 512;
chat_message()
: body_length_(0)
{
}
const char* data() const
{
return data_;
}
char* data()
{
return data_;
}
std::size_t length() const
{
return header_length + body_length_;
}
const char* body() const
{
return data_ + header_length;
}
char* body()
{
return data_ + header_length;
}
std::size_t body_length() const
{
return body_length_;
}
void body_length(std::size_t new_length)
{
body_length_ = new_length;
if (body_length_ > max_body_length)
body_length_ = max_body_length;
}
bool decode_header()
{
char header[header_length + 1] = "";
std::strncat(header, data_, header_length);
body_length_ = std::atoi(header);
if (body_length_ > max_body_length)
chat_message()
: body_length_(0)
{
body_length_ = 0;
return false;
}
return true;
}
void encode_header()
{
char header[header_length + 1] = "";
std::sprintf(header, "%4d", static_cast<int>(body_length_));
std::memcpy(data_, header, header_length);
}
const char *data() const
{
return data_;
}
char *data()
{
return data_;
}
std::size_t length() const
{
return header_length + body_length_;
}
const char *body() const
{
return data_ + header_length;
}
char *body()
{
return data_ + header_length;
}
std::size_t body_length() const
{
return body_length_;
}
void body_length(std::size_t new_length)
{
body_length_ = new_length;
if (body_length_ > max_body_length) {
body_length_ = max_body_length;
}
}
bool decode_header()
{
char header[header_length + 1] = "";
std::strncat(header, data_, header_length);
body_length_ = std::atoi(header);
if (body_length_ > max_body_length) {
body_length_ = 0;
return false;
}
return true;
}
void encode_header()
{
char header[header_length + 1] = "";
std::sprintf(header, "%4d", static_cast<int>(body_length_));
std::memcpy(data_, header, header_length);
}
private:
char data_[header_length + max_body_length];
std::size_t body_length_;
char data_[header_length + max_body_length];
std::size_t body_length_;
};
#endif // CHAT_MESSAGE_HPP

View File

@ -17,107 +17,91 @@
typedef std::deque<chat_message> chat_message_queue;
class chat_client
{
class chat_client {
public:
chat_client(asio::io_context& io_context,
const asio::ip::tcp::resolver::results_type& endpoints)
: io_context_(io_context),
socket_(io_context)
{
do_connect(endpoints);
}
chat_client(asio::io_context &io_context,
const asio::ip::tcp::resolver::results_type &endpoints)
: io_context_(io_context),
socket_(io_context)
{
do_connect(endpoints);
}
void write(const chat_message& msg)
{
asio::post(io_context_,
[this, msg]()
{
bool write_in_progress = !write_msgs_.empty();
write_msgs_.push_back(msg);
if (!write_in_progress)
{
do_write();
}
void write(const chat_message &msg)
{
asio::post(io_context_,
[this, msg]() {
bool write_in_progress = !write_msgs_.empty();
write_msgs_.push_back(msg);
if (!write_in_progress) {
do_write();
}
});
}
}
void close()
{
asio::post(io_context_, [this]() { socket_.close(); });
}
void close()
{
asio::post(io_context_, [this]() {
socket_.close();
});
}
private:
void do_connect(const asio::ip::tcp::resolver::results_type& endpoints)
void do_connect(const asio::ip::tcp::resolver::results_type &endpoints)
{
asio::async_connect(socket_, endpoints,
[this](std::error_code ec, asio::ip::tcp::endpoint)
{
if (!ec)
{
do_read_header();
asio::async_connect(socket_, endpoints,
[this](std::error_code ec, asio::ip::tcp::endpoint) {
if (!ec) {
do_read_header();
}
});
});
}
void do_read_header()
{
asio::async_read(socket_,
asio::buffer(read_msg_.data(), chat_message::header_length),
[this](std::error_code ec, std::size_t /*length*/)
{
if (!ec && read_msg_.decode_header())
{
do_read_body();
asio::async_read(socket_,
asio::buffer(read_msg_.data(), chat_message::header_length),
[this](std::error_code ec, std::size_t /*length*/) {
if (!ec && read_msg_.decode_header()) {
do_read_body();
} else {
socket_.close();
}
else
{
socket_.close();
}
});
});
}
void do_read_body()
{
asio::async_read(socket_,
asio::buffer(read_msg_.body(), read_msg_.body_length()),
[this](std::error_code ec, std::size_t /*length*/)
{
if (!ec)
{
do_read_header();
asio::async_read(socket_,
asio::buffer(read_msg_.body(), read_msg_.body_length()),
[this](std::error_code ec, std::size_t /*length*/) {
if (!ec) {
do_read_header();
} else {
socket_.close();
}
else
{
socket_.close();
}
});
});
}
void do_write()
{
asio::async_write(socket_,
asio::buffer(write_msgs_.front().data(),
write_msgs_.front().length()),
[this](std::error_code ec, std::size_t /*length*/)
{
if (!ec)
{
write_msgs_.pop_front();
if (!write_msgs_.empty())
{
do_write();
}
void do_write()
{
asio::async_write(socket_,
asio::buffer(write_msgs_.front().data(),
write_msgs_.front().length()),
[this](std::error_code ec, std::size_t /*length*/) {
if (!ec) {
write_msgs_.pop_front();
if (!write_msgs_.empty()) {
do_write();
}
} else {
socket_.close();
}
else
{
socket_.close();
}
});
}
});
}
private:
asio::io_context& io_context_;
asio::io_context &io_context_;
asio::ip::tcp::socket socket_;
chat_message read_msg_;
chat_message_queue write_msgs_;

View File

@ -27,176 +27,159 @@ extern std::mutex server_ready;
//----------------------------------------------------------------------
class chat_participant
{
class chat_participant {
public:
virtual ~chat_participant() {}
virtual void deliver(const chat_message& msg) = 0;
virtual ~chat_participant() {}
virtual void deliver(const chat_message &msg) = 0;
};
typedef std::shared_ptr<chat_participant> chat_participant_ptr;
//----------------------------------------------------------------------
class chat_room
{
class chat_room {
public:
void join(chat_participant_ptr participant)
{
participants_.insert(participant);
for (auto msg: recent_msgs_)
participant->deliver(msg);
}
void join(chat_participant_ptr participant)
{
participants_.insert(participant);
for (auto msg : recent_msgs_) {
participant->deliver(msg);
}
}
void leave(chat_participant_ptr participant)
{
participants_.erase(participant);
}
void leave(chat_participant_ptr participant)
{
participants_.erase(participant);
}
void deliver(const chat_message& msg)
{
recent_msgs_.push_back(msg);
while (recent_msgs_.size() > max_recent_msgs)
recent_msgs_.pop_front();
void deliver(const chat_message &msg)
{
recent_msgs_.push_back(msg);
while (recent_msgs_.size() > max_recent_msgs) {
recent_msgs_.pop_front();
}
for (auto participant: participants_)
participant->deliver(msg);
}
for (auto participant : participants_) {
participant->deliver(msg);
}
}
private:
std::set<chat_participant_ptr> participants_;
enum { max_recent_msgs = 100 };
chat_message_queue recent_msgs_;
std::set<chat_participant_ptr> participants_;
enum { max_recent_msgs = 100 };
chat_message_queue recent_msgs_;
};
//----------------------------------------------------------------------
class chat_session
: public chat_participant,
public std::enable_shared_from_this<chat_session>
{
: public chat_participant,
public std::enable_shared_from_this<chat_session> {
public:
chat_session(asio::ip::tcp::socket socket, chat_room& room)
: socket_(std::move(socket)),
room_(room)
{
}
void start()
{
room_.join(shared_from_this());
do_read_header();
}
void deliver(const chat_message& msg)
{
bool write_in_progress = !write_msgs_.empty();
write_msgs_.push_back(msg);
if (!write_in_progress)
chat_session(asio::ip::tcp::socket socket, chat_room &room)
: socket_(std::move(socket)),
room_(room)
{
do_write();
}
}
void start()
{
room_.join(shared_from_this());
do_read_header();
}
void deliver(const chat_message &msg)
{
bool write_in_progress = !write_msgs_.empty();
write_msgs_.push_back(msg);
if (!write_in_progress) {
do_write();
}
}
private:
void do_read_header()
{
auto self(shared_from_this());
asio::async_read(socket_,
asio::buffer(read_msg_.data(), chat_message::header_length),
[this, self](std::error_code ec, std::size_t /*length*/)
{
if (!ec && read_msg_.decode_header())
{
do_read_body();
}
else
{
room_.leave(shared_from_this());
}
});
}
void do_read_header()
{
auto self(shared_from_this());
asio::async_read(socket_,
asio::buffer(read_msg_.data(), chat_message::header_length),
[this, self](std::error_code ec, std::size_t /*length*/) {
if (!ec && read_msg_.decode_header()) {
do_read_body();
} else {
room_.leave(shared_from_this());
}
});
}
void do_read_body()
{
auto self(shared_from_this());
asio::async_read(socket_,
asio::buffer(read_msg_.body(), read_msg_.body_length()),
[this, self](std::error_code ec, std::size_t /*length*/)
{
if (!ec)
{
ESP_LOGD("asio-chat:", "%s", read_msg_.body());
room_.deliver(read_msg_);
do_read_header();
}
else
{
room_.leave(shared_from_this());
}
});
}
void do_read_body()
{
auto self(shared_from_this());
asio::async_read(socket_,
asio::buffer(read_msg_.body(), read_msg_.body_length()),
[this, self](std::error_code ec, std::size_t /*length*/) {
if (!ec) {
ESP_LOGD("asio-chat:", "%s", read_msg_.body());
room_.deliver(read_msg_);
do_read_header();
} else {
room_.leave(shared_from_this());
}
});
}
void do_write()
{
auto self(shared_from_this());
asio::async_write(socket_,
asio::buffer(write_msgs_.front().data(),
write_msgs_.front().length()),
[this, self](std::error_code ec, std::size_t /*length*/)
{
if (!ec)
{
write_msgs_.pop_front();
if (!write_msgs_.empty())
{
do_write();
}
}
else
{
room_.leave(shared_from_this());
}
});
}
void do_write()
{
auto self(shared_from_this());
asio::async_write(socket_,
asio::buffer(write_msgs_.front().data(),
write_msgs_.front().length()),
[this, self](std::error_code ec, std::size_t /*length*/) {
if (!ec) {
write_msgs_.pop_front();
if (!write_msgs_.empty()) {
do_write();
}
} else {
room_.leave(shared_from_this());
}
});
}
asio::ip::tcp::socket socket_;
chat_room& room_;
chat_message read_msg_;
chat_message_queue write_msgs_;
};
asio::ip::tcp::socket socket_;
chat_room &room_;
chat_message read_msg_;
chat_message_queue write_msgs_;
};
//----------------------------------------------------------------------
class chat_server
{
class chat_server {
public:
chat_server(asio::io_context& io_context,
const asio::ip::tcp::endpoint& endpoint)
: acceptor_(io_context, endpoint)
{
do_accept();
}
chat_server(asio::io_context &io_context,
const asio::ip::tcp::endpoint &endpoint)
: acceptor_(io_context, endpoint)
{
do_accept();
}
private:
void do_accept()
{
std::lock_guard<std::mutex> guard(server_ready);
acceptor_.async_accept(
[this](std::error_code ec, asio::ip::tcp::socket socket)
{
if (!ec)
{
std::make_shared<chat_session>(std::move(socket), room_)->start();
}
void do_accept()
{
std::lock_guard<std::mutex> guard(server_ready);
acceptor_.async_accept(
[this](std::error_code ec, asio::ip::tcp::socket socket) {
if (!ec) {
std::make_shared<chat_session>(std::move(socket), room_)->start();
}
do_accept();
});
}
do_accept();
});
}
asio::ip::tcp::acceptor acceptor_;
chat_room room_;
asio::ip::tcp::acceptor acceptor_;
chat_room room_;
};
#endif // CHAT_SERVER_HPP

View File

@ -0,0 +1,16 @@
# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Unlicense OR CC0-1.0
# -*- coding: utf-8 -*-
import re
def test_examples_asio_chat(dut):
msg = 'asio-chat: received hi'
# start the test and expect the client to receive back it's original data
dut.expect(re.compile(b'Waiting for input'), timeout=30)
dut.write(msg)
dut.write('exit')
msg = bytes(msg, encoding='utf8')
dut.expect(re.compile(msg), timeout=30)

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

@ -9,7 +9,7 @@ The application aims to show how to compose async operations using ASIO to build
# Configure and Building example
This example doesn't require any configuration, just build it with
This example doesn't require any configuration, just build it with
```
idf.py build
@ -17,12 +17,12 @@ idf.py build
# Async operations composition and automatic lifetime control
On this example we compose the operation by starting the next step in the chain inside the completion handler of the
previous operation. Also we pass the `Connection` class itself as the parameter of its final handler to be owned by
On this example we compose the operation by starting the next step in the chain inside the completion handler of the
previous operation. Also we pass the `Connection` class itself as the parameter of its final handler to be owned by
the following operation. This is possible due to the control of lifetime by the usage of `std::shared_ptr`.
The control of lifetime of the class, done by `std::shared_ptr` usage, guarantee that the data will be available for
async operations until it's not needed any more. This makes necessary that all of the async operation class must start
The control of lifetime of the class, done by `std::shared_ptr` usage, guarantee that the data will be available for
async operations until it's not needed any more. This makes necessary that all of the async operation class must start
its lifetime as a `std::shared_ptr` due to the usage of `std::enable_shared_from_this`.
@ -48,5 +48,5 @@ its lifetime as a `std::shared_ptr` due to the usage of `std::enable_shared_from
└────►Completion Handler()
The previous diagram shows the process and the life span of each of the tasks in this examples. At each stage the
The previous diagram shows the process and the life span of each of the tasks in this examples. At each stage the
object responsible for the last action inject itself to the completion handler of the next stage for reuse.

View File

@ -5,64 +5,64 @@
(See the README.md file in the upper level 'examples' directory for more information about examples.)
The application aims to show how to connect to a Socks4 proxy using async operations with ASIO. The SOCKS protocol is
briefly described by the diagram below.
The application aims to show how to connect to a Socks4 proxy using async operations with ASIO. The SOCKS protocol is
briefly described by the diagram below.
┌──────┐ ┌─────┐ ┌──────┐
│Client│ │Proxy│ │Target│
└──┬───┘ └──┬──┘ └──┬───┘
│ │ │
│ ╔═╧══════════════╗ │
┌──────┐ ┌─────┐ ┌──────┐
│Client│ │Proxy│ │Target│
└──┬───┘ └──┬──┘ └──┬───┘
│ │ │
│ ╔═╧══════════════╗ │
══════════════════════╪════════════════════════╣ Initialization ╠═══╪════════════════════════════════════════════
│ ╚═╤══════════════╝ │
│ │ │
╔══════════════════╗│ │ │
║We establish a ░║│ Socket Connection │ │
║TCP connection ║│ <─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ > │
║and get a socket ║│ │ │
╚══════════════════╝│ │ │
│ │ │
│ ╔═╧══════════════╗ │
│ ╚═╤══════════════╝ │
│ │ │
╔══════════════════╗│ │ │
║We establish a ░║│ Socket Connection │ │
║TCP connection ║│ <─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ > │
║and get a socket ║│ │ │
╚══════════════════╝│ │ │
│ │ │
│ ╔═╧══════════════╗ │
══════════════════════╪════════════════════════╣ Socks Protocol ╠═══╪════════════════════════════════════════════
│ ╚═╤══════════════╝ │
│ │ │
│ Client Connection Request│ │
│ ─────────────────────────> │
│ │ │
│ │ │
│ ╔════════════╪═══════╤══════════╪════════════════════════════════╗
│ ║ TARGET CONNECTION │ │ ║
│ ╟────────────────────┘ │ ╔═══════════════════╗ ║
│ ║ │ Socket Connection│ ║Proxy establishes ░║ ║
│ ║ │ <─ ─ ─ ─ ─ ─ ─ ─ > ║ TCPconnection ║ ║
│ ║ │ │ ║ with target host ║ ║
│ ╚════════════╪══════════════════╪══╚═══════════════════╝═════════╝
│ │ │
│ Response packet │ │
<───────────────────────── │
│ │ │
│ │ │
│ │ ╔═══════╗ │
│ ╚═╤══════════════╝ │
│ │ │
│ Client Connection Request│ │
│ ─────────────────────────> │
│ │ │
│ │ │
│ ╔════════════╪═══════╤══════════╪════════════════════════════════╗
│ ║ TARGET CONNECTION │ │ ║
│ ╟────────────────────┘ │ ╔═══════════════════╗ ║
│ ║ │ Socket Connection│ ║Proxy establishes ░║ ║
│ ║ │ <─ ─ ─ ─ ─ ─ ─ ─ > ║ TCPconnection ║ ║
│ ║ │ │ ║ with target host ║ ║
│ ╚════════════╪══════════════════╪══╚═══════════════════╝═════════╝
│ │ │
│ Response packet │ │
<───────────────────────── │
│ │ │
│ │ │
│ │ ╔═══════╗ │
══════════════════════╪══════════════════════════╪══╣ Usage ╠═══════╪════════════════════════════════════════════
│ │ ╚═══════╝ │
│ │ │
╔═════════════════╗│ │ │
║Client uses the ░║│ │ │
║ socket opened ║│ │ │
║ with proxy ║│ <─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─>
║to communicate ║│ │ │
║ ║│ │ │
╚═════════════════╝┴───┐ ┌──┴──┐ ┌──┴───┐
│Client│ │Proxy│ │Target│
└──────┘ └─────┘ └──────┘
│ │ ╚═══════╝ │
│ │ │
╔═════════════════╗│ │ │
║Client uses the ░║│ │ │
║ socket opened ║│ │ │
║ with proxy ║│ <─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─>
║to communicate ║│ │ │
║ ║│ │ │
╚═════════════════╝┴───┐ ┌──┴──┐ ┌──┴───┐
│Client│ │Proxy│ │Target│
└──────┘ └─────┘ └──────┘
# Configure and Building example
This example requires the proxy address to be configured. You can do this using the menuconfig option.
Proxy address and port must be configured in order for this example to work.
Proxy address and port must be configured in order for this example to work.
If using Linux ssh can be used as a proxy for testing.
If using Linux ssh can be used as a proxy for testing.
```
ssh -N -v -D 0.0.0.0:1080 localhost
@ -70,4 +70,3 @@ ssh -N -v -D 0.0.0.0:1080 localhost
# Async operations composition and automatic lifetime control
For documentation about the structure of this example look into [async\_request README](../async_request/README.md).

View File

@ -183,7 +183,7 @@ void async_connect(asio::io_context &context, std::string proxy, std::string pro
std::make_shared<Connection>(context)->start(proxy_resolution,
[resolver, host_resolution, completion_handler](std::shared_ptr<Connection> connection) {
auto connect_data = std::make_shared<ConnectionData>(socks4::request::connect, *host_resolution, "");
ESP_LOGI(TAG, "Sending Request to proxy for host connection.");
ESP_LOGI(TAG, "Sending Request to proxy for host connection.");
connection->write_async(connect_data->request.buffers(), [connection, connect_data, completion_handler](std::error_code error, std::size_t bytes_received) {
if (error) {
ESP_LOGE(TAG, "Proxy request write error: %s", error.message().c_str());

View File

@ -20,122 +20,115 @@ namespace socks4 {
const unsigned char version = 0x04;
class request
{
class request {
public:
enum command_type
{
connect = 0x01,
bind = 0x02
};
enum command_type {
connect = 0x01,
bind = 0x02
};
request(command_type cmd, const asio::ip::tcp::endpoint& endpoint,
const std::string& user_id)
: version_(version),
command_(cmd),
user_id_(user_id),
null_byte_(0)
{
// Only IPv4 is supported by the SOCKS 4 protocol.
if (endpoint.protocol() != asio::ip::tcp::v4())
request(command_type cmd, const asio::ip::tcp::endpoint &endpoint,
const std::string &user_id)
: version_(version),
command_(cmd),
user_id_(user_id),
null_byte_(0)
{
throw asio::system_error(
asio::error::address_family_not_supported);
// Only IPv4 is supported by the SOCKS 4 protocol.
if (endpoint.protocol() != asio::ip::tcp::v4()) {
throw asio::system_error(
asio::error::address_family_not_supported);
}
// Convert port number to network byte order.
unsigned short port = endpoint.port();
port_high_byte_ = (port >> 8) & 0xff;
port_low_byte_ = port & 0xff;
// Save IP address in network byte order.
address_ = endpoint.address().to_v4().to_bytes();
}
// Convert port number to network byte order.
unsigned short port = endpoint.port();
port_high_byte_ = (port >> 8) & 0xff;
port_low_byte_ = port & 0xff;
// Save IP address in network byte order.
address_ = endpoint.address().to_v4().to_bytes();
}
std::array<asio::const_buffer, 7> buffers() const
{
return
std::array<asio::const_buffer, 7> buffers() const
{
{
asio::buffer(&version_, 1),
asio::buffer(&command_, 1),
asio::buffer(&port_high_byte_, 1),
asio::buffer(&port_low_byte_, 1),
asio::buffer(address_),
asio::buffer(user_id_),
asio::buffer(&null_byte_, 1)
}
};
}
return {
{
asio::buffer(&version_, 1),
asio::buffer(&command_, 1),
asio::buffer(&port_high_byte_, 1),
asio::buffer(&port_low_byte_, 1),
asio::buffer(address_),
asio::buffer(user_id_),
asio::buffer(&null_byte_, 1)
}
};
}
private:
unsigned char version_;
unsigned char command_;
unsigned char port_high_byte_;
unsigned char port_low_byte_;
asio::ip::address_v4::bytes_type address_;
std::string user_id_;
unsigned char null_byte_;
unsigned char version_;
unsigned char command_;
unsigned char port_high_byte_;
unsigned char port_low_byte_;
asio::ip::address_v4::bytes_type address_;
std::string user_id_;
unsigned char null_byte_;
};
class reply
{
class reply {
public:
enum status_type
{
request_granted = 0x5a,
request_failed = 0x5b,
request_failed_no_identd = 0x5c,
request_failed_bad_user_id = 0x5d
};
reply()
: null_byte_(0),
status_()
{
}
std::array<asio::mutable_buffer, 5> buffers()
{
return
{
{
asio::buffer(&null_byte_, 1),
asio::buffer(&status_, 1),
asio::buffer(&port_high_byte_, 1),
asio::buffer(&port_low_byte_, 1),
asio::buffer(address_)
}
enum status_type {
request_granted = 0x5a,
request_failed = 0x5b,
request_failed_no_identd = 0x5c,
request_failed_bad_user_id = 0x5d
};
}
bool success() const
{
return null_byte_ == 0 && status_ == request_granted;
}
reply()
: null_byte_(0),
status_()
{
}
unsigned char status() const
{
return status_;
}
std::array<asio::mutable_buffer, 5> buffers()
{
return {
{
asio::buffer(&null_byte_, 1),
asio::buffer(&status_, 1),
asio::buffer(&port_high_byte_, 1),
asio::buffer(&port_low_byte_, 1),
asio::buffer(address_)
}
};
}
asio::ip::tcp::endpoint endpoint() const
{
unsigned short port = port_high_byte_;
port = (port << 8) & 0xff00;
port = port | port_low_byte_;
bool success() const
{
return null_byte_ == 0 && status_ == request_granted;
}
asio::ip::address_v4 address(address_);
unsigned char status() const
{
return status_;
}
return asio::ip::tcp::endpoint(address, port);
}
asio::ip::tcp::endpoint endpoint() const
{
unsigned short port = port_high_byte_;
port = (port << 8) & 0xff00;
port = port | port_low_byte_;
asio::ip::address_v4 address(address_);
return asio::ip::tcp::endpoint(address, port);
}
private:
unsigned char null_byte_;
unsigned char status_;
unsigned char port_high_byte_;
unsigned char port_low_byte_;
asio::ip::address_v4::bytes_type address_;
unsigned char null_byte_;
unsigned char status_;
unsigned char port_high_byte_;
unsigned char port_low_byte_;
asio::ip::address_v4::bytes_type address_;
};
} // namespace socks4

View File

@ -1,16 +0,0 @@
from __future__ import unicode_literals
import ttfw_idf
@ttfw_idf.idf_example_test(env_tag='Example_GENERIC', target=['esp32', 'esp32c3'])
def test_examples_asio_ssl(env, extra_data):
dut = env.get_dut('asio_ssl_client_server', 'examples/protocols/asio/ssl_client_server')
dut.start_app()
dut.expect('Reply: GET / HTTP/1.1')
if __name__ == '__main__':
test_examples_asio_ssl()

View File

@ -0,0 +1,7 @@
# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Unlicense OR CC0-1.0
from __future__ import unicode_literals
def test_examples_asio_ssl(dut):
dut.expect('Reply: GET / HTTP/1.1')

View File

@ -1,47 +0,0 @@
import os
import re
import socket
import ttfw_idf
@ttfw_idf.idf_example_test(env_tag='Example_WIFI_Protocols')
def test_examples_protocol_asio_tcp_server(env, extra_data):
"""
steps: |
1. join AP
2. Start server
3. Test connects to server and sends a test message
4. Test evaluates received test message from server
5. Test evaluates received test message on server stdout
"""
test_msg = b'echo message from client to server'
dut1 = env.get_dut('tcp_echo_server', 'examples/protocols/asio/tcp_echo_server', dut_class=ttfw_idf.ESP32DUT)
# check and log bin size
binary_file = os.path.join(dut1.app.binary_path, 'asio_tcp_echo_server.bin')
bin_size = os.path.getsize(binary_file)
ttfw_idf.log_performance('asio_tcp_echo_server_bin_size', '{}KB'.format(bin_size // 1024))
# 1. start test
dut1.start_app()
# 2. get the server IP address
data = dut1.expect(re.compile(r' IPv4 address: ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)'), timeout=30)
# 3. create tcp client and connect to server
dut1.expect('ASIO engine is up and running', timeout=1)
cli = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
cli.settimeout(30)
cli.connect((data[0], 2222))
cli.send(test_msg)
data = cli.recv(1024)
# 4. check the message received back from the server
if (data == test_msg):
print('PASS: Received correct message')
pass
else:
print('Failure!')
raise ValueError('Wrong data received from asi tcp server: {} (expected:{})'.format(data, test_msg))
# 5. check the client message appears also on server terminal
dut1.expect(test_msg.decode())
if __name__ == '__main__':
test_examples_protocol_asio_tcp_server()

View File

@ -1,3 +1,8 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include "asio.hpp"
#include <string>
#include <iostream>
@ -8,78 +13,70 @@
using asio::ip::tcp;
class session
: public std::enable_shared_from_this<session>
{
: public std::enable_shared_from_this<session> {
public:
session(tcp::socket socket)
: socket_(std::move(socket))
{
}
session(tcp::socket socket)
: socket_(std::move(socket))
{
}
void start()
{
do_read();
}
void start()
{
do_read();
}
private:
void do_read()
{
auto self(shared_from_this());
socket_.async_read_some(asio::buffer(data_, max_length),
[this, self](std::error_code ec, std::size_t length)
{
if (!ec)
{
data_[length] = 0;
std::cout << data_ << std::endl;
do_write(length);
}
void do_read()
{
auto self(shared_from_this());
socket_.async_read_some(asio::buffer(data_, max_length),
[this, self](std::error_code ec, std::size_t length) {
if (!ec) {
data_[length] = 0;
std::cout << data_ << std::endl;
do_write(length);
}
});
}
}
void do_write(std::size_t length)
{
auto self(shared_from_this());
asio::async_write(socket_, asio::buffer(data_, length),
[this, self](std::error_code ec, std::size_t length)
{
if (!ec)
{
do_read();
}
void do_write(std::size_t length)
{
auto self(shared_from_this());
asio::async_write(socket_, asio::buffer(data_, length),
[this, self](std::error_code ec, std::size_t length) {
if (!ec) {
do_read();
}
});
}
}
tcp::socket socket_;
enum { max_length = 1024 };
char data_[max_length];
tcp::socket socket_;
enum { max_length = 1024 };
char data_[max_length];
};
class server
{
class server {
public:
server(asio::io_context& io_context, short port)
: acceptor_(io_context, tcp::endpoint(tcp::v4(), port))
{
do_accept();
}
server(asio::io_context &io_context, short port)
: acceptor_(io_context, tcp::endpoint(tcp::v4(), port))
{
do_accept();
}
private:
void do_accept()
{
acceptor_.async_accept(
[this](std::error_code ec, tcp::socket socket)
{
if (!ec)
{
std::make_shared<session>(std::move(socket))->start();
}
void do_accept()
{
acceptor_.async_accept(
[this](std::error_code ec, tcp::socket socket) {
if (!ec) {
std::make_shared<session>(std::move(socket))->start();
}
do_accept();
do_accept();
});
}
}
tcp::acceptor acceptor_;
tcp::acceptor acceptor_;
};

View File

@ -0,0 +1,39 @@
# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Unlicense OR CC0-1.0
import re
import socket
def test_examples_protocol_asio_tcp_server(dut):
"""
steps: |
1. join AP
2. Start server
3. Test connects to server and sends a test message
4. Test evaluates received test message from server
5. Test evaluates received test message on server stdout
"""
test_msg = b'echo message from client to server'
# 2. get the server IP address
data = dut.expect(
re.compile(
b' IPv4 address: ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)'), # noqa: W605
timeout=30).group(1).decode()
# 3. create tcp client and connect to server
dut.expect('ASIO engine is up and running', timeout=1)
cli = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
cli.settimeout(30)
cli.connect((data, 2222))
cli.send(test_msg)
data = cli.recv(1024)
# 4. check the message received back from the server
if (data == test_msg):
print('PASS: Received correct message')
pass
else:
print('Failure!')
raise ValueError(
'Wrong data received from asi tcp server: {} (expected:{})'.format(
data, test_msg))
# 5. check the client message appears also on server terminal
dut.expect(test_msg.decode())

View File

@ -0,0 +1,2 @@
CONFIG_EXAMPLE_CONNECT_WIFI=n
CONFIG_EXAMPLE_CONNECT_ETHERNET=y

View File

@ -1,47 +0,0 @@
import os
import re
import socket
import ttfw_idf
@ttfw_idf.idf_example_test(env_tag='Example_WIFI_Protocols')
def test_examples_protocol_asio_udp_server(env, extra_data):
"""
steps: |
1. join AP
2. Start server
3. Test connects to server and sends a test message
4. Test evaluates received test message from server
5. Test evaluates received test message on server stdout
"""
test_msg = b'echo message from client to server'
dut1 = env.get_dut('udp_echo_server', 'examples/protocols/asio/udp_echo_server', dut_class=ttfw_idf.ESP32DUT)
# check and log bin size
binary_file = os.path.join(dut1.app.binary_path, 'asio_udp_echo_server.bin')
bin_size = os.path.getsize(binary_file)
ttfw_idf.log_performance('asio_udp_echo_server_bin_size', '{}KB'.format(bin_size // 1024))
# 1. start test
dut1.start_app()
# 2. get the server IP address
data = dut1.expect(re.compile(r' IPv4 address: ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)'), timeout=30)
# 3. create tcp client and connect to server
dut1.expect('ASIO engine is up and running', timeout=1)
cli = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
cli.settimeout(30)
cli.connect((data[0], 2222))
cli.send(test_msg)
data = cli.recv(1024)
# 4. check the message received back from the server
if (data == test_msg):
print('PASS: Received correct message')
pass
else:
print('Failure!')
raise ValueError('Wrong data received from asio udp server: {} (expected:{})'.format(data, test_msg))
# 5. check the client message appears also on server terminal
dut1.expect(test_msg.decode())
if __name__ == '__main__':
test_examples_protocol_asio_udp_server()

View File

@ -20,49 +20,43 @@
using asio::ip::udp;
class server
{
class server {
public:
server(asio::io_context& io_context, short port)
: socket_(io_context, udp::endpoint(udp::v4(), port))
{
do_receive();
}
server(asio::io_context &io_context, short port)
: socket_(io_context, udp::endpoint(udp::v4(), port))
{
do_receive();
}
void do_receive()
{
socket_.async_receive_from(
asio::buffer(data_, max_length), sender_endpoint_,
[this](std::error_code ec, std::size_t bytes_recvd)
{
if (!ec && bytes_recvd > 0)
{
data_[bytes_recvd] = 0;
std::cout << data_ << std::endl;
do_send(bytes_recvd);
}
else
{
void do_receive()
{
socket_.async_receive_from(
asio::buffer(data_, max_length), sender_endpoint_,
[this](std::error_code ec, std::size_t bytes_recvd) {
if (!ec && bytes_recvd > 0) {
data_[bytes_recvd] = 0;
std::cout << data_ << std::endl;
do_send(bytes_recvd);
} else {
do_receive();
}
});
}
void do_send(std::size_t length)
{
socket_.async_send_to(
asio::buffer(data_, length), sender_endpoint_,
[this](std::error_code /*ec*/, std::size_t bytes /*bytes_sent*/) {
do_receive();
}
});
}
void do_send(std::size_t length)
{
socket_.async_send_to(
asio::buffer(data_, length), sender_endpoint_,
[this](std::error_code /*ec*/, std::size_t bytes /*bytes_sent*/)
{
do_receive();
});
}
}
private:
udp::socket socket_;
udp::endpoint sender_endpoint_;
enum { max_length = 1024 };
char data_[max_length];
udp::socket socket_;
udp::endpoint sender_endpoint_;
enum { max_length = 1024 };
char data_[max_length];
};
extern "C" void app_main(void)

View File

@ -0,0 +1,37 @@
# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Unlicense OR CC0-1.0
import re
import socket
def test_examples_protocol_asio_udp_server(dut):
"""
steps: |
1. join AP
2. Start server
3. Test connects to server and sends a test message
4. Test evaluates received test message from server
5. Test evaluates received test message on server stdout
"""
test_msg = b'echo message from client to server'
data = dut.expect(
re.compile(
b' IPv4 address: ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)'), # noqa: W605
timeout=30).group(1).decode()
dut.expect('ASIO engine is up and running', timeout=1)
cli = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
cli.settimeout(30)
cli.connect((data, 2222))
cli.send(test_msg)
data = cli.recv(1024)
# 4. check the message received back from the server
if (data == test_msg):
print('PASS: Received correct message')
pass
else:
print('Failure!')
raise ValueError(
'Wrong data received from asio udp server: {} (expected:{})'.
format(data, test_msg))
# 5. check the client message appears also on server terminal
dut.expect(test_msg.decode())

View File

@ -0,0 +1,2 @@
CONFIG_EXAMPLE_CONNECT_WIFI=n
CONFIG_EXAMPLE_CONNECT_ETHERNET=y

View File

@ -1,4 +1,4 @@
version: "1.0.2"
version: "1.14.1~3"
description: ASIO
dependencies:
idf:

View File

@ -19,12 +19,13 @@
namespace asio {
namespace detail {
template <typename Exception>
void throw_exception(const Exception& e)
void throw_exception(const Exception &e)
{
ESP_LOGE("esp32_asio_exception", "Caught exception: %s!", e.what());
abort();
ESP_LOGE("esp32_asio_exception", "Caught exception: %s!", e.what());
abort();
}
}
}
}}
#endif // CONFIG_COMPILER_CXX_EXCEPTIONS==1 && defined (ASIO_NO_EXCEPTIONS)
#endif // _ESP_EXCEPTION_H_

View File

@ -1,5 +1,5 @@
//
// SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
// SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
//
// SPDX-License-Identifier: BSL-1.0
//
@ -16,9 +16,9 @@
#define SSL_OP_SINGLE_DH_USE 0
#define SSL_OP_NO_COMPRESSION 0
#define SSL_OP_NO_SSLv2 0x01000000L
#define SSL_OP_NO_SSLv3 0x02000000L
#define SSL_OP_NO_TLSv1 0x04000000L
#define SSL_OP_NO_SSLv2 0x01000000L
#define SSL_OP_NO_SSLv3 0x02000000L
#define SSL_OP_NO_TLSv1 0x04000000L
#define SSL_VERIFY_NONE 0x00
#define SSL_VERIFY_PEER 0x01
@ -35,12 +35,14 @@ namespace mbedtls {
class engine;
class bio;
class shared_ctx;
} } } // namespace asio::ssl::mbedtls
}
}
} // namespace asio::ssl::mbedtls
//
// Supply OpenSSL types as aliases to mbedtls classes
//
using X509_STORE_CTX=void;
using BIO=asio::ssl::mbedtls::bio;
using SSL_CTX=asio::ssl::mbedtls::shared_ctx;
using SSL=asio::ssl::mbedtls::engine;
using X509_STORE_CTX = void;
using BIO = asio::ssl::mbedtls::bio;
using SSL_CTX = asio::ssl::mbedtls::shared_ctx;
using SSL = asio::ssl::mbedtls::engine;

View File

@ -1,5 +1,5 @@
//
// SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
// SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
//
// SPDX-License-Identifier: BSL-1.0
//
@ -87,7 +87,7 @@ public:
return flags_ & BIO_FLAGS_READ;
}
static std::pair<std::shared_ptr<bio>, std::shared_ptr<bio>> new_pair(const char* error_location)
static std::pair<std::shared_ptr<bio>, std::shared_ptr<bio>> new_pair(const char *error_location)
{
auto b1 = std::shared_ptr<bio>(new (std::nothrow) bio);
auto b2 = std::shared_ptr<bio>(new (std::nothrow) bio);
@ -110,4 +110,6 @@ private:
size_t flags_ {0};
};
} } } // namespace asio::ssl::mbedtls
}
}
} // namespace asio::ssl::mbedtls

View File

@ -1,5 +1,5 @@
//
// SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
// SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
//
// SPDX-License-Identifier: BSL-1.0
//
@ -11,13 +11,13 @@
namespace asio {
namespace error {
const asio::error_category& get_mbedtls_category();
const asio::error_category &get_mbedtls_category();
} // namespace error
namespace ssl {
namespace mbedtls {
void throw_alloc_failure(const char* location);
void throw_alloc_failure(const char *location);
const char *error_message(int error_code);
@ -26,11 +26,10 @@ enum class container {
};
template <typename T, typename... Args>
inline T* create(const char * location, Args &&... args)
inline T *create(const char *location, Args &&... args)
{
T* t = new (std::nothrow) T(std::forward<Args>(args)...);
if (t == nullptr)
{
T *t = new (std::nothrow) T(std::forward<Args>(args)...);
if (t == nullptr) {
throw_alloc_failure(location);
}
return t;
@ -43,12 +42,12 @@ public:
const unsigned char *data(container c) const
{
switch (c) {
case container::CERT:
return static_cast<const unsigned char *>(cert_chain_.data());
case container::CA_CERT:
return static_cast<const unsigned char *>(ca_cert_.data());
case container::PRIVKEY:
return static_cast<const unsigned char *>(private_key_.data());
case container::CERT:
return static_cast<const unsigned char *>(cert_chain_.data());
case container::CA_CERT:
return static_cast<const unsigned char *>(ca_cert_.data());
case container::PRIVKEY:
return static_cast<const unsigned char *>(private_key_.data());
}
return nullptr;
}
@ -56,12 +55,12 @@ public:
std::size_t size(container c) const
{
switch (c) {
case container::CERT:
return cert_chain_.size();
case container::CA_CERT:
return ca_cert_.size();
case container::PRIVKEY:
return private_key_.size();
case container::CERT:
return cert_chain_.size();
case container::CA_CERT:
return ca_cert_.size();
case container::PRIVKEY:
return private_key_.size();
}
return 0;
}
@ -80,11 +79,10 @@ public:
*/
class shared_ctx {
public:
static SSL_CTX *create(const char* location, context_base::method m)
static SSL_CTX *create(const char *location, context_base::method m)
{
auto wrapped = asio::ssl::mbedtls::create<shared_ctx>(location, m);
if (wrapped->ctx_ == nullptr)
{
if (wrapped->ctx_ == nullptr) {
throw_alloc_failure(location);
}
return wrapped;
@ -96,10 +94,12 @@ public:
}
explicit shared_ctx(context_base::method m)
:ctx_(std::shared_ptr<context>(new (std::nothrow) context(m))) { }
: ctx_(std::shared_ptr<context>(new (std::nothrow) context(m))) { }
private:
std::shared_ptr<mbedtls::context> ctx_;
};
} } } // namespace asio::ssl::mbedtls
}
}
} // namespace asio::ssl::mbedtls

View File

@ -23,7 +23,7 @@ const char *error_message(int error_code)
return error_buf;
}
void throw_alloc_failure(const char* location)
void throw_alloc_failure(const char *location)
{
asio::error_code ec( MBEDTLS_ERR_SSL_ALLOC_FAILED, asio::error::get_mbedtls_category());
asio::detail::throw_error(ec, location);
@ -62,7 +62,7 @@ public:
verify_mode_ = mode;
}
bio* ext_bio() const
bio *ext_bio() const
{
return bio_.second.get();
}
@ -95,14 +95,14 @@ public:
int write(const void *buffer, int len)
{
int ret = impl_.write(buffer, len);
state_ = ret == len ? IDLE: WRITING;
state_ = ret == len ? IDLE : WRITING;
return ret;
}
int read(void *buffer, int len)
{
int ret = impl_.read(buffer, len);
state_ = ret == len ? IDLE: READING;
state_ = ret == len ? IDLE : READING;
return ret;
}
@ -117,7 +117,7 @@ private:
static int bio_read(void *ctx, unsigned char *buf, size_t len)
{
auto bio = static_cast<BIO*>(ctx);
auto bio = static_cast<BIO *>(ctx);
int read = bio->read(buf, len);
if (read <= 0 && bio->should_read()) {
return MBEDTLS_ERR_SSL_WANT_READ;
@ -127,7 +127,7 @@ private:
static int bio_write(void *ctx, const unsigned char *buf, size_t len)
{
auto bio = static_cast<BIO*>(ctx);
auto bio = static_cast<BIO *>(ctx);
int written = bio->write(buf, len);
if (written <= 0 && bio->should_write()) {
return MBEDTLS_ERR_SSL_WANT_WRITE;
@ -163,25 +163,27 @@ private:
{
int mode = MBEDTLS_SSL_VERIFY_UNSET;
if (is_client_not_server) {
if (verify_mode_ & SSL_VERIFY_PEER)
if (verify_mode_ & SSL_VERIFY_PEER) {
mode = MBEDTLS_SSL_VERIFY_REQUIRED;
else if (verify_mode_ == SSL_VERIFY_NONE)
} else if (verify_mode_ == SSL_VERIFY_NONE) {
mode = MBEDTLS_SSL_VERIFY_NONE;
}
} else {
if (verify_mode_ & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)
if (verify_mode_ & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
mode = MBEDTLS_SSL_VERIFY_REQUIRED;
else if (verify_mode_ & SSL_VERIFY_PEER)
} else if (verify_mode_ & SSL_VERIFY_PEER) {
mode = MBEDTLS_SSL_VERIFY_OPTIONAL;
else if (verify_mode_ == SSL_VERIFY_NONE)
} else if (verify_mode_ == SSL_VERIFY_NONE) {
mode = MBEDTLS_SSL_VERIFY_NONE;
}
}
return mode;
}
struct impl {
static void print_error(const char* function, int error_code)
static void print_error(const char *function, int error_code)
{
constexpr const char *TAG="mbedtls-engine-impl";
constexpr const char *TAG = "mbedtls-engine-impl";
ESP_LOGE(TAG, "%s() returned -0x%04X", function, -error_code);
ESP_LOGI(TAG, "-0x%04X: %s", -error_code, error_message(error_code));
}
@ -230,7 +232,7 @@ private:
mbedtls_x509_crt_init(&public_cert_);
mbedtls_pk_init(&pk_key_);
mbedtls_x509_crt_init(&ca_cert_);
int ret = mbedtls_ssl_config_defaults(&conf_, is_client_not_server ? MBEDTLS_SSL_IS_CLIENT: MBEDTLS_SSL_IS_SERVER,
int ret = mbedtls_ssl_config_defaults(&conf_, is_client_not_server ? MBEDTLS_SSL_IS_CLIENT : MBEDTLS_SSL_IS_SERVER,
MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT);
if (ret) {
print_error("mbedtls_ssl_config_defaults", ret);
@ -290,4 +292,6 @@ private:
asio::ssl::verify_mode verify_mode_;
};
} } } // namespace asio::ssl::mbedtls
}
}
} // namespace asio::ssl::mbedtls

View File

@ -1,5 +1,5 @@
//
// SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
// SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
//
// SPDX-License-Identifier: BSL-1.0
//
@ -14,30 +14,29 @@ namespace asio {
namespace error {
namespace detail {
class mbedtls_category : public asio::error_category
{
class mbedtls_category : public asio::error_category {
public:
const char* name() const ASIO_ERROR_CATEGORY_NOEXCEPT
const char *name() const ASIO_ERROR_CATEGORY_NOEXCEPT
{
return "asio.ssl";
}
std::string message(int value) const
{
const char* s = asio::ssl::mbedtls::error_message(value);
const char *s = asio::ssl::mbedtls::error_message(value);
return s ? s : "asio.mbedtls error";
}
};
} // namespace detail
const asio::error_category& get_mbedtls_category()
const asio::error_category &get_mbedtls_category()
{
static detail::mbedtls_category instance;
return instance;
}
const asio::error_category& get_ssl_category()
const asio::error_category &get_ssl_category()
{
return asio::error::get_mbedtls_category();
}
@ -47,9 +46,11 @@ const asio::error_category& get_ssl_category()
namespace ssl {
namespace error {
const asio::error_category& get_stream_category()
const asio::error_category &get_stream_category()
{
return asio::error::get_mbedtls_category();
}
} } } // namespace asio::ssl::error
}
}
} // namespace asio::ssl::error

View File

@ -1,5 +1,5 @@
//
// SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
// SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
//
// SPDX-License-Identifier: BSL-1.0
//

View File

@ -1,5 +1,5 @@
//
// SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
// SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
//
// SPDX-License-Identifier: BSL-1.0
//

View File

@ -1,5 +1,5 @@
//
// SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
// SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
//
// SPDX-License-Identifier: BSL-1.0
//

View File

@ -1,5 +1,5 @@
//
// SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
// SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
//
// SPDX-License-Identifier: BSL-1.0
//

View File

@ -1,5 +1,5 @@
//
// SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
// SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
//
// SPDX-License-Identifier: BSL-1.0
//

View File

@ -1,5 +1,5 @@
//
// SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
// SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
//
// SPDX-License-Identifier: BSL-1.0
//

View File

@ -4,7 +4,7 @@
//
// SPDX-License-Identifier: BSL-1.0
//
// SPDX-FileContributor: 2021 Espressif Systems (Shanghai) CO LTD
// SPDX-FileContributor: 2021-2022 Espressif Systems (Shanghai) CO LTD
//
#include "asio/detail/config.hpp"
@ -22,19 +22,19 @@ namespace ssl {
context::context(context::method m)
: handle_(0)
: handle_(0)
{
handle_ = mbedtls::shared_ctx::create("mbedtls-context", m);
set_options(no_compression);
}
context::context(context&& other)
context::context(context &&other)
{
handle_ = other.handle_;
other.handle_ = 0;
}
context& context::operator=(context&& other)
context &context::operator=(context &&other)
{
context tmp(ASIO_MOVE_CAST(context)(*this));
handle_ = other.handle_;
@ -60,14 +60,14 @@ void context::set_options(context::options o)
}
ASIO_SYNC_OP_VOID context::set_options(
context::options o, asio::error_code& ec)
context::options o, asio::error_code &ec)
{
handle_->get()->options_ = o;
ec = asio::error_code();
ASIO_SYNC_OP_VOID_RETURN(ec);
}
void context::add_certificate_authority(const const_buffer& ca)
void context::add_certificate_authority(const const_buffer &ca)
{
asio::error_code ec;
add_certificate_authority(ca, ec);
@ -75,13 +75,13 @@ void context::add_certificate_authority(const const_buffer& ca)
}
ASIO_SYNC_OP_VOID context::add_certificate_authority(
const const_buffer& ca, asio::error_code& ec)
const const_buffer &ca, asio::error_code &ec)
{
handle_->get()->ca_cert_ = ca;
ASIO_SYNC_OP_VOID_RETURN(asio::error_code());
}
void context::use_certificate_chain(const const_buffer& chain)
void context::use_certificate_chain(const const_buffer &chain)
{
asio::error_code ec;
use_certificate_chain(chain, ec);
@ -89,14 +89,14 @@ void context::use_certificate_chain(const const_buffer& chain)
}
ASIO_SYNC_OP_VOID context::use_certificate_chain(
const const_buffer& chain, asio::error_code& ec)
const const_buffer &chain, asio::error_code &ec)
{
handle_->get()->cert_chain_ = chain;
ASIO_SYNC_OP_VOID_RETURN(asio::error_code());
}
void context::use_private_key(
const const_buffer& private_key, context::file_format format)
const const_buffer &private_key, context::file_format format)
{
asio::error_code ec;
use_private_key(private_key, format, ec);
@ -104,8 +104,8 @@ void context::use_private_key(
}
ASIO_SYNC_OP_VOID context::use_private_key(
const const_buffer& private_key, context::file_format format,
asio::error_code& ec)
const const_buffer &private_key, context::file_format format,
asio::error_code &ec)
{
handle_->get()->private_key_ = private_key;
ASIO_SYNC_OP_VOID_RETURN(asio::error_code());

View File

@ -3,7 +3,7 @@
//
// SPDX-License-Identifier: BSL-1.0
//
// SPDX-FileContributor: 2021 Espressif Systems (Shanghai) CO LTD
// SPDX-FileContributor: 2021-2022 Espressif Systems (Shanghai) CO LTD
//
#include "asio/detail/config.hpp"
@ -24,8 +24,8 @@ namespace ssl {
namespace detail {
engine::engine(SSL_CTX* context)
: ssl_(nullptr)
engine::engine(SSL_CTX *context)
: ssl_(nullptr)
{
ssl_ = mbedtls::create<mbedtls::engine>("mbedtls-engine", context->get());
}
@ -35,49 +35,47 @@ engine::~engine()
delete ssl_;
}
SSL* engine::native_handle()
SSL *engine::native_handle()
{
return ssl_;
}
asio::error_code engine::set_verify_mode(
verify_mode v, asio::error_code& ec)
verify_mode v, asio::error_code &ec)
{
ssl_->set_verify_mode(v);
return {};
}
engine::want engine::handshake(
stream_base::handshake_type type, asio::error_code& ec)
stream_base::handshake_type type, asio::error_code &ec)
{
return perform((type == asio::ssl::stream_base::client)
? &engine::do_connect : &engine::do_accept, 0, 0, ec, 0);
}
engine::want engine::shutdown(asio::error_code& ec)
engine::want engine::shutdown(asio::error_code &ec)
{
return perform(&engine::do_shutdown, 0, 0, ec, 0);
}
engine::want engine::write(const asio::const_buffer& data,
asio::error_code& ec, std::size_t& bytes_transferred)
engine::want engine::write(const asio::const_buffer &data,
asio::error_code &ec, std::size_t &bytes_transferred)
{
if (data.size() == 0)
{
if (data.size() == 0) {
ec = asio::error_code();
return engine::want_nothing;
}
return perform(&engine::do_write,
const_cast<void*>(data.data()),
const_cast<void *>(data.data()),
data.size(), ec, &bytes_transferred);
}
engine::want engine::read(const asio::mutable_buffer& data,
asio::error_code& ec, std::size_t& bytes_transferred)
engine::want engine::read(const asio::mutable_buffer &data,
asio::error_code &ec, std::size_t &bytes_transferred)
{
if (data.size() == 0)
{
if (data.size() == 0) {
ec = asio::error_code();
return engine::want_nothing;
}
@ -87,7 +85,7 @@ engine::want engine::read(const asio::mutable_buffer& data,
}
asio::mutable_buffer engine::get_output(
const asio::mutable_buffer& data)
const asio::mutable_buffer &data)
{
int length = ssl_->ext_bio()->read(data.data(), static_cast<int>(data.size()));
@ -96,7 +94,7 @@ asio::mutable_buffer engine::get_output(
}
asio::const_buffer engine::put_input(
const asio::const_buffer& data)
const asio::const_buffer &data)
{
int length = ssl_->ext_bio()->write(data.data(), static_cast<int>(data.size()));
@ -104,23 +102,22 @@ asio::const_buffer engine::put_input(
(length > 0 ? static_cast<std::size_t>(length) : 0));
}
const asio::error_code& engine::map_error_code(
asio::error_code& ec) const
const asio::error_code &engine::map_error_code(
asio::error_code &ec) const
{
// We only want to map the error::eof code.
if (ec != asio::error::eof)
if (ec != asio::error::eof) {
return ec;
}
// If there's data yet to be read, it's an error.
if (ssl_->ext_bio()->wpending())
{
if (ssl_->ext_bio()->wpending()) {
ec = asio::ssl::error::stream_truncated;
return ec;
}
// Otherwise, the peer should have negotiated a proper shutdown.
if (ssl_->shutdown() != 0)
{
if (ssl_->shutdown() != 0) {
ec = asio::ssl::error::stream_truncated;
}
@ -129,47 +126,39 @@ const asio::error_code& engine::map_error_code(
// This is a simplified implementation of a generic ssl io operation
// original implementation using openssl's SSL object is in asio/include/asio/ssl/detail/impl/engine.ipp
engine::want engine::perform(int (engine::* op)(void*, std::size_t),
void* data, std::size_t length, asio::error_code& ec,
std::size_t* bytes_transferred)
engine::want engine::perform(int (engine::* op)(void *, std::size_t),
void *data, std::size_t length, asio::error_code &ec,
std::size_t *bytes_transferred)
{
std::size_t pending_output_before = ssl_->ext_bio()->ctrl_pending();
int result = (this->*op)(data, length);
std::size_t pending_output_after = ssl_->ext_bio()->ctrl_pending();
if (mbedtls::error_codes::is_error(result))
{
if (mbedtls::error_codes::is_error(result)) {
ec = asio::error_code(result, asio::error::get_mbedtls_category());
return pending_output_after > pending_output_before ? want_output : want_nothing;
}
if (result == 0)
{
if (result == 0) {
return pending_output_after > pending_output_before
? want_output : want_nothing;
}
if (result > 0 && bytes_transferred)
if (result > 0 && bytes_transferred) {
*bytes_transferred = static_cast<std::size_t>(result);
}
if (mbedtls::error_codes::want_write(result))
{
if (mbedtls::error_codes::want_write(result)) {
ec = asio::error_code();
return want_output_and_retry;
}
else if (pending_output_after > pending_output_before)
{
} else if (pending_output_after > pending_output_before) {
ec = asio::error_code();
return result > 0 ? want_output : want_output_and_retry;
}
else if (mbedtls::error_codes::want_read(result))
{
} else if (mbedtls::error_codes::want_read(result)) {
ec = asio::error_code();
return want_input_and_retry;
}
else if (ssl_->get_state() == mbedtls::CLOSED)
{
} else if (ssl_->get_state() == mbedtls::CLOSED) {
ec = asio::error::eof;
return want_nothing;
}
@ -178,27 +167,27 @@ engine::want engine::perform(int (engine::* op)(void*, std::size_t),
return want_nothing;
}
int engine::do_accept(void*, std::size_t)
int engine::do_accept(void *, std::size_t)
{
return ssl_->accept();
}
int engine::do_connect(void*, std::size_t)
int engine::do_connect(void *, std::size_t)
{
return ssl_->connect();
}
int engine::do_shutdown(void*, std::size_t)
int engine::do_shutdown(void *, std::size_t)
{
return ssl_->shutdown();
}
int engine::do_read(void* data, std::size_t length)
int engine::do_read(void *data, std::size_t length)
{
return ssl_->read(data, length < INT_MAX ? static_cast<int>(length) : INT_MAX);
}
int engine::do_write(void* data, std::size_t length)
int engine::do_write(void *data, std::size_t length)
{
return ssl_->write(data, length < INT_MAX ? static_cast<int>(length) : INT_MAX);
}

View File

@ -1,5 +1,5 @@
//
// SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
// SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
//
// SPDX-License-Identifier: Apache-2.0
//
@ -17,4 +17,6 @@ asio::detail::shared_ptr<openssl_init_base::do_init> openssl_init_base::instance
return nullptr;
}
} } } // namespace asio::ssl::detail
}
}
} // namespace asio::ssl::detail

View File

@ -90,4 +90,7 @@ build
dependencies.lock
# ignore generated docs
docs/html
docs/html
# esp-idf managed components
**/managed_components/**

View File

@ -48,4 +48,14 @@ if(${target} STREQUAL "linux")
set_target_properties(${COMPONENT_LIB} PROPERTIES COMPILE_FLAGS -Wno-format)
endif()
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")
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,28 @@
menu "esp-modem"
config ESP_MODEM_CMUX_DEFRAGMENT_PAYLOAD
bool "Defragment CMUX messages internally"
default y
help
If enabled (default), the esp-modem automatically defragments CMUX messages
to only pass the completed CMUX message to higher layers.
This is useful for messages in command mode (if they're received fragmented).
It's not a problem for messages in data mode as the upper layer (PPP protocol)
defines message boundaries.
Keep the default to true for most cases (as most devices use simply 1 byte CMUX
length, as the internal Rx buffer of size >= 256 bytes won't overflow)
Set to false if your devices uses 2 byte CMUX payload (e.g. A7672S).
The operation would work without an issue in data mode, but some replies
in command mode might come fragmented in rare cases so might need to retry
AT commands.
config ESP_MODEM_CMUX_DELAY_AFTER_DLCI_SETUP
int "Delay in ms to wait before creating another virtual terminal"
default 0
help
Some devices might need a pause before sending SABM command that creates
virtual terminal. This delay applies only to establishing a CMUX mode.
The typical reason for failing SABM request without a delay is that
some devices (SIM800) send MSC requests just after opening a new DLCI.
endmenu

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

@ -2522,4 +2522,3 @@ DOT_CLEANUP = YES
#DOT_GRAPH_MAX_NODES = 100
#MAX_DOT_GRAPH_DEPTH = 0
#DOT_TRANSPARENT = YES

View File

@ -1,14 +1,14 @@
# ESP MODEM
This component is used to communicate with modems in the command mode (using AT commands), as well as the data mode
(over PPPoS protocol).
(over PPPoS protocol).
The modem device is modeled with a DCE (Data Communication Equipment) object, which is composed of:
* DTE (Data Terminal Equipment), which abstracts the terminal (currently only UART implemented).
* PPP Netif representing a network interface communicating with the DTE using PPP protocol.
* Module abstracting the specific device model and its commands.
```
+-----+
+-----+
| DTE |--+
+-----+ | +-------+
+-->| DCE |
@ -16,17 +16,17 @@ The modem device is modeled with a DCE (Data Communication Equipment) object, wh
| Module|--->| |
+-------+ | |o--- send_commands
+->| |
+------+ | +-------+
| PPP |--+
+------+ | +-------+
| PPP |--+
| netif|------------------> network events
+------+
+------+
```
## Modem components
### DCE
This is the basic operational unit of the esp_modem component, abstracting a specific module in software,
which is basically configured by
which is basically configured by
* the I/O communication media (UART), defined by the DTE configuration
* the specific command library supported by the device model, defined with the module type
* network interface configuration (PPPoS config in lwip)
@ -52,7 +52,7 @@ Users interact with the esp-modem using the DCE's interface, to basically
* Switch between command and data mode to connect to the internet via cellular network.
* Send various commands to the device (e.g. send SMS)
The applications typically register handlers for network events to receive notification on the network availability and
The applications typically register handlers for network events to receive notification on the network availability and
IP address changes.
Common use cases of the esp-modem are also listed as the examples:
@ -69,10 +69,24 @@ after creating multiple virtual terminals, designating some of them solely to da
### DTE's
Currently we support only UART, but modern modules support other communication interfaces, such as USB, SPI.
Currently, we support only UART (and USB as a preview feature), but modern modules support other communication interfaces, such as USB, SPI.
### Other devices
Adding a new device is a must-have requirement for the esp-modem component. Different modules support different commands,
or some commands might have a different implementation. Adding a new device means to provide a new implementation
as a class derived from `GenericModule`, where we could add new commands or modify the existing ones.
## Configuration
Modem abstraction is configurable both compile-time and run-time.
### Component Kconfig
Compile-time configuration is provided using menuconfig. Please check the description for the CMUX mode configuration options.
### Runtime configuration
Is defined using standard configuration structures for `DTE` and `DCE` objects separately. Please find documentation of
* :cpp:class:`esp_modem_dte_config_t`
* :cpp:class:`esp_modem_dce_config_t`

View File

@ -46,4 +46,3 @@ a custom DTE object and supply it into :ref:`the DCE factory<dce_factory>`. The
- Create the DTE which uses the custom Terminal
Please refer to the implementation of the existing UART DTE.

View File

@ -6,7 +6,7 @@ C API Documentation
The C API is very simple and consist of these two basic parts:
- :ref:`lifecycle_api`
- :ref:`lifecycle_api`
- :ref:`modem_commands`
The Typical application workflow is to:
@ -54,4 +54,4 @@ Configuration structures
.. doxygengroup:: ESP_MODEM_CONFIG
:members:
:members:

View File

@ -2,11 +2,6 @@
#
# English Language RTD & Sphinx config file
#
import os
import os.path
import re
import subprocess
import sys
# General information about the project.
project = u'esp-modem'
@ -18,11 +13,12 @@ language = 'en'
extensions = ['breathe', 'recommonmark']
breathe_projects = {'esp_modem': 'xml'}
breathe_default_project = "esp_modem"
breathe_default_project = 'esp_modem'
source_suffix = ['.rst', '.md']
source_parsers = {'.md': 'recommonmark.parser.CommonMarkParser', }
source_parsers = {
'.md': 'recommonmark.parser.CommonMarkParser',
}

View File

@ -41,4 +41,4 @@ Destroy the DCE
---------------
The DCE object is created as ``std::unique_ptr`` by default and as such doesn't have to be explicitly destroyed.
It simply gets destroyed and cleaned-up automatically if the object goes out of the block scope.
It simply gets destroyed and cleaned-up automatically if the object goes out of the block scope.

View File

@ -5,16 +5,16 @@
* Use C++ with additional C API
* Use exceptions
- Use macro wrapper over `try-catch` blocks when exceptions off (use `abort()` if `THROW()`)
- Use macro wrapper over `try-catch` blocks when exceptions off (use `abort()` if `THROW()`)
* Initializes and allocates in the constructor (might throw)
- easier code with exceptions ON, with exceptions OFF alloc/init failures are not treated as runtime error (program aborts)
- break down long initialization in constructor into more private methods
* Implements different devices using inheritance from `GenericModule`, which is the most general implementation of a common modem
- Internally uses templates with device specialization (modeled as `DCE<SpecificModule>`) which could be used as well for some special cases,
- Internally uses templates with device specialization (modeled as `DCE<SpecificModule>`) which could be used as well for some special cases,
such as implantation of a minimal device (ModuleIf), add new AT commands (oOnly in compile time), or using the Module with DTE only (no DCE, no Netif) for sending AT commands without network
## DCE collaboration model
The diagram describes how the DCE class collaborates with DTE, PPP and the device abstraction

View File

@ -115,8 +115,3 @@ Modem types
.. doxygengroup:: ESP_MODEM_TYPES
:members:

View File

@ -18,4 +18,4 @@ Also, to demonstrate the dce_factory functionality, a new `NetDCE_Factory` is im
### Supported IDF versions
This example is only supported from `v4.2`, since is uses NAPT feature.
This example is only supported from `v4.2`, since is uses NAPT feature.

View File

@ -1,24 +1,26 @@
/* softAP to PPPoS Example
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
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.
/*
* softAP to PPPoS Example
*/
#include <string.h>
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_idf_version.h"
#include "nvs_flash.h"
#include "lwip/lwip_napt.h"
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "network_dce.h"
#if ESP_IDF_VERSION_MAJOR >= 5
#include "esp_mac.h"
#include "dhcpserver/dhcpserver.h"
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
#include "esp_mac.h"
#include "dhcpserver/dhcpserver.h"
#endif
#define EXAMPLE_ESP_WIFI_SSID CONFIG_ESP_WIFI_SSID
@ -76,15 +78,15 @@ static esp_err_t set_dhcps_dns(esp_netif_t *netif, uint32_t addr)
return ESP_OK;
}
static void wifi_event_handler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data)
static void wifi_event_handler(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data)
{
if (event_id == WIFI_EVENT_AP_STACONNECTED) {
wifi_event_ap_staconnected_t* event = (wifi_event_ap_staconnected_t*) event_data;
wifi_event_ap_staconnected_t *event = (wifi_event_ap_staconnected_t *) event_data;
ESP_LOGI(TAG, "station "MACSTR" join, AID=%d",
MAC2STR(event->mac), event->aid);
} else if (event_id == WIFI_EVENT_AP_STADISCONNECTED) {
wifi_event_ap_stadisconnected_t* event = (wifi_event_ap_stadisconnected_t*) event_data;
wifi_event_ap_stadisconnected_t *event = (wifi_event_ap_stadisconnected_t *) event_data;
ESP_LOGI(TAG, "station "MACSTR" leave, AID=%d",
MAC2STR(event->mac), event->aid);
}
@ -97,10 +99,10 @@ void wifi_init_softap(void)
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
ESP_EVENT_ANY_ID,
&wifi_event_handler,
NULL,
NULL));
ESP_EVENT_ANY_ID,
&wifi_event_handler,
NULL,
NULL));
wifi_config_t wifi_config = {
.ap = {
@ -161,8 +163,8 @@ void app_main(void)
// Initialize NVS
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);

View File

@ -1,10 +1,11 @@
/* softAP to PPPoS Example (network_dce)
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
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.
/*
* softAP to PPPoS Example (network_dce)
*/
#include <string.h>

View File

@ -1,10 +1,11 @@
/* softAP to PPPoS Example (network_dce)
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
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.
/*
* softAP to PPPoS Example (network_dce)
*/
#include "cxx_include/esp_modem_dte.hpp"
@ -92,8 +93,9 @@ public:
bool check_signal()
{
int rssi, ber;
if (dce_commands::get_signal_quality(dte.get(), rssi, ber) != command_result::OK)
if (dce_commands::get_signal_quality(dte.get(), rssi, ber) != command_result::OK) {
return false;
}
return rssi != 99 && rssi > 5;
}
@ -215,4 +217,4 @@ extern "C" bool modem_check_signal()
return dce->get_module()->check_signal();
}
}
}

View File

@ -1,10 +1,11 @@
/* softAP to PPPoS Example (network_dce)
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
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.
/*
* softAP to PPPoS Example (network_dce)
*/
#pragma once

View File

@ -20,4 +20,4 @@ over PPPoS, i.e. over the modem serial line.
### Supported IDF versions
This example (using the default CMake IDF build system) is only supported from `v4.4`, since is uses `idf.py`'s linux target.
This example (using the default CMake IDF build system) is only supported from `v4.4`, since is uses `idf.py`'s linux target.

View File

@ -1,3 +1,8 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <memory>
#include <cassert>
#include <unistd.h>
@ -61,7 +66,7 @@ int main()
bool pin_ok = true;
if (dce->read_pin(pin_ok) == command_result::OK && !pin_ok) {
throw_if_false(dce->set_pin(CONFIG_EXAMPLE_SIM_PIN) == command_result::OK, "Cannot set PIN!");
ESP_MODEM_THROW_IF_FALSE(dce->set_pin(CONFIG_EXAMPLE_SIM_PIN) == command_result::OK, "Cannot set PIN!");
usleep(1000000);
}
std::string str;
@ -79,4 +84,4 @@ int main()
usleep(15'000'000);
esp_netif_destroy(tun_netif);
}
}

View File

@ -2,15 +2,5 @@
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
set(EXTRA_COMPONENT_DIRS "../..")
include($ENV{IDF_PATH}/tools/cmake/version.cmake)
if("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_GREATER_EQUAL "4.4")
if(("${IDF_TARGET}" STREQUAL "esp32s2") OR ("${IDF_TARGET}" STREQUAL "esp32s3"))
list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/examples/peripherals/usb/host/cdc/common")
endif()
endif()
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(modem-console)

View File

@ -8,4 +8,3 @@ PROJECT_NAME := modem-console
EXTRA_COMPONENT_DIRS = $(IDF_PATH)/examples/common_components/protocol_examples_common
include $(IDF_PATH)/make/project.mk

View File

@ -20,10 +20,14 @@ For USB enabled targets (ESP32-S2 and ESP32-S3), it is possible to connect to th
1. In menuconfig, navigate to `Example Configuration->Type of serial connection to the modem` and choose `USB`.
2. Connect the modem USB signals to pin 19 (DATA-) and 20 (DATA+) on your ESP chip.
USB example uses Quactel BG96 modem device.
USB example uses Quactel BG96 modem device. BG96 needs a positive pulse on its PWK pin to boot-up.
This example supports USB modem hot-plugging and reconnection. There is one limitation coming from esp_console component:
When esp_console REPL is being destroyed (after USB mode disconnection or after `exit` command), it will block on UART read.
You must send a character to it (via idf.py monitor), so it unblocks and properly exits.
### Supported IDF versions
This example is only supported from `v4.2`, due to support of the console repl mode.
USB example is supported from `v4.4`.
USB example is supported from `v4.4`.

View File

@ -1,19 +0,0 @@
include($ENV{IDF_PATH}/tools/cmake/version.cmake)
idf_build_get_property(target IDF_TARGET)
# USB is supported on S2 and S3 targets and IDF version >= 4.4
if("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_GREATER_EQUAL "4.4")
if(("${target}" STREQUAL "esp32s2") OR ("${target}" STREQUAL "esp32s3"))
idf_component_register(SRCS "esp_modem_usb.cpp" "esp_modem_usb_api_target.cpp"
REQUIRES cdc_acm_host esp_modem
REQUIRED_IDF_TARGETS esp32s2 esp32s3
PRIV_INCLUDE_DIRS "private_include"
INCLUDE_DIRS "include")
set_target_properties(${COMPONENT_LIB} PROPERTIES
CXX_STANDARD 17
)
endif()
endif()

View File

@ -1,191 +0,0 @@
// Copyright 2021 Espressif Systems (Shanghai) CO LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "esp_log.h"
#include "esp_modem_config.h"
#include "esp_modem_usb_config.h"
#include "cxx_include/esp_modem_dte.hpp"
#include "usb/usb_host.h"
#include "usb/cdc_acm_host.h"
#include "sdkconfig.h"
#include "usb_terminal.hpp"
static const char *TAG = "usb_terminal";
/**
* @brief USB Host task
*
* This task is created only if install_usb_host is set to true in DTE configuration.
* In case the user doesn't want in install USB Host driver here, he must install it before creating UsbTerminal object.
*
* @param arg Unused
*/
void usb_host_task(void *arg)
{
while (1) {
// Start handling system events
uint32_t event_flags;
usb_host_lib_handle_events(portMAX_DELAY, &event_flags);
if (event_flags & USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS) {
ESP_LOGD(TAG, "No more clients: clean up\n");
usb_host_device_free_all();
}
if (event_flags & USB_HOST_LIB_EVENT_FLAGS_ALL_FREE) {
ESP_LOGD(TAG, "All free: uninstall USB lib\n");
break;
}
}
// Clean up USB Host
vTaskDelay(10); // Short delay to allow clients clean-up
usb_host_lib_handle_events(0, NULL); // Make sure there are now pending events
usb_host_uninstall();
vTaskDelete(NULL);
}
namespace esp_modem {
class UsbTerminal : public Terminal, private CdcAcmDevice {
public:
explicit UsbTerminal(const esp_modem_dte_config *config)
{
const struct esp_modem_usb_term_config* usb_config = (struct esp_modem_usb_term_config*)(config->extension_config);
// Install USB Host driver
if (usb_config->install_usb_host) {
const usb_host_config_t host_config = {
.skip_phy_setup = false,
.intr_flags = ESP_INTR_FLAG_LEVEL1,
};
throw_if_esp_fail(usb_host_install(&host_config), "USB Host install failed");
ESP_LOGD(TAG, "USB Host installed");
throw_if_false(pdTRUE == xTaskCreatePinnedToCore(usb_host_task, "usb_host", 4096, NULL, config->task_priority + 1, NULL, usb_config->xCoreID), "USB host task failed");
}
// Install CDC-ACM driver
const cdc_acm_host_driver_config_t esp_modem_cdc_acm_driver_config = {
.driver_task_stack_size = config->task_stack_size,
.driver_task_priority = config->task_priority,
.xCoreID = (BaseType_t)usb_config->xCoreID
};
// Silently continue of error: CDC-ACM driver might be already installed
cdc_acm_host_install(&esp_modem_cdc_acm_driver_config);
// Open CDC-ACM device
const cdc_acm_host_device_config_t esp_modem_cdc_acm_device_config = {
.connection_timeout_ms = usb_config->timeout_ms,
.out_buffer_size = config->dte_buffer_size,
.event_cb = handle_notif,
.data_cb = handle_rx,
.user_arg = this
};
if (usb_config->cdc_compliant) {
throw_if_esp_fail(this->CdcAcmDevice::open(usb_config->vid, usb_config->pid,
usb_config->interface_idx, &esp_modem_cdc_acm_device_config),
"USB Device open failed");
} else {
throw_if_esp_fail(this->CdcAcmDevice::open_vendor_specific(usb_config->vid, usb_config->pid,
usb_config->interface_idx, &esp_modem_cdc_acm_device_config),
"USB Device open failed");
}
};
~UsbTerminal()
{
this->CdcAcmDevice::close();
};
void start() override
{
return;
}
void stop() override
{
return;
}
int write(uint8_t *data, size_t len) override
{
ESP_LOG_BUFFER_HEXDUMP(TAG, data, len, ESP_LOG_DEBUG);
if (this->CdcAcmDevice::tx_blocking(data, len) != ESP_OK) {
return -1;
}
return len;
}
int read(uint8_t *data, size_t len) override
{
// This function should never be called. UsbTerminal provides data through Terminal::on_read callback
ESP_LOGW(TAG, "Unexpected call to UsbTerminal::read function");
return -1;
}
private:
UsbTerminal() = delete;
UsbTerminal(const UsbTerminal &copy) = delete;
UsbTerminal &operator=(const UsbTerminal &copy) = delete;
bool operator== (const UsbTerminal &param) const = delete;
bool operator!= (const UsbTerminal &param) const = delete;
static void handle_rx(uint8_t *data, size_t data_len, void *user_arg)
{
ESP_LOG_BUFFER_HEXDUMP(TAG, data, data_len, ESP_LOG_DEBUG);
UsbTerminal *this_terminal = static_cast<UsbTerminal *>(user_arg);
if (data_len > 0 && this_terminal->on_read) {
this_terminal->on_read(data, data_len);
} else {
ESP_LOGD(TAG, "Unhandled RX data");
}
}
static void handle_notif(cdc_acm_dev_hdl_t cdc_hdl, const cdc_acm_host_dev_event_data_t *event, void *user_ctx)
{
UsbTerminal *this_terminal = static_cast<UsbTerminal *>(user_ctx);
switch (event->type) {
// Notifications like Ring, Rx Carrier indication or Network connection indication are not relevant for USB terminal
case CDC_ACM_HOST_NETWORK_CONNECTION:
case CDC_ACM_HOST_SERIAL_STATE:
break;
case CDC_ACM_HOST_DEVICE_DISCONNECTED:
ESP_LOGW(TAG, "USB terminal disconnected");
cdc_acm_host_close(cdc_hdl);
if (this_terminal->on_error) {
this_terminal->on_error(terminal_error::UNEXPECTED_CONTROL_FLOW);
}
break;
case CDC_ACM_HOST_ERROR:
ESP_LOGE(TAG, "Unexpected CDC-ACM error: %d.", event->data.error);
if (this_terminal->on_error) {
this_terminal->on_error(terminal_error::UNEXPECTED_CONTROL_FLOW);
}
break;
default:
abort();
}
};
};
std::unique_ptr<Terminal> create_usb_terminal(const esp_modem_dte_config *config)
{
TRY_CATCH_RET_NULL(
return std::make_unique<UsbTerminal>(config);
)
}
} // namespace esp_modem

View File

@ -1,32 +0,0 @@
// Copyright 2021-2022 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "usb_terminal.hpp"
#include "cxx_include/esp_modem_api.hpp"
#include "cxx_include/esp_modem_netif.hpp"
#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
static const char *TAG = "modem_usb_api_target";
#endif
namespace esp_modem {
std::shared_ptr<DTE> create_usb_dte(const dte_config *config)
{
TRY_CATCH_RET_NULL(
auto term = create_usb_terminal(config);
return std::make_shared<DTE>(config, std::move(term));
)
}
}

View File

@ -1,29 +0,0 @@
// Copyright 2021-2022 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include "cxx_include/esp_modem_dce.hpp"
#include "cxx_include/esp_modem_dce_module.hpp"
namespace esp_modem {
/**
* @brief Create USB DTE
*
* @param config DTE configuration
* @return shared ptr to DTE on success
* nullptr on failure (either due to insufficient memory or wrong dte configuration)
* if exceptions are disabled the API abort()'s on error
*/
std::shared_ptr<DTE> create_usb_dte(const dte_config *config);
}

View File

@ -1,63 +0,0 @@
// Copyright 2021-2022 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include <stdint.h>
#include <stdbool.h>
/**
* @brief USB configuration structure
* @see USB host CDC-ACM driver documentation for details about interfaces settings
*/
struct esp_modem_usb_term_config {
uint16_t vid; /*!< Vendor ID of the USB device */
uint16_t pid; /*!< Product ID of the USB device */
int interface_idx; /*!< USB Interface index that will be used */
uint32_t timeout_ms; /*!< Time for a USB modem to connect to USB host. 0 means wait forever. */
int xCoreID; /*!< Core affinity of created tasks: CDC-ACM driver task and optional USB Host task */
bool cdc_compliant; /*!< Treat the USB device as CDC-compliant. Read CDC-ACM driver documentation for more details */
bool install_usb_host; /*!< Flag whether USB Host driver should be installed */
};
/**
* @brief ESP Mode USB DTE Default Configuration
*
* @param[in] _usb_config esp_modem_usb_term_config configuration structure. Can be obtained by ESP_MODEM_DEFAULT_USB_CONFIG
*
*/
#define ESP_MODEM_DTE_DEFAULT_USB_CONFIG(_usb_config) \
{ \
.dte_buffer_size = 512, \
.task_stack_size = 4096, \
.task_priority = 5, \
.extension_config = &_usb_config \
}
/**
* @brief ESP Modem USB Default Configuration
*
* @param[in] _vid USB Vendor ID
* @param[in] _pid USB Product ID
* @see USB host CDC-ACM driver documentation for details about interfaces settings
*/
#define ESP_MODEM_DEFAULT_USB_CONFIG(_vid, _pid) \
{ \
.vid = _vid, \
.pid = _pid, \
.interface_idx = 0, \
.timeout_ms = 0, \
.xCoreID = 0, \
.cdc_compliant = false, \
.install_usb_host = true \
}

View File

@ -1,51 +0,0 @@
// Copyright 2021 Espressif Systems (Shanghai) CO LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include "cxx_include/esp_modem_dte.hpp"
#include "sdkconfig.h"
#include "esp_log.h"
struct esp_modem_dte_config;
// Copy-pasted from esp_modem/private_include/exception_stub.hpp
#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
#define TRY_CATCH_OR_DO(block, action) \
try { block \
} catch (std::bad_alloc& e) { \
ESP_LOGE(TAG, "Out of memory"); \
action; \
} catch (::esp_modem::esp_err_exception& e) { \
esp_err_t err = e.get_err_t(); \
ESP_LOGE(TAG, "%s: Exception caught with ESP err_code=%d", __func__, err); \
ESP_LOGE(TAG, "%s", e.what()); \
action; \
}
#define TRY_CATCH_RET_NULL(block) TRY_CATCH_OR_DO(block, return nullptr)
#else
#define TRY_CATCH_OR_DO(block, action) \
block
#define TRY_CATCH_RET_NULL(block) \
block
#endif
namespace esp_modem {
std::unique_ptr<Terminal> create_usb_terminal(const esp_modem_dte_config *config);
} // namespace esp_modem

View File

@ -2,6 +2,6 @@ idf_component_register(SRCS "modem_console_main.cpp"
"console_helper.cpp"
"httpget_handle.c"
"ping_handle.c"
REQUIRES console esp_http_client nvs_flash esp_modem esp_modem_usb_dte
REQUIRES console esp_http_client nvs_flash
INCLUDE_DIRS ".")
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")

View File

@ -1,17 +1,172 @@
menu "Example Configuration"
choice EXAMPLE_SERIAL_CONFIG
prompt "Type of serial connection to the modem"
default EXAMPLE_SERIAL_CONFIG_UART
config EXAMPLE_SERIAL_CONFIG_UART
bool "UART"
help
Connect to modem via UART.
config EXAMPLE_SERIAL_CONFIG_USB
bool "USB"
depends on IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
help
Connect to modem via USB (CDC-ACM class). For IDF version >= 4.4.
endchoice
endmenu
menu "Example Configuration"
choice EXAMPLE_SERIAL_CONFIG
prompt "Type of serial connection to the modem"
default EXAMPLE_SERIAL_CONFIG_UART
config EXAMPLE_SERIAL_CONFIG_UART
bool "UART"
help
Connect to modem via UART.
config EXAMPLE_SERIAL_CONFIG_USB
bool "USB"
depends on IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
help
Connect to modem via USB (CDC-ACM class). For IDF version >= 4.4.
endchoice
choice EXAMPLE_MODEM_DEVICE
depends on EXAMPLE_SERIAL_CONFIG_UART
prompt "Choose supported modem device (DCE)"
default EXAMPLE_MODEM_DEVICE_BG96
help
Select modem device connected to the ESP DTE.
config EXAMPLE_MODEM_DEVICE_SHINY
bool "SHINY"
help
SHINY is a GSM/GPRS module.
It supports SHINY.
config EXAMPLE_MODEM_DEVICE_SIM800
bool "SIM800"
help
SIMCom SIM800L is a GSM/GPRS module.
It supports Quad-band 850/900/1800/1900MHz.
config EXAMPLE_MODEM_DEVICE_BG96
bool "BG96"
help
Quectel BG96 is a series of LTE Cat M1/Cat NB1/EGPRS module.
config EXAMPLE_MODEM_DEVICE_SIM7000
bool "SIM7000"
help
SIM7000 is a Multi-Band LTE-FDD and GSM/GPRS/EDGE module.
config EXAMPLE_MODEM_DEVICE_SIM7070
bool "SIM7070"
help
SIM7070 is Multi-Band CAT M and NB IoT module.
config EXAMPLE_MODEM_DEVICE_SIM7600
bool "SIM7600"
help
SIM7600 is a Multi-Band LTE-TDD/LTE-FDD/HSPA+ and GSM/GPRS/EDGE module.
endchoice
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_PPP_AUTH_USERNAME
string "Set username for authentication"
default "espressif"
depends on !EXAMPLE_MODEM_PPP_AUTH_NONE
help
Set username for PPP Authentication.
config EXAMPLE_MODEM_PPP_AUTH_PASSWORD
string "Set password for authentication"
default "esp32"
depends on !EXAMPLE_MODEM_PPP_AUTH_NONE
help
Set password for PPP Authentication.
config EXAMPLE_MODEM_PPP_AUTH_NONE
bool "Skip PPP authentication"
default n
help
Set to true for the PPP client to skip authentication
menu "UART Configuration"
depends on EXAMPLE_SERIAL_CONFIG_UART
choice EXAMPLE_FLOW_CONTROL
bool "Set preferred modem control flow"
default EXAMPLE_FLOW_CONTROL_NONE
help
Set the modem's preferred control flow
config EXAMPLE_FLOW_CONTROL_NONE
bool "No control flow"
config EXAMPLE_FLOW_CONTROL_SW
bool "SW control flow"
config EXAMPLE_FLOW_CONTROL_HW
bool "HW control flow"
endchoice
config EXAMPLE_MODEM_UART_TX_PIN
int "TXD Pin Number"
default 25
range 0 31
help
Pin number of UART TX.
config EXAMPLE_MODEM_UART_RX_PIN
int "RXD Pin Number"
default 26
range 0 31
help
Pin number of UART RX.
config EXAMPLE_MODEM_UART_RTS_PIN
int "RTS Pin Number"
default 27
range 0 31
help
Pin number of UART RTS.
config EXAMPLE_MODEM_UART_CTS_PIN
int "CTS Pin Number"
default 23
range 0 31
help
Pin number of UART CTS.
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_PATTERN_QUEUE_SIZE
int "UART Pattern Queue Size"
range 10 40
default 20
help
Length of UART pattern 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.
endmenu

View File

@ -1,10 +1,11 @@
/* Modem console example
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
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.
/*
* Modem console example
*/
#include "console_helper.hpp"
@ -18,6 +19,16 @@ ConsoleCommand::ConsoleCommand(const char *command, const char *help, const std:
RegisterCommand(command, help, args);
}
ConsoleCommand::~ConsoleCommand()
{
// Find this command in static list of commands and remove it
auto cmd = std::find(console_commands.begin(), console_commands.end(), this);
if (cmd != console_commands.end()) {
console_commands.erase(cmd);
last_command--;
}
}
void ConsoleCommand::RegisterCommand(const char *command, const char *help, const std::vector<CommandArgs> &args)
{
assert(last_command <= MAX_REPEAT_NR);

View File

@ -1,10 +1,11 @@
/* Modem console example
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
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.
/*
* Modem console example
*/
#pragma once
@ -92,6 +93,11 @@ public:
*/
explicit ConsoleCommand(const char *command, const char *help, const std::vector<CommandArgs> &args, std::function<bool(ConsoleCommand *)> f);
/**
* @brief Destructor of ConsoleCommand
*/
~ConsoleCommand();
/**
* @brief Utility getters of various params from the argument list
*/

View File

@ -1,10 +1,12 @@
/* Modem console example
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
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.
/*
* Modem console example
*
*/
#include <stdio.h>
@ -19,34 +21,34 @@ static const char *TAG = "modem_console_httpget";
static esp_err_t http_event_handler(esp_http_client_event_t *evt)
{
switch(evt->event_id) {
case HTTP_EVENT_ERROR:
ESP_LOGD(TAG, "HTTP_EVENT_ERROR");
break;
case HTTP_EVENT_ON_CONNECTED:
ESP_LOGD(TAG, "HTTP_EVENT_ON_CONNECTED");
break;
case HTTP_EVENT_HEADER_SENT:
ESP_LOGD(TAG, "HTTP_EVENT_HEADER_SENT");
break;
case HTTP_EVENT_ON_HEADER:
ESP_LOGD(TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value);
break;
case HTTP_EVENT_ON_DATA:
ESP_LOGD(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
if ((bool)evt->user_data &&
switch (evt->event_id) {
case HTTP_EVENT_ERROR:
ESP_LOGD(TAG, "HTTP_EVENT_ERROR");
break;
case HTTP_EVENT_ON_CONNECTED:
ESP_LOGD(TAG, "HTTP_EVENT_ON_CONNECTED");
break;
case HTTP_EVENT_HEADER_SENT:
ESP_LOGD(TAG, "HTTP_EVENT_HEADER_SENT");
break;
case HTTP_EVENT_ON_HEADER:
ESP_LOGD(TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value);
break;
case HTTP_EVENT_ON_DATA:
ESP_LOGD(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
if ((bool)evt->user_data &&
!esp_http_client_is_chunked_response(evt->client)) {
ESP_LOG_BUFFER_HEXDUMP(TAG, evt->data, evt->data_len, ESP_LOG_INFO);
}
ESP_LOG_BUFFER_HEXDUMP(TAG, evt->data, evt->data_len, ESP_LOG_INFO);
}
break;
case HTTP_EVENT_ON_FINISH:
ESP_LOGD(TAG, "HTTP_EVENT_ON_FINISH");
break;
case HTTP_EVENT_DISCONNECTED:
ESP_LOGI(TAG, "HTTP_EVENT_DISCONNECTED");
break;
default: break;
break;
case HTTP_EVENT_ON_FINISH:
ESP_LOGD(TAG, "HTTP_EVENT_ON_FINISH");
break;
case HTTP_EVENT_DISCONNECTED:
ESP_LOGI(TAG, "HTTP_EVENT_DISCONNECTED");
break;
default: break;
}
return ESP_OK;
}
@ -65,7 +67,7 @@ static int do_http_client(int argc, char **argv)
return 1;
}
esp_http_client_config_t config = {
.event_handler = http_event_handler,
.event_handler = http_event_handler,
};
if (http_args.host->count > 0) {
@ -76,11 +78,11 @@ static int do_http_client(int argc, char **argv)
if (http_args.hex->count > 0) {
// show hex data from http-get
config.user_data = (void*)true;
config.user_data = (void *)true;
}
esp_http_client_handle_t client = esp_http_client_init(&config);
esp_http_client_handle_t client = esp_http_client_init(&config);
esp_err_t err = esp_http_client_perform(client);
if (err == ESP_OK) {
@ -99,11 +101,11 @@ void modem_console_register_http(void)
http_args.hex = arg_litn("p", "print-hex", 0, 1, "print hex output"),
http_args.end = arg_end(1);
const esp_console_cmd_t http_cmd = {
.command = "httpget",
.help = "http get command to test data mode",
.hint = NULL,
.func = &do_http_client,
.argtable = &http_args
.command = "httpget",
.help = "http get command to test data mode",
.hint = NULL,
.func = &do_http_client,
.argtable = &http_args
};
ESP_ERROR_CHECK(esp_console_cmd_register(&http_cmd));
}

View File

@ -0,0 +1,12 @@
## IDF Component Manager Manifest File
dependencies:
## Required IDF version
idf: ">=4.1.0"
espressif/esp_modem:
version: "^0.1.20"
override_path: "../../../"
espressif/esp_modem_usb_dte:
version: "^1.0.0"
rules:
- if: "idf_version >=4.4"
- if: "target in [esp32s2, esp32s3]"

View File

@ -1,10 +1,11 @@
/* Modem console example
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
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.
/*
* Modem console example
*/
#include <cstdio>
@ -15,10 +16,12 @@
#include "esp_console.h"
#include "esp_event.h"
#include "nvs_flash.h"
#include "esp_sleep.h"
#include "driver/gpio.h"
#include "cxx_include/esp_modem_dte.hpp"
#include "esp_modem_config.h"
#include "cxx_include/esp_modem_api.hpp"
#if defined(CONFIG_USB_OTG_SUPPORTED)
#if defined(CONFIG_EXAMPLE_SERIAL_CONFIG_USB)
#include "esp_modem_usb_config.h"
#include "cxx_include/esp_modem_usb_api.hpp"
#endif
@ -26,6 +29,14 @@
#include "console_helper.hpp"
#include "my_module_dce.hpp"
#if defined(CONFIG_EXAMPLE_FLOW_CONTROL_NONE)
#define EXAMPLE_FLOW_CONTROL ESP_MODEM_FLOW_CONTROL_NONE
#elif defined(CONFIG_EXAMPLE_FLOW_CONTROL_SW)
#define EXAMPLE_FLOW_CONTROL ESP_MODEM_FLOW_CONTROL_SW
#elif defined(CONFIG_EXAMPLE_FLOW_CONTROL_HW)
#define EXAMPLE_FLOW_CONTROL ESP_MODEM_FLOW_CONTROL_HW
#endif
#define CHECK_ERR(cmd, success_action) do { \
auto err = cmd; \
if (err == command_result::OK) { \
@ -33,7 +44,7 @@
return 0; \
} else { \
ESP_LOGE(TAG, "Failed with %s", err == command_result::TIMEOUT ? "TIMEOUT":"ERROR"); \
return 1; \
return 1; \
} } while (0)
/**
@ -41,6 +52,9 @@
*/
#define DEFAULT_APN "my_apn"
#define GPIO_OUTPUT_PWRKEY (gpio_num_t)CONFIG_EXAMPLE_MODEM_PWRKEY_PIN
#define GPIO_OUTPUT_PIN_SEL (1ULL<<GPIO_OUTPUT_PWRKEY)
extern "C" void modem_console_register_http(void);
extern "C" void modem_console_register_ping(void);
@ -48,10 +62,40 @@ static const char *TAG = "modem_console";
static esp_console_repl_t *s_repl = nullptr;
using namespace esp_modem;
static SignalGroup exit_signal;
void config_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 wakeup_modem(void)
{
/* Power on the modem */
ESP_LOGI(TAG, "Power on the modem");
gpio_set_level(GPIO_OUTPUT_PWRKEY, 1);
vTaskDelay(pdMS_TO_TICKS(1000));
gpio_set_level(GPIO_OUTPUT_PWRKEY, 0);
vTaskDelay(pdMS_TO_TICKS(2000));
}
extern "C" void app_main(void)
{
static RTC_RODATA_ATTR char apn_rtc[20] = DEFAULT_APN;
static RTC_DATA_ATTR modem_mode mode_rtc = esp_modem::modem_mode::COMMAND_MODE;
config_gpio();
ESP_ERROR_CHECK(nvs_flash_init());
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
@ -64,29 +108,98 @@ extern "C" void app_main(void)
#if defined(CONFIG_EXAMPLE_SERIAL_CONFIG_UART)
esp_modem_dte_config_t dte_config = ESP_MODEM_DTE_DEFAULT_CONFIG();
/* 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.rts_io_num = CONFIG_EXAMPLE_MODEM_UART_RTS_PIN;
dte_config.uart_config.cts_io_num = CONFIG_EXAMPLE_MODEM_UART_CTS_PIN;
dte_config.uart_config.flow_control = EXAMPLE_FLOW_CONTROL;
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;
auto uart_dte = create_uart_dte(&dte_config);
#if CONFIG_EXAMPLE_MODEM_DEVICE_SHINY == 1
ESP_LOGI(TAG, "Initializing esp_modem for the SHINY module...");
auto dce = create_shiny_dce(&dce_config, uart_dte, esp_netif);
#elif CONFIG_EXAMPLE_MODEM_DEVICE_BG96 == 1
ESP_LOGI(TAG, "Initializing esp_modem for the BG96 module...");
auto dce = create_BG96_dce(&dce_config, uart_dte, esp_netif);
#elif CONFIG_EXAMPLE_MODEM_DEVICE_SIM800 == 1
ESP_LOGI(TAG, "Initializing esp_modem for the SIM800 module...");
auto dce = create_SIM800_dce(&dce_config, uart_dte, esp_netif);
#elif CONFIG_EXAMPLE_MODEM_DEVICE_SIM7000 == 1
ESP_LOGI(TAG, "Initializing esp_modem for the SIM7000 module...");
auto dce = create_SIM7000_dce(&dce_config, uart_dte, esp_netif);
#elif CONFIG_EXAMPLE_MODEM_DEVICE_SIM7070 == 1
ESP_LOGI(TAG, "Initializing esp_modem for the SIM7070 module...");
auto dce = create_SIM7070_dce(&dce_config, uart_dte, esp_netif);
#elif CONFIG_EXAMPLE_MODEM_DEVICE_SIM7600 == 1
ESP_LOGI(TAG, "Initializing esp_modem for the SIM7600 module...");
auto dce = create_SIM7600_dce(&dce_config, uart_dte, esp_netif);
#else
ESP_LOGI(TAG, "Initializing esp_modem for a generic module...");
auto dce = create_generic_dce(&dce_config, uart_dte, esp_netif);
#endif
#elif defined(CONFIG_EXAMPLE_SERIAL_CONFIG_USB)
struct esp_modem_usb_term_config usb_config = ESP_MODEM_DEFAULT_USB_CONFIG(0x2C7C, 0x0296); // VID and PID of BG96 modem
// BG96 modem implements Vendor Specific class, that is CDC-ACM like. Interface for AT commands has index no. 2.
usb_config.interface_idx = 2;
esp_modem_dte_config_t dte_config = ESP_MODEM_DTE_DEFAULT_USB_CONFIG(usb_config);
ESP_LOGI(TAG, "Waiting for USB device connection...");
auto dte = create_usb_dte(&dte_config);
std::unique_ptr<DCE> dce = create_BG96_dce(&dce_config, dte, esp_netif);
while (1) {
exit_signal.clear(1);
struct esp_modem_usb_term_config usb_config = ESP_MODEM_DEFAULT_USB_CONFIG(0x2C7C, 0x0296, 2); // VID, PID and interface num of BG96 modem
const esp_modem_dte_config_t dte_config = ESP_MODEM_DTE_DEFAULT_USB_CONFIG(usb_config);
ESP_LOGI(TAG, "Waiting for USB device connection...");
auto dte = create_usb_dte(&dte_config);
dte->set_error_cb([&](terminal_error err) {
ESP_LOGI(TAG, "error handler %d", err);
if (err == terminal_error::DEVICE_GONE) {
exit_signal.set(1);
}
});
std::unique_ptr<DCE> dce = create_BG96_dce(&dce_config, dte, esp_netif);
#else
#error Invalid serial connection to modem.
#endif
assert(dce != nullptr);
if (dte_config.uart_config.flow_control == ESP_MODEM_FLOW_CONTROL_HW) {
if (command_result::OK != dce->set_flow_control(2, 2)) {
ESP_LOGE(TAG, "Failed to set the set_flow_control mode");
return;
}
ESP_LOGI(TAG, "set_flow_control OK");
}
// init console REPL environment
esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT();
esp_console_dev_uart_config_t uart_config = ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_console_new_repl_uart(&uart_config, &repl_config, &s_repl));
switch (esp_sleep_get_wakeup_cause()) {
case ESP_SLEEP_WAKEUP_TIMER:
if (esp_modem::modem_mode::CMUX_MODE == mode_rtc) {
ESP_LOGI(TAG, "Deep sleep reset\n");
/* Set APN */
auto new_pdp = std::unique_ptr<PdpContext>(new PdpContext(apn_rtc));
dce->get_module()->configure_pdp_context(std::move(new_pdp));
/* Set CMUX mode */
if (!dce->set_mode(mode_rtc)) {
ESP_LOGE(TAG, "Failed to set the desired mode");
}
}
break;
case ESP_SLEEP_WAKEUP_UNDEFINED:
default:
ESP_LOGD(TAG, "Not a deep sleep reset\n");
}
modem_console_register_http();
modem_console_register_ping();
const struct SetModeArgs {
@ -97,12 +210,25 @@ 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;
} else if (mode == "CMUX") {
/* Even if switching to CMUX fails, we make the DTE multiplex terminal.
(This is potentially a bug and might be fixed eventually) */
dev_mode = esp_modem::modem_mode::CMUX_MODE;
mode_rtc = dev_mode;
} else {
ESP_LOGE(TAG, "Unsupported mode: %s", mode.c_str());
return 1;
@ -112,6 +238,8 @@ extern "C" void app_main(void)
ESP_LOGE(TAG, "Failed to set the desired mode");
return 1;
}
mode_rtc = dev_mode;
ESP_LOGI(TAG, "OK");
}
return 0;
@ -219,6 +347,7 @@ extern "C" void app_main(void)
if (c->get_count_of(&SetApn::apn)) {
auto apn = c->get_string_of(&SetApn::apn);
ESP_LOGI(TAG, "Setting the APN=%s...", apn.c_str());
strcpy(apn_rtc, apn.c_str());
auto new_pdp = std::unique_ptr<PdpContext>(new PdpContext(apn));
dce->get_module()->configure_pdp_context(std::move(new_pdp));
ESP_LOGI(TAG, "OK");
@ -226,16 +355,96 @@ extern "C" void app_main(void)
return 0;
});
SignalGroup exit_signal;
const ConsoleCommand ExitConsole("exit", "exit the console application", no_args, [&](ConsoleCommand * c) {
ESP_LOGI(TAG, "Exiting...");
exit_signal.set(1);
s_repl->del(s_repl);
return 0;
});
/* Put the esp32 into deep sleep */
const struct DeepSleepArgs {
DeepSleepArgs(): timeout(INT1, nullptr, nullptr, "<tout>", "TIMEOUT") {}
CommandArgs timeout;
} deep_sleep_args;
const ConsoleCommand SetDeepSleep("set_deep_sleep", "Put esp32 to deep sleep", &deep_sleep_args, sizeof(deep_sleep_args), [&](ConsoleCommand * c) {
int tout = c->get_int_of(&DeepSleepArgs::timeout);
ESP_LOGI(TAG, "Entering deep sleep for %d sec", tout);
ESP_LOGI(TAG, "Wakeup Cause: %d ", esp_sleep_get_wakeup_cause());
esp_deep_sleep(tout * 1000000);
return 0;
});
/* Wake up modem */
const ConsoleCommand WakeupModem("wakeup_modem", "Wakes up the modem from PSM", no_args, [&](ConsoleCommand * c) {
wakeup_modem();
ESP_LOGI(TAG, "OK");
return 0;
});
/* Enable PSM modem */
const ConsoleCommand EnablePSM("enable_psm", "Enables PSM on the modem", no_args, [&](ConsoleCommand * c) {
std::string out;
CHECK_ERR(dce->at("AT+CPSMS=1", out, 500), ESP_LOGI(TAG, "OK. %s", out.c_str()));
return 0;
});
/* Disable PSM modem */
const ConsoleCommand DisablePSM("disable_psm", "Disables PSM on the modem", no_args, [&](ConsoleCommand * c) {
std::string out;
CHECK_ERR(dce->at("AT+CPSMS=0", out, 500), ESP_LOGI(TAG, "OK. %s", out.c_str()));
return 0;
});
/* Get modem PSM cfg */
const ConsoleCommand GetModemCfg("get_psm_cfg", "Get PSM config", no_args, [&](ConsoleCommand * c) {
std::string out;
CHECK_ERR(dce->at("AT+CPSMS?", out, 500), ESP_LOGI(TAG, "OK. %s", out.c_str()));
return 0;
});
/* Set modem PSM config */
const struct SetPsmCfgArgs {
SetPsmCfgArgs():
periodic_tau(STR1, nullptr, nullptr, "<Requested_Periodic-TAU>", "T3412 Timer in 8-bit format"),
active_time(STR0, nullptr, nullptr, "<Requested_Active-Time>", "T3324 Timer in 8-bit format") {}
CommandArgs periodic_tau;
CommandArgs active_time;
} set_psm_cfg_args;
const ConsoleCommand SetPsmCfg("set_psm_cfg", "Set PSM config", &set_psm_cfg_args, sizeof(set_psm_cfg_args), [&](ConsoleCommand * c) {
std::string out;
auto periodic_tau = c->get_string_of(&SetPsmCfgArgs::periodic_tau);
auto active_time = c->get_string_of(&SetPsmCfgArgs::active_time);
/* Validate input */
if ((strlen(periodic_tau.c_str()) != strlen("00000000")) ||
(strlen(active_time.c_str()) != strlen("00000000"))) {
ESP_LOGE(TAG, "Failed with ERROR: Invalid argument length");
return 1;
}
/* Get PSM config */
dce->at("AT+CPSMS?", out, 500);
/* Update PSM config */
if (out.size() > 8) {
std::string set_cmd = "AT+CPSMS=" + std::to_string(out.c_str()[8] - '0') + ",,,\"" + periodic_tau.c_str() + "\",\"" + active_time.c_str() + "\"";
CHECK_ERR(dce->at(set_cmd, out, 500), ESP_LOGI(TAG, "OK. %s", out.c_str()));
} else {
ESP_LOGE(TAG, "Failed with ERROR: Invalid AT+CPSMS? return length");
}
return 0;
});
// start console REPL
ESP_ERROR_CHECK(esp_console_start_repl(s_repl));
// wait for exit
exit_signal.wait_any(1, UINT32_MAX);
s_repl->del(s_repl);
ESP_LOGI(TAG, "Exiting...%d", esp_get_free_heap_size());
#if defined(CONFIG_EXAMPLE_SERIAL_CONFIG_USB)
// USB example runs in a loop to demonstrate hot-plugging and sudden disconnection features.
} // while (1)
#endif
}

View File

@ -1,10 +1,11 @@
/* Modem console example: Custom DCE
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
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.
/*
* Modem console example: Custom DCE
*/
#pragma once

View File

@ -1,10 +1,10 @@
/* Ping handle 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.
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
/*
* Ping handle example
*/
#include <stdio.h>
@ -29,7 +29,7 @@ static void cmd_ping_on_ping_success(esp_ping_handle_t hdl, void *args)
esp_ping_get_profile(hdl, ESP_PING_PROF_SIZE, &recv_len, sizeof(recv_len));
esp_ping_get_profile(hdl, ESP_PING_PROF_TIMEGAP, &elapsed_time, sizeof(elapsed_time));
ESP_LOGI(TAG, "%d bytes from %s icmp_seq=%d ttl=%d time=%d ms\n",
recv_len, inet_ntoa(target_addr.u_addr.ip4), seqno, ttl, elapsed_time);
recv_len, inet_ntoa(target_addr.u_addr.ip4), seqno, ttl, elapsed_time);
}
static void cmd_ping_on_ping_timeout(esp_ping_handle_t hdl, void *args)
@ -58,7 +58,7 @@ static void cmd_ping_on_ping_end(esp_ping_handle_t hdl, void *args)
ESP_LOGI(TAG, "\n--- %s ping statistics ---\n", inet6_ntoa(*ip_2_ip6(&target_addr)));
}
ESP_LOGI(TAG, "%d packets transmitted, %d received, %d%% packet loss, time %dms\n",
transmitted, received, loss, total_time_ms);
transmitted, received, loss, total_time_ms);
// delete the ping sessions, so that we clean up all resources and can create a new ping session
// we don't have to call delete function in the callback, instead we can call delete function from other tasks
esp_ping_delete_session(hdl);
@ -112,10 +112,10 @@ static int do_ping_cmd(int argc, char **argv)
/* set callback functions */
esp_ping_callbacks_t cbs = {
.on_ping_success = cmd_ping_on_ping_success,
.on_ping_timeout = cmd_ping_on_ping_timeout,
.on_ping_end = cmd_ping_on_ping_end,
.cb_args = NULL
.on_ping_success = cmd_ping_on_ping_success,
.on_ping_timeout = cmd_ping_on_ping_timeout,
.on_ping_end = cmd_ping_on_ping_end,
.cb_args = NULL
};
esp_ping_handle_t ping;
esp_ping_new_session(&config, &cbs, &ping);
@ -131,11 +131,11 @@ void modem_console_register_ping(void)
ping_args.host = arg_str1(NULL, NULL, "<host>", "Host address");
ping_args.end = arg_end(1);
const esp_console_cmd_t ping_cmd = {
.command = "ping",
.help = "send ICMP ECHO_REQUEST to network hosts",
.hint = NULL,
.func = &do_ping_cmd,
.argtable = &ping_args
.command = "ping",
.help = "send ICMP ECHO_REQUEST to network hosts",
.hint = NULL,
.func = &do_ping_cmd,
.argtable = &ping_args
};
ESP_ERROR_CHECK(esp_console_cmd_register(&ping_cmd));
}
}

View File

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

View File

@ -1,8 +1,7 @@
# Override some defaults to enable PPP
# This file was generated using idf.py save-defconfig. It can be edited manually.
# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration
#
CONFIG_ESP_MAIN_TASK_STACK_SIZE=7168
CONFIG_LWIP_PPP_SUPPORT=y
# CONFIG_LWIP_PPP_ENABLE_IPV6 is not set
CONFIG_LWIP_PPP_PAP_SUPPORT=y
CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=4096
# Do not enable IPV6 in dte<->dce link local
CONFIG_LWIP_PPP_ENABLE_IPV6=n
# Disable legacy API
CONFIG_MODEM_LEGACY_API=n

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