Compare commits

..

166 Commits

Author SHA1 Message Date
eb12d05bf3 Merge pull request #773 from david-cermak/fix/mdns_add_version_macro
[mdns]: Bump 1.7.0 -> 1.8.0
2025-03-04 15:59:54 +01:00
520b8194fc fix(common): Fix clang-tidy runner to use supported versions 2025-03-04 15:29:38 +01:00
40142cdcfd bump(mdns): 1.7.0 -> 1.8.0
1.8.0
Features
- Add version keys (e01e67e7)
Bug Fixes
- Reformat mdns sources per indent-cont=120 (c7663cde)
2025-03-04 15:20:49 +01:00
c7663cdef2 fix(mdns): Reformat mdns sources per indent-cont=120 2025-02-27 10:42:03 +01:00
e01e67e7eb feat(mdns): Add version keys 2025-02-27 10:33:53 +01:00
37f84ee5a4 Merge pull request #768 from deodatomatheus/fix/handle-nullptr-dte-constructors
fix(modem): handle nullptr in DTE constructors to prevent invalid access (IDFGH-14688)
2025-02-27 09:19:16 +01:00
95b56600ed fix(modem): handle nullptr in DTE constructors to prevent invalid access 2025-02-26 11:37:02 -03:00
a22c3da49e Merge pull request #762 from david-cermak/fix/examples_target_tests
[examples]: Test the SLIP netif example on target as well
2025-02-20 14:32:54 +01:00
5d0fd5c1c5 Merge pull request #770 from david-cermak/fix/lws_license
[lws]: Adds missing license info
2025-02-20 14:17:47 +01:00
7ea6879a19 fix(lws): Adds missing license info 2025-02-20 12:34:40 +01:00
2db11bbb8c fix(examples): Fix SLIP netif example to make esp_netif use special netif
by enabling PPP netif, so esp_netif knows that lwip's netif->state
will be reserved for special netif info (slip)

Closes https://github.com/espressif/esp-protocols/issues/759
2025-02-20 11:58:54 +01:00
cdb7bfd188 fix(examples): Test the SLIP netif example on target as well 2025-02-20 11:58:49 +01:00
c679ceed85 Merge pull request #718 from glmfe/feat/lws
[lws]: Add initial support for libwebsockets
2025-02-19 11:26:03 -03:00
c009892968 bump(lws): First version 4.3.3
4.3.3
Features
- Add initial support libwebsockets component (ef3443d)
2025-02-19 10:21:35 -03:00
5f66f35f5f feat(lws): Add initial support libwebsockets component 2025-02-19 10:16:42 -03:00
dea5f1c431 Merge pull request #764 from david-cermak/feat/mdns_malloc_caps
[mdns]: Allow allocate memory with configured caps
2025-02-18 13:23:41 +01:00
384d1c23ba bump(mdns): 1.6.0 -> 1.7.0
1.7.0
Features
- Support user defined allocators (88162d1f)
- Allow allocate memory with configured caps (7d29b476)
Bug Fixes
- Adjust some formatting per indent-cont=120 (5b2077e3)
2025-02-18 12:53:46 +01:00
88162d1f3a feat(mdns): Support user defined allocators
Defines mem-alloc function optionally weak, so users can override them
and implement their own allocation, or a static/bss memory for the mdns
task stack.
2025-02-18 12:52:21 +01:00
e65f22ab6c ci(mdns): Check mdns sources for std alloc functions 2025-02-13 15:02:18 +01:00
7d29b47676 feat(mdns): Allow allocate memory with configured caps 2025-02-13 13:51:22 +01:00
f1a72ec42c Merge pull request #760 from glmfe/feat/add-ws-unregister
feat(websocket): add unregister event to websocket client
2025-02-12 18:50:52 +01:00
ce160505dc feat(websocket): add unregister event to websocket client 2025-02-12 08:46:39 -03:00
87e96b4682 Merge pull request #761 from david-cermak/fix/ci_astyle
[ci]: Fix pre-commit hook to call astyle correctly
2025-02-12 11:47:40 +01:00
5b2077e373 fix(common): Adjust some formatting per indent-cont=120
As we updated astyle configuration to be in line with IDF style
2025-02-12 11:40:21 +01:00
b45fe143a4 ci(common): Fix pre-commit hook to call astyle correctly 2025-02-11 17:16:11 +01:00
ee2fbbbee7 Merge pull request #756 from david-cermak/feat/mdns_alloc_task
[mdns]: support allocating mDNS task with caps
2025-02-10 11:50:59 +01:00
cb061c9c38 bump(mdns): 1.5.3 -> 1.6.0
1.6.0
Features
- support allocating mDNS task from SPIRAM (8fcad10c)
Bug Fixes
- Use correct task delete function (eb4ab524)
Updated
- ci(mdns): Fix mdns host test layers with static task creation (0690eba3)
2025-02-10 11:18:55 +01:00
0690eba3a8 ci(mdns): Fix mdns host test layers with static task creation 2025-02-10 11:18:19 +01:00
eb4ab52487 fix(mdns): Use correct task delete function 2025-02-10 11:18:19 +01:00
zwx
8fcad10ccf feat(mdns): support allocating mDNS task from SPIRAM 2025-02-10 11:18:19 +01:00
936e43f9d8 Merge pull request #758 from david-cermak/fix/mdns_ignore_only_invalid_queries
[mdns]: Fix the responder to ignore only invalid queries
2025-02-07 15:11:14 +01:00
64d818b2d3 bump(mdns): 1.5.2 -> 1.5.3
1.5.3
Bug Fixes
- Fix responder to ignore only invalid queries (cd07228f, #754)
2025-02-07 14:31:18 +01:00
cd07228f81 fix(mdns): Fix responder to ignore only invalid queries
not the entire packet, so we can still reply to next questions

Closes https://github.com/espressif/esp-protocols/issues/754
2025-02-07 14:30:10 +01:00
1c6580e22b Merge pull request #753 from david-cermak/fix/ci_mosq
[mosquitto]: Fix minor CI issue
2025-02-03 14:54:07 +01:00
87f835af0f fix(mosq): Run IDF build test only on master or labeled PRs 2025-01-31 11:19:00 +01:00
85a8dac42d Merge pull request #750 from david-cermak/bump/ws_client
[websocket]:  Bump 1.3.0 -> 1.4.0
2025-01-30 08:48:45 +01:00
39866116f5 bump(websocket): 1.3.0 -> 1.4.0
1.4.0
Features
- Support DS peripheral for mutual TLS (55385ec3)
Bug Fixes
- wait for task on destroy (42674b49)
- Fix pytest to verify client correctly (9046af8f)
- propagate error type (eeeb9006)
- fix example buffer leak (5219c39d)
Updated
- chore(websocket): align structure members (beb6e57e)
- chore(websocket): remove unused client variable (15d3a01e)
2025-01-30 07:16:24 +01:00
7740b591b6 Merge pull request #749 from david-cermak/fix/ws_client_test
[websocket]: Fix pytest to verify client correctly
2025-01-30 07:09:34 +01:00
b57979d967 Merge pull request #751 from johanstokking/fix/await-task-on-destroy
fix(websocket): wait for task on destroy (IDFGH-14533)
2025-01-29 15:27:38 +01:00
42674b49f9 fix(websocket): wait for task on destroy 2025-01-29 14:30:32 +01:00
e069ae7762 Merge pull request #520 from johanstokking/feature/websocket/client_ds_data
feat(websocket): Support DS peripheral for mutual TLS (IDFGH-12285)
2025-01-28 16:59:34 +01:00
44d476fc50 docs(websocket): fix minor readability issues 2025-01-28 14:59:24 +01:00
55385ec312 feat(websocket): Support DS peripheral for mutual TLS 2025-01-28 14:58:54 +01:00
a3c2bbed9e Merge pull request #748 from david-cermak/fix/mdns_coverity
[mdns]: Bump v1.5.2
2025-01-28 10:23:24 +01:00
84c47c37f1 bump(mdns): 1.5.1 -> 1.5.2
1.5.2
Bug Fixes
- Fix potential NULL deref when sending sub-buy (e7273c46)
- Fix _mdns_append_fqdn excessive stack usage (bd23c233)
2025-01-28 09:54:54 +01:00
e7273c46ec fix(mdns): Fix potential NULL deref when sending sub-buy
Closes coverity reported issue: 473829 Dereference null return value
2025-01-28 09:54:16 +01:00
2e7d240abd Merge pull request #744 from andrew-lifx/fix/mdns_append_fqdn
fix(mdns): Fix _mdns_append_fqdn excessive stack usage (IDFGH-14506)
2025-01-28 07:28:00 +01:00
d4a004b5b4 Merge pull request #694 from johanstokking/fix/websocket-esp-tls-errors
fix(websocket): propagate error type (IDFGH-14518)
2025-01-27 15:50:32 +01:00
9046af8f8d fix(websocket): Fix pytest to verify client correctly 2025-01-27 15:34:49 +01:00
eeeb9006eb fix(websocket): propagate error type 2025-01-25 21:52:06 +01:00
b167aa315f Merge pull request #747 from david-cermak/fix/publish_asio_1.32
bump(asio): Publish 1.32.0 to component manager
2025-01-24 15:53:54 +01:00
72ba24470d bump(asio): Publish 1.32.0 to component manager
Related to the bump-commit: ac6a388cdd
but missed to update idf_component.yml
This publishes ASIO-1.32-0~0
2025-01-24 14:32:20 +01:00
7dc87d28b2 Merge pull request #717 from david-cermak/feat/asio_sync_upstream
[asio]: Drop esp-asio patches in favor of sock-utils
2025-01-24 13:49:53 +01:00
ac6a388cdd bump(asio): 1.28.0 -> 1.32.0
1.32.0
Features
- Upgrade asio to 1.32 (9bdd429c)
- Drop esp/asio patches in favor of sock-utils (27435b7f)
Bug Fixes
- Fix chat example to print only the message body (76aaea08)
- Make asio enable if_nametoindex to fix linking (5db32cce)
- Re-applie refs to common comps idf_component.yml (9fe44a45)
- Reference common component from IDF (74fc228c)
- Revert referencing protocol_examples_common from IDF (f9e0281a)
- reference protocol_examples_common from IDF (09abb18b)
- specify override_path in example manifest files (1d8923cf)
Updated
- docs(asio): Updates asio docs (ce9337d3)
2025-01-24 12:40:45 +01:00
76aaea08d2 fix(asio): Fix chat example to print only the message body 2025-01-24 12:37:39 +01:00
5db32cce30 fix(asio): Make asio enable if_nametoindex to fix linking 2025-01-24 12:37:39 +01:00
9bdd429c7c feat(asio): Upgrade asio to 1.32 2025-01-24 10:47:54 +01:00
6f7c52cc3f fix(asio): Add tests for IDF-v5.4 2025-01-24 10:47:54 +01:00
27435b7f34 feat(asio): Drop esp/asio patches in favor of sock-utils 2025-01-24 10:47:54 +01:00
813331f003 Merge pull request #743 from david-cermak/fix/modem_ci
[modem]: Fix deprecated CI download action
2025-01-24 08:27:37 +01:00
bd23c233a4 fix(mdns): Fix _mdns_append_fqdn excessive stack usage
Move "mdns_name_t name" declaration inside loop to move it out of scope and reclain stack space before recursion call.
2025-01-24 17:39:04 +10:30
4eda7d472f fix(modem): Fix deprecated download action 2025-01-23 19:15:28 +01:00
163029c0b6 Merge pull request #742 from david-cermak/bump/mdns_1.5.1
[mdns]: Bump 1.5.0 -> 1.5.1
2025-01-23 15:32:49 +01:00
96eae25096 bump(mdns): 1.5.0 -> 1.5.1
1.5.1
Bug Fixes
- Fix incorrect memory free for mdns browse (4451a8c5)
2025-01-23 09:00:01 +01:00
ebec8eff63 Merge pull request #740 from gytxxsy/fix/fix_wrong_mem_free_of_mdns_browse
[mdns]: fix incorrect memory free for mdns browse
2025-01-23 08:58:05 +01:00
4451a8c5ad fix(mdns): Fix incorrect memory free for mdns browse 2025-01-23 09:08:25 +08:00
6d19aabb02 Merge pull request #721 from david-cermak/feat/mosq_target_tests
[mosq]: Add IDF MQTT stress tests to mosquitto CI
2025-01-21 12:55:49 +01:00
9162de1150 fix(mosq): Remove temp modification of IDF files 2025-01-21 12:27:09 +01:00
dbd164dd91 fix(mosq): Add a note about stack size 2025-01-21 12:27:09 +01:00
90d663ad01 feat(mosq): Add IDF MQTT stress tests to mosquitto CI 2025-01-21 12:27:09 +01:00
a83f1b6787 Merge pull request #736 from david-cermak/bump/mdns_1.4.4
[mdns]: Bump 1.4.3 -> 1.5.0
2025-01-21 10:56:48 +01:00
84caca465d bump(mdns): 1.4.3 -> 1.5.0
1.5.0
Features
- supported removal of subtype when updating service (4ad88e29)
Bug Fixes
- Fix zero-sized VLA clang-tidy warnings (196198ec)
- Remove dead store to arg variable shared (e838bf03)
- Fix name mangling not to use strcpy() (99b54ac3)
- Fix potential null derefernce in _mdns_execute_action() (f5be2f41)
- Fix AFL test mock per espressif/esp-idf@a5bc08fb55 (3d8835cf)
- Fixed potential out-of-bound interface error (24f55ce9)
- Fixed incorrect error conversion (8f8516cc)
- Fixed potential overflow when allocating txt data (75a8e864)
- Move MDNS_NAME_BUF_LEN to public headers (907087c0, #724)
- Cleanup includes in mdns.c (68a9e148, #725)
- Allow advertizing service with port==0 (827ea65f)
- Fixed complier warning if MDNS_MAX_SERVICES==0 (95377216, #611)
2025-01-20 17:57:07 +01:00
8f81478fff Merge pull request #735 from david-cermak/fix/docs_build
[common]: Fix esp-docs dependencies
2025-01-20 14:50:32 +01:00
ae5a8ceeda fix(mosq): Run mosquitto version check only on labeled job or push 2025-01-20 12:56:02 +01:00
774bab22ea fix(common): Update esp-docs dependencies to fix docs-build job 2025-01-20 12:52:52 +01:00
265e38d684 Merge pull request #731 from tanyanquan/feat/update_subtype_removal
feat(mdns): supported removal of subtype when updating service (IDFGH-14413)
2025-01-20 09:48:27 +01:00
93f772171c Merge pull request #732 from david-cermak/fix/mdns_clangtiy_warns
[mdns]: Fixes clang-tidy warnings
2025-01-20 09:47:56 +01:00
4ad88e297f feat(mdns): supported removal of subtype when updating service 2025-01-16 10:56:54 +08:00
196198ecc9 fix(mdns): Fix zero-sized VLA clang-tidy warnings
and some minor leaks in creation of browse results
2025-01-15 14:23:34 +01:00
e838bf03f4 fix(mdns): Remove dead store to arg variable shared
Fixing: warning: Value stored to 'shared' is never read [clang-analyzer-deadcode.DeadStores]
2025-01-15 14:23:34 +01:00
99b54ac384 fix(mdns): Fix name mangling not to use strcpy()
Since it was flagged by clang-tidy as insecture API
2025-01-15 14:23:34 +01:00
f5be2f4115 fix(mdns): Fix potential null derefernce in _mdns_execute_action()
We did check for null-deref before checking 'a->type', but contol
continues and passes potential null-ptr to the processing function
_mdns_execute_action()
Fixed by asserting action != NULL, since it is an invalid state which
should never happen.
2025-01-15 14:21:59 +01:00
9b74256b51 Merge pull request #730 from david-cermak/fix/mdns_minor
[mdns]: Fixed some minor bugs
2025-01-15 12:27:05 +01:00
3d8835cfb9 fix(mdns): Fix AFL test mock per espressif/esp-idf@a5bc08fb55 2025-01-15 11:42:34 +01:00
24f55ce9b4 fix(mdns): Fixed potential out-of-bound interface error
invalid mdns_if was handled for enabling/announcing pcbs,
but not for the consequent browsing

Closes coverity isssue: 470162 Out-of-bounds access
2025-01-15 10:46:15 +01:00
8f8516cc3f fix(mdns): Fixed incorrect error conversion
Mixing esp_err_t (int) with err_t (uint8_t) from lwip.

Closes coverity isssue: 470139 Overflowed return value
2025-01-15 10:46:15 +01:00
75a8e8640a fix(mdns): Fixed potential overflow when allocating txt data
Closes coverity warning: 470092 Overflowed integer argument
2025-01-15 10:46:15 +01:00
907087c09b fix(mdns): Move MDNS_NAME_BUF_LEN to public headers
Since it's used by public API as maximum length of user buffer

Closes https://github.com/espressif/esp-protocols/issues/724
2025-01-15 10:46:10 +01:00
68a9e14898 fix(mdns): Cleanup includes in mdns.c
Closes https://github.com/espressif/esp-protocols/issues/725
2025-01-15 10:44:12 +01:00
827ea65fd5 fix(mdns): Allow advertizing service with port==0
Closes https://github.com/espressif/esp-idf/issues/14335
2025-01-15 10:44:12 +01:00
9537721600 fix(mdns): Fixed complier warning if MDNS_MAX_SERVICES==0
Closes https://github.com/espressif/esp-protocols/issues/611
2025-01-15 10:44:07 +01:00
4394f845fc Merge pull request #728 from david-cermak/bump/mdns_1.4.3
[mdns]: bump: 1.4.2 -> 1.4.3
2025-01-08 10:24:01 +01:00
9b0ba6060f bump(mdns): 1.4.2 -> 1.4.3
1.4.3
Features
- support zero item when update subtype (5bd82c01)
2025-01-08 09:42:38 +01:00
7c6a3098af Merge pull request #726 from zwx1995esp/feature/support_update_zero_item_of_subtype_for_mdns
feat(mdns): support zero item when update subtype (IDFGH-14369)
2025-01-07 18:40:25 +01:00
f3f3e23bec Merge pull request #727 from david-cermak/fix/sockutls_gai_error
fix(sockutls): Fix gai_strerror() impl to return const string
2025-01-07 15:59:24 +01:00
9ed835ba3f bump(sockutls): 0.2.1 -> 0.2.2
0.2.2
Bug Fixes
- Fix gai_strerror() impl to return const string (f12a2056)
2025-01-07 14:06:42 +01:00
f12a205657 fix(sockutls): Fix gai_strerror() impl to return const string
Previous gai_strerror() returned numeric representation of the code,
but used TLS storage, which might cause issues with stack sizes on all
tasks in the system. Alternatively we can leave the storage to static
only (which wouldn't be thread-safe) or we could one-time allocate and
never free (which is wrong).
This option uses hardcoded strings for common error codes used in lwip.
The disadvantage is that we might need to update the impl in the future
when lwip adds more codes.
2025-01-07 14:06:00 +01:00
zwx
5bd82c01a5 feat(mdns): support zero item when update subtype 2025-01-07 10:28:02 +08:00
b4cb8f8a66 Merge pull request #720 from david-cermak/fix/sock_utils_define_conflict
[sock-utils] Fix potential macro conflict
2024-12-20 16:36:08 +01:00
0499ed93df bump(sockutls): 0.2.0 -> 0.2.1
0.2.1
Bug Fixes
- Fix potential macro colission including standard headers (ade9448c)
2024-12-20 15:41:10 +01:00
ade9448c01 fix(sockutls): Fix potential macro colission including standard headers 2024-12-20 15:40:54 +01:00
4745fc8fe1 Merge pull request #719 from david-cermak/bump/mosq_2.2.0_1
[mosq]:  Bump: v2.0.20 -> 2.0.20~1
2024-12-20 15:31:13 +01:00
73e523e736 bump(mosq): 2.0.20 -> 2.0.20~1
2.0.20~1
Bug Fixes
- Use sock_utils instead of func stubs (3cd0ed37)
- Update API docs adding on-message callback (5dcc3330)
2024-12-20 15:09:41 +01:00
3cd0ed377b fix(mosq): Use sock_utils instead of func stubs 2024-12-20 15:07:42 +01:00
95294f5f89 fix(mosq): Add consistency check for api docs and versions 2024-12-20 15:07:37 +01:00
5dcc33300f fix(mosq): Update API docs adding on-message callback 2024-12-20 12:09:48 +01:00
840a561de4 Merge pull request #710 from david-cermak/feat/mosq_p2p_example
[mosq]: Add serverless broker example
2024-12-19 17:11:13 +01:00
e6fb8aa078 bump(mosq): 2.0.18~0 -> 2.0.20~0
2.0.20~0
Features
- Upgrade to mosquitto v2.0.20 (3b2c614d)
- Add support for on-message callback (cdeab8f5)
- Add example with two brokers synced on P2P (d57b8c5b)
Bug Fixes
- Fix dependency issues moving esp-tls to public deps (6cce87e4)
2024-12-19 16:51:49 +01:00
3b2c614d86 feat(mosq): Upgrade to mosquitto v2.0.20
Used tagged version v2.0.20
2024-12-19 16:41:37 +01:00
cdeab8f517 feat(mosq): Add support for on-message callback 2024-12-19 16:41:37 +01:00
6cce87e465 fix(mosq): Fix dependency issues moving esp-tls to public deps
Since esp-tls structs are using in public header files
2024-12-19 16:41:37 +01:00
d57b8c5b29 feat(mosq): Add example with two brokers synced on P2P
Broker-less two chip example which virtual private IoT
networks on MQTT protocol.
2024-12-19 16:40:02 +01:00
9c11003449 Merge pull request #713 from david-cermak/feat/sock_utiis_0.2
[sock-utils]: Bump 0.1 -> 0.2
2024-12-19 11:13:59 +01:00
85a7fc772c bump(sockutls): 0.1.0 -> 0.2.0
0.2.0
Features
- Declare socketpair and gai_strerror via standard headers (b090a3cb)
- Add support for gethostname() (f7c0b756)
2024-12-19 10:57:36 +01:00
b090a3cb69 feat(sockutls): Declare socketpair and gai_strerror via standard headers
Adding a reverse dependency to lwip and define macros, which
enable declarations of socketpair() and gai_strerror() in standard
heders (sys/socket.h and netdb.h)
2024-12-19 10:54:56 +01:00
42cde46c97 Merge pull request #714 from bryghtlabs-richard/chore/websocketTidying
Chore(websocket) tidy up two small issues
2024-12-17 11:35:57 +01:00
beb6e57e5e chore(websocket): align structure members 2024-12-16 16:20:21 -06:00
15d3a01e11 chore(websocket): remove unused client variable 2024-12-16 15:46:43 -06:00
e12ecb8e89 Merge pull request #707 from david-cermak/bugfix/sckutls_gethostname
[sock-utils]: Add support for gethostname()
2024-12-16 16:36:32 +01:00
54271a1b96 Merge pull request #709 from david-cermak/bump/modem_1.3
[modem]: bump 1.2.1 -> 1.3.0
2024-12-12 09:46:27 +01:00
886215032f bump(modem): 1.2.1 -> 1.3.0
1.3.0
Features
- Add mode detection to the example (18f196fa)
- Support for pausing network in C-API (1db83cd1)
- Add support for pausing netif (247f1681, #699)
Bug Fixes
- Minor cleanup of pppos example (5e929902)
- Fix PPP mode detection to accept LCP/conf (c989c6ad)
- Refine mode switch data->command (8b6ea331, #692)
- Detect serial ports properly (0cb59ff8)
- Fix CMUX enter to ignore URC before transition (1284f66d, #669)
2024-12-10 12:48:09 +01:00
269351f41c Merge pull request #700 from david-cermak/feat/modem_pause_network
[modem]: Add support for pausing netif
2024-12-10 12:14:10 +01:00
5e929902c7 fix(modem): Minor cleanup of pppos example
* Use CONFIG_EXAMPLE_DETECT_MODE_BEFORE_CONNECT to demonstrate mode
detect
* Use disconnection flag to indicate conneciton issue and gracefully
degrade to command mode
* Remove IDF-verion < v5.0 code
2024-12-10 11:36:10 +01:00
f7c0b7564a feat(sockutls): Add support for gethostname()
Closes https://github.com/espressif/esp-idf/issues/14849
2024-12-09 17:16:59 +01:00
c989c6adae fix(modem): Fix PPP mode detection to accept LCP/conf 2024-12-06 10:12:25 +01:00
18f196fa1e feat(modem): Add mode detection to the example 2024-12-06 09:48:00 +01:00
1db83cd1ca feat(modem): Support for pausing network in C-API
also adds a demo of this feature to pppos client example
2024-12-05 20:16:45 +01:00
247f1681e8 feat(modem): Add support for pausing netif
Closes https://github.com/espressif/esp-protocols/issues/699
2024-12-05 20:16:41 +01:00
32387f7e39 Merge pull request #702 from david-cermak/fix/modem_data_cmd_mode_refine
[modem]: Refine data -> command transition
2024-12-04 15:42:43 +01:00
dbc3ea6809 fix(common): Export IDF environment in bash shell
To avoid issues with IDF_PATH/export with the latest tools
2024-12-04 14:44:43 +01:00
8b6ea3311a fix(modem): Refine mode switch data->command
* netif.stop() moved after setting the transition callback
* send PPP escape sequence if enabled before waiting for transition to
complete
* add newline character before sync() command (after the "+++")

Closes https://github.com/espressif/esp-protocols/issues/692
2024-12-04 14:39:01 +01:00
8e55b93b59 Merge pull request #703 from david-cermak/fix/modem_cmux_data_before_switch
[modem]: CMUX: ignore URC before entering CMUX
2024-12-04 08:18:54 +01:00
0cb59ff80d fix(modem): Detect serial ports properly 2024-11-29 18:27:26 +01:00
1284f66d58 fix(modem): Fix CMUX enter to ignore URC before transition
Closes https://github.com/espressif/esp-protocols/issues/669
2024-11-29 17:32:35 +01:00
c5b49de2db Merge pull request #502 from espressif-abhikroy/component/console_cmd_mqtt
feat(console): Added component with mqtt command
2024-11-29 21:53:01 +11:00
2e9bb6ee45 bump(console): First version [1.0.0]
1.0.0
Features
- Added component with mqtt command (1fcc5b1d)
2024-11-29 21:48:50 +11:00
1fcc5b1d56 feat(console): Added component with mqtt command 2024-11-29 00:59:27 +11:00
849fe7b6cb Merge pull request #698 from david-cermak/fix/modem_minor_fixes_on_1.2
[modem]: Support for URC handler in C-API -> v1.2.1
2024-11-20 16:28:39 +01:00
5eadf1edee bump(modem): 1.2.0 -> 1.2.1
1.2.1
Bug Fixes
- Use higher GPIO range to support new chips (428fdbbd, #558)
- Remove tests and support for IDFv4.4, added IDFv5.4 (433a033f)
- Fix typo GENETIC -> GENERIC in mode types (090b1ff8, #667)
- Add support for URC handler into C-API (295d99df, #180)
2024-11-20 15:47:03 +01:00
428fdbbd80 fix(modem): Use higher GPIO range to support new chips
We can use IDF's Kconfig.env_caps in future, but that's not available on v5.0.

Closes https://github.com/espressif/esp-protocols/issues/558
2024-11-20 11:36:00 +01:00
433a033fcc fix(modem): Remove tests and support for IDFv4.4, added IDFv5.4 2024-11-20 11:35:33 +01:00
090b1ff845 fix(modem): Fix typo GENETIC -> GENERIC in mode types
Closes https://github.com/espressif/esp-protocols/issues/667
2024-11-20 10:25:20 +01:00
295d99df96 fix(modem): Add support for URC handler into C-API
Closes https://github.com/espressif/esp-protocols/issues/180
2024-11-20 10:15:22 +01:00
b65cff3a0b Merge pull request #696 from david-cermak/bump/mdsn_1.4.2
[mdns]: Bump to v1.4.2
2024-11-14 15:31:45 +01:00
e711f26670 bump(mdns): 1.4.1 -> 1.4.2
1.4.2
Features
- support update subtype (062b8dca)
Updated
- chore(mdns): Add more info to idf_component.yml (4a1cb65c)
2024-11-14 12:04:25 +01:00
4a1cb65c67 chore(mdns): Add more info to idf_component.yml
Fixing component manager warnings:
WARNING: A component description has not been provided in the manifest file. Please update your  file and include a brief description of the component.This will help other developers understand the purpose and functionality of your component. Documentation: https://***/projects/idf-component-manager/en/latest/guides/packaging_components.html#create-idf-component-yml
WARNING: A homepage URL has not been provided in the manifest file. Please update your  file and include the URL to the component's homepage. Documentation: https://***/projects/idf-component-manager/en/latest/guides/packaging_components.html#create-idf-component-yml
2024-11-14 12:03:56 +01:00
6c61dd39cf Merge pull request #693 from zwx1995esp/feat/support_add_remove_subtype
feat(mdns): support update subtype (IDFGH-14068)
2024-11-14 10:36:22 +01:00
8821ea3a99 Merge pull request #695 from david-cermak/bump/mdns_1.4.1
bump(mdns): 1.4.0 -> 1.4.1
2024-11-14 10:32:22 +01:00
zwx
062b8dcacc feat(mdns): support update subtype 2024-11-14 11:07:43 +08:00
7de57bb412 bump(mdns): 1.4.0 -> 1.4.1
1.4.1
Features
- Send PTR query for mdns browse when interface is ready (010a404a)
Bug Fixes
- Prevent deadlock when deleting a browse request (3f48f9ea)
- Fix use after free reported by coverity (25b3d5fd)
- Fixed dead-code reported by coverity (11846c7d)
2024-11-13 17:47:19 +01:00
67191f3bb5 Merge pull request #671 from david-cermak/feat/sock_utils
[sock-utils]: Add initial support for socket helpers
2024-11-11 18:29:45 +01:00
6d94ad646d bump(sockutls): Initial version 0.1.0
0.1.0
Features
- Add initial support for socket helpers (31f57ad0)
2024-11-11 16:47:57 +01:00
685d47cd2f fix(common): Disable clang-check for unsecure/deprecated APIs 2024-11-11 16:47:18 +01:00
31f57ad067 feat(sockutls): Add initial support for socket helpers 2024-11-11 16:47:13 +01:00
32ac21b03c Merge pull request #688 from david-cermak/fix/modem_docs_limitations
[modem]: bump: 1.1.0 -> 1.2.0
2024-11-11 16:26:41 +01:00
5b06a3b319 bump(modem): 1.1.0 -> 1.2.0
1.2.0
Features
- Add support for guessing mode (52598e5f)
- Delete CMUX internal implementation even if terminal exit fails (0e0cbd6b)
- Add support for handling URC (1b6a3b3b, #180)
- add ability to change ESP_MODEM_C_API_STR_MAX from Kconfig (17909892)
- Added target test config with CHAP authentication (f8ae7def)
- example add esp32p4 usb support (adafeae5)
- Publish mbedtls component (0140455f)
- host test support of the latest ESP-IDF release (3f74b4e8)
Bug Fixes
- Fix console example to use urc/detect features (1a9eaf3e)
- Update target test builds to use external Catch2 (554f022c)
- Fix arguments names when spawn esp_modem_xxx declarations (b6792c52)
- Remove catch dependency (c3480768)
- Examples: use local configs for MQTT topic/data (f5c13b92)
- Fixed clang-tidy warnings (70fa3af7)
- Fix CI build per IDFv5.3 (d0c17ef0)
- Fixed UART task to check for buffered data periodically (4bdd90cc, #536)
- Cleanup unused configs from PPPoS example (08a62ccc)
- Update CMUX example with SIM7070_gnss cleaned-up (56fe5327)
- Update console example with SIM7070_gnss format comments (5baaf542)
- Fix remaining print format warnings (3b80181d)
Updated
- docs(modem): Fix esp_modem_at_raw() description (C-API) (492a6a00)
- ci(common): updated github actions(checkout, upload, download) v3 to 4, Ubuntu 20.04 to v22.04 (a23a0027)
2024-11-07 12:42:11 +01:00
cc2741d4ad fix(modem): Document CMUX compatibility issue with CAVLI C16QS
Closes https://github.com/espressif/esp-protocols/issues/507
2024-11-07 12:41:47 +01:00
c5653ff204 Merge pull request #677 from david-cermak/fix/docs_links
[asio]: Fix links in documentation
2024-11-06 14:40:23 +01:00
77731c9b36 Merge pull request #678 from david-cermak/fix/modem_docs
[modem]: Fix docs to link tests correctly
2024-11-06 14:40:05 +01:00
2442f6b553 Merge pull request #612 from david-cermak/feat/modem_mode_detect
[modem]: Add support for guessing mode
2024-11-06 14:39:37 +01:00
0b5e362a7b Merge pull request #686 from bryghtlabs-richard/fix/wsExampleLeak
fix(websocket): fix example buffer leak
2024-11-05 17:11:35 +01:00
5219c39d09 fix(websocket): fix example buffer leak 2024-11-04 08:39:13 -06:00
1a9eaf3e98 fix(modem): Fix console example to use urc/detect features 2024-11-01 15:31:39 +01:00
52598e5f03 feat(modem): Add support for guessing mode 2024-11-01 13:49:52 +01:00
2d9759265b fix(modem): Fix docs to link tests correctly
Closes https://github.com/espressif/esp-protocols/issues/664
2024-10-25 12:56:08 +02:00
8f1f935858 fix(asio): Fix docs to link examples correctly 2024-10-25 12:43:19 +02:00
205 changed files with 7372 additions and 912 deletions

View File

@ -13,7 +13,7 @@ jobs:
name: Build
strategy:
matrix:
idf_ver: ["latest", "release-v5.0", "release-v5.1", "release-v5.2", "release-v5.3"]
idf_ver: ["latest", "release-v5.0", "release-v5.1", "release-v5.2", "release-v5.3", "release-v5.4"]
idf_target: ["esp32", "esp32s2"]
example: ["asio_chat", "async_request", "socks4", "ssl_client_server", "tcp_echo_server", "udp_echo_server"]
runs-on: ubuntu-22.04
@ -64,7 +64,7 @@ jobs:
name: Target tests
strategy:
matrix:
idf_ver: ["latest", "release-v5.0", "release-v5.2", "release-v5.3"]
idf_ver: ["latest", "release-v5.1", "release-v5.2", "release-v5.3", "release-v5.4"]
idf_target: ["esp32"]
example: ["asio_chat", "tcp_echo_server", "udp_echo_server", "ssl_client_server"]
needs: build_asio

View File

@ -9,10 +9,10 @@ on:
jobs:
build:
name: Run clang-tidy
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
container: espressif/idf:latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
submodules: 'true'
- name: Install esp-clang
@ -24,6 +24,7 @@ jobs:
chmod +x clang-tidy-sarif
curl -sSL https://raw.githubusercontent.com/espressif/idf-extra-components/master/.github/filter_sarif.py -o filter_sarif.py
- name: Install pyclang
shell: bash
run: |
. ${IDF_PATH}/export.sh
pip install pyclang~=0.2.0
@ -35,7 +36,7 @@ jobs:
working-directory: test_app
run: |
. ${IDF_PATH}/export.sh
idf.py clang-check --include-paths $GITHUB_WORKSPACE --exclude-paths $PWD --run-clang-tidy-py run-clang-tidy
idf.py clang-check --include-paths $GITHUB_WORKSPACE --exclude-paths $PWD --run-clang-tidy-py run-clang-tidy --run-clang-tidy-options "-checks=-clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling"
cp warnings.txt ../
- name: Convert clang-tidy results into SARIF output
run: |
@ -49,7 +50,7 @@ jobs:
results.sarif
results.sarif.raw
- name: Upload SARIF file
uses: github/codeql-action/upload-sarif@v2
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: results.sarif
category: clang-tidy

View File

@ -0,0 +1,32 @@
name: "console_cmd_mqtt: build-tests"
on:
push:
branches:
- master
pull_request:
types: [opened, synchronize, reopened, labeled]
jobs:
build_console_cmd_mqtt:
if: contains(github.event.pull_request.labels.*.name, 'console') || github.event_name == 'push'
name: Build
strategy:
matrix:
idf_ver: ["latest", "release-v5.0", "release-v5.1", "release-v5.2", "release-v5.3"]
idf_target: ["esp32"]
test: [ { app: mqtt_ssl_auth_console, path: "components/console_cmd_mqtt/examples" }]
runs-on: ubuntu-22.04
container: espressif/idf:${{ matrix.idf_ver }}
steps:
- name: Checkout esp-protocols
uses: actions/checkout@v4
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}/export.sh
pip install idf-component-manager idf-build-apps --upgrade
python ../../../ci/build_apps.py ./${{ matrix.test.app }} --target ${{ matrix.idf_target }} -vv --preserve-all --pytest-app

View File

@ -13,12 +13,15 @@ jobs:
name: Build examples
strategy:
matrix:
idf_ver: ["latest", "release-v5.1", "release-v5.2", "release-v5.3"]
idf_ver: ["latest", "release-v5.1", "release-v5.2", "release-v5.3", "release-v5.4"]
include:
- idf_ver: "latest"
warning: "Warning: The smallest app partition is nearly full"
runs-on: ubuntu-22.04
container: espressif/idf:${{ matrix.idf_ver }}
env:
TARGET_TEST: examples/esp_netif/slip_custom_netif/
TARGET_TEST_DIR: build_esp32c3_target
steps:
- name: Checkout esp-protocols
uses: actions/checkout@v4
@ -31,6 +34,16 @@ jobs:
python -m pip install idf-build-apps
# Build default configs for all targets
python ./ci/build_apps.py examples -m examples/.build-test-rules.yml -d -c
# Build target tests
python ./ci/build_apps.py ${TARGET_TEST} -r sdkconfig.ci=target
cd ${TARGET_TEST}
${GITHUB_WORKSPACE}/ci/clean_build_artifacts.sh `pwd`/${TARGET_TEST_DIR}
zip -qur artifacts.zip ${TARGET_TEST_DIR}
- uses: actions/upload-artifact@v4
with:
name: slip_target_${{ matrix.idf_ver }}
path: ${{ env.TARGET_TEST }}/artifacts.zip
if-no-files-found: error
build_and_run_on_host:
if: contains(github.event.pull_request.labels.*.name, 'examples') || github.event_name == 'push'
@ -51,3 +64,38 @@ jobs:
python ./ci/build_apps.py examples/mqtt -l -t linux
timeout 5 ./examples/mqtt/build_linux_default/esp_mqtt_demo.elf | tee test.log || true
grep 'MQTT_EVENT_DATA' test.log
run_on_target:
# Skip running on forks since it won't have access to secrets
if: |
github.repository == 'espressif/esp-protocols' &&
( contains(github.event.pull_request.labels.*.name, 'examples') || github.event_name == 'push' )
name: Slip example target test
needs: build_all_examples
strategy:
matrix:
idf_ver: ["release-v5.4", "latest"]
runs-on:
- self-hosted
- modem
env:
TARGET_TEST: examples/esp_netif/slip_custom_netif/
TARGET_TEST_DIR: build_esp32c3_target
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
name: slip_target_${{ matrix.idf_ver }}
path: ${{ env.TARGET_TEST }}/ci/
- name: Run Test
working-directory: ${{ env.TARGET_TEST }}
run: |
python -m venv .venv
source .venv/bin/activate
pip install --prefer-binary cryptography pytest-embedded pytest-embedded-serial-esp pytest-embedded-idf pytest-custom_exit_code esptool netifaces
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 --target=esp32c3
done

86
.github/workflows/lws_build.yml vendored Normal file
View File

@ -0,0 +1,86 @@
name: "lws: build-tests"
on:
push:
branches:
- master
pull_request:
types: [opened, synchronize, reopened, labeled]
jobs:
build_lws:
if: contains(github.event.pull_request.labels.*.name, 'lws') || github.event_name == 'push'
name: Libwebsockets build
strategy:
matrix:
idf_ver: ["latest", "release-v5.3", "release-v5.4"]
test: [ { app: example, path: "examples/client" }]
runs-on: ubuntu-22.04
container: espressif/idf:${{ matrix.idf_ver }}
env:
TEST_DIR: components/libwebsockets/${{ matrix.test.path }}
steps:
- name: Checkout esp-protocols
uses: actions/checkout@v4
with:
submodules: recursive
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }}
shell: bash
run: |
. ${IDF_PATH}/export.sh
python -m pip install idf-build-apps
python ./ci/build_apps.py ${TEST_DIR}
cd ${TEST_DIR}
for dir in `ls -d build_esp32_*`; do
$GITHUB_WORKSPACE/ci/clean_build_artifacts.sh `pwd`/$dir
zip -qur artifacts.zip $dir
done
- uses: actions/upload-artifact@v4
with:
name: lws_target_esp32_${{ matrix.idf_ver }}_${{ matrix.test.app }}
path: ${{ env.TEST_DIR }}/artifacts.zip
if-no-files-found: error
run-target-lws:
# Skip running on forks since it won't have access to secrets
if: |
github.repository == 'espressif/esp-protocols' &&
( contains(github.event.pull_request.labels.*.name, 'lws') || github.event_name == 'push' )
name: Target test
needs: build_lws
strategy:
fail-fast: false
matrix:
idf_ver: ["latest", "release-v5.3", "release-v5.4"]
idf_target: ["esp32"]
test: [ { app: example, path: "examples/client" }]
runs-on:
- self-hosted
- ESP32-ETHERNET-KIT
env:
TEST_DIR: components/libwebsockets/${{ matrix.test.path }}
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
name: lws_target_esp32_${{ matrix.idf_ver }}_${{ matrix.test.app }}
path: ${{ env.TEST_DIR }}/ci/
- name: Install Python packages
env:
PIP_EXTRA_INDEX_URL: "https://www.piwheels.org/simple"
run: |
pip install --only-binary cryptography --extra-index-url https://dl.espressif.com/pypi/ -r $GITHUB_WORKSPACE/ci/requirements.txt
- name: Run Example Test on target
working-directory: ${{ env.TEST_DIR }}
run: |
unzip ci/artifacts.zip -d ci
for dir in `ls -d ci/build_*`; do
rm -rf build sdkconfig.defaults
mv $dir build
python -m pytest --log-cli-level DEBUG --junit-xml=./results_${{ matrix.test.app }}_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${dir#"ci/build_"}.xml --target=${{ matrix.idf_target }}
done
- uses: actions/upload-artifact@v4
if: always()
with:
name: results_${{ matrix.test.app }}_${{ matrix.idf_target }}_${{ matrix.idf_ver }}.xml
path: components/libwebsockets/${{ matrix.test.path }}/*.xml

View File

@ -35,30 +35,36 @@ jobs:
# Next we run the pytest (using the console app)
pytest
build_afl_host_test_mdns:
host_compat_checks:
if: contains(github.event.pull_request.labels.*.name, 'mdns') || github.event_name == 'push'
name: Build AFL host test
name: Set of compatibility checks
strategy:
matrix:
idf_ver: ["latest"]
idf_target: ["esp32"]
runs-on: ubuntu-22.04
container: espressif/idf:${{ matrix.idf_ver }}
steps:
- name: Checkout esp-protocols
uses: actions/checkout@v4
with:
path: esp-protocols
- name: Install Necessary Libs
run: |
apt-get update -y
apt-get install -y libbsd-dev
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
env:
IDF_TARGET: ${{ matrix.idf_target }}
- name: Test AFL compat build
shell: bash
run: |
. ${IDF_PATH}/export.sh
cd $GITHUB_WORKSPACE/esp-protocols/components/mdns/tests/test_afl_fuzz_host/
cd components/mdns/tests/test_afl_fuzz_host/
make INSTR=off
- name: Test no malloc functions
shell: bash
run: |
cd components/mdns
for file in $(ls *.c); do
cp $file /tmp
echo -n "Checking that $file does not call any std allocations directly..."
python mem_prefix_script.py $file
diff -q $file /tmp/$file || exit 1
echo "OK"
done

View File

@ -13,11 +13,8 @@ jobs:
name: Build examples
strategy:
matrix:
idf_ver: ["latest", "release-v4.4", "release-v5.0", "release-v5.1", "release-v5.2", "release-v5.3"]
idf_ver: ["latest", "release-v5.0", "release-v5.1", "release-v5.2", "release-v5.3", "release-v5.4"]
example: ["pppos_client", "modem_console", "modem_tcp_client", "ap_to_pppos", "simple_cmux_client"]
exclude:
- idf_ver: "release-v4.4"
example: modem_tcp_client
include:
- idf_ver: "release-v5.0"
example: "simple_cmux_client"
@ -26,13 +23,7 @@ jobs:
runs-on: ubuntu-22.04
container: espressif/idf:${{ matrix.idf_ver }}
steps:
- name: Check out code (v3) # @v4 failed due to Node 20's requirement, incompatible with older IDF versions
if: matrix.idf_ver != 'latest' && matrix.idf_ver < 'release-v5.0'
uses: actions/checkout@v3
with:
path: protocols
- name: Check out code (v4)
if: matrix.idf_ver == 'latest' || matrix.idf_ver >= 'release-v5.0'
- name: Check out code
uses: actions/checkout@v4
with:
path: protocols
@ -53,7 +44,7 @@ jobs:
name: Build tests
strategy:
matrix:
idf_ver: ["release-v5.0", "release-v5.1", "release-v5.2", "release-v5.3", "latest"]
idf_ver: ["release-v5.0", "release-v5.1", "release-v5.2", "release-v5.3", "release-v5.4", "latest"]
test: ["target", "target_ota", "target_iperf"]
runs-on: ubuntu-22.04

View File

@ -42,7 +42,7 @@ jobs:
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
- uses: actions/upload-artifact@v4
with:
name: modem_target_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.test.app }}
path: ${{ env.TEST_DIR }}/build
@ -75,12 +75,17 @@ jobs:
run: |
sudo rm -fr $GITHUB_WORKSPACE && mkdir $GITHUB_WORKSPACE
- uses: actions/checkout@v3
- uses: actions/download-artifact@v3
- uses: actions/download-artifact@v4
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 }}
env:
PIP_EXTRA_INDEX_URL: "https://dl.espressif.com/pypi/"
run: |
python -m pip install -r $GITHUB_WORKSPACE/ci/requirements.txt
python -m venv .venv
source .venv/bin/activate
pip install --prefer-binary cryptography pytest-embedded pytest-embedded-serial-esp pytest-embedded-idf pytest-custom_exit_code esptool
pip install -r $GITHUB_WORKSPACE/ci/requirements.txt
cd ${{ env.TEST_DIR }}
python -m pytest --log-cli-level DEBUG --target=${{ matrix.idf_target }}

View File

@ -17,7 +17,8 @@ jobs:
runs-on: ubuntu-22.04
container: espressif/idf:${{ matrix.idf_ver }}
env:
TEST_DIR: components/mosquitto/examples/broker
TEST_DIR: components/mosquitto/examples
TARGET_TEST: broker
TARGET_TEST_DIR: build_esp32_default
steps:
- name: Checkout esp-protocols
@ -29,14 +30,15 @@ jobs:
run: |
. ${IDF_PATH}/export.sh
pip install idf-component-manager idf-build-apps --upgrade
python ci/build_apps.py ${TEST_DIR}
cd ${TEST_DIR}
python ci/build_apps.py -c ${TEST_DIR} -m components/mosquitto/.build-test-rules.yml
# upload only the target test artifacts
cd ${TEST_DIR}/${TARGET_TEST}
${GITHUB_WORKSPACE}/ci/clean_build_artifacts.sh `pwd`/${TARGET_TEST_DIR}
zip -qur artifacts.zip ${TARGET_TEST_DIR}
- uses: actions/upload-artifact@v4
with:
name: mosq_target_esp32_${{ matrix.idf_ver }}
path: ${{ env.TEST_DIR }}/artifacts.zip
path: ${{ env.TEST_DIR }}/${{ env.TARGET_TEST }}/artifacts.zip
if-no-files-found: error
test_mosq:
@ -71,3 +73,108 @@ jobs:
mv $dir build
python -m pytest --log-cli-level DEBUG --junit-xml=./results_esp32_${{ matrix.idf_ver }}_${dir#"ci/build_"}.xml --target=esp32
done
check_consistency:
if: contains(github.event.pull_request.labels.*.name, 'mosquitto') || github.event_name == 'push'
name: Checks that API docs and versions are consistent
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Checks API Docs and versions
run: |
sudo apt-get update
sudo apt-get -y install doxygen
pip install esp-doxybook
cd components/mosquitto
cp api.md api_orig.md
./generate_api_docs.sh
diff -wB api.md api_orig.md
# check version consistency
CONFIG_VERSION=$(grep -Po '(?<=#define VERSION ")[^"]*' port/priv_include/config.h)
CZ_VERSION=$(grep -Po '(?<=version: )[^"]*' .cz.yaml)
COMP_VERSION=$(grep -Po '(?<=version: ")[^"]*' idf_component.yml)
if [ "$CONFIG_VERSION" != "v$CZ_VERSION" ] || [ "$CONFIG_VERSION" != "v$COMP_VERSION" ]; then
echo "Version mismatch detected:"
echo "config.h: $CONFIG_VERSION"
echo ".cz.yaml: $CZ_VERSION"
echo "idf_component.yml: $COMP_VERSION"
exit 1
fi
echo "Versions are consistent: $CONFIG_VERSION"
build_idf_tests_with_mosq:
if: |
github.repository == 'espressif/esp-protocols' &&
( contains(github.event.pull_request.labels.*.name, 'mosquitto') || github.event_name == 'push' )
name: Build IDF tests
strategy:
matrix:
idf_ver: ["latest"]
idf_target: ["esp32"]
test: [ { app: publish, path: "tools/test_apps/protocols/mqtt/publish_connect_test" }]
runs-on: ubuntu-20.04
container: espressif/idf:${{ matrix.idf_ver }}
env:
TARGET_TEST_DIR: build_esp32_local_broker
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
submodules: recursive
- name: Build ${{ matrix.test.app }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
shell: bash
run: |
. ${IDF_PATH}/export.sh
pip install idf-component-manager idf-build-apps --upgrade
export MOSQUITTO_PATH=`pwd`/components/mosquitto
# to use the actual version of mosquitto
sed -i '/espressif\/mosquitto:/a \ \ \ \ override_path: "${MOSQUITTO_PATH}"' ${IDF_PATH}/${{matrix.test.path}}/main/idf_component.yml
export PEDANTIC_FLAGS="-DIDF_CI_BUILD -Werror -Werror=deprecated-declarations -Werror=unused-variable -Werror=unused-but-set-variable -Werror=unused-function"
export EXTRA_CFLAGS="${PEDANTIC_FLAGS} -Wstrict-prototypes"
export EXTRA_CXXFLAGS="${PEDANTIC_FLAGS}"
cd ${IDF_PATH}/${{matrix.test.path}}
idf-build-apps find --config sdkconfig.ci.local_broker -vv --target ${{ matrix.idf_target }} --build-dir=${TARGET_TEST_DIR}
idf-build-apps build --config sdkconfig.ci.local_broker -vv --target ${{ matrix.idf_target }} --build-dir=${TARGET_TEST_DIR}
${GITHUB_WORKSPACE}/ci/clean_build_artifacts.sh `pwd`/${TARGET_TEST_DIR}
# to replace mqtt test configs with specific mosquitto markers
python ${MOSQUITTO_PATH}/test/replace_decorators.py pytest_mqtt_publish_app.py ${TARGET_TEST_DIR}/pytest_mosquitto.py
zip -qur ${GITHUB_WORKSPACE}/artifacts.zip ${TARGET_TEST_DIR}
- uses: actions/upload-artifact@v4
with:
name: mosq_publish_esp32_${{ matrix.idf_ver }}
path: artifacts.zip
if-no-files-found: error
test_idf_ci_with_mosq:
# Skip running on forks since it won't have access to secrets
if: |
github.repository == 'espressif/esp-protocols' &&
( contains(github.event.pull_request.labels.*.name, 'mosquitto') || github.event_name == 'push' )
name: Mosquitto IDF target tests
needs: build_idf_tests_with_mosq
strategy:
matrix:
idf_ver: ["latest"]
runs-on:
- self-hosted
- ESP32-ETHERNET-KIT
env:
TEST_DIR: examples
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
name: mosq_publish_esp32_${{ matrix.idf_ver }}
path: ${{ env.TEST_DIR }}/ci/
- name: Run Test
working-directory: ${{ env.TEST_DIR }}
run: |
python -m pip install pytest-embedded-serial-esp pytest-embedded-idf pytest-rerunfailures pytest-timeout pytest-ignore-test-results "paho-mqtt<2"
unzip ci/artifacts.zip -d ci
for dir in `ls -d ci/build_*`; do
rm -rf build sdkconfig.defaults
mv $dir build
mv build/*.py .
# Run only "test_mosquitto" marked tests
python -m pytest --log-cli-level DEBUG --junit-xml=./results_esp32_${{ matrix.idf_ver }}_${dir#"ci/build_"}.xml --target=esp32 -m test_mosquitto
done

View File

@ -98,7 +98,10 @@ jobs:
components/console_cmd_ping;
components/console_cmd_ifconfig;
components/console_cmd_wifi;
components/console_cmd_mqtt;
components/mbedtls_cxx;
components/mosquitto;
components/sock_utils;
components/libwebsockets;
namespace: "espressif"
api_token: ${{ secrets.IDF_COMPONENT_API_TOKEN }}

95
.github/workflows/sockutls_build.yml vendored Normal file
View File

@ -0,0 +1,95 @@
name: "sock_utils: build-tests"
on:
push:
branches:
- master
pull_request:
types: [opened, synchronize, reopened, labeled]
jobs:
build_sock_utils:
if: contains(github.event.pull_request.labels.*.name, 'sock_utils') || github.event_name == 'push'
name: Socket helpers build
strategy:
matrix:
idf_ver: ["latest", "release-v5.3"]
runs-on: ubuntu-22.04
container: espressif/idf:${{ matrix.idf_ver }}
env:
TEST_DIR: components/sock_utils/examples/simple
TARGET_TEST_DIR: build_esp32_default
steps:
- name: Checkout esp-protocols
uses: actions/checkout@v4
with:
submodules: recursive
- name: Build with IDF-${{ matrix.idf_ver }}
shell: bash
run: |
. ${IDF_PATH}/export.sh
pip install idf-component-manager idf-build-apps --upgrade
python ci/build_apps.py ${TEST_DIR}
cd ${TEST_DIR}
${GITHUB_WORKSPACE}/ci/clean_build_artifacts.sh `pwd`/${TARGET_TEST_DIR}
zip -qur artifacts.zip ${TARGET_TEST_DIR}
- uses: actions/upload-artifact@v4
with:
name: sock_utils_target_esp32_${{ matrix.idf_ver }}
path: ${{ env.TEST_DIR }}/artifacts.zip
if-no-files-found: error
host_test_sock_utils:
if: contains(github.event.pull_request.labels.*.name, 'sock_utils') || github.event_name == 'push'
name: Socket helpers host test
strategy:
matrix:
idf_ver: ["latest", "release-v5.3"]
runs-on: ubuntu-22.04
container: espressif/idf:${{ matrix.idf_ver }}
env:
TEST_DIR: components/sock_utils/test/host
steps:
- name: Checkout esp-protocols
uses: actions/checkout@v4
with:
submodules: recursive
- name: Build with IDF-${{ matrix.idf_ver }}
shell: bash
run: |
. ${IDF_PATH}/export.sh
pip install idf-component-manager idf-build-apps --upgrade
cd ${TEST_DIR}
idf.py build
./build/sock_utils_host_test.elf
test_sock_utils:
# Skip running on forks since it won't have access to secrets
if: |
github.repository == 'espressif/esp-protocols' &&
( contains(github.event.pull_request.labels.*.name, 'sock_utils') || github.event_name == 'push' )
name: Socket helpers target test
needs: build_sock_utils
strategy:
matrix:
idf_ver: ["latest", "release-v5.3"]
runs-on:
- self-hosted
- ESP32-ETHERNET-KIT
env:
TEST_DIR: components/sock_utils/examples/simple
TARGET_TEST_DIR: build_esp32_default
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
name: sock_utils_target_esp32_${{ matrix.idf_ver }}
path: ${{ env.TEST_DIR }}/ci/
- name: Run Test
working-directory: ${{ env.TEST_DIR }}
run: |
unzip ci/artifacts.zip -d ci
for dir in `ls -d ci/build_*`; do
rm -rf build sdkconfig.defaults
mv $dir build
python -m pytest --log-cli-level DEBUG --junit-xml=./results_esp32_${{ matrix.idf_ver }}_${dir#"ci/build_"}.xml --target=esp32
done

5
.gitmodules vendored
View File

@ -1,6 +1,9 @@
[submodule "components/asio/asio"]
path = components/asio/asio
url = https://github.com/espressif/asio
url = https://github.com/chriskohlhoff/asio
[submodule "components/mosquitto/mosquitto"]
path = components/mosquitto/mosquitto
url = https://github.com/eclipse/mosquitto
[submodule "components/libwebsockets/libwebsockets"]
path = components/libwebsockets/libwebsockets
url = https://github.com/warmcat/libwebsockets.git

View File

@ -51,7 +51,7 @@ repos:
rev: v1.0.5
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', '--exclude-list=ci/ignore_astyle.txt']
args: ['--style=otbs', '--attach-namespaces', '--attach-classes', '--indent=spaces=4', '--convert-tabs', '--align-reference=name', '--keep-one-line-statements', '--pad-header', '--pad-oper', '--unpad-paren', '--max-continuation-indent=120', '--exclude-list=ci/ignore_astyle.txt']
- repo: https://github.com/commitizen-tools/commitizen
rev: v2.42.1
hooks:
@ -61,8 +61,8 @@ repos:
- repo: local
hooks:
- id: commit message scopes
name: "commit message must be scoped with: mdns, modem, websocket, asio, mqtt_cxx, console, common, eppp, tls_cxx, mosq"
entry: '\A(?!(feat|fix|ci|bump|test|docs|chore)\((mdns|modem|common|console|websocket|asio|mqtt_cxx|examples|eppp|tls_cxx|mosq)\)\:)'
name: "commit message must be scoped with: mdns, modem, websocket, asio, mqtt_cxx, console, common, eppp, tls_cxx, mosq, sockutls, lws"
entry: '\A(?!(feat|fix|ci|bump|test|docs|chore)\((mdns|modem|common|console|websocket|asio|mqtt_cxx|examples|eppp|tls_cxx|mosq|sockutls|lws)\)\:)'
language: pygrep
args: [--multiline]
stages: [commit-msg]

View File

@ -62,3 +62,11 @@ Please refer to instructions in [ESP-IDF](https://github.com/espressif/esp-idf)
* Brief introduction [README](components/mosquitto/README.md)
* API documentation [api.md](components/mosquitto/api.md)
### Socket helpers (sock-utils)
* Brief introduction [README](components/sock_utils/README.md)
### libwebsockets
* Brief introduction [README](components/libwebsockets/README.md)

View File

@ -0,0 +1 @@
components/mosquitto/examples/serverless_mqtt/components/libjuice/port/juice_random.c

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -64,7 +64,7 @@ static struct generic_queue_handle *create_generic_queue(queue_type_t type, uint
return h;
}
QueueHandle_t xQueueCreate(uint32_t uxQueueLength, uint32_t uxItemSize )
QueueHandle_t xQueueCreate(uint32_t uxQueueLength, uint32_t uxItemSize)
{
return (QueueHandle_t)create_generic_queue(QUEUE, uxQueueLength, uxItemSize);
}
@ -75,7 +75,7 @@ uint32_t xQueueSend(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t
return osal_queue_send(h->q, (uint8_t *)pvItemToQueue, h->item_size) ? pdTRUE : pdFAIL;
}
uint32_t xQueueSendToBack(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait )
uint32_t xQueueSendToBack(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait)
{
return xQueueSend(xQueue, pvItemToQueue, xTicksToWait);
}
@ -86,7 +86,7 @@ uint32_t xQueueReceive(QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksTo
return osal_queue_recv(h->q, (uint8_t *)pvBuffer, h->item_size, xTicksToWait) ? pdTRUE : pdFAIL;
}
BaseType_t xSemaphoreGive( QueueHandle_t xQueue)
BaseType_t xSemaphoreGive(QueueHandle_t xQueue)
{
struct generic_queue_handle *h = xQueue;
if (h->type == MUTEX) {
@ -96,7 +96,7 @@ BaseType_t xSemaphoreGive( QueueHandle_t xQueue)
return xQueueSend(xQueue, &s_semaphore_data, portMAX_DELAY);
}
BaseType_t xSemaphoreGiveRecursive( QueueHandle_t xQueue)
BaseType_t xSemaphoreGiveRecursive(QueueHandle_t xQueue)
{
struct generic_queue_handle *h = xQueue;
if (h->type == MUTEX_REC) {
@ -106,7 +106,7 @@ BaseType_t xSemaphoreGiveRecursive( QueueHandle_t xQueue)
return pdFALSE;
}
BaseType_t xSemaphoreTake( QueueHandle_t xQueue, TickType_t pvTask )
BaseType_t xSemaphoreTake(QueueHandle_t xQueue, TickType_t pvTask)
{
struct generic_queue_handle *h = xQueue;
if (h->type == MUTEX) {
@ -116,7 +116,7 @@ BaseType_t xSemaphoreTake( QueueHandle_t xQueue, TickType_t pvTask )
return xQueueReceive(xQueue, &s_semaphore_data, portMAX_DELAY);
}
BaseType_t xSemaphoreTakeRecursive( QueueHandle_t xQueue, TickType_t pvTask )
BaseType_t xSemaphoreTakeRecursive(QueueHandle_t xQueue, TickType_t pvTask)
{
struct generic_queue_handle *h = xQueue;
if (h->type == MUTEX_REC) {
@ -126,7 +126,7 @@ BaseType_t xSemaphoreTakeRecursive( QueueHandle_t xQueue, TickType_t pvTask )
return pdFALSE;
}
void vQueueDelete( QueueHandle_t xQueue )
void vQueueDelete(QueueHandle_t xQueue)
{
struct generic_queue_handle *h = xQueue;
if (h->q) {
@ -176,14 +176,14 @@ void vTaskSuspend(void *task)
vTaskDelete(task);
}
TickType_t xTaskGetTickCount( void )
TickType_t xTaskGetTickCount(void)
{
struct timespec spec;
clock_gettime(CLOCK_REALTIME, &spec);
return spec.tv_nsec / 1000000 + spec.tv_sec * 1000;
}
void vTaskDelay( const TickType_t xTicksToDelay )
void vTaskDelay(const TickType_t xTicksToDelay)
{
usleep(xTicksToDelay * 1000);
}
@ -212,13 +212,27 @@ void *pthread_task(void *params)
return NULL;
}
BaseType_t xTaskCreatePinnedToCore( TaskFunction_t pvTaskCode,
const char *const pcName,
const uint32_t usStackDepth,
void *const pvParameters,
UBaseType_t uxPriority,
TaskHandle_t *const pvCreatedTask,
const BaseType_t xCoreID)
TaskHandle_t xTaskCreateStaticPinnedToCore(TaskFunction_t pxTaskCode,
const char *const pcName,
const uint32_t ulStackDepth,
void *const pvParameters,
UBaseType_t uxPriority,
StackType_t *const puxStackBuffer,
StaticTask_t *const pxTaskBuffer,
const BaseType_t xCoreID)
{
static TaskHandle_t pvCreatedTask;
xTaskCreate(pxTaskCode, pcName, ulStackDepth, pvParameters, uxPriority, &pvCreatedTask);
return pvCreatedTask;
}
BaseType_t xTaskCreatePinnedToCore(TaskFunction_t pvTaskCode,
const char *const pcName,
const uint32_t usStackDepth,
void *const pvParameters,
UBaseType_t uxPriority,
TaskHandle_t *const pvCreatedTask,
const BaseType_t xCoreID)
{
xTaskCreate(pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pvCreatedTask);
return pdTRUE;
@ -266,7 +280,7 @@ void xTaskNotifyGive(TaskHandle_t task)
}
}
BaseType_t xTaskNotifyWait(uint32_t bits_entry_clear, uint32_t bits_exit_clear, uint32_t *value, TickType_t wait_time )
BaseType_t xTaskNotifyWait(uint32_t bits_entry_clear, uint32_t bits_exit_clear, uint32_t *value, TickType_t wait_time)
{
return true;
}
@ -276,32 +290,32 @@ TaskHandle_t xTaskGetCurrentTaskHandle(void)
return (TaskHandle_t)pthread_self();
}
EventGroupHandle_t xEventGroupCreate( void )
EventGroupHandle_t xEventGroupCreate(void)
{
return osal_signal_create();
}
void vEventGroupDelete( EventGroupHandle_t xEventGroup )
void vEventGroupDelete(EventGroupHandle_t xEventGroup)
{
osal_signal_delete(xEventGroup);
}
EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear )
EventBits_t xEventGroupClearBits(EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear)
{
return osal_signal_clear(xEventGroup, uxBitsToClear);
}
EventBits_t xEventGroupGetBits( EventGroupHandle_t xEventGroup)
EventBits_t xEventGroupGetBits(EventGroupHandle_t xEventGroup)
{
return osal_signal_get(xEventGroup);
}
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet )
EventBits_t xEventGroupSetBits(EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet)
{
return osal_signal_set(xEventGroup, uxBitsToSet);
}
EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait )
EventBits_t xEventGroupWaitBits(EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait)
{
return osal_signal_wait(xEventGroup, uxBitsToWaitFor, xWaitForAllBits, xTicksToWait);
}

View File

@ -1,11 +1,12 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "freertos/FreeRTOS.h"
#include "esp_heap_caps.h"
#ifdef __cplusplus
extern "C" {
@ -15,7 +16,10 @@ extern "C" {
#define TaskHandle_t TaskHandle_t
#define vSemaphoreDelete( xSemaphore ) vQueueDelete( ( QueueHandle_t ) ( xSemaphore ) )
void vTaskDelay( const TickType_t xTicksToDelay );
typedef void *StackType_t;
typedef void *StaticTask_t;
void vTaskDelay(const TickType_t xTicksToDelay);
void xTaskNotifyGive(TaskHandle_t task);
@ -23,39 +27,48 @@ void ulTaskNotifyTake(bool stuff, uint32_t timeout);
TaskHandle_t xTaskGetCurrentTaskHandle(void);
BaseType_t xTaskNotifyWait(uint32_t bits_entry_clear, uint32_t bits_exit_clear, uint32_t *value, TickType_t wait_time );
BaseType_t xTaskNotifyWait(uint32_t bits_entry_clear, uint32_t bits_exit_clear, uint32_t *value, TickType_t wait_time);
BaseType_t xTaskCreatePinnedToCore( TaskFunction_t pvTaskCode,
const char *const pcName,
const uint32_t usStackDepth,
void *const pvParameters,
UBaseType_t uxPriority,
TaskHandle_t *const pvCreatedTask,
const BaseType_t xCoreID);
TaskHandle_t xTaskCreateStaticPinnedToCore(TaskFunction_t pxTaskCode,
const char *const pcName,
const uint32_t ulStackDepth,
void *const pvParameters,
UBaseType_t uxPriority,
StackType_t *const puxStackBuffer,
StaticTask_t *const pxTaskBuffer,
const BaseType_t xCoreID);
BaseType_t xTaskCreatePinnedToCore(TaskFunction_t pvTaskCode,
const char *const pcName,
const uint32_t usStackDepth,
void *const pvParameters,
UBaseType_t uxPriority,
TaskHandle_t *const pvCreatedTask,
const BaseType_t xCoreID);
BaseType_t xTaskCreate(TaskFunction_t pvTaskCode, const char *const pcName, const uint32_t usStackDepth, void *const pvParameters, UBaseType_t uxPriority, TaskHandle_t *const pvCreatedTask);
TickType_t xTaskGetTickCount( void );
TickType_t xTaskGetTickCount(void);
void vQueueDelete( QueueHandle_t xQueue );
void vQueueDelete(QueueHandle_t xQueue);
QueueHandle_t xSemaphoreCreateBinary(void);
QueueHandle_t xSemaphoreCreateMutex(void);
QueueHandle_t xSemaphoreCreateRecursiveMutex(void);
BaseType_t xSemaphoreGive( QueueHandle_t xQueue);
BaseType_t xSemaphoreGive(QueueHandle_t xQueue);
BaseType_t xSemaphoreTake( QueueHandle_t xQueue, TickType_t pvTask );
BaseType_t xSemaphoreTake(QueueHandle_t xQueue, TickType_t pvTask);
BaseType_t xSemaphoreGiveRecursive( QueueHandle_t xQueue);
BaseType_t xSemaphoreGiveRecursive(QueueHandle_t xQueue);
BaseType_t xSemaphoreTakeRecursive( QueueHandle_t xQueue, TickType_t pvTask );
BaseType_t xSemaphoreTakeRecursive(QueueHandle_t xQueue, TickType_t pvTask);
void vTaskDelete(TaskHandle_t *task);
QueueHandle_t xQueueCreate( uint32_t uxQueueLength,
uint32_t uxItemSize );
QueueHandle_t xQueueCreate(uint32_t uxQueueLength,
uint32_t uxItemSize);
uint32_t xQueueSend(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait);
@ -63,23 +76,26 @@ uint32_t xQueueReceive(QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksTo
void vTaskSuspend(void *task);
EventGroupHandle_t xEventGroupCreate( void );
void vEventGroupDelete( EventGroupHandle_t xEventGroup );
EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToClear );
EventGroupHandle_t xEventGroupCreate(void);
void vEventGroupDelete(EventGroupHandle_t xEventGroup);
EventBits_t xEventGroupClearBits(EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToClear);
EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToWaitFor,
const BaseType_t xClearOnExit,
const BaseType_t xWaitForAllBits,
TickType_t xTicksToWait );
EventBits_t xEventGroupWaitBits(EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToWaitFor,
const BaseType_t xClearOnExit,
const BaseType_t xWaitForAllBits,
TickType_t xTicksToWait);
EventBits_t xEventGroupGetBits( EventGroupHandle_t xEventGroup);
EventBits_t xEventGroupGetBits(EventGroupHandle_t xEventGroup);
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToSet );
EventBits_t xEventGroupSetBits(EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToSet);
uint32_t xQueueSendToBack(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait );
uint32_t xQueueSendToBack(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait);
void *heap_caps_malloc(size_t size, uint32_t caps);
void heap_caps_free(void *ptr);
#ifdef __cplusplus
}

View File

@ -1,7 +1,8 @@
---
commitizen:
bump_message: 'bump(asio): $current_version -> $new_version'
pre_bump_hooks: python ../../ci/changelog.py asio
tag_format: asio-v$version
version: 1.28.0~0
version: 1.32.0
version_files:
- idf_component.yml

View File

@ -1,5 +1,26 @@
# Changelog
## [1.32.0](https://github.com/espressif/esp-protocols/commits/asio-v1.32.0)
### Features
- Upgrade asio to 1.32 ([9bdd429c](https://github.com/espressif/esp-protocols/commit/9bdd429c))
- Drop esp/asio patches in favor of sock-utils ([27435b7f](https://github.com/espressif/esp-protocols/commit/27435b7f))
### Bug Fixes
- Fix chat example to print only the message body ([76aaea08](https://github.com/espressif/esp-protocols/commit/76aaea08))
- Make asio enable if_nametoindex to fix linking ([5db32cce](https://github.com/espressif/esp-protocols/commit/5db32cce))
- Re-applie refs to common comps idf_component.yml ([9fe44a45](https://github.com/espressif/esp-protocols/commit/9fe44a45))
- Reference common component from IDF ([74fc228c](https://github.com/espressif/esp-protocols/commit/74fc228c))
- Revert referencing protocol_examples_common from IDF ([f9e0281a](https://github.com/espressif/esp-protocols/commit/f9e0281a))
- reference protocol_examples_common from IDF ([09abb18b](https://github.com/espressif/esp-protocols/commit/09abb18b))
- specify override_path in example manifest files ([1d8923cf](https://github.com/espressif/esp-protocols/commit/1d8923cf))
### Updated
- docs(asio): Updates asio docs ([ce9337d3](https://github.com/espressif/esp-protocols/commit/ce9337d3))
## [1.28.2~0](https://github.com/espressif/esp-protocols/commits/asio-1.28.2_0)
### Bug Fixes

View File

@ -6,8 +6,8 @@ if(NOT CONFIG_LWIP_IPV6 AND NOT CMAKE_BUILD_EARLY_EXPANSION)
return()
endif()
set(asio_sources "asio/asio/src/asio.cpp")
set(asio_requires lwip)
set(asio_sources "asio/asio/src/asio.cpp" "port/src/asio_stub.cpp")
set(asio_requires lwip sock_utils)
if(CONFIG_ASIO_SSL_SUPPORT)
list(APPEND asio_sources
@ -18,7 +18,7 @@ if(CONFIG_ASIO_SSL_SUPPORT)
endif()
idf_component_register(SRCS ${asio_sources}
INCLUDE_DIRS "asio/asio/include" "port/include"
INCLUDE_DIRS "port/include" "asio/asio/include"
PRIV_INCLUDE_DIRS ${asio_priv_includes}
PRIV_REQUIRES ${asio_requires})
@ -30,6 +30,7 @@ target_compile_definitions(${COMPONENT_LIB} PUBLIC SA_RESTART=0x01
ASIO_STANDALONE
ASIO_HAS_PTHREADS
OPENSSL_NO_ENGINE
ASIO_DETAIL_IMPL_POSIX_EVENT_IPP # this replaces asio's posix_event constructor
)
if(NOT CONFIG_COMPILER_CXX_EXCEPTIONS)

View File

@ -1,6 +1,15 @@
menu "ESP-ASIO"
visible if LWIP_IPV6
config ASIO_IS_ENABLED
# Invisible option that is enabled if ASIO is added to the IDF components.
# This is used to "select" LWIP_NETIF_API option
# which enables if_indextoname() and if_nametoindex() functions
# (these are optionally used in asio)
bool
default "y"
select LWIP_NETIF_API
config ASIO_SSL_SUPPORT
bool "Enable SSL/TLS support of ASIO"
default n

View File

@ -120,7 +120,7 @@ private:
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());
ESP_LOGD("asio-chat", "%.*s", read_msg_.body_length(), read_msg_.body());
room_.deliver(read_msg_);
do_read_header();
} else {

View File

@ -1,4 +1,4 @@
version: "1.28.2~0"
version: "1.32.0"
description: Cross-platform C++ library for network and I/O programming
url: https://github.com/espressif/esp-protocols/tree/master/components/asio
issues: https://github.com/espressif/esp-protocols/issues
@ -7,3 +7,5 @@ repository: https://github.com/espressif/esp-protocols.git
dependencies:
idf:
version: ">=5.0"
espressif/sock_utils:
version: "^0.1"

View File

@ -0,0 +1,11 @@
//
// SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
//
// SPDX-License-Identifier: BSL-1.0
//
#pragma once
#include "sys/socket.h"
#include "socketpair.h"
#include_next "asio/detail/config.hpp"

View File

@ -1,12 +0,0 @@
/*
* SPDX-FileCopyrightText: 2018-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _ESP_ASIO_CONFIG_H_
#define _ESP_ASIO_CONFIG_H_
#define ASIO_SSL_DETAIL_OPENSSL_TYPES_HPP
#include "openssl_stub.hpp"
#endif // _ESP_ASIO_CONFIG_H_

View File

@ -8,7 +8,7 @@
//
#include "asio/detail/config.hpp"
#include "openssl_stub.hpp"
#include "asio/ssl/detail/openssl_types.hpp"
#include <cstring>
#include "asio/detail/throw_error.hpp"
#include "asio/error.hpp"

View File

@ -7,7 +7,7 @@
//
#include "asio/detail/config.hpp"
#include "openssl_stub.hpp"
#include "asio/ssl/detail/openssl_types.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/error.hpp"
#include "asio/ssl/detail/engine.hpp"

View File

@ -0,0 +1,36 @@
//
// SPDX-FileCopyrightText: 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// SPDX-License-Identifier: BSL-1.0
//
// SPDX-FileContributor: 2024 Espressif Systems (Shanghai) CO LTD
//
#include "asio/detail/posix_event.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/error.hpp"
#include "asio/detail/push_options.hpp"
#include <unistd.h>
#include <climits>
namespace asio::detail {
// This replaces asio's posix_event constructor
// since the default POSIX version uses pthread_condattr_t operations (init, setclock, destroy),
// which are not available on all IDF versions (some are defined in compilers' headers, others in
// pthread library, but they typically return `ENOSYS` which causes trouble in the event wrapper)
// IMPORTANT: Check implementation of posix_event() when upgrading upstream asio in order not to
// miss any initialization step.
posix_event::posix_event()
: state_(0)
{
int error = ::pthread_cond_init(&cond_, nullptr);
asio::error_code ec(error, asio::error::get_system_category());
asio::detail::throw_error(ec, "event");
}
} // namespace asio::detail
extern "C" int pause (void)
{
while (true) {
::sleep(UINT_MAX);
}
}

View File

@ -0,0 +1,8 @@
---
commitizen:
bump_message: 'bump(console): $current_version -> $new_version'
pre_bump_hooks: python ../../ci/changelog.py console_cmd_mqtt
tag_format: console_cmd_mqtt-v$version
version: 1.0.0
version_files:
- idf_component.yml

View File

@ -0,0 +1,7 @@
# Changelog
## [1.0.0](https://github.com/espressif/esp-protocols/commits/console_cmd_mqtt-v1.0.0)
### Features
- Added component with mqtt command ([1fcc5b1d](https://github.com/espressif/esp-protocols/commit/1fcc5b1d))

View File

@ -0,0 +1,7 @@
idf_component_register(SRCS "console_mqtt.c"
INCLUDE_DIRS "."
PRIV_REQUIRES esp_netif console mqtt)
if(CONFIG_MQTT_CMD_AUTO_REGISTRATION)
target_link_libraries(${COMPONENT_LIB} PRIVATE "-u console_cmd_mqtt_register")
endif()

View File

@ -0,0 +1,15 @@
menu "MQTT Configuration"
config MQTT_CMD_AUTO_REGISTRATION
bool "Enable Console command mqtt Auto-registration"
default y
help
Enabling this allows for the autoregistration of the wifi command.
config MQTT_BROKER_URL
string "Broker URL or IP address"
default "mqtt://mqtt.eclipseprojects.io"
help
URL or IP address of the broker to connect to
endmenu

View File

@ -0,0 +1,87 @@
# Console command mqtt
The component provides a console where mqtt commands can be executed.
## MQTT Configuration:
1. Broker: Use menuconfig **"MQTT Configuration"** to configure the broker url.
## API
### Steps to enable console in an example code:
1. Add this component to your project using ```idf.py add-dependency``` command.
2. In the main file of the example, add the following line:
```c
#include "console_mqtt.h"
```
3. Ensure esp-netif is initialized and default event loop is created in your app_main():
```c
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
```
4. In your app_main() function, add the following line as the last line:
```c
ESP_ERROR_CHECK(console_cmd_init()); // Initialize console
// Register all plugin command added to your project
ESP_ERROR_CHECK(console_cmd_all_register());
// To register only mqtt command skip calling console_cmd_all_register()
ESP_ERROR_CHECK(console_cmd_mqtt_register());
ESP_ERROR_CHECK(console_cmd_start()); // Start console
```
Note: Auto-registration of a specific plugin command can be disabled from menuconfig.
### Certificate Integration for Mutual Authentication
To enhance security and enable secure communication over MQTT, three functions have been added to the API, allowing users to set client certificates, client keys, and broker certificates separately.
Setting the client certificate:
```c
set_mqtt_client_cert(client_cert_pem_start, client_cert_pem_end);
```
Setting the client key:
```c
set_mqtt_client_key(client_key_pem_start, client_key_pem_end);
```
Setting the broker certificate:
```c
set_mqtt_broker_certs(broker_cert_pem_start, broker_cert_pem_end);
```
Each function takes pointers to the start and end of the respective PEM-encoded data, allowing users to specify the necessary certificate and key information independently. For a complete secure MQTT setup, users should call all three functions in their application code.
To utilize these certificates, users need to include additional arguments when establishing MQTT connections using the library. Specifically, users should provide the `--cert`, `--key`, and `--cafile` options along with the MQTT connection command.
### Adding a plugin command or component:
To add a plugin command or any component from IDF component manager into your project, simply include an entry within the `idf_component.yml` file.
For more details refer [IDF Component Manager](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/tools/idf-component-manager.html)
## Suported command:
### mqtt:
```
mqtt [-CsD] [-h <host>] [-u <username>] [-P <password>] [--cert] [--key] [--cafile]
mqtt command
-C, --connect Connect to a broker (flag, no argument)
-h, --host=<host> Specify the host uri to connect to
-s, --status Displays the status of the mqtt client (flag, no argument)
-u, --username=<username> Provide a username to be used for authenticating with the broker
-P, --password=<password> Provide a password to be used for authenticating with the broker
--cert Define the PEM encoded certificate for this client, if required by the broker (flag, no argument)
--key Define the PEM encoded private key for this client, if required by the broker (flag, no argument)
--cafile Define the PEM encoded CA certificates that are trusted (flag, no argument)
--use-internal-bundle Use the internal certificate bundle for TLS (flag, no argument)
-D, --disconnect Disconnect from the broker (flag, no argument)
mqtt_pub [-t <topic>] [-m <message>]
mqtt publish command
-t, --topic=<topic> Topic to Subscribe/Publish
-m, --message=<message> Message to Publish
mqtt_sub [-U] [-t <topic>]
mqtt subscribe command
-t, --topic=<topic> Topic to Subscribe/Publish
-U, --unsubscribe Unsubscribe from a topic
```

View File

@ -0,0 +1,475 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <string.h>
#include "sdkconfig.h"
#include "esp_console.h"
#include "esp_event.h"
#include "esp_log.h"
#include "argtable3/argtable3.h"
#include "console_mqtt.h"
#include "mqtt_client.h"
#if defined(CONFIG_MBEDTLS_CERTIFICATE_BUNDLE)
#include "esp_crt_bundle.h"
#endif
static const char *TAG = "console_mqtt";
#define CONNECT_HELP_MSG "mqtt -C -h <host uri> -u <username> -P <password> --cert --key --cafile\n"
#define PUBLISH_HELP_MSG "Usage: mqtt -P -t <topic> -d <data>\n"
#define SUBSCRIBE_HELP_MSG "Usage: mqtt -S -t <topic>\n"
#define UNSUBSCRIBE_HELP_MSG "Usage: mqtt -U\n"
#define DISCONNECT_HELP_MSG "Usage: mqtt -D\n"
#if CONFIG_MQTT_CMD_AUTO_REGISTRATION
/**
* Static registration of this plugin is achieved by defining the plugin description
* structure and placing it into .console_cmd_desc section.
* The name of the section and its placement is determined by linker.lf file in 'plugins' component.
*/
static const console_cmd_plugin_desc_t __attribute__((section(".console_cmd_desc"), used)) PLUGIN = {
.name = "console_cmd_mqtt",
.plugin_regd_fn = &console_cmd_mqtt_register
};
#endif
static struct {
struct arg_lit *connect;
struct arg_str *uri;
struct arg_lit *status;
struct arg_str *username;
struct arg_str *password;
struct arg_lit *cert;
struct arg_lit *key;
struct arg_lit *cafile;
#if defined(CONFIG_MBEDTLS_CERTIFICATE_BUNDLE)
struct arg_lit *use_internal_bundle;
#endif
struct arg_lit *disconnect;
struct arg_end *end;
} mqtt_args;
static struct {
struct arg_str *topic;
struct arg_lit *unsubscribe;
struct arg_end *end;
} mqtt_sub_args;
static struct {
struct arg_str *topic;
struct arg_str *message;
struct arg_end *end;
} mqtt_pub_args;
typedef enum {
MQTT_STATE_INIT = 0,
MQTT_STATE_DISCONNECTED,
MQTT_STATE_CONNECTED,
MQTT_STATE_ERROR,
MQTT_STATE_STOPPED,
} mqtt_client_state_t;
mqtt_client_state_t client_status = MQTT_STATE_INIT;
static esp_mqtt_client_handle_t client_handle = NULL;
static const uint8_t *s_own_cert_pem_start = NULL;
static const uint8_t *s_own_cert_pem_end = NULL;
static const uint8_t *s_own_key_pem_start = NULL;
static const uint8_t *s_own_key_pem_end = NULL;
static const uint8_t *s_ca_cert_pem_start = NULL;
static const uint8_t *s_ca_cert_pem_end = NULL;
static void log_error_if_nonzero(const char *message, int error_code)
{
if (error_code != 0) {
ESP_LOGE(TAG, "Last error %s: 0x%x", message, error_code);
}
}
/*
* @brief Event handler registered to receive MQTT events
*
* This function is called by the MQTT client event loop.
*
* @param handler_args user data registered to the event.
* @param base Event base for the handler(always MQTT Base in this example).
* @param event_id The id for the received event.
* @param event_data The data for the event, esp_mqtt_event_handle_t.
*/
static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
{
ESP_LOGD(TAG, "Event dispatched from event loop base=%s, event_id=%" PRIi32, base, event_id);
esp_mqtt_event_handle_t event = event_data;
switch ((esp_mqtt_event_id_t)event_id) {
case MQTT_EVENT_BEFORE_CONNECT:
ESP_LOGI(TAG, "MQTT_EVENT_BEFORE_CONNECT");
break;
case MQTT_EVENT_CONNECTED:
client_status = MQTT_STATE_CONNECTED;
ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
break;
case MQTT_EVENT_DISCONNECTED:
client_status = MQTT_STATE_DISCONNECTED;
ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
break;
case MQTT_EVENT_SUBSCRIBED:
ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id);
break;
case MQTT_EVENT_UNSUBSCRIBED:
ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);
break;
case MQTT_EVENT_PUBLISHED:
ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
break;
case MQTT_EVENT_DATA:
ESP_LOGI(TAG, "MQTT_EVENT_DATA");
ESP_LOGI(TAG, "TOPIC=%.*s\r\n", event->topic_len, event->topic);
ESP_LOGI(TAG, "DATA=%.*s\r\n", event->data_len, event->data);
break;
case MQTT_EVENT_ERROR:
client_status = MQTT_STATE_ERROR;
ESP_LOGI(TAG, "MQTT_EVENT_ERROR");
if (event->error_handle->error_type == MQTT_ERROR_TYPE_TCP_TRANSPORT) {
log_error_if_nonzero("reported from esp-tls", event->error_handle->esp_tls_last_esp_err);
log_error_if_nonzero("reported from tls stack", event->error_handle->esp_tls_stack_err);
log_error_if_nonzero("captured as transport's socket errno", event->error_handle->esp_transport_sock_errno);
ESP_LOGI(TAG, "Last errno string (%s)", strerror(event->error_handle->esp_transport_sock_errno));
}
break;
default:
ESP_LOGI(TAG, "Other event id:%d", event->event_id);
break;
}
}
static const char *mqtt_state_to_string(mqtt_client_state_t state)
{
switch (state) {
case MQTT_STATE_INIT:
return "Initializing";
case MQTT_STATE_DISCONNECTED:
return "Disconnected";
case MQTT_STATE_CONNECTED:
return "Connected";
case MQTT_STATE_ERROR:
return "Error";
case MQTT_STATE_STOPPED:
return "Disconnected and Stopped";
default:
return "Unknown State";
}
}
static int do_mqtt_cmd(int argc, char **argv)
{
int nerrors = arg_parse(argc, argv, (void **)&mqtt_args);
if (nerrors != 0) {
arg_print_errors(stderr, mqtt_args.end, argv[0]);
return 1;
}
if (mqtt_args.status->count > 0) {
ESP_LOGI(TAG, "MQTT Client Status: %s\n", mqtt_state_to_string(client_status));
return 0;
}
if (mqtt_args.connect->count > 0) {
if (client_handle != NULL) {
ESP_LOGW(TAG, "mqtt client already connected");
ESP_LOGI(TAG, "Try: %s", DISCONNECT_HELP_MSG);
return 0;
}
char *uri = CONFIG_MQTT_BROKER_URL;
if (mqtt_args.uri->count > 0) {
uri = (char *)mqtt_args.uri->sval[0];
}
esp_mqtt_client_config_t mqtt_cfg = {
.broker.address.uri = uri,
};
if ((mqtt_args.username->count > 0) && (mqtt_args.password->count > 0)) {
mqtt_cfg.credentials.username = mqtt_args.username->sval[0];
mqtt_cfg.credentials.authentication.password = mqtt_args.password->sval[0];
}
ESP_LOGI(TAG, "broker: %s", mqtt_cfg.broker.address.uri);
#if defined(CONFIG_MBEDTLS_CERTIFICATE_BUNDLE)
/* Ensure --use_internal_bundle and --cafile are mutually exclusive */
if ((mqtt_args.use_internal_bundle->count > 0) && (mqtt_args.cafile->count > 0)) {
ESP_LOGE(TAG, "Error: Options can't be used together. Use either --use-internal-bundle or --cafile. \n");
return 1;
}
if (mqtt_args.use_internal_bundle->count > 0) {
mqtt_cfg.broker.verification.crt_bundle_attach = esp_crt_bundle_attach;
}
#endif
if (mqtt_args.cafile->count > 0) {
if (s_ca_cert_pem_start && s_ca_cert_pem_end) {
mqtt_cfg.broker.verification.certificate = (const char *)s_ca_cert_pem_start;
} else {
ESP_LOGW(TAG, "cafile not provided");
}
}
if (mqtt_args.cert->count > 0) {
if (s_own_cert_pem_start && s_own_cert_pem_end) {
mqtt_cfg.credentials.authentication.certificate = (const char *)s_own_cert_pem_start;
} else {
ESP_LOGW(TAG, "cert not provided");
}
if (mqtt_args.key->count > 0) {
if (s_own_key_pem_start && s_own_key_pem_end) {
mqtt_cfg.credentials.authentication.key = (const char *)s_own_key_pem_start;
} else {
ESP_LOGW(TAG, "key not provided");
}
} else {
mqtt_cfg.credentials.authentication.key = NULL;
}
}
client_handle = esp_mqtt_client_init(&mqtt_cfg);
if (client_handle == NULL) {
ESP_LOGE(TAG, "ERROR: Client init");
ESP_LOGI(TAG, "Try: %s", DISCONNECT_HELP_MSG);
ESP_LOGE(TAG, CONNECT_HELP_MSG);
return 1;
}
/* The last argument may be used to pass data to the event handler, in this example mqtt_event_handler */
esp_mqtt_client_register_event(client_handle, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL);
esp_mqtt_client_start(client_handle);
} else if (mqtt_args.disconnect->count > 0) {
ESP_LOGD(TAG, "Disconnect command received:");
if (client_handle == NULL) {
ESP_LOGE(TAG, "mqtt client not connected");
return 0;
}
if (esp_mqtt_client_stop(client_handle) != ESP_OK) {
ESP_LOGE(TAG, "Failed to stop mqtt client task");
return 1;
}
client_handle = NULL;
client_status = MQTT_STATE_STOPPED;
ESP_LOGI(TAG, "mqtt client disconnected and stopped");
}
return 0;
}
esp_err_t set_mqtt_client_cert(const uint8_t *client_cert_pem_start_i, const uint8_t *client_cert_pem_end_i)
{
if (!client_cert_pem_start_i || !client_cert_pem_end_i ||
(client_cert_pem_start_i > client_cert_pem_end_i)) {
ESP_LOGE(TAG, "Invalid mqtt Client certs(%d)\n", __LINE__);
return ESP_ERR_INVALID_ARG;
}
s_own_cert_pem_start = client_cert_pem_start_i;
s_own_cert_pem_end = client_cert_pem_end_i;
return ESP_OK;
}
esp_err_t set_mqtt_client_key(const uint8_t *client_key_pem_start_i, const uint8_t *client_key_pem_end_i)
{
if (client_key_pem_start_i && client_key_pem_end_i &&
(client_key_pem_start_i >= client_key_pem_end_i)) {
ESP_LOGE(TAG, "Invalid mqtt Client key(%d)\n", __LINE__);
return ESP_ERR_INVALID_ARG;
}
s_own_key_pem_start = client_key_pem_start_i;
s_own_key_pem_end = client_key_pem_end_i;
return ESP_OK;
}
esp_err_t set_mqtt_broker_certs(const uint8_t *ca_cert_pem_start_i, const uint8_t *ca_cert_pem_end_i)
{
if (!ca_cert_pem_start_i || !ca_cert_pem_end_i ||
(ca_cert_pem_start_i > ca_cert_pem_end_i)) {
ESP_LOGE(TAG, "Invalid mqtt ca cert(%d)\n", __LINE__);
return ESP_ERR_INVALID_ARG;
}
s_ca_cert_pem_start = ca_cert_pem_start_i;
s_ca_cert_pem_end = ca_cert_pem_end_i;
return ESP_OK;
}
static int do_mqtt_sub_cmd(int argc, char **argv)
{
int msg_id;
int nerrors = arg_parse(argc, argv, (void **)&mqtt_sub_args);
if (nerrors != 0) {
arg_print_errors(stderr, mqtt_sub_args.end, argv[0]);
return 1;
}
if (client_handle == NULL) {
ESP_LOGE(TAG, "mqtt client not connected");
return 0;
}
if (mqtt_sub_args.unsubscribe->count > 0) {
if (mqtt_sub_args.topic->count <= 0) {
ESP_LOGE(TAG, UNSUBSCRIBE_HELP_MSG);
return 0;
}
char *topic = (char *)mqtt_sub_args.topic->sval[0];
msg_id = esp_mqtt_client_unsubscribe(client_handle, mqtt_sub_args.topic->sval[0]);
ESP_LOGI(TAG, "Unsubscribe successful, msg_id=%d, topic=%s", msg_id, topic);
} else {
if (mqtt_sub_args.topic->count <= 0) {
ESP_LOGE(TAG, SUBSCRIBE_HELP_MSG);
return 0;
}
char *topic = (char *)mqtt_sub_args.topic->sval[0];
msg_id = esp_mqtt_client_subscribe(client_handle, topic, 0);
ESP_LOGI(TAG, "Subscribe successful, msg_id=%d, topic=%s", msg_id, topic);
}
return 0;
}
static int do_mqtt_pub_cmd(int argc, char **argv)
{
int msg_id;
int nerrors = arg_parse(argc, argv, (void **)&mqtt_pub_args);
if (nerrors != 0) {
arg_print_errors(stderr, mqtt_pub_args.end, argv[0]);
return 1;
}
if (client_handle == NULL) {
ESP_LOGE(TAG, "mqtt client not connected");
return 0;
}
if ((mqtt_pub_args.topic->count <= 0) || (mqtt_pub_args.message->count <= 0)) {
ESP_LOGE(TAG, PUBLISH_HELP_MSG);
}
msg_id = esp_mqtt_client_publish(client_handle,
mqtt_pub_args.topic->sval[0],
mqtt_pub_args.message->sval[0],
0, 1, 0);
if (msg_id == -1) {
ESP_LOGE(TAG, "mqtt client not connected");
return 0;
}
ESP_LOGI(TAG, "Publish successful, msg_id=%d, topic=%s, data=%s",
msg_id, mqtt_pub_args.topic->sval[0], mqtt_pub_args.message->sval[0]);
return 0;
}
/**
* @brief Registers the mqtt commands.
*
* @return
* - esp_err_t
*/
esp_err_t console_cmd_mqtt_register(void)
{
esp_err_t ret = ESP_OK;
/* Register mqtt */
mqtt_args.connect = arg_lit0("C", "connect", "Connect to a broker (flag, no argument)");
mqtt_args.uri = arg_str0("h", "host", "<host>", "Specify the host uri to connect to");
mqtt_args.status = arg_lit0("s", "status", "Displays the status of the mqtt client (flag, no argument)");
mqtt_args.username = arg_str0("u", "username", "<username>", "Provide a username to be used for authenticating with the broker");
mqtt_args.password = arg_str0("P", "password", "<password>", "Provide a password to be used for authenticating with the broker");
mqtt_args.cert = arg_lit0(NULL, "cert", "Define the PEM encoded certificate for this client, if required by the broker (flag, no argument)");
mqtt_args.key = arg_lit0(NULL, "key", "Define the PEM encoded private key for this client, if required by the broker (flag, no argument)");
mqtt_args.cafile = arg_lit0(NULL, "cafile", "Define the PEM encoded CA certificates that are trusted (flag, no argument)");
#if defined(CONFIG_MBEDTLS_CERTIFICATE_BUNDLE)
mqtt_args.use_internal_bundle = arg_lit0(NULL, "use-internal-bundle", "Use the internal certificate bundle for TLS (flag, no argument)");
#endif
mqtt_args.disconnect = arg_lit0("D", "disconnect", "Disconnect from the broker (flag, no argument)");
mqtt_args.end = arg_end(1);
const esp_console_cmd_t mqtt_cmd = {
.command = "mqtt",
.help = "mqtt command",
.hint = NULL,
.func = &do_mqtt_cmd,
.argtable = &mqtt_args
};
ret = esp_console_cmd_register(&mqtt_cmd);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Unable to register mqtt");
return ret;
}
/* Register mqtt_pub */
mqtt_pub_args.topic = arg_str0("t", "topic", "<topic>", "Topic to Subscribe/Publish");
mqtt_pub_args.message = arg_str0("m", "message", "<message>", "Message to Publish");
mqtt_pub_args.end = arg_end(1);
const esp_console_cmd_t mqtt_pub_cmd = {
.command = "mqtt_pub",
.help = "mqtt publish command",
.hint = NULL,
.func = &do_mqtt_pub_cmd,
.argtable = &mqtt_pub_args
};
ret = esp_console_cmd_register(&mqtt_pub_cmd);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Unable to register mqtt_pub");
return ret;
}
/* Register mqtt_sub */
mqtt_sub_args.topic = arg_str0("t", "topic", "<topic>", "Topic to Subscribe/Publish");
mqtt_sub_args.unsubscribe = arg_lit0("U", "unsubscribe", "Unsubscribe from a topic");
mqtt_sub_args.end = arg_end(1);
const esp_console_cmd_t mqtt_sub_cmd = {
.command = "mqtt_sub",
.help = "mqtt subscribe command",
.hint = NULL,
.func = &do_mqtt_sub_cmd,
.argtable = &mqtt_sub_args
};
ret = esp_console_cmd_register(&mqtt_sub_cmd);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Unable to register mqtt_sub");
}
return ret;
}

View File

@ -0,0 +1,73 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "console_simple_init.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Registers the mqtt command.
*
* @return
* - esp_err_t
*/
esp_err_t console_cmd_mqtt_register(void);
/**
* @brief Set MQTT client certificate
*
* This function sets the MQTT client certificate for secure communication.
* The function takes the PEM(Privacy Enhanced Mail) encoded certificate arguments.
*
* @param client_cert_pem_start_i Pointer to the beginning of the client certificate PEM data.
* @param client_cert_pem_end_i Pointer to the end of the client certificate PEM data.
*
* @return
* ESP_OK on success
* ESP_ERR_INVALID_ARG on invalid arguments
*/
esp_err_t set_mqtt_client_cert(const uint8_t *client_cert_pem_start_i, const uint8_t *client_cert_pem_end_i);
/**
* @brief Set MQTT client key
*
* This function sets the MQTT client key for secure communication.
* The function takes the PEM(Privacy Enhanced Mail) encoded key arguments.
*
* @param client_key_pem_start_i Pointer to the beginning of the client key PEM data.
* @param client_key_pem_end_i Pointer to the end of the client key PEM data.
*
* @return
* ESP_OK on success
* ESP_ERR_INVALID_ARG on invalid arguments
*/
esp_err_t set_mqtt_client_key(const uint8_t *client_key_pem_start_i, const uint8_t *client_key_pem_end_i);
/**
* @brief Set MQTT broker certificate
*
* This function sets the MQTT broker certificate for secure communication.
* The function takes the PEM(Privacy Enhanced Mail) encoded broker certificate arguments.
*
* @param broker_cert_pem_start_i Pointer to the beginning of the broker certificate PEM data.
* @param broker_cert_pem_end_i Pointer to the end of the broker certificate PEM data.
*
* @return
* ESP_OK on success
* ESP_ERR_INVALID_ARG on invalid arguments
*/
esp_err_t set_mqtt_broker_certs(const uint8_t *broker_cert_pem_start_i, const uint8_t *broker_cert_pem_end_i);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,11 @@
# The following five lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(mqtt_ssl_auth_console)
# Certs for mqtts://test.mosquitto.org:8884
target_add_binary_data(${CMAKE_PROJECT_NAME}.elf "certs/client.crt" TEXT)
target_add_binary_data(${CMAKE_PROJECT_NAME}.elf "certs/client.key" TEXT)
target_add_binary_data(${CMAKE_PROJECT_NAME}.elf "certs/mosquitto.org.pem" TEXT)

View File

@ -0,0 +1,174 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- |
# ESP-MQTT SSL Authentication Console
This example demonstrates the use of the MQTT command-line component to connect to both secured and unsecured MQTT brokers. It provides multiple modes of connection, including:
* Unsecured transport: Connect to a broker without encryption.
* SSL/TLS transport: Securely connect using SSL/TLS with options for:
* Validating the broker using a provided CA certificate.
* Validating the broker using the internal certificate bundle.
* Performing SSL mutual authentication using client and broker certificates.
Additionally, the example allows subscribing to topics, unsubscribing from topics, and publishing messages to a specified topic through commands. Connections to the broker at test.mosquitto.org are used to demonstrate these features.
(Please note that the public broker is maintained by the community so may not be always available, for details please visit http://test.mosquitto.org)
It uses ESP-MQTT library which implements mqtt client to connect to mqtt broker.
## How to use example
### Hardware Required
This example can be executed on any ESP32 board, the only required interface is WiFi and connection to internet.
### Configure the project
* Open the project configuration menu (`idf.py menuconfig`)
* Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details.
* Generate your client keys and certificate (specific to testing with Mosquitto broker)
Note: The following steps are for testing with the Mosquitto broker. If you're using a different broker, you may need to adapt the steps to meet your broker's certificate and key requirements.
#### Steps for SSL Mutual authentication:
Navigate to the certs directory
```
cd certs
```
Generate a client key and a CSR. When you are generating the CSR, do not use the default values. At a minimum, the CSR must include the Country, Organisation and Common Name fields.
```
openssl genrsa -out client.key
openssl req -out client.csr -key client.key -new
```
Paste the generated CSR in the [Mosquitto test certificate signer](https://test.mosquitto.org/ssl/index.php), click Submit and copy the downloaded `client.crt` in the `main` directory.
Please note, that the supplied files `client.crt` and `client.key` in the `main` directory are only placeholders for your client certificate and key (i.e. the example "as is" would compile but would not connect to the broker)
The broker certificate `mosquitto.org.pem` can be downloaded in pem format from [mosquitto.org.crt](https://test.mosquitto.org/ssl/mosquitto.org.crt). Convert it to `mosquitto.org.pem` simply by renaming it.
Note: If your certificate and key file names differ, update the root `CMakeLists.txt` file and main/`mqtt_ssl_auth_console.c` accordingly.
### Build and Flash
Build the project and flash it to the board, then run monitor tool to view serial output:
```
idf.py -p PORT flash monitor
```
(To exit the serial monitor, type ``Ctrl-]``.)
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
Warning: This example might need a bigger app partition size if you're compiling it for debug. To ensere this issue doesn't happen "optimize for size is enabled in menuconfig.
### Command Usage:
```
esp> help
help [<string>]
Print the summary of all registered commands if no arguments are given,
otherwise print summary of given command.
<string> Name of command
mqtt [-CsD] [-h <host>] [-u <username>] [-P <password>] [--cert] [--key] [--cafile]
mqtt command
-C, --connect Connect to a broker (flag, no argument)
-h, --host=<host> Specify the host uri to connect to
-s, --status Displays the status of the mqtt client (flag, no argument)
-u, --username=<username> Provide a username to be used for authenticating with the broker
-P, --password=<password> Provide a password to be used for authenticating with the broker
--cert Define the PEM encoded certificate for this client, if required by the broker (flag, no argument)
--key Define the PEM encoded private key for this client, if required by the broker (flag, no argument)
--cafile Define the PEM encoded CA certificates that are trusted (flag, no argument)
--use-internal-bundle Use the internal certificate bundle for TLS (flag, no argument)
-D, --disconnect Disconnect from the broker (flag, no argument)
mqtt_pub [-t <topic>] [-m <message>]
mqtt publish command
-t, --topic=<topic> Topic to Subscribe/Publish
-m, --message=<message> Message to Publish
mqtt_sub [-U] [-t <topic>]
mqtt subscribe command
-t, --topic=<topic> Topic to Subscribe/Publish
-U, --unsubscribe Unsubscribe from a topic
```
### Connection:
#### Connect without Validating the Broker:
This option connects to the broker without validating its certificate. It is not secure.
```
mqtt -h mqtts://test.mosquitto.org -C
```
or
```
mqtt -h mqtts://mqtt.eclipseprojects.io -C
```
#### Validate the Broker using the Internal Certificate Bundle:
This option uses the ESP-IDF's built-in certificate bundle to verify the broker's identity.
```
mqtt -h mqtts://mqtt.eclipseprojects.io -C --use-internal-bundle
```
or
```
mqtt -h mqtts://test.mosquitto.org -C --use-internal-bundle
```
#### Validate the Broker using a Provided CA Certificate:
This option requires you to provide the broker's CA certificate for validation.
```
mqtt -h mqtts://test.mosquitto.org -C --cafile
```
#### SSL Mutual Authentication(encrypted, client certificate required):
This option performs client authentication in addition to broker validation. It requires the client certificate, private key, and broker CA certificate.
```
mqtt -h mqtts://test.mosquitto.org:8884 -C --cert --key --cafile
```
or
```
mqtt -h mqtts://test.mosquitto.org:8884 -C --cert --key --use-internal-bundle
```
Note: In this example, the broker's certificate is included in the certificate bundle (refer to sdkconfig.default).
### Disconnect:
```
esp> mqtt -D
I (1189949) console_mqtt: mqtt client disconnected
```
### Subscribe/Unsubscribe:
```
esp> mqtt_sub -t test0
I (897289) console_mqtt: Subscribe successful, msg_id=57425, topic=test0
esp> I (897799) console_mqtt: MQTT_EVENT_SUBSCRIBED, msg_id=57425
esp>
esp> mqtt_sub -U -t test0
I (902009) console_mqtt: Unsubscribe successful, msg_id=27663, topic=test0
esp> I (902509) console_mqtt: MQTT_EVENT_UNSUBSCRIBED, msg_id=27663
```
### Publish:
```
esp> mqtt_pub -t test0 -m "Hello, Testing 123"
I (999469) console_mqtt: Publish successful, msg_id=55776, topic=test0, data=Hello, Testing 123
I (1000009) console_mqtt: MQTT_EVENT_PUBLISHED, msg_id=55776
esp>
```
### Receiving data event:
```
esp> I (999999) console_mqtt: MQTT_EVENT_DATA
I (999999) console_mqtt: TOPIC=test0
I (999999) console_mqtt: DATA=Hello, Testing 123
```

View File

@ -0,0 +1,24 @@
-----BEGIN CERTIFICATE-----
MIIEAzCCAuugAwIBAgIUBY1hlCGvdj4NhBXkZ/uLUZNILAwwDQYJKoZIhvcNAQEL
BQAwgZAxCzAJBgNVBAYTAkdCMRcwFQYDVQQIDA5Vbml0ZWQgS2luZ2RvbTEOMAwG
A1UEBwwFRGVyYnkxEjAQBgNVBAoMCU1vc3F1aXR0bzELMAkGA1UECwwCQ0ExFjAU
BgNVBAMMDW1vc3F1aXR0by5vcmcxHzAdBgkqhkiG9w0BCQEWEHJvZ2VyQGF0Y2hv
by5vcmcwHhcNMjAwNjA5MTEwNjM5WhcNMzAwNjA3MTEwNjM5WjCBkDELMAkGA1UE
BhMCR0IxFzAVBgNVBAgMDlVuaXRlZCBLaW5nZG9tMQ4wDAYDVQQHDAVEZXJieTES
MBAGA1UECgwJTW9zcXVpdHRvMQswCQYDVQQLDAJDQTEWMBQGA1UEAwwNbW9zcXVp
dHRvLm9yZzEfMB0GCSqGSIb3DQEJARYQcm9nZXJAYXRjaG9vLm9yZzCCASIwDQYJ
KoZIhvcNAQEBBQADggEPADCCAQoCggEBAME0HKmIzfTOwkKLT3THHe+ObdizamPg
UZmD64Tf3zJdNeYGYn4CEXbyP6fy3tWc8S2boW6dzrH8SdFf9uo320GJA9B7U1FW
Te3xda/Lm3JFfaHjkWw7jBwcauQZjpGINHapHRlpiCZsquAthOgxW9SgDgYlGzEA
s06pkEFiMw+qDfLo/sxFKB6vQlFekMeCymjLCbNwPJyqyhFmPWwio/PDMruBTzPH
3cioBnrJWKXc3OjXdLGFJOfj7pP0j/dr2LH72eSvv3PQQFl90CZPFhrCUcRHSSxo
E6yjGOdnz7f6PveLIB574kQORwt8ePn0yidrTC1ictikED3nHYhMUOUCAwEAAaNT
MFEwHQYDVR0OBBYEFPVV6xBUFPiGKDyo5V3+Hbh4N9YSMB8GA1UdIwQYMBaAFPVV
6xBUFPiGKDyo5V3+Hbh4N9YSMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL
BQADggEBAGa9kS21N70ThM6/Hj9D7mbVxKLBjVWe2TPsGfbl3rEDfZ+OKRZ2j6AC
6r7jb4TZO3dzF2p6dgbrlU71Y/4K0TdzIjRj3cQ3KSm41JvUQ0hZ/c04iGDg/xWf
+pp58nfPAYwuerruPNWmlStWAXf0UTqRtg4hQDWBuUFDJTuWuuBvEXudz74eh/wK
sMwfu1HFvjy5Z0iMDU8PUDepjVolOCue9ashlS4EB5IECdSR2TItnAIiIwimx839
LdUdRudafMu5T5Xma182OC0/u/xRlEm+tvKGGmfFcN0piqVl8OrSPBgIlb+1IKJE
m/XriWr/Cq4h/JfB7NTsezVslgkBaoU=
-----END CERTIFICATE-----

View File

@ -0,0 +1,2 @@
idf_component_register(SRCS "mqtt_ssl_auth_console.c"
INCLUDE_DIRS ".")

View File

@ -0,0 +1,8 @@
dependencies:
idf:
version: ">=5.0"
protocol_examples_common:
path: ${IDF_PATH}/examples/common_components/protocol_examples_common
console_cmd_mqtt:
version: "*"
override_path: '../../../'

View File

@ -0,0 +1,51 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <stdio.h>
#include "nvs_flash.h"
#include "esp_netif.h"
#include "esp_event.h"
#include <netdb.h>
#include "console_mqtt.h"
#include "protocol_examples_common.h"
// Certs for mqtts://test.mosquitto.org:8884
extern const uint8_t g_client_cert_pem_start[] asm("_binary_client_crt_start");
extern const uint8_t g_client_cert_pem_end[] asm("_binary_client_crt_end");
extern const uint8_t g_client_key_pem_start[] asm("_binary_client_key_start");
extern const uint8_t g_client_key_pem_end[] asm("_binary_client_key_end");
extern const uint8_t g_broker_cert_pem_start[] asm("_binary_mosquitto_org_pem_start");
extern const uint8_t g_broker_cert_pem_end[] asm("_binary_mosquitto_org_pem_end");
void app_main(void)
{
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
esp_err_t ret = nvs_flash_init(); //Initialize NVS
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(ret);
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
* Read "Establishing Wi-Fi or Ethernet Connection" section in
* ${IDF_PATH}/examples/protocols/README.md for more information about this function.
*/
ESP_ERROR_CHECK(example_connect());
// Initialize console REPL
ESP_ERROR_CHECK(console_cmd_init());
ESP_ERROR_CHECK(console_cmd_all_register());
set_mqtt_client_cert(g_client_cert_pem_start, g_client_cert_pem_end);
set_mqtt_client_key(g_client_key_pem_start, g_client_key_pem_end);
set_mqtt_broker_certs(g_broker_cert_pem_start, g_broker_cert_pem_end);
// start console REPL
ESP_ERROR_CHECK(console_cmd_start());
}

View File

@ -0,0 +1,19 @@
# SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Unlicense OR CC0-1.0
# -*- coding: utf-8 -*-
import pytest
@pytest.mark.esp32
def test_examples_ifconfig_command(dut):
dut.expect('esp>', timeout=30)
dut.write('help mqtt')
dut.expect(r'mqtt \[-CsD\] \[-h <host>\] \[-u <username>\] \[-P <password>\] \[--cert\] \[--key\] \[--cafile\]', timeout=30)
dut.write('help mqtt_pub')
dut.expect(r'mqtt_pub \[-t <topic>\] \[-m <message>\]', timeout=30)
dut.write('help mqtt_sub')
dut.expect(r'mqtt_sub \[-U\] \[-t <topic>\]', timeout=30)

View File

@ -0,0 +1,7 @@
# This file was generated using idf.py save-defconfig. It can be edited manually.
# Espressif IoT Development Framework (ESP-IDF) 5.5.0 Project Minimal Configuration
#
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_CMN=y
CONFIG_MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE=y
CONFIG_MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE_PATH="certs/mosquitto.org.pem"

View File

@ -0,0 +1,11 @@
version: 1.0.0
url: https://github.com/espressif/esp-protocols/tree/master/components/console_cmd_mqtt
description: The component provides a console where the 'mqtt' command can be executed.
license: Apache-2.0
dependencies:
idf:
version: '>=5.0'
espressif/console_simple_init:
version: '>=1.1.0'
override_path: '../console_simple_init'
public: true

View File

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

View File

@ -1,5 +1,63 @@
# Changelog
## [1.3.0](https://github.com/espressif/esp-protocols/commits/modem-v1.3.0)
### Features
- Add mode detection to the example ([18f196fa](https://github.com/espressif/esp-protocols/commit/18f196fa))
- Support for pausing network in C-API ([1db83cd1](https://github.com/espressif/esp-protocols/commit/1db83cd1))
- Add support for pausing netif ([247f1681](https://github.com/espressif/esp-protocols/commit/247f1681), [#699](https://github.com/espressif/esp-protocols/issues/699))
### Bug Fixes
- Minor cleanup of pppos example ([5e929902](https://github.com/espressif/esp-protocols/commit/5e929902))
- Fix PPP mode detection to accept LCP/conf ([c989c6ad](https://github.com/espressif/esp-protocols/commit/c989c6ad))
- Refine mode switch data->command ([8b6ea331](https://github.com/espressif/esp-protocols/commit/8b6ea331), [#692](https://github.com/espressif/esp-protocols/issues/692))
- Detect serial ports properly ([0cb59ff8](https://github.com/espressif/esp-protocols/commit/0cb59ff8))
- Fix CMUX enter to ignore URC before transition ([1284f66d](https://github.com/espressif/esp-protocols/commit/1284f66d), [#669](https://github.com/espressif/esp-protocols/issues/669))
## [1.2.1](https://github.com/espressif/esp-protocols/commits/modem-v1.2.1)
### Bug Fixes
- Use higher GPIO range to support new chips ([428fdbbd](https://github.com/espressif/esp-protocols/commit/428fdbbd), [#558](https://github.com/espressif/esp-protocols/issues/558))
- Remove tests and support for IDFv4.4, added IDFv5.4 ([433a033f](https://github.com/espressif/esp-protocols/commit/433a033f))
- Fix typo GENETIC -> GENERIC in mode types ([090b1ff8](https://github.com/espressif/esp-protocols/commit/090b1ff8), [#667](https://github.com/espressif/esp-protocols/issues/667))
- Add support for URC handler into C-API ([295d99df](https://github.com/espressif/esp-protocols/commit/295d99df), [#180](https://github.com/espressif/esp-protocols/issues/180))
## [1.2.0](https://github.com/espressif/esp-protocols/commits/modem-v1.2.0)
### Features
- Add support for guessing mode ([52598e5f](https://github.com/espressif/esp-protocols/commit/52598e5f))
- Delete CMUX internal implementation even if terminal exit fails ([0e0cbd6b](https://github.com/espressif/esp-protocols/commit/0e0cbd6b))
- Add support for handling URC ([1b6a3b3b](https://github.com/espressif/esp-protocols/commit/1b6a3b3b), [#180](https://github.com/espressif/esp-protocols/issues/180))
- add ability to change ESP_MODEM_C_API_STR_MAX from Kconfig ([17909892](https://github.com/espressif/esp-protocols/commit/17909892))
- Added target test config with CHAP authentication ([f8ae7def](https://github.com/espressif/esp-protocols/commit/f8ae7def))
- example add esp32p4 usb support ([adafeae5](https://github.com/espressif/esp-protocols/commit/adafeae5))
- Publish mbedtls component ([0140455f](https://github.com/espressif/esp-protocols/commit/0140455f))
- host test support of the latest ESP-IDF release ([3f74b4e8](https://github.com/espressif/esp-protocols/commit/3f74b4e8))
### Bug Fixes
- Fix console example to use urc/detect features ([1a9eaf3e](https://github.com/espressif/esp-protocols/commit/1a9eaf3e))
- Update target test builds to use external Catch2 ([554f022c](https://github.com/espressif/esp-protocols/commit/554f022c))
- Fix arguments names when spawn esp_modem_xxx declarations ([b6792c52](https://github.com/espressif/esp-protocols/commit/b6792c52))
- Remove catch dependency ([c3480768](https://github.com/espressif/esp-protocols/commit/c3480768))
- Examples: use local configs for MQTT topic/data ([f5c13b92](https://github.com/espressif/esp-protocols/commit/f5c13b92))
- Fixed clang-tidy warnings ([70fa3af7](https://github.com/espressif/esp-protocols/commit/70fa3af7))
- Fix CI build per IDFv5.3 ([d0c17ef0](https://github.com/espressif/esp-protocols/commit/d0c17ef0))
- Fixed UART task to check for buffered data periodically ([4bdd90cc](https://github.com/espressif/esp-protocols/commit/4bdd90cc), [#536](https://github.com/espressif/esp-protocols/issues/536))
- Cleanup unused configs from PPPoS example ([08a62ccc](https://github.com/espressif/esp-protocols/commit/08a62ccc))
- Update CMUX example with SIM7070_gnss cleaned-up ([56fe5327](https://github.com/espressif/esp-protocols/commit/56fe5327))
- Update console example with SIM7070_gnss format comments ([5baaf542](https://github.com/espressif/esp-protocols/commit/5baaf542))
- Fix remaining print format warnings ([3b80181d](https://github.com/espressif/esp-protocols/commit/3b80181d))
### Updated
- docs(modem): Fix esp_modem_at_raw() description (C-API) ([492a6a00](https://github.com/espressif/esp-protocols/commit/492a6a00))
- ci(common): updated github actions(checkout, upload, download) v3 to 4, Ubuntu 20.04 to v22.04 ([a23a0027](https://github.com/espressif/esp-protocols/commit/a23a0027))
## [1.1.0](https://github.com/espressif/esp-protocols/commits/modem-v1.1.0)
### Features

View File

@ -76,4 +76,20 @@ menu "esp-modem"
help
If enabled, APIs to add URC handler are available
config ESP_MODEM_PPP_ESCAPE_BEFORE_EXIT
bool "Send escape sequence when switching PPP -> CMD"
default n
help
If enabled, the library sends a PPP escape ("+++" command)
to switch to command mode. This make switching from PPP to CMD
mode more robust for some devices (e.g. Quectel), but might cause
trouble for other devices (e.g. SIMCOM).
config ESP_MODEM_ADD_DEBUG_LOGS
bool "Add UART Tx/Rx logs"
default n
help
If enabled, the library dumps all transmitted and received data.
This option is only used for debugging.
endmenu

View File

@ -15,7 +15,3 @@ By default, this example simply connects to the PPP server using a supported dev
This example however, doesn't rely on sending specific AT commands, just the bare minimum to setup the cellular network.
Thus, if the `EXAMPLE_USE_MINIMAL_DCE` option is enabled, we directly inherit from the `ModuleIf` and implement only the basic commands.
Also, to demonstrate the dce_factory functionality, a new `NetDCE_Factory` is implemented for creating the network module and the DCE.
### Supported IDF versions
This example is only supported from `v4.2`, since is uses NAPT feature.

View File

@ -17,7 +17,3 @@ over PPPoS, i.e. over the modem serial line.
* Experiment with the network, after getting the IP from the modem device
- directly in the code
- in the system (need to set `tun` interface IP, dns servers, and routing the desired traffic over the tun interface)
### 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.

View File

@ -25,9 +25,3 @@ USB example uses Quactel BG96 modem device. BG96 needs a positive pulse on its P
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`.

View File

@ -108,28 +108,28 @@ menu "Example Configuration"
config EXAMPLE_MODEM_UART_TX_PIN
int "TXD Pin Number"
default 25
range 0 31
range 0 56
help
Pin number of UART TX.
config EXAMPLE_MODEM_UART_RX_PIN
int "RXD Pin Number"
default 26
range 0 31
range 0 56
help
Pin number of UART RX.
config EXAMPLE_MODEM_UART_RTS_PIN
int "RTS Pin Number"
default 27
range 0 31
range 0 56
help
Pin number of UART RTS.
config EXAMPLE_MODEM_UART_CTS_PIN
int "CTS Pin Number"
default 23
range 0 31
range 0 56
help
Pin number of UART CTS.
@ -179,7 +179,7 @@ menu "Example Configuration"
config EXAMPLE_MODEM_PWRKEY_PIN
int "PWRKEY Pin Number"
default 18
range 0 31
range 0 56
help
Pin number connected to modem's power key pin.
endmenu

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
@ -89,7 +89,7 @@ void wakeup_modem(void)
vTaskDelay(pdMS_TO_TICKS(2000));
}
#ifdef CONFIG_EXAMPLE_MODEM_DEVICE_SHINY
#ifdef CONFIG_ESP_MODEM_URC_HANDLER
command_result handle_urc(uint8_t *data, size_t len)
{
ESP_LOG_BUFFER_HEXDUMP("on_read", data, len, ESP_LOG_INFO);
@ -238,7 +238,9 @@ 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 == "UNDEF") {
if (mode == "AUTO") {
dev_mode = esp_modem::modem_mode::AUTODETECT;
} else if (mode == "UNDEF") {
dev_mode = esp_modem::modem_mode::UNDEF;
} else if (mode == "CMUX1") {
dev_mode = esp_modem::modem_mode::CMUX_MANUAL_MODE;
@ -370,19 +372,30 @@ extern "C" void app_main(void)
ESP_LOGI(TAG, "Resetting the module...");
CHECK_ERR(dce->reset(), ESP_LOGI(TAG, "OK"));
});
#ifdef CONFIG_EXAMPLE_MODEM_DEVICE_SHINY
#ifdef CONFIG_ESP_MODEM_URC_HANDLER
const ConsoleCommand HandleURC("urc", "toggle urc handling", no_args, [&](ConsoleCommand * c) {
static int cnt = 0;
if (++cnt % 2) {
ESP_LOGI(TAG, "Adding URC handler");
dce->set_on_read(handle_urc);
dce->set_urc(handle_urc);
} else {
ESP_LOGI(TAG, "URC removed");
dce->set_on_read(nullptr);
dce->set_urc(nullptr);
}
return 0;
});
#endif
const ConsoleCommand PauseNetwork("pause_net", "toggle network pause", no_args, [&](ConsoleCommand * c) {
static int cnt = 0;
if (++cnt % 2) {
ESP_LOGI(TAG, "Pausing netif");
dce->pause_netif(true);
} else {
ESP_LOGI(TAG, "Unpausing netif");
dce->pause_netif(false);
}
return 0;
});
const struct SetApn {
SetApn(): apn(STR1, nullptr, nullptr, "<apn>", "APN (Access Point Name)") {}

View File

@ -20,14 +20,14 @@ menu "Example Configuration"
config EXAMPLE_MODEM_UART_TX_PIN
int "TXD Pin Number"
default 4
range 0 31
range 0 56
help
Pin number of UART TX.
config EXAMPLE_MODEM_UART_RX_PIN
int "RXD Pin Number"
default 5
range 0 31
range 0 56
help
Pin number of UART RX.
@ -70,14 +70,14 @@ menu "Example Configuration"
config EXAMPLE_MODEM_PWRKEY_PIN
int "PWRKEY Pin Number"
default 18
range 0 31
range 0 56
help
Pin number connected to modem's power key pin.
config EXAMPLE_MODEM_STATUS_PIN
int "STATUS Pin Number"
default 19
range 0 31
range 0 56
help
Pin number connected to modem's status pin.

View File

@ -22,7 +22,3 @@ To enable this mode, please set `EXAMPLE_CUSTOM_TCP_TRANSPORT=y`
This configuration could be used with any network library, which is connecting to a localhost endpoint instead of remote one. This example creates a localhost listener which basically mimics the remote endpoint by forwarding the traffic between the library and the TCP/socket layer of the modem (which is already secure if the TLS is used in the network library)
![with localhost listener](at_client_localhost.png)
### Supported IDF versions
This example is supported from IDF `v5.0`.

View File

@ -30,28 +30,28 @@ menu "Example Configuration"
config EXAMPLE_MODEM_UART_TX_PIN
int "TXD Pin Number"
default 25
range 0 31
range 0 56
help
Pin number of UART TX.
config EXAMPLE_MODEM_UART_RX_PIN
int "RXD Pin Number"
default 26
range 0 31
range 0 56
help
Pin number of UART RX.
config EXAMPLE_MODEM_UART_RTS_PIN
int "RTS Pin Number"
default 27
range 0 31
range 0 56
help
Pin number of UART RTS.
config EXAMPLE_MODEM_UART_CTS_PIN
int "CTS Pin Number"
default 23
range 0 31
range 0 56
help
Pin number of UART CTS.

View File

@ -18,9 +18,3 @@ For USB enabled targets (ESP32-S2, ESP32-S3, or ESP32-P4), it is possible to con
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.
### Supported IDF versions
This example is only supported from `v4.1`, as this is the default dependency of `esp-modem` component.
USB example is supported from `v4.4`.

View File

@ -100,28 +100,28 @@ menu "Example Configuration"
config EXAMPLE_MODEM_UART_TX_PIN
int "TXD Pin Number"
default 25
range 0 31
range 0 56
help
Pin number of UART TX.
config EXAMPLE_MODEM_UART_RX_PIN
int "RXD Pin Number"
default 26
range 0 31
range 0 56
help
Pin number of UART RX.
config EXAMPLE_MODEM_UART_RTS_PIN
int "RTS Pin Number"
default 27
range 0 31
range 0 56
help
Pin number of UART RTS.
config EXAMPLE_MODEM_UART_CTS_PIN
int "CTS Pin Number"
default 23
range 0 31
range 0 56
help
Pin number of UART CTS.
@ -201,4 +201,23 @@ menu "Example Configuration"
help
MQTT data message, which we publish and expect to receive.
config EXAMPLE_PAUSE_NETIF_TO_CHECK_SIGNAL
bool "Demonstrate netif pause"
default n
help
Set this to true to demonstrate network pausing.
If enabled, the example waits for an MQTT data, then temporarily
drops network to check signal quality, resumes networking and
publishes another MQTT message.
Connection to the MQTT broker should be kept.
config EXAMPLE_DETECT_MODE_BEFORE_CONNECT
bool "Detect mode before connect"
default n
help
Set this to true to demonstrate mode auto-detection.
If enabled, the example tries to recognize the actual mode.
If mode is detected correctly and it is not a command mode,
then the example switches to command mode.
endmenu

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
@ -34,6 +34,7 @@
static const char *TAG = "pppos_example";
static EventGroupHandle_t event_group = NULL;
static const int CONNECT_BIT = BIT0;
static const int DISCONNECT_BIT = BIT1;
static const int GOT_DATA_BIT = BIT2;
static const int USB_DISCONNECTED_BIT = BIT3; // Used only with USB DTE but we define it unconditionally, to avoid too many #ifdefs in the code
@ -55,6 +56,7 @@ static void usb_terminal_error_handler(esp_modem_terminal_error_t err)
}
#define CHECK_USB_DISCONNECTION(event_group) \
if ((xEventGroupGetBits(event_group) & USB_DISCONNECTED_BIT) == USB_DISCONNECTED_BIT) { \
ESP_LOGE(TAG, "USB_DISCONNECTED_BIT destroying modem dce"); \
esp_modem_destroy(dce); \
continue; \
}
@ -140,6 +142,7 @@ static void on_ip_event(void *arg, esp_event_base_t event_base,
ESP_LOGI(TAG, "GOT ip event!!!");
} else if (event_id == IP_EVENT_PPP_LOST_IP) {
ESP_LOGI(TAG, "Modem Disconnect from PPP Server");
xEventGroupSetBits(event_group, DISCONNECT_BIT);
} else if (event_id == IP_EVENT_GOT_IP6) {
ESP_LOGI(TAG, "GOT IPv6 event!");
@ -158,6 +161,7 @@ void app_main(void)
ESP_ERROR_CHECK(esp_event_handler_register(NETIF_PPP_STATUS, ESP_EVENT_ANY_ID, &on_ppp_changed, NULL));
/* Configure the PPP netif */
esp_err_t err;
esp_modem_dce_config_t dce_config = ESP_MODEM_DCE_DEFAULT_CONFIG(CONFIG_EXAMPLE_MODEM_PPP_APN);
esp_netif_config_t netif_ppp_config = ESP_NETIF_DEFAULT_PPP();
esp_netif_t *esp_netif = esp_netif_new(&netif_ppp_config);
@ -205,7 +209,7 @@ void app_main(void)
#endif
assert(dce);
if (dte_config.uart_config.flow_control == ESP_MODEM_FLOW_CONTROL_HW) {
esp_err_t err = esp_modem_set_flow_control(dce, 2, 2); //2/2 means HW Flow Control.
err = esp_modem_set_flow_control(dce, 2, 2); //2/2 means HW Flow Control.
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to set the set_flow_control mode");
return;
@ -246,7 +250,27 @@ void app_main(void)
#error Invalid serial connection to modem.
#endif
xEventGroupClearBits(event_group, CONNECT_BIT | GOT_DATA_BIT | USB_DISCONNECTED_BIT);
#if CONFIG_EXAMPLE_DETECT_MODE_BEFORE_CONNECT
xEventGroupClearBits(event_group, CONNECT_BIT | GOT_DATA_BIT | USB_DISCONNECTED_BIT | DISCONNECT_BIT);
err = esp_modem_set_mode(dce, ESP_MODEM_MODE_DETECT);
if (err != ESP_OK) {
ESP_LOGE(TAG, "esp_modem_set_mode(ESP_MODEM_MODE_DETECT) failed with %d", err);
return;
}
esp_modem_dce_mode_t mode = esp_modem_get_mode(dce);
ESP_LOGI(TAG, "Mode detection completed: current mode is: %d", mode);
if (mode == ESP_MODEM_MODE_DATA) { // set back to command mode
err = esp_modem_set_mode(dce, ESP_MODEM_MODE_COMMAND);
if (err != ESP_OK) {
ESP_LOGE(TAG, "esp_modem_set_mode(ESP_MODEM_MODE_COMMAND) failed with %d", err);
return;
}
ESP_LOGI(TAG, "Command mode restored");
}
#endif // CONFIG_EXAMPLE_DETECT_MODE_BEFORE_CONNECT
xEventGroupClearBits(event_group, CONNECT_BIT | GOT_DATA_BIT | USB_DISCONNECTED_BIT | DISCONNECT_BIT);
/* Run the modem demo app */
#if CONFIG_EXAMPLE_NEED_SIM_PIN == 1
@ -262,7 +286,7 @@ void app_main(void)
#endif
int rssi, ber;
esp_err_t err = esp_modem_get_signal_quality(dce, &rssi, &ber);
err = esp_modem_get_signal_quality(dce, &rssi, &ber);
if (err != ESP_OK) {
ESP_LOGE(TAG, "esp_modem_get_signal_quality failed with %d %s", err, esp_err_to_name(err));
return;
@ -301,22 +325,41 @@ void app_main(void)
}
/* Wait for IP address */
ESP_LOGI(TAG, "Waiting for IP address");
xEventGroupWaitBits(event_group, CONNECT_BIT | USB_DISCONNECTED_BIT, pdFALSE, pdFALSE, portMAX_DELAY);
xEventGroupWaitBits(event_group, CONNECT_BIT | USB_DISCONNECTED_BIT | DISCONNECT_BIT, pdFALSE, pdFALSE,
pdMS_TO_TICKS(60000));
CHECK_USB_DISCONNECTION(event_group);
if ((xEventGroupGetBits(event_group) & CONNECT_BIT) != CONNECT_BIT) {
ESP_LOGW(TAG, "Modem not connected, switching back to the command mode");
err = esp_modem_set_mode(dce, ESP_MODEM_MODE_COMMAND);
if (err != ESP_OK) {
ESP_LOGE(TAG, "esp_modem_set_mode(ESP_MODEM_MODE_COMMAND) failed with %d", err);
return;
}
ESP_LOGI(TAG, "Command mode restored");
return;
}
/* Config MQTT */
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
esp_mqtt_client_config_t mqtt_config = {
.broker.address.uri = CONFIG_EXAMPLE_MQTT_BROKER_URI,
};
#else
esp_mqtt_client_config_t mqtt_config = {
.uri = CONFIG_EXAMPLE_MQTT_BROKER_URI,
};
#endif
esp_mqtt_client_handle_t mqtt_client = esp_mqtt_client_init(&mqtt_config);
esp_mqtt_client_register_event(mqtt_client, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL);
esp_mqtt_client_start(mqtt_client);
#if CONFIG_EXAMPLE_PAUSE_NETIF_TO_CHECK_SIGNAL
xEventGroupWaitBits(event_group, GOT_DATA_BIT, pdTRUE, pdFALSE, portMAX_DELAY);
esp_modem_pause_net(dce, true);
err = esp_modem_get_signal_quality(dce, &rssi, &ber);
if (err != ESP_OK) {
ESP_LOGE(TAG, "esp_modem_get_signal_quality failed with %d", err);
return;
}
ESP_LOGI(TAG, "Signal quality: rssi=%d, ber=%d", rssi, ber);
esp_modem_pause_net(dce, false);
esp_mqtt_client_publish(mqtt_client, CONFIG_EXAMPLE_MQTT_TEST_TOPIC, CONFIG_EXAMPLE_MQTT_TEST_DATA, 0, 0, 0);
#endif // CONFIG_EXAMPLE_PAUSE_NETIF_TO_CHECK_SIGNAL
ESP_LOGI(TAG, "Waiting for MQTT data");
xEventGroupWaitBits(event_group, GOT_DATA_BIT | USB_DISCONNECTED_BIT, pdFALSE, pdFALSE, portMAX_DELAY);
CHECK_USB_DISCONNECTION(event_group);

View File

@ -12,7 +12,7 @@ def test_pppos_connect(dut):
4. checks that the client cleanly disconnects
"""
# Check the sequence of connecting, publishing, disconnecting
dut.expect('Modem Connect to PPP Server')
dut.expect('Modem Connect to PPP Server', timeout=90)
# Check for MQTT connection and the data event
dut.expect('MQTT_EVENT_CONNECTED')
dut.expect('MQTT_EVENT_DATA')

View File

@ -11,5 +11,7 @@ CONFIG_EXAMPLE_MODEM_DEVICE_SIM800=y
CONFIG_EXAMPLE_MODEM_DEVICE_BG96=n
CONFIG_EXAMPLE_MODEM_PPP_APN="lpwa.vodafone.com"
CONFIG_EXAMPLE_MQTT_TEST_TOPIC="/ci/esp-modem/pppos-client"
CONFIG_EXAMPLE_PAUSE_NETIF_TO_CHECK_SIGNAL=y
CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT=y
CONFIG_ESP32_PANIC_PRINT_HALT=y
CONFIG_EXAMPLE_DETECT_MODE_BEFORE_CONNECT=y

View File

@ -11,11 +11,3 @@ The example uses the following configuration options to demonstrate basic esp-mo
* `EXAMPLE_NEED_SIM_PIN`: To unlock the SIM card with a PIN code if needed
* `EXAMPLE_PERFORM_OTA`: To start simple OTA at the end of the example to exercise basic CMUX/modem networking. Please note that the option `CONFIG_UART_ISR_IN_IRAM` is not enabled automatically, so that buffer overflows are expected and CMUX/PPP and networking should recover.
* `EXAMPLE_USE_VFS_TERM`: To demonstrate using an abstract file descriptor to talk to the device (instead of the UART driver directly). This option could be used when implementing a custom VFS driver.
## About the esp_modem
Please check the component [README](../../README.md)
### Supported IDF versions
This example is only supported from `v4.3`, since is uses an experimental `esp_event_cxx` component.

View File

@ -69,28 +69,28 @@ menu "Example Configuration"
config EXAMPLE_MODEM_UART_TX_PIN
int "TXD Pin Number"
default 25
range 0 31
range 0 56
help
Pin number of UART TX.
config EXAMPLE_MODEM_UART_RX_PIN
int "RXD Pin Number"
default 26
range 0 31
range 0 56
help
Pin number of UART RX.
config EXAMPLE_MODEM_UART_RTS_PIN
int "RTS Pin Number"
default 27
range 0 31
range 0 56
help
Pin number of UART RTS.
config EXAMPLE_MODEM_UART_CTS_PIN
int "CTS Pin Number"
default 23
range 0 31
range 0 56
help
Pin number of UART CTS.
endmenu

View File

@ -16,3 +16,4 @@ CONFIG_COMPILER_CXX_EXCEPTIONS=y
CONFIG_ESP_MAIN_TASK_STACK_SIZE=8192
CONFIG_EXAMPLE_CLOSE_CMUX_AT_END=y
CONFIG_EXAMPLE_MQTT_TEST_TOPIC="/ci/esp-modem/pppos-client"
CONFIG_BROKER_URI="mqtt://mqtt.eclipseprojects.io"

View File

@ -1,4 +1,4 @@
version: "1.1.0"
version: "1.3.0"
description: Library for communicating with cellular modems in command and data modes
url: https://github.com/espressif/esp-protocols/tree/master/components/esp_modem
issues: https://github.com/espressif/esp-protocols/issues

View File

@ -30,9 +30,11 @@ public:
~DCE_Mode() = default;
bool set(DTE *dte, ModuleIf *module, Netif &netif, modem_mode m);
modem_mode get();
modem_mode guess(DTE *dte, bool with_cmux = false);
private:
bool set_unsafe(DTE *dte, ModuleIf *module, Netif &netif, modem_mode m);
modem_mode guess_unsafe(DTE *dte, bool with_cmux);
modem_mode mode;
};
@ -79,11 +81,21 @@ public:
return dte->command(command, std::move(got_line), time_ms);
}
modem_mode guess_mode(bool with_cmux = false)
{
return mode.guess(dte.get(), with_cmux);
}
bool set_mode(modem_mode m)
{
return mode.set(dte.get(), device.get(), netif, m);
}
modem_mode get_mode()
{
return mode.get();
}
bool recover()
{
return dte->recover();
@ -96,6 +108,29 @@ public:
}
#endif
/**
* @brief Pauses/Unpauses network temporarily
* @param do_pause true to pause, false to unpause
* @param force true to ignore command failures and continue
* @return command_result of the underlying commands
*/
command_result pause_netif(bool do_pause, bool force = false, int delay = 1000)
{
command_result result;
if (do_pause) {
netif.pause();
Task::Delay(delay); // Mandatory 1s pause before
dte->set_command_callbacks();
result = device->set_command_mode();
} else {
result = device->resume_data_mode();
if (result == command_result::OK || force) {
netif.resume();
}
}
return result;
}
protected:
std::shared_ptr<DTE> dte;
std::shared_ptr<SpecificModule> device;

View File

@ -77,7 +77,9 @@ public:
if (set_command_mode() == command_result::OK) {
return true;
}
Task::Delay(1000); // Mandatory 1s pause after escape
// send a newline to delimit the escape from the upcoming sync command
uint8_t delim = '\n';
dte->write(&delim, 1);
if (sync() == command_result::OK) {
return true;
}

View File

@ -65,6 +65,18 @@ public:
int write(DTE_Command command);
/**
* @brief send data to the selected terminal, by default (without term_id argument)
* this API works the same as write: sends data to the secondary terminal, which is
* typically used as data terminal (for networking).
*
* @param data Data pointer to write
* @param len Data len to write
* @param term_id Terminal id: Primary if id==0, Secondary if id==1
* @return number of bytes written
*/
int send(uint8_t *data, size_t len, int term_id = 1);
/**
* @brief Reading from the underlying terminal
* @param d Returning the data pointer of the received payload
@ -133,6 +145,12 @@ public:
*/
bool recover();
/**
* @brief Set internal command callbacks to the underlying terminal.
* Here we capture command replies to be processed by supplied command callbacks in struct command_cb.
*/
void set_command_callbacks();
protected:
/**
* @brief Allows for locking the DTE
@ -192,12 +210,6 @@ private:
} inflatable;
#endif // CONFIG_ESP_MODEM_USE_INFLATABLE_BUFFER_IF_NEEDED
/**
* @brief Set internal command callbacks to the underlying terminal.
* Here we capture command replies to be processed by supplied command callbacks in struct command_cb.
*/
void set_command_callbacks();
/**
* @brief This abstracts command callback processing and implements its locking, signaling of completion and timeouts.
*/

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -54,6 +54,16 @@ public:
*/
void stop();
/**
* @brief Pause the network interface
*/
void pause();
/**
* @brief Resume the network interface
*/
void resume();
void receive(uint8_t *data, size_t len);
private:

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -37,6 +37,17 @@ enum class modem_mode {
CMUX_MANUAL_DATA, /*!< Sets the primary terminal to DATA mode in manual CMUX */
CMUX_MANUAL_COMMAND, /*!< Sets the primary terminal to COMMAND mode in manual CMUX */
CMUX_MANUAL_SWAP, /*!< Swaps virtual terminals in manual CMUX mode (primary <-> secondary) */
RESUME_DATA_MODE, /*!< This is used when the device is already in DATA mode and we need the modem lib to
* enter the mode without switching. On success, we would end up in DATA-mode, UNDEF otherwise */
RESUME_COMMAND_MODE, /*!< This is used when the device is already in COMMAND mode and we want to resume it
* On success, we would end up in DATA-mode, UNDEF otherwise */
RESUME_CMUX_MANUAL_MODE, /*!< This is used when the device is already in CMUX mode and we need the modem lib to
* enter it without switching. On success, we would end up in CMUX_MANUAL-mode, UNDEF otherwise */
RESUME_CMUX_MANUAL_DATA, /*!< This is used when the device is already in CMUX-DATA mode and we need the modem lib to
* enter it without switching. On success, we would end up in CMUX_MANUAL-DATA mode, UNDEF otherwise */
AUTODETECT, /*!< Auto-detection command: It tries to send a few packets in order to recognize which mode the
* the device currently is and update the modem library mode. On success the modem is updated,
* otherwise it's set to UNDEF */
};
/**

View File

@ -13,6 +13,10 @@
extern "C" {
#endif
/* Compatibility macro to be removed in v2.0
*/
#define ESP_MODEM_DCE_GENETIC ESP_MODEM_DCE_GENERIC
typedef struct esp_modem_dce_wrap esp_modem_dce_t;
typedef struct esp_modem_PdpContext_t {
@ -41,13 +45,15 @@ typedef enum esp_modem_dce_mode {
ESP_MODEM_MODE_CMUX_MANUAL_SWAP, /**< Swap terminals in CMUX manual mode */
ESP_MODEM_MODE_CMUX_MANUAL_DATA, /**< Set DATA mode in CMUX manual mode */
ESP_MODEM_MODE_CMUX_MANUAL_COMMAND, /**< Set COMMAND mode in CMUX manual mode */
ESP_MODEM_MODE_DETECT, /**< Detect the mode and resume it (if sucessfully detected) */
ESP_MODEM_MODE_UNDEF,
} esp_modem_dce_mode_t;
/**
* @brief DCE devices: Enum list of supported devices
*/
typedef enum esp_modem_dce_device {
ESP_MODEM_DCE_GENETIC, /**< The most generic device */
ESP_MODEM_DCE_GENERIC, /**< The most generic device */
ESP_MODEM_DCE_SIM7600,
ESP_MODEM_DCE_SIM7070,
ESP_MODEM_DCE_SIM7000,
@ -141,6 +147,33 @@ esp_err_t esp_modem_command(esp_modem_dce_t *dce, const char *command, esp_err_t
*/
esp_err_t esp_modem_set_apn(esp_modem_dce_t *dce, const char *apn);
#ifdef CONFIG_ESP_MODEM_URC_HANDLER
/**
* @brief Sets a handler for unsolicited result codes (URCs) from the modem
*
* This function registers a callback that is triggered whenever an unsolicited
* result code (URC) is received from the modem. URCs are typically sent by the
* modem without a prior command to notify the host about certain events or status changes.
*
* @param dce Modem DCE handle
* @param got_line_cb Callback function which is called whenever a URC line is received
* @return ESP_OK on success, ESP_FAIL on failure
*/
esp_err_t esp_modem_set_urc(esp_modem_dce_t *dce, esp_err_t(*got_line_cb)(uint8_t *data, size_t len));
#endif
/**
* @brief This API provides support for temporarily pausing networking in order
* to send/receive AT commands and resume networking afterwards.
* @note This function does not switch modes, the modem is still in data mode.
*
* @param dce Modem DCE handle
* @param pause true to pause the network interface, false to resume networking
* @return ESP_OK on success
*/
esp_err_t esp_modem_pause_net(esp_modem_dce_t *dce, bool pause);
esp_modem_dce_mode_t esp_modem_get_mode(esp_modem_dce_t *dce);
/**
* @}
*/

View File

@ -44,7 +44,7 @@ inline dce_factory::ModemType convert_modem_enum(esp_modem_dce_device_t module)
case ESP_MODEM_DCE_SIM800:
return esp_modem::dce_factory::ModemType::SIM800;
default:
case ESP_MODEM_DCE_GENETIC:
case ESP_MODEM_DCE_GENERIC:
return esp_modem::dce_factory::ModemType::GenericModule;
}
}

View File

@ -60,7 +60,7 @@ extern "C" esp_modem_dce_t *esp_modem_new_dev(esp_modem_dce_device_t module, con
extern "C" esp_modem_dce_t *esp_modem_new(const esp_modem_dte_config_t *dte_config, const esp_modem_dce_config_t *dce_config, esp_netif_t *netif)
{
return esp_modem_new_dev(ESP_MODEM_DCE_GENETIC, dte_config, dce_config, netif);
return esp_modem_new_dev(ESP_MODEM_DCE_GENERIC, dte_config, dce_config, netif);
}
extern "C" void esp_modem_destroy(esp_modem_dce_t *dce_wrap)
@ -95,12 +95,43 @@ extern "C" esp_err_t esp_modem_sync(esp_modem_dce_t *dce_wrap)
return command_response_to_esp_err(dce_wrap->dce->sync());
}
extern "C" esp_modem_dce_mode_t esp_modem_get_mode(esp_modem_dce_t *dce_wrap)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_MODEM_MODE_UNDEF;
}
auto mode = dce_wrap->dce->get_mode();
switch (mode) {
default:
case modem_mode::UNDEF:
return ESP_MODEM_MODE_UNDEF;
case modem_mode::COMMAND_MODE:
return ESP_MODEM_MODE_COMMAND;
case modem_mode::DATA_MODE:
return ESP_MODEM_MODE_DATA;
case modem_mode::CMUX_MODE:
return ESP_MODEM_MODE_CMUX;
case modem_mode::CMUX_MANUAL_MODE:
return ESP_MODEM_MODE_CMUX_MANUAL;
case modem_mode::CMUX_MANUAL_EXIT:
return ESP_MODEM_MODE_CMUX_MANUAL_EXIT;
case modem_mode::CMUX_MANUAL_DATA:
return ESP_MODEM_MODE_CMUX_MANUAL_DATA;
case modem_mode::CMUX_MANUAL_COMMAND:
return ESP_MODEM_MODE_CMUX_MANUAL_COMMAND;
case modem_mode::CMUX_MANUAL_SWAP:
return ESP_MODEM_MODE_CMUX_MANUAL_SWAP;
}
}
extern "C" esp_err_t esp_modem_set_mode(esp_modem_dce_t *dce_wrap, esp_modem_dce_mode_t mode)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
switch (mode) {
case ESP_MODEM_MODE_UNDEF:
return dce_wrap->dce->set_mode(modem_mode::UNDEF) ? ESP_OK : ESP_FAIL;
case ESP_MODEM_MODE_DATA:
return dce_wrap->dce->set_mode(modem_mode::DATA_MODE) ? ESP_OK : ESP_FAIL;
case ESP_MODEM_MODE_COMMAND:
@ -117,6 +148,8 @@ extern "C" esp_err_t esp_modem_set_mode(esp_modem_dce_t *dce_wrap, esp_modem_dce
return dce_wrap->dce->set_mode(modem_mode::CMUX_MANUAL_DATA) ? ESP_OK : ESP_FAIL;
case ESP_MODEM_MODE_CMUX_MANUAL_COMMAND:
return dce_wrap->dce->set_mode(modem_mode::CMUX_MANUAL_COMMAND) ? ESP_OK : ESP_FAIL;
case ESP_MODEM_MODE_DETECT:
return dce_wrap->dce->set_mode(modem_mode::AUTODETECT) ? ESP_OK : ESP_FAIL;
}
return ESP_ERR_NOT_SUPPORTED;
}
@ -451,3 +484,43 @@ extern "C" esp_err_t esp_modem_set_apn(esp_modem_dce_t *dce_wrap, const char *ap
dce_wrap->dce->get_module()->configure_pdp_context(std::move(new_pdp));
return ESP_OK;
}
#ifdef CONFIG_ESP_MODEM_URC_HANDLER
extern "C" esp_err_t esp_modem_set_urc(esp_modem_dce_t *dce_wrap, esp_err_t(*got_line_fn)(uint8_t *data, size_t len))
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
if (got_line_fn == nullptr) {
dce_wrap->dce->set_urc(nullptr);
return ESP_OK;
}
dce_wrap->dce->set_urc([got_line_fn](uint8_t *data, size_t len) {
switch (got_line_fn(data, len)) {
case ESP_OK:
return command_result::OK;
case ESP_FAIL:
return command_result::FAIL;
default:
return command_result::TIMEOUT;
}
});
return ESP_OK;
}
#endif
extern "C" esp_err_t esp_modem_pause_net(esp_modem_dce_t *dce_wrap, bool pause)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
return command_response_to_esp_err(dce_wrap->dce->pause_netif(pause));
}
extern "C" esp_err_t esp_modem_hang_up(esp_modem_dce_t *dce_wrap)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
return command_response_to_esp_err(dce_wrap->dce->hang_up());
}

View File

@ -123,7 +123,12 @@ bool CMux::data_available(uint8_t *data, size_t len)
{
if (data && (type & FT_UIH) == FT_UIH && len > 0 && dlci > 0) { // valid payload on a virtual term
int virtual_term = dlci - 1;
if (virtual_term < MAX_TERMINALS_NUM && read_cb[virtual_term]) {
if (virtual_term < MAX_TERMINALS_NUM) {
if (read_cb[virtual_term] == nullptr) {
// ignore all virtual terminal's data before we completely establish CMUX
ESP_LOG_BUFFER_HEXDUMP("CMUX Rx before init", data, len, ESP_LOG_DEBUG);
return true;
}
// Post partial data (or defragment to post on CMUX footer)
#ifdef DEFRAGMENT_CMUX_PAYLOAD
if (payload_start == nullptr) {
@ -142,7 +147,11 @@ bool CMux::data_available(uint8_t *data, size_t len)
sabm_ack = dlci;
} else if (data == nullptr && dlci > 0) {
int virtual_term = dlci - 1;
if (virtual_term < MAX_TERMINALS_NUM && read_cb[virtual_term]) {
if (virtual_term < MAX_TERMINALS_NUM) {
if (read_cb[virtual_term] == nullptr) {
// silently ignore this CMUX frame (not finished entering CMUX, yet)
return true;
}
#ifdef DEFRAGMENT_CMUX_PAYLOAD
read_cb[virtual_term](payload_start, total_payload_size);
#endif

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -18,7 +18,6 @@ namespace transitions {
static bool exit_data(DTE &dte, ModuleIf &device, Netif &netif)
{
netif.stop();
auto signal = std::make_shared<SignalGroup>();
std::weak_ptr<SignalGroup> weak_signal = signal;
dte.set_read_cb([&netif, weak_signal](uint8_t *data, size_t len) -> bool {
@ -32,7 +31,7 @@ static bool exit_data(DTE &dte, ModuleIf &device, Netif &netif)
if (memchr(data, '\n', len))
{
ESP_LOG_BUFFER_HEXDUMP("esp-modem: debug_data (CMD)", data, len, ESP_LOG_DEBUG);
const auto pass = std::list<std::string_view>({"NO CARRIER", "DISCONNECTED"});
const auto pass = std::list<std::string_view>({"NO CARRIER", "DISCONNECTED", "OK"});
std::string_view response((char *) data, len);
for (auto &it : pass)
if (response.find(it) != std::string::npos) {
@ -44,8 +43,14 @@ static bool exit_data(DTE &dte, ModuleIf &device, Netif &netif)
}
return false;
});
netif.stop();
netif.wait_until_ppp_exits();
if (!signal->wait(1, 2000)) {
#ifdef ESP_MODEM_PPP_ESCAPE_BEFORE_EXIT
std::array<uint8_t, 3> ppp_escape = {'+', '+', '+'};
dte.write(ppp_escape.data(), ppp_escape.size());
#endif
if (!signal->wait(1, 2000)) { // wait for any of the disconnection messages
// if no reply -> set device to command mode
dte.set_read_cb(nullptr);
if (!device.set_mode(modem_mode::COMMAND_MODE)) {
return false;
@ -103,6 +108,51 @@ bool DCE_Mode::set_unsafe(DTE *dte, ModuleIf *device, Netif &netif, modem_mode m
return true;
case modem_mode::DUAL_MODE: // Only DTE can be in Dual mode
break;
case modem_mode::AUTODETECT: {
auto guessed = guess_unsafe(dte, true);
if (guessed == modem_mode::UNDEF) {
return false;
}
// prepare the undefined mode before to allow all possible transitions
if (!dte->set_mode(modem_mode::UNDEF)) {
return false;
}
mode = modem_mode::UNDEF;
ESP_LOGD("DCE mode", "Detected mode: %d", static_cast<int>(guessed));
if (guessed == modem_mode::DATA_MODE) {
return set_unsafe(dte, device, netif, esp_modem::modem_mode::RESUME_DATA_MODE);
} else if (guessed == esp_modem::modem_mode::COMMAND_MODE) {
return set_unsafe(dte, device, netif, esp_modem::modem_mode::RESUME_COMMAND_MODE);
} else if (guessed == esp_modem::modem_mode::CMUX_MODE) {
if (!set_unsafe(dte, device, netif, esp_modem::modem_mode::RESUME_CMUX_MANUAL_MODE)) {
return false;
}
// now we guess the mode for each terminal
guessed = guess_unsafe(dte, false);
ESP_LOGD("DCE mode", "Detected mode on primary term: %d", static_cast<int>(guessed));
// now we need to access the second terminal, so we could simply send a SWAP command
// (switching to data mode does the swapping internally, so we only swap if we're in CMD mode)
if (guessed == modem_mode::DATA_MODE) {
// switch to DATA on the primary terminal and swap terminals
if (!set_unsafe(dte, device, netif, esp_modem::modem_mode::RESUME_CMUX_MANUAL_DATA)) {
return false;
}
} else {
// swap terminals
if (!set_unsafe(dte, device, netif, esp_modem::modem_mode::CMUX_MANUAL_SWAP)) {
return false;
}
}
guessed = guess_unsafe(dte, false);
ESP_LOGD("DCE mode", "Detected mode on secondary term: %d", static_cast<int>(guessed));
if (guessed == modem_mode::DATA_MODE) {
if (!set_unsafe(dte, device, netif, esp_modem::modem_mode::RESUME_CMUX_MANUAL_DATA)) {
return false;
}
}
}
return true;
}
case modem_mode::COMMAND_MODE:
if (mode == modem_mode::COMMAND_MODE || mode >= modem_mode::CMUX_MANUAL_MODE) {
return false;
@ -122,6 +172,32 @@ bool DCE_Mode::set_unsafe(DTE *dte, ModuleIf *device, Netif &netif, modem_mode m
}
mode = m;
return true;
case modem_mode::RESUME_DATA_MODE:
if (!dte->set_mode(modem_mode::DATA_MODE)) {
return false;
}
netif.start();
mode = modem_mode::DATA_MODE;
return true;
case modem_mode::RESUME_COMMAND_MODE:
if (!dte->set_mode(modem_mode::COMMAND_MODE)) {
return false;
}
mode = modem_mode::COMMAND_MODE;
return true;
case modem_mode::RESUME_CMUX_MANUAL_MODE:
if (!dte->set_mode(modem_mode::CMUX_MANUAL_MODE)) {
return false;
}
mode = modem_mode::CMUX_MANUAL_MODE;
return true;
case modem_mode::RESUME_CMUX_MANUAL_DATA:
if (!dte->set_mode(modem_mode::CMUX_MANUAL_SWAP)) {
return false;
}
netif.start();
mode = modem_mode::CMUX_MANUAL_MODE;
return true;
case modem_mode::DATA_MODE:
if (mode == modem_mode::DATA_MODE || mode == modem_mode::CMUX_MODE || mode >= modem_mode::CMUX_MANUAL_MODE) {
return false;
@ -191,4 +267,121 @@ modem_mode DCE_Mode::get()
return mode;
}
modem_mode DCE_Mode::guess(DTE *dte, bool with_cmux)
{
Scoped<DTE> lock(*dte);
return guess_unsafe(dte, with_cmux);
}
/**
* This namespace contains probe packets and expected replies on 3 different protocols,
* the modem device could use (as well as timeouts and mode ids for synchronisation)
*/
namespace probe {
namespace ppp {
// Test that we're in the PPP mode by sending an LCP protocol echo request and expecting LCP echo reply
constexpr std::array<uint8_t, 16> lcp_echo_request = {0x7e, 0xff, 0x03, 0xc0, 0x21, 0x09, 0x01, 0x00, 0x08, 0x99, 0xd1, 0x35, 0xc1, 0x8e, 0x2c, 0x7e };
constexpr std::array<uint8_t, 5> lcp_echo_reply_head = {0x7e, 0xff, 0x7d, 0x23, 0xc0};
const size_t mode = 1 << 0;
const int timeout = 200;
}
namespace cmd {
// For command mode, we just send a simple AT command
const char at[] = "\r\nAT\r\n";
const size_t max_at_reply = 16; // account for some whitespaces and/or CMUX encapsulation
const char reply[] = { 'O', 'K' };
const int mode = 1 << 1;
const int timeout = 500;
}
namespace cmux {
// For CMUX mode, we send an SABM on control terminal (0)
const uint8_t sabm0_reqest[] = {0xf9, 0x03, 0x3f, 0x01, 0x1c, 0xf9};
const uint8_t sabm0_reply[] = {0xf9, 0x03, 0x73, 0x01};
const int mode = 1 << 0;
const int timeout = 200;
}
};
modem_mode DCE_Mode::guess_unsafe(DTE *dte, bool with_cmux)
{
// placeholder for reply and its size, since it could come in pieces, and we have to cache
// this is captured by the lambda by reference.
// must make sure the lambda is cleared before exiting this function (done by dte->on_read(nullptr))
uint8_t reply[std::max(probe::cmd::max_at_reply, std::max(sizeof(probe::ppp::lcp_echo_request), sizeof(probe::cmux::sabm0_reply)))];
size_t reply_pos = 0;
auto signal = std::make_shared<SignalGroup>();
std::weak_ptr<SignalGroup> weak_signal = signal;
dte->on_read([weak_signal, with_cmux, &reply, &reply_pos](uint8_t *data, size_t len) {
// storing the response in the `reply` array and de-fragmenting
if (reply_pos >= sizeof(reply)) {
return command_result::TIMEOUT;
}
auto reply_size = std::min((size_t)sizeof(reply) - reply_pos, len);
::memcpy(reply + reply_pos, data, reply_size);
reply_pos += reply_size;
ESP_LOG_BUFFER_HEXDUMP("esp-modem: guess mode data:", reply, reply_pos, ESP_LOG_DEBUG);
// Check whether the response resembles the "golden" reply (for these 3 protocols)
if (reply_pos >= sizeof(probe::ppp::lcp_echo_reply_head)) {
// check for initial 2 bytes
auto *ptr = static_cast<uint8_t *>(memmem(reply, reply_pos, probe::ppp::lcp_echo_reply_head.data(), 2));
// and check the other two bytes for protocol ID:
// * either LCP reply
if (ptr && ptr[3] == probe::ppp::lcp_echo_reply_head[3] && ptr[4] == probe::ppp::lcp_echo_reply_head[4]) {
if (auto signal = weak_signal.lock()) {
signal->set(probe::ppp::mode);
}
}
// * or LCP conf request
if (ptr && ptr[3] == probe::ppp::lcp_echo_request[3] && ptr[4] == probe::ppp::lcp_echo_request[4]) {
if (auto signal = weak_signal.lock()) {
signal->set(probe::ppp::mode);
}
}
}
if (reply_pos >= 4 && memmem(reply, reply_pos, probe::cmd::reply, sizeof(probe::cmd::reply))) {
if (reply[0] != 0xf9) { // double check that the reply is not wrapped in CMUX headers
if (auto signal = weak_signal.lock()) {
signal->set(probe::cmd::mode);
}
}
}
if (with_cmux && reply_pos >= sizeof(probe::cmux::sabm0_reply)) {
// checking the initial 3 bytes
auto *ptr = static_cast<uint8_t *>(memmem(reply, reply_pos, probe::cmux::sabm0_reply, 3));
// and checking that DLCI is 0 (control frame)
if (ptr && (ptr[3] >> 2) == 0) {
if (auto signal = weak_signal.lock()) {
signal->set(probe::cmux::mode);
}
}
}
return command_result::TIMEOUT;
});
auto guessed = modem_mode::UNDEF;
// Check the PPP mode fist by sending LCP echo request
dte->send((uint8_t *)probe::ppp::lcp_echo_request.data(), sizeof(probe::ppp::lcp_echo_request), 0);
if (signal->wait(probe::ppp::mode, probe::ppp::timeout)) {
guessed = modem_mode::DATA_MODE;
} else { // LCP echo timeout
// now check for AT mode
reply_pos = 0;
dte->send((uint8_t *)probe::cmd::at, sizeof(probe::cmd::at), 0);
if (signal->wait(probe::cmd::mode, probe::cmd::timeout)) {
guessed = modem_mode::COMMAND_MODE;
} else if (with_cmux) { // no AT reply, check for CMUX mode (if requested)
reply_pos = 0;
dte->send((uint8_t *) probe::cmux::sabm0_reqest, sizeof(probe::cmux::sabm0_reqest), 0);
if (signal->wait(probe::cmux::mode, probe::cmux::timeout)) {
guessed = modem_mode::CMUX_MODE;
}
}
}
dte->on_read(nullptr);
return guessed;
}
} // esp_modem

View File

@ -14,38 +14,53 @@ using namespace esp_modem;
static const size_t dte_default_buffer_size = 1000;
DTE::DTE(const esp_modem_dte_config *config, std::unique_ptr<Terminal> terminal):
buffer(config->dte_buffer_size),
cmux_term(nullptr), primary_term(std::move(terminal)), secondary_term(primary_term),
mode(modem_mode::UNDEF)
DTE::DTE(const esp_modem_dte_config *config, std::unique_ptr<Terminal> terminal)
: buffer(config->dte_buffer_size),
cmux_term(nullptr),
primary_term(std::move(terminal)),
secondary_term(primary_term),
mode(modem_mode::UNDEF)
{
ESP_MODEM_THROW_IF_FALSE(primary_term != nullptr, "Invalid argument: terminal cannot be null");
set_command_callbacks();
}
DTE::DTE(std::unique_ptr<Terminal> terminal):
buffer(dte_default_buffer_size),
cmux_term(nullptr), primary_term(std::move(terminal)), secondary_term(primary_term),
mode(modem_mode::UNDEF)
DTE::DTE(std::unique_ptr<Terminal> terminal)
: buffer(dte_default_buffer_size),
cmux_term(nullptr),
primary_term(std::move(terminal)),
secondary_term(primary_term),
mode(modem_mode::UNDEF)
{
ESP_MODEM_THROW_IF_FALSE(primary_term != nullptr, "Invalid argument: terminal cannot be null");
set_command_callbacks();
}
DTE::DTE(const esp_modem_dte_config *config, std::unique_ptr<Terminal> t, std::unique_ptr<Terminal> s):
buffer(config->dte_buffer_size),
cmux_term(nullptr), primary_term(std::move(t)), secondary_term(std::move(s)),
mode(modem_mode::DUAL_MODE)
DTE::DTE(const esp_modem_dte_config *config, std::unique_ptr<Terminal> t, std::unique_ptr<Terminal> s)
: buffer(config->dte_buffer_size),
cmux_term(nullptr),
primary_term(std::move(t)),
secondary_term(std::move(s)),
mode(modem_mode::DUAL_MODE)
{
ESP_MODEM_THROW_IF_FALSE(primary_term != nullptr, "Invalid argument: primary terminal cannot be null");
ESP_MODEM_THROW_IF_FALSE(secondary_term != nullptr, "Invalid argument: secondary terminal cannot be null");
set_command_callbacks();
}
DTE::DTE(std::unique_ptr<Terminal> t, std::unique_ptr<Terminal> s):
buffer(dte_default_buffer_size),
cmux_term(nullptr), primary_term(std::move(t)), secondary_term(std::move(s)),
mode(modem_mode::DUAL_MODE)
DTE::DTE(std::unique_ptr<Terminal> t, std::unique_ptr<Terminal> s)
: buffer(dte_default_buffer_size),
cmux_term(nullptr),
primary_term(std::move(t)),
secondary_term(std::move(s)),
mode(modem_mode::DUAL_MODE)
{
ESP_MODEM_THROW_IF_FALSE(primary_term != nullptr, "Invalid argument: primary terminal cannot be null");
ESP_MODEM_THROW_IF_FALSE(secondary_term != nullptr, "Invalid argument: secondary terminal cannot be null");
set_command_callbacks();
}
void DTE::set_command_callbacks()
{
primary_term->set_read_cb([this](uint8_t *data, size_t len) {
@ -223,13 +238,13 @@ bool DTE::set_mode(modem_mode m)
}
}
// transitions (COMMAND|DUAL|CMUX|UNDEF) -> DATA
if (m == modem_mode::DATA_MODE) {
if (m == modem_mode::DATA_MODE || m == modem_mode::RESUME_DATA_MODE) {
if (mode == modem_mode::CMUX_MODE || mode == modem_mode::CMUX_MANUAL_MODE || mode == modem_mode::DUAL_MODE) {
// mode stays the same, but need to swap terminals (as command has been switched)
secondary_term.swap(primary_term);
set_command_callbacks();
} else {
mode = m;
mode = modem_mode::DATA_MODE;
}
return true;
}
@ -316,6 +331,12 @@ int DTE::write(uint8_t *data, size_t len)
return secondary_term->write(data, len);
}
int DTE::send(uint8_t *data, size_t len, int term_id)
{
Terminal *term = term_id == 0 ? primary_term.get() : secondary_term.get();
return term->write(data, len);
}
int DTE::write(DTE_Command command)
{
return primary_term->write(command.data, command.len);

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -87,8 +87,10 @@ void Netif::start()
receive(data, len);
return true;
});
signal.set(PPP_STARTED);
esp_netif_action_start(driver.base.netif, nullptr, 0, nullptr);
if (!signal.is_any(PPP_STARTED)) {
signal.set(PPP_STARTED);
esp_netif_action_start(driver.base.netif, nullptr, 0, nullptr);
}
}
void Netif::stop()
@ -97,6 +99,20 @@ void Netif::stop()
signal.clear(PPP_STARTED);
}
void Netif::resume()
{
ppp_dte->set_read_cb([this](uint8_t *data, size_t len) -> bool {
receive(data, len);
return true;
});
signal.set(PPP_STARTED);
}
void Netif::pause()
{
signal.clear(PPP_STARTED);
}
Netif::~Netif()
{
if (signal.is_any(PPP_STARTED)) {

View File

@ -52,7 +52,6 @@ void Netif::start()
void Netif::stop()
{
ppp_dte->set_read_cb(nullptr);
signal.clear(PPP_STARTED);
}

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -72,6 +72,7 @@ private:
{
auto t = static_cast<UartTerminal *>(task_param);
t->task();
t->task_handle.task_handle = nullptr;
vTaskDelete(nullptr);
}
@ -175,13 +176,20 @@ int UartTerminal::read(uint8_t *data, size_t len)
uart_get_buffered_data_len(uart.port, &length);
length = std::min(len, length);
if (length > 0) {
return uart_read_bytes(uart.port, data, length, portMAX_DELAY);
int read_len = uart_read_bytes(uart.port, data, length, portMAX_DELAY);
#if CONFIG_ESP_MODEM_ADD_DEBUG_LOGS
ESP_LOG_BUFFER_HEXDUMP("uart-rx", data, read_len, ESP_LOG_DEBUG);
#endif
return read_len;
}
return 0;
}
int UartTerminal::write(uint8_t *data, size_t len)
{
#if CONFIG_ESP_MODEM_ADD_DEBUG_LOGS
ESP_LOG_BUFFER_HEXDUMP("uart-tx", data, len, ESP_LOG_DEBUG);
#endif
return uart_write_bytes_compat(uart.port, data, len);
}

View File

@ -16,14 +16,14 @@ menu "Test App Configuration"
config TEST_APP_UART_TX_PIN
int "TXD Pin Number"
default 6
range 0 31
range 0 56
help
Pin number of UART TX.
config TEST_APP_UART_RX_PIN
int "RXD Pin Number"
default 7
range 0 31
range 0 56
help
Pin number of UART RX.

View File

@ -9,6 +9,20 @@ from threading import Event, Thread
import netifaces
def is_esp32(port):
"""
Check if the given port is connected to an ESP32 using esptool.
"""
try:
result = subprocess.run(
['esptool.py', '--port', port, 'chip_id'],
stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True, text=True
)
return 'ESP32' in result.stdout
except subprocess.CalledProcessError:
return False
def run_server(server_stop, port, server_ip, client_ip, auth, auth_user, auth_password):
print('Starting PPP server on port: {}'.format(port))
try:
@ -66,13 +80,27 @@ def test_examples_protocol_pppos_connect(dut):
)
raise
# the PPP test env uses two ttyUSB's: one for ESP32 board, another one for ppp server
# use the other port for PPP server than the DUT/ESP
port = '/dev/ttyUSB0' if dut.serial.port == '/dev/ttyUSB1' else '/dev/ttyUSB1'
# the PPP test env uses three ttyUSB's: two for ESP32 board and another one for the ppp server
# we need to detect the server_port (for PPPD)
server_port = None
for i in ['/dev/ttyUSB0', '/dev/ttyUSB1', '/dev/ttyUSB2']:
if i == dut.serial.port:
print(f'DUT port: {i}')
elif is_esp32(i):
print(f'Some other ESP32: {i}')
else:
print(f'Port for PPPD: {i}')
server_port = i
if server_port is None:
print(
'ENV_TEST_FAILURE: Cannot locate PPPD port'
)
raise
# Start the PPP server
server_stop = Event()
t = Thread(target=run_server,
args=(server_stop, port, server_ip, client_ip, auth, auth_user, auth_password))
args=(server_stop, server_port, server_ip, client_ip, auth, auth_user, auth_password))
t.start()
try:
ppp_server_timeout = time.time() + 30

View File

@ -3,6 +3,6 @@ commitizen:
bump_message: 'bump(websocket): $current_version -> $new_version'
pre_bump_hooks: python ../../ci/changelog.py esp_websocket_client
tag_format: websocket-v$version
version: 1.3.0
version: 1.4.0
version_files:
- idf_component.yml

View File

@ -1,5 +1,23 @@
# Changelog
## [1.4.0](https://github.com/espressif/esp-protocols/commits/websocket-v1.4.0)
### Features
- Support DS peripheral for mutual TLS ([55385ec3](https://github.com/espressif/esp-protocols/commit/55385ec3))
### Bug Fixes
- wait for task on destroy ([42674b49](https://github.com/espressif/esp-protocols/commit/42674b49))
- Fix pytest to verify client correctly ([9046af8f](https://github.com/espressif/esp-protocols/commit/9046af8f))
- propagate error type ([eeeb9006](https://github.com/espressif/esp-protocols/commit/eeeb9006))
- fix example buffer leak ([5219c39d](https://github.com/espressif/esp-protocols/commit/5219c39d))
### Updated
- chore(websocket): align structure members ([beb6e57e](https://github.com/espressif/esp-protocols/commit/beb6e57e))
- chore(websocket): remove unused client variable ([15d3a01e](https://github.com/espressif/esp-protocols/commit/15d3a01e))
## [1.3.0](https://github.com/espressif/esp-protocols/commits/websocket-v1.3.0)
### Features

View File

@ -93,10 +93,13 @@ typedef struct {
size_t client_cert_len;
const char *client_key;
size_t client_key_len;
#if CONFIG_ESP_TLS_USE_DS_PERIPHERAL
void *client_ds_data;
#endif
bool use_global_ca_store;
bool skip_cert_common_name_check;
const char *cert_common_name;
esp_err_t (*crt_bundle_attach)(void *conf);
esp_err_t (*crt_bundle_attach)(void *conf);
esp_transport_handle_t ext_transport;
} websocket_config_storage_t;
@ -122,12 +125,11 @@ struct esp_websocket_client {
uint64_t ping_tick_ms;
uint64_t pingpong_tick_ms;
int wait_timeout_ms;
int auto_reconnect;
bool run;
bool wait_for_pong_resp;
bool selected_for_destroying;
EventGroupHandle_t status_bits;
SemaphoreHandle_t lock;
SemaphoreHandle_t lock;
size_t errormsg_size;
char *errormsg_buffer;
char *rx_buffer;
@ -186,9 +188,9 @@ static void esp_websocket_free_buf(esp_websocket_client_handle_t client, bool is
}
static esp_err_t esp_websocket_client_dispatch_event(esp_websocket_client_handle_t client,
esp_websocket_event_id_t event,
const char *data,
int data_len)
esp_websocket_event_id_t event,
const char *data,
int data_len)
{
esp_err_t err;
esp_websocket_event_data_t event_data;
@ -204,8 +206,8 @@ static esp_err_t esp_websocket_client_dispatch_event(esp_websocket_client_handle
if (client->error_handle.error_type == WEBSOCKET_ERROR_TYPE_TCP_TRANSPORT) {
event_data.error_handle.esp_tls_last_esp_err = esp_tls_get_and_clear_last_error(esp_transport_get_error_handle(client->transport),
&client->error_handle.esp_tls_stack_err,
&client->error_handle.esp_tls_cert_verify_flags);
&client->error_handle.esp_tls_stack_err,
&client->error_handle.esp_tls_cert_verify_flags);
event_data.error_handle.esp_tls_stack_err = client->error_handle.esp_tls_stack_err;
event_data.error_handle.esp_tls_cert_verify_flags = client->error_handle.esp_tls_cert_verify_flags;
event_data.error_handle.esp_transport_sock_errno = esp_transport_get_errno(client->transport);
@ -235,14 +237,14 @@ static esp_err_t esp_websocket_client_abort_connection(esp_websocket_client_hand
} else {
client->reconnect_tick_ms = _tick_get_ms();
ESP_LOGI(TAG, "Reconnect after %d ms", client->wait_timeout_ms);
client->error_handle.error_type = error_type;
client->state = WEBSOCKET_STATE_WAIT_TIMEOUT;
}
client->error_handle.error_type = error_type;
esp_websocket_client_dispatch_event(client, WEBSOCKET_EVENT_DISCONNECTED, NULL, 0);
return ESP_OK;
}
static esp_err_t esp_websocket_client_error(esp_websocket_client_handle_t client, const char *format, ...) __attribute__ ((format (printf, 2, 3)));
static esp_err_t esp_websocket_client_error(esp_websocket_client_handle_t client, const char *format, ...) __attribute__((format(printf, 2, 3)));
static esp_err_t esp_websocket_client_error(esp_websocket_client_handle_t client, const char *format, ...)
{
va_list myargs;
@ -447,6 +449,21 @@ static void destroy_and_free_resources(esp_websocket_client_handle_t client)
client = NULL;
}
static esp_err_t stop_wait_task(esp_websocket_client_handle_t client)
{
/* A running client cannot be stopped from the websocket task/event handler */
TaskHandle_t running_task = xTaskGetCurrentTaskHandle();
if (running_task == client->task_handle) {
ESP_LOGE(TAG, "Client cannot be stopped from websocket task");
return ESP_FAIL;
}
client->run = false;
xEventGroupWaitBits(client->status_bits, STOPPED_BIT, false, true, portMAX_DELAY);
client->state = WEBSOCKET_STATE_UNKNOW;
return ESP_OK;
}
static esp_err_t set_websocket_transport_optional_settings(esp_websocket_client_handle_t client, const char *scheme)
{
esp_transport_handle_t trans = esp_transport_list_get_transport(client->transport_list, scheme);
@ -532,6 +549,10 @@ static esp_err_t esp_websocket_client_create_transport(esp_websocket_client_hand
} else {
esp_transport_ssl_set_client_key_data_der(ssl, client->config->client_key, client->config->client_key_len);
}
#if CONFIG_ESP_TLS_USE_DS_PERIPHERAL
} else if (client->config->client_ds_data) {
esp_transport_ssl_set_ds_data(ssl, client->config->client_ds_data);
#endif
}
if (client->config->crt_bundle_attach) {
#ifdef CONFIG_MBEDTLS_CERTIFICATE_BUNDLE
@ -654,7 +675,7 @@ esp_websocket_client_handle_t esp_websocket_client_init(const esp_websocket_clie
client->keep_alive_cfg.keep_alive_enable = true;
client->keep_alive_cfg.keep_alive_idle = (config->keep_alive_idle == 0) ? WEBSOCKET_KEEP_ALIVE_IDLE : config->keep_alive_idle;
client->keep_alive_cfg.keep_alive_interval = (config->keep_alive_interval == 0) ? WEBSOCKET_KEEP_ALIVE_INTERVAL : config->keep_alive_interval;
client->keep_alive_cfg.keep_alive_count = (config->keep_alive_count == 0) ? WEBSOCKET_KEEP_ALIVE_COUNT : config->keep_alive_count;
client->keep_alive_cfg.keep_alive_count = (config->keep_alive_count == 0) ? WEBSOCKET_KEEP_ALIVE_COUNT : config->keep_alive_count;
}
if (config->if_name) {
@ -697,6 +718,9 @@ esp_websocket_client_handle_t esp_websocket_client_init(const esp_websocket_clie
client->config->client_cert_len = config->client_cert_len;
client->config->client_key = config->client_key;
client->config->client_key_len = config->client_key_len;
#if CONFIG_ESP_TLS_USE_DS_PERIPHERAL
client->config->client_ds_data = config->client_ds_data;
#endif
client->config->skip_cert_common_name_check = config->skip_cert_common_name_check;
client->config->cert_common_name = config->cert_common_name;
client->config->crt_bundle_attach = config->crt_bundle_attach;
@ -745,6 +769,7 @@ esp_websocket_client_handle_t esp_websocket_client_init(const esp_websocket_clie
ESP_WS_CLIENT_MEM_CHECK(TAG, client->status_bits, {
goto _websocket_init_fail;
});
xEventGroupSetBits(client->status_bits, STOPPED_BIT);
client->buffer_size = buffer_size;
return client;
@ -759,9 +784,11 @@ esp_err_t esp_websocket_client_destroy(esp_websocket_client_handle_t client)
if (client == NULL) {
return ESP_ERR_INVALID_ARG;
}
if (client->run) {
esp_websocket_client_stop(client);
if (client->status_bits && (STOPPED_BIT & xEventGroupGetBits(client->status_bits)) == 0) {
stop_wait_task(client);
}
destroy_and_free_resources(client);
return ESP_OK;
}
@ -923,7 +950,7 @@ static esp_err_t esp_websocket_client_recv(esp_websocket_client_handle_t client)
client->last_fin = esp_transport_ws_get_fin_flag(client->transport);
client->last_opcode = esp_transport_ws_get_read_opcode(client->transport);
if (rlen == 0 && client->last_opcode == WS_TRANSPORT_OPCODES_NONE ) {
if (rlen == 0 && client->last_opcode == WS_TRANSPORT_OPCODES_NONE) {
ESP_LOGV(TAG, "esp_transport_read timeouts");
esp_websocket_free_buf(client, false);
return ESP_OK;
@ -1029,7 +1056,7 @@ static void esp_websocket_client_task(void *pv)
}
}
if ( _tick_get_ms() - client->pingpong_tick_ms > client->config->pingpong_timeout_sec * 1000 ) {
if (_tick_get_ms() - client->pingpong_tick_ms > client->config->pingpong_timeout_sec * 1000) {
if (client->wait_for_pong_resp) {
esp_websocket_client_error(client, "Error, no PONG received for more than %d seconds after PING", client->config->pingpong_timeout_sec);
esp_websocket_client_abort_connection(client, WEBSOCKET_ERROR_TYPE_PONG_TIMEOUT);
@ -1150,23 +1177,13 @@ esp_err_t esp_websocket_client_stop(esp_websocket_client_handle_t client)
if (client == NULL) {
return ESP_ERR_INVALID_ARG;
}
if (!client->run) {
if (xEventGroupGetBits(client->status_bits) & STOPPED_BIT) {
ESP_LOGW(TAG, "Client was not started");
return ESP_FAIL;
}
/* A running client cannot be stopped from the websocket task/event handler */
TaskHandle_t running_task = xTaskGetCurrentTaskHandle();
if (running_task == client->task_handle) {
ESP_LOGE(TAG, "Client cannot be stopped from websocket task");
return ESP_FAIL;
}
client->run = false;
xEventGroupWaitBits(client->status_bits, STOPPED_BIT, false, true, portMAX_DELAY);
client->state = WEBSOCKET_STATE_UNKNOW;
return ESP_OK;
return stop_wait_task(client);
}
static int esp_websocket_client_send_close(esp_websocket_client_handle_t client, int code, const char *additional_data, int total_len, TickType_t timeout)
@ -1356,3 +1373,13 @@ esp_err_t esp_websocket_register_events(esp_websocket_client_handle_t client,
}
return esp_event_handler_register_with(client->event_handle, WEBSOCKET_EVENTS, event, event_handler, event_handler_arg);
}
esp_err_t esp_websocket_unregister_events(esp_websocket_client_handle_t client,
esp_websocket_event_id_t event,
esp_event_handler_t event_handler)
{
if (client == NULL) {
return ESP_ERR_INVALID_ARG;
}
return esp_event_handler_unregister_with(client->event_handle, WEBSOCKET_EVENTS, event, event_handler);
}

View File

@ -222,10 +222,12 @@ static void websocket_app_start(void)
char *long_data = malloc(size);
memset(long_data, 'a', size);
esp_websocket_client_send_text(client, long_data, size, portMAX_DELAY);
free(long_data);
xSemaphoreTake(shutdown_sema, portMAX_DELAY);
esp_websocket_client_close(client, portMAX_DELAY);
ESP_LOGI(TAG, "Websocket Stopped");
esp_websocket_unregister_events(client, WEBSOCKET_EVENT_ANY, websocket_event_handler);
esp_websocket_client_destroy(client);
}

View File

@ -55,7 +55,7 @@ class Websocket(object):
ssl_context.load_cert_chain(certfile='main/certs/server/server_cert.pem', keyfile='main/certs/server/server_key.pem')
if self.client_verify is True:
ssl_context.load_verify_locations(cafile='main/certs/ca_cert.pem')
ssl_context.verify = ssl.CERT_REQUIRED
ssl_context.verify_mode = ssl.CERT_REQUIRED
ssl_context.check_hostname = False
self.server = SimpleSSLWebSocketServer('', self.port, WebsocketTestEcho, ssl_context=ssl_context)
else:

View File

@ -1,4 +1,4 @@
version: "1.3.0"
version: "1.4.0"
description: WebSocket protocol client for ESP-IDF
url: https://github.com/espressif/esp-protocols/tree/master/components/esp_websocket_client
dependencies:

View File

@ -108,10 +108,13 @@ typedef struct {
int buffer_size; /*!< Websocket buffer size */
const char *cert_pem; /*!< Pointer to certificate data in PEM or DER format for server verify (with SSL), default is NULL, not required to verify the server. PEM-format must have a terminating NULL-character. DER-format requires the length to be passed in cert_len. */
size_t cert_len; /*!< Length of the buffer pointed to by cert_pem. May be 0 for null-terminated pem */
const char *client_cert; /*!< Pointer to certificate data in PEM or DER format for SSL mutual authentication, default is NULL, not required if mutual authentication is not needed. If it is not NULL, also `client_key` has to be provided. PEM-format must have a terminating NULL-character. DER-format requires the length to be passed in client_cert_len. */
const char *client_cert; /*!< Pointer to certificate data in PEM or DER format for SSL mutual authentication, default is NULL, not required if mutual authentication is not needed. If it is not NULL, also `client_key` or `client_ds_data` (if supported) has to be provided. PEM-format must have a terminating NULL-character. DER-format requires the length to be passed in client_cert_len. */
size_t client_cert_len; /*!< Length of the buffer pointed to by client_cert. May be 0 for null-terminated pem */
const char *client_key; /*!< Pointer to private key data in PEM or DER format for SSL mutual authentication, default is NULL, not required if mutual authentication is not needed. If it is not NULL, also `client_cert` has to be provided. PEM-format must have a terminating NULL-character. DER-format requires the length to be passed in client_key_len */
const char *client_key; /*!< Pointer to private key data in PEM or DER format for SSL mutual authentication, default is NULL, not required if mutual authentication is not needed. If it is not NULL, also `client_cert` has to be provided and `client_ds_data` (if supported) gets ignored. PEM-format must have a terminating NULL-character. DER-format requires the length to be passed in client_key_len */
size_t client_key_len; /*!< Length of the buffer pointed to by client_key_pem. May be 0 for null-terminated pem */
#if CONFIG_ESP_TLS_USE_DS_PERIPHERAL
void *client_ds_data; /*!< Pointer to the encrypted private key data for SSL mutual authentication using the DS peripheral, default is NULL, not required if mutual authentication is not needed. If it is not NULL, also `client_cert` has to be provided. It is ignored if `client_key` is provided */
#endif
esp_websocket_transport_t transport; /*!< Websocket transport type, see `esp_websocket_transport_t */
const char *subprotocol; /*!< Websocket subprotocol */
const char *user_agent; /*!< Websocket user-agent */
@ -457,6 +460,18 @@ esp_err_t esp_websocket_register_events(esp_websocket_client_handle_t client,
esp_event_handler_t event_handler,
void *event_handler_arg);
/**
* @brief Unegister the Websocket Events
*
* @param client The client handle
* @param event The event id
* @param event_handler The callback function
* @return esp_err_t
*/
esp_err_t esp_websocket_unregister_events(esp_websocket_client_handle_t client,
esp_websocket_event_id_t event,
esp_event_handler_t event_handler);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,8 @@
---
commitizen:
bump_message: 'bump(lws): $current_version -> $new_version'
pre_bump_hooks: python ../../ci/changelog.py libwebsockets
tag_format: lws-v$version
version: 4.3.3
version_files:
- idf_component.yml

View File

@ -0,0 +1,7 @@
# Changelog
## [4.3.3](https://github.com/espressif/esp-protocols/commits/lws-v4.3.3)
### Features
- Add initial support libwebsockets component ([ef3443d](https://github.com/espressif/esp-protocols/commit/ef3443d))

View File

@ -0,0 +1,20 @@
idf_component_register(REQUIRES mbedtls)
set(LWS_WITH_EXPORT_LWSTARGETS OFF CACHE BOOL "Export libwebsockets CMake targets. Disable if they conflict with an outer cmake project.")
set(LWS_WITH_MBEDTLS ON CACHE BOOL "Use mbedTLS (>=2.0) replacement for OpenSSL.")
set(LWS_WITH_JPEG OFF CACHE BOOL "Enable stateful JPEG stream decoder")
set(WRAP_FUNCTIONS mbedtls_ssl_handshake_step
lws_adopt_descriptor_vhost)
foreach(wrap ${WRAP_FUNCTIONS})
target_link_libraries(${COMPONENT_LIB} INTERFACE "-Wl,--wrap=${wrap}")
endforeach()
target_link_libraries(${COMPONENT_LIB} INTERFACE websockets)
target_sources(${COMPONENT_LIB} INTERFACE "port/lws_port.c")
add_subdirectory(libwebsockets)

View File

@ -0,0 +1,9 @@
Libwebsockets and included programs are provided under the terms of the
MIT license, with the exception that some sources are under
a similar permissive license like BSD, or are explicitly CC0 / public
domain to remove any obstacles from basing differently-licensed code on
them.
Please refer to the LWS LICENSE for more details.
Espressif port files are licensed under Apache-2.0 license.
Espressif examples and tests are distributed under Unlicense/CC0.

View File

@ -0,0 +1,24 @@
# ESP32 libwebsockets Port
This is a lightweight port of the libwebsockets library designed to run on the ESP32. It provides WebSocket client functionalities.
## Supported Options
The ESP-IDF port of libwebsockets supports a set of common WebSocket configurations for clients. These options can be configured through a structure passed to the `lws_create_context()` function.
Key features supported:
- WebSocket with optional SSL/TLS
- HTTP/1.1 client support
## Memory Footprint Considerations
The memory consumption primarily depends on the number of concurrent connections and the selected options for WebSocket frames, protocol handling, and SSL/TLS features. It consumes approximately 300 kB of program memory.
### Client:
The values bellow were extracted from the client example (./examples/client/main/lws-client.c)
- **Initial Memory Usage**: ~8 kB of heap on startup
- **Connected Memory Usage Over TLS**: ~35.3 kB of heap after connected to a server
- **Connected Memory Usage Over TCP (Plain)**: ~4.5 kB of heap after connected to a server
#### When configuring a WebSocket client, ensure that you have enough heap space to handle the desired number of concurrent client connections.
#### SSL/TLS configurations may require additional memory overhead, depending on the certificate size and cryptographic settings.

View File

@ -0,0 +1,6 @@
# The following lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(client_example)

View File

@ -0,0 +1,311 @@
Libwebsockets and included programs are provided under the terms of the
MIT license shown below, with the exception that some sources are under
a similar permissive license like BSD, or are explicitly CC0 / public
domain to remove any obstacles from basing differently-licensed code on
them.
Original liberal license retained:
- lib/misc/sha-1.c - 3-clause BSD license retained, link to original [BSD3]
- win32port/zlib
- lib/drivers/display/upng.* - ZLIB license (see zlib.h) [ZLIB]
- lib/tls/mbedtls/wrapper - Apache 2.0 (only built if linked against mbedtls) [APACHE2]
- lib/tls/mbedtls/mbedtls-extensions.c
- lib/misc/base64-decode.c - already MIT
- contrib/mcufont/encoder
- lib/misc/ieeehalfprecision.c - 2-clause BSD license retained [BSD2]
- contrib/mcufont/fonts - Open Font License [OFL]
Relicensed to MIT:
- lib/misc/daemonize.c - relicensed from Public Domain to MIT,
link to original Public Domain version
- lib/plat/windows/windows-resolv.c - relicensed from "Beerware v42" to MIT
Public Domain (CC-zero) to simplify reuse:
- test-apps/*.c
- test-apps/*.h
- minimal-examples/*
- lwsws/*
Although libwebsockets is available under a permissive license, it does not
change the reality of dealing with large lumps of external code... if your
copy diverges it is guaranteed to contain security problems after a while
and can be very painful to pick backports (especially since historically,
we are very hot on cleaning and refactoring the codebase). The least
painful and lowest risk way remains sending your changes and fixes upstream
to us so you can easily use later releases and fixes.
## MIT License applied to libwebsockets
https://opensource.org/licenses/MIT
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
## BSD2
```
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the distribution
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
```
## BSD3
For convenience, a copy of the license on `./lib/misc/sha-1.c`. In binary
distribution, this applies to builds with ws support enabled, and without
`LWS_WITHOUT_BUILTIN_SHA1` at cmake.
```
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH
```
## ZLIB
For convenience, a copy of the license on zlib. In binary distribution,
this applies for win32 builds with internal zlib only. You can avoid
building any zlib usage or copy at all with `-DLWS_WITH_ZLIB=0` (the
default), and so avoid needing to observe the license for binary
distribution that doesn't include the related code.
```
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
Jean-loup Gailly Mark Adler
jloup@gzip.org madler@alumni.caltech.edu
```
## APACHE2
For convenience, a copy of the license on the mbedtls wrapper part. In binary
distribution, this applies only when building lws against mbedtls.
The canonical license application to source files uses the URL reference, so the
whole is not reproduced here.
```
// Copyright 2015-2016 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.
```
## CC0
For convenience,the full text of CC0 dedication found on the lws examples.
The intention of this is to dedicate the examples to the public domain, so
users can build off and modify them without any constraint.
```
Statement of Purpose
The laws of most jurisdictions throughout the world automatically confer exclusive Copyright and Related Rights (defined below) upon the creator and subsequent owner(s) (each and all, an "owner") of an original work of authorship and/or a database (each, a "Work").
Certain owners wish to permanently relinquish those rights to a Work for the purpose of contributing to a commons of creative, cultural and scientific works ("Commons") that the public can reliably and without fear of later claims of infringement build upon, modify, incorporate in other works, reuse and redistribute as freely as possible in any form whatsoever and for any purposes, including without limitation commercial purposes. These owners may contribute to the Commons to promote the ideal of a free culture and the further production of creative, cultural and scientific works, or to gain reputation or greater distribution for their Work in part through the use and efforts of others.
For these and/or other purposes and motivations, and without any expectation of additional consideration or compensation, the person associating CC0 with a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and publicly distribute the Work under its terms, with knowledge of his or her Copyright and Related Rights in the Work and the meaning and intended legal effect of CC0 on those rights.
1. Copyright and Related Rights. A Work made available under CC0 may be protected by copyright and related or neighboring rights ("Copyright and Related Rights"). Copyright and Related Rights include, but are not limited to, the following:
the right to reproduce, adapt, distribute, perform, display, communicate, and translate a Work;
moral rights retained by the original author(s) and/or performer(s);
publicity and privacy rights pertaining to a person's image or likeness depicted in a Work;
rights protecting against unfair competition in regards to a Work, subject to the limitations in paragraph 4(a), below;
rights protecting the extraction, dissemination, use and reuse of data in a Work;
database rights (such as those arising under Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, and under any national implementation thereof, including any amended or successor version of such directive); and
other similar, equivalent or corresponding rights throughout the world based on applicable law or treaty, and any national implementations thereof.
2. Waiver. To the greatest extent permitted by, but not in contravention of, applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and unconditionally waives, abandons, and surrenders all of Affirmer's Copyright and Related Rights and associated claims and causes of action, whether now known or unknown (including existing as well as future claims and causes of action), in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each member of the public at large and to the detriment of Affirmer's heirs and successors, fully intending that such Waiver shall not be subject to revocation, rescission, cancellation, termination, or any other legal or equitable action to disrupt the quiet enjoyment of the Work by the public as contemplated by Affirmer's express Statement of Purpose.
3. Public License Fallback. Should any part of the Waiver for any reason be judged legally invalid or ineffective under applicable law, then the Waiver shall be preserved to the maximum extent permitted taking into account Affirmer's express Statement of Purpose. In addition, to the extent the Waiver is so judged Affirmer hereby grants to each affected person a royalty-free, non transferable, non sublicensable, non exclusive, irrevocable and unconditional license to exercise Affirmer's Copyright and Related Rights in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "License"). The License shall be deemed effective as of the date CC0 was applied by Affirmer to the Work. Should any part of the License for any reason be judged legally invalid or ineffective under applicable law, such partial invalidity or ineffectiveness shall not invalidate the remainder of the License, and in such case Affirmer hereby affirms that he or she will not (i) exercise any of his or her remaining Copyright and Related Rights in the Work or (ii) assert any associated claims and causes of action with respect to the Work, in either case contrary to Affirmer's express Statement of Purpose.
4. Limitations and Disclaimers.
No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, licensed or otherwise affected by this document.
Affirmer offers the Work as-is and makes no representations or warranties of any kind concerning the Work, express, implied, statutory or otherwise, including without limitation warranties of title, merchantability, fitness for a particular purpose, non infringement, or the absence of latent or other defects, accuracy, or the present or absence of errors, whether or not discoverable, all to the greatest extent permissible under applicable law.
Affirmer disclaims responsibility for clearing rights of other persons that may apply to the Work or any use thereof, including without limitation any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims responsibility for obtaining any necessary consents, permissions or other rights required for any use of the Work.
Affirmer understands and acknowledges that Creative Commons is not a party to this document and has no duty or obligation with respect to this CC0 or use of the Work.
```
## OFL: Open Font License
```
Copyright (c) 2012-2015, The Mozilla Foundation and Telefonica S.A.
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.
```

View File

@ -0,0 +1,87 @@
# Websocket LWS client example
This example will shows how to set up and communicate over a websocket.
## How to Use Example
### Hardware Required
This example can be executed on any ESP32 board, the only required interface is WiFi and connection to internet or a local server.
### Configure the project
* Open the project configuration menu (`idf.py menuconfig`)
* Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu.
* Configure the websocket endpoint URI under "Example Configuration"
### Server Certificate Verification
* Mutual Authentication: When `CONFIG_WS_OVER_TLS_MUTUAL_AUTH=y` is enabled, it's essential to provide valid certificates for both the server and client.
This ensures a secure two-way verification process.
* Server-Only Authentication: To perform verification of the server's certificate only (without requiring a client certificate), set `CONFIG_WS_OVER_TLS_SERVER_AUTH=y`.
This method skips client certificate verification.
* Example below demonstrates how to generate a new self signed certificates for the server and client using the OpenSSL command line tool
Please note: This example represents an extremely simplified approach to generating self-signed certificates/keys with a single common CA, devoid of CN checks, lacking password protection, and featuring hardcoded key sizes and types. It is intended solely for testing purposes.
In the outlined steps, we are omitting the configuration of the CN (Common Name) field due to the context of a testing environment. However, it's important to recognize that the CN field is a critical element of SSL/TLS certificates, significantly influencing the security and efficacy of HTTPS communications. This field facilitates the verification of a website's identity, enhancing trust and security in web interactions. In practical deployments beyond testing scenarios, ensuring the CN field is accurately set is paramount for maintaining the integrity and reliability of secure communications
It is **strongly recommended** to not reuse the example certificate in your application;
it is included only for demonstration.
### Build and Flash
Build the project and flash it to the board, then run monitor tool to view serial output:
```
idf.py -p PORT flash monitor
```
(To exit the serial monitor, type ``Ctrl-]``.)
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
## Example Output
```
I (18208) lws-client: LWS minimal ws client echo
219868: lws_create_context: LWS: 4.3.99-v4.3.0-424-ga74362ff, MbedTLS-3.6.2 NET CLI SRV H1 H2 WS SS-JSON-POL ConMon IPv6-absent
219576: mem: platform fd map: 20 bytes
217880: __lws_lc_tag: ++ [wsi|0|pipe] (1)
216516: __lws_lc_tag: ++ [vh|0|default||-1] (1)
I (18248) lws-client: connect_cb: connecting
210112: __lws_lc_tag: ++ [wsicli|0|WS/h1/default/echo.websocket.events] (1)
204800: [wsicli|0|WS/h1/default/echo.websocket.events]: lws_client_connect_3_connect: trying 13.248.241.119
180776: lws_ssl_client_bio_create: allowing selfsigned
I (19998) wifi:<ba-add>idx:0 (ifx:0, b4:89:01:63:9d:08), tid:0, ssn:321, winSize:64
I (20768) lws-client: WEBSOCKET_EVENT_CONNECTED
I (20768) lws-client: Sending hello 0000
I (20778) lws-client: WEBSOCKET_EVENT_DATA
W (20778) lws-client: Received=echo.websocket.events sponsored by Lob.com
I (20968) lws-client: WEBSOCKET_EVENT_DATA
W (20968) lws-client: Received=hello 0000
I (22978) lws-client: Sending hello 0001
I (23118) lws-client: WEBSOCKET_EVENT_DATA
W (23118) lws-client: Received=hello 0001
I (23778) lws-client: Sending hello 0002
I (23938) lws-client: WEBSOCKET_EVENT_DATA
W (23938) lws-client: Received=hello 0002
I (25948) lws-client: Sending hello 0003
I (26088) lws-client: WEBSOCKET_EVENT_DATA
W (26088) lws-client: Received=hello 0003
I (26948) lws-client: Sending hello 0004
I (27118) lws-client: WEBSOCKET_EVENT_DATA
W (27118) lws-client: Received=hello 0004
```

View File

@ -0,0 +1,12 @@
set(SRC_FILES "lws-client.c") # Define source files
set(INCLUDE_DIRS ".") # Define include directories
set(EMBED_FILES "") # Initialize an empty list for files to embed
list(APPEND EMBED_FILES
"certs/client_cert.pem"
"certs/ca_cert.pem"
"certs/client_key.pem")
idf_component_register(SRCS "${SRC_FILES}"
INCLUDE_DIRS "${INCLUDE_DIRS}"
EMBED_TXTFILES "${EMBED_FILES}")

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